From 6278da37ece477e036b00f2059a71ae5234b8876 Mon Sep 17 00:00:00 2001 From: Jian Wu Date: Mon, 1 Jun 2026 13:29:58 +0800 Subject: [PATCH 1/3] fix(agents): add Foundry-Features header to invoke endpoint requests PR #8347 switched agent endpoint calls from api-version=2025-11-15-preview to api-version=v1. The preview version implicitly satisfied the Foundry preview-feature gate, but v1 enforces it explicitly via the Foundry-Features: HostedAgents=V1Preview header. Commit 61450ef47 (#8441) fixed this for CreateAgentVersion (deploy path) but missed the data-plane invoke endpoints. This causes azd ai agent invoke to return 403 preview_feature_required. Add the header to all remote data-plane requests in invoke.go: - responsesRemote (OpenAI responses protocol) - invocationsRemote (invocations protocol) - pollInvocationResult (async invocation polling) - createConversation (conversation session creation) Also add the header to GetAgentSessionLogStream in agent_api/operations.go which uses a manual HTTP client outside the azcore pipeline. Fixes #8473 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go | 4 ++++ .../internal/pkg/agents/agent_api/operations.go | 1 + 2 files changed, 5 insertions(+) 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 16c62eb2ae2..350ce18846f 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go @@ -954,6 +954,7 @@ func (a *InvokeAction) responsesRemote(ctx context.Context) error { } req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+rc.bearerToken) + req.Header.Set("Foundry-Features", "HostedAgents=V1Preview") applyIsolationHeaders(req, &a.flags.isolationHeaderFlags) if raw { // Disable Go's transparent gzip handling so the dumped headers and @@ -1181,6 +1182,7 @@ func (a *InvokeAction) invocationsRemote(ctx context.Context) error { } req.Header.Set("Content-Type", contentTypeForBody(body)) req.Header.Set("Authorization", "Bearer "+rc.bearerToken) + req.Header.Set("Foundry-Features", "HostedAgents=V1Preview") applyIsolationHeaders(req, &a.flags.isolationHeaderFlags) if raw { // Disable Go's transparent gzip handling so the dumped headers and @@ -1525,6 +1527,7 @@ func handleInvocationLRO( if bearerToken != "" { req.Header.Set("Authorization", "Bearer "+bearerToken) } + req.Header.Set("Foundry-Features", "HostedAgents=V1Preview") options.ApplyHeaders(req.Header) if raw { // Disable Go's transparent gzip handling so the dumped headers @@ -1645,6 +1648,7 @@ func createConversation( } req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+bearerToken) + req.Header.Set("Foundry-Features", "HostedAgents=V1Preview") options.ApplyHeaders(req.Header) client := &http.Client{Timeout: 30 * time.Second} diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations.go index a9e29b83118..1cad34eb7f3 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations.go @@ -816,6 +816,7 @@ func (c *AgentClient) GetAgentSessionLogStream( req.Header.Set("Authorization", "Bearer "+token.Token) req.Header.Set("User-Agent", fmt.Sprintf("azd-ext-azure-ai-agents/%s", version.Version)) + req.Header.Set("Foundry-Features", "HostedAgents=V1Preview") options.ApplyHeaders(req.Header) httpClient := &http.Client{} From 144829210f1d15efd1a1ebca7c1caec68e00ad7e Mon Sep 17 00:00:00 2001 From: Jian Wu Date: Mon, 1 Jun 2026 14:30:26 +0800 Subject: [PATCH 2/3] fix(agents): correct session CRUD header from AgentEndpoints to HostedAgents The SessionController in the Foundry service gates Create/Get/Delete/List session operations with [FoundryFeatures(HostedAgents=V1Preview)], not AgentEndpoints=V1Preview. The incorrect header value causes 403 preview_feature_required on azd ai agent sessions list and related commands. Verified against Vienna repo: SessionController.cs lines 76, 113, 133, 152 all use FoundryFeature.HostedAgents_V1Preview_Value. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../internal/pkg/agents/agent_api/operations.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations.go b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations.go index 1cad34eb7f3..8d966d63fdf 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations.go +++ b/cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations.go @@ -1190,7 +1190,7 @@ func (c *AgentClient) CreateSession( return nil, fmt.Errorf("failed to set request body: %w", err) } - req.Raw().Header.Set("Foundry-Features", "AgentEndpoints=V1Preview") + req.Raw().Header.Set("Foundry-Features", "HostedAgents=V1Preview") options.ApplyHeaders(req.Raw().Header) resp, err := c.pipeline.Do(req) @@ -1241,7 +1241,7 @@ func (c *AgentClient) GetSession( return nil, fmt.Errorf("failed to create request: %w", err) } - req.Raw().Header.Set("Foundry-Features", "AgentEndpoints=V1Preview") + req.Raw().Header.Set("Foundry-Features", "HostedAgents=V1Preview") options.ApplyHeaders(req.Raw().Header) resp, err := c.pipeline.Do(req) @@ -1292,7 +1292,7 @@ func (c *AgentClient) DeleteSession( return fmt.Errorf("failed to create request: %w", err) } - req.Raw().Header.Set("Foundry-Features", "AgentEndpoints=V1Preview") + req.Raw().Header.Set("Foundry-Features", "HostedAgents=V1Preview") options.ApplyHeaders(req.Raw().Header) resp, err := c.pipeline.Do(req) @@ -1341,7 +1341,7 @@ func (c *AgentClient) ListSessions( return nil, fmt.Errorf("failed to create request: %w", err) } - req.Raw().Header.Set("Foundry-Features", "AgentEndpoints=V1Preview") + req.Raw().Header.Set("Foundry-Features", "HostedAgents=V1Preview") options.ApplyHeaders(req.Raw().Header) resp, err := c.pipeline.Do(req) From 994e9313243eb694018118349f12215f5966877d Mon Sep 17 00:00:00 2001 From: Jian Wu Date: Mon, 1 Jun 2026 15:49:58 +0800 Subject: [PATCH 3/3] test(agents): assert Foundry-Features header in existing tests Add regression assertions for the HostedAgents=V1Preview header to existing tests that already capture request headers: - TestGetAgentSessionLogStream_ApplyIsolationHeaders - TestSessionLifecycleOperations_ApplyIsolationHeaders (create/get/delete/list) - TestHandleInvocationLRO_PropagatesIsolationHeaders (poll requests) - TestCreateConversation_PropagatesIsolationHeaders Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../extensions/azure.ai.agents/internal/cmd/invoke_test.go | 6 ++++++ .../internal/pkg/agents/agent_api/operations_test.go | 2 ++ 2 files changed, 8 insertions(+) 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 4db3f79e9ad..2beb166641f 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 @@ -1664,6 +1664,9 @@ func assertPollRequestsHaveHeaders( if got := r.Header.Get("Authorization"); got != "Bearer token" { t.Errorf("poll %d: Authorization = %q, want Bearer token", pollNumber, got) } + if got := r.Header.Get("Foundry-Features"); got != "HostedAgents=V1Preview" { + t.Errorf("poll %d: Foundry-Features = %q, want HostedAgents=V1Preview", pollNumber, got) + } if got := r.Header.Get(agent_api.AgentUserIsolationKeyHeader); got != wantUser { t.Errorf("poll %d: %s = %q, want %q", pollNumber, agent_api.AgentUserIsolationKeyHeader, got, wantUser) } @@ -1832,6 +1835,9 @@ func TestCreateConversation_PropagatesIsolationHeaders(t *testing.T) { } request := <-reqCh + if got := request.Header.Get("Foundry-Features"); got != "HostedAgents=V1Preview" { + t.Errorf("Foundry-Features = %q, want HostedAgents=V1Preview", got) + } if got := request.Header.Get(agent_api.AgentUserIsolationKeyHeader); got != "user-1" { t.Errorf("%s = %q, want user-1", agent_api.AgentUserIsolationKeyHeader, got) } 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 0bd745b8efc..4506f9d5b1b 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 @@ -391,6 +391,7 @@ func TestSessionLifecycleOperations_ApplyIsolationHeaders(t *testing.T) { require.NoError(t, tt.call(client, options)) require.Len(t, transport.requests, 1) + require.Equal(t, "HostedAgents=V1Preview", transport.requests[0].Header.Get("Foundry-Features")) requireIsolationHeaders(t, transport.requests[0], "user-1", "chat-1", tt.wantSession) }) } @@ -555,6 +556,7 @@ func TestGetAgentSessionLogStream_ApplyIsolationHeaders(t *testing.T) { } require.NotNil(t, request) require.Equal(t, "Bearer test-token", request.Header.Get("Authorization")) + require.Equal(t, "HostedAgents=V1Preview", request.Header.Get("Foundry-Features")) requireIsolationHeaders(t, request, "user-1", "chat-1", "") }