Commit Graph

2234 Commits

  • Python A2A: Expose supported_protocol_bindings as configurable parameter (#6098)
    * Expose supported_protocol_bindings as configurable parameter on A2AAgent
    
    Add supported_protocol_bindings parameter to A2AAgent.__init__() allowing
    users to configure which A2A protocol bindings (JSONRPC, GRPC, HTTP+JSON)
    the client prefers when connecting to remote agents.
    
    - Defaults to ["JSONRPC"] matching current behavior
    - Passes through to ClientConfig for transport negotiation
    - Replaces 4 hardcoded references with the configurable value
    
    Closes #6057
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix empty list falsy trap and add fallback path test coverage
    
    - Use 'is not None' check instead of 'or' to preserve explicit empty list
    - Add test verifying empty list is not silently replaced with defaults
    - Add test verifying fallback path uses custom bindings
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Document known protocol binding values in docstring
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Use Literal union for protocol binding type hint
    
    Provides IDE autocomplete for known values while keeping the type
    open for custom bindings (Literal is str at runtime).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • .NET: feat: Update GroupChatManager semantics to match other Orchestration patterns (#6140)
    * Refactor group chat workflow to prevent message echoing and enhance checkpointing
    
    - Updated GroupChatWorkflowBuilder to disable forwarding incoming messages to prevent duplicates.
    - Enhanced RoundRobinGroupChatManager with checkpointing support to preserve state across executions.
    - Modified GroupChatHost to maintain a history of messages and track the current speaker for message broadcasting.
    - Implemented broadcasting logic to ensure participants receive messages from others while excluding their own responses.
    - Added comprehensive unit tests for group chat orchestration, including scenarios for tool approval and function calls.
    - Introduced a new ApprovalHarness for testing tool invocation and approval workflows.
    
    * fixup: format
    
    * Add JSON serialization support for GroupChatManagerState and RoundRobinGroupChatManagerState
    
    ---------
    
    Co-authored-by: Jacob Alber <jalber@lokitoth.com>
  • .NET: [Breaking] Refactor AgentFileSkillsSource for depth-based discovery and predicate filters (#6109)
    * Refactor AgentFileSkillsSource to use filter predicates and add AgentFileSkillFilterContext
    
    - Replace hardcoded script/resource directory lists with configurable ScriptFilter and ResourceFilter predicates
    - Add AgentFileSkillFilterContext class to provide contextual file information to filter predicates
    - Replace MaxSearchDepth constant with configurable SearchDepth option
    - Update AgentFileSkillsSourceOptions with new filter and search depth properties
    - Update tests to reflect the new filtering approach
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Log '(none)' instead of empty string for missing file extensions in debug output
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • .NET: feat: Bring Handoff Orchestration to parity with Python (#6138)
    * feat: implement autonomous mode and termination conditions in handoff workflow
    
    * fixup: format
    
    * feat: enhance autonomous mode with per-agent configurations and add unit tests
    
    * fixup: remove empty file
    
    ---------
    
    Co-authored-by: Jacob Alber <jalber@lokitoth.com>
  • .NET: Support ClaimsIdentity-based scoping of agent sessions (#5696)
    * feat: Add DelegatingAgentSessionStore
    
    Add helper for decorator pattern for AgentSessionStore
    
    * feat: Add UserIdentityScopedSessionStore
    
    Add support for using the ASP.Net Core ambient `ClaimsIdentity` User, along with a user-specified claim type to scope the session store based on authenticated identity.
    
    * fix: Harden scope mapping
    
    * fix: Add UserIdentityScopeSessionStoreOptions to avoid future breaking changes
    
    * Split UserIdentityScopedSessionStore into a separate IsolationKeyProvider and IsolationKeyScopedSessionStore
    
    * Add GetService<>() capabilities to interrogate AgentSessionStore delegation chain
    
    * Harden default for A2A hosting by using an IsolationKeyScopedAgentSessionStore when no store is available.
    
    * Pipe isolation through Hosting helper extension methods
    
    * Add comment to samples about adding SessionIsolationKeyProvider
    
    * Fix isolation key provider nullability semantics
    
    * fix A2A defaults
    
    * fixup
    
    * remove unneeded keyProvider requirement test
    
    * Add trust-model XML docs to AgentSessionStore, InMemoryAgentSessionStore, MapAGUI, A2A entry points
    
    Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/e466c53a-faad-40a8-8b5f-83cf0dce0b1d
    
    Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com>
    
    * fix: Switch ClaimsBasedIsolationKeyProvider to be Singleton
    
       * matches HttpContextAccessor and related MAF services
    
    * release: Ensure new project is in the release filter
    
    * fixup: Integraitaon tests
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com>
  • Python: [Breaking] Refactor Skill API to async resource and script lookup (#6135)
    Port of .NET commit 08541ee5a9.
    
    Replace property-based Skill.content/resources/scripts with async
    by-name lookup methods:
    - content property -> async get_content() -> str
    - resources property -> async get_resource(name) -> SkillResource | None
    - scripts property -> async get_script(name) -> SkillScript | None
    
    SkillsProvider now always includes all three tools (load_skill,
    read_skill_resource, run_skill_script) and both instruction blocks
    regardless of whether any skills have resources or scripts.
    
    ClassSkill retains resources/scripts properties as overridable hooks
    for subclass reflection-based discovery.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • .NET: Fix render dupe and text input clear bugs, and improve guardrail error messaging (#6136)
    * Fix render dupe and text input clear bugs
    
    * Fix another text rendering issue and improve guardrails messaging
    
    * Address PR comments
    
    * Improve guardrail rendering and json error handling
    
    * Another tweak for input box render issue
    
    * Address PR comments
  • .NET: Add Foundry Toolbox MCP skills discovery sample (#6134)
    * feat: add Agent_Step26_FoundryToolboxMcpSkills sample
    
    Add a new sample demonstrating MCP-based skills discovery from a Foundry
    Toolbox endpoint using AgentSkillsProviderBuilder and AIContextProviders.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: address PR review comments for Step26 sample
    
    - Add Foundry-Features: Toolboxes=V1Preview header to MCP transport
      options, matching the Step25 pattern
    - Document skill://index.json prerequisite in README
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Update dotnet/samples/02-agents/AgentsWithFoundry/Agent_Step26_FoundryToolboxMcpSkills/Program.cs
    
    Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
  • Bump Python package versions for 1.7.0 release (#6142)
    Bumps the released 1.6.0 packages agent-framework, agent-framework-core, agent-framework-foundry, and agent-framework-openai to 1.7.0, with root continuing to exactly pin agent-framework-core[all]. Bumps the changed prerelease packages agent-framework-a2a, agent-framework-chatkit, agent-framework-declarative, agent-framework-devui, and agent-framework-foundry-hosting to the 260528 date stamp, raises core floors on the packages included in this release, raises Foundry's OpenAI floor alongside OpenAI, and raises ChatKit's openai-chatkit floor to the minimum version required by the current typed API usage. No beta cohort bump was applied; the absent mistal/mistral package was intentionally not bumped because no such package exists in this branch.
  • Python: [Breaking] Remove Python-only declarative actions and rename alias kinds to C# canonical names (#6126)
    * Remove Python-only declarative actions and rename alias kinds to C# canonical names
    
    * Address PR comments.
    
    * Address PR comments.
    
    * Reduce verbose and duplicate output from sample workflow.
  • Python: fix: pass Foundry agent default headers (#6040)
    * fix: pass Foundry agent default headers
    
    * test: loosen Foundry default header assertions
  • Python: Allow hosted checkpoints to restore MessageRole (#6049)
    * Python: Allow hosted checkpoints to restore MessageRole
    
    Allow Responses hosting checkpoint storage to deserialize the Azure Responses MessageRole enum that hosted workflows can persist inside Agent Framework Message objects.
    
    Add regression coverage for both direct load() and the hosted get_latest() restore path, including the plain-storage failure mode where list_checkpoints logs the blocked type and get_latest() returns None.
    
    Ruff also normalizes a duplicate contextlib import in the touched hosting module.
    
    * Address MessageRole checkpoint review comments
    
    * Cover hosted MessageRole checkpoint restore path
  • Python: Align c# and python TodoProvider tool names (#6107)
    * Align c# and python TodoProvider tool names
    
    * Potential fix for pull request finding
    
    Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
    
    * Address PR review: remove __slots__ and add typed schemas for tool params
    
    - Remove __slots__ from TodoItem, TodoInput, and TodoCompleteInput classes
      (not needed for low-instance-count objects and hinders dev scenarios)
    - Add _TodoAddItemSchema and _TodoCompleteItemSchema TypedDicts to provide
      proper JSON schema for todos_add and todos_complete tool parameters
    - Use typing_extensions for Python 3.10 compatibility
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: read headers defensively to support stream wrappers without .headers (#6028) (#6029)
    `OpenAIChatClient._inner_get_response()` reads `.headers` on the raw streaming
    response returned by `client.responses.with_raw_response.create(stream=True)`
    (and its three sibling call sites - retrieve-streaming, non-streaming create
    and background retrieve) to surface the `x-ms-served-model` Azure header,
    introduced in #5910.
    
    When `azure-ai-projects>=2.1.0` experimental GenAI tracing is enabled
    (`AZURE_EXPERIMENTAL_ENABLE_GENAI_TRACING=true`), the instrumentor wraps the
    raw streaming response in an inline `AsyncStreamWrapper` that exposes
    `.response` but not `.headers`. Reading `raw_create_response.headers` then
    raises `AttributeError: 'AsyncStreamWrapper' object has no attribute 'headers'`,
    which `FoundryChatClient` rethrows as a `ChatClientException` and breaks every
    streaming call (workflows and free chat).
    
    Fix: read the header dict via `getattr(raw_response, "headers", None)` at all
    four call sites. `_extract_served_model()` already short-circuits on `None`,
    so the served-model surfacing degrades gracefully (model stays the deployment
    alias) instead of crashing when the response is wrapped by an instrumentor
    that does not proxy `.headers`.
    
    Regression test added:
    `test_streaming_response_without_headers_attribute_does_not_crash`
    simulates a stream wrapper that raises `AttributeError` on `.headers` and
    asserts the stream still completes with the deployment alias as `update.model`.
    
    Fixes #6028
    
    Co-authored-by: Emilien Mottet <emilien.mottet@michelin.com>
  • feat(a2a): add A2AAgentSession with reference_task_ids and input-required support (#5980)
    * feat(a2a): link follow-up messages via reference_task_ids
    
    Track the task_id from A2A responses (task, status_update, artifact_update,
    and message payloads) on session.state and include it as reference_task_ids
    on subsequent outgoing messages. This enables remote agents to correlate
    follow-up messages as task refinements per the A2A spec.
    
    Resolves #5938
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * feat(a2a): add A2AAgentSession for typed protocol state tracking
    
    Introduce A2AAgentSession (subclass of AgentSession) with context_id,
    task_id, and task_state properties. This follows the DurableAgentSession
    pattern and mirrors the .NET A2AAgentSession design.
    
    - Track task_id, context_id, and task_state from all response payload types
    - Validate context_id consistency (raise on mismatch)
    - Auto-assign server-generated context_id when not set
    - Only A2AAgentSession gets reference tracking (no state dict fallback)
    - Plain AgentSession continues to work without reference tracking
    - Add serialization support (to_dict/from_dict)
    - Export via agent_framework.a2a and agent_framework_a2a
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * style: remove unnecessary string annotation (pyupgrade)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: use AgentSession.from_dict for state deserialization
    
    Avoids importing private _deserialize_state, matching the
    DurableAgentSession pattern.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix: track context_id from message payloads in A2AAgentSession
    
    Previously, context_id was only captured from task, status_update, and
    artifact_update payloads. Message-only responses (which carry context_id
    but may lack task_id) were silently lost. This fix:
    
    - Captures msg.context_id in the message handler
    - Persists session state when either last_task_id or last_context_id is
      present (not only when task_id is truthy)
    - Only updates task_id/task_state when a task_id was actually returned
    - Adds a test for message-only context_id tracking
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * addressed comments
    
    * Gate status content to INPUT_REQUIRED/terminal states (match .NET)
    
    Match .NET's GetUserInputRequests pattern: only emit TaskStatusUpdateEvent
    message content when state is INPUT_REQUIRED or terminal. Intermediate
    status text (WORKING, SUBMITTED) is no longer surfaced to callers.
    
    When state is INPUT_REQUIRED, set additional_properties['input_required']
    = True so callers can distinguish input requests from final responses.
    
    Closes #5937
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: remove message task_id tracking, defensive fallbacks, and input_required flag
    
    - Do not track task_id from Message payloads (simple interactions
      without task tracking)
    - Remove 'or last_task_id' fallback from status_update and
      artifact_update handlers (spec guarantees task_id is always set)
    - Remove additional_properties['input_required'] flag (content gating
      to INPUT_REQUIRED/terminal states is the signal itself)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Fix deprecated asyncio.iscoroutinefunction usage in test_cleanup_hooks.py (#4563)
    Fixes #4522
    
    Replace deprecated `asyncio.iscoroutinefunction()` with `inspect.iscoroutinefunction()`
    to resolve Python 3.13+ deprecation warning.
    
    Changes:
    - Added `import inspect` to imports
    - Replaced `asyncio.iscoroutinefunction(hook)` with `inspect.iscoroutinefunction(hook)` on line 126
    - This makes the code consistent with other test methods in the same file (lines 201, 236)
    
    The rest of the file already uses `inspect.iscoroutinefunction()` correctly, making
    this change consistent with the existing codebase pattern.
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Co-authored-by: Claude <noreply@anthropic.com>
    Co-authored-by: Tao Chen <taochen@microsoft.com>
  • .NET: [BREAKING] Remove Support for Code-Gen in Declarative Workflows (#6095)
    * Removed
    
    * Remove sample
    
    * Remove orphaned code-gen related code path
    
    * Remove remaining references to code gen.
    
    ---------
    
    Co-authored-by: Chris Rickman <crickman@microsoft.com>
    Co-authored-by: Chris <66376200+crickman@users.noreply.github.com>
  • Python: fix: keep citation get_url metadata (#6037)
    * fix: keep citation get_url metadata
    
    * fix: satisfy citation metadata mypy check
  • .NET: Add MCP-based skills support (skill-md type) (#6108)
    * Add MCP-based skills support
    
    - Add AgentMcpSkill, AgentMcpSkillResource, AgentMcpSkillsSource, and McpSkillIndex to Microsoft.Agents.AI.Mcp
    - Add AgentSkillsProviderBuilderMcpExtensions for DI integration
    - Add Agent_Step06_McpBasedSkills sample project
    - Add unit tests for AgentMcpSkillsSource
    - Update solution file and project references
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove unnecessary [Experimental] attributes from MCP package
    
    The package is already alpha, so the [Experimental] attribute is redundant.
    Removed from both AgentSkillsProviderBuilderMcpExtensions and
    AgentMcpSkillsSource classes.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Make Agent_Step06_McpBasedSkills self-contained and add to verify-samples
    
    Embed an internal MCP server (launched via --server flag as a child process)
    that serves skill://index.json and skill://unit-converter/SKILL.md resources,
    replacing the external MCP_SKILLS_ENDPOINT dependency. The sample now uses
    StdioClientTransport and a fixed prompt instead of an interactive loop.
    
    Added SampleDefinition to AgentsSamples.cs for automated verification.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Sort usings
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add a HarnessAgent with available features and sample (#6041)
    * Add a HarnessAgent with available features and sample
    
    * Fix formatting
    
    * Address PR comments and fix mypy error
    
    * Add web search support to HarnessAgent
    
    * Fix build warning
    
    * Apply suggestions from code review
    
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
    
    * Address PR comments
    
    * Address PR comments
    
    * Address further PR comments.
    
    * Fix markdown broken link
    
    ---------
    
    Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
  • Python: feat(foundry): add to_prompt_agent / deploy_as_prompt_agent (experimental) (#5959)
    * feat(foundry): add experimental to_prompt_agent converter
    
    Adds `to_prompt_agent(agent)`, an experimental converter
    (`ExperimentalFeature.TO_PROMPT_AGENT`) that turns an Agent Framework
    `Agent` into a Foundry `PromptAgentDefinition` ready to publish via
    `AIProjectClient.agents.create_version(...)`.
    
    Behaviour:
    
    * `agent.client` must be a `FoundryChatClient` (or subclass); otherwise
      `TypeError` is raised. The model deployment name is lifted from the
      bound client so the same Agent definition used for local runs can be
      published as a hosted prompt agent without restating the model.
    * Foundry SDK tool instances (from `FoundryChatClient.get_*_tool()`) are
      passed through unchanged. AF `FunctionTool`s (and `@tool`-decorated
      callables) are emitted as Foundry `FunctionTool` declarations.
    * Local AF MCP tools cannot be expressed in a `PromptAgentDefinition`;
      the converter raises `ValueError` and points at
      `FoundryChatClient.get_mcp_tool()` for hosted MCP servers.
    * The converter walks both `agent.default_options["tools"]` and
      `agent.mcp_tools` because `normalize_tools()` splits local MCP off
      into its own list.
    
    Re-exported through the `agent_framework.foundry` lazy-loading namespace
    (updates both `__init__.py` and the `__init__.pyi` type stub).
    
    Adds a portable-agent sample showing the same `Agent` driven through
    both `agent.run(...)` and `to_prompt_agent(agent)`, and a README section
    covering the new converter.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * chore(samples): remove snippet tags from portable agent sample
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * chore(samples): inline FoundryChatClient and enable prompt-agent publish
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * chore(samples): drop async credential context manager
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(foundry): trim README to_prompt_agent example to publish-only flow
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(foundry): note FoundryAgent runs @tool callables for deployed prompt agents
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(foundry): address review comments on to_prompt_agent converter
    
    * Construct `PromptAgentDefinition` `Tool` from a dict via `**tool_item`
      unpacking rather than the positional Mapping constructor \u2014 cleaner and
      matches the typical Pydantic / Azure SDK pattern.
    * Drop the redundant `isinstance(mcp_tool, MCPTool)` guard in
      `_convert_tools`; the parameter is already typed `Iterable[MCPTool]` so
      the second `raise` was unreachable. The remaining single `raise`
      fires for every entry as intended.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(foundry): match Agent.__init__ model resolution in to_prompt_agent
    
    * Read the model from `agent.default_options.get("model")` first,
      falling back to `agent.client.model`. This mirrors the order
      `Agent.__init__` uses (`_agents.py:740`) when assembling
      default_options, so the model the agent runs with is the same model
      the converter publishes \u2014 e.g. when the caller passes
      `default_options={"model": "..."}` to override the bound client.
    * Updated the missing-model error message to point at both the client
      and the default_options paths.
    * Added tests:
      * tool-only agent with no `instructions` produces a definition
        where `instructions` is `None` and is omitted from the dict
        payload (`Agent.__init__` strips None values from default_options
        before storing them).
      * `default_options['model']` wins over the bound client's model.
      * Fallback to client.model when default_options has no model.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * feat(foundry): add deploy_as_prompt_agent helper + samples
    
    Adds `deploy_as_prompt_agent(agent)`, a convenience wrapper around
    `to_prompt_agent` that reuses the bound FoundryChatClient's project
    client to call `project_client.agents.create_version(...)`. Defaults
    `agent_name` / `description` from `agent.name` / `agent.description`
    so the Agent stays the single source of truth.
    
    * Exposed from `agent_framework_foundry` and the lazy-loading
      `agent_framework.foundry` namespace (including the .pyi stub).
    * Marked experimental with the existing
      `ExperimentalFeature.TO_PROMPT_AGENT` tag.
    * Tests cover the happy path, name/description defaulting, explicit
      override, no-name error, metadata + description forwarding, extra
      kwargs passthrough, and the experimental metadata.
    
    Samples:
    * Renamed the existing sample to `creating_prompt_agents.py`, drops
      'portable' wording, presents `deploy_as_prompt_agent` first as the
      recommended path and `to_prompt_agent` + `AIProjectClient` as the
      two-step alternative, and adds a cleanup step that deletes the
      published agent so re-runs stay idempotent.
    * New `using_prompt_agents.py` shows the end-to-end loop: deploy the
      agent, connect to it with `FoundryAgent` passing the same local
      `@tool` callable, run a query against the deployed prompt agent,
      then clean up.
    
    README updated to introduce `deploy_as_prompt_agent` as the
    recommended path and link to both runnable samples.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(foundry): restore missing-model ValueError in to_prompt_agent
    
    The check was accidentally dropped while reworking docstrings in the
    previous commit. Test `test_to_prompt_agent_rejects_missing_model`
    exercises this path and was failing on CI as a result.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(foundry): rename deploy_as_prompt_agent -> create_prompt_agent
    
    Renames the helper across the foundry package, core lazy-loader stubs,
    tests, README and samples. The new name better matches the action
    performed (a prompt-agent definition is created in Foundry) and is
    consistent with the surrounding ''create_*'' API surface.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(foundry): drop create_prompt_agent, enrich to_prompt_agent params
    
    Remove the create_prompt_agent helper and consolidate on to_prompt_agent.
    Expose every PromptAgentDefinition parameter that has either an Agent
    Framework equivalent (sourced from default_options) or no equivalent
    (accepted as a keyword argument).
    
    * default_options-sourced (with kwarg overrides):
      temperature, top_p, string tool_choice
    * kwarg-only Foundry knobs:
      reasoning, text, structured_inputs, rai_config, ToolChoiceParam tool_choice
    
    Precedence is always: explicit keyword > default_options entry > unset.
    
    Tests cover every path (defaults, default_options, kwargs, kwarg override).
    Samples and README rewritten around the enriched to_prompt_agent.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(foundry): single source of truth for prompt-agent options
    
    Stop duplicating the generation-parameter surface between FoundryChatOptions
    and to_prompt_agent. Translate every field with an Agent Framework equivalent
    (temperature, top_p, tool_choice, reasoning, response_format/text/verbosity)
    from agent.default_options via a new RawFoundryChatClient helper
    _prepare_prompt_agent_options. Only Foundry-specific fields with no AF
    equivalent — structured_inputs and rai_config — remain as keyword arguments
    on to_prompt_agent.
    
    - tool_choice is dropped when there are no tools (mirrors _prepare_options
      semantics and avoids polluting tool-less prompt agents with Agent.__init__'s
      'auto' default).
    - response_format Pydantic models route through
      openai.lib._parsing._responses.type_to_text_format_param; dict shapes go
      through the existing _prepare_response_and_text_format helper.
    - default_options is not mutated; text dict is defensively copied.
    
    Tests, README, and creating_prompt_agents.py sample updated to reflect the
    new single-source model.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(foundry): consolidate prompt-agent sample
    
    Drop creating_prompt_agents.py (the publish-only variant) and rename
    using_prompt_agents.py to foundry_prompt_agents.py so the single sample
    covers the full convert -> publish -> connect -> run loop. Update the
    README link list accordingly.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(foundry): run local Agent + deployed agent in same sample
    
    Add an agent.run() call against the local Agent before publishing, then run
    the deployed prompt agent on the same query. Expand the docstring with a
    compare-and-contrast covering runtime/latency, configurability, and
    persistence/sharing differences between the two execution paths.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * test(foundry): cover conflicting response_format + text.format in to_prompt_agent
    
    Exercises the ValueError path when a Pydantic response_format would overwrite
    an explicit text.format mapping with a different shape. Lifts _chat_client.py
    coverage from 89% to 90%.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(foundry): move _prepare_prompt_agent_options into _to_prompt_agent
    
    Lift the translation helper off RawFoundryChatClient and into the
    _to_prompt_agent module as a module-private function that takes the client
    as its first argument. The chat client no longer needs to carry a method
    whose only consumer is the prompt-agent converter, while still serving as
    the source of the request-path helper (_prepare_response_and_text_format)
    that the converter reuses for dict-shaped response_format values.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(python): codify GA terminology + post-run docs review
    
    Add two pieces of guidance to python/AGENTS.md:
    
    * Terminology - reserve 'GA' for hosted services; use 'released' or 'stable'
      for Agent Framework code/features to match the feature-lifecycle stages.
    * Maintaining Documentation - review AGENTS.md and skills at the end of every
      run and update any guidance the conversation made stale; before adding a
      new principle, ask the user to confirm it should be captured.
    
    Also pulls in a docstring fix in foundry_prompt_agents.py that swaps the
    stray 'GA' for 'released', applying the new terminology rule.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * address PR review: strict=True default, Tool._deserialize dispatch, sample cleanup safety
    
    - FunctionTool published as strict=True so the server-side schema validation
      matches what the local FoundryAgent(tools=[same_callable]) dispatcher
      enforces. AF FunctionTool has no 'strict' attribute, so the safer default
      is used uniformly instead of silently downgrading to a permissive contract.
    - _validate_mapping_tool now dispatches through ProjectsTool._deserialize so
      dict-shaped tools rehydrate to the concrete subclass (FunctionTool,
      WebSearchTool, ...) via the 'type' discriminator instead of returning a
      generic Tool. Added a test that asserts isinstance(WebSearchTool) and a
      new test for the function-typed dict path.
    - foundry_prompt_agents.py sample now wraps credential + project client in
      async with and the create_version / run flow in try/finally so a failure
      on connect or run still deletes the published prompt agent rather than
      leaving an orphaned, billable resource in the user's Foundry project.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(ci): correct linkspector ignorePattern typo (./pulls -> ./pull)
    
    GitHub PR URLs use the singular segment /pull/N (compare to /issues/N
    for issues). The existing './pulls' ignore pattern never matched
    anything as a result, so legitimately stale PR links (e.g. PRs deleted
    from forks) surface as linkspector failures on unrelated PRs.
    
    This is the same convention the './issues' rule above already follows.
    Fixes the markdown-link-check failure on a dangling link in
    dotnet/src/Microsoft.Agents.AI.DurableTask/CHANGELOG.md.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Add a BackgroundAgentsProvider for python (#6069)
    * Add a BackgroundAgentsProvider for python
    
    * Address PR comments and fix linting warnings
    
    * Address PR comment
  • Python: Fix DevUI streaming memory growth regression (#6038)
    * Fix DevUI streaming memory growth regression
    
    Bounds retained streaming/debug state in DevUI and strengthens browser regression coverage for long streamed responses.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address DevUI memory review feedback
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix DevUI bundle trailing whitespace
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: fix(openai): guard against null delta in streaming chunks from non-co… (#5734)
    * fix(openai): guard against null delta in streaming chunks from non-compliant providers (#5732)
    
    * chore: resolve nit and align with project style
    
    ---------
    
    Co-authored-by: Sergey Borisov <sergey.borisov@dataimpact.io>
    Co-authored-by: Giles Odigwe <79032838+giles17@users.noreply.github.com>
  • .NET: Updating version for dotnet release 1.7.0 (#6093)
    * Updating version for dotnet release 1.6.3
    
    * Change to minor version bump.
    
    ---------
    
    Co-authored-by: Ben Thomas <25218250+alliscode@users.noreply.github.com>
  • Python: Add Python parity sample for invoking Foundry Toolbox tools from declarative workflows (#5933)
    * Add Python parity sample for invoking Foundry Toolbox tools from declarative workflows
    
    * Python: address PR review on declarative toolbox sample
    
    Two security fixes for PR #5933:
    
    1. Add safe_mode flag to WorkflowFactory (default True) mirroring
       AgentFactory. Gates =Env.* exposure inside DeclarativeWorkflowState
       PowerFx symbols via _safe_mode_context, so workflow YAML loaded from
       untrusted sources no longer leaks the host's full os.environ snapshot
       into PowerFx evaluation. The flag is also forwarded to the
       internally-constructed AgentFactory so inline agent definitions
       follow the same policy.
    
    2. Pin the invoke_foundry_toolbox_mcp sample's _client_provider to the
       resolved toolbox endpoint. The bearer-authenticated httpx client is
       now only returned when MCPToolInvocation.server_url matches the
       toolbox URL case-insensitively; any other URL gets None (the default
       unauthenticated path), preventing the Foundry AAD bearer token from
       being attached to a mis-configured or injected server URL. Mirrors
       the .NET sample's httpClientProvider guard.
    
    The sample is updated to opt in to safe_mode=False because its YAML
    intentionally uses =Env.FOUNDRY_TOOLBOX_* to keep configuration in env
    vars under the developer's control.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix pyright issues.
    
    * Addressed PR comments.
    
    * Fix CI pipelines.
    
    * Resolve PR comments
    
    * Revamped sample to address PR comments.
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Align ModeProvider tool names and instructions (#6071)
    * Align ModeProvider tool names and instructions
    
    * Address PR comments
  • .NET: [Breaking] Refactor AgentSkill API to async resource and script lookup (#6030)
    * .NET: Refactor AgentSkill API to async resource and script lookup
    
    Replace property-based AgentSkill.Content, Resources, and Scripts with
    async-by-name lookup methods plus boolean availability flags:
    
    - Content (string getter) -> GetContentAsync(CancellationToken)
    - Resources (full list) -> HasResources + GetResourceAsync(name, ct)
    - Scripts (full list) -> HasScripts + GetScriptAsync(name, ct)
    
    This makes the API friendlier for sources like MCP where enumerating all
    resources up front is expensive or impossible, and allows skill implementations
    to fetch content lazily.
    
    Subclass changes:
    - AgentFileSkill and AgentInlineSkill implement the new async API while
      preserving content caching.
    - AgentClassSkill<TSelf> keeps virtual Resources/Scripts properties for
      reflection-based discovery and seals the new HasResources/HasScripts/
      GetResourceAsync/GetScriptAsync overrides. Its previously non-thread-safe
      lazy initialization is replaced with Lazy<T> (default thread-safety) wired
      up in a new protected constructor, so concurrent first-access from multiple
      threads is safe.
    - AgentSkillsProvider calls the new async API and exposes 
    ead_skill_resource
      / load_skill / 
    un_skill_script tools that await the per-name lookups.
    
    Includes baseline CompatibilitySuppressions.xml entries for the removed
    property getters.
    
    Tests:
    - Direct coverage for HasResources, HasScripts, GetResourceAsync, and
      GetScriptAsync on all three skill implementations (positive, missing-name,
      and no-resources/no-scripts cases).
    - Thread-safety regression test for AgentClassSkill<TSelf> that exercises
      concurrent first-access to Resources, Scripts, and GetContentAsync from
      many tasks and asserts all observers see the same cached instance.
    - Provider-level coverage for the 
    ead_skill_resource tool (invocation +
      error paths) and for the previously untested error paths of load_skill
      and 
    un_skill_script (empty names, skill/resource/script not found).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review comments
    
    - Move GetScriptAsync inside try/catch in RunSkillScriptAsync for error-handling parity
    - Remove dead _reflectedResources branch from AgentSkillTestExtensions
    - Fix XML docs to reference virtual Resources/Scripts properties (not sealed methods)
    - Add Async suffix to async test methods per naming convention
    - Make no-await tests synchronous to eliminate CS1998
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix formatting: add UTF-8 BOM and remove unused using
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix XML cref: Resources/Scripts are on AgentClassSkill<TSelf>
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove HasResources and HasScripts properties from AgentSkill
    
    Drop the virtual HasResources and HasScripts properties from AgentSkill
    and all concrete subclasses (AgentFileSkill, AgentInlineSkill,
    AgentClassSkill). AgentSkillsProvider now always includes all three
    tools (load_skill, read_skill_resource, run_skill_script) and both
    instruction blocks, since the tools already handle missing
    resources/scripts gracefully.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add blank line for readability in file-based skills sample
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fix HostedAgentSkillsPatternTests for always-included tools
    
    Update assertions to expect read_skill_resource and run_skill_script
    tools are always present, matching the new behavior.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • .NET: Add Hosted-AgentSkills sample with Foundry Skills integration (#6013)
    * .NET: Add Hosted-AgentSkills sample for Foundry Skills integration
    
    Add a new hosted agent sample that demonstrates how to load behavioral
    guidelines from Foundry Skills at startup using AgentSkillsProvider and
    the progressive disclosure pattern (advertise -> load on demand).
    
    The sample:
    - Downloads SKILL.md files from Foundry via ProjectAgentSkills SDK
    - Extracts ZIP archives with zip-slip protection
    - Wires skills into AgentSkillsProvider as an AIContextProvider
    - Hosts the agent via the Responses protocol
    
    Ships two Contoso Outdoors skills matching the Python sample (PR #5822):
    - support-style: tone, formatting, signature guidelines
    - escalation-policy: when and how to escalate tickets
    
    Includes convenience provisioning gated behind PROVISION_SAMPLE_SKILLS
    env var, clearly documented as NOT a production pattern.
    
    Closes #5776
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * .NET: Add unit tests and integration test for Hosted-AgentSkills
    
    Unit tests (14 tests, all passing):
    - ZIP extraction with zip-slip guard (valid archive, traversal attack,
      sibling-prefix attack, directory entries)
    - Skill name validation (rejects dots, separators, traversal patterns)
    - AgentSkillsProvider with downloaded skills (advertises both skills,
      load_skill returns canary tokens, unknown skill returns error)
    
    Container integration test:
    - New 'agent-skills' scenario in the test container that creates
      Contoso Outdoors skills on disk and wires AgentSkillsProvider
    - AgentSkillsHostedAgentFixture + 4 integration tests verifying:
      - Routine questions load support-style skill (STYLE-CANARY-3318)
      - Escalation triggers load escalation-policy (ESC-CANARY-7742)
      - Skills are advertised in system prompt
      - load_skill tool is invoked via FunctionCallContent
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * .NET: Add smoke test, bootstrap, and docs for agent-skills integration
    
    - Add scripts/smoke.ps1 for local Docker smoke testing: builds the
      contributor image, runs the container, verifies both skills are loaded
      via canary tokens (STYLE-CANARY-3318, ESC-CANARY-7742)
    - Add 'agent-skills' to the bootstrap script scenario list
    - Add agent-skills row to the integration test README scenarios table
    - Exclude HostedAgentSkillsPatternTests from net472 (uses net8.0+ APIs)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * .NET: Update commented-out package versions to latest across all hosted samples
    
    Update the end-user PackageReference versions (in the commented-out
    sections) from 1.0.0 to the current latest NuGet versions:
    
    - Microsoft.Agents.AI: 1.6.1
    - Microsoft.Agents.AI.Foundry: 1.6.1-preview.260514.1
    - Microsoft.Agents.AI.Foundry.Hosting: 1.6.1-preview.260514.1
    - Microsoft.Agents.AI.Hosting: 1.6.1-preview.260514.1
    - Microsoft.Agents.AI.OpenAI: 1.6.1
    - Microsoft.Agents.AI.Workflows: 1.6.1
    
    Also adds explicit versions to Hosted-Workflow-Handoff which had bare
    PackageReference entries without Version attributes.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * .NET: Fix broken markdown links in Hosted-AgentSkills README
    
    Remove references to non-existent ../../README.md. Replace with
    inline instructions matching other hosted samples that don't have
    a parent README.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * .NET: Use OS-appropriate string comparison in zip-slip guard
    
    Use Ordinal on Unix (case-sensitive FS) and OrdinalIgnoreCase on
    Windows to prevent case-based path bypass on Linux containers.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • .NET: fix parallel tool call rendering in AGUI translation layer (#6009)
    Fix three interlocked bugs that prevent parallel tool calls from rendering
    correctly in AG-UI protocol clients:
    
    Bug #1: Scope synthetic MessageId fallback to text events only. The shared
    streamingMessageId was leaking into ToolCallStartEvent.ParentMessageId,
    causing all parallel tool calls to collapse into one FE card.
    
    Bug #2: Make ToolCallResultEvent.MessageId deterministically unique using
    result-{CallId} format. MEAI's FunctionInvokingChatClient batches all
    results with a shared MessageId, collapsing them in FE reconciliation.
    
    Bug #3: Coalesce consecutive assistant-tool-call messages in AsChatMessages.
    Once Bug #1 is fixed, the FE produces separate AGUIAssistantMessage per
    tool call. On multi-turn replay these become consecutive assistant messages
    without intervening tool results, triggering HTTP 400 from Azure OpenAI.
    
    Remove the now-dead ContainsToolResult helper introduced by PR #5800.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • .NET: HarnessConsole: Improve rendering perf / reduce flickering (#6014)
    * HarnessConsole: Improve rendering perf / reduce flickering
    
    * Address PR comments
  • .NET: Add MCP long-running task support for MCP client tools (#5994)
    * Add MCP long-running task support for MCP client tools
    
    * Fixed project file formatting issue.
    
    * Removed experimentation tag from MCP alpha project.
    
    * Addressed PR comments
  • .NET: Add Magentic Orchestration Sample (#5823)
    * Add Magentic orchestration sample scaffold
    
    Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/8799740a-74d8-4100-b6f6-76dcd0418c87
    
    Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com>
    
    * Validate Magentic orchestration sample
    
    Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/8799740a-74d8-4100-b6f6-76dcd0418c87
    
    Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com>
    
    * Document follow-up changes for the Magentic .NET sample
    
    Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/caa3488f-d6f5-494d-a928-a45d6a98b3c3
    
    Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com>
    
    * Remove CHANGES.md from Magentic sample
    
    Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/ffab38e2-37f9-4643-a782-20680573965a
    
    Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com>
    
    * Fix PauseIfInteractive to also skip when stdout is redirected
    
    Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/07ddf735-29cc-4775-b588-fd71ca76fa58
    
    Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com>
    
    * fix: Update for PR Review Feedback
    
    * fix: Update Sample README for PR Feedback
    
    ---------
    
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com>
    Co-authored-by: Jacob Alber <jaalber@microsoft.com>
  • fix: populate MessageId from TaskStatusUpdateEvent.Status.Message (#6043)
    When A2AAgent receives a TaskStatusUpdateEvent during streaming,
    ConvertToAgentResponseUpdate now sets AgentResponseUpdate.MessageId
    from Status.Message.MessageId when the message is present.
    
    This fixes the missing message correlation metadata reported in
    microsoft/agent-framework#4987.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: fix(core): point @experimental warnings at user code, not stdlib internals (#5996)
    * fix(core): point @experimental warnings at user code, not stdlib internals
    
    Previously the wrappers installed by @experimental called warnings.warn
    with a fixed stacklevel=3. ABCMeta inserts an extra abc.__new__ frame
    when an experimental ABC is subclassed, so the warning landed inside
    abc.py (or <frozen abc>:106 on modern CPython) instead of the user's
    class Sub(...) line.
    
    Resolve the user frame by walking inspect.currentframe(), skipping
    frames whose module name is abc/functools/typing/contextlib (or
    submodules), then emit via warnings.warn_explicit so the recorded
    filename/lineno point at user code. Falls back to warnings.warn with
    stacklevel=2 if no user frame is found. Module-name matching is used
    because frozen stdlib modules report '<frozen abc>' as their filename.
    
    Also install a one-line warnings.formatwarning specifically for
    FeatureStageWarning so 'file:line: ExperimentalWarning: [ID] Name ...'
    prints without the secondary source-snippet line. Other categories
    delegate to the stdlib default formatter unchanged.
    
    Added a regression test that subclasses an @experimental ABC inside
    warnings.catch_warnings and asserts the recorded filename equals the
    test file.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(core): address review feedback on @experimental warning fix
    
    - Make _install_feature_stage_formatter idempotent: tag the installed
      formatter with a marker attribute and short-circuit re-installation,
      so re-imports/reloads don't wrap the formatter on top of itself.
      Also expose the previous formatter via __wrapped__ for restoration.
    - Avoid leaking frame references in _resolve_user_frame: capture data
      into plain locals inside try and del frame/candidate in finally,
      per CPython's guidance on inspect.currentframe usage.
    - Drop redundant _WARNED_FEATURES.clear() in the new ABC subclass test
      (the autouse fixture already handles it).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * changed query for foundry web search test
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: bump package versions for 1.6.0 release (#6017)
    * Python: bump package versions for 1.6.0 release
    
    - Released cohort (agent-framework, core, openai, foundry): 1.5.0 -> 1.6.0
    - Beta packages (21 packages): 1.0.0b260519 -> 1.0.0b260521
    - Alpha packages (azure-contentunderstanding, foundry-hosting, gemini, monty): 1.0.0a260518/19 -> 1.0.0a260521
    - ag-ui stays at 1.0.0rc2, orchestrations at 1.0.0rc1 (dependency bounds updated)
    - Inter-package dependency lower bounds updated (>=1.5.0,<2 -> >=1.6.0,<2)
    - Update CHANGELOG compare links
    - uv.lock refreshed
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: bump RC packages, add shell tool to changelog
    
    - ag-ui: 1.0.0rc2 -> 1.0.0rc3
    - orchestrations: 1.0.0rc1 -> 1.0.0rc2
    - Add shell tool (#5664) to CHANGELOG
    - uv.lock refreshed
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • .NET: Fix declarative workflow regressions for hosted agents (#5905)
    * Fix declarative workflow regressions for hosted agents
    
    Three regressions surfaced when running a declarative workflow as a
    Foundry hosted agent. Together they caused every condition group to fall
    through to elseActions and the raw agent JSON to leak to the caller.
    
    1. AgentProviderExtensions.InvokeAgentAsync forced autoSend to true
       whenever the agent ran on the workflow conversation, which overrode
       the explicit autoSend: false declared in workflow.yaml and streamed
       the raw structured-output JSON straight to the user. Honor the
       caller-supplied autoSend instead.
    
    2. IWorkflowContextExtensions.ReadState / QueueStateUpdateAsync /
       QueueStateResetAsync took the variable name and namespace alias
       directly from PropertyPath.VariableName / NamespaceAlias. Against
       Microsoft.Agents.ObjectModel 2026.2.4.1 those properties return null
       for a dotted reference such as `Local.Triage` even when
       SegmentCount == 2 and IsValid == true, so every assignment threw
       ArgumentNullException via Throw.IfNull. Fall back to Segments() to
       reconstruct the name and alias when the parser returns null.
    
    3. The same ObjectModel version no longer recognizes the user-facing
       `Local` scope alias: VariableScopeNames.IsValidName(`Local`)
       returns false and GetNamespaceFromName(`Local`) returns Unknown, so
       the declarative interpreter's IsManagedScope check fails and the
       State.Set call is silently skipped. Translate the `Local` alias to
       its canonical `Topic` form before forwarding to
       QueueStateUpdateAsync; WorkflowFormulaState.Bind continues to expose
       it as `Local` to PowerFx.
    
    Verified end-to-end against a deployed Foundry hosted agent: the
    declarative triage workflow now routes Technical / Billing / General
    inputs correctly and only the autoSend-eligible messages reach the
    caller.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Hosted-agent HITL: persist session across previous_response_id chains; run approved local AIFunctions
    
    Two regressions hit declarative workflows that use require_approval=true when
    the client chains turns via previous_response_id (no conversation_id):
    
    1. AgentFrameworkResponseHandler keyed the AgentSession store solely on
       conversation_id, so when only previous_response_id was present the
       StateBag (which holds ToolApprovalIdMap) was discarded after each turn.
       The next turn then threw 'No approval mapping recorded for wire id ...'
       in InputConverter.ConvertMcpApprovalResponse.
    
       Fix: fall back to previous_response_id on load and to context.ResponseId
       on save so the response-id chain becomes a valid session key. Conversation
       id remains preferred when present.
    
    2. InvokeFunctionToolExecutor.CaptureResponseAsync only acted on
       FunctionResultContent. In the hosted Foundry path the approval response
       arrives as a ToolApprovalResponseContent with no FunctionResultContent,
       so the local AIFunction never ran and downstream PropertyPath/SendActivity
       consumers (e.g. {Local.RefundResult}) saw empty values.
    
       Fix: when no FunctionResultContent matches but an approved
       ToolApprovalResponseContent does, look up the registered AIFunction by
       name on agentProvider.Functions and invoke it with the evaluated
       arguments, surfacing the result through the existing assignment path.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Apply PropertyPath workaround to initialization path; share + tidy helpers
    
    Address PR #5905 review feedback:
    
    * Move the PropertyPath VariableName/NamespaceAlias fallback and 'Local'
      -> 'Topic' scope remap into a shared internal PropertyPathExtensions
      helper. Materializes Segments() once, names the magic 'Local' alias
      as a const, and carries a TODO referencing the tracking issue.
    
    * Apply the same helper in WorkflowDiagnostics.InitializeDefaults so a
      declared default for a dotted variable like 'Local.Triage' is no
      longer silently skipped at workflow startup (closes the gap flagged
      by the reviewer: runtime ReadState/QueueStateUpdateAsync worked but
      state.Initialize did not).
    
    * Restore the previous strict failure mode on namespace alias by
      wrapping GetNamespaceAlias() in Throw.IfNull at call sites so a
      malformed single-segment path keeps failing fast rather than
      silently passing null to State.Get/Set.
    
    All 821 unit tests pass.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Add tests for AgentProviderExtensions.InvokeAgentAsync autoSend behavior
    
    Covers the autoSend regression fix: when the agent runs on the workflow conversation with autoSend=false, no AgentResponseUpdateEvent or AgentResponseEvent is added to the context. Also covers autoSend=true (events emitted) and autoSend=false on a non-workflow conversation.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Surface SendActivity output via AgentResponseUpdateEvent
    
    SendActivityExecutor previously only emitted the activity text via YieldOutputAsync, which the runtime converts to an AgentResponseEvent. WorkflowSession gates AgentResponseEvent behind includeWorkflowOutputsInResponse, so when a host opts out of summary outputs (the default for AsAIAgent) the SendActivity reply is silently dropped.
    
    Mirror the pattern used by AgentProviderExtensions for autoSend agent invocations: also emit an AgentResponseUpdateEvent, which WorkflowSession yields unconditionally. This makes SendActivity reliably reach chat-protocol clients without requiring includeWorkflowOutputsInResponse = true (which would also duplicate autoSend agent output).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Revert previous_response_id session-key fallback
    
    The fallback let a session be keyed by an unbroken previous_response_id chain,
    but conversation_id is the right way to thread state across turns: it survives
    shared/branched chains (e.g. when another agent generates a response in between)
    and is the documented model for stateful clients. Restore conversation_id as the
    sole session key and rely on the client to thread it. The InvokeFunctionTool
    approval/local-function half of 1baf4af4d remains.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Set Foundry ProductContext per-executor instead of via PropertyPath workaround
    
    ObjectModel 2026.2.4.1 resolves PropertyPath.VariableName / NamespaceAlias and VariableScopeNames.IsValidName against AsyncLocal<ProductContext> at access time. In hosted-agent scenarios each HTTP request runs on a fresh async context where that AsyncLocal is default, so dotted refs like Local.Triage returned null and the Local scope alias was rejected.
    
    Replace the PropertyPathExtensions helper (which papered over both symptoms) with a single WorkflowDiagnostics.SetFoundryProduct() call at the entry of DeclarativeActionExecutor.HandleAsync. The set writes to the request's logical async context before any code reads PropertyPath, letting the existing parser and scope resolver work as designed.
    
    Validated: 824/824 declarative unit tests pass; technical/billing/general routes all dispatch correctly against a deployed Foundry hosted agent.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback on InvokeFunctionToolExecutor
    
    - Surface registered-function lookup failures and invocation exceptions via FunctionResultContent.Exception instead of returning the error text as a successful Result, so downstream {Local.X} assignments can distinguish failures from successes.
    
    - Use AIJsonUtilities.DefaultOptions to JSON-serialize non-string function results (matching FunctionInvokingChatClient / ToolBridge), so complex types stay consumable by PropertyPath consumers instead of degrading to Object.ToString().
    
    - Drop the explicit System. prefix on StringComparison / Exception now that the file imports System.
    
    - Add AutoSendTrueOnExternalConversationEmitsResponseEventsAndCopiesMessagesAsync to cover the (autoSend: true, external conversation) quadrant, asserting that response events are emitted and that messages are mirrored to the workflow conversation.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Honor AutoSendIsDefaultValue when computing autoSend
    
    AzureAgentOutput.AutoSend and InvokeToolOutput.AutoSend in
    Microsoft.Agents.ObjectModel 2026.2.4.1 are never null — they
    return a literal-false default when the YAML omits the field.
    The previous null check in Get/AutoSendValue therefore always
    fell through to evaluating the literal false, so every action
    whose YAML had any output block but no explicit autoSend was
    treated as autoSend = false. This was previously masked by
    `autoSend |= isWorkflowConversation` in AgentProviderExtensions
    (removed earlier in this PR to honor explicit autoSend: false),
    which silently re-enabled autoSend on the workflow conversation.
    
    Use AutoSendIsDefaultValue to distinguish an explicit autoSend
    value from the implicit default and treat the implicit default
    as true, restoring the historical behavior for ValidateCaseAsync
    InvokeAgent.yaml (3 InvokeAzureAgent actions, last one captures
    to Local.RatingResponse via output.messages with no autoSend
    specified) while keeping the hosted-agent fix that honors an
    explicit autoSend: false.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Ben Thomas <25218250+alliscode@users.noreply.github.com>
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
  • Python: Shell tool with support for local and Docker (#5664)
    * feat(tools): add cross-OS LocalShellTool in new agent-framework-tools package
    
    Introduces a safe, cross-OS local shell tool as the first citizen of a new
    
    agent-framework-tools workspace package. Supports persistent (default) and
    
    stateless modes across pwsh/powershell.exe/bash/sh, with policy denylist,
    
    allowlist, approval gating, process-tree kill on timeout, output truncation,
    
    and audit hooks. Integrates with existing provider get_shell_tool(func=...)
    
    factories via FunctionTool kind='shell'.
    
    See docs/decisions/0026-builtin-tools-local-shell.md for the full design.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * feat(tools): security hardening for LocalShellTool
    
    Codifies what LocalShellTool does and does not defend against, and
    
    delegates the security-relevant lifecycle primitive to a battle-tested
    
    library instead of hand-rolled per-OS code.
    
    Changes:
    
    - Adopt psutil for cross-OS process-tree termination (executor + session).
    
      Replaces hand-rolled taskkill/killpg with one canonical implementation.
    
    - Resolve taskkill.exe to absolute %SystemRoot%\System32 path so PATH
    
      poisoning cannot redirect us to an attacker-supplied binary.
    
    - Reframe ShellPolicy docstring + ADR + README: denylist is a guardrail,
    
      not a security boundary.
    
    - Require acknowledge_unsafe=True to set approval_mode='never_require',
    
      making the unsafe path explicitly opt-in with a self-documenting name.
    
    - Add tests/test_security.py codifying named CVE-style cases. Defenses
    
      we DO claim are asserted; non-defenses (denylist bypasses via
    
      backslash insertion, variable expansion, interpreter escape, base64,
    
      alternative tools, PowerShell-native verbs) are documented as
    
      expected-to-pass tests so residual risk stays visible.
    
    - Add Threat Model + Confidence Strategy sections to ADR 0026.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * feat(tools): add DockerShellTool sandboxed shell tier
    
    Adds a container-backed shell executor as the recommended pattern for untrusted-input shell workflows. The container provides the security boundary (--network none, non-root user, --read-only, --cap-drop ALL, no-new-privileges, memory/pids limits, tmpfs /tmp), so approval gating is optional unlike LocalShellTool.
    
    Also introduces a ShellExecutor Protocol so callers can plug in custom backends (Firecracker, SSH, WASI) without forking the framework.
    
    Removes the planned HyperlightShellExecutor follow-up from ADR 0026: Hyperlight is a WASM code sandbox with no kernel/userland/shell binary, so a Hyperlight-backed shell is not viable. Docker is the realistic sandbox tier for shell.
    
    Tests: 11 unit tests for argv builders + lifecycle (no Docker daemon required); 3 integration tests gated on is_docker_available().
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(tools): backport shell-tool fixes from .NET parity review
    
    Applies the applicable subset of bug fixes accumulated during the
    .NET shell-tool PR review (microsoft/agent-framework#5604) to the
    Python shell tool.
    
    A1 - Quote workdir safely in _maybe_reanchor
    
      Previously _tool.py used double-quote interpolation when emitting
      the cd/Set-Location prefix, which expanded $VAR, $(), and backticks
      in the workdir path. A workdir containing shell metacharacters could
      trigger arbitrary command execution before the user command ran.
    
      Replaced with single-quote escaping helpers _quote_posix and
      _quote_powershell that emit literal-string forms safe for both
      hosts.
    
    A5/A6 - Consolidate truncation to a single byte-aware helper
    
      Extracted a shared truncate_head_tail / truncate_text_head_tail
      helper in _truncate.py. The new implementation distributes odd
      caps so head receives floor(cap/2) and tail receives ceil(cap/2)
      bytes, matching the .NET round-9 fix and ensuring no input bytes
      are silently dropped on the boundary.
    
      _session.py previously truncated by Python str length while the
      caller passed _max_output_bytes - the unit mismatch is now gone:
      raw byte buffers go through truncate_head_tail and decoded text
      goes through truncate_text_head_tail.
    
    Unit tests added for the truncate and quote helpers.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(tools): tone down narrative and overconfident comments in shell tool
    
    The shell tool's docstrings and comments contained two patterns that
    the .NET review pushed back on:
    
    - Narrative framing about implementation history ("hard-won",
      "we sidestep", "design inspiration: ...", competitor framework
      name-drops in module docstrings).
    - Overstated security guarantees ("battle-tested",
      "reasonable for untrusted input", "recommended executor for any
      agent that runs commands from untrusted input",
      "destructive commands are blocked", "safe local shell tool",
      "blocks shell injection").
    
    Rewrites the affected docstrings and comments to describe what the
    code does in neutral terms. Behaviour is unchanged.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * feat(tools): add ShellEnvironmentProvider for the Python shell tool
    
    Ports the .NET ShellEnvironmentProvider as a Python ContextProvider
    so agents using LocalShellTool or DockerShellTool can be primed with
    an accurate description of the shell they're talking to (family,
    version, OS, working directory, and which CLIs are available).
    
    The provider runs probes through any ShellExecutor, caches the
    resulting snapshot, and on every before_run extends the session
    instructions with a markdown block describing the shell idiom to
    use. A failed first probe leaves the cache empty so the next call
    retries (no permanent poisoning).
    
    Probe failures from a narrow set of expected error types
    (ShellCommandError, ShellExecutionError, ShellTimeoutError, and
    asyncio.TimeoutError from the per-probe timeout) are recorded as
    None fields in the snapshot. Other exceptions propagate. Tool
    names are validated against ^[A-Za-z0-9._-]+$ before being
    interpolated into a probe command.
    
    Includes 12 unit tests covering happy path, stderr fallback,
    timeout handling, expected/unexpected exception paths, malicious
    tool name rejection, case-insensitive deduplication, retry after
    failure, concurrent first-callers sharing one probe, and the
    default and custom formatter paths.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(tools): document ShellEnvironmentProvider and finish comment cleanup
    
    Add a README section introducing ShellEnvironmentProvider, soften two remaining overconfident security-boundary comments in _executor_base.py and the DockerShellTool class docstring, and add a sample (shell_with_environment_provider.py) that demonstrates the provider in stateless and persistent modes.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(tools): move shell samples to python/samples/02-agents/tools
    
    The repository convention is to host samples under python/samples/ rather than inside the package directory. Move the two net-new shell samples (allow-list and environment-provider) to python/samples/02-agents/tools/ and drop the in-package samples/ directory; the existing top-level providers/openai/client_with_local_shell.py already covers the basic LocalShellTool walkthrough.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * test(tools): cover confine_workdir default and ShellResult.format_for_model
    
    Two new tests in test_local_shell_tool.py exercise the default confine_workdir=True behaviour on POSIX and PowerShell, asserting that 'cd' inside one persistent-mode call does not leak into the next. A new test_shell_result.py module provides direct unit coverage for every conditional branch of ShellResult.format_for_model (stdout, truncated, stderr, timed_out, exit_code) so regressions in the LLM-facing format are caught immediately.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(tools): address PR #5664 review feedback
    
    - _tool.py: detect PowerShell via is_powershell() helper instead of basename string match
    
    - _environment.py: use public ContextProvider import (no private _ prefix)
    
    - _session.py: trim _stdout_buf/_stderr_buf after copying to avoid unbounded retention across calls
    
    - _docker.py: short-circuit start()/close() in stateless mode; add configurable shell kwarg (default bash, e.g. 'sh' for alpine)
    
    - tests: parenthesized multi-line assert; alpine integration tests now pass shell='sh'
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(tools): satisfy CI quality gates
    
    - pyupgrade: drop quoted self-class refs in __aenter__/method annotations
    
    - ruff format: reflow long lines per workspace style
    
    - pyright: assert psutil non-None in optional-import branch; lowercase mutable module globals; annotate _approval_mode as Literal so tool() Literal-typed kwarg is accepted; add ... body to ShellExecutor.run protocol; remove unused deprecated _kill_tree wrapper
    
    - tests: skip docker integration tests on win32 (Windows containers don't support --read-only / alpine images)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Remove DEFAULT_DENYLIST; document single-session ownership; fix bandit findings
    
    Mirrors the .NET PR #5604 cleanup:
    
    - Remove DEFAULT_DENYLIST from ShellPolicy. ShellPolicy() now ships with an empty deny-list; operators opt into site-specific patterns explicitly. No major agent framework uses regex matching as a primary security control; AutoGen v2 removed theirs. Approval gating + sandbox tier remain the real boundaries.
    
    - Rewrite module / class docstrings to frame ShellPolicy as a UX pre-filter, not a security control.
    
    - Add Single-session ownership paragraphs to ShellExecutor, ShellSession, LocalShellTool, and DockerShellTool: a persistent-mode tool is owned by exactly one conversation / agent session; do not share across users or concurrent conversations.
    
    - Tests now supply explicit deny patterns instead of relying on a default.
    
    - Address Pre-commit Hooks (bandit) CI failures: convert internal-invariant asserts to explicit RuntimeError, annotate intentional subprocess/shell usage with # nosec, document container-internal /tmp paths.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR #5664 round-2 review feedback
    
    Deny-list documentation drift:
    
    - README and the OpenAI/local-shell sample no longer claim a built-in deny-list of destructive commands. ShellPolicy is described as an optional, operator-supplied UX pre-filter; the real boundaries remain approval gating and the sandbox tier.
    
    Behavioural fixes called out in review:
    
    - ShellPolicy.evaluate() now denies empty / whitespace-only commands explicitly instead of returning allow with no rationale.
    
    - truncate_head_tail() raises ValueError for cap <= 0 instead of silently returning the full input with truncated=False, which previously could defeat output-capping in callers that mis-configured the budget.
    
    - LocalShellTool.as_function() / DockerShellTool.as_function() return the ShellCommandError text directly so the model sees a single, non-redundant 'Command rejected by policy: …' message instead of the prior duplicated 'Command blocked by policy: Command rejected …' wrapping.
    
    - ShellSession POSIX sentinel trailer now snapshots and restores the prior errexit (set -e) state around the trailer, so a user 'set -e' in the persistent shell is no longer permanently disabled by the next run().
    
    Tests:
    
    - New test_shell_parse_rc.py covers the full _parse_rc() edge-case surface (zero, positive, negative, CRLF, no newline, missing prefix, empty input, non-digits, trailing garbage, partial digits).
    
    - test_policy.py asserts the new empty-command deny.
    
    - test_shell_truncate_and_quote.py asserts ValueError for cap=0 and cap<0.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback for shell tool
    
    - _resolve.py: reject empty/whitespace shell override string
    - _tool.py / _docker.py: mode-aware default tool description (persistent vs stateless)
    - _tool.py: fix misleading workdir docstring (re-anchor, not blocking)
    - _types.py: emit stream-agnostic [output truncated] marker
    - _policy.py: declare _denies/_allows as dataclass fields
    - _environment.py: use $(pwd) instead of $PWD in POSIX probe
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address PR review feedback: shell override flag + probe timeout safety
    
    - _resolve.py: in stateless mode, ensure shell overrides end with -c/-Command so commands aren't misinterpreted as script-file paths.
    - ShellExecutor.run / LocalShellTool.run / DockerShellTool.run now accept an optional 	imeout kwarg; ShellEnvironmentProvider drops the outer asyncio.wait_for and lets the executor enforce the probe timeout internally, so cancellation no longer risks leaving a hung subprocess or corrupted session.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review feedback: docker isolation + lifecycle robustness
    
    - pyproject.toml: bump agent-framework-core minimum from 1.2.0 to 1.2.2 to align with the rest of the workspace.
    - _docker.py: validate extra_run_args at construction time and reject flags that would dismantle the isolation defaults (--privileged, --cap-add, --security-opt, --network/--net, -v/--volume/--mount, --device, --pid, --ipc, --userns, --user, --read-only, --tmpfs, --add-host, --gpus, --cgroupns, --device-cgroup-rule); also documented the warning on the docstring.
    - _docker._stop_container: retry docker rm -f once and log a warning/error when it does not succeed, so operators can audit leaked containers instead of getting a silent success.
    - _docker._run_stateless timeout path: fall back to docker rm -f when docker kill fails or times out (--rm only reaps on clean exit), and log instead of silently swallowing communicate() errors.
    
    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: alliscode <25218250+alliscode@users.noreply.github.com>
  • .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>