.NET: Add Foundry hosted session and user identity pass-through - #7648
.NET: Add Foundry hosted session and user identity pass-through#7648Roger Barreto (rogerbarreto) wants to merge 7 commits into
Conversation
Let user agents pin hosted agent_session_id on AgentSession and send x-ms-user-identity per call for Foundry hosted agents.
Cover service-managed and admin-pinned hosted sandboxes, sticky hosted session id, and per-call x-ms-user-identity isolation with separate AgentSessions sharing one sandbox. Echo container avoids model quota for identity assertions.
There was a problem hiding this comment.
Pull request overview
Adds .NET support for sticky Foundry hosted sandboxes and request-scoped delegated user identities.
Changes:
- Adds hosted-session and user-identity APIs.
- Injects and captures Foundry request context.
- Adds unit and live integration coverage.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
dotnet/tests/Microsoft.Agents.AI.Foundry.UnitTests/Microsoft.Agents.Agents.AI.Foundry.UnitTests.csproj |
Configures target-specific test compilation. |
dotnet/tests/Microsoft.Agents.AI.Foundry.UnitTests/FoundryHostedRequestTests.cs |
Tests request context behavior. |
dotnet/tests/Microsoft.Agents.AI.Foundry.UnitTests/FoundryAgentTests.cs |
Verifies decorator wiring. |
dotnet/tests/Foundry.Hosting.IntegrationTests/scripts/it-bootstrap-agents.ps1 |
Bootstraps the identity scenario. |
dotnet/tests/Foundry.Hosting.IntegrationTests/README.md |
Documents the live-test scenario. |
dotnet/tests/Foundry.Hosting.IntegrationTests/HostedSessionAndUserIdentityTests.cs |
Exercises hosted sessions and identities. |
dotnet/tests/Foundry.Hosting.IntegrationTests/Fixtures/UserIdentityHostedAgentFixture.cs |
Defines the identity fixture. |
dotnet/tests/Foundry.Hosting.IntegrationTests.TestContainer/UserIdentityEchoAgent.cs |
Echoes the platform user key. |
dotnet/tests/Foundry.Hosting.IntegrationTests.TestContainer/Program.cs |
Registers the identity scenario. |
dotnet/src/Microsoft.Agents.AI.Foundry/UserIdentityScope.cs |
Carries request-scoped identity. |
dotnet/src/Microsoft.Agents.AI.Foundry/UserIdentityPolicy.cs |
Stamps the identity header. |
dotnet/src/Microsoft.Agents.AI.Foundry/HostedSessionIdCaptureScope.cs |
Carries captured session state. |
dotnet/src/Microsoft.Agents.AI.Foundry/HostedSessionIdCapturePolicy.cs |
Captures response session IDs. |
dotnet/src/Microsoft.Agents.AI.Foundry/FoundryHostedRequestAgent.cs |
Coordinates request and sticky-session context. |
dotnet/src/Microsoft.Agents.AI.Foundry/FoundryChatOptionsExtensions.cs |
Adds per-call Foundry options. |
dotnet/src/Microsoft.Agents.AI.Foundry/FoundryAgentSessionExtensions.cs |
Stores hosted session IDs. |
dotnet/src/Microsoft.Agents.AI.Foundry/FoundryAgent.cs |
Wires the pipeline and session API. |
Suppressed comments (1)
dotnet/src/Microsoft.Agents.AI.Foundry/FoundryHostedRequestAgent.cs:55
- The sticky update is skipped when a streaming consumer stops enumeration early or the stream throws. Since disposing an async iterator does not execute ordinary code after the
await foreach, a service-created sandbox ID captured from the response is lost and the next turn may create another sandbox. Put the update in afinallyso iterator disposal persists it.
await foreach (var update in this.InnerAgent.RunStreamingAsync(messages, session, prepared.Options, cancellationToken).ConfigureAwait(false))
{
yield return update;
}
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
MAF Automated Review — Iteration 1
Result: Findings reported
Scope: full PR (2 commit(s)): 0617be7f94b4, 9eada879cebd
Model: gpt-5.6-sol
Overview
The PR cleanly separates sticky hosted-session state from request-scoped user identity, validates conflicting session identifiers, captures platform-assigned identifiers, and adds focused unit and live integration coverage. Async-local carriers and serializable session state provide useful isolation and persistence guardrails. Two residual defects remain: nested calls can inherit an enclosing delegated identity, and adapting generic run options drops public base-option behavior.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
2 verified findings remained after source verification (2 high) across 1 file. Details are attached to the affected lines below.
Affected areas: dotnet/src/Microsoft.Agents.AI.Foundry/FoundryHostedRequestAgent.cs
Persist sticky id in finally, clone run options before factory wrap, validate whitespace pin on CreateHostedSessionAsync, and throw on unexpected hosted session id change in the response. Docs: distinct AgentSessions per user identity may share one sandbox.
Always assign UserIdentityScope including null so nested runs do not inherit a parent identity. When upgrading plain AgentRunOptions, keep background, format, and additional properties on the specialized clone.
Align WithUserIdentity guidance with Foundry Learn multiplex docs: response chains are bound to the creating user even inside a shared hosted sandbox.
Motivation & Context
Callers of Foundry hosted agents need two independent controls on each run:
agent_session_idon the Responses body, sticky across turns so the same container sandbox is reused.x-ms-user-identityrequest header, so one middle-tier app can invoke the same agent for different end users without mixing their isolation keys.Today those values are not first-class on
FoundryAgent/ChatClientAgentoptions and session state. Without them, multi-user apps cannot pin a hosted sandbox or stamp per-request user identity through the agent pipeline in a consistent way.Description & Review Guide
What are the major changes?
AgentSession.StateBag(same conflict model asConversationId: session vs options mismatch throws).ChatOptions.WithFoundryHostedAgentSessionId(...)andChatOptions.WithFoundryHostedAgentUserIdentity(...).FoundryAgent.CreateFoundryHostedAgentSessionAsync(hostedSessionId?, conversationId?)to pin at session creation.FoundryHostedRequestAgent+ policies) that:agent_session_idx-ms-user-identityx-agent-session-idfrom the response into session stateCreateSessionpin + sticky reuseAgentSessionAgentSessioninstances for distinct user identities (sharedHostedAgentSessionId, independent conversation trails, distinct platform user keys). The user-identity test container echoesUSER-ID:<opaque>without calling a chat model.What is the impact of these changes?
HostedSessionContext.UserIdis an opaque isolation key (sourced from platformx-agent-user-id). Do not assume a particular string shape.What do you want reviewers to focus on?
ConversationId).ConversationId(chat trail) vsHostedAgentSessionId(sandbox) vsx-ms-user-identity(delegated user).AgentSessioninstances pinned to the same sandbox (reusing one session reusesprevious_response_idand 404s under per-user response partitioning).Foundry*extension class naming/namespaces to avoid MEAI collisions.MEAI001).Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.