From 1a0212d60f9954c9393661bd6e10b40811795486 Mon Sep 17 00:00:00 2001 From: Glenn Harper Date: Sat, 23 May 2026 09:14:08 -0400 Subject: [PATCH 1/6] Fix Azure AI Agents endpoint API version Use v1 for hosted agent endpoint protocol and session requests while preserving the preview version for management APIs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../internal/cmd/agent_context.go | 3 ++ .../internal/cmd/agent_endpoint_test.go | 20 ++++++------- .../azure.ai.agents/internal/cmd/invoke.go | 29 ++++++++++++++----- .../internal/cmd/invoke_test.go | 18 ++++++++++-- .../azure.ai.agents/internal/cmd/session.go | 8 ++--- .../azure.ai.agents/internal/cmd/show_test.go | 2 +- .../pkg/agents/agent_api/api_versions.go | 7 +++++ .../pkg/agents/agent_api/operations_test.go | 20 ++++++------- .../internal/pkg/paths/paths_test.go | 4 ++- .../internal/project/service_target_agent.go | 4 +-- .../project/service_target_agent_test.go | 29 +++++++++++-------- 11 files changed, 94 insertions(+), 50 deletions(-) create mode 100644 cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/api_versions.go diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go index 390d14a21ba..2b3f3ba3126 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go @@ -21,6 +21,9 @@ import ( // DefaultAgentAPIVersion is the default API version for agent operations. const DefaultAgentAPIVersion = "2025-11-15-preview" +// AgentEndpointAPIVersion is the API version for hosted agent endpoint protocol and session requests. +const AgentEndpointAPIVersion = agent_api.AgentEndpointAPIVersion + // ConversationsAPIVersion is the API version used by the Foundry Conversations protocol. const ConversationsAPIVersion = "v1" diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint_test.go index bb5618cc44c..001d5154ba9 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint_test.go @@ -24,11 +24,11 @@ func TestParseAgentEndpoint(t *testing.T) { }{ { name: "invocations with api-version", - raw: "https://acct.services.ai.azure.com/api/projects/proj/agents/hello/endpoint/protocols/invocations?api-version=2025-11-15-preview", + raw: "https://acct.services.ai.azure.com/api/projects/proj/agents/hello/endpoint/protocols/invocations?api-version=v1", wantProj: "https://acct.services.ai.azure.com/api/projects/proj", wantAgent: "hello", wantProto: agent_api.AgentProtocolInvocations, - wantAPIVer: "2025-11-15-preview", + wantAPIVer: "v1", }, { name: "invocations without api-version", @@ -39,11 +39,11 @@ func TestParseAgentEndpoint(t *testing.T) { }, { name: "responses (openai/responses)", - raw: "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/responses?api-version=2025-11-15-preview", + raw: "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/responses?api-version=v1", wantProj: "https://acct.services.ai.azure.com/api/projects/proj", wantAgent: "echo", wantProto: agent_api.AgentProtocolResponses, - wantAPIVer: "2025-11-15-preview", + wantAPIVer: "v1", }, { name: "trailing slash tolerated", @@ -177,7 +177,7 @@ func TestParseAgentEndpoint_RejectsInvalidAgentNames(t *testing.T) { for _, name := range cases { t.Run(name, func(t *testing.T) { endpoint := "https://acct.services.ai.azure.com/api/projects/proj/agents/" + - name + "/endpoint/protocols/invocations?api-version=2025-11-15-preview" + name + "/endpoint/protocols/invocations?api-version=v1" _, err := parseAgentEndpoint(endpoint) if err == nil { t.Fatalf("parseAgentEndpoint(%q) = nil, want error", name) @@ -191,13 +191,13 @@ func TestParseAgentEndpoint_RejectsInvalidAgentNames(t *testing.T) { func TestBuildResponsesURL(t *testing.T) { t.Parallel() parsed, err := parseAgentEndpoint( - "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/responses?api-version=2025-11-15-preview", + "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/responses?api-version=custom-version", ) if err != nil { t.Fatalf("parseAgentEndpoint: %v", err) } got := buildResponsesURL(parsed.ProjectEndpoint, parsed.AgentName, parsed.APIVersion) - want := "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/responses?api-version=2025-11-15-preview" + want := "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/responses?api-version=custom-version" if got != want { t.Errorf("buildResponsesURL = %q, want %q", got, want) } @@ -214,7 +214,7 @@ func TestBuildResponsesURL(t *testing.T) { func TestBuildInvocationsURL(t *testing.T) { t.Parallel() parsed, err := parseAgentEndpoint( - "https://acct.services.ai.azure.com/api/projects/proj/agents/hello/endpoint/protocols/invocations?api-version=2025-11-15-preview", + "https://acct.services.ai.azure.com/api/projects/proj/agents/hello/endpoint/protocols/invocations?api-version=custom-version", ) if err != nil { t.Fatalf("parseAgentEndpoint: %v", err) @@ -222,7 +222,7 @@ func TestBuildInvocationsURL(t *testing.T) { t.Run("no session id", func(t *testing.T) { got := buildInvocationsURL(parsed.ProjectEndpoint, parsed.AgentName, parsed.APIVersion, "") - want := "https://acct.services.ai.azure.com/api/projects/proj/agents/hello/endpoint/protocols/invocations?api-version=2025-11-15-preview" + want := "https://acct.services.ai.azure.com/api/projects/proj/agents/hello/endpoint/protocols/invocations?api-version=custom-version" if got != want { t.Errorf("buildInvocationsURL = %q, want %q", got, want) } @@ -266,7 +266,7 @@ func TestResolveRemoteContext_EphemeralMode(t *testing.T) { name: "api-version omitted falls back to default", raw: "https://acct.services.ai.azure.com/api/projects/proj/agents/" + "hello/endpoint/protocols/openai/responses", - wantAPIVersion: DefaultAgentAPIVersion, + wantAPIVersion: "v1", wantName: "hello", wantProject: "https://acct.services.ai.azure.com/api/projects/proj", }, diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go index c249d7ac380..40ce09a7fb4 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go @@ -110,7 +110,7 @@ and --chat-isolation-key on each remote invoke.`, # Invoke a deployed agent from any directory using the endpoint URL shown by 'azd ai agent show' azd ai agent invoke \ - --agent-endpoint https://.services.ai.azure.com/api/projects//agents//endpoint/protocols/openai/responses?api-version=2025-11-15-preview \ + --agent-endpoint https://.services.ai.azure.com/api/projects//agents//endpoint/protocols/openai/responses?api-version=v1 \ "Hello!"`, Args: cobra.RangeArgs(0, 2), RunE: func(cmd *cobra.Command, args []string) error { @@ -600,7 +600,7 @@ func (rc *remoteContext) nextStepName() string { // and avoid unnecessary token round-trips on invalid input. Callers must close // rc.azdClient when non-nil. func (a *InvokeAction) resolveRemoteContext(ctx context.Context) (*remoteContext, error) { - rc := &remoteContext{apiVersion: DefaultAgentAPIVersion, version: a.flags.version} + rc := &remoteContext{apiVersion: AgentEndpointAPIVersion, version: a.flags.version} if a.endpoint != nil { rc.name = a.endpoint.AgentName @@ -701,7 +701,11 @@ func (a *InvokeAction) resolveRemoteSessionID(ctx context.Context, rc *remoteCon } } - session, err := createInvokeVersionSession(ctx, rc.projectEndpoint, rc.name, rc.version) + apiVersion := rc.apiVersion + if apiVersion == "" { + apiVersion = AgentEndpointAPIVersion + } + session, err := createInvokeVersionSession(ctx, rc.projectEndpoint, rc.name, rc.version, apiVersion) if err != nil { return "", err } @@ -724,7 +728,12 @@ func createInvokeVersionSessionImpl( projectEndpoint string, agentName string, agentVersion string, + apiVersion string, ) (*agent_api.AgentSessionResource, error) { + if apiVersion == "" { + apiVersion = AgentEndpointAPIVersion + } + credential, err := newAgentCredential() if err != nil { return nil, err @@ -740,7 +749,7 @@ func createInvokeVersionSessionImpl( AgentVersion: agentVersion, }, }, - DefaultAgentAPIVersion, + apiVersion, nil, ) if err != nil { @@ -989,7 +998,7 @@ func (a *InvokeAction) invocationsLocal(ctx context.Context) error { fmt.Printf("Invocation: %s\n", invID) } - if err := handleInvocationResponse(ctx, resp, "", "", agentKey, a.httpTimeout(), nil); err != nil { + if err := handleInvocationResponse(ctx, resp, "", "", agentKey, a.httpTimeout(), "", nil); err != nil { // See invocationsRemote for the status-code rationale. if resp.StatusCode >= 400 { a.emitInvokeFailureNextStep(nextstep.InvokeLocal, agentName, "") @@ -1095,6 +1104,7 @@ func (a *InvokeAction) invocationsRemote(ctx context.Context) error { rc.bearerToken, rc.name, a.httpTimeout(), + rc.apiVersion, a.flags.sessionRequestOptions(), ); err != nil { // Only emit failure Next: for platform HTTP failures. @@ -1122,6 +1132,7 @@ func handleInvocationResponse( bearerToken string, agentName string, timeout time.Duration, + apiVersion string, options *agent_api.SessionRequestOptions, ) error { if traceID := responseTraceID(resp); traceID != "" { @@ -1141,7 +1152,7 @@ func handleInvocationResponse( } if resp.StatusCode == http.StatusAccepted { - return handleInvocationLRO(ctx, resp, endpoint, bearerToken, agentName, timeout, options) + return handleInvocationLRO(ctx, resp, endpoint, bearerToken, agentName, timeout, apiVersion, options) } contentType := resp.Header.Get("Content-Type") @@ -1256,6 +1267,7 @@ func handleInvocationLRO( bearerToken string, agentName string, timeout time.Duration, + apiVersion string, options *agent_api.SessionRequestOptions, ) error { // Read the 202 body once — used for both invocation ID extraction and status display. @@ -1302,9 +1314,12 @@ func handleInvocationLRO( } } if pollURL == "" { + if apiVersion == "" { + apiVersion = AgentEndpointAPIVersion + } pollURL = fmt.Sprintf( "%s/agents/%s/endpoint/protocols/invocations/%s?api-version=%s", - endpoint, agentName, invocationID, DefaultAgentAPIVersion, + endpoint, agentName, invocationID, url.QueryEscape(apiVersion), ) } diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go index 0bb6bcd3771..5b506d6bbf2 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go @@ -743,7 +743,7 @@ func TestAgentEndpointFlagValidation(t *testing.T) { t.Parallel() const validURL = "https://acct.services.ai.azure.com/api/projects/proj/agents/" + - "hello/endpoint/protocols/invocations?api-version=2025-11-15-preview" + "hello/endpoint/protocols/invocations?api-version=v1" tests := []struct { name string @@ -822,6 +822,7 @@ func TestResolveRemoteSessionID_ReusesCachedVersionSession(t *testing.T) { string, string, string, + string, ) (*agent_api.AgentSessionResource, error) { t.Fatal("createInvokeVersionSession should not be called when a cached session exists") return nil, nil @@ -861,6 +862,7 @@ func TestResolveRemoteSessionID_NewSessionSkipsCachedVersionSession(t *testing.T string, string, string, + string, ) (*agent_api.AgentSessionResource, error) { calls++ return &agent_api.AgentSessionResource{AgentSessionID: "fresh-session"}, nil @@ -903,6 +905,7 @@ func TestResolveRemoteSessionID_CreatesSessionForExplicitVersion(t *testing.T) { projectEndpoint string, agentName string, agentVersion string, + apiVersion string, ) (*agent_api.AgentSessionResource, error) { calls++ if projectEndpoint != "https://acct.services.ai.azure.com/api/projects/proj" { @@ -914,6 +917,9 @@ func TestResolveRemoteSessionID_CreatesSessionForExplicitVersion(t *testing.T) { if agentVersion != "3" { t.Errorf("agentVersion = %q", agentVersion) } + if apiVersion != "custom-version" { + t.Errorf("apiVersion = %q", apiVersion) + } return &agent_api.AgentSessionResource{AgentSessionID: "session-v3"}, nil } @@ -922,6 +928,7 @@ func TestResolveRemoteSessionID_CreatesSessionForExplicitVersion(t *testing.T) { name: "hello", projectEndpoint: "https://acct.services.ai.azure.com/api/projects/proj", version: "3", + apiVersion: "custom-version", agentKey: buildAgentKey("https://acct.services.ai.azure.com/api/projects/proj", "hello", "3", false), } @@ -1255,7 +1262,9 @@ func TestHandleInvocationResponse_Routing(t *testing.T) { resp.Header.Set(k, v) } - err := handleInvocationResponse(t.Context(), resp, "", "", "test-agent", 10*time.Second, nil) + err := handleInvocationResponse( + t.Context(), resp, "", "", "test-agent", 10*time.Second, "", nil, + ) if tt.wantErr { if err == nil { @@ -1508,7 +1517,9 @@ func TestHandleInvocationLRO(t *testing.T) { resp.Header.Set("x-agent-invocation-id", tt.initial202Header) } - err := handleInvocationLRO(t.Context(), resp, "", "", "test-agent", tt.timeout, nil) + err := handleInvocationLRO( + t.Context(), resp, "", "", "test-agent", tt.timeout, "", nil, + ) if tt.wantErr { if err == nil { @@ -1623,6 +1634,7 @@ func captureInvocationLROPollRequests( "token", "test-agent", time.Second, + "", options, ) if err != nil { diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/session.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/session.go index 2eeb51e00e7..479079be351 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/session.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/session.go @@ -273,7 +273,7 @@ func (a *SessionCreateAction) Run(ctx context.Context) error { ctx, sc.agentName, request, - DefaultAgentAPIVersion, + AgentEndpointAPIVersion, a.flags.sessionRequestOptionsWithSessionKey(a.flags.isolationKey), ) if err != nil { @@ -359,7 +359,7 @@ func (a *SessionShowAction) Run(ctx context.Context) error { ctx, sc.agentName, a.sessionID, - DefaultAgentAPIVersion, + AgentEndpointAPIVersion, a.flags.sessionRequestOptions(), ) if err != nil { @@ -462,7 +462,7 @@ func (a *SessionDeleteAction) Run(ctx context.Context) error { ctx, sc.agentName, a.sessionID, - DefaultAgentAPIVersion, + AgentEndpointAPIVersion, a.flags.sessionRequestOptionsWithSessionKey(a.flags.isolationKey), ) if err != nil { @@ -597,7 +597,7 @@ func (a *SessionListAction) Run(ctx context.Context) error { sc.agentName, limit, token, - DefaultAgentAPIVersion, + AgentEndpointAPIVersion, a.flags.sessionRequestOptions(), ) if err != nil { diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/show_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/show_test.go index 73302119212..9828055f4e9 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/show_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/show_test.go @@ -158,7 +158,7 @@ func TestPrintAgentVersionJSON_Format(t *testing.T) { AgentVersionObject: version, PlaygroundURL: "https://ai.azure.com/nextgen/r/test/build/agents/test-agent/build?version=2", Endpoints: map[string]string{ - "Responses": "https://acct.services.ai.azure.com/api/projects/proj/agents/test-agent/endpoint/protocols/openai/responses?api-version=2025-11-15-preview", + "Responses": "https://acct.services.ai.azure.com/api/projects/proj/agents/test-agent/endpoint/protocols/openai/responses?api-version=v1", }, } diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/api_versions.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/api_versions.go new file mode 100644 index 00000000000..bbc05e97781 --- /dev/null +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/api_versions.go @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package agent_api + +// AgentEndpointAPIVersion is the API version for hosted agent endpoint protocol and session requests. +const AgentEndpointAPIVersion = "v1" diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations_test.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations_test.go index 045b8031c8c..26ebaacd3ae 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations_test.go @@ -174,7 +174,7 @@ func TestDeleteSession_Accepts200(t *testing.T) { ) err := client.DeleteSession( - t.Context(), "my-agent", "sess-1", "2025-11-15-preview", nil, + t.Context(), "my-agent", "sess-1", AgentEndpointAPIVersion, nil, ) require.NoError(t, err, "200 OK should be treated as success") } @@ -186,7 +186,7 @@ func TestDeleteSession_Accepts204(t *testing.T) { ) err := client.DeleteSession( - t.Context(), "my-agent", "sess-1", "2025-11-15-preview", nil, + t.Context(), "my-agent", "sess-1", AgentEndpointAPIVersion, nil, ) require.NoError(t, err, "204 No Content should be treated as success") } @@ -198,7 +198,7 @@ func TestDeleteSession_Rejects500(t *testing.T) { ) err := client.DeleteSession( - t.Context(), "my-agent", "sess-1", "2025-11-15-preview", nil, + t.Context(), "my-agent", "sess-1", AgentEndpointAPIVersion, nil, ) require.Error(t, err, "500 should be an error") } @@ -210,7 +210,7 @@ func TestGetSession_404ReturnsError(t *testing.T) { ) _, err := client.GetSession( - t.Context(), "my-agent", "sess-1", "2025-11-15-preview", nil, + t.Context(), "my-agent", "sess-1", AgentEndpointAPIVersion, nil, ) require.Error(t, err, "404 should be an error from GetSession") } @@ -256,7 +256,7 @@ func TestCreateSession_Returns201WithBody(t *testing.T) { AgentVersion: "3", }, }, - "2025-11-15-preview", + AgentEndpointAPIVersion, nil, ) @@ -290,7 +290,7 @@ func TestListSessions_Returns200WithPagination(t *testing.T) { ) result, err := client.ListSessions( - t.Context(), "my-agent", nil, nil, "2025-11-15-preview", nil, + t.Context(), "my-agent", nil, nil, AgentEndpointAPIVersion, nil, ) require.NoError(t, err) @@ -326,7 +326,7 @@ func TestSessionLifecycleOperations_ApplyIsolationHeaders(t *testing.T) { t.Context(), "my-agent", &CreateAgentSessionRequest{}, - "2025-11-15-preview", + AgentEndpointAPIVersion, options, ) return err @@ -342,7 +342,7 @@ func TestSessionLifecycleOperations_ApplyIsolationHeaders(t *testing.T) { t.Context(), "my-agent", "sess-1", - "2025-11-15-preview", + AgentEndpointAPIVersion, options, ) return err @@ -356,7 +356,7 @@ func TestSessionLifecycleOperations_ApplyIsolationHeaders(t *testing.T) { t.Context(), "my-agent", "sess-1", - "2025-11-15-preview", + AgentEndpointAPIVersion, options, ) }, @@ -372,7 +372,7 @@ func TestSessionLifecycleOperations_ApplyIsolationHeaders(t *testing.T) { "my-agent", nil, nil, - "2025-11-15-preview", + AgentEndpointAPIVersion, options, ) return err diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/paths/paths_test.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/paths/paths_test.go index 54fc73c1350..65eef4aec8d 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/paths/paths_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/paths/paths_test.go @@ -7,6 +7,7 @@ import ( "errors" "os" "path/filepath" + "strings" "testing" "github.com/stretchr/testify/require" @@ -133,7 +134,8 @@ func createSymlinkOrSkip(t *testing.T, oldname, newname string) { t.Helper() if err := os.Symlink(oldname, newname); err != nil { - if errors.Is(err, os.ErrPermission) { + if errors.Is(err, os.ErrPermission) || os.IsPermission(err) || + strings.Contains(strings.ToLower(err.Error()), "privilege") { t.Skipf("symlink creation not permitted: %v", err) } t.Fatalf("create symlink: %v", err) diff --git a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go index d2877ee9c42..38e5520f743 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go +++ b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go @@ -47,7 +47,7 @@ import ( // Reference implementation -// agentAPIVersion is the API version used for agent endpoint invocation URLs. +// agentAPIVersion is the API version used for agent management operations. const agentAPIVersion = "2025-11-15-preview" // displayableProtocolEntry defines a protocol that produces user-visible invocation endpoints. @@ -1771,7 +1771,7 @@ func agentInvocationEndpoints( Protocol: p.Protocol, URL: fmt.Sprintf( "%s/agents/%s/endpoint/protocols/%s?api-version=%s", - projectEndpoint, agentName, path, agentAPIVersion), + projectEndpoint, agentName, path, agent_api.AgentEndpointAPIVersion), }) } return endpoints diff --git a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent_test.go b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent_test.go index 82be86491c5..193148efc1b 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent_test.go @@ -366,7 +366,8 @@ func createSymlinkOrSkip(t *testing.T, oldname, newname string) { t.Helper() if err := os.Symlink(oldname, newname); err != nil { - if errors.Is(err, os.ErrPermission) { + if errors.Is(err, os.ErrPermission) || os.IsPermission(err) || + strings.Contains(strings.ToLower(err.Error()), "privilege") { t.Skipf("symlink creation not permitted: %v", err) } t.Fatalf("create symlink: %v", err) @@ -456,13 +457,17 @@ func TestRegisterAgentEnvironmentVariables(t *testing.T) { // Per-protocol endpoints require.Contains(t, envStub.values, "AGENT_MY_SVC_RESPONSES_ENDPOINT") - require.Contains(t, + require.Equal( + t, + "https://proj.azure.com/agents/my-agent/endpoint/protocols/openai/responses?api-version=v1", envStub.values["AGENT_MY_SVC_RESPONSES_ENDPOINT"], - "/agents/my-agent/endpoint/protocols/openai/responses") + ) require.Contains(t, envStub.values, "AGENT_MY_SVC_INVOCATIONS_ENDPOINT") - require.Contains(t, + require.Equal( + t, + "https://proj.azure.com/agents/my-agent/endpoint/protocols/invocations?api-version=v1", envStub.values["AGENT_MY_SVC_INVOCATIONS_ENDPOINT"], - "/agents/my-agent/endpoint/protocols/invocations") + ) // Base agent endpoint for session management require.Contains(t, envStub.values, "AGENT_MY_SVC_ENDPOINT") @@ -589,7 +594,7 @@ func TestAgentInvocationEndpoints(t *testing.T) { expected: []protocolEndpointInfo{ { Protocol: "responses", - URL: baseURL + "openai/responses?api-version=" + agentAPIVersion, + URL: baseURL + "openai/responses?api-version=v1", }, }, }, @@ -601,7 +606,7 @@ func TestAgentInvocationEndpoints(t *testing.T) { expected: []protocolEndpointInfo{ { Protocol: "invocations", - URL: baseURL + "invocations?api-version=" + agentAPIVersion, + URL: baseURL + "invocations?api-version=v1", }, }, }, @@ -615,11 +620,11 @@ func TestAgentInvocationEndpoints(t *testing.T) { expected: []protocolEndpointInfo{ { Protocol: "responses", - URL: baseURL + "openai/responses?api-version=" + agentAPIVersion, + URL: baseURL + "openai/responses?api-version=v1", }, { Protocol: "invocations", - URL: baseURL + "invocations?api-version=" + agentAPIVersion, + URL: baseURL + "invocations?api-version=v1", }, }, }, @@ -668,7 +673,7 @@ func TestDeployArtifacts_HostedAgent_ProtocolEndpoints(t *testing.T) { wantResponses := ep + "/agents/test-agent/endpoint/protocols/openai/responses" + - "?api-version=" + agentAPIVersion + "?api-version=v1" require.Equal(t, wantResponses, artifacts[0].Location) require.Equal(t, "Agent endpoint (responses)", artifacts[0].Metadata["label"]) require.Empty(t, artifacts[0].Metadata["note"], @@ -676,7 +681,7 @@ func TestDeployArtifacts_HostedAgent_ProtocolEndpoints(t *testing.T) { wantInvocations := ep + "/agents/test-agent/endpoint/protocols/invocations" + - "?api-version=" + agentAPIVersion + "?api-version=v1" require.Equal(t, wantInvocations, artifacts[1].Location) require.Equal(t, "Agent endpoint (invocations)", artifacts[1].Metadata["label"]) require.Contains(t, artifacts[1].Metadata["note"], "invoking the agent") @@ -702,7 +707,7 @@ func TestDeployArtifacts_ResponsesProtocol(t *testing.T) { require.Len(t, artifacts, 1) wantURL := ep + "/agents/prompt-agent/endpoint/protocols/openai/responses" + - "?api-version=" + agentAPIVersion + "?api-version=v1" require.Equal(t, wantURL, artifacts[0].Location) require.Equal(t, "Agent endpoint (responses)", artifacts[0].Metadata["label"]) require.Contains(t, artifacts[0].Metadata["note"], "invoking the agent") From 15cf91e4d3a0c84cb46413cd1e6024e0f0edc415 Mon Sep 17 00:00:00 2001 From: Glenn Harper <64209257+glharper@users.noreply.github.com> Date: Tue, 26 May 2026 12:45:36 -0400 Subject: [PATCH 2/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go index 40ce09a7fb4..d44b52a96ce 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go @@ -998,7 +998,7 @@ func (a *InvokeAction) invocationsLocal(ctx context.Context) error { fmt.Printf("Invocation: %s\n", invID) } - if err := handleInvocationResponse(ctx, resp, "", "", agentKey, a.httpTimeout(), "", nil); err != nil { + if err := handleInvocationResponse(ctx, resp, "", "", agentName, a.httpTimeout(), "", nil); err != nil { // See invocationsRemote for the status-code rationale. if resp.StatusCode >= 400 { a.emitInvokeFailureNextStep(nextstep.InvokeLocal, agentName, "") From 16b2fe844c0644ae2022bd53c073f33ca597046f Mon Sep 17 00:00:00 2001 From: Glenn Harper Date: Tue, 26 May 2026 16:03:34 -0400 Subject: [PATCH 3/6] update all version literals to v1 --- .../internal/cmd/agent_context.go | 2 +- .../checks_agent_identity_roles_test.go | 4 +-- .../cmd/doctor/checks_agent_status_test.go | 6 ++-- .../doctor/checks_foundry_endpoint_test.go | 34 +++++++++---------- .../azure.ai.agents/internal/cmd/eval_test.go | 4 +-- .../pkg/connections/data_client.go | 2 +- .../pkg/agents/agent_api/operations_test.go | 22 ++++++------ .../pkg/agents/dataset_api/operations_test.go | 8 ++--- .../pkg/agents/eval_api/operations_test.go | 26 +++++++------- .../internal/pkg/agents/existence_test.go | 2 +- .../pkg/azure/foundry_projects_client.go | 2 +- .../internal/project/service_target_agent.go | 2 +- 12 files changed, 57 insertions(+), 57 deletions(-) diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go index 2b3f3ba3126..a20636c6d7c 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go @@ -19,7 +19,7 @@ import ( ) // DefaultAgentAPIVersion is the default API version for agent operations. -const DefaultAgentAPIVersion = "2025-11-15-preview" +const DefaultAgentAPIVersion = "v1" // AgentEndpointAPIVersion is the API version for hosted agent endpoint protocol and session requests. const AgentEndpointAPIVersion = agent_api.AgentEndpointAPIVersion diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_agent_identity_roles_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_agent_identity_roles_test.go index 0ccee69e6f6..76ee2379ffa 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_agent_identity_roles_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_agent_identity_roles_test.go @@ -48,7 +48,7 @@ func runIdentityCheck(t *testing.T, deps Dependencies, prior []Result) Result { deps.AzdClient = &azdext.AzdClient{} } if deps.AgentAPIVersion == "" { - deps.AgentAPIVersion = "2025-11-15-preview" + deps.AgentAPIVersion = "v1" } if deps.readProjectResourceIDFn == nil { deps.readProjectResourceIDFn = func(_ context.Context, _ *azdext.AzdClient) (string, error) { @@ -441,7 +441,7 @@ func TestCheckAgentIdentityRoles_RedactedDetailsDoNotLeakIdentifiers(t *testing. return agentIdentityProbeResult{PrincipalID: rawPrincipal, StatusCode: 200} }, queryAgentIdentityRoles: makeQueryReturning(canned), - AgentAPIVersion: "2025-11-15-preview", + AgentAPIVersion: "v1", }) resU := check.Fn(t.Context(), Options{Unredacted: true}, prior) detailsUnredacted := flattenDetails(resU.Details) diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_agent_status_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_agent_status_test.go index b0d52b93f42..f962f817f38 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_agent_status_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_agent_status_test.go @@ -86,7 +86,7 @@ func runCheckWithDeps(t *testing.T, deps Dependencies, prior []Result) Result { deps.AzdClient = &azdext.AzdClient{} } if deps.AgentAPIVersion == "" { - deps.AgentAPIVersion = "2025-11-15-preview" + deps.AgentAPIVersion = "v1" } c := newCheckAgentStatus(deps) require.NotNil(t, c.Fn, "newCheckAgentStatus must return a non-nil Fn") @@ -202,7 +202,7 @@ func TestCheckAgentStatus_SkipsWhenEndpointMissingFromUpstream(t *testing.T) { func TestCheckAgentStatus_SkipsWhenAgentServiceListMissingFromUpstream(t *testing.T) { t.Parallel() - deps := Dependencies{AzdClient: &azdext.AzdClient{}, AgentAPIVersion: "2025-11-15-preview"} + deps := Dependencies{AzdClient: &azdext.AzdClient{}, AgentAPIVersion: "v1"} prior := []Result{ {ID: "local.environment-selected", Status: StatusPass}, // agent-service-detected passed but didn't surface the list: @@ -769,7 +769,7 @@ func TestMakeRealProbeAgentStatus_ReturnsNonNilCloser(t *testing.T) { // but we can pin the factory: it must return a non-nil closure that // surfaces a credential-creation error or a network error rather // than panicking when called. - probe := makeRealProbeAgentStatus("2025-11-15-preview") + probe := makeRealProbeAgentStatus("v1") require.NotNil(t, probe) // Invoking with an obviously-invalid endpoint should still // produce a structured result (not a panic). We pass a very diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_foundry_endpoint_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_foundry_endpoint_test.go index 9d9ceb6a10f..40d658d3325 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_foundry_endpoint_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_foundry_endpoint_test.go @@ -16,11 +16,11 @@ import ( // foundryProbeStub builds a Dependencies whose probeFoundryEndpoint // seam returns a fixed foundryProbeResult and an AgentAPIVersion of -// `2025-11-15-preview`. Centralised so every status-code test reads +// `v1`. Centralised so every status-code test reads // at the same level of abstraction. func foundryProbeStub(res foundryProbeResult) Dependencies { return Dependencies{ - AgentAPIVersion: "2025-11-15-preview", + AgentAPIVersion: "v1", probeFoundryEndpoint: func(_ context.Context, _ string) foundryProbeResult { return res }, @@ -135,7 +135,7 @@ func TestCheckFoundryEndpoint_PassesOn200(t *testing.T) { endpoint := "https://acct.services.ai.azure.com/api/projects/proj" check := newCheckFoundryEndpoint(foundryProbeStub(foundryProbeResult{ statusCode: http.StatusOK, - requestedURL: endpoint + "/agents?api-version=2025-11-15-preview&limit=1", + requestedURL: endpoint + "/agents?api-version=v1&limit=1", })) got := check.Fn(t.Context(), Options{}, passingPriors(endpoint)) @@ -278,7 +278,7 @@ func TestCheckFoundryEndpoint_SkipsOnUserCancellation(t *testing.T) { endpoint := "https://acct.services.ai.azure.com/api/projects/proj" check := newCheckFoundryEndpoint(Dependencies{ - AgentAPIVersion: "2025-11-15-preview", + AgentAPIVersion: "v1", probeFoundryEndpoint: func(ctx context.Context, _ string) foundryProbeResult { <-ctx.Done() return foundryProbeResult{err: ctx.Err()} @@ -298,7 +298,7 @@ func TestCheckFoundryEndpoint_FailsOnProbeTimeout(t *testing.T) { endpoint := "https://acct.services.ai.azure.com/api/projects/proj" check := newCheckFoundryEndpoint(Dependencies{ - AgentAPIVersion: "2025-11-15-preview", + AgentAPIVersion: "v1", probeFoundryEndpoint: func(_ context.Context, _ string) foundryProbeResult { return foundryProbeResult{err: context.DeadlineExceeded} }, @@ -322,7 +322,7 @@ func TestCheckFoundryEndpoint_FallsBackToRealProbeWhenSeamMissing(t *testing.T) // regardless of the host's network state, and assert the // cancellation classification kicks in. check := newCheckFoundryEndpoint(Dependencies{ - AgentAPIVersion: "2025-11-15-preview", + AgentAPIVersion: "v1", }) ctx, cancel := context.WithCancel(t.Context()) @@ -360,7 +360,7 @@ func TestRealProbeFoundryEndpoint_RequestShapeAgainstHTTPTestServer(t *testing.T })) defer srv.Close() - got, err := buildFoundryProbeURL(srv.URL, "2025-11-15-preview") + got, err := buildFoundryProbeURL(srv.URL, "v1") require.NoError(t, err) req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, got, nil) @@ -373,7 +373,7 @@ func TestRealProbeFoundryEndpoint_RequestShapeAgainstHTTPTestServer(t *testing.T require.Equal(t, "/agents", seenPath, "the built URL must resolve to /agents on the wire") - require.Contains(t, seenQuery, "api-version=2025-11-15-preview") + require.Contains(t, seenQuery, "api-version=v1") require.Contains(t, seenQuery, "limit=1", "the probe must use limit=1 (matches production "+ "agent_api/operations.go) — not $top=1") @@ -395,7 +395,7 @@ func TestBuildFoundryProbeURL(t *testing.T) { endpoint: "https://x.services.ai.azure.com/api/projects/proj", wantContains: []string{ "https://x.services.ai.azure.com/api/projects/proj/agents?", - "api-version=2025-11-15-preview", + "api-version=v1", "limit=1", }, }, @@ -412,7 +412,7 @@ func TestBuildFoundryProbeURL(t *testing.T) { endpoint: "https://x.services.ai.azure.com/api/projects/proj?api-version=evil&injected=x", wantContains: []string{ "/api/projects/proj/agents?", - "api-version=2025-11-15-preview", + "api-version=v1", "limit=1", }, wantMissing: []string{"api-version=evil", "injected=x"}, @@ -422,7 +422,7 @@ func TestBuildFoundryProbeURL(t *testing.T) { endpoint: "https://x.services.ai.azure.com/api/projects/proj#evil/agents", wantContains: []string{ "/api/projects/proj/agents?", - "api-version=2025-11-15-preview", + "api-version=v1", "limit=1", }, wantMissing: []string{"#"}, @@ -439,7 +439,7 @@ func TestBuildFoundryProbeURL(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { t.Parallel() - got, err := buildFoundryProbeURL(tc.endpoint, "2025-11-15-preview") + got, err := buildFoundryProbeURL(tc.endpoint, "v1") require.NoError(t, err) for _, sub := range tc.wantContains { require.Containsf(t, got, sub, "URL %q missing substring %q", got, sub) @@ -481,7 +481,7 @@ func TestBuildFoundryProbeURL_RejectsNonHTTPSOrMalformedEndpoint(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { t.Parallel() - _, err := buildFoundryProbeURL(tc.endpoint, "2025-11-15-preview") + _, err := buildFoundryProbeURL(tc.endpoint, "v1") require.Error(t, err, "builder must reject non-HTTPS / relative / malformed "+ "endpoints so the probe never sends a bearer token "+ @@ -540,7 +540,7 @@ func TestCheckFoundryEndpoint_FailsOnNonHTTPSEndpoint(t *testing.T) { // the request at validation time, BEFORE any token is acquired // or any probe is dispatched. check := newCheckFoundryEndpoint(Dependencies{ - AgentAPIVersion: "2025-11-15-preview", + AgentAPIVersion: "v1", probeFoundryEndpoint: func(_ context.Context, _ string) foundryProbeResult { t.Fatal("probe must not be invoked for a non-HTTPS endpoint") return foundryProbeResult{} @@ -561,7 +561,7 @@ func TestCheckFoundryEndpoint_FailsOnMalformedEndpoint(t *testing.T) { t.Parallel() check := newCheckFoundryEndpoint(Dependencies{ - AgentAPIVersion: "2025-11-15-preview", + AgentAPIVersion: "v1", probeFoundryEndpoint: func(_ context.Context, _ string) foundryProbeResult { t.Fatal("probe must not be invoked for a malformed endpoint") return foundryProbeResult{} @@ -648,7 +648,7 @@ func TestFoundryDetails_IncludesStatusAndURLWhenSet(t *testing.T) { d := foundryDetails("https://x", foundryProbeResult{ statusCode: 200, - requestedURL: "https://x/agents?api-version=2025-11-15-preview&limit=1", + requestedURL: "https://x/agents?api-version=v1&limit=1", }) require.Equal(t, 200, d["statusCode"]) require.Contains(t, d["requestedURL"], "/agents") @@ -665,7 +665,7 @@ func TestFoundryDetails_NeverContainsToken(t *testing.T) { // refuse to surface it. d := foundryDetails("https://x", foundryProbeResult{ statusCode: 200, - requestedURL: "https://x/agents?api-version=2025-11-15-preview", + requestedURL: "https://x/agents?api-version=v1", }) for k, v := range d { require.NotContains(t, strings.ToLower(k), "token", diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_test.go index 0d9b59d447b..991d5509046 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_test.go @@ -300,7 +300,7 @@ func TestWriteEvalReviewArtifacts_SkipsWhenResultExists(t *testing.T) { func TestDownloadDatasetArtifact_NilDataset(t *testing.T) { t.Parallel() - _, err := eval_api.DownloadDatasetArtifact(t.Context(), nil, t.TempDir(), nil, "2025-11-15-preview") + _, err := eval_api.DownloadDatasetArtifact(t.Context(), nil, t.TempDir(), nil, "v1") require.NoError(t, err) } @@ -320,7 +320,7 @@ func TestDownloadDatasetArtifact_WritesBlob(t *testing.T) { dir := t.TempDir() ref := &evalDatasetRef{Name: "test-ds", Version: "v1"} - _, err := eval_api.DownloadDatasetArtifact(t.Context(), client, dir, ref, "2025-11-15-preview") + _, err := eval_api.DownloadDatasetArtifact(t.Context(), client, dir, ref, "v1") require.Error(t, err) assert.Contains(t, err.Error(), "getting dataset credential") diff --git a/cli/azd/extensions/azure.ai.agents/internal/connections/pkg/connections/data_client.go b/cli/azd/extensions/azure.ai.agents/internal/connections/pkg/connections/data_client.go index 5fa66eae3c3..d0deaddaed5 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/connections/pkg/connections/data_client.go +++ b/cli/azd/extensions/azure.ai.agents/internal/connections/pkg/connections/data_client.go @@ -18,7 +18,7 @@ import ( "github.com/azure/azure-dev/cli/azd/pkg/azsdk" ) -const dataPlaneAPIVersion = "2025-11-15-preview" +const dataPlaneAPIVersion = "v1" // DataClient provides read operations via the Foundry data plane. // Used for listing connections (including ARM ID discovery) and fetching credentials. diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations_test.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations_test.go index 26ebaacd3ae..945a17547fe 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations_test.go @@ -412,7 +412,7 @@ func TestSessionFileOperations_ApplyIsolationHeaders(t *testing.T) { "my-agent", "sess-1", "/data/input.txt", - "2025-11-15-preview", + "v1", bytes.NewReader([]byte("hello")), options, ) @@ -428,7 +428,7 @@ func TestSessionFileOperations_ApplyIsolationHeaders(t *testing.T) { "my-agent", "sess-1", "/data/input.txt", - "2025-11-15-preview", + "v1", options, ) if err != nil { @@ -447,7 +447,7 @@ func TestSessionFileOperations_ApplyIsolationHeaders(t *testing.T) { "my-agent", "sess-1", "", - "2025-11-15-preview", + "v1", options, ) return err @@ -463,7 +463,7 @@ func TestSessionFileOperations_ApplyIsolationHeaders(t *testing.T) { "sess-1", "/data/input.txt", false, - "2025-11-15-preview", + "v1", options, ) }, @@ -477,7 +477,7 @@ func TestSessionFileOperations_ApplyIsolationHeaders(t *testing.T) { "my-agent", "sess-1", "/data", - "2025-11-15-preview", + "v1", options, ) }, @@ -492,7 +492,7 @@ func TestSessionFileOperations_ApplyIsolationHeaders(t *testing.T) { "my-agent", "sess-1", "/data/input.txt", - "2025-11-15-preview", + "v1", options, ) return err @@ -536,7 +536,7 @@ func TestGetAgentSessionLogStream_ApplyIsolationHeaders(t *testing.T) { t.Context(), "my-agent", "sess-1", - "2025-11-15-preview", + "v1", "console", 50, false, @@ -600,7 +600,7 @@ func TestPatchAgent_Success(t *testing.T) { } result, err := client.PatchAgent( - t.Context(), "my-agent", req, "2025-11-15-preview", + t.Context(), "my-agent", req, "v1", ) require.NoError(t, err) require.Equal(t, "my-agent", result.Name) @@ -619,7 +619,7 @@ func TestPatchAgent_400ReturnsError(t *testing.T) { } _, err := client.PatchAgent( - t.Context(), "my-agent", req, "2025-11-15-preview", + t.Context(), "my-agent", req, "v1", ) require.Error(t, err, "400 should be an error") } @@ -633,7 +633,7 @@ func TestPatchAgent_404ReturnsError(t *testing.T) { req := &PatchAgentRequest{} _, err := client.PatchAgent( - t.Context(), "no-such-agent", req, "2025-11-15-preview", + t.Context(), "no-such-agent", req, "v1", ) require.Error(t, err, "404 should be an error") } @@ -649,7 +649,7 @@ func TestPatchAgent_500ReturnsError(t *testing.T) { req := &PatchAgentRequest{} _, err := client.PatchAgent( - t.Context(), "my-agent", req, "2025-11-15-preview", + t.Context(), "my-agent", req, "v1", ) require.Error(t, err, "500 should be an error") } diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/dataset_api/operations_test.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/dataset_api/operations_test.go index 64ec678fb29..aee5ca70aa2 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/dataset_api/operations_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/dataset_api/operations_test.go @@ -78,7 +78,7 @@ func TestCreateDataset_Success(t *testing.T) { Version: "v1", Format: "jsonl", Content: `{"input":"hello"}`, - }, "2025-11-15-preview") + }, "v1") require.NoError(t, err) assert.Equal(t, "/datasets", capturedPath) @@ -107,7 +107,7 @@ func TestGetDataset_Success(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.GetDataset(t.Context(), "golden", "v2", "2025-11-15-preview") + result, err := client.GetDataset(t.Context(), "golden", "v2", "v1") require.NoError(t, err) assert.Equal(t, "/datasets/golden/versions/v2", capturedPath) @@ -172,7 +172,7 @@ func TestGetDatasetCredential_Success(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.GetDatasetCredential(t.Context(), "golden", "v2", "2025-11-15-preview") + result, err := client.GetDatasetCredential(t.Context(), "golden", "v2", "v1") require.NoError(t, err) assert.Equal(t, "/datasets/golden/versions/v2/credentials", capturedPath) @@ -234,7 +234,7 @@ func TestGetDataset_NotFound(t *testing.T) { }) client, _ := newTestClient(t, handler) - _, err := client.GetDataset(t.Context(), "missing", "v1", "2025-11-15-preview") + _, err := client.GetDataset(t.Context(), "missing", "v1", "v1") require.Error(t, err) } diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go index 08d845303cb..3dbcc8b24c8 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go @@ -144,7 +144,7 @@ func TestCreateEvaluatorGenerationJob_Success(t *testing.T) { client, _ := newTestClient(t, handler) result, err := client.CreateEvaluatorGenerationJob( - t.Context(), &EvaluatorGenerationJobRequest{Name: "my-eval"}, "2025-11-15-preview", + t.Context(), &EvaluatorGenerationJobRequest{Name: "my-eval"}, "v1", ) require.NoError(t, err) @@ -175,7 +175,7 @@ func TestGetEvaluatorGenerationJob_Success(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.GetEvaluatorGenerationJob(t.Context(), "eval-op-456", "2025-11-15-preview") + result, err := client.GetEvaluatorGenerationJob(t.Context(), "eval-op-456", "v1") require.NoError(t, err) assert.Equal(t, "/evaluator_generation_jobs/eval-op-456", capturedPath) @@ -204,7 +204,7 @@ func TestCreateOpenAIEval_Success(t *testing.T) { client, _ := newTestClient(t, handler) result, err := client.CreateOpenAIEval( - t.Context(), &CreateOpenAIEvalRequest{Name: "smoke-core"}, "2025-11-15-preview", + t.Context(), &CreateOpenAIEvalRequest{Name: "smoke-core"}, "v1", ) require.NoError(t, err) @@ -236,7 +236,7 @@ func TestListOpenAIEvals_Success(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.ListOpenAIEvals(t.Context(), 10, "2025-11-15-preview") + result, err := client.ListOpenAIEvals(t.Context(), 10, "v1") require.NoError(t, err) assert.Equal(t, "10", capturedLimit) @@ -256,7 +256,7 @@ func TestListOpenAIEvals_ZeroLimit(t *testing.T) { }) client, _ := newTestClient(t, handler) - _, err := client.ListOpenAIEvals(t.Context(), 0, "2025-11-15-preview") + _, err := client.ListOpenAIEvals(t.Context(), 0, "v1") require.NoError(t, err) assert.False(t, hasLimitParam, "limit should not be set when 0") @@ -281,7 +281,7 @@ func TestGetOpenAIEval_Success(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.GetOpenAIEval(t.Context(), "eval-001", "2025-11-15-preview") + result, err := client.GetOpenAIEval(t.Context(), "eval-001", "v1") require.NoError(t, err) assert.Equal(t, "/openai/evals/eval-001", capturedPath) @@ -310,7 +310,7 @@ func TestCreateOpenAIEvalRun_Success(t *testing.T) { result, err := client.CreateOpenAIEvalRun( t.Context(), "eval-001", &CreateOpenAIEvalRunRequest{ Metadata: map[string]string{"agent": "a"}, - }, "2025-11-15-preview", + }, "v1", ) require.NoError(t, err) @@ -338,7 +338,7 @@ func TestListOpenAIEvalRuns_Success(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.ListOpenAIEvalRuns(t.Context(), "eval-001", 5, "2025-11-15-preview") + result, err := client.ListOpenAIEvalRuns(t.Context(), "eval-001", 5, "v1") require.NoError(t, err) assert.Equal(t, "/openai/evals/eval-001/runs", capturedPath) @@ -365,7 +365,7 @@ func TestGetOpenAIEvalRun_Success(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.GetOpenAIEvalRun(t.Context(), "eval-001", "run-001", "2025-11-15-preview") + result, err := client.GetOpenAIEvalRun(t.Context(), "eval-001", "run-001", "v1") require.NoError(t, err) assert.Equal(t, "/openai/evals/eval-001/runs/run-001", capturedPath) @@ -384,7 +384,7 @@ func TestDoRequest_ServerError(t *testing.T) { }) client, _ := newTestClient(t, handler) - _, err := client.CreateOpenAIEval(t.Context(), &CreateOpenAIEvalRequest{}, "2025-11-15-preview") + _, err := client.CreateOpenAIEval(t.Context(), &CreateOpenAIEvalRequest{}, "v1") assert.Error(t, err) } @@ -396,7 +396,7 @@ func TestDoRequest_EmptyBody(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.ListOpenAIEvals(t.Context(), 0, "2025-11-15-preview") + result, err := client.ListOpenAIEvals(t.Context(), 0, "v1") require.NoError(t, err) assert.Empty(t, result.Data) } @@ -414,9 +414,9 @@ func TestDoRequest_APIVersionInQuery(t *testing.T) { }) client, _ := newTestClient(t, handler) - _, err := client.GetOpenAIEval(t.Context(), "eval-1", "2025-11-15-preview") + _, err := client.GetOpenAIEval(t.Context(), "eval-1", "v1") require.NoError(t, err) - assert.Equal(t, "2025-11-15-preview", capturedAPIVersion) + assert.Equal(t, "v1", capturedAPIVersion) } func TestDoRequest_RequestBodySent(t *testing.T) { diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/existence_test.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/existence_test.go index a0dc1d2f17a..a8f15c87356 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/existence_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/existence_test.go @@ -55,7 +55,7 @@ func TestAgentExists(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - exists, err := AgentExists(t.Context(), fakeAgentGetter{err: tt.err}, "my-agent", "2025-11-15-preview") + exists, err := AgentExists(t.Context(), fakeAgentGetter{err: tt.err}, "my-agent", "v1") if tt.wantErr { if err == nil { t.Fatal("expected error") diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/azure/foundry_projects_client.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/azure/foundry_projects_client.go index 9bcbafc02e4..d7435d57815 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/azure/foundry_projects_client.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/azure/foundry_projects_client.go @@ -70,7 +70,7 @@ func NewFoundryProjectsClient( return &FoundryProjectsClient{ baseEndpoint: baseEndpoint, baseOriginURL: parsedBase, - apiVersion: "2025-11-15-preview", + apiVersion: "v1", pipeline: pipeline, }, nil } diff --git a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go index 38e5520f743..6c392075cb9 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go +++ b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go @@ -48,7 +48,7 @@ import ( // Reference implementation // agentAPIVersion is the API version used for agent management operations. -const agentAPIVersion = "2025-11-15-preview" +const agentAPIVersion = "v1" // displayableProtocolEntry defines a protocol that produces user-visible invocation endpoints. type displayableProtocolEntry struct { From 90aa78871a726a3700e2b70d52678f6f3800c1f7 Mon Sep 17 00:00:00 2001 From: Glenn Harper Date: Tue, 26 May 2026 17:02:29 -0400 Subject: [PATCH 4/6] fix(ai-agents): consolidate endpoint api version Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../internal/cmd/agent_context.go | 8 +------ .../azure.ai.agents/internal/cmd/invoke.go | 10 ++++---- .../internal/cmd/invoke_test.go | 4 ++-- .../azure.ai.agents/internal/cmd/session.go | 8 +++---- .../internal/project/service_target_agent.go | 23 +++++++++++-------- 5 files changed, 25 insertions(+), 28 deletions(-) diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go index a20636c6d7c..4f147226cea 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_context.go @@ -19,13 +19,7 @@ import ( ) // DefaultAgentAPIVersion is the default API version for agent operations. -const DefaultAgentAPIVersion = "v1" - -// AgentEndpointAPIVersion is the API version for hosted agent endpoint protocol and session requests. -const AgentEndpointAPIVersion = agent_api.AgentEndpointAPIVersion - -// ConversationsAPIVersion is the API version used by the Foundry Conversations protocol. -const ConversationsAPIVersion = "v1" +const DefaultAgentAPIVersion = agent_api.AgentEndpointAPIVersion // AgentContext holds the common properties of a hosted agent. type AgentContext struct { diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go index d44b52a96ce..58612503c80 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go @@ -600,7 +600,7 @@ func (rc *remoteContext) nextStepName() string { // and avoid unnecessary token round-trips on invalid input. Callers must close // rc.azdClient when non-nil. func (a *InvokeAction) resolveRemoteContext(ctx context.Context) (*remoteContext, error) { - rc := &remoteContext{apiVersion: AgentEndpointAPIVersion, version: a.flags.version} + rc := &remoteContext{apiVersion: DefaultAgentAPIVersion, version: a.flags.version} if a.endpoint != nil { rc.name = a.endpoint.AgentName @@ -703,7 +703,7 @@ func (a *InvokeAction) resolveRemoteSessionID(ctx context.Context, rc *remoteCon apiVersion := rc.apiVersion if apiVersion == "" { - apiVersion = AgentEndpointAPIVersion + apiVersion = DefaultAgentAPIVersion } session, err := createInvokeVersionSession(ctx, rc.projectEndpoint, rc.name, rc.version, apiVersion) if err != nil { @@ -731,7 +731,7 @@ func createInvokeVersionSessionImpl( apiVersion string, ) (*agent_api.AgentSessionResource, error) { if apiVersion == "" { - apiVersion = AgentEndpointAPIVersion + apiVersion = DefaultAgentAPIVersion } credential, err := newAgentCredential() @@ -1315,7 +1315,7 @@ func handleInvocationLRO( } if pollURL == "" { if apiVersion == "" { - apiVersion = AgentEndpointAPIVersion + apiVersion = DefaultAgentAPIVersion } pollURL = fmt.Sprintf( "%s/agents/%s/endpoint/protocols/invocations/%s?api-version=%s", @@ -1416,7 +1416,7 @@ func createConversation( ) (string, error) { convURL := fmt.Sprintf( "%s/agents/%s/endpoint/protocols/openai/conversations?api-version=%s", - projectEndpoint, agentName, ConversationsAPIVersion, + projectEndpoint, agentName, DefaultAgentAPIVersion, ) req, err := http.NewRequestWithContext(ctx, http.MethodPost, convURL, bytes.NewReader([]byte("{}"))) if err != nil { diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go index 5b506d6bbf2..f6e3a945e9f 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go @@ -1761,8 +1761,8 @@ func TestCreateConversation(t *testing.T) { } // Verify api-version query parameter uses the constant - if got := r.URL.Query().Get("api-version"); got != ConversationsAPIVersion { - t.Errorf("api-version = %q, want %q", got, ConversationsAPIVersion) + if got := r.URL.Query().Get("api-version"); got != DefaultAgentAPIVersion { + t.Errorf("api-version = %q, want %q", got, DefaultAgentAPIVersion) } // Verify auth header diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/session.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/session.go index 479079be351..2eeb51e00e7 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/session.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/session.go @@ -273,7 +273,7 @@ func (a *SessionCreateAction) Run(ctx context.Context) error { ctx, sc.agentName, request, - AgentEndpointAPIVersion, + DefaultAgentAPIVersion, a.flags.sessionRequestOptionsWithSessionKey(a.flags.isolationKey), ) if err != nil { @@ -359,7 +359,7 @@ func (a *SessionShowAction) Run(ctx context.Context) error { ctx, sc.agentName, a.sessionID, - AgentEndpointAPIVersion, + DefaultAgentAPIVersion, a.flags.sessionRequestOptions(), ) if err != nil { @@ -462,7 +462,7 @@ func (a *SessionDeleteAction) Run(ctx context.Context) error { ctx, sc.agentName, a.sessionID, - AgentEndpointAPIVersion, + DefaultAgentAPIVersion, a.flags.sessionRequestOptionsWithSessionKey(a.flags.isolationKey), ) if err != nil { @@ -597,7 +597,7 @@ func (a *SessionListAction) Run(ctx context.Context) error { sc.agentName, limit, token, - AgentEndpointAPIVersion, + DefaultAgentAPIVersion, a.flags.sessionRequestOptions(), ) if err != nil { diff --git a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go index 6c392075cb9..a0246141add 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go +++ b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go @@ -47,9 +47,6 @@ import ( // Reference implementation -// agentAPIVersion is the API version used for agent management operations. -const agentAPIVersion = "v1" - // displayableProtocolEntry defines a protocol that produces user-visible invocation endpoints. type displayableProtocolEntry struct { Protocol agent_api.AgentProtocol @@ -899,7 +896,7 @@ func writeExistingAgentVersionWarningIfPresent( agentChecker agents.AgentChecker, agentName string, ) bool { - exists, err := agents.AgentExists(ctx, agentChecker, agentName, agentAPIVersion) + exists, err := agents.AgentExists(ctx, agentChecker, agentName, agent_api.AgentEndpointAPIVersion) if err != nil { log.Printf("existing agent name check skipped for %q: %v", agentName, err) return false @@ -1030,7 +1027,7 @@ func (p *AgentServiceTargetProvider) patchAgentEndpointFields( AgentCard: agentCard, } - _, err := agentClient.PatchAgent(ctx, agentName, patchRequest, agentAPIVersion) + _, err := agentClient.PatchAgent(ctx, agentName, patchRequest, agent_api.AgentEndpointAPIVersion) if err != nil { return exterrors.ServiceFromAzure(err, exterrors.OpCreateAgent) } @@ -1518,7 +1515,7 @@ func (p *AgentServiceTargetProvider) deployHostedCodeAgent( // Check if agent already exists (GET /agents/{name}) progress("Creating agent") - _, getErr := agentClient.GetAgent(ctx, agentDef.Name, agentAPIVersion) + _, getErr := agentClient.GetAgent(ctx, agentDef.Name, agent_api.AgentEndpointAPIVersion) var agentResp *agent_api.AgentObject if getErr != nil { @@ -1528,7 +1525,9 @@ func (p *AgentServiceTargetProvider) deployHostedCodeAgent( } // Agent doesn't exist — create fmt.Fprintf(os.Stderr, "Creating new agent: %s\n", agentDef.Name) - agentResp, err = agentClient.CreateAgentFromZip(ctx, agentDef.Name, versionRequest, zipData, sha256Hex, agentAPIVersion) + agentResp, err = agentClient.CreateAgentFromZip( + ctx, agentDef.Name, versionRequest, zipData, sha256Hex, agent_api.AgentEndpointAPIVersion, + ) if err != nil { return nil, exterrors.Internal( exterrors.CodeAgentCreateFailed, @@ -1538,7 +1537,9 @@ func (p *AgentServiceTargetProvider) deployHostedCodeAgent( } else { // Agent exists — update writeExistingAgentVersionWarning(agentDef.Name) - agentResp, err = agentClient.UpdateAgentFromZip(ctx, agentDef.Name, versionRequest, zipData, sha256Hex, agentAPIVersion) + agentResp, err = agentClient.UpdateAgentFromZip( + ctx, agentDef.Name, versionRequest, zipData, sha256Hex, agent_api.AgentEndpointAPIVersion, + ) if err != nil { return nil, exterrors.Internal( exterrors.CodeAgentCreateFailed, @@ -1850,7 +1851,7 @@ func (p *AgentServiceTargetProvider) waitForAgentActive( attempt++ progress(fmt.Sprintf("Polling agent status (%d/%d)", attempt, maxAttempts)) - versionResp, err := agentClient.GetAgentVersion(ctx, agentName, version, agentAPIVersion) + versionResp, err := agentClient.GetAgentVersion(ctx, agentName, version, agent_api.AgentEndpointAPIVersion) if err != nil { fmt.Fprintf(os.Stderr, " Warning: poll failed: %s\n", err) // Reset counters on error — don't count transient failures @@ -1923,7 +1924,9 @@ func (p *AgentServiceTargetProvider) createAgent( } // Create agent version - agentVersionResponse, err := agentClient.CreateAgentVersion(ctx, request.Name, versionRequest, agentAPIVersion) + agentVersionResponse, err := agentClient.CreateAgentVersion( + ctx, request.Name, versionRequest, agent_api.AgentEndpointAPIVersion, + ) if err != nil { return nil, exterrors.ServiceFromAzure(err, exterrors.OpCreateAgent) } From 1cfaf6227264c78a34279b9767c9231bcd31f1d8 Mon Sep 17 00:00:00 2001 From: Glenn Harper Date: Tue, 26 May 2026 21:38:12 -0400 Subject: [PATCH 5/6] update openai routes --- .../internal/cmd/agent_endpoint.go | 17 +++++------ .../internal/cmd/agent_endpoint_test.go | 29 +++++++------------ .../azure.ai.agents/internal/cmd/invoke.go | 8 ++--- .../internal/cmd/invoke_test.go | 8 ++--- .../azure.ai.agents/internal/cmd/show_test.go | 2 +- .../pkg/agents/eval_api/operations.go | 26 ++++++++--------- .../pkg/agents/eval_api/operations_test.go | 14 ++++----- .../internal/project/service_target_agent.go | 10 ++++--- .../project/service_target_agent_test.go | 14 ++++----- 9 files changed, 60 insertions(+), 68 deletions(-) diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint.go index 9e590a65217..1ef1d92df69 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint.go @@ -27,9 +27,9 @@ const agentEndpointHint = "run `azd ai agent show` to see the agent endpoint URL // // [1] project name (URL-escaped), // [2] agent name (URL-escaped), -// [3] protocol tail ("invocations" or "openai/responses"). +// [3] protocol tail ("invocations" or "openai/v1/responses"). var agentEndpointPathRegex = regexp.MustCompile( - `^/api/projects/([^/]+)/agents/([^/]+)/endpoint/protocols/(invocations|openai/responses)/?$`, + `^/api/projects/([^/]+)/agents/([^/]+)/endpoint/protocols/(invocations|openai/v1/responses)/?$`, ) // parsedAgentEndpoint describes a deployed agent invocation endpoint. @@ -47,7 +47,7 @@ type parsedAgentEndpoint struct { // Accepted shapes: // // https://.services.ai.azure.com/api/projects//agents//endpoint/protocols/invocations[?api-version=…] -// https://.services.ai.azure.com/api/projects//agents//endpoint/protocols/openai/responses[?api-version=…] +// https://.services.ai.azure.com/api/projects//agents//endpoint/protocols/openai/v1/responses // // The host must be a `*.services.ai.azure.com` Foundry host. The path must include the // protocol-specific suffix; the protocol is derived from the URL. @@ -131,7 +131,7 @@ func parseAgentEndpoint(rawURL string) (*parsedAgentEndpoint, error) { switch protocolTail { case "invocations": protocol = agent_api.AgentProtocolInvocations - case "openai/responses": + case "openai/v1/responses": protocol = agent_api.AgentProtocolResponses } @@ -160,12 +160,11 @@ func parseAgentEndpoint(rawURL string) (*parsedAgentEndpoint, error) { }, nil } -// buildResponsesURL builds the Foundry "openai/responses" protocol URL for an agent. -// apiVersion is URL-encoded so unusual characters cannot break out of the query value. -func buildResponsesURL(projectEndpoint, agentName, apiVersion string) string { +// buildResponsesURL builds the Foundry "openai/v1/responses" protocol URL for an agent. +func buildResponsesURL(projectEndpoint, agentName string) string { return fmt.Sprintf( - "%s/agents/%s/endpoint/protocols/openai/responses?api-version=%s", - projectEndpoint, agentName, url.QueryEscape(apiVersion), + "%s/agents/%s/endpoint/protocols/openai/v1/responses", + projectEndpoint, agentName, ) } diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint_test.go index 001d5154ba9..fb553357c6a 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/agent_endpoint_test.go @@ -38,12 +38,11 @@ func TestParseAgentEndpoint(t *testing.T) { wantProto: agent_api.AgentProtocolInvocations, }, { - name: "responses (openai/responses)", - raw: "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/responses?api-version=v1", - wantProj: "https://acct.services.ai.azure.com/api/projects/proj", - wantAgent: "echo", - wantProto: agent_api.AgentProtocolResponses, - wantAPIVer: "v1", + name: "responses (openai/v1/responses)", + raw: "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/v1/responses", + wantProj: "https://acct.services.ai.azure.com/api/projects/proj", + wantAgent: "echo", + wantProto: agent_api.AgentProtocolResponses, }, { name: "trailing slash tolerated", @@ -186,27 +185,21 @@ func TestParseAgentEndpoint_RejectsInvalidAgentNames(t *testing.T) { } } -// TestBuildResponsesURL verifies that the responses URL builder uses the parsed -// api-version (rather than the default fallback) and URL-encodes it. +// TestBuildResponsesURL verifies that the responses URL builder uses the +// openai/v1 path with no api-version query parameter. func TestBuildResponsesURL(t *testing.T) { t.Parallel() parsed, err := parseAgentEndpoint( - "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/responses?api-version=custom-version", + "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/v1/responses", ) if err != nil { t.Fatalf("parseAgentEndpoint: %v", err) } - got := buildResponsesURL(parsed.ProjectEndpoint, parsed.AgentName, parsed.APIVersion) - want := "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/responses?api-version=custom-version" + got := buildResponsesURL(parsed.ProjectEndpoint, parsed.AgentName) + want := "https://acct.services.ai.azure.com/api/projects/proj/agents/echo/endpoint/protocols/openai/v1/responses" if got != want { t.Errorf("buildResponsesURL = %q, want %q", got, want) } - - // api-version must be query-escaped so unusual characters cannot break out. - gotEscaped := buildResponsesURL("https://acct.services.ai.azure.com/api/projects/proj", "echo", "weird value&x=1") - if !strings.Contains(gotEscaped, "api-version=weird+value%26x%3D1") { - t.Errorf("buildResponsesURL did not escape api-version: %q", gotEscaped) - } } // TestBuildInvocationsURL verifies that the invocations URL builder propagates @@ -265,7 +258,7 @@ func TestResolveRemoteContext_EphemeralMode(t *testing.T) { { name: "api-version omitted falls back to default", raw: "https://acct.services.ai.azure.com/api/projects/proj/agents/" + - "hello/endpoint/protocols/openai/responses", + "hello/endpoint/protocols/openai/v1/responses", wantAPIVersion: "v1", wantName: "hello", wantProject: "https://acct.services.ai.azure.com/api/projects/proj", diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go index 58612503c80..d55569ffe41 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go @@ -110,7 +110,7 @@ and --chat-isolation-key on each remote invoke.`, # Invoke a deployed agent from any directory using the endpoint URL shown by 'azd ai agent show' azd ai agent invoke \ - --agent-endpoint https://.services.ai.azure.com/api/projects//agents//endpoint/protocols/openai/responses?api-version=v1 \ + --agent-endpoint https://.services.ai.azure.com/api/projects//agents//endpoint/protocols/openai/v1/responses \ "Hello!"`, Args: cobra.RangeArgs(0, 2), RunE: func(cmd *cobra.Command, args []string) error { @@ -882,7 +882,7 @@ func (a *InvokeAction) responsesRemote(ctx context.Context) error { return fmt.Errorf("failed to marshal request: %w", err) } - respURL := buildResponsesURL(rc.projectEndpoint, rc.name, rc.apiVersion) + respURL := buildResponsesURL(rc.projectEndpoint, rc.name) req, err := http.NewRequestWithContext(ctx, http.MethodPost, respURL, bytes.NewReader(payload)) if err != nil { return fmt.Errorf("failed to create request: %w", err) @@ -1415,8 +1415,8 @@ func createConversation( options *agent_api.SessionRequestOptions, ) (string, error) { convURL := fmt.Sprintf( - "%s/agents/%s/endpoint/protocols/openai/conversations?api-version=%s", - projectEndpoint, agentName, DefaultAgentAPIVersion, + "%s/agents/%s/endpoint/protocols/openai/v1/conversations", + projectEndpoint, agentName, ) req, err := http.NewRequestWithContext(ctx, http.MethodPost, convURL, bytes.NewReader([]byte("{}"))) if err != nil { diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go index f6e3a945e9f..6ef92f70774 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go @@ -1755,14 +1755,14 @@ func TestCreateConversation(t *testing.T) { // Verify path includes the agent name and conversations endpoint wantPath := "/agents/" + tt.agentName + - "/endpoint/protocols/openai/conversations" + "/endpoint/protocols/openai/v1/conversations" if r.URL.Path != wantPath { t.Errorf("path = %s, want %s", r.URL.Path, wantPath) } - // Verify api-version query parameter uses the constant - if got := r.URL.Query().Get("api-version"); got != DefaultAgentAPIVersion { - t.Errorf("api-version = %q, want %q", got, DefaultAgentAPIVersion) + // OpenAI v1 routes should not include an api-version query parameter. + if got := r.URL.Query().Get("api-version"); got != "" { + t.Errorf("api-version = %q, want empty", got) } // Verify auth header diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/show_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/show_test.go index 9828055f4e9..2bf2d662e00 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/show_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/show_test.go @@ -158,7 +158,7 @@ func TestPrintAgentVersionJSON_Format(t *testing.T) { AgentVersionObject: version, PlaygroundURL: "https://ai.azure.com/nextgen/r/test/build/agents/test-agent/build?version=2", Endpoints: map[string]string{ - "Responses": "https://acct.services.ai.azure.com/api/projects/proj/agents/test-agent/endpoint/protocols/openai/responses?api-version=v1", + "Responses": "https://acct.services.ai.azure.com/api/projects/proj/agents/test-agent/endpoint/protocols/openai/v1/responses", }, } diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations.go index 8c661cadd13..d6042e19ccf 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations.go @@ -29,7 +29,7 @@ const ( pathEvaluatorGenerationJobs = "/evaluator_generation_jobs" pathEvaluators = "/evaluators" pathDatasets = "/datasets" - pathOpenAIEvals = "/openai/evals" + pathOpenAIEvals = "/openai/v1/evals" ) // EvalClient provides methods for interacting with the Azure AI eval APIs. @@ -145,25 +145,25 @@ func (c *EvalClient) GetEvaluatorRaw( func (c *EvalClient) CreateOpenAIEval( ctx context.Context, request *CreateOpenAIEvalRequest, - apiVersion string, + _ string, ) (*OpenAIEval, error) { - return doRequestTyped[OpenAIEval](c, ctx, http.MethodPost, pathOpenAIEvals, nil, request, apiVersion) + return doRequestTyped[OpenAIEval](c, ctx, http.MethodPost, pathOpenAIEvals, nil, request, "") } // ListOpenAIEvals lists OpenAI eval definitions. -func (c *EvalClient) ListOpenAIEvals(ctx context.Context, limit int, apiVersion string) (*OpenAIEvalList, error) { +func (c *EvalClient) ListOpenAIEvals(ctx context.Context, limit int, _ string) (*OpenAIEvalList, error) { query := map[string]string{} if limit > 0 { query["limit"] = strconv.Itoa(limit) } - return doRequestTyped[OpenAIEvalList](c, ctx, http.MethodGet, pathOpenAIEvals, query, nil, apiVersion) + return doRequestTyped[OpenAIEvalList](c, ctx, http.MethodGet, pathOpenAIEvals, query, nil, "") } // GetOpenAIEval gets an OpenAI eval definition. -func (c *EvalClient) GetOpenAIEval(ctx context.Context, evalID string, apiVersion string) (*OpenAIEval, error) { +func (c *EvalClient) GetOpenAIEval(ctx context.Context, evalID string, _ string) (*OpenAIEval, error) { path := pathOpenAIEvals + "/" + url.PathEscape(evalID) - return doRequestTyped[OpenAIEval](c, ctx, http.MethodGet, path, nil, nil, apiVersion) + return doRequestTyped[OpenAIEval](c, ctx, http.MethodGet, path, nil, nil, "") } // CreateOpenAIEvalRun starts a run for an OpenAI eval definition. @@ -171,10 +171,10 @@ func (c *EvalClient) CreateOpenAIEvalRun( ctx context.Context, evalID string, request *CreateOpenAIEvalRunRequest, - apiVersion string, + _ string, ) (*OpenAIEvalRun, error) { path := fmt.Sprintf("%s/%s/runs", pathOpenAIEvals, url.PathEscape(evalID)) - return doRequestTyped[OpenAIEvalRun](c, ctx, http.MethodPost, path, nil, request, apiVersion) + return doRequestTyped[OpenAIEvalRun](c, ctx, http.MethodPost, path, nil, request, "") } // ListOpenAIEvalRuns lists runs for an OpenAI eval definition. @@ -182,7 +182,7 @@ func (c *EvalClient) ListOpenAIEvalRuns( ctx context.Context, evalID string, limit int, - apiVersion string, + _ string, ) (*OpenAIEvalRunList, error) { query := map[string]string{} if limit > 0 { @@ -190,7 +190,7 @@ func (c *EvalClient) ListOpenAIEvalRuns( } path := fmt.Sprintf("%s/%s/runs", pathOpenAIEvals, url.PathEscape(evalID)) - return doRequestTyped[OpenAIEvalRunList](c, ctx, http.MethodGet, path, query, nil, apiVersion) + return doRequestTyped[OpenAIEvalRunList](c, ctx, http.MethodGet, path, query, nil, "") } // GetOpenAIEvalRun gets a run for an OpenAI eval definition. @@ -198,10 +198,10 @@ func (c *EvalClient) GetOpenAIEvalRun( ctx context.Context, evalID string, runID string, - apiVersion string, + _ string, ) (*OpenAIEvalRun, error) { path := fmt.Sprintf("%s/%s/runs/%s", pathOpenAIEvals, url.PathEscape(evalID), url.PathEscape(runID)) - return doRequestTyped[OpenAIEvalRun](c, ctx, http.MethodGet, path, nil, nil, apiVersion) + return doRequestTyped[OpenAIEvalRun](c, ctx, http.MethodGet, path, nil, nil, "") } func (c *EvalClient) doRequest( diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go index 3dbcc8b24c8..521714315f1 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go @@ -208,7 +208,7 @@ func TestCreateOpenAIEval_Success(t *testing.T) { ) require.NoError(t, err) - assert.Equal(t, "/openai/evals", capturedPath) + assert.Equal(t, "/openai/v1/evals", capturedPath) assert.Equal(t, "eval-001", result.ID) } @@ -284,7 +284,7 @@ func TestGetOpenAIEval_Success(t *testing.T) { result, err := client.GetOpenAIEval(t.Context(), "eval-001", "v1") require.NoError(t, err) - assert.Equal(t, "/openai/evals/eval-001", capturedPath) + assert.Equal(t, "/openai/v1/evals/eval-001", capturedPath) assert.Equal(t, "smoke-core", result.Name) } @@ -314,7 +314,7 @@ func TestCreateOpenAIEvalRun_Success(t *testing.T) { ) require.NoError(t, err) - assert.Equal(t, "/openai/evals/eval-001/runs", capturedPath) + assert.Equal(t, "/openai/v1/evals/eval-001/runs", capturedPath) assert.Equal(t, "run-001", result.ID) } @@ -341,7 +341,7 @@ func TestListOpenAIEvalRuns_Success(t *testing.T) { result, err := client.ListOpenAIEvalRuns(t.Context(), "eval-001", 5, "v1") require.NoError(t, err) - assert.Equal(t, "/openai/evals/eval-001/runs", capturedPath) + assert.Equal(t, "/openai/v1/evals/eval-001/runs", capturedPath) assert.Equal(t, "5", capturedLimit) assert.Len(t, result.Data, 1) } @@ -368,7 +368,7 @@ func TestGetOpenAIEvalRun_Success(t *testing.T) { result, err := client.GetOpenAIEvalRun(t.Context(), "eval-001", "run-001", "v1") require.NoError(t, err) - assert.Equal(t, "/openai/evals/eval-001/runs/run-001", capturedPath) + assert.Equal(t, "/openai/v1/evals/eval-001/runs/run-001", capturedPath) assert.Equal(t, "completed", result.Status) } @@ -401,7 +401,7 @@ func TestDoRequest_EmptyBody(t *testing.T) { assert.Empty(t, result.Data) } -func TestDoRequest_APIVersionInQuery(t *testing.T) { +func TestDoRequest_NoAPIVersionInOpenAIQuery(t *testing.T) { t.Parallel() var capturedAPIVersion string @@ -416,7 +416,7 @@ func TestDoRequest_APIVersionInQuery(t *testing.T) { client, _ := newTestClient(t, handler) _, err := client.GetOpenAIEval(t.Context(), "eval-1", "v1") require.NoError(t, err) - assert.Equal(t, "v1", capturedAPIVersion) + assert.Equal(t, "", capturedAPIVersion) } func TestDoRequest_RequestBodySent(t *testing.T) { diff --git a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go index a0246141add..6d56d8a1832 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go +++ b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent.go @@ -57,7 +57,7 @@ type displayableProtocolEntry struct { // displayableProtocols is the single source of truth for protocols that produce // user-facing invocation endpoints and env vars. var displayableProtocols = []displayableProtocolEntry{ - {Protocol: agent_api.AgentProtocolResponses, URLPath: "openai/responses", EnvSuffix: "RESPONSES"}, + {Protocol: agent_api.AgentProtocolResponses, URLPath: "openai/v1/responses", EnvSuffix: "RESPONSES"}, {Protocol: agent_api.AgentProtocolInvocations, URLPath: "invocations", EnvSuffix: "INVOCATIONS"}, } @@ -1768,11 +1768,13 @@ func agentInvocationEndpoints( if path == "" { continue } + endpointURL := fmt.Sprintf("%s/agents/%s/endpoint/protocols/%s", projectEndpoint, agentName, path) + if !strings.HasPrefix(path, "openai/") { + endpointURL += fmt.Sprintf("?api-version=%s", agent_api.AgentEndpointAPIVersion) + } endpoints = append(endpoints, protocolEndpointInfo{ Protocol: p.Protocol, - URL: fmt.Sprintf( - "%s/agents/%s/endpoint/protocols/%s?api-version=%s", - projectEndpoint, agentName, path, agent_api.AgentEndpointAPIVersion), + URL: endpointURL, }) } return endpoints diff --git a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent_test.go b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent_test.go index 193148efc1b..0a4364c9e42 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/project/service_target_agent_test.go @@ -459,7 +459,7 @@ func TestRegisterAgentEnvironmentVariables(t *testing.T) { require.Contains(t, envStub.values, "AGENT_MY_SVC_RESPONSES_ENDPOINT") require.Equal( t, - "https://proj.azure.com/agents/my-agent/endpoint/protocols/openai/responses?api-version=v1", + "https://proj.azure.com/agents/my-agent/endpoint/protocols/openai/v1/responses", envStub.values["AGENT_MY_SVC_RESPONSES_ENDPOINT"], ) require.Contains(t, envStub.values, "AGENT_MY_SVC_INVOCATIONS_ENDPOINT") @@ -560,7 +560,7 @@ func TestProtocolPath(t *testing.T) { protocol string expected string }{ - {"responses", "responses", "openai/responses"}, + {"responses", "responses", "openai/v1/responses"}, {"invocations", "invocations", "invocations"}, {"activity_protocol excluded", "activity_protocol", ""}, {"unknown excluded", "unknown_proto", ""}, @@ -594,7 +594,7 @@ func TestAgentInvocationEndpoints(t *testing.T) { expected: []protocolEndpointInfo{ { Protocol: "responses", - URL: baseURL + "openai/responses?api-version=v1", + URL: baseURL + "openai/v1/responses", }, }, }, @@ -620,7 +620,7 @@ func TestAgentInvocationEndpoints(t *testing.T) { expected: []protocolEndpointInfo{ { Protocol: "responses", - URL: baseURL + "openai/responses?api-version=v1", + URL: baseURL + "openai/v1/responses", }, { Protocol: "invocations", @@ -672,8 +672,7 @@ func TestDeployArtifacts_HostedAgent_ProtocolEndpoints(t *testing.T) { require.Len(t, artifacts, 2) wantResponses := ep + - "/agents/test-agent/endpoint/protocols/openai/responses" + - "?api-version=v1" + "/agents/test-agent/endpoint/protocols/openai/v1/responses" require.Equal(t, wantResponses, artifacts[0].Location) require.Equal(t, "Agent endpoint (responses)", artifacts[0].Metadata["label"]) require.Empty(t, artifacts[0].Metadata["note"], @@ -706,8 +705,7 @@ func TestDeployArtifacts_ResponsesProtocol(t *testing.T) { require.Len(t, artifacts, 1) wantURL := ep + - "/agents/prompt-agent/endpoint/protocols/openai/responses" + - "?api-version=v1" + "/agents/prompt-agent/endpoint/protocols/openai/v1/responses" require.Equal(t, wantURL, artifacts[0].Location) require.Equal(t, "Agent endpoint (responses)", artifacts[0].Metadata["label"]) require.Contains(t, artifacts[0].Metadata["note"], "invoking the agent") From 8dd49df880eb22c54ff7bdb6dd4451aacc94a13e Mon Sep 17 00:00:00 2001 From: Glenn Harper Date: Wed, 27 May 2026 15:23:12 -0400 Subject: [PATCH 6/6] Remove unused OpenAI eval API version parameters --- .../azure.ai.agents/internal/cmd/eval_list.go | 4 ++-- .../azure.ai.agents/internal/cmd/eval_run.go | 5 ++--- .../azure.ai.agents/internal/cmd/eval_show.go | 6 +++--- .../pkg/agents/eval_api/operations.go | 8 ++------ .../pkg/agents/eval_api/operations_test.go | 20 +++++++++---------- 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_list.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_list.go index 51dc7fe9a54..5861f0a2e28 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_list.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_list.go @@ -62,7 +62,7 @@ func runEvalList(ctx context.Context, flags *evalListFlags) error { activeEvalID = state.EvalID } - resp, err := resolved.evalClient.ListOpenAIEvals(ctx, flags.limit, DefaultAgentAPIVersion) + resp, err := resolved.evalClient.ListOpenAIEvals(ctx, flags.limit) if err != nil { return fmt.Errorf("failed to list evals: %w", err) } @@ -81,7 +81,7 @@ func runEvalList(ctx context.Context, flags *evalListFlags) error { defer wg.Done() sem <- struct{}{} defer func() { <-sem }() - runs, err := resolved.evalClient.ListOpenAIEvalRuns(ctx, evalID, 10, DefaultAgentAPIVersion) + runs, err := resolved.evalClient.ListOpenAIEvalRuns(ctx, evalID, 10) if err != nil || runs == nil { return } diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_run.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_run.go index 28361af71de..64015942165 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_run.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_run.go @@ -109,7 +109,7 @@ func runEvalRun(ctx context.Context, flags *evalRunFlags, noPrompt bool) error { if evalID == "" { created, err := resolved.evalClient.CreateOpenAIEval( - ctx, buildOpenAIEvalRequest(evalCfg), DefaultAgentAPIVersion, + ctx, buildOpenAIEvalRequest(evalCfg), ) if err != nil { return fmt.Errorf("failed to create eval: %w", err) @@ -154,7 +154,6 @@ func runEvalRun(ctx context.Context, flags *evalRunFlags, noPrompt bool) error { ctx, evalID, runReq, - DefaultAgentAPIVersion, ) if err != nil { return fmt.Errorf("failed to start eval run: %w", err) @@ -255,7 +254,7 @@ func pollEvalRun( case <-time.After(defaultEvalPollInterval): } - run, err := client.GetOpenAIEvalRun(ctx, evalID, runID, DefaultAgentAPIVersion) + run, err := client.GetOpenAIEvalRun(ctx, evalID, runID) if err != nil { if agents.IsTransientError(err) { consecutiveTransient++ diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_show.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_show.go index 22e77f4ad88..a7b7a76cffc 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_show.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/eval_show.go @@ -71,7 +71,7 @@ func runEvalShow(ctx context.Context, evalID string, flags *evalShowFlags) error } if flags.evalRunID != "" { - run, err := resolved.evalClient.GetOpenAIEvalRun(ctx, evalID, flags.evalRunID, DefaultAgentAPIVersion) + run, err := resolved.evalClient.GetOpenAIEvalRun(ctx, evalID, flags.evalRunID) if err != nil { return fmt.Errorf("failed to get eval run: %w", err) } @@ -81,11 +81,11 @@ func runEvalShow(ctx context.Context, evalID string, flags *evalShowFlags) error return printEvalRunSummary(evalID, run) } - evalObj, err := resolved.evalClient.GetOpenAIEval(ctx, evalID, DefaultAgentAPIVersion) + evalObj, err := resolved.evalClient.GetOpenAIEval(ctx, evalID) if err != nil { return fmt.Errorf("failed to get eval: %w", err) } - runs, err := resolved.evalClient.ListOpenAIEvalRuns(ctx, evalID, flags.limit, DefaultAgentAPIVersion) + runs, err := resolved.evalClient.ListOpenAIEvalRuns(ctx, evalID, flags.limit) if err != nil { return fmt.Errorf("failed to list eval runs: %w", err) } diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations.go index d6042e19ccf..cfcfaa580c5 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations.go @@ -145,13 +145,12 @@ func (c *EvalClient) GetEvaluatorRaw( func (c *EvalClient) CreateOpenAIEval( ctx context.Context, request *CreateOpenAIEvalRequest, - _ string, ) (*OpenAIEval, error) { return doRequestTyped[OpenAIEval](c, ctx, http.MethodPost, pathOpenAIEvals, nil, request, "") } // ListOpenAIEvals lists OpenAI eval definitions. -func (c *EvalClient) ListOpenAIEvals(ctx context.Context, limit int, _ string) (*OpenAIEvalList, error) { +func (c *EvalClient) ListOpenAIEvals(ctx context.Context, limit int) (*OpenAIEvalList, error) { query := map[string]string{} if limit > 0 { query["limit"] = strconv.Itoa(limit) @@ -161,7 +160,7 @@ func (c *EvalClient) ListOpenAIEvals(ctx context.Context, limit int, _ string) ( } // GetOpenAIEval gets an OpenAI eval definition. -func (c *EvalClient) GetOpenAIEval(ctx context.Context, evalID string, _ string) (*OpenAIEval, error) { +func (c *EvalClient) GetOpenAIEval(ctx context.Context, evalID string) (*OpenAIEval, error) { path := pathOpenAIEvals + "/" + url.PathEscape(evalID) return doRequestTyped[OpenAIEval](c, ctx, http.MethodGet, path, nil, nil, "") } @@ -171,7 +170,6 @@ func (c *EvalClient) CreateOpenAIEvalRun( ctx context.Context, evalID string, request *CreateOpenAIEvalRunRequest, - _ string, ) (*OpenAIEvalRun, error) { path := fmt.Sprintf("%s/%s/runs", pathOpenAIEvals, url.PathEscape(evalID)) return doRequestTyped[OpenAIEvalRun](c, ctx, http.MethodPost, path, nil, request, "") @@ -182,7 +180,6 @@ func (c *EvalClient) ListOpenAIEvalRuns( ctx context.Context, evalID string, limit int, - _ string, ) (*OpenAIEvalRunList, error) { query := map[string]string{} if limit > 0 { @@ -198,7 +195,6 @@ func (c *EvalClient) GetOpenAIEvalRun( ctx context.Context, evalID string, runID string, - _ string, ) (*OpenAIEvalRun, error) { path := fmt.Sprintf("%s/%s/runs/%s", pathOpenAIEvals, url.PathEscape(evalID), url.PathEscape(runID)) return doRequestTyped[OpenAIEvalRun](c, ctx, http.MethodGet, path, nil, nil, "") diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go index 521714315f1..05b8aca73dd 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/eval_api/operations_test.go @@ -204,7 +204,7 @@ func TestCreateOpenAIEval_Success(t *testing.T) { client, _ := newTestClient(t, handler) result, err := client.CreateOpenAIEval( - t.Context(), &CreateOpenAIEvalRequest{Name: "smoke-core"}, "v1", + t.Context(), &CreateOpenAIEvalRequest{Name: "smoke-core"}, ) require.NoError(t, err) @@ -236,7 +236,7 @@ func TestListOpenAIEvals_Success(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.ListOpenAIEvals(t.Context(), 10, "v1") + result, err := client.ListOpenAIEvals(t.Context(), 10) require.NoError(t, err) assert.Equal(t, "10", capturedLimit) @@ -256,7 +256,7 @@ func TestListOpenAIEvals_ZeroLimit(t *testing.T) { }) client, _ := newTestClient(t, handler) - _, err := client.ListOpenAIEvals(t.Context(), 0, "v1") + _, err := client.ListOpenAIEvals(t.Context(), 0) require.NoError(t, err) assert.False(t, hasLimitParam, "limit should not be set when 0") @@ -281,7 +281,7 @@ func TestGetOpenAIEval_Success(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.GetOpenAIEval(t.Context(), "eval-001", "v1") + result, err := client.GetOpenAIEval(t.Context(), "eval-001") require.NoError(t, err) assert.Equal(t, "/openai/v1/evals/eval-001", capturedPath) @@ -310,7 +310,7 @@ func TestCreateOpenAIEvalRun_Success(t *testing.T) { result, err := client.CreateOpenAIEvalRun( t.Context(), "eval-001", &CreateOpenAIEvalRunRequest{ Metadata: map[string]string{"agent": "a"}, - }, "v1", + }, ) require.NoError(t, err) @@ -338,7 +338,7 @@ func TestListOpenAIEvalRuns_Success(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.ListOpenAIEvalRuns(t.Context(), "eval-001", 5, "v1") + result, err := client.ListOpenAIEvalRuns(t.Context(), "eval-001", 5) require.NoError(t, err) assert.Equal(t, "/openai/v1/evals/eval-001/runs", capturedPath) @@ -365,7 +365,7 @@ func TestGetOpenAIEvalRun_Success(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.GetOpenAIEvalRun(t.Context(), "eval-001", "run-001", "v1") + result, err := client.GetOpenAIEvalRun(t.Context(), "eval-001", "run-001") require.NoError(t, err) assert.Equal(t, "/openai/v1/evals/eval-001/runs/run-001", capturedPath) @@ -384,7 +384,7 @@ func TestDoRequest_ServerError(t *testing.T) { }) client, _ := newTestClient(t, handler) - _, err := client.CreateOpenAIEval(t.Context(), &CreateOpenAIEvalRequest{}, "v1") + _, err := client.CreateOpenAIEval(t.Context(), &CreateOpenAIEvalRequest{}) assert.Error(t, err) } @@ -396,7 +396,7 @@ func TestDoRequest_EmptyBody(t *testing.T) { }) client, _ := newTestClient(t, handler) - result, err := client.ListOpenAIEvals(t.Context(), 0, "v1") + result, err := client.ListOpenAIEvals(t.Context(), 0) require.NoError(t, err) assert.Empty(t, result.Data) } @@ -414,7 +414,7 @@ func TestDoRequest_NoAPIVersionInOpenAIQuery(t *testing.T) { }) client, _ := newTestClient(t, handler) - _, err := client.GetOpenAIEval(t.Context(), "eval-1", "v1") + _, err := client.GetOpenAIEval(t.Context(), "eval-1") require.NoError(t, err) assert.Equal(t, "", capturedAPIVersion) }