Support header isolation keys for agent sessions#8206
Conversation
Add user and chat isolation key flags to session-level agent commands and propagate them through invoke, monitor, files, and sessions requests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🔗 Linked Issue RequiredThanks for the contribution! Please link a GitHub issue to this PR by adding |
There was a problem hiding this comment.
Pull request overview
Adds support for propagating Foundry header-based isolation keys across session-scoped Azure AI Agents operations in the azure.ai.agents extension, while preserving the existing session-ownership isolation key behavior.
Changes:
- Introduces
SessionRequestOptions+ well-known header constants inagent_apiand threads these options through session lifecycle, files, and log streaming APIs. - Adds
--user-isolation-keyand--chat-isolation-keyflags to session-level CLI commands (sessions, invoke, monitor, files) and applies them to outbound requests (including LRO polling and conversation creation). - Expands unit tests to validate header propagation across the affected operations and command flag registration.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations.go | Adds isolation header constants + SessionRequestOptions, and applies headers across session/files/logstream operations. |
| cli/azd/extensions/azure.ai.agents/internal/pkg/agents/agent_api/operations_test.go | Adds tests ensuring isolation headers are applied for session lifecycle, file ops, and log streaming. |
| cli/azd/extensions/azure.ai.agents/internal/cmd/isolation_headers.go | New shared flag plumbing for --user-isolation-key / --chat-isolation-key and conversion to request options. |
| cli/azd/extensions/azure.ai.agents/internal/cmd/session.go | Registers isolation header flags on session commands and propagates options to agent API calls. |
| cli/azd/extensions/azure.ai.agents/internal/cmd/session_test.go | Extends tests to assert new isolation flags exist with correct defaults. |
| cli/azd/extensions/azure.ai.agents/internal/cmd/monitor.go | Adds isolation header flags and passes options to session log streaming. |
| cli/azd/extensions/azure.ai.agents/internal/cmd/monitor_test.go | Extends tests to assert new isolation flags exist with correct defaults. |
| cli/azd/extensions/azure.ai.agents/internal/cmd/invoke.go | Adds isolation header flags and propagates options through invoke flows (requests, LRO polling, conversation creation). |
| cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go | Adds tests asserting flag registration and propagation through LRO polling and conversation creation. |
| cli/azd/extensions/azure.ai.agents/internal/cmd/helpers.go | Threads session request options into conversation ID resolution and conversation creation. |
| cli/azd/extensions/azure.ai.agents/internal/cmd/files.go | Adds isolation header flags for file operations and propagates options to agent API calls. |
| cli/azd/extensions/azure.ai.agents/internal/cmd/files_test.go | Extends tests to assert new isolation flags exist across file subcommands. |
Comments suppressed due to low confidence (1)
cli/azd/extensions/azure.ai.agents/internal/cmd/invoke_test.go:1162
- This test stores the request pointer in an outer variable from the server handler goroutine and reads it from the test goroutine without synchronization; with
t.Parallel()this will be flagged as a race by the race detector. Use a channel to hand the request back to the test (or otherwise synchronize) before making assertions.
func TestCreateConversation_PropagatesIsolationHeaders(t *testing.T) {
t.Parallel()
var request *http.Request
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
request = r
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"id":"conv-headers"}`))
}))
defer srv.Close()
| "azureaiagent/internal/pkg/agents/agent_api" | ||
|
|
||
| "github.com/spf13/cobra" |
| func TestGetAgentSessionLogStream_ApplyIsolationHeaders(t *testing.T) { | ||
| var request *http.Request | ||
| server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| request = r | ||
| w.WriteHeader(http.StatusOK) | ||
| _, _ = w.Write([]byte("event: log\n\n")) | ||
| })) |
| func TestHandleInvocationLRO_PropagatesIsolationHeaders(t *testing.T) { | ||
| origInterval := defaultLROPollInterval | ||
| defaultLROPollInterval = time.Millisecond | ||
| t.Cleanup(func() { defaultLROPollInterval = origInterval }) | ||
|
|
||
| var pollRequest *http.Request | ||
| srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| pollRequest = r | ||
| w.WriteHeader(http.StatusOK) | ||
| _, _ = w.Write([]byte(`{"status":"completed"}`)) | ||
| })) |
|
@copilot apply changes based on the comments in this thread |
Agent-Logs-Url: https://github.com/Azure/azure-dev/sessions/4eb6559e-3bc1-409c-942a-12ccc66e54e4 Co-authored-by: glharper <64209257+glharper@users.noreply.github.com>
Applied all three review comments in af6d390:
All three tests pass under |
wbreza
left a comment
There was a problem hiding this comment.
Supplemental review — focused on what the prior reviewer didn't already cover. Prior race-condition findings stand; please address those.
Test Coverage
LRO polling test only verifies the last poll request — TestHandleInvocationLRO_PropagatesIsolationHeaders (invoke_test.go ~L446–497) overwrites pollRequest on each iteration, so headers are only asserted on the final poll. Recommend pairing this with the race fix already requested: switch to a buffered channel (or mutex-guarded slice) and assert headers on every poll request. That single change resolves the race and tightens the contract.
No partial-set coverage for the new flags — every new test sets both UserIsolationKey and ChatIsolationKey (or neither). Please add cases for user-only and chat-only to lock in the independence of the two headers. ApplyHeaders is implemented correctly today, but a future change that gates one header on the other being set would currently slip through.
Minor
Duplicated test logic — TestApplyIsolationHeaders (invoke_test.go ~L396–419) duplicates TestSessionRequestOptions_ApplyHeaders (operations_test.go ~L1170–1185). Consider removing it, or repurposing it to test the CLI-flag-struct → SessionRequestOptions conversion (sessionRequestOptions / sessionRequestOptionsWithSessionKey), which is currently only exercised indirectly through end-to-end tests.
Flag help text disambiguation — isolation_headers.go adds --user-isolation-key and --chat-isolation-key alongside the pre-existing --isolation-key. The three names look very similar in --help. Consider noting in the descriptions that the new flags are independent of the session-ownership --isolation-key to reduce CLI confusion.
Looks good
- Headers are applied consistently across sessions, files, invoke (incl. LRO polling), monitor/log-stream, and conversation creation.
SessionRequestOptions.ApplyHeadersis nil-safe and filters empty values.- Existing
--isolation-keysemantics preserved viasessionRequestOptionsWithSessionKey. - Header constants are exported with doc comments.
- No isolation-key values are logged in debug output.
Summary
--user-isolation-keyand--chat-isolation-keyto session-level Azure AI Agents commands--isolation-keybehavior for session ownership headersTests
go test .\... -count=1Fixes #8154