Commit Graph

16 Commits

  • .NET: Surface x-ms-served-model header as ChatResponse.ModelId for Foundry agents (#5979)
    * .NET: Surface x-ms-served-model header as ChatResponse.ModelId for Foundry agents
    
    Mirrors Python PR #5910. Adds an internal SCM PipelinePolicy that reads the x-ms-served-model HTTP response header on Azure OpenAI Responses calls and writes it into an AsyncLocal box. A DelegatingChatClient sits between OpenTelemetry and the MEAI OpenAIResponsesChatClient and overwrites ChatResponse.ModelId with the served snapshot so OTel spans report the actual model rather than the deployment alias. Wired through all AsAIAgent paths in Microsoft.Agents.AI.Foundry.
    
    * .NET: Fix line endings and BOM on ResponsesAgentServedModelTests
    
    * .NET: Address Copilot review on Foundry served-model PR
    
    - Restore previous ServedModelScope in finally to avoid AsyncLocal leak into caller execution context.
    - Make served-model integration test assertion robust to deployment names that already match the snapshot pattern.
    - Broaden UnitTests csproj comment to cover all conditional removals (net8.0+ requirement).
    
    * .NET: Split ServedModelTests into per-SUT files with regions
    
    Split the combined ServedModelTests.cs into one test class per SUT:
    
    - ServedModelScopeTests.cs (AsyncLocal carrier)
    - ServedModelPolicyTests.cs (SCM pipeline policy)
    - ServedModelChatClientTests.cs (delegating client, with regions for Non-streaming / Streaming / End-to-end)
    
    Shared helpers and fake clients moved into ServedModelTestHelpers.cs.
    
    Csproj net8.0+ exclusion list updated accordingly.
    
    * .NET: Consolidate served-model logic into FoundryChatClient
    
    Move x-ms-served-model header capture from the standalone ServedModelChatClient
    decorator directly into FoundryChatClient, eliminating a separate wrapper that
    had to be applied at every Foundry entry point via WireServedModel().
    
    - Register ServedModelPolicy in FoundryChatClient constructors (alongside the
      existing AgentFrameworkUserAgentPolicy registration)
    - Add StrongBox push/read logic to FoundryChatClient.GetResponseAsync and
      GetStreamingResponseAsync
    - Delete ServedModelChatClient.cs and its unit tests
    - Remove WireServedModel() from FoundryAgent and AIProjectClientExtensions
    - Update ServedModelPolicy/Scope XML docs to reference FoundryChatClient
    - Simplify ServedModelTestHelpers to use FoundryChatClient directly
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • .NET: Promote FoundryChatClient to public, add file/vector-store helpers and ToPromptAgentAsync converter (#5940)
    * Consolidate Foundry chat client decorators into FoundryChatClient
    
    - Replace AzureAIProjectChatClient and AzureAIProjectResponsesChatClient with a single internal sealed FoundryChatClient that covers three modes (pure responses, server-side agent reference, hosted agent endpoint).
    - Rename AzureAIProjectChatClientExtensions to AIProjectClientExtensions to reflect that it extends AIProjectClient.
    - All four AsAIAgent extension overloads and both FoundryAgent constructors now construct FoundryChatClient internally so the microsoft.foundry telemetry tag is uniform across paths.
    - Introduce AgentFrameworkUserAgentPolicy that stamps agent-framework-dotnet/{version} on outbound requests, mirroring the Python agent-framework-python/{version} contract.
    - Delete the Foundry-local MeaiUserAgentPolicy duplicate; rely on MEAI 10.5.1 to stamp MEAI/{version} automatically.
    - HostedAgentUserAgentPolicy keeps the combined foundry-hosting/agent-framework-dotnet/{version} segment (Python parity) and upgrades the bare segment in place to avoid duplication.
    - Tests reorganized: FoundryChatClientTests, AIProjectClientExtensionsTests, AgentFrameworkUserAgentPolicyTests, MeaiAutoUserAgentVerificationTests, plus in-place upgrade unit tests in HostedOutboundUserAgentTests.
    
    * Promote FoundryChatClient to public; add file/vector-store helpers and ToPromptAgentAsync converter
    
    - Promote FoundryChatClient from internal sealed to public sealed for Python parity, so .NET developers can hold and pass a FoundryChatClient directly the way Python developers do.
    - Mode 3 (hosted agent endpoint) now materializes an AIProjectClient from the parsed project root, making GetService<AIProjectClient>() non-null across all three construction modes. This eliminates the per-mode asymmetry that previously hid project-level helpers from agents constructed via an agent endpoint URL.
    - Add four new instance methods on FoundryChatClient mirroring Python's spec: UploadFileAsync, DeleteFileAsync, CreateVectorStoreAsync (bundles upload + create + wait), DeleteVectorStoreAsync. Single overload each, path-only inputs to start; additional overloads can be added later without breaking callers. All are Experimental, consistent with the rest of the Foundry package.
    - Add ToPromptAgentAsync extension methods on ChatClientAgent and FoundryAgent for the agent-to-prompt-agent converter described in the Foundry spec. Mode 1 (responses API) synthesizes a DeclarativeAgentDefinition from the agent's ChatOptions; mode 2 (server-side agent reference, version, or record) returns the cached or freshly fetched Definition; mode 3 throws InvalidOperationException because no local definition exists to convert.
    - Strict AITool to ResponseTool mapping for mode 1: AIFunction becomes CreateFunctionTool with the function's JSON schema; AITool instances that wrap a ResponseTool unwrap via GetService(typeof(ResponseTool)); anything else throws InvalidOperationException naming the offending tool type. Matches the Python spec's unsupported-tools-raise-ValueError contract.
    - New unit tests: FoundryChatClientVectorStoreTests (22 tests covering all four helpers across the three FoundryChatClient construction modes plus validation and cancellation), FoundryPromptAgentConverterTests (16 tests covering both extension entry points across mode 1 synthesis, mode 2 cached and fetched paths, all failure modes, and a Python-parity guard asserting both extensions produce equivalent definitions for equivalent inputs), plus four new tests in FoundryChatClientTests for the mode 3 AIProjectClient materialization.
    
    * Stop building duplicate ProjectOpenAIClient in FoundryAgent agent-endpoint ctor
    
    After Plan #2's mode-3 AIProjectClient materialization, the inner FoundryChatClient already exposes a project-level AIProjectClient (via GetService) that internally provides the project-level ProjectOpenAIClient via GetProjectOpenAIClient(). FoundryAgent's agent-endpoint constructor was still independently constructing a second project-level ProjectOpenAIClient via the now-redundant CreateProjectLevelOpenAIClientFromAgentEndpoint helper — two handles to the same logical resource.
    
    Refactor: the agent-endpoint constructor now reads the inner FoundryChatClient's materialized AIProjectClient via base.GetService(typeof(AIProjectClient)) and derives the project-level ProjectOpenAIClient from it. The dead helper on both FoundryAgent (private static wrapper) and FoundryChatClient (the actual implementation) is removed. The user-supplied per-agent ClientPipelineOptions primitives (Transport, RetryPolicy, NetworkTimeout, UserAgentApplicationId) are propagated into the materialized AIProjectClientOptions so test-injected transports and explicit retry / timeout / user-agent settings reach the project-level pipeline — preserving the behavior the dead helper used to provide.
    
    Updated AgentEndpointConstructor_GetServiceAIProjectClient_ReturnsNull to its now-correct counterpart AgentEndpointConstructor_GetServiceAIProjectClient_ReturnsNonNull, since after Plan #2 the agent-endpoint ctor surfaces a non-null AIProjectClient (per user direction in Plan #2 Q2).
    
    * Strip duplicated AIProjectClient/ProjectOpenAIClient state from FoundryAgent
    
    Both _aiProjectClient and _projectOpenAIClient fields on FoundryAgent were redundant:
    
    - _aiProjectClient: FoundryAgent's GetService<AIProjectClient> override returned this field, but DelegatingAIAgent.GetService → ChatClientAgent.GetService → FoundryChatClient.GetService<AIProjectClient> already returns the same instance through the delegating chain. Field + override are pure duplication.
    
    - _projectOpenAIClient: only used by FoundryAgent's own GetService<ProjectOpenAIClient> override and by CreateConversationSessionAsync. Per user direction, ProjectOpenAIClient is no longer exposed via GetService on either FoundryChatClient or FoundryAgent — callers retrieve it from the AIProjectClient themselves (aiProjectClient.GetProjectOpenAIClient()) the same way the framework does internally. This eliminates the mode-3 asymmetry where the chat client's stored ProjectOpenAIClient was per-agent (URL /agents/{name}/endpoint/protocols/openai) while the agent's was project-level.
    
    Refactor:
    - Delete both fields on FoundryAgent and the GetService override.
    - Delete the ProjectOpenAIClient branch from FoundryChatClient.GetService.
    - CreateConversationSessionAsync now resolves AIProjectClient at call time via this.GetService<AIProjectClient>() and derives the conversations client from it.
    - Update FoundryChatClient tests that asserted on GetService<ProjectOpenAIClient> to assert Null (deliberate removal).
    - Update FoundryAgent tests AgentEndpointConstructor_GetServiceProjectOpenAIClient_ReturnsNonNull and ProjectEndpointConstructor_GetServiceProjectOpenAIClient_ReturnsNonNull to ...ReturnsNull, and rewrite AgentEndpointConstructor_PropagatesUserAgentApplicationId_ToProjectLevelClient to look up AIProjectClient instead.
    
    No production code (only tests) referenced GetService<ProjectOpenAIClient>, so this is a safe surface reduction. Net: 30 insertions, 61 deletions; FoundryAgent shrinks to a pure delegator with only the two convenience methods (CreateSessionAsync, CreateConversationSessionAsync) on top of the delegating chain.
    
    * Rename FoundryChatClient.HostedAgentName to AgentName and populate it for mode 2
    
    The previous name implied a mode 3 only property tied to the hosted-agent endpoint URL. Today only hosted endpoints surface this name, but conceptually an agent name exists for every server-side agent the client talks to. Renaming to AgentName makes the property general-purpose and ready for future modes where the same chat client may target other server-side agent shapes that are not necessarily 'hosted'.
    
    Mode 2 (server-side agent reference) now mirrors AgentReference.Name into AgentName so callers have a uniform handle regardless of construction mode:
    
    * Mode 1 (pure responses): AgentName is null. There is no agent.
    * Mode 2 (AgentReference): AgentName == AgentReference.Name.
    * Mode 3 (agent endpoint URL): AgentName is parsed from the URL segment as before.
    
    Converter discriminator update: FoundryPromptAgentConverter previously used 'HostedAgentName is not null' to detect mode 3 and reject it. Now that mode 2 also populates AgentName, the mode 3 guard moves to the end of the resolution chain and uses the unambiguous 'AgentName is set AND no AgentReference exists' test. The user-visible error message and behavior are preserved.
    
    Dead-state cleanup spotted during format verify:
    
    * IDE0052 surfaced that FoundryChatClient._projectOpenAIClient is never read since the prior refactor stopped exposing ProjectOpenAIClient via GetService and rewired CreateConversationSessionAsync to resolve the AIProjectClient through the delegating chain. The field is deleted and its three ctor assignments removed.
    * HostedAgentEndpointInner.PerAgentClient only existed to plumb the per-agent ProjectOpenAIClient into that now-deleted field, so the property and its ctor parameter are removed. The local 'perAgentClient' variable inside BuildHostedAgentEndpointInner is still needed to derive the inner IChatClient, but no longer escapes the helper.
    
    Tests:
    
    * Mode1_PureResponses_ReturnsNullForAgentSpecificServices now also asserts AgentName is null.
    * New Mode2_AgentReference_PopulatesAgentNameFromAgentReference asserts the mode 2 mirror.
    * Mode3_HostedAgentEndpoint_ParsesAgentNameFromUrl renamed assertion target HostedAgentName to AgentName.
    
    Verification: 335/335 net10.0, 273/273 net472 Foundry unit; 229/229 Foundry.Hosting unit; format-verify (WSL2 + Docker mcr.microsoft.com/dotnet/sdk:10.0) clean on Microsoft.Agents.AI.Foundry.
    
    * Adopt canonical mode names: Responses Agent, Prompt Agent, Agent Endpoint
    
    Three FoundryChatClient construction modes now have one canonical noun used everywhere.
    
    * Responses Agent (Mode 1): inline ChatClientAgent, project-level Responses API, no server-side def.
    * Prompt Agent (Mode 2): server-side ProjectsAgentDefinition invoked by AgentReference.
    * Agent Endpoint (Mode 3): per-agent URL /agents/{name}/endpoint/protocols/openai. Hosted-or-not.
    
    'Hosted' stays the kind of agent (Microsoft.Agents.AI.Foundry.Hosting). Not synonym of Mode 3.
    
    Rings:
    1. XML docs + error messages use canonical names. en-GB to en-US: centralises, synthesise.
    2. HostedAgentEndpointInner -> AgentEndpointInner, BuildHostedAgentEndpointInner -> BuildAgentEndpointInner.
    3. Tests: Mode1_PureResponses_* -> Mode1_ResponsesAgent_*, Mode2_AgentReference_* -> Mode2_PromptAgent_*, Mode3_HostedAgentEndpoint_* -> Mode3_AgentEndpoint_*.
    
    Pure rename. No behavior change. 335/335 net10 + 273/273 net472 unit, format clean.
    
    * Address PR #5940 design feedback (Q-A through Q-F)
    
    Q-A: poll vector store til status leaves InProgress before return. Exp backoff 250ms-2s. Honor cancel.
    Q-B: try/catch upload loop. Mid-fail = best-effort DeleteFileAsync on already-uploaded ids. Swallow cleanup errors.
    Q-C: pinned AgentReference.Version uses GetAgentVersionAsync. Empty/whitespace/'latest' = GetLatest path.
    Q-D: HostedAgentUserAgentPolicy detects existing combined 'foundry-hosting/...' segment. No double prefix.
    Q-E: mode-3 vector-store test uses fake transport. No DNS to example.com.
    Q-F: no shim. Class always [Experimental] (since 8015e00f5, before dotnet-1.0.0). No compat contract. Callers rename to AIProjectClientExtensions.
    
    Rebase onto origin/main reconciliation: aad20c2b3 added public AsAIAgent(this AIProjectClient, Uri agentEndpoint, ...) extension that calls an internal FoundryAgent(AIProjectClient, Uri, ...) ctor. Reintroduced that ctor + a new FoundryChatClient(AIProjectClient, Uri, ProjectOpenAIClientOptions?) overload that reuses the supplied AIProjectClient's pipeline (via GetProjectResponsesClientForAgentEndpoint) instead of stamping a fresh credential.
    
    Verified: 346/346 net10 + 284/284 net472 Foundry unit, 230/230 Foundry.Hosting unit, format clean.
    
    * Add FoundryAgent helper extensions: UploadFile/DeleteFile/CreateVectorStore/DeleteVectorStore
    
    4 thin forwarders on FoundryAgent that route to the inner FoundryChatClient's helpers via agent.GetService<FoundryChatClient>().X(). Live in existing FoundryAgentExtensions.cs alongside ToPromptAgentAsync.
    
    Throws InvalidOperationException when agent does not expose a FoundryChatClient via GetService (same pattern as ToPromptAgentAsync).
    
    Unit tests: FoundryAgentExtensionsTests covers all 4 forwarders + null-agent ArgumentNullException for each. 8 new tests, 354/354 net10 + 292/292 net472.
    
    Integration tests: parallel FoundryAgentExtensionsTests under Foundry.IntegrationTests mirrors the existing CreateAgent_CreatesAgentWithVectorStoresAsync shape (upload -> create vector store -> FileSearch tool answers question -> cleanup), but routes every helper call through the new FoundryAgent extensions. 4 new IT tests, all verified pass live against the real Foundry project (12-30s each). Skipped by default like the existing vector-store IT.
    
    * Address Sergey's PR review comments
    
    #1 (FoundryAgent.cs:139): drop unused aiProjectClient param from internal FoundryAgent(AIProjectClient, ChatClientAgent) ctor. Was discarded after null-check. Inner FoundryChatClient already surfaces AIProjectClient via GetService. 3 call sites in AIProjectClientExtensions updated.
    
    #2 (FoundryChatClient.cs:376): add pollingTimeout param to CreateVectorStoreAsync. Defaults to 5 min, configurable, Timeout.InfiniteTimeSpan disables. Throws TimeoutException with vector store id and elapsed seconds when bound exceeded. CancellationToken still wins. New unit test PollingTimeout_ThrowsTimeoutExceptionAsync. FoundryAgentExtensions forwarder updated to plumb the new param.
    
    Verified: 355/355 net10 + 293/293 net472 Foundry unit, 230/230 Foundry.Hosting unit, format clean.
  • .NET: Bump Azure.AI.Projects to 2.1.0-beta.2 and add agent-endpoint AsAIAgent path (#5899)
    * .NET: Bump Azure.AI.Projects to 2.1.0-beta.2 and add agent-endpoint AsAIAgent path
    
    Bumps Azure.AI.Projects to 2.1.0-beta.2 with the matching transitive pins (Azure.Core 1.55.0, System.ClientModel 1.11.0).
    
    Foundry agent endpoint plumbing:
    * FoundryAgent now routes the agent-endpoint constructor through the new GetProjectResponsesClientForAgentEndpoint helper.
    * Adds an internal FoundryAgent ctor that takes an existing AIProjectClient plus a parsed agent endpoint so the public extension does not need to construct a second project client.
    * Adds public AIProjectClient.AsAIAgent(Uri agentEndpoint, ...) extension. This is the path consumer samples are expected to use for hosted agents because version selection happens server-side.
    * Trims the dangling "If you want to construct a FoundryAgent against a project endpoint..." sentence from ParseAgentEndpoint.
    
    Unit tests:
    * Four new tests in AzureAIProjectChatClientExtensionsTests cover the AIProjectClient.AsAIAgent(Uri agentEndpoint, ...) overload. 263/263 pass.
    
    Consumer samples (Using-Samples):
    * SimpleAgent and SessionFilesClient now read AZURE_AI_PROJECT_ENDPOINT and AZURE_AI_AGENT_NAME (both required, throw on missing), derive the agent endpoint with new Uri($"{projectEndpoint}/agents/{agentName}/endpoint/protocols/openai"), then call aiProjectClient.AsAIAgent(agentEndpoint, ...).
    * SessionFilesClient README updated.
    
    Contributor samples (responses/*):
    * New HostedContributorRouteExtensions.MapDevTemporaryLocalAgentEndpoint() wildcard route extension so localhost contributor servers accept the per-agent OpenAI endpoint shape the production Hosted runtime exposes.
    * All 11 contributor Program.cs files call MapDevTemporaryLocalAgentEndpoint() with a contributor-only warning comment.
    * Hosted-Files and Hosted-AzureSearchRag were importing Hosted_Shared_Contributor_Setup but never calling AddDevTemporaryLocalContributorSetup(). Both now call it so HostedSessionIsolationKeyProvider resolves correctly in dev.
    * Hosted-AzureSearchRag, Hosted-Files, Hosted-MemoryAgent csprojs drop stale VersionOverride="2.1.0-beta.1" pins.
    * Hosted-AzureSearchRag and Hosted-Files csprojs add ProjectReference to Hosted_Shared_Contributor_Setup.
    * Hosted-Observability/.dockerignore removed the out/ exclusion that was blocking COPY out/ . in Dockerfile.contributor.
    
    Verified:
    * Full solution-scoped build of changed projects: green.
    * Scoped CI-parity dotnet format via WSL2 + Docker (mcr.microsoft.com/dotnet/sdk:10.0) over every changed csproj: clean.
    * Foundry unit tests: 263/263.
    * Contributor docker smoke for 8 hosted samples (publish + docker build + docker run + curl POST to the wildcard route): HTTP 200 / 500 with route matched.
    * End-to-end smoke against the real Azure Foundry project with a fresh bearer token: Hosted-Files contributor container served HTTP 200, the agent invoked ListBundledFiles, and returned the expected file name.
    
    * Address PR review: forward pipeline settings; add UTs
    
    - CreateProjectClientOptions also carries RetryPolicy, NetworkTimeout, ClientLoggingOptions, MessageLoggingPolicy (was Transport+UserAgentApplicationId only).
    
    - Make CreateProjectClientOptions internal so tests can verify the copy directly.
    
    - Add AsAIAgent(Uri) UTs covering tools forwarding to inner ChatOptions and null tools handling.
    
    - Add CreateProjectClientOptions UTs covering null caller and full pipeline-settings copy.
  • .NET: Fix bug in store-false helper to ensure addition rather than replacement (#5895)
    * Fix bug in store-false helper to ensure addition rather than replacement
    
    * Address PR comments
  • .NET: feat(evals): add ground_truth/expected_output support for workflow evaluation (#5755)
    * .NET: feat(evals): add ground_truth/expected_output support for workflow eval
    
    Brings .NET to parity with Python PR #5234 for issue #5135:
    
    - Add expectedOutput parameter to Run.EvaluateAsync (workflow) and stamp on the overall EvalItem.ExpectedOutput.
    - Map EvalItem.ExpectedOutput -> ground_truth in the Foundry JSONL payload, item_schema, and data_mapping for similarity.
    - Add GroundTruthEvaluators set (currently builtin.similarity) and a FindMissingGroundTruthEvaluators helper.
    - Fail fast with InvalidOperationException when a ground-truth evaluator is selected but no item provides an ExpectedOutput, instead of surfacing a remote provider error.
    - Add tests in FoundryEvalConverterTests and WorkflowEvaluationTests.
    - Add Evaluation_WorkflowExpectedOutputs sample (workflow + Foundry similarity).
    
    Fixes microsoft/agent-framework#5135 (.NET side).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: relax BuildOverallItem events to IReadOnlyList<WorkflowEvent>
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Sample: disable per-agent breakdown when using reference-based evaluator
    
    Per-agent EvalItems are intentionally left without ExpectedOutput, so the new fail-fast validation in FoundryEvals would throw when Similarity is invoked for per-agent items. Pass includePerAgent: false in the workflow + similarity sample, and document this gotcha in the EvaluateAsync XML doc.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix BuildOverallItem: fall back to last ExecutorCompletedEvent
    
    AgentResponseEvent is only emitted when AIAgentHostOptions.EmitAgentResponseEvents is enabled, which is not the default for WorkflowBuilder(agent).AddEdge(...). When it is absent, fall back to the last non-internal ExecutorCompletedEvent whose Data is an AgentResponse / ChatMessage / string so the overall EvalItem (and any expectedOutput) is produced. Without this, samples wired up the standard way returned 0 evaluation items.
    
    Update test to cover the fallback path.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Sample: enable EmitAgentResponseEvents; eval throws clear error when no overall response found
    
    Root cause of '0 results': AIAgentHostExecutor only emits AgentResponseEvent when AIAgentHostOptions.EmitAgentResponseEvents is true (default false). For ordinary AIAgent executors the runtime's ExecutorCompletedEvent.Data is null, so the prior fallback couldn't find a final response either.
    
    Sample now builds executors with EmitAgentResponseEvents=true via BindAsExecutor(hostOptions). EvaluateAsync now throws InvalidOperationException with a remediation hint when the user supplies expectedOutput but no overall final response can be located, instead of silently returning 0/0.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Guard against null sample/error/usage/datasource_item in ParseDetailedItem
    
    Foundry eval responses can have these properties present with JSON null
    or non-object values, which caused JsonElement.TryGetProperty to throw
    'requires Object, has Null'. Check ValueKind == Object before drilling in.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review: reorder expectedOutput, tighten ground-truth check, add fail-fast test
    
    * WorkflowEvaluationExtensions.EvaluateAsync: move 'expectedOutput' to
      after 'splitter' so the original positional contract of (splitter,
      cancellationToken) is preserved for existing callers.
    * FoundryEvals: require ALL items to carry ExpectedOutput when a
      ground-truth evaluator is selected (e.g. similarity), not just any.
      Reference-based evaluators score per-item, so a single missing GT
      would still surface as a provider-side validation error. Updated
      fail-fast message accordingly.
    * WorkflowEvaluationTests: add EvaluateAsync_WithExpectedOutputButNoFinalResponse_ThrowsAsync
      to verify the InvalidOperationException is thrown (and that the
      message mentions EmitAgentResponseEvents).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fail-fast on missing overall item regardless of expectedOutput; harden BuildOverallItem default
    
    * EvaluateAsync now throws InvalidOperationException whenever 'includeOverall'
      is requested but BuildOverallItem cannot produce an item, instead of only
      when 'expectedOutput' is supplied. Same misconfiguration (agents not bound
      with EmitAgentResponseEvents) used to silently return empty results — now
      it surfaces a clear, actionable error in both cases.
    * BuildOverallItem switch default now throws instead of returning null. The
      preceding for-loop already constrains Data to AgentResponse/ChatMessage/
      string, so reaching default would indicate a contract drift; throw to make
      the bug visible.
    * Test renamed and broadened to verify the throw fires without expectedOutput.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: alliscode <25218250+alliscode@users.noreply.github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Simplify ClientHeadersScope, drop redundant using/Dispose (#5676)
    Wesley pointed out (with a clean demo) that AsyncLocal<T> mutations made
    inside an awaited async method do not leak back to the caller after the
    method returns - the runtime restores the caller's view automatically.
    
    ClientHeadersAgent.RunCoreAsync and RunCoreStreamingAsync are the only
    callers of the scope, both are async methods awaited by their callers,
    so the explicit using/Dispose pattern was doing work the runtime already
    does for us.
    
    * ClientHeadersScope collapsed to a single Current { get; set; } property
      over an AsyncLocal<IReadOnlyDictionary<string,string>?>. Drops Push,
      the Scope struct, and Dispose. XML doc explains the AsyncLocal natural-
      restoration semantics so the design intent is self-documenting.
    * ClientHeadersAgent uses a direct ClientHeadersScope.Current = snapshot
      before delegating. Drops the local RunAsyncCoreAsync helper and the
      snapshot-passed-as-parameter dance.
    * Test 10 renamed to ClientHeadersScope_IsAsyncLocalIsolatedAndAutoRestoresAsync;
      drops the LIFO claim, keeps the parallel-isolation assertion, and adds
      a Wesley-style 'set inside async, caller sees null on return' assertion.
    * Test 12 switches from using ClientHeadersScope.Push to direct
      Current = ... with try/finally for test isolation.
    
    Snapshot deep-copy in TrySnapshot stays - it defends against caller
    mutating the source Dictionary mid-run, which is independent of the
    AsyncLocal restoration mechanism.
  • .NET: Update FoundryAgent to address HostedAgents strict URL routing (#5677)
    * .NET: Foundry agent-endpoint constructor uses ProjectOpenAIClient directly to fix hosted-agent URL routing
    
    Fixes the experimental FoundryAgent(Uri agentEndpoint, AuthenticationTokenProvider, ...)
    constructor so it actually works against Foundry hosted agents.
    
    The previous implementation routed through AzureAIProjectChatClient, which
    internally called aiProjectClient.GetProjectOpenAIClient().GetProjectResponsesClientForAgent(...).
    For an agent-endpoint URL of the canonical shape
    
      https://<host>/api/projects/<project>/agents/<agentName>/endpoint/protocols/openai
    
    the chain produced
    
      POST https://<host>/api/projects/<project>/openai/v1/responses
    
    (project-level path, no /agents/ segment). The Foundry service rejects this with
    HTTP 400 "Hosted agents can only be called through the agent endpoint:
    .../agents/<agentName>/endpoint/protocols/openai/responses".
    
    The constructor also extracted the agent name via
    agentEndpoint.Segments[^1].TrimEnd('/'), which returns "openai" (the last segment),
    not the agent name.
    
    What changed
    - Public ctor signature: clientOptions parameter type changed from
      AIProjectClientOptions? to ProjectOpenAIClientOptions?. The constructor is
      fundamentally building a ProjectOpenAIClient; accepting AIProjectClientOptions
      was a leaky abstraction whose translation silently dropped any pipeline
      policies the caller added via AddPolicy(...). With the direct type, caller
      policies pass through to the per-agent traffic verbatim.
    - Per-agent client construction: `new ProjectOpenAIClient(BearerTokenPolicy, ProjectOpenAIClientOptions)`
      with Endpoint and AgentName set, then `GetProjectResponsesClient().AsIChatClient()`.
      The SDK auto-appends ?api-version=v1 when AgentName is set.
    - New private static ParseAgentEndpoint helper: single source of truth for both
      agent-name extraction and project-root derivation. Tolerates trailing slash,
      case variants on /agents/ and the suffix segment, strips query/fragment, and
      throws ArgumentException with paramName=nameof(agentEndpoint) for malformed input.
    - Project-level client (used by CreateConversationSessionAsync) is built fresh
      from the derived project root with primitive properties copied
      (RetryPolicy/NetworkTimeout/Transport/UserAgentApplicationId) plus MEAI UA.
    - New GetService<ProjectOpenAIClient>() entry alongside the existing
      GetService<AIProjectClient>() (the latter returns null in agent-endpoint mode
      since no AIProjectClient is constructed on that path).
    - Endpoint and AgentName on caller-supplied ProjectOpenAIClientOptions are
      overridden by values derived from agentEndpoint.
    
    Compatibility
    - FoundryAgent is [Experimental(OPENAI001)]. No GA surface touched. The Foundry
      project does not maintain PublicAPI.*.txt baselines so there is no shipped
      baseline to update.
    - The Microsoft.Agents.AI.Foundry csproj pins
      Azure.AI.Projects to VersionOverride 2.1.0-beta.1 (matching what the IT and
      hosting projects already use); the central pin in Directory.Packages.props
      stays at 2.0.0.
    - WireClientHeaders from PR #5652 is invoked on the agent-endpoint path so
      per-call x-client-* headers behave identically across both ctors.
    
    Tests
    - 23 new unit tests in FoundryAgentTests.cs:
      - 12 for the agent-endpoint constructor (URL routing for non-streaming and
        streaming, conversations URL shape, MEAI UA stamping, caller-policy
        passthrough on the per-agent pipeline, Endpoint/AgentName override
        semantics, GetService matrix, ProjectOpenAIClient propagation,
        UserAgentApplicationId propagation, null-arg validation, ID/Name slug)
      - 9 for ParseAgentEndpoint (standard shape, trailing slash, casing,
        sovereign-cloud host without /api/projects/ literal prefix, special chars
        in agent name, query/fragment stripping, three negative cases)
      - 2 null-arg tests for the public ctor
    - All 250 Microsoft.Agents.AI.Foundry.UnitTests pass (was 221 baseline plus
      29 from PR #5652 plus 23 new in this PR equals 273; pre-existing tests
      collapsed by the rebase merge keep the total at 250).
    - All 225 Microsoft.Agents.AI.Foundry.Hosting.UnitTests pass; no behavioral
      change to the hosting layer.
    - dotnet build clean across net8/9/10/netstandard2.0/net472 with
      TreatWarningsAsErrors=true.
    - dotnet format --verify-no-changes clean for the touched src and test projects.
    
    * .NET: Bump central Azure.AI.Projects pin to 2.1.0-beta.1 and flip Microsoft.Agents.AI.Foundry to preview
    
    Required to fix the NU1109 downgrade chain that broke CI on the agent-endpoint
    constructor rewire (#5677). Microsoft.Agents.AI.Foundry now depends on
    ProjectOpenAIClientOptions.AgentName and the (AuthenticationPolicy, options)
    constructor that only exist in Azure.AI.Projects 2.1.0-beta.1.
    
    Changes:
    * Directory.Packages.props: Azure.AI.Projects 2.0.0 -> 2.1.0-beta.1.
    * Microsoft.Agents.AI.Foundry.csproj: drop IsReleased=true so the package ships
      as preview (matches the beta SDK we now depend on). Add a comment noting the
      flip is temporary and should revert once Azure.AI.Projects ships a stable
      2.1.0.
    * Drop redundant VersionOverride="2.1.0-beta.1" from the 10 csprojs that had it
      as a workaround; the central pin now suffices.
    
    Verified:
    * dotnet build agent-framework-dotnet.slnx --warnaserror clean across all TFMs.
    * Microsoft.Agents.AI.Foundry.UnitTests 250/250 pass.
    * Microsoft.Agents.AI.Foundry.Hosting.UnitTests 211/211 pass.
    * dotnet format --verify-no-changes clean for the touched src and test projects.
  • .NET: Bump MEAI to 10.5.1 and add Foundry per-call x-client header support (#5652)
    * Bump MEAI to 10.5.1 and add per-call x-client header support
    
    Replaces the brittle UserAgentResponsesClient subclass with a clean
    per-call x-client-* header pipeline built on the new Microsoft.Extensions.AI
    10.5.1 OpenAIRequestPolicies hook.
    
    Public surface (Microsoft.Agents.AI.Foundry, [Experimental(MAAI001)]):
    * chatOptions.WithClientHeader(name, value) and .WithClientHeaders(IEnumerable)
      validate the x-client- prefix (case-insensitive), apply all-or-nothing on
      bulk, and throw InvalidOperationException on foreign-typed slot collision
    * myAgent.AsBuilder().UseClientHeaders().Build() opts a customer-built agent
      into the pipeline; idempotent via agent.GetService<ClientHeadersAgent>()
    * Foundry-built agents (FoundryAgent.Create*) pre-wire automatically
    
    Internals:
    * ClientHeadersAgent decorator snapshots the dict at scope-push time so
      concurrent runs sharing a ChatOptions reference do not leak headers
    * ClientHeadersScope is an AsyncLocal<IReadOnlyDictionary<string,string>?>
      with LIFO push/dispose semantics
    * ClientHeadersPolicy singleton stamps headers via Headers.Set so per-call
      values overwrite any same-name header from earlier policies and so
      duplicate registration is value-stable
    * OpenAIRequestPoliciesReflection dedups against MEAI's private _entries
      field and falls back to AddPolicy on any reflection failure; a CI test
      asserts the field shape on every MEAI bump
    
    Hosting cleanup:
    * Deleted UserAgentResponsesClient and its dummy throwing pipeline
    * HostedAgentUserAgentPolicy is now registered via OpenAIRequestPolicies
      in FoundryHostingExtensions.TryApplyUserAgent
    
    Tests:
    * 19 new unit tests in ClientHeadersExtensionsTests.cs covering validation,
      AsyncLocal isolation, snapshot semantics, end-to-end wire stamping, and
      shared-chat-client dedup
    * Updated OpenTelemetryAgentTests for MEAI 10.5.1 changes to web_search
      serialization and the reduced tool definition payload when sensitive
      data capture is disabled
    
    Microsoft.Extensions.Compliance.Abstractions stays at 10.5.0 because no
    10.5.1 release exists on nuget.org.
    
    * Address PR review: pre-wire AsAIAgent path and dedup TryApplyUserAgent
    
    * FoundryAgent: extract WireClientHeaders helper and call it from the
      internal (AIProjectClient, ChatClientAgent) constructor used by
      AzureAIProjectChatClientExtensions.AsAIAgent so those Foundry-built
      agents also pre-wire the x-client header pipeline.
    * Foundry.Hosting TryApplyUserAgent: dedup HostedAgentUserAgentPolicy
      registration per OpenAIRequestPolicies instance via
      ConditionalWeakTable so per-request resolution does not grow the
      policy list unboundedly on singleton agents.
    
    * Add tests covering AsAIAgent pre-wire and TryApplyUserAgent dedup
    
    Backs the PR review fixes from a4c8f91 with regression tests:
    * ClientHeadersExtensionsTests: AsAIAgent_FoundryAgent_HasPreWiredClientHeadersAgent
      asserts the FoundryAgent built via AzureAIProjectChatClientExtensions.AsAIAgent
      contains a ClientHeadersAgent in its delegating chain (catches future
      regressions of the bypass).
    * ClientHeadersExtensionsTests: FoundryAgent_PublicConstructor_HasPreWiredClientHeadersAgent
      covers the public constructor path the same way.
    * ClientHeadersExtensionsTests: UseClientHeaders_RepeatedRegistrations_OnSameChatClient_OnlyRegistersOnce
      invokes UseClientHeaders 25 times on a shared chat client and asserts via
      reflection that OpenAIRequestPolicies._entries length is exactly 1.
    * HostedTryApplyUserAgentDedupTests: two tests asserting
      FoundryHostingExtensions.TryApplyUserAgent stays at one entry per
      OpenAIRequestPolicies instance after 50 calls on the same agent and across
      distinct agents on different chat clients.
    
    * Move tests next to their SUT
    
    Removes the dedicated HostedTryApplyUserAgentDedupTests.cs test class.
    Tests are co-located with the SUT they exercise:
    
    * FoundryAgentTests.cs gains the Constructor_PreWiresClientHeadersAgent
      and Constructor_FromAsAIAgentExtension_PreWiresClientHeadersAgent
      cases, since FoundryAgent is the SUT for the pre-wire behavior.
    * HostedOutboundUserAgentTests.cs gains the two TryApplyUserAgent dedup
      cases, since FoundryHostingExtensions.TryApplyUserAgent is the SUT
      it already covers.
    * ClientHeadersExtensionsTests.cs keeps only the
      UseClientHeaders_RepeatedRegistrations_OnSameChatClient_OnlyRegistersOnce
      case, which exercises the public ClientHeadersExtensions surface.
    
    * Remove redundant WithCancellation on inner streaming call
    
    ct is already passed to InnerAgent.RunStreamingAsync, so
    .WithCancellation(ct) on the resulting IAsyncEnumerable is a no-op.
    Caught by Sergey on PR review.
    
    * Address PR review: surface downstream MEAI experimental ID
    
    * Add AIOpenAIRequestPolicies = MEAIExperiments alias to
      DiagnosticIds.Experiments (matches the existing AIResponseContinuations,
      AIMcpServers, AIFunctionApprovals pattern).
    * Mark public ClientHeadersExtensions with [Experimental(AIOpenAIRequestPolicies)]
      instead of AgentsAIExperiments. Consumers now see the MEAI001 warning,
      surfacing the dependency on MEAI's experimental OpenAIRequestPolicies hook.
    * Mark internal OpenAIRequestPoliciesReflection with the same alias to
      suppress warnings at the source rather than via project-wide NoWarn.
    * Remove MEAI001 from Foundry csproj NoWarn (kept on Foundry.Hosting where
      pre-PR usages remain).
    * Clarify ClientHeadersScope XML doc: AsyncLocal flows values forward but
      does NOT auto-restore on method return; explicit using/Dispose is what
      gives stack-style LIFO semantics.
  • .NET: Add dedicated Foundry.Hosting UnitTest project (#5592)
    * Foundry.Hosting.UnitTests: extract project from Foundry.UnitTests
    
    Move all Hosting/* tests, three toolbox TestData JSONs, and the FakeAuthenticationTokenProvider/HttpHandlerAssert/TestDataUtil helpers (trimmed to toolbox getters) into a new Microsoft.Agents.AI.Foundry.Hosting.UnitTests project. Add it to the slnx and grant the new assembly InternalsVisibleTo from Microsoft.Agents.AI.Foundry and Microsoft.Agents.AI.Foundry.Hosting.
    
    * Foundry.Hosting.UnitTests: align namespaces to assembly name
    
    Rename namespaces from Microsoft.Agents.AI.Foundry.UnitTests(.Hosting) to Microsoft.Agents.AI.Foundry.Hosting.UnitTests across all moved tests, the duplicated helpers, and the trimmed TestDataUtil. Also fixes the prior namespace inconsistency in FoundryToolboxTests.
    
    * Foundry.Hosting.UnitTests: split WorkflowIntegrationTests by SUT
    
    Replace the WorkflowIntegrationTests file (an IT-named file inside a UT project) with two SUT-focused files plus a shared test-doubles file:
    
    - AgentFrameworkResponseHandlerWorkflowTests.cs - the 5 handler-driven tests that exercise AgentFrameworkResponseHandler with a real workflow agent.
    - OutputConverterWorkflowTests.cs - the 5 OutputConverter tests driven by hand-crafted update sequences mirroring real workflow patterns.
    - WorkflowTestAgents.cs - StreamingTextAgent and ThrowingStreamingAgent extracted as internal types used by both files.
    
    * Foundry.UnitTests: trim Hosting-related conditionals and dead testdata
    
    Now that Hosting tests live in their own project:
    - drop the Compile Remove guard for the Hosting subfolder,
    - drop the .NETCoreApp-only PackageReferences (Azure.AI.AgentServer.Responses, Microsoft.AspNetCore.TestHost, OpenTelemetry, OpenTelemetry.Exporter.InMemory),
    - drop the conditional ProjectReference to Microsoft.Agents.AI.Foundry.Hosting,
    - delete the three Toolbox JSON files and the matching Toolbox getters in TestDataUtil.
    
    * Foundry.Hosting.UnitTests: drop redundant 'using Microsoft.Agents.AI.Foundry.Hosting'
    
    The new project namespace is Microsoft.Agents.AI.Foundry.Hosting.UnitTests, which already brings the parent Microsoft.Agents.AI.Foundry.Hosting namespace into scope. The explicit using statement is therefore redundant (IDE0005). Caught by 'dotnet format --verify-no-changes' running on Linux against the .NET 10 SDK.
    
    * Foundry.Hosting: drop InternalsVisibleTo to Foundry.UnitTests
    
    The non-hosting Foundry.UnitTests project no longer holds any Hosting tests after the split, so it doesn't need access to internal types in Microsoft.Agents.AI.Foundry.Hosting. Only Microsoft.Agents.AI.Foundry.Hosting.UnitTests needs it.
    
    * Foundry.Hosting: rename DelegatingResponsesClient to UserAgentResponsesClient
    
    Address westey-m's review feedback on PR #5453: `Delegating*` is conventionally reserved for inheritable base classes (mirroring `DelegatingHandler`) where consumers override one or two members. This polyfill is sealed and only injects the User-Agent supplement, so the new name reflects its actual purpose.
    
    Renamed via `git mv` to preserve history:
    * `src/Microsoft.Agents.AI.Foundry.Hosting/DelegatingResponsesClient.cs` to `UserAgentResponsesClient.cs`
    * `tests/Microsoft.Agents.AI.Foundry.Hosting.UnitTests/DelegatingResponsesClientTests.cs` to `UserAgentResponsesClientTests.cs`
    
    Class, constructor, and all references updated across:
    * `src/.../UserAgentResponsesClient.cs` (class + constructor + internal log message)
    * `src/.../ServiceCollectionExtensions.cs` (cref + type check + instantiation)
    * `src/.../HostedAgentUserAgentPolicy.cs` (cref)
    * `tests/Foundry.UnitTests/RequestOptionsExtensionsTests.cs` (comment)
    * `tests/Foundry.Hosting.UnitTests/UserAgentResponsesClientTests.cs` (class + cref + instantiations)
  • .NET: dotnet: Add hosted-agent User-Agent supplement to outgoing requests (#5453)
    * dotnet: Add hosted-agent User-Agent supplement to outgoing requests
    
    When an agent runs inside a Foundry Hosted Agent, the outgoing
    User-Agent header now includes 'agent-framework-hosted/{version}'
    alongside the existing 'MEAI/{version}' segment.
    
    - Add HostedAgentContext with AsyncLocal<string?> property
    - MeaiUserAgentPolicy reads the supplement per-call
    - AgentFrameworkResponseHandler sets/restores the context
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * chore: update hosted UA format to foundry-hosting/agent-framework-dotnet/{version}
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Trying to get UA flowing, no luck yet.
    
    * .NET: Polyfill MEAI OpenAIResponsesChatClient to add hosted-agent User-Agent supplement
    
    When AgentFrameworkResponseHandler resolves an agent (i.e. we are running in a
    hosted context), TryApplyUserAgent walks the agent's IChatClient decorator chain
    to find MEAI's internal OpenAIResponsesChatClient and reflectively swaps its
    inner _responseClient field with a DelegatingResponsesClient wrapper. The
    wrapper overrides the public-virtual protocol methods to add a per-call
    HostedAgentUserAgentPolicy to the RequestOptions and delegate to the inner
    ResponsesClient. The OpenAI SDK's internal streaming overloads bottom out in
    calls to the public-virtual non-streaming overloads via virtual dispatch on
    this, so streaming is covered without overriding any non-virtual member.
    
    The wrapper accepts any ResponsesClient-derived inner — both the Foundry
    ProjectResponsesClient and the native OpenAI ResponsesClient — and preserves
    the inner client's full pipeline (Transport, RetryPolicy, NetworkTimeout,
    OrganizationId / ProjectId / UserAgentApplicationId, custom policies).
    
    - Add DelegatingResponsesClient + HostedAgentUserAgentPolicy in Microsoft.Agents.AI.Foundry.Hosting.
    - Add TryApplyUserAgent next to ApplyOpenTelemetry in FoundryHostingExtensions; wire it into AgentFrameworkResponseHandler.GetAgent for both keyed and default-agent paths.
    - Drop earlier-iteration dead code: AddHostedAgentTelemetry extension, HostedUserAgentPolicy class, HostedAgentContext.cs, and the never-called ToRequestOptions helper.
    - Revert RequestOptionsExtensions.MeaiUserAgentPolicy to MEAI-only (the supplement is now injected by the polyfill).
    - Revert unrelated whitespace change in Agent_Step25_ToolboxServerSideTools sample.
    - Tests cover streaming AND non-streaming, retry policy preservation, OrganizationId/ProjectId/UserAgentApplicationId pass-through, idempotency, native OpenAI ResponsesClient, and reflection guards for MEAI/OpenAI shape drift.
    
    * .NET: Address review feedback on hosted-agent User-Agent polyfill
    
    - TryApplyUserAgent: replace silent null-return with ArgumentNullException to match the codebase's convention.
    - Add idempotency test (TryApplyUserAgent_CalledTwiceOnSameAgent_DoesNotDoubleWrap) — runs the polyfill twice on the same agent and asserts the wire UA contains exactly one foundry-hosting segment, proving the 'current is DelegatingResponsesClient' guard prevents nested wrapping.
    - Add retry-double-append test (Polyfill_RetryWithinCall_DoesNotDuplicateSupplementInUserAgent) — exercises the HostedAgentUserAgentPolicy Contains-guard via a custom retry policy that re-runs the inner pipeline on the same message.
    - Replace TryApplyUserAgent_NullAgent_ReturnsNullWithoutThrowing with TryApplyUserAgent_NullAgent_ThrowsArgumentNullException to match the new contract.
    
    * .NET: Drop null check from TryApplyUserAgent and its now-redundant test
    
    The two call sites in AgentFrameworkResponseHandler.GetAgent already null-check the agent before invoking TryApplyUserAgent, so the defensive ArgumentNullException is unreachable. Remove it and the corresponding test.
    
    * .NET: Remove unused Microsoft.Shared.Diagnostics import in ServiceCollectionExtensions
    
    The Throw.IfNull helper from this namespace was used by the now-removed null check in TryApplyUserAgent. Drop the unused import to satisfy IDE0005 in CI's full-project dotnet format run.
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
  • .NET: dotnet: Add server-side Foundry Toolbox support and fix SDK beta.4 br… (#5450)
    * dotnet: Add server-side Foundry Toolbox support and fix SDK beta.4 breaking changes
    
    Add FoundryToolbox and AIProjectClient extensions to Microsoft.Agents.AI.Foundry.Hosting
    for server-side toolbox tool integration matching Python's FoundryChatClient.get_toolbox()
    pattern. Tools are fetched from the Foundry project SDK and passed as server-side tools
    in the Responses API request.
    
    New files:
    - FoundryToolbox.cs: Core implementation using AgentAdministrationClient SDK
    - AIProjectClientToolboxExtensions.cs: Extension methods on AIProjectClient
    - Agent_Step25_ToolboxServerSideTools sample with create helper and combine flow
    - 19 unit tests covering param validation, conversion, sanitization, and extensions
    
    SDK breaking changes (Azure.AI.AgentServer.Responses beta.3 -> beta.4):
    - FunctionToolCallOutputResource renamed to OutputItemFunctionToolCallOutput
    - AzureAIAgentServerResponsesModelFactory made internal, replaced with direct constructors
    - ResponseUsage constructor now requires non-null token details parameters
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: reuse endpoint variable in CreateSampleToolboxAsync
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: pass endpoint through static local functions to avoid capture
    
    Static local functions cannot capture top-level variables. Thread the
    endpoint parameter through Main, CombineToolboxes, and CreateSampleToolboxAsync.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor: remove unused projectClient param from CreateSampleToolboxAsync
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Update dotnet/samples/02-agents/AgentsWithFoundry/Agent_Step25_ToolboxServerSideTools/README.md
    
    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
    
    * Update dotnet/samples/02-agents/AgentsWithFoundry/Agent_Step25_ToolboxServerSideTools/Program.cs
    
    Co-authored-by: westey <164392973+westey-m@users.noreply.github.com>
    
    * Update dotnet/samples/02-agents/AgentsWithFoundry/Agent_Step25_ToolboxServerSideTools/Program.cs
    
    Co-authored-by: westey <164392973+westey-m@users.noreply.github.com>
    
    * Removing GetToolbocVersion.
    
    * Removing tests for GetToolboxVersion
    
    * fix: map cached/reasoning token counts in ConvertUsage instead of hardcoding zeros
    
    Extract InputTokenDetails.CachedTokenCount and OutputTokenDetails.ReasoningTokenCount
    from UsageDetails.AdditionalCounts, matching the pattern in AgentResponseExtensions.
    Also accumulate detail counts when merging with existing usage.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
    Co-authored-by: westey <164392973+westey-m@users.noreply.github.com>
  • .NET [WIP] Foundry Hosted Agents Support (#5312)
    * Add Azure AI Foundry Responses hosting adapter
    
    Implement Microsoft.Agents.AI.Hosting.AzureAIResponses to host agent-framework
    AIAgents and workflows within Azure Foundry as hosted agents via the
    Azure.AI.AgentServer.Responses SDK.
    
    - AgentFrameworkResponseHandler: bridges ResponseHandler to AIAgent execution
    - InputConverter: converts Responses API inputs/history to MEAI ChatMessage
    - OutputConverter: converts agent response updates to SSE event stream
    - ServiceCollectionExtensions: DI registration helpers
    - 336 unit tests across net8.0/net9.0/net10.0 (112 per TFM)
    - ResponseStreamValidator: SSE protocol validation tool for samples
    - FoundryResponsesHosting sample app
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Bump System.ClientModel to 1.10.0 for Azure.Core 1.52.0 compat
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Clean up tests and sample formatting
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Update Azure.AI.AgentServer packages to 1.0.0-alpha.20260401.5
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add hosted package version suffix (0.9.0-hosted) to distinguish from mainline
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Move Foundry Responses hosting into Microsoft.Agents.AI.Foundry package
    
    Move source and test files from the standalone Hosting.AzureAIResponses project
    into the Foundry package under a Hosting/ subfolder. This consolidates the
    Foundry-specific hosting adapter into the main Foundry package.
    
    - Source: Microsoft.Agents.AI.Foundry.Hosting namespace
    - Tests: merged into Foundry.UnitTests/Hosting/
    - Conditionally compiled for .NETCoreApp TFMs only (net8.0+)
    - Deleted standalone Hosting.AzureAIResponses project and test project
    - Updated sample and solution references
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Bump package version to 0.9.0-hosted.260402.2
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Bump OpenTelemetry packages to fix NU1109 downgrade errors
    
    - OpenTelemetry/Api/Exporter.Console/Exporter.InMemory: 1.13.1 -> 1.15.0
    - OpenTelemetry.Exporter.OpenTelemetryProtocol: already 1.15.0
    - OpenTelemetry.Extensions.Hosting: already 1.14.0
    - OpenTelemetry.Instrumentation.AspNetCore/Http: already 1.14.0
    - OpenTelemetry.Instrumentation.Runtime: 1.13.0 -> 1.14.0
    - Azure.Monitor.OpenTelemetry.Exporter: 1.4.0 -> 1.5.0
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CA1873: guard LogWarning with IsEnabled check
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix model override bug and add client REPL sample
    
    - InputConverter: stop propagating request.Model to ChatOptions.ModelId
      Hosted agents use their own model; client-provided model values like
      'hosted-agent' were being passed through and causing server errors.
    - Add FoundryResponsesRepl sample: interactive CLI client that connects
      to a Foundry Responses endpoint using ResponsesClient.AsAIAgent()
    - Bump package version to 0.9.0-hosted.260403.1
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Catch agent errors and emit response.failed with real error message
    
    Previously, unhandled exceptions from agent execution would bubble up
    to the SDK orchestrator, which emits a generic 'An internal server
    error occurred.' message — hiding the actual cause (e.g., 401 auth
    failures, model not found, etc.).
    
    Now AgentFrameworkResponseHandler catches non-cancellation exceptions
    and emits a proper response.failed event containing the real error
    message, making it visible to clients and in logs.
    
    OperationCanceledException still propagates for proper cancellation
    handling by the SDK.
    
    Also bumps package version to 0.9.0-hosted.260403.2.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Renaming and merging hosting extensions. (#5091)
    
    * Rename AddAgentFrameworkHandler to AddFoundryResponses and add MapFoundryResponses
    
    - Rename extension methods: AddAgentFrameworkHandler -> AddFoundryResponses, MapAgentFrameworkHandler -> MapFoundryResponses
    - AddFoundryResponses now calls AddResponsesServer() internally
    - Add MapFoundryResponses() extension on IEndpointRouteBuilder
    - Update sample and tests to use new API names
    - Remove redundant AddResponsesServer() and /ready endpoint from sample
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fixing numbering in sample.
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address breaking changes in 260408
    
    * Bump hosted internal package version
    
    * Add UserAgent middleware tests for Foundry hosting
    
    * Hosting Samples update
    
    * Hosting Samples update
    
    * Hosting Samples update
    
    * Hosting Samples update
    
    * ChatClientAgent working
    
    * Adding SessionStorage and SessionManagement, improving samples to align Consumption vs Hosting
    
    * Using updates
    
    * Update chat client agent for contributor and devs
    
    * Foundry Agent Hosting
    
    * Address text rag sample working
    
    * Version bump
    
    * Adding LocalTools + Workflow samples
    
    * Removing extra using samples
    
    * Add Hosted-McpTools sample with dual MCP pattern
    
    Demonstrates two MCP integration layers in a single hosted agent:
    - Client-side MCP: McpClient connects to Microsoft Learn, agent handles
      tool invocations locally (docs_search, code_sample_search, docs_fetch)
    - Server-side MCP: HostedMcpServerTool delegates tool discovery and
      invocation to the LLM provider (Responses API), no local connection
    
    Includes DevTemporaryTokenCredential for Docker local debugging,
    Dockerfile.contributor for ProjectReference builds, and the openai/v1
    route mapping for AIProjectClient compatibility in Development mode.
    
    * .NET: Bump Azure.AI.AgentServer packages to 1.0.0-beta.1/beta.21 and fix br… (#5287)
    
    * Bump Azure.AI.AgentServer packages to 1.0.0-beta.1/beta.21 and fix breaking API changes
    
    - Azure.AI.AgentServer.Core: 1.0.0-beta.11 -> 1.0.0-beta.21
    - Azure.AI.AgentServer.Invocations: 1.0.0-alpha.20260408.4 -> 1.0.0-beta.1
    - Azure.AI.AgentServer.Responses: 1.0.0-alpha.20260408.4 -> 1.0.0-beta.1
    - Azure.Identity: 1.20.0 -> 1.21.0 (transitive requirement)
    - Azure.Core: 1.52.0 -> 1.53.0 (transitive requirement)
    - Remove azure-sdk-for-net dev feed (packages now on nuget.org)
    - Fix OutputConverter for new builder API (auto-tracked children, split EmitTextDone/EmitDone)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fixing small issues.
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add Azure AI Foundry Responses hosting adapter
    
    Implement Microsoft.Agents.AI.Hosting.AzureAIResponses to host agent-framework
    AIAgents and workflows within Azure Foundry as hosted agents via the
    Azure.AI.AgentServer.Responses SDK.
    
    - AgentFrameworkResponseHandler: bridges ResponseHandler to AIAgent execution
    - InputConverter: converts Responses API inputs/history to MEAI ChatMessage
    - OutputConverter: converts agent response updates to SSE event stream
    - ServiceCollectionExtensions: DI registration helpers
    - 336 unit tests across net8.0/net9.0/net10.0 (112 per TFM)
    - ResponseStreamValidator: SSE protocol validation tool for samples
    - FoundryResponsesHosting sample app
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Bump System.ClientModel to 1.10.0 for Azure.Core 1.52.0 compat
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Clean up tests and sample formatting
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Update Azure.AI.AgentServer packages to 1.0.0-alpha.20260401.5
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add hosted package version suffix (0.9.0-hosted) to distinguish from mainline
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Move Foundry Responses hosting into Microsoft.Agents.AI.Foundry package
    
    Move source and test files from the standalone Hosting.AzureAIResponses project
    into the Foundry package under a Hosting/ subfolder. This consolidates the
    Foundry-specific hosting adapter into the main Foundry package.
    
    - Source: Microsoft.Agents.AI.Foundry.Hosting namespace
    - Tests: merged into Foundry.UnitTests/Hosting/
    - Conditionally compiled for .NETCoreApp TFMs only (net8.0+)
    - Deleted standalone Hosting.AzureAIResponses project and test project
    - Updated sample and solution references
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Bump package version to 0.9.0-hosted.260402.2
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Bump OpenTelemetry packages to fix NU1109 downgrade errors
    
    - OpenTelemetry/Api/Exporter.Console/Exporter.InMemory: 1.13.1 -> 1.15.0
    - OpenTelemetry.Exporter.OpenTelemetryProtocol: already 1.15.0
    - OpenTelemetry.Extensions.Hosting: already 1.14.0
    - OpenTelemetry.Instrumentation.AspNetCore/Http: already 1.14.0
    - OpenTelemetry.Instrumentation.Runtime: 1.13.0 -> 1.14.0
    - Azure.Monitor.OpenTelemetry.Exporter: 1.4.0 -> 1.5.0
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CA1873: guard LogWarning with IsEnabled check
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix model override bug and add client REPL sample
    
    - InputConverter: stop propagating request.Model to ChatOptions.ModelId
      Hosted agents use their own model; client-provided model values like
      'hosted-agent' were being passed through and causing server errors.
    - Add FoundryResponsesRepl sample: interactive CLI client that connects
      to a Foundry Responses endpoint using ResponsesClient.AsAIAgent()
    - Bump package version to 0.9.0-hosted.260403.1
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Catch agent errors and emit response.failed with real error message
    
    Previously, unhandled exceptions from agent execution would bubble up
    to the SDK orchestrator, which emits a generic 'An internal server
    error occurred.' message — hiding the actual cause (e.g., 401 auth
    failures, model not found, etc.).
    
    Now AgentFrameworkResponseHandler catches non-cancellation exceptions
    and emits a proper response.failed event containing the real error
    message, making it visible to clients and in logs.
    
    OperationCanceledException still propagates for proper cancellation
    handling by the SDK.
    
    Also bumps package version to 0.9.0-hosted.260403.2.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Renaming and merging hosting extensions. (#5091)
    
    * Rename AddAgentFrameworkHandler to AddFoundryResponses and add MapFoundryResponses
    
    - Rename extension methods: AddAgentFrameworkHandler -> AddFoundryResponses, MapAgentFrameworkHandler -> MapFoundryResponses
    - AddFoundryResponses now calls AddResponsesServer() internally
    - Add MapFoundryResponses() extension on IEndpointRouteBuilder
    - Update sample and tests to use new API names
    - Remove redundant AddResponsesServer() and /ready endpoint from sample
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fixing numbering in sample.
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address breaking changes in 260408
    
    * Bump hosted internal package version
    
    * Add UserAgent middleware tests for Foundry hosting
    
    * Hosting Samples update
    
    * Hosting Samples update
    
    * Hosting Samples update
    
    * Hosting Samples update
    
    * ChatClientAgent working
    
    * Adding SessionStorage and SessionManagement, improving samples to align Consumption vs Hosting
    
    * Using updates
    
    * Update chat client agent for contributor and devs
    
    * Foundry Agent Hosting
    
    * Address text rag sample working
    
    * Version bump
    
    * Adding LocalTools + Workflow samples
    
    * Removing extra using samples
    
    * Add Hosted-McpTools sample with dual MCP pattern
    
    Demonstrates two MCP integration layers in a single hosted agent:
    - Client-side MCP: McpClient connects to Microsoft Learn, agent handles
      tool invocations locally (docs_search, code_sample_search, docs_fetch)
    - Server-side MCP: HostedMcpServerTool delegates tool discovery and
      invocation to the LLM provider (Responses API), no local connection
    
    Includes DevTemporaryTokenCredential for Docker local debugging,
    Dockerfile.contributor for ProjectReference builds, and the openai/v1
    route mapping for AIProjectClient compatibility in Development mode.
    
    * Bump Azure.AI.AgentServer packages to 1.0.0-beta.1/beta.21 and fix breaking API changes
    
    - Azure.AI.AgentServer.Core: 1.0.0-beta.11 -> 1.0.0-beta.21
    - Azure.AI.AgentServer.Invocations: 1.0.0-alpha.20260408.4 -> 1.0.0-beta.1
    - Azure.AI.AgentServer.Responses: 1.0.0-alpha.20260408.4 -> 1.0.0-beta.1
    - Azure.Identity: 1.20.0 -> 1.21.0 (transitive requirement)
    - Azure.Core: 1.52.0 -> 1.53.0 (transitive requirement)
    - Remove azure-sdk-for-net dev feed (packages now on nuget.org)
    - Fix OutputConverter for new builder API (auto-tracked children, split EmitTextDone/EmitDone)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fixing small issues.
    
    * Fix IDE0009: add 'this' qualification in DevTemporaryTokenCredential
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix IDE0009: add 'this' qualification in all HostedAgentsV2 samples
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CHARSET: add UTF-8 BOM to Hosted-LocalTools and Hosted-Workflows
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix dotnet format: add Async suffix to test methods (IDE1006), fix encoding and style
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Register AgentSessionStore in test DI setups
    
    Add InMemoryAgentSessionStore registration to all ServiceCollection
    setups in AgentFrameworkResponseHandlerTests and WorkflowIntegrationTests.
    This is needed after the AgentSessionStore infrastructure was introduced
    in the responses-hosting feature. Tests still have NotImplementedException
    stubs for CreateSessionCoreAsync which will be fixed when the session
    infrastructure is fully available.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add Invocations protocol samples (hosted echo agent + client) (#5278)
    
    Add Hosted-Invocations-EchoAgent: a minimal echo agent hosted via the
    Invocations protocol (POST /invocations) using AddInvocationsServer and
    MapInvocationsServer, bridged to an Agent Framework AIAgent through a
    custom InvocationHandler.
    
    Add SimpleInvocationsAgent: a console REPL client that wraps HttpClient
    calls to the /invocations endpoint in a custom InvocationsAIAgent,
    demonstrating programmatic consumption of the Invocations protocol.
    
    Both samples default to port 8088 for consistency with other hosted
    agent samples.
    
    * Restructure FoundryHostedAgents samples into invocations/ and responses/
    
    Align dotnet hosted agent samples with the Python side (PR #5281) by
    reorganizing the directory structure:
    
    - Remove HostedAgentsV1 entirely (old API pattern)
    - Split HostedAgentsV2 into invocations/ and responses/ based on protocol
    - Move Using-Samples accordingly (SimpleAgent to responses, SimpleInvocationsAgent to invocations)
    - Update slnx with new project paths and add previously missing invocations projects
    - Update README cd paths from HostedAgentsV2 to invocations or responses
    - Rename .env.local to .env.example to match Python naming convention
    - Fix format violations in newly included invocations projects
    
    * Remove launchSettings, use .env for port configuration
    
    - Delete all launchSettings.json files (port 8088 now comes from ASPNETCORE_URLS in .env)
    - Add DotNetEnv to Hosted-Invocations-EchoAgent so it loads .env like the responses samples
    - Create .env.example for EchoAgent with ASPNETCORE_URLS and ASPNETCORE_ENVIRONMENT
    - Add AGENT_NAME to ChatClientAgent and FoundryAgent .env.example (required by those samples)
    - Add AZURE_BEARER_TOKEN=DefaultAzureCredential to all .env.example files
    - Update DevTemporaryTokenCredential in all 6 samples to treat the sentinel value
      as unavailable, allowing ChainedTokenCredential to fall through to DefaultAzureCredential
    - Update EchoAgent README with Configuration section
    
    * Use placeholder for AGENT_NAME in Hosted-FoundryAgent .env.example
    
    * Move FoundryResponsesHosting to responses/Hosted-WorkflowHandoff, use GetResponsesClient
    
    * Rename Hosted-Workflows to Hosted-Workflow-Simple, Hosted-WorkflowHandoff to Hosted-Workflow-Handoff
    
    * Remove FoundryResponsesRepl and empty FoundryResponsesHosting directory
    
    * Add Dockerfiles, README, agent yamls and bearer token support to Hosted-Workflow-Handoff
    
    - Add Dockerfile and Dockerfile.contributor for Docker-based testing
    - Add agent.yaml and agent.manifest.yaml with triage-workflow as primary agent
    - Add README.md following sibling pattern, noting Azure OpenAI vs Foundry endpoint
    - Add DevTemporaryTokenCredential and ChainedTokenCredential for Docker auth
    - Register triage-workflow as non-keyed default so azd invoke works without model
    - Update .env.example with AZURE_BEARER_TOKEN sentinel
    - Add .gitignore to 04-hosting to suppress VS-generated launchSettings.json
    - Fix docker run image name in Hosted-Workflow-Simple README
    
    * Fix AgentFrameworkResponseHandlerTests: implement session methods in test mock agents
    
    * .NET: Auto-instrument resolved AIAgents with OpenTelemetry for Foundry Hosted Agents (#5316)
    
    * Auto-instrument resolved AIAgents with OpenTelemetry using Core ResponsesSourceName
    
    * Add OTel telemetry capture tests for Foundry hosted agent handler
    
    * Net: Prepare Foundry Preview Release (#5336)
    
    * Prepare Foundry preview release 1.2.0-preview.*
    
    Bump VersionPrefix to 1.2.0 and update the preview stamp date. Invert packaging opt-in so only the Foundry preview set produces NuGet packages:
    
    - Microsoft.Agents.AI.Abstractions
    
    - Microsoft.Agents.AI
    
    - Microsoft.Agents.AI.Workflows
    
    - Microsoft.Agents.AI.Workflows.Generators
    
    - Microsoft.Agents.AI.Foundry
    
    Flip IsReleased=false on the preview set so they pick up the -preview.YYMMDD.N suffix. Gate GeneratePackageOnBuild on IsPackable=true. Remove the global IsPackable=true from nuget-package.props so the repo-level default (false) applies to everything else.
    
    * Lower preview VersionPrefix to 0.0.1
    
    Retroactive preview publish: bump VersionPrefix and GitTag from 1.2.0 to 0.0.1 so the 5 Foundry preview packages emit as 0.0.1-preview.260417.1.
    
    * Net: Publish all packages as 0.0.1-preview.260417.2 (#5341)
    
    Revises the Foundry pre-release approach to publish ALL normally packable src projects as preview packages stamped 0.0.1-preview.260417.2, including projects previously flagged IsReleased=true or with a non-default VersionSuffix (rc/alpha).
    
    nuget-package.props:
    
    - Collapse the four conditional PackageVersion expressions (IsReleaseCandidate, VersionSuffix, default preview, IsReleased stable) into a single unconditional 0.0.1-preview.260417.2. On this preview-only branch every package ships with the same pre-release stamp regardless of per-project flags.
    
    - Restore the global IsPackable=true default (offsetting the repo-wide IsPackable=false in Directory.Build.props). Projects that opt out (Mem0, Declarative) already set IsPackable=false AFTER importing this file so they remain non-packable.
    
    - Remove the IsReleased-gated EnablePackageValidation line. Package validation does not apply to a 0.0.1 preview.
    
    csproj reverts (Abstractions, Agents.AI, Workflows, Workflows.Generators, Foundry):
    
    - Revert the IsPackable=true opt-in block introduced in #5336 (now redundant since the props default is true again).
    
    - Restore IsReleased=true to its pre-PR value. The setting is now a no-op because the props no longer branches on it.
    
    * Bump preview version to 260420.1 and fix AgentServer package deps (#5367)
    
    - Bump PackageVersion to 0.0.1-preview.260420.1
    - Bump Azure.AI.AgentServer.Core beta.21 -> beta.22 (required by
      Azure.AI.AgentServer.Responses beta.3)
    - Replace AgentHostTelemetry.ResponsesSourceName with local constant
      (type made internal in AgentServer.Core beta.22)
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * .NET: Hosted agents toolbox support (#5368)
    
    * feat: Add Foundry Toolbox (MCP) support to AgentFrameworkResponseHandler
    
    Adds support for Foundry Toolsets MCP proxy integration in the hosted agent
    response handler. Toolsets connect at startup via IHostedService, gating the
    readiness probe per spec §3.1. MCP tools are injected into every request's
    ChatOptions and OAuth consent errors (-32006) are intercepted and surfaced as
    mcp_approval_request + incomplete SSE events.
    
    New files:
    - FoundryToolboxOptions.cs: configuration POCO for toolset names and API version
    - FoundryToolboxBearerTokenHandler.cs: DelegatingHandler with Azure Bearer token
      auth, Foundry-Features header injection, and 3x exponential backoff on 429/5xx
    - McpConsentContext.cs: AsyncLocal-based per-request consent state shared between
      the tool wrapper and the response handler
    - ConsentAwareMcpClientTool.cs: AIFunction wrapper that catches -32006 errors and
      signals consent via shared state and linked CancellationTokenSource
    - FoundryToolboxService.cs: IHostedService that creates McpClient per toolset at
      startup and exposes cached tools
    
    Modified files:
    - AgentFrameworkResponseHandler.cs: injects toolbox tools into ChatOptions, sets
      up linked CTS consent interception, emits mcp_approval_request on -32006
    - ServiceCollectionExtensions.cs: adds AddFoundryToolboxes(params string[]) extension
    - Microsoft.Agents.AI.Foundry.csproj: adds ModelContextProtocol and Azure.Identity
      dependencies under NETCoreApp condition
    
    Sample:
    - Hosted-Toolbox: minimal hosted agent sample using AddFoundryToolboxes
    
    * Rename toolset to toolbox in user-facing API; rename ConsentAwareMcpClientTool to ConsentAwareMcpClientAIFunction
    
    * Add HostedMcpToolboxAITool for client-selectable Foundry toolboxes
    
    Introduces HostedMcpToolboxAITool, a marker tool subclassing HostedMcpServerTool that rides the OpenAI Responses 'mcp' wire format to let clients request a specific Foundry toolbox per request.
    
    - New FoundryAITool.CreateHostedMcpToolbox(name, version?) factory.
    
    - FoundryToolboxOptions.StrictMode (default true) rejects unregistered toolboxes; set to false to allow lazy-open on first use.
    
    - FoundryToolboxService.GetToolboxToolsAsync(name, version?) resolves cached or lazy-opened MCP tools.
    
    - AgentFrameworkResponseHandler parses request.Tools for foundry-toolbox://name[?version=v] markers and injects resolved tools per request, merging with pre-registered ones.
    
    - Unit tests for marker parsing and strict-mode resolution.
    
    * Bump Azure.AI.Projects to 2.1.0-alpha; add ToolboxRecord/ToolboxVersion factory overloads + tests
    
    * Fix PR review issues: retry off-by-one, URI encoding, docs, tests, build
    
    - Fix off-by-one in FoundryToolboxBearerTokenHandler retry loop (4 attempts → 3)
    - URI-encode version parameter in HostedMcpToolboxAITool.BuildAddress
    - Add XML doc clarifying version pinning is reserved for future use
    - Add comment clarifying AddHostedService deduplication safety
    - Fix DevTemporaryTokenCredential expiry to use DateTimeOffset.MaxValue
    - Fix AgentCard ambiguity in A2AServer sample with using alias
    - Add 18 new unit tests for retry handler and ReadMcpToolboxMarkers
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * .NET: Hosted agent adapter (#5371)
    
    * Bump preview version to 260420.1 and fix AgentServer package deps
    
    - Bump PackageVersion to 0.0.1-preview.260420.1
    - Bump Azure.AI.AgentServer.Core beta.21 -> beta.22 (required by
      Azure.AI.AgentServer.Responses beta.3)
    - Replace AgentHostTelemetry.ResponsesSourceName with local constant
      (type made internal in AgentServer.Core beta.22)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CA1873: guard LogError with IsEnabled check in FoundryToolboxService
    
    Wrap the LogError call with an IsEnabled(LogLevel.Error) guard to satisfy
    the CA1873 analyzer rule which flags potentially expensive argument
    evaluation when logging is disabled.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * .NET: Hosted agent adapter (#5374)
    
    * Bump preview version to 260420.1 and fix AgentServer package deps
    
    - Bump PackageVersion to 0.0.1-preview.260420.1
    - Bump Azure.AI.AgentServer.Core beta.21 -> beta.22 (required by
      Azure.AI.AgentServer.Responses beta.3)
    - Replace AgentHostTelemetry.ResponsesSourceName with local constant
      (type made internal in AgentServer.Core beta.22)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CA1873: guard LogError with IsEnabled check in FoundryToolboxService
    
    Wrap the LogError call with an IsEnabled(LogLevel.Error) guard to satisfy
    the CA1873 analyzer rule which flags potentially expensive argument
    evaluation when logging is disabled.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Bumping NuGet version
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * .NET: Hosted agent adapter (#5406)
    
    * Bump preview version to 260420.1 and fix AgentServer package deps
    
    - Bump PackageVersion to 0.0.1-preview.260420.1
    - Bump Azure.AI.AgentServer.Core beta.21 -> beta.22 (required by
      Azure.AI.AgentServer.Responses beta.3)
    - Replace AgentHostTelemetry.ResponsesSourceName with local constant
      (type made internal in AgentServer.Core beta.22)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CA1873: guard LogError with IsEnabled check in FoundryToolboxService
    
    Wrap the LogError call with an IsEnabled(LogLevel.Error) guard to satisfy
    the CA1873 analyzer rule which flags potentially expensive argument
    evaluation when logging is disabled.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Bumping NuGet version
    
    * Restore conditional versioning, remove dev feed, bump Azure.AI.Projects to beta.1
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Hosted agent adapter (#5408)
    
    * Bump preview version to 260420.1 and fix AgentServer package deps
    
    - Bump PackageVersion to 0.0.1-preview.260420.1
    - Bump Azure.AI.AgentServer.Core beta.21 -> beta.22 (required by
      Azure.AI.AgentServer.Responses beta.3)
    - Replace AgentHostTelemetry.ResponsesSourceName with local constant
      (type made internal in AgentServer.Core beta.22)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix CA1873: guard LogError with IsEnabled check in FoundryToolboxService
    
    Wrap the LogError call with an IsEnabled(LogLevel.Error) guard to satisfy
    the CA1873 analyzer rule which flags potentially expensive argument
    evaluation when logging is disabled.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Bumping NuGet version
    
    * Restore conditional versioning, remove dev feed, bump Azure.AI.Projects to beta.1
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR #5312 review comments
    
    - Add comment explaining NU1903 suppression (Microsoft.Bcl.Memory transitive vuln)
    - Remove NU1903 from sample/test projects where not needed
    - Fix Dockerfile ENTRYPOINT mismatch in Hosted-Workflow-Simple
    - Align agent name to 'hosted-workflow-simple' in agent.yaml and README
    - Fix Hosted-McpTools README: replace GitHub PAT refs with Microsoft Learn
    - Fix session persistence: only persist when client provides conversation ID
    - Upgrade IsNullOrEmpty to IsNullOrWhiteSpace for session ID checks
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Split Foundry into stable V1 and preview Hosting package
    
    Extract hosted agent functionality from Microsoft.Agents.AI.Foundry into a
    new Microsoft.Agents.AI.Foundry.Hosting preview package. This resolves NU5104
    build errors caused by the stable Foundry package depending on prerelease
    Azure SDK packages (Azure.AI.AgentServer.Responses, Azure.AI.Projects beta).
    
    Changes:
    - Create Microsoft.Agents.AI.Foundry.Hosting with VersionSuffix=preview,
      targeting .NET Core only (net8.0/9.0/10.0)
    - Move all Hosting/ source files to the new project
    - Move ToolboxRecord/ToolboxVersion overloads to FoundryAIToolExtensions
    - Revert Azure.AI.Projects to 2.0.0 in Directory.Packages.props;
      Hosting uses VersionOverride for 2.1.0-beta.1
    - Clean V1 Foundry csproj: remove beta deps, ASP.NET Core ref, hosting conditionals
    - Update 8 hosted agent sample projects to reference Foundry.Hosting
    - Split unit tests: ToolboxRecord/ToolboxVersion tests moved to Hosting/
    - Add Foundry.Hosting to solution file
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review comments: experimental attrs, doc fixes, token propagation
    
    - Add [Experimental(OPENAI001)] to all 7 public Hosting types per reviewer request
    - Fix McpConsentContext XML doc: 'Thread-static' -> 'Async-local' (AsyncLocal
      flows with ExecutionContext, not thread-static)
    - Expand UserAgentMiddleware test regex to match prerelease versions (e.g. 1.0.0-rc.4)
    - Propagate CancellationToken in AgentFrameworkResponseHandler session save
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove unnecessary MEAI001 suppression from stable Foundry package
    
    MEAI001 was a leftover from when Hosting code lived in the same project.
    The stable V1 Foundry package builds clean without it, and suppressing
    experimental diagnostics in a released package can hide unintentional
    exposure of experimental APIs to consumers.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add Foundry.Hosting to release solution filter
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Ben Thomas <ben.thomas@microsoft.com>
  • .NET: Foundry Evals integration for .NET (#4914)
    * Foundry Evals integration for .NET
    
    - Core evaluation framework: EvalItem, LocalEvaluator, FunctionEvaluator, EvalChecks
    - IAgentEvaluator interface with MeaiEvaluatorAdapter bridge
    - AgentEvaluationExtensions for agent.EvaluateAsync() overloads
    - FoundryEvals wrapping MEAI quality/safety evaluators
    - ConversationSplitters (LastTurn, Full) and IConversationSplitter
    - EvalItem.PerTurnItems() for multi-turn decomposition
    - HasImageContent for multimodal content detection
    - WorkflowEvaluationExtensions for per-agent workflow evaluation
    - 7 eval samples mirroring Python parity:
      02-agents/Evaluation: SimpleEval, ExpectedOutputs, Multimodal
      03-workflows/Evaluation: WorkflowEval
      05-end-to-end/Evaluation: FoundryQuality, MixedProviders, ConversationSplits
    - Comprehensive unit tests (1958 passing)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Rewrite FoundryEvals to use real Foundry Evals API
    
    Replace MEAI evaluator shim with actual OpenAI EvaluationClient protocol
    methods. FoundryEvals now creates eval definitions, submits runs, polls
    for completion, and fetches per-item results server-side.
    
    - New constructor: FoundryEvals(AIProjectClient, model, evaluators)
    - Add FoundryEvalConverter for MEAI ChatMessage -> Foundry JSON format
    - Add EvalId, RunId, ReportUrl to AgentEvaluationResults
    - All 20 built-in evaluator constants now work (agent, tool, quality, safety)
    - Remove Microsoft.Extensions.AI.Evaluation.Quality/Safety dependencies
    - Update all samples for new constructor (no more ChatConfiguration)
    - Replace BuildEvaluators tests with ResolveEvaluator tests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add response output to CustomEvals and ExpectedOutputs samples
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: pagination, validation, error handling, tests
    
    FoundryEvals fixes:
    - Add pagination for output items (has_more/after cursor)
    - Add guard clauses for pollIntervalSeconds/timeoutSeconds <= 0
    - Fix double TryGetProperty for passed field parsing
    - Throw on all-tool-evaluators with no tool definitions
    - Fix XML doc (default 300s, not 180s)
    
    New tests (30 added, 1989 total):
    - EvalChecks: NonEmpty, ContainsExpected (pass/fail/skip/case),
      HasImageContent, ToolCallsPresent
    - FoundryEvalConverter: ConvertMessage (text, image, function call,
      function results fan-out, empty fallback, mixed content),
      ConvertEvalItem, BuildTestingCriteria (quality/agent/tool/groundedness
      data mappings), BuildItemSchema
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix review: null-refs, Data.ToString() bug, ContainsExpected, add tests
    
    - Fix NullReferenceException in sample Response display (pattern matching)
    - Fix WorkflowEvaluationExtensions Data?.ToString() producing type names
      instead of message text (pattern-match ChatMessage/AgentResponse/list)
    - Change EvalChecks.ContainsExpected to return Passed=false when no
      ExpectedOutput (was silently passing, masking misconfiguration)
    - Add EvalItem constructor tests with LastTurn/Full/null splitters
    - Add FoundryEvalConverter.ConvertMessage DataContent (base64 image) test
    - Add ExtractAgentData tests with ChatMessage, list, and AgentResponse data
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix review: conversation fidelity, eval caching, fallback tests
    
    - WorkflowEvaluationExtensions: preserve full response messages (tool calls,
      intermediate) instead of synthetic 2-message conversation. Cast completed
      Data to AgentResponse and use Messages when available, fallback to text.
    - FoundryEvals: cache evalId per schema shape (hasContext, hasTools) so
      subsequent EvaluateAsync calls create runs under the same eval definition.
    - MeaiEvaluatorAdapter: code already correctly passes queryMessages (not full
      conversation) to IEvaluator — no change needed, verified by inspection.
    - Add tests: AgentResponse full messages preservation, unknown object
      ToString() fallback for ExtractAgentData.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Rename AzureAI→Foundry: move eval files, update references
    
    - Move FoundryEvals.cs and FoundryEvalConverter.cs from
      Microsoft.Agents.AI.AzureAI to Microsoft.Agents.AI.Foundry
    - Update namespace from AzureAI to Foundry in both files
    - Add explicit usings required by Foundry project (no implicit usings)
    - Move FoundryEvalConverter tests to Foundry.UnitTests project
      (avoids ReplacingRedactor type conflict from dual project refs)
    - Update all sample csproj references and using statements
    - Remove Foundry project reference from AI UnitTests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * PR review round 4: wire up tool extraction, remove eval cache, fix null safety
    
    - BuildEvalItem: extract tools from agent via GetService<ChatOptions>() into EvalItem.Tools (Python parity)
    - FoundryEvals: remove eval ID cache - each call creates fresh definition (matches Python behavior)
    - FoundryEvals: replace null-forgiving operators with descriptive InvalidOperationException
    - MixedProviders sample: remove unnecessary explicit PackageReferences (transitively provided)
    - FoundryEvalConverter: document that tool results take precedence over text content
    - Add LocalEvaluator zero-checks test documenting 0 metrics = failed behavior
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Python-dotnet parity: 9 feature gaps filled
    
    New checks:
    - ToolCallArgsMatch() — verify tool call names + argument subset match
    - ToolCalledCheck(ToolCalledMode.Any, ...) — match any of the specified tools
    - ToolCalledMode enum (All/Any)
    
    FoundryEvals enhancements:
    - Default evaluators now [Relevance, Coherence, TaskAdherence] (was Relevance, Coherence)
    - Auto-add ToolCallAccuracy when items have tool definitions
    - EvaluateTracesAsync — evaluate by response_ids, trace_ids, or agent_id
    - EvaluateFoundryTargetAsync — evaluate deployed Foundry targets
    
    Result type enrichment:
    - AgentEvaluationResults: added Status, Error, PerEvaluator, DetailedItems
    - New EvalItemResult/EvalScoreResult/PerEvaluatorResult types
    - FoundryEvals populates all new fields from API responses
    
    Workflow fix:
    - Skip internal executors (_*, input-conversation, end-conversation, end)
    
    Tests: 8 new tests covering ToolCallArgsMatch, ToolCalledMode.Any, internal executor filtering
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add MeaiEvaluatorAdapter and PerTurnItems edge case tests
    
    - 3 tests for MeaiEvaluatorAdapter: query message forwarding, synthetic
      response fallback, multiple items aggregation
    - 3 tests for EvalItem.PerTurnItems: empty conversation, no user messages,
      system+assistant only
    - StubEvaluator and StubChatClient test helpers
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Blocking link check for outdated package in DevUI.
    
    * Replace Dictionary<string, object> payloads with typed wire models
    
    Introduce internal FoundryEvalWireModels.cs with compile-time-safe types
    for the OpenAI Evals API wire format. The OpenAI .NET SDK (2.9.1) only
    provides protocol-level methods with BinaryContent/ClientResult — no
    typed request models. These internal models replace scattered dictionary
    literals with [JsonPropertyName]-annotated classes, giving:
    
    - Compile-time safety (typos become build errors)
    - Single point of change when the API evolves
    - IntelliSense discoverability
    - Cleaner serialization via JsonPolymorphic for content items
    
    Models: WireContentItem hierarchy (text, image, tool_call, tool_result),
    WireMessage, WireEvalItemPayload, WireTestingCriterion, WireItemSchema,
    WireCreateEvalRequest, WireCreateRunRequest, and data source variants.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Skip metric when Foundry returns neither score nor passed
    
    When an evaluator returns no score and no passed value, the previous
    code created BooleanMetric(name, false), which falsely failed items
    via ItemPassed. Now we skip the MEAI metric entirely for indeterminate
    results — the raw data remains available in DetailedItems for diagnostics.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR #4914 review comments: fix tool evaluator bug and add tests
    
    - Fix duplicate ToolCallAccuracy: resolve evaluator names before checking
      against ToolEvaluators set (Comment 2)
    - Make FilterToolEvaluators internal for testability; add tests for the
      ArgumentException edge case when all evaluators are tool-type (Comment 3)
    - Add CancellationToken test for LocalEvaluator (Comment 4)
    - Add EvaluateAsync integration test on Run with sequential workflow and
      per-agent SubResults verification (Comment 5)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address Peter's review comments on PR #4914
    
    - Add trailing newline to Evaluation_FoundryQuality.csproj (Comment 6)
    - Make evaluator name lookups case-insensitive: switch BuiltinEvaluators,
      ToolEvaluators, AgentEvaluators, and ResolveEvaluator's StartsWith check
      from Ordinal to OrdinalIgnoreCase (Comment 7)
    - Add Trace.TraceWarning when Foundry returns fewer results than submitted
      items, indicating expected vs actual count before padding (Comment 8)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add Microsoft.Extensions.AI.Evaluation packages to Directory.Packages.props
    
    These were removed in #5269 as unused, but are needed by the Foundry
    and core evaluation integration added in this PR.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: alliscode <bentho@microsoft.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Add CreateSessionAsync(conversationId) to FoundryAgent (#5144)
    Adds a public CreateSessionAsync(string conversationId, CancellationToken)
    method to FoundryAgent that delegates to the inner ChatClientAgent,
    allowing users to create sessions with existing server-side conversation IDs.
    
    Fixes #5138
  • .NET: Bump Azure.AI.Projects to 2.0.0 GA (#5060)
    * Bump Azure.AI.Projects to 2.0.0 GA
    
    - Update Azure.AI.Projects from 2.0.0-beta.2 to 2.0.0 in CPM
    - Update Azure.Identity from 1.19.0 to 1.20.0 (transitive dep)
    - Update System.ClientModel from 1.9.0 to 1.10.0 (transitive dep)
    - Rename types per Azure.AI.Projects.Agents 2.0.0 breaking changes:
      - AgentVersion -> ProjectsAgentVersion
      - AgentRecord -> ProjectsAgentRecord
      - AgentDefinition -> ProjectsAgentDefinition
      - AgentVersionCreationOptions -> ProjectsAgentVersionCreationOptions
      - PromptAgentDefinition -> DeclarativeAgentDefinition
      - AgentTool -> ProjectsAgentTool
      - AgentsClient -> AgentAdministrationClient
      - .Agents property -> .AgentAdministrationClient
    - Add using Azure.AI.Projects.Memory namespace (types moved)
    - Update AGENTS.md with BOM and output capture conventions
    
    * Address PR review feedback
    
    - Rename AIProjectClient parameter to aiProjectClient in AsChatClientAgent overloads
    - Fix XML doc: ProjectsAgentTool namespace from Azure.AI.Projects.OpenAI to Azure.AI.Projects.Agents
    - Rename test method to reflect DeclarativeAgentDefinition terminology
  • .NET: Rename Microsoft.Agents.AI.AzureAI to Microsoft.Agents.AI.Foundry and consolidate FoundryMemory (#5042)
    * Update Foundry Responses as ChatClientAgent
    
    * Migrate obsolete AzureAI integration tests to versioned agent pattern
    
    Replace obsolete CreateAIAgentAsync/GetAIAgentAsync calls with
    Agents.CreateAgentVersionAsync() + AsAIAgent(AgentVersion) in all
    AzureAI integration tests.
    
    - Rename AIProjectClient* test files to FoundryVersionedAgent*
    - Register AIFunction tools in PromptAgentDefinition.Tools for
      server-side visibility via AsOpenAIResponseTool()
    - Skip structured output tests (AzureAIProjectChatClient clears
      ResponseFormat for versioned agents)
    - Remove all [Obsolete] attributes and #pragma warning disable CS0618
    
    * Merge FoundryMemory package into AzureAI under Memory/ folder
    
    Move all FoundryMemory source, unit tests, and integration tests into
    the Microsoft.Agents.AI.AzureAI package. Change namespace from
    Microsoft.Agents.AI.FoundryMemory to Microsoft.Agents.AI.AzureAI.
    
    - Add [Experimental] to FoundryMemoryProviderOptions and Scope
    - Rename internal AIProjectClientExtensions to MemoryStoreExtensions
    - Update AzureAI .csproj with Compliance.Abstractions, Redaction
    - Remove FoundryMemory from solution and release filter
    - Update sample to reference AzureAI instead of FoundryMemory
    - Delete old Microsoft.Agents.AI.FoundryMemory project and tests
    
    * Add EnsureMemoryStoreCreatedAsync and memory existence checks to integration tests
    
    - Ensure memory store is created before testing memory operations
    - Add AZURE_AI_EMBEDDING_DEPLOYMENT_NAME config setting
    - Assert memories exist in store via SearchMemoriesAsync before cleanup
    - Verify scope isolation with direct memory store queries
    
    * Fix and rename AzureAI unit tests for RAPI vs Versioned clarity
    
    - Rename AsAIAgentAsync_* to AsAIAgent_* (drop Async from method group)
    - Add _Rapi_ prefix to non-versioned (Responses API) tests
    - Add _Versioned_ prefix to versioned agent tests where needed
    - Fix RAPI tests: assert GetService<AIProjectClient>() is null
    - Fix Versioned tests: assert IsType<FoundryAgent> and
      GetService<AIProjectClient>() returns the client instance
    - Fix UserAgent header tests: proper HTTP handler routing
    - Fix ChatClient_UsesDefaultConversationIdAsync test setup
    - All 153 unit tests pass with 0 failures
    
    * Rename Microsoft.Agents.AI.AzureAI to Microsoft.Agents.AI.Foundry
    
    Rename the project, namespace, folder, and all references from
    Microsoft.Agents.AI.AzureAI to Microsoft.Agents.AI.Foundry.
    Also rename Workflows.Declarative.AzureAI to .Foundry.
    
    - Rename src, unit test, integration test, and workflow folders
    - Update namespaces in all source and test .cs files
    - Update ProjectReferences in ~47 sample and test .csproj files
    - Update solution files (.slnx, .slnf)
    - Update sample using statements
    - Update READMEs, SKILL.md, ADRs in docs/
    - Disable package validation baseline for renamed packages
    - Fix UTF-8 BOM encoding on all affected .cs files
    - AzureAI.Persistent left completely unchanged
    
    * Fix format: remove ImplicitUsings, add explicit usings, fix BOM encoding
    
    - Remove ImplicitUsings=enable from Foundry csproj to resolve IDE0005
      on shared ReplacingRedactor.cs
    - Add explicit System usings to all source files that relied on them
    - Sort usings alphabetically per editorconfig rules
    - Fix UTF-8 BOM on 12 sample Program.cs files
    - Rename Azure AI Foundry Agents to Microsoft Foundry Agents in docs