feat(ai-agents): show command surfaces agent_endpoint via GetAgent#7938
feat(ai-agents): show command surfaces agent_endpoint via GetAgent#7938antriksh30 wants to merge 1 commit intomainfrom
Conversation
🔗 Linked Issue RequiredThanks for the contribution! Please link a GitHub issue to this PR by adding |
544df08 to
ff8e0af
Compare
There was a problem hiding this comment.
Pull request overview
Updates the azd ai agent show extension command to retrieve full agent details (via GetAgent) so output can include the agent_endpoint details, with a fallback to GetAgentVersion when the requested version is not the latest.
Changes:
- Add
agent_endpoint(protocols, authorization schemes) to agent API models and round-trip tests. - Switch show action to call
GetAgentfirst, falling back toGetAgentVersionwhen needed. - Extend JSON and table output to render the new endpoint information.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/models.go | Adds agent_endpoint and related structs to the agent model. |
| cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/models_test.go | Extends model round-trip test coverage to include agent_endpoint. |
| cli/azd/extensions/azure.ai.agents/internal/cmd/show.go | Uses GetAgent for show, merges endpoint info into JSON and table output, with fallback to GetAgentVersion. |
| cli/azd/extensions/azure.ai.agents/internal/cmd/show_test.go | Updates tests for updated print function signatures. |
Comments suppressed due to low confidence (1)
cli/azd/extensions/azure.ai.agents/internal/cmd/show.go:196
- The command now surfaces agent_endpoint in JSON and table output, but the tests only validate that printing succeeds (no assertions that agent_endpoint fields are actually rendered). Add tests that capture stdout for printAgentVersionJSON/printAgentVersionTable and assert presence/format of Protocols and AuthorizationSchemes rows/fields to prevent regressions.
jsonBytes, err := json.MarshalIndent(out, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal agent version to JSON: %w", err)
}
fmt.Println(string(jsonBytes))
return nil
}
func printAgentVersionTable(version *agent_api.AgentVersionObject, endpoint *agent_api.AgentEndpointInfo) error {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "FIELD\tVALUE")
fmt.Fprintln(w, "-----\t-----")
fmt.Fprintf(w, "ID\t%s\n", version.ID)
fmt.Fprintf(w, "Name\t%s\n", version.Name)
fmt.Fprintf(w, "Version\t%s\n", version.Version)
if version.Status != "" {
fmt.Fprintf(w, "Status\t%s\n", version.Status)
}
if version.Description != nil {
fmt.Fprintf(w, "Description\t%s\n", *version.Description)
}
if version.CreatedAt != 0 {
ts := time.Unix(version.CreatedAt, 0).UTC().Format(time.RFC3339)
fmt.Fprintf(w, "Created At\t%s\n", ts)
}
if version.AgentGUID != "" {
fmt.Fprintf(w, "Agent GUID\t%s\n", version.AgentGUID)
}
if version.InstanceIdentity != nil {
fmt.Fprintf(w, "Instance Identity Principal ID\t%s\n", version.InstanceIdentity.PrincipalID)
fmt.Fprintf(w, "Instance Identity Client ID\t%s\n", version.InstanceIdentity.ClientID)
}
if version.Blueprint != nil {
fmt.Fprintf(w, "Blueprint Principal ID\t%s\n", version.Blueprint.PrincipalID)
fmt.Fprintf(w, "Blueprint Client ID\t%s\n", version.Blueprint.ClientID)
}
if version.BlueprintReference != nil {
fmt.Fprintf(w, "Blueprint Reference Type\t%s\n", version.BlueprintReference.Type)
fmt.Fprintf(w, "Blueprint Reference ID\t%s\n", version.BlueprintReference.BlueprintID)
}
for k, v := range version.Metadata {
fmt.Fprintf(w, "Metadata[%s]\t%s\n", k, v)
}
if endpoint != nil {
if len(endpoint.Protocols) > 0 {
fmt.Fprintf(w, "Endpoint Protocols\t%s\n", strings.Join(endpoint.Protocols, ", "))
}
for i, scheme := range endpoint.AuthorizationSchemes {
label := fmt.Sprintf("Endpoint Auth[%d]", i)
if scheme.IsolationKeySource != nil {
fmt.Fprintf(w, "%s\t%s (isolation: %s)\n", label, scheme.Type, scheme.IsolationKeySource.Kind)
} else {
fmt.Fprintf(w, "%s\t%s\n", label, scheme.Type)
}
}
}
return w.Flush()
}
ff8e0af to
7eba15b
Compare
| return fmt.Errorf("failed to get agent: %w", err) | ||
| } | ||
|
|
||
| version := &agent.Versions.Latest |
There was a problem hiding this comment.
show now calls GetAgent() and always prints agent.Versions.Latest, ignoring the version resolved from the azd environment (info.Version / a.Version). This also means the command can still fail earlier if AGENT_<SERVICE>_VERSION isn’t set even though the new API call doesn’t need it, and it can display a different version than the one tracked in the environment. Consider either (a) removing the environment-version requirement and treating show as “latest version”, or (b) keeping the previous behavior by selecting the env-tracked version (e.g., call GetAgentVersion for a.Version) while still using GetAgent only to retrieve agent_endpoint.
| version := &agent.Versions.Latest | |
| version, err := agentClient.GetAgentVersion(ctx, a.Name, a.Version, DefaultAgentAPIVersion) | |
| if err != nil { | |
| return fmt.Errorf("failed to get agent version: %w", err) | |
| } |
There was a problem hiding this comment.
Restored GetAgentVersion(a.Version) for the version body in cec7ef1. GetAgent is still called to fetch agent_endpoint (which the per-version route doesn't return). If GetAgent fails the command still succeeds with the version body alone.
| func TestPrintAgentVersionJSON(t *testing.T) { | ||
| version := &agent_api.AgentVersionObject{ | ||
| Object: "agent.version", | ||
| ID: "ver-123", | ||
| Name: "my-agent", | ||
| Version: "1", | ||
| CreatedAt: 1735689600, // 2025-01-01T00:00:00Z | ||
| } | ||
|
|
||
| err := printAgentVersionJSON(version) | ||
| err := printAgentVersionJSON(version, nil) | ||
| require.NoError(t, err) | ||
| } |
There was a problem hiding this comment.
Tests don’t currently assert the new agent_endpoint field in the JSON output. TestPrintAgentVersionJSON_Format marshals the version directly (not the agentShowOutput used by printAgentVersionJSON), and TestPrintAgentVersionJSON only checks for no error. Consider capturing stdout from printAgentVersionJSON(version, endpoint) and asserting that agent_endpoint is present and correctly shaped when a non-nil endpoint is provided.
There was a problem hiding this comment.
Added TestPrintAgentVersionJSON_WithEndpoint and TestPrintAgentVersionJSON_NilEndpointOmitsField in cec7ef1 — they capture stdout, unmarshal, and assert agent_endpoint shape (and that it's omitted when nil).
| } | ||
|
|
||
| err := printAgentVersionTable(version) | ||
| err := printAgentVersionTable(version, nil) | ||
| require.NoError(t, err) | ||
| } |
There was a problem hiding this comment.
printAgentVersionTable gained endpoint rows, but the table tests only assert the function returns no error and don’t verify the new rows render. Consider adding a test that passes a non-nil endpoint and captures stdout to assert the protocols/auth scheme lines are emitted (and remain stable).
There was a problem hiding this comment.
Added TestPrintAgentVersionTable_WithEndpoint in cec7ef1 — captures stdout and asserts the Endpoint Protocols, Endpoint Auth[i], and isolation: rows render as expected.
Switches �zd ai agent show from GetAgentVersion to GetAgent so the response includes the agent_endpoint block (protocols, authorization_schemes). Falls back to GetAgentVersion when the deployed version no longer matches the service's latest. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
7eba15b to
cec7ef1
Compare
jongio
left a comment
There was a problem hiding this comment.
Solid approach - calling GetAgent for enrichment while keeping GetAgentVersion authoritative for the selected version is clean. A few suggestions to tighten debuggability and test coverage.
| var endpoint *agent_api.AgentEndpointInfo | ||
| if agent, err := agentClient.GetAgent(ctx, a.Name, DefaultAgentAPIVersion); err == nil { | ||
| endpoint = agent.AgentEndpoint | ||
| } |
There was a problem hiding this comment.
Consider logging the error in debug mode when GetAgent fails. Without it, users can't distinguish 'the agent has no endpoint' from 'the fetch failed silently'. Something like:
| } | |
| var endpoint *agent_api.AgentEndpointInfo | |
| if agent, err := agentClient.GetAgent(ctx, a.Name, DefaultAgentAPIVersion); err == nil { | |
| endpoint = agent.AgentEndpoint | |
| } else { | |
| log.Printf("show: GetAgent for %q: %v", a.Name, err) | |
| } |
This aligns with the log.Printf pattern used in helpers.go for non-blocking errors.
| err := printAgentVersionJSON(version) | ||
| err := printAgentVersionJSON(version, nil) | ||
| require.NoError(t, err) | ||
| } |
There was a problem hiding this comment.
The rendering tests are thorough. One gap: the key contract that show still succeeds when GetAgent fails (but fails when GetAgentVersion fails) doesn't have a direct test. If Run() is later refactored, this fallback behavior could regress without failing any test.
Worth adding a test that exercises Run() with a mocked/fake client where GetAgent returns an error and verifying the command still produces valid output.
| _, err = io.Copy(&buf, r) | ||
| require.NoError(t, err) | ||
| require.NoError(t, runErr) | ||
| return buf.String() |
There was a problem hiding this comment.
Nit: consider using .Cleanup to ensure stdout is restored even if the callback panics or a require trips early.
Updates
azd ai agent showto surface theagent_endpointblock (protocols, authorization_schemes) which the per-version API route never returns.Approach
GetAgentVersionfor the env-tracked version (preserves prior version-selection behavior).GetAgentto fetch the agent-levelagent_endpointand merge it into the JSON/table output.GetAgentfails, the command still succeeds with the version body alone (agent_endpointis omitted from output).