Commit Graph

3 Commits

  • .NET: Remove Foundry Toolbox server-side tools support (#5753)
    * .NET: Remove Foundry Toolbox server-side tools support
    
    Mirrors the Python cleanup in microsoft/agent-framework#5671. Passing
    toolbox tools as server-side Responses tools is not the experience we
    want to support; the hosted-agent MCP toolbox path (HostedMcpToolboxAITool
    + FoundryToolboxService) remains the supported way to consume Foundry
    Toolboxes.
    
    Removed:
    - FoundryToolbox static class (GetToolboxVersionAsync / GetToolsAsync /
      ToAITools / SanitizeAndConvert)
    - AIProjectClient.GetToolboxToolsAsync extension
    - Agent_Step25_ToolboxServerSideTools sample (+ slnx entry)
    - FoundryToolboxTests, TestDataUtil, HttpHandlerAssert, and the toolbox
      JSON fixtures only those tests referenced
    - ToolboxHostedAgentTests and ToolboxHostedAgentFixture; the "toolbox"
      switch arm + CreateToolboxAgent helper in TestContainer; matching
      README scenario row and bootstrap script entry
    
    Kept (MCP path, unchanged):
    - HostedMcpToolboxAITool, FoundryAITool.CreateHostedMcpToolbox,
      FoundryAIToolExtensions.CreateHostedMcpToolbox(ToolboxRecord/Version)
    - FoundryToolboxService, AddFoundryToolboxes, marker injection in
      AgentFrameworkResponseHandler, InputConverter.ReadMcpToolboxMarkers
    - Hosted-Toolbox sample, McpToolbox* tests, FoundryToolboxServiceTests
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * .NET: Add Foundry Toolbox MCP sample (Agent_Step25_FoundryToolboxMcp)
    
    Adds a non-hosted-agent equivalent of the Python foundry_chat_client_with_toolbox.py sample. The agent connects to a Foundry Toolbox's MCP endpoint via Streamable HTTP, injects a fresh Azure AI bearer token on every request, and discovers the toolbox's tools at runtime via McpClient.ListToolsAsync.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * .NET: Tighten Agent_Step25_FoundryToolboxMcp README/Program comments
    
    Drop 'non-hosted agent' framing from README (this sample isn't related to hosted agents) and remove narrative comparison to server-side tools from the Program.cs header comment.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Drop python sample reference from Agent_Step25 README
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Drop incorrect .NET 10 prereq from Agent_Step25 README
    
    Toolboxes don't require .NET 10 (Microsoft.Agents.AI.Foundry targets net8.0+); the parent AgentsWithFoundry README already lists the sample SDK prereq.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix Toolsets api-version in Agent_Step25 example endpoint
    
    Use 2025-05-01-preview to match FoundryToolboxOptions.ApiVersion. The placeholder 'v1' is not accepted by the Toolsets endpoint.
    
    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: 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: 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)