Skip to content

.NET: Add Foundry hosted session and user identity pass-through - #7648

Open
Roger Barreto (rogerbarreto) wants to merge 7 commits into
microsoft:mainfrom
rogerbarreto:foundry-session-user-isolation-support
Open

.NET: Add Foundry hosted session and user identity pass-through#7648
Roger Barreto (rogerbarreto) wants to merge 7 commits into
microsoft:mainfrom
rogerbarreto:foundry-session-user-isolation-support

Conversation

@rogerbarreto

@rogerbarreto Roger Barreto (rogerbarreto) commented Aug 13, 2026

Copy link
Copy Markdown
Member

Motivation & Context

Callers of Foundry hosted agents need two independent controls on each run:

  1. Hosted sandbox continuity via agent_session_id on the Responses body, sticky across turns so the same container sandbox is reused.
  2. Delegated user isolation via the x-ms-user-identity request 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 / ChatClientAgent options 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?

    • Sticky hosted agent session id stored on AgentSession.StateBag (same conflict model as ConversationId: session vs options mismatch throws).
    • Per-call options: ChatOptions.WithFoundryHostedAgentSessionId(...) and ChatOptions.WithFoundryHostedAgentUserIdentity(...).
    • FoundryAgent.CreateFoundryHostedAgentSessionAsync(hostedSessionId?, conversationId?) to pin at session creation.
    • Request pipeline (FoundryHostedRequestAgent + policies) that:
      • patches the Responses body with agent_session_id
      • stamps x-ms-user-identity
      • captures x-agent-session-id from the response into session state
    • Unit tests for sticky session, conflict rules, and header/body injection.
    • Live ITs (skipped by default) covering:
      • service-managed sandbox create + sticky reuse
      • admin CreateSession pin + sticky reuse
      • same user identity stable on one AgentSession
      • same hosted sandbox, different AgentSession instances for distinct user identities (shared HostedAgentSessionId, independent conversation trails, distinct platform user keys). The user-identity test container echoes USER-ID:<opaque> without calling a chat model.
  • What is the impact of these changes?

    • One process can serve many users while keeping sandbox, conversation trail, and delegated identity separate.
    • Hosted session id is sticky like conversation id; user identity stays request-scoped and is never stored on the session.
    • In the container, HostedSessionContext.UserId is an opaque isolation key (sourced from platform x-agent-user-id). Do not assume a particular string shape.
  • What do you want reviewers to focus on?

    • Conflict rules for hosted session id vs options (parity with ConversationId).
    • Separation: ConversationId (chat trail) vs HostedAgentSessionId (sandbox) vs x-ms-user-identity (delegated user).
    • Why different user identities must use different AgentSession instances pinned to the same sandbox (reusing one session reuses previous_response_id and 404s under per-user response partitioning).
    • Foundry* extension class naming/namespaces to avoid MEAI collisions.
    • Experimental attribute still required for OpenAI request policies (MEAI001).

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

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.
Copilot AI balanced review requested due to automatic review settings August 13, 2026 15:01
@agent-framework-automation agent-framework-automation Bot added documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs .NET Usage: [Issues, PRs], Target: .Net labels Aug 13, 2026
@rogerbarreto
Roger Barreto (rogerbarreto) marked this pull request as ready for review August 13, 2026 15:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 a finally so 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.

Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryHostedRequestAgent.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryHostedRequestAgent.cs
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryAgent.cs Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryHostedRequestAgent.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryHostedRequestAgent.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/HostedSessionIdCapturePolicy.cs Outdated
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.
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryAgent.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryAgent.cs
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryAgent.cs
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryAgentSessionExtensions.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryAgentSessionExtensions.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryChatOptionsExtensions.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryChatOptionsExtensions.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryChatOptionsExtensions.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryAgent.cs
Comment thread dotnet/src/Microsoft.Agents.AI.Foundry/FoundryChatOptionsExtensions.cs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs .NET Usage: [Issues, PRs], Target: .Net

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants