mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
peibekwe/declarative-bugfix-python-new
2293 Commits
-
Yufeng He ·
2026-05-22 15:31:18 +00:00 -
Yufeng He ·
2026-05-22 15:30:55 +00:00 -
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>
Eduard van Valkenburg ·
2026-05-22 12:07:10 +00:00 -
Evan Mattson ·
2026-05-22 15:56:32 +09:00 -
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>
Giles Odigwe ·
2026-05-22 01:59:20 +00:00 -
Updating versions for release 1.6.2 (#6019)
Co-authored-by: alliscode <bentho@microsoft.com>
Ben Thomas ·
2026-05-22 01:10:34 +00:00 -
.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
1baf4af4dremains. 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>Ben Thomas ·
2026-05-22 01:06:38 +00:00 -
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>
Ben Thomas ·
2026-05-22 00:29:59 +00:00 -
.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>
Roger Barreto ·
2026-05-21 21:26:42 +00:00 -
Python: Prevent duplicate system instructions in Python telemetry (#5981)
* Initial plan * Fix duplicated system instructions in Python telemetry * Clarify telemetry message filtering * test: cover separate and in-history system messages * Clarify observability message logging split * Simplify observability logging serialization * Harden observability regression test * Reuse observability span message serialization * Clarify observability logging loops * Polish observability message serialization * Tighten observability zip checks * Refactor observability message capture loop * Fix telemetry logging for separate system instructions * Refine observability OTEL message typing * Restore prepended-instruction logging path in _capture_messages * Revert logging change in _capture_messages; keep chat-history-only logging --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Copilot ·
2026-05-21 19:59:06 +00:00 -
.NET: Add shell support to the HarnessAgent (#6005)
* Add shell support to the HarnessAgent * Address PR comments * Address PR comments
westey ·
2026-05-21 17:25:33 +00:00 -
Yufeng He ·
2026-05-21 16:23:36 +00:00 -
Python: feat(a2a): use non-streaming transport and return_immediately for background ops (#5963)
* feat(a2a): use non-streaming transport and return_immediately for background ops When stream=False, use a client configured with streaming=False so the SDK sends a single HTTP POST to message/send instead of opening an SSE connection via message/stream. This matches the A2A protocol's design: non-streaming calls use direct request/response, streaming calls use Server-Sent Events. Also sets return_immediately=background on SendMessageConfiguration so the server respects the caller's intent for background operations. Changes: - Create separate streaming and non-streaming internal clients (sharing the same httpx connection pool) to match protocol transport semantics - Select non-streaming client for run(stream=False) calls - Add SendMessageConfiguration with return_immediately=background - Fallback to streaming client when non-streaming unavailable (e.g. user provides their own client via constructor) - Add tests for client selection and return_immediately behavior Resolves microsoft/agent-framework#5936 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address PR review feedback - Initialize last_request in MockA2AClient.__init__ for explicit state - Use 'is not None' instead of truthiness for _non_streaming_client check - Assert return_immediately propagates through non-streaming client path Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: only set configuration when background=True Only attach SendMessageConfiguration to the request when background=True, keeping requests minimal and preserving server-side defaults for normal (foreground) operations. This follows the framework pattern of only setting optional fields when they have meaningful values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: only set return_immediately for non-streaming background ops Per the A2A spec, return_immediately only applies to message/send (non-streaming). It has no effect on streaming operations. Only set the configuration field when both background=True and stream=False. Adds test verifying streaming+background does not set return_immediately. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-05-21 15:04:56 +00:00 -
.NET: Add additional openai specific error observers and move them to openai project (#6004)
* Add additional openai specific error observers and move them to openai project * Address PR comments
westey ·
2026-05-21 13:54:47 +00:00 -
.NET: Add background agents support to HarnessAgent (#5977)
* Add background agents support to HarnessAgent * Add unit tests * Address PR comments
westey ·
2026-05-21 10:57:06 +00:00 -
.NET: Promote FoundryChatClient to public, add file/vector-store helpers and ToPromptAgentAsync converter (#5940)
* Consolidate Foundry chat client decorators into FoundryChatClient - Replace AzureAIProjectChatClient and AzureAIProjectResponsesChatClient with a single internal sealed FoundryChatClient that covers three modes (pure responses, server-side agent reference, hosted agent endpoint). - Rename AzureAIProjectChatClientExtensions to AIProjectClientExtensions to reflect that it extends AIProjectClient. - All four AsAIAgent extension overloads and both FoundryAgent constructors now construct FoundryChatClient internally so the microsoft.foundry telemetry tag is uniform across paths. - Introduce AgentFrameworkUserAgentPolicy that stamps agent-framework-dotnet/{version} on outbound requests, mirroring the Python agent-framework-python/{version} contract. - Delete the Foundry-local MeaiUserAgentPolicy duplicate; rely on MEAI 10.5.1 to stamp MEAI/{version} automatically. - HostedAgentUserAgentPolicy keeps the combined foundry-hosting/agent-framework-dotnet/{version} segment (Python parity) and upgrades the bare segment in place to avoid duplication. - Tests reorganized: FoundryChatClientTests, AIProjectClientExtensionsTests, AgentFrameworkUserAgentPolicyTests, MeaiAutoUserAgentVerificationTests, plus in-place upgrade unit tests in HostedOutboundUserAgentTests. * Promote FoundryChatClient to public; add file/vector-store helpers and ToPromptAgentAsync converter - Promote FoundryChatClient from internal sealed to public sealed for Python parity, so .NET developers can hold and pass a FoundryChatClient directly the way Python developers do. - Mode 3 (hosted agent endpoint) now materializes an AIProjectClient from the parsed project root, making GetService<AIProjectClient>() non-null across all three construction modes. This eliminates the per-mode asymmetry that previously hid project-level helpers from agents constructed via an agent endpoint URL. - Add four new instance methods on FoundryChatClient mirroring Python's spec: UploadFileAsync, DeleteFileAsync, CreateVectorStoreAsync (bundles upload + create + wait), DeleteVectorStoreAsync. Single overload each, path-only inputs to start; additional overloads can be added later without breaking callers. All are Experimental, consistent with the rest of the Foundry package. - Add ToPromptAgentAsync extension methods on ChatClientAgent and FoundryAgent for the agent-to-prompt-agent converter described in the Foundry spec. Mode 1 (responses API) synthesizes a DeclarativeAgentDefinition from the agent's ChatOptions; mode 2 (server-side agent reference, version, or record) returns the cached or freshly fetched Definition; mode 3 throws InvalidOperationException because no local definition exists to convert. - Strict AITool to ResponseTool mapping for mode 1: AIFunction becomes CreateFunctionTool with the function's JSON schema; AITool instances that wrap a ResponseTool unwrap via GetService(typeof(ResponseTool)); anything else throws InvalidOperationException naming the offending tool type. Matches the Python spec's unsupported-tools-raise-ValueError contract. - New unit tests: FoundryChatClientVectorStoreTests (22 tests covering all four helpers across the three FoundryChatClient construction modes plus validation and cancellation), FoundryPromptAgentConverterTests (16 tests covering both extension entry points across mode 1 synthesis, mode 2 cached and fetched paths, all failure modes, and a Python-parity guard asserting both extensions produce equivalent definitions for equivalent inputs), plus four new tests in FoundryChatClientTests for the mode 3 AIProjectClient materialization. * Stop building duplicate ProjectOpenAIClient in FoundryAgent agent-endpoint ctor After Plan #2's mode-3 AIProjectClient materialization, the inner FoundryChatClient already exposes a project-level AIProjectClient (via GetService) that internally provides the project-level ProjectOpenAIClient via GetProjectOpenAIClient(). FoundryAgent's agent-endpoint constructor was still independently constructing a second project-level ProjectOpenAIClient via the now-redundant CreateProjectLevelOpenAIClientFromAgentEndpoint helper — two handles to the same logical resource. Refactor: the agent-endpoint constructor now reads the inner FoundryChatClient's materialized AIProjectClient via base.GetService(typeof(AIProjectClient)) and derives the project-level ProjectOpenAIClient from it. The dead helper on both FoundryAgent (private static wrapper) and FoundryChatClient (the actual implementation) is removed. The user-supplied per-agent ClientPipelineOptions primitives (Transport, RetryPolicy, NetworkTimeout, UserAgentApplicationId) are propagated into the materialized AIProjectClientOptions so test-injected transports and explicit retry / timeout / user-agent settings reach the project-level pipeline — preserving the behavior the dead helper used to provide. Updated AgentEndpointConstructor_GetServiceAIProjectClient_ReturnsNull to its now-correct counterpart AgentEndpointConstructor_GetServiceAIProjectClient_ReturnsNonNull, since after Plan #2 the agent-endpoint ctor surfaces a non-null AIProjectClient (per user direction in Plan #2 Q2). * Strip duplicated AIProjectClient/ProjectOpenAIClient state from FoundryAgent Both _aiProjectClient and _projectOpenAIClient fields on FoundryAgent were redundant: - _aiProjectClient: FoundryAgent's GetService<AIProjectClient> override returned this field, but DelegatingAIAgent.GetService → ChatClientAgent.GetService → FoundryChatClient.GetService<AIProjectClient> already returns the same instance through the delegating chain. Field + override are pure duplication. - _projectOpenAIClient: only used by FoundryAgent's own GetService<ProjectOpenAIClient> override and by CreateConversationSessionAsync. Per user direction, ProjectOpenAIClient is no longer exposed via GetService on either FoundryChatClient or FoundryAgent — callers retrieve it from the AIProjectClient themselves (aiProjectClient.GetProjectOpenAIClient()) the same way the framework does internally. This eliminates the mode-3 asymmetry where the chat client's stored ProjectOpenAIClient was per-agent (URL /agents/{name}/endpoint/protocols/openai) while the agent's was project-level. Refactor: - Delete both fields on FoundryAgent and the GetService override. - Delete the ProjectOpenAIClient branch from FoundryChatClient.GetService. - CreateConversationSessionAsync now resolves AIProjectClient at call time via this.GetService<AIProjectClient>() and derives the conversations client from it. - Update FoundryChatClient tests that asserted on GetService<ProjectOpenAIClient> to assert Null (deliberate removal). - Update FoundryAgent tests AgentEndpointConstructor_GetServiceProjectOpenAIClient_ReturnsNonNull and ProjectEndpointConstructor_GetServiceProjectOpenAIClient_ReturnsNonNull to ...ReturnsNull, and rewrite AgentEndpointConstructor_PropagatesUserAgentApplicationId_ToProjectLevelClient to look up AIProjectClient instead. No production code (only tests) referenced GetService<ProjectOpenAIClient>, so this is a safe surface reduction. Net: 30 insertions, 61 deletions; FoundryAgent shrinks to a pure delegator with only the two convenience methods (CreateSessionAsync, CreateConversationSessionAsync) on top of the delegating chain. * Rename FoundryChatClient.HostedAgentName to AgentName and populate it for mode 2 The previous name implied a mode 3 only property tied to the hosted-agent endpoint URL. Today only hosted endpoints surface this name, but conceptually an agent name exists for every server-side agent the client talks to. Renaming to AgentName makes the property general-purpose and ready for future modes where the same chat client may target other server-side agent shapes that are not necessarily 'hosted'. Mode 2 (server-side agent reference) now mirrors AgentReference.Name into AgentName so callers have a uniform handle regardless of construction mode: * Mode 1 (pure responses): AgentName is null. There is no agent. * Mode 2 (AgentReference): AgentName == AgentReference.Name. * Mode 3 (agent endpoint URL): AgentName is parsed from the URL segment as before. Converter discriminator update: FoundryPromptAgentConverter previously used 'HostedAgentName is not null' to detect mode 3 and reject it. Now that mode 2 also populates AgentName, the mode 3 guard moves to the end of the resolution chain and uses the unambiguous 'AgentName is set AND no AgentReference exists' test. The user-visible error message and behavior are preserved. Dead-state cleanup spotted during format verify: * IDE0052 surfaced that FoundryChatClient._projectOpenAIClient is never read since the prior refactor stopped exposing ProjectOpenAIClient via GetService and rewired CreateConversationSessionAsync to resolve the AIProjectClient through the delegating chain. The field is deleted and its three ctor assignments removed. * HostedAgentEndpointInner.PerAgentClient only existed to plumb the per-agent ProjectOpenAIClient into that now-deleted field, so the property and its ctor parameter are removed. The local 'perAgentClient' variable inside BuildHostedAgentEndpointInner is still needed to derive the inner IChatClient, but no longer escapes the helper. Tests: * Mode1_PureResponses_ReturnsNullForAgentSpecificServices now also asserts AgentName is null. * New Mode2_AgentReference_PopulatesAgentNameFromAgentReference asserts the mode 2 mirror. * Mode3_HostedAgentEndpoint_ParsesAgentNameFromUrl renamed assertion target HostedAgentName to AgentName. Verification: 335/335 net10.0, 273/273 net472 Foundry unit; 229/229 Foundry.Hosting unit; format-verify (WSL2 + Docker mcr.microsoft.com/dotnet/sdk:10.0) clean on Microsoft.Agents.AI.Foundry. * Adopt canonical mode names: Responses Agent, Prompt Agent, Agent Endpoint Three FoundryChatClient construction modes now have one canonical noun used everywhere. * Responses Agent (Mode 1): inline ChatClientAgent, project-level Responses API, no server-side def. * Prompt Agent (Mode 2): server-side ProjectsAgentDefinition invoked by AgentReference. * Agent Endpoint (Mode 3): per-agent URL /agents/{name}/endpoint/protocols/openai. Hosted-or-not. 'Hosted' stays the kind of agent (Microsoft.Agents.AI.Foundry.Hosting). Not synonym of Mode 3. Rings: 1. XML docs + error messages use canonical names. en-GB to en-US: centralises, synthesise. 2. HostedAgentEndpointInner -> AgentEndpointInner, BuildHostedAgentEndpointInner -> BuildAgentEndpointInner. 3. Tests: Mode1_PureResponses_* -> Mode1_ResponsesAgent_*, Mode2_AgentReference_* -> Mode2_PromptAgent_*, Mode3_HostedAgentEndpoint_* -> Mode3_AgentEndpoint_*. Pure rename. No behavior change. 335/335 net10 + 273/273 net472 unit, format clean. * Address PR #5940 design feedback (Q-A through Q-F) Q-A: poll vector store til status leaves InProgress before return. Exp backoff 250ms-2s. Honor cancel. Q-B: try/catch upload loop. Mid-fail = best-effort DeleteFileAsync on already-uploaded ids. Swallow cleanup errors. Q-C: pinned AgentReference.Version uses GetAgentVersionAsync. Empty/whitespace/'latest' = GetLatest path. Q-D: HostedAgentUserAgentPolicy detects existing combined 'foundry-hosting/...' segment. No double prefix. Q-E: mode-3 vector-store test uses fake transport. No DNS to example.com. Q-F: no shim. Class always [Experimental] (since8015e00f5, before dotnet-1.0.0). No compat contract. Callers rename to AIProjectClientExtensions. Rebase onto origin/main reconciliation:aad20c2b3added public AsAIAgent(this AIProjectClient, Uri agentEndpoint, ...) extension that calls an internal FoundryAgent(AIProjectClient, Uri, ...) ctor. Reintroduced that ctor + a new FoundryChatClient(AIProjectClient, Uri, ProjectOpenAIClientOptions?) overload that reuses the supplied AIProjectClient's pipeline (via GetProjectResponsesClientForAgentEndpoint) instead of stamping a fresh credential. Verified: 346/346 net10 + 284/284 net472 Foundry unit, 230/230 Foundry.Hosting unit, format clean. * Add FoundryAgent helper extensions: UploadFile/DeleteFile/CreateVectorStore/DeleteVectorStore 4 thin forwarders on FoundryAgent that route to the inner FoundryChatClient's helpers via agent.GetService<FoundryChatClient>().X(). Live in existing FoundryAgentExtensions.cs alongside ToPromptAgentAsync. Throws InvalidOperationException when agent does not expose a FoundryChatClient via GetService (same pattern as ToPromptAgentAsync). Unit tests: FoundryAgentExtensionsTests covers all 4 forwarders + null-agent ArgumentNullException for each. 8 new tests, 354/354 net10 + 292/292 net472. Integration tests: parallel FoundryAgentExtensionsTests under Foundry.IntegrationTests mirrors the existing CreateAgent_CreatesAgentWithVectorStoresAsync shape (upload -> create vector store -> FileSearch tool answers question -> cleanup), but routes every helper call through the new FoundryAgent extensions. 4 new IT tests, all verified pass live against the real Foundry project (12-30s each). Skipped by default like the existing vector-store IT. * Address Sergey's PR review comments #1 (FoundryAgent.cs:139): drop unused aiProjectClient param from internal FoundryAgent(AIProjectClient, ChatClientAgent) ctor. Was discarded after null-check. Inner FoundryChatClient already surfaces AIProjectClient via GetService. 3 call sites in AIProjectClientExtensions updated. #2 (FoundryChatClient.cs:376): add pollingTimeout param to CreateVectorStoreAsync. Defaults to 5 min, configurable, Timeout.InfiniteTimeSpan disables. Throws TimeoutException with vector store id and elapsed seconds when bound exceeded. CancellationToken still wins. New unit test PollingTimeout_ThrowsTimeoutExceptionAsync. FoundryAgentExtensions forwarder updated to plumb the new param. Verified: 355/355 net10 + 293/293 net472 Foundry unit, 230/230 Foundry.Hosting unit, format clean.Roger Barreto ·
2026-05-21 10:05:58 +00:00 -
Python: feat(foundry): add experimental hosted tool factories on FoundryChatClient (#5958)
* feat(foundry): add experimental hosted tool factories on FoundryChatClient Adds eight new `@experimental` static factory methods on `FoundryChatClient` covering Foundry-hosted tools that previously had no helper: - get_azure_ai_search_tool - get_sharepoint_tool - get_fabric_tool - get_memory_search_tool - get_computer_use_tool - get_browser_automation_tool - get_bing_custom_search_tool - get_a2a_tool All factories are marked with the new `ExperimentalFeature.FOUNDRY_TOOLS` tag and resolve the underlying `azure-ai-projects` preview classes lazily through a `_require_sdk_class` helper so older SDK versions still import cleanly and fail with a clear `ImportError` only on use. Tests cover each factory's return type and field wiring, the experimental metadata, and the missing-SDK-class fallback. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(foundry): address review comments on tool-factory tests * Skip preview-tool tests gracefully (`_skip_if_sdk_class_missing`) when the installed `azure-ai-projects` does not expose the required preview class, matching the lazy-import guard in production code so the test suite stays green on older SDK installs. * Add `filterwarnings("ignore::FutureWarning")` to each new tool-factory test (and the parametrized metadata test) so they remain stable under strict warning configurations \u2014 the global dedup in `_feature_stage._WARNED_FEATURES` makes `pytest.warns` brittle across ordered runs. * Use `monkeypatch.setattr(..., None, raising=False)` instead of `delattr` in the missing-SDK-class test so it works for modules that implement PEP 562 `__getattr__`. * Split the long `get_bing_custom_search_tool` return into two lines for readability. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): harden tool-factory kwargs against silent override * Reorder the dict-literal kwargs assembly in get_azure_ai_search_tool, get_memory_search_tool, and get_bing_custom_search_tool so explicit parameters always take precedence over **kwargs (matching the safe pattern already used in get_a2a_tool). This prevents a caller passing `project_connection_id`, `index_name`, `memory_store_name`, `scope`, or `instance_name` through `**kwargs` from silently overriding the explicit security-sensitive arguments. * Update the README experimental note to reflect once-per-feature-id dedup semantics of `_feature_stage._WARNED_FEATURES` rather than claiming a per-factory "first use" warning. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(foundry): split FOUNDRY_TOOLS / FOUNDRY_PREVIEW_TOOLS, add bing-grounding - Add ExperimentalFeature.FOUNDRY_PREVIEW_TOOLS to distinguish wrappers around preview Foundry SDK tool classes (Sharepoint/Fabric/Memory/ComputerUse/ BrowserAutomation/BingCustomSearch/A2A) from FOUNDRY_TOOLS, which is for GA-SDK wrappers that are simply new in agent-framework-foundry (AzureAISearch, BingGrounding). - Add get_bing_grounding_tool factory and a 'Choosing a web grounding tool' comparison block on get_web_search_tool / get_bing_grounding_tool / get_bing_custom_search_tool docstrings. - Drop the _require_sdk_class lazy resolver: every guarded class is available at azure-ai-projects>=2.1.0 (the package floor), so import them eagerly. Concrete return types replace 'Any'. - README: split the experimental factories into two tables, one per feature flag, with a note explaining the distinction. - Tests: split into FOUNDRY_TOOLS / FOUNDRY_PREVIEW_TOOLS factory cases; drop the obsolete missing-SDK-class ImportError test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-21 08:39:08 +00:00 -
ci: pin third-party GitHub Actions to commit SHAs (#5972)
Replaces every floating tag in our workflow and composite action files with an immutable 40-character commit SHA, keeping the original `# vX` comment so Dependabot can still propose version bumps. 186 occurrences across 25 workflows and 2 composite actions. Also widens the github-actions Dependabot entry to use the plural `directories` key with `/.github/actions/*` so composite actions under `.github/actions/<name>/action.yml` are kept up to date. Previously Dependabot only scanned `.github/workflows` and the repo-root `action.yml`, leaving our `python-setup` and `sample-validation-setup` composite actions unmaintained.
Roger Barreto ·
2026-05-20 22:10:32 +00:00 -
Python: Show more authentication methods in Foundry Toolbox MCP (#5719)
* Show more authentication methods in Foundry Toolbox MCP * Remove hardcoded toolbox version num * Add Foundry MCP OAuth consent handling * Use message instead of the dedicated item type * Go back to using OAuthConsentRequestOutputItem * WIP: sample testing * Update error code * Address review on Foundry Toolbox MCP samples Reviewed feedback addressed: - Drop the branch-pinned `git+https://...@feature/...` entries from `04_foundry_toolbox/requirements.txt`; restore the simple comment + `mcp` runtime dep. The git pins were only useful while iterating on the PR and shouldn't ship. (eavanvalkenburg) - Fix the `/toolsets/` typo in both `04_foundry_toolbox/README.md` and `06_files/README.md`. Verified empirically against the research_toolbox in the test workspace: the toolbox MCP gateway lives at `/toolboxes/{name}/mcp?api-version=v1` and requires the `Foundry-Features: Toolboxes=V1Preview` header. `/toolsets/{name}/mcp` returns 403 with `preview_feature_required: Toolsets=V1Preview` (a different opt-in feature). - Wrap `httpx.AsyncClient(...)` in `async with ... as http_client:` in both samples so the connection pool is cleaned up. (Copilot reviewer) - Make the `TOOLBOX_NAME` env var consistent in both samples. Previously the tool name silently fell back to `"toolbox"` when `TOOLBOX_NAME` was unset, but `resolve_toolbox_endpoint()` still required `TOOLBOX_NAME` and would raise `KeyError`. The samples now resolve the endpoint once and derive the tool name from the resolved URL when `TOOLBOX_NAME` isn't set, so the local tool name always matches the upstream toolbox identity regardless of which env var the user set. (Copilot reviewer) - Rename `_responses.is_consent_error` to `consent_url_from_error`: the helper returns `str | None` (the consent URL), not a bool, so the new name matches behavior. Update the test class accordingly. (eavanvalkenburg) - Tighten `_handle_inner_agent`'s lazy-entry catch from `Exception` to `AgentFrameworkException`, the type the MCP layer actually wraps consent errors in via `MCPStreamableHTTPTool.__aenter__` → `ToolExecutionException(inner_exception=mcp_error)`. Network failures, cancellations, and other non-framework exceptions now propagate normally instead of being briefly caught and re-raised. The test helper `_make_consent_error` is updated to use `ToolExecutionException` so it matches the real-world wrapping. (eavanvalkenburg) - Clarify the `github_pat` description in `agent.manifest.yaml` to note it's only needed when the PAT-based connection (`github-mcp-pat-conn`) is chosen; users selecting the OAuth2 connection (`github-mcp-oauth-conn`) can leave it empty. (Copilot reviewer) Validation: ran both samples end-to-end against a real Foundry toolbox (`research_toolbox`) -- the samples connect successfully and the agent lists the toolbox's MCP tools (`api_specs___fetch_azure_rest_api_docs`, etc.). `uv run poe test -P foundry_hosting` passes (119 tests), pyright + mypy clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: fix broken Foundry samples link in 04_foundry_toolbox README The previous URL pointed to an old location of the toolbox supported-scenarios doc; the doc moved to /samples/python/hosted-agents/SUPPORTED_TOOLBOX_SCENARIOS.md and the old /samples/python/toolbox/azd path now 404s. Caught by the markdown-link-check CI step. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tao Chen ·
2026-05-20 12:00:38 +00:00 -
[BREAKING] Python: Enable instrumentation by default (#5865)
* Enable instrumentation by default * Update samples * Optimization when span is not recording * Address Copilot comments * Revert uv.lock * Add warning * Formatting * Fix mypy * Add disable_instrumentation() with sticky user-intent semantics Add a public disable_instrumentation() entry point so users can explicitly opt out of Agent Framework telemetry, with a sticky-disable flag that makes the user's intent "leading" — no framework code path (foundry's configure_azure_monitor, configure_otel_providers, enable_instrumentation, enable_sensitive_telemetry, or direct OBSERVABILITY_SETTINGS.enable_* writes) can re-enable instrumentation until the user explicitly clears the disable with enable_instrumentation(force=True) / enable_sensitive_telemetry(force=True). Also addresses the two remaining unresolved review threads on the PR: 1. test_observability_settings_defaults_instrumentation_true pins the new "ENABLE_INSTRUMENTATION defaults to True when env unset" behavior. 2. test_enable_instrumentation_reads_env_sensitive_data restores coverage for the post-import load_dotenv() fallback path. Implementation: - ObservabilitySettings.enable_instrumentation / enable_sensitive_data become properties backed by _enable_*. While _user_disabled is True, the getters return False and the setters drop True writes (defense in depth so third- party writes can't subvert the disable). - Public is_user_disabled read-only property lets integrations (e.g. foundry's configure_azure_monitor) cheaply check the disable state without poking at privates. - enable_instrumentation() and enable_sensitive_telemetry() short-circuit with an info log when disabled; gain a force=True kwarg that clears the disable. - configure_otel_providers() still creates providers / exporters / views so a later force-enable can use them, but logs an info message when called while disabled. - Foundry's FoundryChatClient.configure_azure_monitor and FoundryAgent.configure_azure_monitor early-return when the user has disabled, so Azure Monitor's global providers aren't installed unnecessarily. Tests: 11 new tests covering default-on, env re-read at call time, sticky behavior against each re-enable surface (enable_instrumentation, enable_sensitive_telemetry, configure_otel_providers, direct attribute writes), force=True override, re-arming the disable, and the __all__ export. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: document disable_instrumentation() and force=True paths Add a "Disabling instrumentation" section to the observability sample README that walks through: - The distinction between the ENABLE_INSTRUMENTATION env var (initial, non-sticky) and disable_instrumentation() (process-wide, sticky). - Why the sticky semantics matter: framework integrations like FoundryChatClient.configure_azure_monitor() can call enable_instrumentation() as part of their setup, and the user's opt-out needs to win. - All five surfaces guarded by the sticky disable (property reads, public enable functions, configure_otel_providers, direct attribute writes, is_user_disabled-aware integrations). - The force=True escape hatch on both enable_instrumentation() and enable_sensitive_telemetry(). - How third-party integrations should consult OBSERVABILITY_SETTINGS.is_user_disabled. - The limits of the disable (does not tear down existing providers / in-flight spans / third-party instrumentation, does not persist across processes). Cross-links the new section from the ENABLE_INSTRUMENTATION row in the env vars table. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: soften disable_instrumentation() overclaim about telemetry guarantees Replace 'no telemetry will be emitted no matter what' (which is too strong, since callers can still pass force=True or mutate private attributes) with language framing the disable as a user-intent contract that library and framework code is expected to honor: the framework actively short-circuits the public enable paths, force=True and private-attribute writes are acknowledged as out-of-contract escape hatches that integrations should not use on the user's behalf. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: correct observability Dependencies section - opentelemetry-sdk is no longer a hard dependency; it is lazily imported by create_resource(), create_metric_views(), and configure_otel_providers() with a clear ImportError when missing. Day-to-day instrumentation works with opentelemetry-api alone provided some other component configures the global OpenTelemetry providers (Azure Monitor, an APM agent, application bootstrap, etc.). - opentelemetry-semantic-conventions-ai is no longer used anywhere in the source; remove it from the listed dependencies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: replace stale observability migration guide with current PR's only relevant migration The old guide documented the move away from setup_observability(otlp_endpoint=...) which was an earlier-release API change unrelated to this PR and stale enough that it's more confusing than helpful at this point. Replace it with a short note on the single migration this PR introduces: callers of enable_instrumentation(enable_sensitive_data=True) should switch to enable_sensitive_telemetry(). Cross-link to the Disabling instrumentation section for the rare 'force on without enabling sensitive data' use case where enable_instrumentation() still applies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tao Chen ·
2026-05-20 11:52:08 +00:00 -
Python: Skip MCP prompt loading when unsupported (#5370)
* Python: Skip MCP prompt loading when unsupported * Fix MCP pagination pyright checks * Simplify MCP support flag checks
Baidar ·
2026-05-20 11:50:26 +00:00 -
.NET: Add A2AAgentOptions and align A2AAgent constructors with ChatClientAgent pattern (#5954)
* .NET: Add A2AAgentOptions and align A2AAgent constructors with ChatClientAgent pattern Adds a new A2AAgentOptions class (Id, Name, Description, Clone) and an options-based constructor on A2AAgent, mirroring ChatClientAgent/ChatClientAgentOptions. The existing parameter-based constructor is preserved for backward compatibility and now delegates to the options-based one. Extension methods are extended with options-based overloads: - A2AClientExtensions.AsAIAgent(IA2AClient, A2AAgentOptions, ...) - A2AAgentCardExtensions.AsAIAgent(AgentCard, A2AAgentOptions, ...) - A2ACardResolverExtensions.GetAIAgentAsync(A2ACardResolver, A2AAgentOptions, ...) For card-based creation, user-supplied options override values from the agent card; Name and Description fall back to card values when not set. Options are cloned when stored on the agent to prevent post-construction mutation, matching the ChatClientAgent pattern. Resolves #5870. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review comments - Add Throw.IfNull(client) in A2AClientExtensions.AsAIAgent - Add Throw.IfNull(card) in A2AAgentCardExtensions.AsAIAgent - Clarify httpClient docs in A2ACardResolverExtensions.GetAIAgentAsync: it applies to the created A2A client, not to card discovery - Rename test methods from GetAIAgent_* to AsAIAgent_* to match the API under test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SergeyMenshykh ·
2026-05-20 10:05:24 +00:00 -
Evan Mattson ·
2026-05-20 10:01:44 +09:00 -
Python: feat: add agent-framework-monty (Monty-backed CodeAct provider) (#5915)
* Python: feat: add agent-framework-monty (Monty-backed CodeAct) New alpha package that wraps pydantic-monty (a Rust-based Python interpreter) behind the same CodeAct API surface as agent-framework-hyperlight, so users can swap providers with minimal code change. Public API (agent_framework_monty): - MontyCodeActProvider — ContextProvider that injects a run-scoped execute_code tool plus dynamic CodeAct instructions. - MontyExecuteCodeTool — standalone FunctionTool for mixed-tool agents or manual static wiring. - FileMount / FileMountInput / MountMode — public types mirroring the Hyperlight names, with Monty's mode (read-only/read-write/overlay) and write_bytes_limit on FileMount. Constructor kwargs (both classes) mirror Hyperlight where possible: tools, approval_mode, workspace_root, file_mounts; plus a Monty-only resource_limits forwarding ResourceLimits to Monty.start(). Filesystem flow: - workspace_root auto-mounts at /input (read-write), matching Hyperlight. - file_mounts accepts string shorthand, (host, mount) tuple, or FileMount with mode + write cap. - Files written under read-write mounts are scanned post-execution and returned as Content.from_data items (mirrors Hyperlight /output). - overlay mounts buffer writes in-memory; read-only mounts reject writes. Internals: - _monty_bridge.InlineCodeBridge ports the inline (non-durable) bridge from anthonychu/maf-codeact-monty-python; handles FunctionSnapshot / FutureSnapshot pause/resume, dispatches direct typed calls + the call_tool fallback, forwards mount/limits to Monty.start(...). - generate_type_stubs emits per-tool stubs so Monty's `ty` type-checker rejects bad calls before any host tool runs. Alpha-policy compliance (per python-package-management skill): - Added agent-framework-monty = { workspace = true } to root pyproject.toml. - Added row to python/PACKAGE_STATUS.md. - Added monty entry under Experimental in python/AGENTS.md. - NOT added to core[all]; NO agent_framework.monty lazy shim (deferred to beta promotion). Samples (three sets, import from agent_framework_monty directly): - samples/02-agents/context_providers/code_act/monty_code_act.py (provider pattern) + updated local README. - samples/02-agents/tools/monty_code_interpreter/ (standalone + manual-wiring + README). - samples/04-hosting/foundry-hosted-agents/responses/11_monty_codeact/ (full hosted-agent layout with uv-based pyproject.toml + Dockerfile, Azure Monitor wiring via APPLICATIONINSIGHTS_CONNECTION_STRING + enable_instrumentation, ENABLE_INSTRUMENTATION and ENABLE_SENSITIVE_DATA env vars). The alpha wheel is vendored into ./wheels/ (gitignored) via vendor-wheel.sh; new row added to the parent Responses-API README. Tests: - 28 hermetic unit tests (stubbed pydantic_monty). - 18 integration tests marked @pytest.mark.integration, auto-skipped when pydantic_monty is unimportable; exercise the real Monty runtime: print round-trip, last-expression value, direct typed tool dispatch, call_tool fallback, async tool, asyncio.gather parallelism, ty type-check rejection, OS blocked by default, workspace_root read+write capture, read-only / overlay mount semantics, resource_limits.max_duration_secs abort, approval gating end-to-end, full Agent run with a scripted chat client. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix: monty FileMount test compares against the normalized POSIX path The shorthand string mount goes through _normalize_mount_path, which rewrites Windows drive letters like 'C:\\Users\\...' into '/C:/Users/...' (POSIX-style). The Windows CI runners surfaced this because tmp_path resolves to a backslashed Windows path; the test was comparing against the raw str(host_a) instead of the normalized form. Compare against _normalize_mount_path(str(host_a)) so the assertion is platform-independent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix: address PR #5915 review feedback - _execute_code_tool docstring: clarify that the Monty backend supports scoped filesystem access via workspace_root / file_mounts (blocked by default). - _to_monty_mount: import pydantic_monty lazily through load_monty so missing-dependency errors surface as the same actionable RuntimeError the rest of the package raises (not a bare ImportError at module load). Renamed _load_monty -> load_monty for the same reason. - _python_type_repr: emit None for type(None) instead of Any, and normalize both typing.Union[...] and PEP-604 X | Y to PEP-604 syntax so Optional[X] / Union[..., None] / -> None signatures round-trip correctly through ty validation. Added a regression test. - _PrintCollector: track a running character count instead of recomputing sum(len(c) for c in self.chunks) per callback. Eliminates the O(n^2) cost on print-heavy code. - Instructions: mention that the value of the final expression is also returned alongside captured stdout (matches actual behavior). - 11_monty_codeact Dockerfile: pin ghcr.io/astral-sh/uv to 0.11.6 instead of :latest for reproducible builds. - 11_monty_codeact README: replace the bare "see parent README" pointer with sample-specific steps (./vendor-wheel.sh + uv sync + uv run), since the sample uses pyproject.toml + a vendored wheel rather than requirements.txt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: sample: 11_monty_codeact installs agent-framework-monty from PyPI Drop the vendored-wheel scaffolding now that agent-framework-monty is on PyPI as an alpha (1.0.0a*) release: - pyproject.toml: remove [tool.uv.sources] override; keep [tool.uv] prerelease = "allow" so uv pulls the alpha automatically. - Dockerfile: drop the COPY wheels/ step. - README: drop the ./vendor-wheel.sh setup step and the not-yet-on-PyPI warning. - Delete vendor-wheel.sh and the gitignored wheels/ directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix(monty): harden post-execution file capture against symlink escape Same class of issue as the MSRC-reported Hyperlight finding: the post-execution capture walked workspace_root with Path.rglob() + is_file() + read_bytes() - all of which follow symlinks. An attacker who controls the workspace (cloned repo, extracted archive, shared workspace) could pre-place `workspace/leak.txt -> /etc/passwd` or `workspace/outside_dir -> /etc/` and have host files surface as captured Content items. Monty's mount layer already rejects symlink reads from inside the sandbox across all three modes (verified empirically), so the runtime path was safe. This commit closes the post-execution scan path. Changes: - New `_iter_real_files(root)` walker that uses iterdir() + is_symlink() to skip symlinks at every directory level and yields only real files. Replaces the previous `host_root.rglob("*")` calls in both `_snapshot_writable_mounts` and `_capture_written_files`. - Use `Path.lstat()` instead of `Path.stat()` so size/mtime can never be taken from a symlink target. - Three new integration tests reproducing the MSRC attack shape against the workspace_root flow: symlink-to-file outside workspace, symlink-to-directory outside workspace, and a guard ensuring legitimate sandbox writes are still captured when symlinks are present. Per user request, hyperlight is untouched in this commit (separate fix). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix(monty): skip symlink regression tests when unsupported Apply the same Windows-CI safety guard as the hyperlight fix in PR #5919: the three symlink integration tests create symlinks via Path.symlink_to(), which fails with OSError / NotImplementedError on unprivileged Windows runners. Add a local _symlinks_supported helper (mirroring the one in packages/core/tests/core/test_skills.py) and pytest.skip when symlinks aren't available, so the tests no longer fail for environment reasons. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix(monty): address PR #5915 follow-up review feedback - _invoke_tool: drop the inspect.iscoroutinefunction(...) branch and always `await self.tool_map[name](**kwargs)`. Every entry in tool_map is `partial(FunctionTool.invoke, skip_parsing=True)` and FunctionTool.invoke is `async def`, so the branching was dead code - and on Python versions affected by cpython#98590, iscoroutinefunction(partial(bound_async_method, ...)) returns False, causing the bridge to take the asyncio.to_thread path, return an unawaited coroutine, and surface it as a JSON-serialization failure for every tool call. Added a regression test test_invoke_tool_awaits_partial_wrapped_async_method. - generate_type_stubs: skip tools whose name is not a valid Python identifier or is a Python keyword. FunctionTool.name has no upstream validation, so a name like "weird-name" produced a syntax error in the stubs and a name like "broken\n pass\nasync def injected" would inject arbitrary stub source. Non-identifier names stay reachable via `call_tool("weird-name", ...)` at runtime; they just don't get type-checked stubs. Added regression test test_generate_type_stubs_skips_non_identifier_tool_names. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>Eduard van Valkenburg ·
2026-05-20 00:35:23 +00:00 -
Python: Bump Python package versions for a release (#5964)
* Bump Python package versions to 1.5.0 for a release * Promote orchestrations to 1.0.0rc1 * ci(python-setup): merge dynamic exclude into existing workspace exclude The python-setup action injected exclude = [...] verbatim into [tool.uv.workspace], producing a duplicate 'exclude' key when the section already had a static exclude. Scope the rewrite to the [tool.uv.workspace] section and append the package to the existing array when present; idempotent if the package is already excluded. * Address Copilot review feedback: raise inter-package floors to 1.5.0 - foundry, foundry-local: agent-framework-openai >=1.4.0 -> >=1.5.0 - azure-contentunderstanding: agent-framework-foundry >=1.4.0 -> >=1.5.0 - azurefunctions: pin agent-framework-durabletask to >=1.0.0b260519,<2 Keeps lockstep cohort consistent and avoids mixed 1.4.x / 1.5.0 installs. * Re-include azurefunctions and durabletask in the uv workspace The pinned durabletask>=1.4.0 floor is enough to make resolution succeed; the workspace exclude was over-correction and broke CI samples and pyright type-checking (re-exports in agent_framework/azure/__init__.pyi plus samples/04-hosting/{azure_functions,durabletask}/ could not resolve their imports). Dropping them from agent-framework-core[all] still stands so the metapackage does not pull them. * Restore azurefunctions and durabletask in agent-framework-core[all] The durabletask floor pin keeps users on the safe 1.4.0, so they are once again included in the metapackage. Update CHANGELOG to reflect the pin rather than an [all] removal. * Raise uvicorn ceiling in ag-ui and devui to allow 0.42+ The root override-dependencies pins uvicorn[standard]>=0.34.0 (no upper) and the workspace lock resolves to 0.47.0. The package ceiling <0.42.0 meant the workspace was no longer testing the declared supported range. Bump to <1 so the lock fits within the declared bounds. Also picked up by validate-dependency-bounds: refresh stale orchestrations RC pin in devui dev deps.Evan Mattson ·
2026-05-20 09:20:53 +09:00 -
ci(python-setup): drop -U upgrade flag from uv sync (#5961)
The shared composite action ran `uv sync --all-packages --all-extras --dev -U` on every job, which upgrades every dependency to the latest compatible version instead of using the pinned versions in `uv.lock`. That is currently producing a hard resolver failure on every CI job: No solution found when resolving dependencies for split (markers: python_full_version >= '3.11' and sys_platform == 'darwin') Because there are no versions of durabletask and agent-framework-durabletask depends on durabletask>=1.3.0,<2, we can conclude that agent-framework-durabletask's requirements are unsatisfiable. Dropping `-U` makes the install use the workspace lockfile, which is what is reproducible locally and what we publish releases against. Upgrades should be opt-in (via a scheduled job or a separate workflow) rather than implicit on every CI run. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>Eduard van Valkenburg ·
2026-05-19 19:33:11 +00:00 -
.NET: Reduce re-rendering in harness console (#5953)
* Reduce re-rendering in harness console * Address PR comments * Fix broken merge
westey ·
2026-05-19 19:10:57 +00:00 -
.NET: Harness code act skill sample (#5930)
* Add sample that shows code execution and skills together * Use nuget for python module path * Update readme. * Fix formatting. * Reduce flashing in rendering. * Improve screen clearing for Powershell * Add a couple of small UX fixes
westey ·
2026-05-19 15:49:03 +00:00 -
westey ·
2026-05-19 15:32:14 +00:00 -
Remove duplicate pop in InMemoryCacheProvider.remove (#5795)
The second self._cache.pop(key, None) call is a guaranteed no-op: the first pop has already removed the key (or returned None), and there is no await between the two statements that could allow another coroutine to re-add it. Removing the dead line clarifies intent without changing behavior.
Taisir Hassan ·
2026-05-19 14:02:20 +00:00 -
Python: fix: hyperlight skips symlinks when staging sandbox input (#5919)
* Python: fix(hyperlight): skip symlinks when staging files into the sandbox The helpers that populate the sandbox input tree (``_copy_path`` and the ``_path_tree_signature`` walker used for cache invalidation) relied on ``Path.is_file()``, ``Path.is_dir()`` and ``shutil.copy2`` - all of which follow symlinks by default. When the source tree contains symlinks, that let entries from outside the configured input source surface inside the sandbox. Harden both code paths to never follow symlinks: - ``_copy_path`` now bails out via ``Path.is_symlink()`` before any ``is_dir()`` / ``is_file()`` check, skips non-regular files, and uses ``shutil.copy2(..., follow_symlinks=False)`` as defense in depth. - New ``_iter_real_entries`` walker replaces the previous ``Path.rglob`` call inside ``_path_tree_signature`` (rglob follows directory symlinks). - ``_path_tree_signature`` switches to ``Path.lstat()`` so size/mtime are never read through a symlink target. Added regression tests covering: - A pre-placed file symlink in ``workspace_root`` (top level). - A pre-placed directory symlink in ``workspace_root``. - A nested file symlink inside a real subdirectory. - ``_path_tree_signature`` ignoring symlinks so the cache key reflects only what is actually staged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix(hyperlight): address PR #5919 review feedback - _iter_real_entries now yields directories and regular files only, skipping non-regular entries (sockets/FIFOs/devices). Keeps the cache-key signature consistent with what _copy_path actually stages. - The four new symlink regression tests skip when the platform does not support symlink creation (e.g. unprivileged Windows runners), via a local _symlinks_supported helper modelled on the one in packages/core/tests/core/test_skills.py. Prevents OSError / NotImplementedError from failing CI jobs that have nothing to do with the change under test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix(hyperlight): address PR #5919 follow-up review feedback - _copy_path docstring: narrow the scope to "symlink entries present in the source tree at rest" and explicitly call out that the copy is NOT atomic with respect to concurrent mutation of the source tree. Callers who need that stronger guarantee should snapshot their workspace before passing it in. Avoids overpromising on a TOCTOU window that pathlib cannot express; closing it properly would need fd-based traversal (O_NOFOLLOW | O_DIRECTORY + os.scandir(fd)) with a separate Windows story, which is out of scope for this targeted fix. - _path_tree_signature: drop the `if path.is_symlink(): return ()` short-circuit. Resolve a symlink root to its real target before walking instead. The public construction flow already resolves workspace_root / file_mounts[].host_path up front so this never affected user-facing code, but the short-circuit was misleading and would have produced an empty, stable signature for any direct caller that builds a _RunConfig without going through the public constructor. Defense in depth: even if a future call site forgets to resolve the root, the cache key still reflects real contents. - Added regression test test_path_tree_signature_walks_through_symlinked_root: a symlinked workspace root must produce a non-empty signature, AND the signature must change when the real target's contents change so the cache key actually invalidates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-19 11:41:53 +00:00 -
Python: Record actual served model from Azure OpenAI (#5910)
* Record actual served model as response model for Azure OpenAI * Formatting * Fix tests * Fix pipeline error * Comments * Address review: surface served model via ChatResponse.model Apply blocking review feedback from PR #5910: - Use ChatResponse.model / ChatResponseUpdate.model as the source of truth for the Azure x-ms-served-model header value, instead of stashing it in additional_properties and overriding it again in observability. Observability already reads response.model; the chat client now overwrites it post-parse when the served-model header is present. Empirically the Azure Responses API returns the deployment alias in body.model and the actual snapshot (e.g. gpt-5-nano-2025-08-07) in this header. - Move the AZURE_OPENAI_SERVED_MODEL_HEADER constant out of observability.py and into RawOpenAIChatClient (as the SERVED_MODEL_HEADER ClassVar). The header is Azure-OpenAI-Responses-API-specific so observability does not need to know about it. - Revert the streaming text_format path to client.responses.stream(...) and drop the _pydantic_model_to_text_format_param helper. That helper imported from openai.lib._parsing._responses (a private SDK path) and the swap to responses.create(stream=True) dropped client-side output_parsed for structured-output streaming. The streaming-with-text_format path is the only one that does not surface the served-model header - documented inline. - Wrap the raw streaming responses in async with so the underlying socket closes deterministically (continuation_token retrieve + create paths). - Fix the empty-string / whitespace-only header at the source by stripping in _extract_served_model and returning None when nothing remains. - Revert unrelated formatting-only churn in _skills.py and test_mcp.py. - Update unit tests to assert against chat_response.model / update.model and add an aggregated streaming assertion plus a pin that the streaming-with-text_format path does not get the header. Verified end-to-end against Azure OpenAI Responses API: deployment alias gpt-5-nano now reports gpt-5-nano-2025-08-07 as ChatResponse.model in both the non-streaming and streaming paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: preserve streaming structured output finalization Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/f62076ef-558d-49e8-8fe2-f38d527c9639 Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com> * refactor: name streaming response finalizer Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/f62076ef-558d-49e8-8fe2-f38d527c9639 Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com> * fix: capture streaming response format after prepare Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/f62076ef-558d-49e8-8fe2-f38d527c9639 Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com> * refactor: clarify streaming response format capture Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/f62076ef-558d-49e8-8fe2-f38d527c9639 Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com> * test: use public API for streaming structured output Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/f62076ef-558d-49e8-8fe2-f38d527c9639 Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com> * Inline the served-model header override at its two call sites The `_apply_served_model_header` helper was a 1-line wrapper around `_extract_served_model`. Inlining the `if served_model is not None: ...` matches the pattern already used in the streaming paths and folds the explanatory docstring onto `_extract_served_model` (which is now the single place that knows about the header). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com>
Tao Chen ·
2026-05-19 06:38:53 +00:00 -
Python: Improve the handling of intermediate outputs for workflows and orchestrations (#5623)
* Improve the handling of intermediate outputs for workflows and orchestrations * Address PR review feedback on intermediate output forwarding - Switch workflow.as_agent() forwarding to an explicit allowlist of {output, intermediate, data, request_info} so orchestration-internal events (group_chat, handoff_sent, magentic_orchestrator) stay inside the workflow instead of leaking into agent responses via str(data) coercion. - Stop raising on intermediate AgentResponseUpdate in non-streaming run(); surface the partial as a Message with text_reasoning content. The defensive raise still applies to terminal output events, where Update payloads would corrupt message ordering. - Extend the DevUI workflow-event mapper so intermediate yields wrapping plain strings, Messages, and list[Message] render as visible output items instead of generic completed-trace events. - Add orchestration coverage for GroupChat, Handoff, and Magentic builders (default vs intermediate_outputs=True; structural where end-to-end is heavy). * Lift output-designation policy into a value type Replace the ``Workflow._output_executors`` list and the ``RunnerContext.should_label_as_intermediate`` Protocol method with a single immutable ``OutputDesignation`` value type owned by ``Workflow``. Thread the designation as a parameter through the existing call chain (Runner -> EdgeRunner -> Executor -> WorkflowContext) so ``yield_output`` consults the threaded snapshot directly rather than calling back into the runner context. Removes the ``InProcRunnerContext._workflow`` back-reference and the ``WorkflowBuilder.build()`` assignment that wired it up. Adds the public predicate ``Workflow.is_terminal_executor(executor_id)`` for external observers; ``OutputDesignation`` itself stays package-internal. Key decisions - ``OutputDesignation.designated`` is ``frozenset[str] | None`` -- ``None`` preserves legacy "every yield is type='output'" behavior, any frozenset (including empty) opts into strict mode. The ``DeprecationWarning`` for legacy mode at build time is unchanged. - ``output_designation`` is an optional parameter on ``Runner``, ``EdgeRunner.send_message``, ``EdgeRunner._execute_on_target``, ``Executor.execute``, ``Executor._create_context_for_handler``, and ``WorkflowContext.__init__``. Each defaults to legacy ``OutputDesignation()`` so direct callers (Azure Functions ``CapturingRunnerContext``, ``test_runner`` recording fixtures) keep working without ceremony. - The workflow-level filter in ``_run_core`` reads ``self._output_designation`` live, preserving today's semantics where mutating the designation after build still affects subsequent runs (used by two existing tests). - ``Workflow.to_dict()`` continues to emit ``"output_executors": list[str] | None`` (sorted from the frozenset). Checkpoint format unchanged. Files changed - _workflow.py: add ``OutputDesignation`` dataclass; replace ``_output_executors`` with ``_output_designation``; add ``is_terminal_executor``; delete ``_should_yield_output_event``. - _runner_context.py: drop ``should_label_as_intermediate`` Protocol method and ``InProcRunnerContext`` impl; drop ``_workflow`` back-reference. - _workflow_builder.py: remove ``context._workflow = workflow`` assignment. - _runner.py, _edge_runner.py, _executor.py, _workflow_context.py: thread ``output_designation`` parameter through the call chain. - tests/workflow/test_output_designation.py (new): three-state coverage of the value type plus the public predicate delegation. - tests/workflow/test_workflow_builder.py, test_validation.py, test_workflow.py, test_runner.py and orchestrations/tests/test_orchestration_intermediate_vs_terminal.py: switch probes from ``_output_executors`` set checks to ``get_output_executors`` / ``is_terminal_executor``; update two post-build mutation tests to set ``_output_designation`` instead. Verification - core/tests/workflow/, orchestrations/tests/, azurefunctions/tests/: 1119 passed, 42 skipped, 2 xfailed. - ``uv run poe lint``: clean. - ``uv run poe typing``: only the pre-existing ``_AGENT_FORWARDED_EVENT_TYPES`` pyright warning from394bcd607remains. Notes for next iteration - The builder's own ``_output_executors`` attribute (``list[Executor | SupportsAgentRun]``) is intentionally untouched; the issue scoped the rename to the workflow attribute. - Adjacent review candidates (twin ``WorkflowAgent`` translators, ``_AGENT_FORWARDED_EVENT_TYPES`` kind classifier, ``_event_origin_context`` ContextVar removal, ``WorkflowEvent`` ADT split, legacy-mode removal) remain out of scope. * Add explicit workflow output designation Key decisions - Extend the internal OutputDesignation value type from terminal-only membership to output/intermediate/hidden classification. Legacy mode remains outputs=None, so workflows built without output_executors or intermediate_executors still label every yield_output as type='output'. - WorkflowBuilder now accepts intermediate_executors. Providing either designation enters explicit mode; output executors emit output, intermediate executors emit intermediate, and unlisted yield_output payloads are hidden from caller-facing events while remaining in executor_completed data. - Empty explicit designation, duplicate entries, overlaps, unknown executors, and designated executors without workflow output annotations fail build validation. Existing orchestration builders pass intermediate-capable participants through intermediate_executors to preserve current intermediate_outputs behavior until participant-oriented designation lands. Files changed - packages/core/agent_framework/_workflows/_workflow.py, _workflow_builder.py, _workflow_context.py, _validation.py, _events.py - packages/core/tests/workflow/test_output_designation.py, test_output_executors_contract.py, test_strict_mode_event_labeling.py, test_validation.py, test_workflow.py, test_workflow_agent_intermediate.py - packages/orchestrations/agent_framework_orchestrations/_sequential.py, _concurrent.py, _group_chat.py, _magentic.py - packages/core/AGENTS.md Verification - uv run pytest packages/core/tests/workflow packages/orchestrations/tests packages/devui/tests/devui/test_mapper.py -q - uv run pytest packages/azurefunctions/tests -q - uv run poe lint - uv run poe typing fails only on pre-existing packages/core/agent_framework/_workflows/_agent.py _AGENT_FORWARDED_EVENT_TYPES private-use pyright error. Notes for next iteration - issues/03-core-workflow-explicit-designation.md was moved to issues/done but issues/ remains untracked and intentionally excluded from this commit. - Slice 4 should tighten workflow.as_agent() mapping for hidden emissions and streaming-only update payloads; Slice 5 should replace orchestration intermediate_outputs with participant-oriented designation. * Tighten workflow-as-agent output mapping Key decisions - Treat AgentResponseUpdate as a streaming-only payload across the workflow.as_agent() adapter, so non-streaming agent runs now reject both terminal output and intermediate workflow events carrying updates. - Keep streaming classification behavior explicit: terminal update payloads remain normal text content, while intermediate update payloads are rewritten to text_reasoning content. - Add explicit-mode coverage proving hidden yield_output emissions do not appear in non-streaming AgentResponse messages or streaming AgentResponseUpdate chunks. Files changed - packages/core/agent_framework/_workflows/_agent.py - packages/core/tests/workflow/test_workflow_agent_intermediate.py Verification - uv run pytest packages/core/tests/workflow/test_workflow_agent_intermediate.py -q - uv run pytest packages/core/tests/workflow/test_workflow_agent.py packages/core/tests/workflow/test_workflow_agent_intermediate.py -q - uv run pytest packages/core/tests/workflow packages/orchestrations/tests packages/devui/tests/devui/test_mapper.py -q - uv run poe lint - uv run poe typing fails only on the pre-existing packages/core/agent_framework/_workflows/_agent.py _AGENT_FORWARDED_EVENT_TYPES private-use pyright error. Blockers or notes for next iteration - issues/04-workflow-as-agent-output-mapping.md was moved to issues/done/ but issues/ remains untracked and intentionally excluded from this commit. - Slice 5 should replace orchestration intermediate_outputs with participant-oriented designation. * Add orchestration participant output designation Key decisions - Replace orchestration intermediate_outputs with participant-oriented output_participants and intermediate_participants across Sequential, Concurrent, GroupChat, Magentic, and Handoff builders. - Keep synthetic final executors terminal by default for Concurrent, GroupChat, and Magentic; keep Sequential's final participant terminal by default; keep Handoff participants terminal by default. - Centralize participant designation validation for empty explicit designation, duplicates, overlaps, and unknown participants, then map validated participants to workflow output/intermediate executors. Files changed - packages/orchestrations/agent_framework_orchestrations/_participant_designation.py - packages/orchestrations/agent_framework_orchestrations/_sequential.py - packages/orchestrations/agent_framework_orchestrations/_concurrent.py - packages/orchestrations/agent_framework_orchestrations/_group_chat.py - packages/orchestrations/agent_framework_orchestrations/_magentic.py - packages/orchestrations/agent_framework_orchestrations/_handoff.py - packages/orchestrations/tests/test_orchestration_intermediate_vs_terminal.py - packages/orchestrations/tests/test_magentic.py Blockers or notes for next iteration - issues/05-orchestration-participant-designation.md was moved to issues/done/ but issues/ remains untracked and intentionally excluded from this commit. - Slice 7 should migrate samples and docs away from intermediate_outputs to the new participant designation API. - uv run poe typing still fails only on the pre-existing packages/core/agent_framework/_workflows/_agent.py _AGENT_FORWARDED_EVENT_TYPES private-use pyright error. * Migrate samples to explicit output designation Key decisions - Replace sample usage of the removed orchestration intermediate_outputs boolean with participant-oriented intermediate_participants designation. - Update raw workflow guidance to show output_executors together with intermediate_executors, and document that unlisted yields are hidden in explicit designation mode. - Keep orchestration final outputs terminal while streaming designated participant responses as intermediate progress, including workflow.as_agent() samples where intermediates map to text_reasoning content. - Refresh workflow and orchestration README guidance plus the changelog reference so public docs no longer point users at intermediate_outputs. Files changed - CHANGELOG.md - packages/orchestrations/README.md - samples/README.md - samples/03-workflows/README.md - samples/03-workflows/control-flow/intermediate_vs_terminal_outputs.py - samples/03-workflows/orchestrations/README.md - samples/03-workflows/orchestrations/group_chat_agent_manager.py - samples/03-workflows/orchestrations/group_chat_philosophical_debate.py - samples/03-workflows/orchestrations/group_chat_simple_selector.py - samples/03-workflows/orchestrations/magentic.py - samples/03-workflows/orchestrations/magentic_human_plan_review.py - samples/03-workflows/orchestrations/sequential_chain_only_agent_responses.py - samples/03-workflows/agents/group_chat_workflow_as_agent.py - samples/03-workflows/agents/magentic_workflow_as_agent.py - samples/03-workflows/agents/sequential_workflow_as_agent.py - samples/semantic-kernel-migration/orchestrations/group_chat.py - samples/semantic-kernel-migration/orchestrations/magentic.py Blockers or notes for next iteration - issues/07-samples-and-docs-explicit-output-designation.md was moved to issues/done/ but issues/ remains untracked and intentionally excluded from this commit. - issues/06-devui-intermediate-event-rendering.md remains present and appears already satisfied by existing DevUI mapper/tests from the prior implementation slice. - PRD-explicit-workflow-output-designation.md remains untracked and intentionally excluded from this commit. * Render DevUI intermediate workflow outputs Key decisions - Preserve workflow output designation metadata on visible DevUI output messages and text deltas so intermediate/data emissions remain distinguishable from terminal output. - Render intermediate workflow message items in the execution timeline using executor metadata, while excluding them from the final workflow result aggregation. - Keep terminal output message rendering unchanged and retain legacy data events on the intermediate compatibility path. Files changed - packages/devui/agent_framework_devui/_mapper.py - packages/devui/frontend/src/components/features/workflow/execution-timeline.tsx - packages/devui/frontend/src/components/features/workflow/workflow-view.tsx - packages/devui/frontend/src/types/openai.ts - packages/devui/tests/devui/test_mapper.py Blockers or notes for next iteration - issues/06-devui-intermediate-event-rendering.md was moved to issues/done/ but issues/ remains untracked and intentionally excluded from this commit. - PRD-explicit-workflow-output-designation.md remains untracked and intentionally excluded from this commit. - uv run poe typing still fails only on the pre-existing packages/core/agent_framework/_workflows/_agent.py _AGENT_FORWARDED_EVENT_TYPES private-use pyright error. * Fix mypy * Clarify orchestration participant output config * Rename participant output kwargs for clarity output_participants -> final_output_from, intermediate_participants -> intermediate_output_from. The old names read like categories of participant; the new names make it clear the kwarg designates which participants' outputs surface as final vs. intermediate events. * Rename core workflow output kwargs with deprecation shim Adds final_output_from / intermediate_output_from as canonical kwargs on Workflow and WorkflowBuilder. Old output_executors / intermediate_executors kwargs continue to work but emit DeprecationWarning via a shared coalesce helper that also rejects supplying both. Wire-format keys in to_dict() stay as output_executors / intermediate_executors so checkpoint compatibility is preserved. Internal call sites in orchestrations and samples updated to the new names so users following sample code learn the canonical vocabulary; legacy callers still work with a one-shot warning. * Suppress pyright reportPrivateUsage on cross-module sentinel import * Update docstrings * Propagate sub-workflow intermediate outputs, fix handoff/sequential intermediate-only designation, and shore up tests, sample, and docstrings around the intermediate output contract. * Add canonical workflow output_from selection Key decisions:\n- Make output_from the canonical workflow-output allow-list and keep output_executors/final_output_from as deprecated compatibility aliases.\n- Treat empty output_from/intermediate_output_from lists as explicit selections and keep validation responsible for empty, duplicate, overlap, and unknown selections.\n- Remove the branch-only public intermediate_executors WorkflowBuilder kwarg while preserving legacy wire keys in to_dict().\n\nFiles changed:\n- packages/core/agent_framework/_workflows/_workflow.py\n- packages/core/agent_framework/_workflows/_workflow_builder.py\n- packages/core/agent_framework/_workflows/_workflow_context.py\n- packages/core/agent_framework/_workflows/_agent.py\n- packages/core/agent_framework/_workflows/_agent_executor.py\n- packages/core/tests/workflow/* output-selection coverage updates\n- packages/core/AGENTS.md\n- issues/done/001-canonical-list-based-output-selection.md\n\nBlockers/notes:\n- Orchestration builders still pass final_output_from internally; follow-up issue 004 should migrate them to output_from.\n- Legacy omitted-selection behavior and explicit all/all_other literals are left for issues 002 and 003. * Add explicit all workflow output selection Key decisions: - Treat output_from='all' as an explicit workflow-output selection sentinel and expand it at build time to executors with declared workflow output types. - Keep omitted output selections in legacy all-output mode with a deprecation warning that names output_from and intermediate_output_from and points to output_from='all'. - Reject intermediate_output_from='all' at construction because the all-output literal is output-only for this issue. Files changed: - packages/core/agent_framework/_workflows/_workflow_builder.py - packages/core/tests/workflow/test_output_executors_contract.py - issues/done/002-explicit-all-output-and-legacy-migration.md Blockers/notes: - all_other intermediate-output selection remains for issue 003. - Workflow-as-agent/orchestration parity remains for issue 004. * Add all-other intermediate output selection Key decisions: - Treat intermediate_output_from='all_other' as an explicit intermediate-output selection sentinel and expand it at build time after the workflow graph is complete. - Expand all_other to output-capable executors not selected by output_from; omitted or empty output_from selects no workflow outputs, while output_from='all' leaves an empty intermediate selection. - Keep output_from='all_other' invalid so all_other remains intermediate-output-only and runtime classification still receives concrete executor-id sets. Files changed: - packages/core/agent_framework/_workflows/_workflow_builder.py - packages/core/tests/workflow/test_output_executors_contract.py - issues/done/003-all-other-intermediate-output-selection.md Blockers/notes: - Workflow-as-agent and orchestration parity remains for issue 004. - Full documentation updates remain for issue 005. * Add orchestration output selection parity Key decisions: - Expose output_from on sequential, concurrent, group chat, handoff, and magentic builders while keeping final_output_from as a deprecated compatibility alias. - Resolve orchestration participant selections through the same explicit rules as workflows: output_from='all', intermediate_output_from='all_other', hidden unselected participant payloads, and overlap/duplicate/unknown/invalid-literal validation. - Continue preserving documented orchestration defaults by always designating each pattern's terminal internal executor where applicable. Files changed: - packages/orchestrations/agent_framework_orchestrations/_participant_output_config.py - packages/orchestrations/agent_framework_orchestrations/_sequential.py - packages/orchestrations/agent_framework_orchestrations/_concurrent.py - packages/orchestrations/agent_framework_orchestrations/_group_chat.py - packages/orchestrations/agent_framework_orchestrations/_handoff.py - packages/orchestrations/agent_framework_orchestrations/_magentic.py - packages/orchestrations/agent_framework_orchestrations/_orchestration_request_info.py - packages/orchestrations/tests/test_orchestration_intermediate_vs_terminal.py - issues/done/004-workflow-as-agent-and-orchestration-parity.md Blockers/notes: - Full documentation and sample migration wording remains for issue 005. - Existing tests that intentionally use final_output_from now emit the new deprecation warning. * Document workflow output selection contract Key decisions: - Use Workflow Output and Intermediate Output as the developer-facing terms for selected caller-facing emissions. - Document output_from and intermediate_output_from as the canonical API, with output_from as an allow-list and unselected payloads hidden unless explicitly selected as intermediate. - Add scenario and invalid-selection tables for workflow and orchestration docs, including legacy omission warnings, output_from='all', intermediate_output_from='all_other', list selections, invalid literals, overlap, duplicates, unknown selections, and empty explicit selections. - Migrate samples away from final_output_from and output_executors except where compatibility aliases are explicitly documented. Files changed: - packages/core/AGENTS.md - packages/orchestrations/README.md - packages/orchestrations/agent_framework_orchestrations/_handoff.py - packages/orchestrations/agent_framework_orchestrations/_sequential.py - samples/03-workflows/README.md - samples/03-workflows/control-flow/intermediate_vs_terminal_outputs.py - samples/03-workflows/human-in-the-loop/agents_with_approval_requests.py - samples/03-workflows/orchestrations/README.md - samples/04-hosting/foundry-hosted-agents/responses/05_workflows/main.py - scripts/sample_validation/create_dynamic_workflow_executor.py - issues/done/005-document-output-selection-contract.md Blockers/notes: - Direct full Ruff on scripts/sample_validation/create_dynamic_workflow_executor.py still reports pre-existing docstring/print/line-length issues outside this docs migration; syntax-focused checks for changed files pass. - No remaining AFK issue files are present under issues/. * Latest updates * Typing fixes * CleanupEvan Mattson ·
2026-05-19 00:15:25 +00:00 -
.NET: Delegate MCP ContentBlock to AIContent conversion to the MCP SDK (#5903)
* Add sample for invoking Foundry Toolbox tools from declarative workflows * Addressed initial PR comments. * Delegate MCP ContentBlock to AIContent conversion to the MCP SDK * Addressed additional properties metadata in the conversion fallback.
Peter Ibekwe ·
2026-05-18 20:39:56 +00:00 -
.NET: Bump Azure.AI.Projects to 2.1.0-beta.2 and add agent-endpoint AsAIAgent path (#5899)
* .NET: Bump Azure.AI.Projects to 2.1.0-beta.2 and add agent-endpoint AsAIAgent path Bumps Azure.AI.Projects to 2.1.0-beta.2 with the matching transitive pins (Azure.Core 1.55.0, System.ClientModel 1.11.0). Foundry agent endpoint plumbing: * FoundryAgent now routes the agent-endpoint constructor through the new GetProjectResponsesClientForAgentEndpoint helper. * Adds an internal FoundryAgent ctor that takes an existing AIProjectClient plus a parsed agent endpoint so the public extension does not need to construct a second project client. * Adds public AIProjectClient.AsAIAgent(Uri agentEndpoint, ...) extension. This is the path consumer samples are expected to use for hosted agents because version selection happens server-side. * Trims the dangling "If you want to construct a FoundryAgent against a project endpoint..." sentence from ParseAgentEndpoint. Unit tests: * Four new tests in AzureAIProjectChatClientExtensionsTests cover the AIProjectClient.AsAIAgent(Uri agentEndpoint, ...) overload. 263/263 pass. Consumer samples (Using-Samples): * SimpleAgent and SessionFilesClient now read AZURE_AI_PROJECT_ENDPOINT and AZURE_AI_AGENT_NAME (both required, throw on missing), derive the agent endpoint with new Uri($"{projectEndpoint}/agents/{agentName}/endpoint/protocols/openai"), then call aiProjectClient.AsAIAgent(agentEndpoint, ...). * SessionFilesClient README updated. Contributor samples (responses/*): * New HostedContributorRouteExtensions.MapDevTemporaryLocalAgentEndpoint() wildcard route extension so localhost contributor servers accept the per-agent OpenAI endpoint shape the production Hosted runtime exposes. * All 11 contributor Program.cs files call MapDevTemporaryLocalAgentEndpoint() with a contributor-only warning comment. * Hosted-Files and Hosted-AzureSearchRag were importing Hosted_Shared_Contributor_Setup but never calling AddDevTemporaryLocalContributorSetup(). Both now call it so HostedSessionIsolationKeyProvider resolves correctly in dev. * Hosted-AzureSearchRag, Hosted-Files, Hosted-MemoryAgent csprojs drop stale VersionOverride="2.1.0-beta.1" pins. * Hosted-AzureSearchRag and Hosted-Files csprojs add ProjectReference to Hosted_Shared_Contributor_Setup. * Hosted-Observability/.dockerignore removed the out/ exclusion that was blocking COPY out/ . in Dockerfile.contributor. Verified: * Full solution-scoped build of changed projects: green. * Scoped CI-parity dotnet format via WSL2 + Docker (mcr.microsoft.com/dotnet/sdk:10.0) over every changed csproj: clean. * Foundry unit tests: 263/263. * Contributor docker smoke for 8 hosted samples (publish + docker build + docker run + curl POST to the wildcard route): HTTP 200 / 500 with route matched. * End-to-end smoke against the real Azure Foundry project with a fresh bearer token: Hosted-Files contributor container served HTTP 200, the agent invoked ListBundledFiles, and returned the expected file name. * Address PR review: forward pipeline settings; add UTs - CreateProjectClientOptions also carries RetryPolicy, NetworkTimeout, ClientLoggingOptions, MessageLoggingPolicy (was Transport+UserAgentApplicationId only). - Make CreateProjectClientOptions internal so tests can verify the copy directly. - Add AsAIAgent(Uri) UTs covering tools forwarding to inner ChatOptions and null tools handling. - Add CreateProjectClientOptions UTs covering null caller and full pipeline-settings copy.Roger Barreto ·
2026-05-18 20:20:56 +00:00 -
.NET: Add ability to export/import sessions in harness console (#5920)
* Add ability to export/import sessions in harness console * Address PR comments
westey ·
2026-05-18 18:44:50 +00:00 -
.NET: Add otel file logging and switch samples to projects client with store=true (#5924)
* Add otel file logging and switch samples to projects client with store=true * Fix formatting and remove rogue file
westey ·
2026-05-18 17:39:29 +00:00 -
.NET: Require TODO finish reason and rename SubAgents to BackgroundAgents (#5902)
* Require TODO finish reason and rename SubAgents to BackgroundAgents * Address PR comments
westey ·
2026-05-18 15:37:25 +00:00 -
.NET: Adding default providers and tools to HarnessAgent (#5896)
* Adding default providers and tools to HarnessAgent * Address PR comments * Add further comments to clarify certain setings. * Apply suggestion from @SergeyMenshykh Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com> --------- Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>
westey ·
2026-05-18 10:07:16 +00:00 -
.NET: fix: avoid AGUI tool result message id collisions (#5800)
* fix: avoid AGUI tool result message id collisions * fix: split mixed tool result message ids
Yufeng He ·
2026-05-15 21:52:25 +00:00 -
Python: New Foundry Hosted Agents samples: RAG, Skills, and Memory (#5822)
* WIP: Add rag sample; need deployment testing * Rag sample ready * Add Foundry Skills sample * WIP: Foundry memory * Done: Foundry Memory * Address Copilot comments * Fix README * Restore uv.loack
Tao Chen ·
2026-05-15 17:31:57 +00:00 -
.NET: Add observer for OpenAIWebSearch (#5894)
* Add observer for OpenAIWebSearch * Update reference in comment * Use types where possible.
westey ·
2026-05-15 17:30:01 +00:00 -
.NET: Fix bug in store-false helper to ensure addition rather than replacement (#5895)
* Fix bug in store-false helper to ensure addition rather than replacement * Address PR comments
westey ·
2026-05-15 15:51:45 +00:00 -
Python: Fix GitHubCopilotAgent to include tools added by ContextProvider.before_run in session creation (#5780)
* Fix GitHubCopilotAgent ignoring tools from context providers (#5736) _create_session and _resume_session only forwarded self._tools (constructor tools) to CopilotClient.create_session, dropping any tools contributed by context providers via session_context.extend_tools() during before_run. Merge provider-contributed tools into runtime_options in both _run_impl and _stream_updates before session creation, mirroring how RawAgent handles the merge at lines 1435-1440 in _agents.py. Update _create_session and _resume_session to combine self._tools with the merged runtime tools. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Fix GitHubCopilotAgent to include tools added by ContextProvider.before_run in session creation Fixes #5736 * Fix provider tool merge to avoid mutating caller's list - Replace in-place .extend() with fresh list creation in both _run_impl and _stream_updates paths to prevent mutating the caller-provided options['tools'] list (shallow copy issue) - Also handles immutable Sequence types (e.g. tuple) correctly - Add test for provider tools forwarded via _resume_session path Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5736: review comment fixes --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-05-15 14:59:22 +00:00 -
add AgentSession StateBag edge case coverage (#5838)
Co-authored-by: Challa Ravindranath <chravin@microsoft.com>
Challa Ravi ·
2026-05-15 11:02:37 +00:00 -
Python: Parse YAML block scalars in SKILL.md frontmatter (#5863)
The frontmatter parser previously matched only single-line `key: value` pairs, so block scalar indicators (`|` literal, `>` folded, with chomping `-`/`+`) were silently truncated to the indicator character. Multi-line descriptions like `description: >\n ...` lost their content. Add `_parse_yaml_scalar_value()` which detects block scalar indicators, collects indented continuation lines, strips the common leading indentation, joins per scalar style (newlines for `|`, spaces for `>`), and applies chomping per the YAML 1.2 spec. Update `_extract_frontmatter()` to use the helper for unquoted values. Adds 15 unit tests covering literal/folded styles, all chomping variants, indentation handling, content containing colons, non-description fields, tab indentation, blank-line preservation, and a regression test for plain values. Fixes #5713. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SergeyMenshykh ·
2026-05-15 09:47:00 +00:00 -
.NET: Add Hosted-MemoryAgent sample with isolation key plumbing (#5692) (#5702)
* .NET: Add Hosted-MemoryAgent sample with isolation key plumbing (#5692) Adds HostedSessionContext + HostedSessionIsolationKeyProvider in Microsoft.Agents.AI.Foundry.Hosting so AIContextProviders (notably FoundryMemoryProvider) can scope per user via the platform's x-agent-user-isolation-key / x-agent-chat-isolation-key headers. - New types: HostedSessionContext (sealed), HostedSessionContextExtensions (public Get, internal Set), abstract HostedSessionIsolationKeyProvider (async), internal PlatformHostedSessionIsolationKeyProvider mapping ResponseContext.Isolation. - AgentFrameworkResponseHandler now resolves the provider, tags fresh sessions, and validates resumed sessions against the live request (strict 403 'Hosted session identity context mismatch' on any mismatch; 500 on null keys). - New shared sample project Hosted_Shared_Contributor_Setup hosts DevTemporaryTokenCredential and DevTemporaryLocalSessionIsolationKeyProvider plus AddDevTemporaryLocalContributorSetup. All 9 existing responses samples migrated to consume it so local runs keep working under the strict isolation contract. - New Hosted-MemoryAgent sample: travel assistant wired through FoundryMemoryProvider with stateInitializer reading session.GetHostedContext().UserId. Includes Dockerfile, smoke.ps1, agent.yaml/manifest. - New IT scenario 'memory' in Foundry.Hosting.IntegrationTests + MemoryHostedAgentFixture + MemoryHostedAgentTests. Verified end to end against the tao Foundry project. - ADR 0026 captures the design tree. * Address PR review feedback - Dockerfile: add header noting it targets NuGet builds; contributors must use Dockerfile.contributor for ProjectReference source builds. - PlatformHostedSessionIsolationKeyProvider: doc said 'returns context with empty values'; corrected to 'returns null' which the handler treats as 500. - FakeHostedSessionIsolationKeyProvider: doc clarifies that null configurations are allowed for testing the handler error path. - HostedSessionContextExtensions.SetHostedContext: enforce write-once with InvalidOperationException; doc + xml exception updated. - AgentFrameworkResponseHandler: cache PlatformHostedSessionIsolationKeyProvider as static readonly to avoid per-request allocation. - MemoryHostedAgentTests: tighten waits from 20s to 5s (FoundryMemoryProvider defaults UpdateDelay=0; ingestion ~3s). - Sample Program.cs imports reordered to satisfy IDE0005. * Add HostedFoundryMemoryProviderScopes built-in helpers (#5692) Addresses review feedback from @lokitoth on Hosted-MemoryAgent/Program.cs:54. - New HostedFoundryMemoryProviderScopes static class with PerUser, PerChat, PerUserAndChat factories returning Func<AgentSession?, FoundryMemoryProvider.State>. - All helpers throw InvalidOperationException when GetHostedContext() is null, with a message pointing at writing a custom stateInitializer for non-hosted scenarios. - New HostedFoundryMemoryScope enum and AddHostedFoundryMemoryProvider DI extension (two overloads: explicit AIProjectClient and DI-resolved). Singleton lifetime. Default scope = PerUser. - Hosted-MemoryAgent sample and the memory IT scenario container both swap their inline lambdas for HostedFoundryMemoryProviderScopes.PerUser(). - 14 new unit tests (241/241 hosting unit tests pass). * Replace HostedFoundryMemoryScope enum with Func<...> parameter (#5692) Address PR review feedback from @westey-m: enums are a breaking-change hazard when extended, and the enum was redundant with the existing HostedFoundryMemoryProviderScopes static class. - Delete HostedFoundryMemoryScope.cs. - AddHostedFoundryMemoryProvider DI extensions now take Func<AgentSession?, FoundryMemoryProvider.State>? stateInitializer = null. When null, default to HostedFoundryMemoryProviderScopes.PerUser(). - Callers pick a built-in helper (PerUser/PerChat/PerUserAndChat) or pass a custom delegate. New built-ins are a single static method addition with zero impact on existing callers. - Tests updated; 244/244 hosting unit tests pass. * Fix isolation context resume for externally-created conversations (#5692) Branch on the session's existing hosted-context (not on conversation_id presence) so a conversation provisioned externally (e.g. via conversations.CreateProjectConversationAsync) is treated as fresh on first hosted-agent request and stamped, rather than rejected with 403 hosted_session_identity_mismatch. Strict equality is preserved on real resume of an already-stamped session. Also tighten dotnet/global.json to version 10.0.204 + rollForward latestPatch so local builds match the CI Docker image SDK and avoid 10.0.300 dotnet format stripping required usings. * Revert global.json SDK pin to upstream (#5692) The 10.0.204 + latestPatch pin from the previous commit broke the dotnet-format CI job (hostfxr_resolve_sdk2 could not find a compatible SDK in the mcr.microsoft.com/dotnet/sdk:10.0 image). Restore upstream 10.0.200 + minor; local Release builds with SDK 10.0.300 should set GITHUB_ACTIONS=true to bypass the auto-format-on-build target.
Roger Barreto ·
2026-05-15 05:42:12 +00:00 -
Evan Mattson ·
2026-05-15 10:49:46 +09:00 -
Python: bump package versions for 1.4.0 release (#5872)
* fixes * fixes * Python: bump package versions for 1.4.0 release Cuts the python-1.4.0 release. MINOR bump on the released cohort (agent-framework, agent-framework-core, agent-framework-openai, agent-framework-foundry: 1.3.0 -> 1.4.0), driven by breaking changes in experimental skills API and new features. All 21 beta packages stamp 1.0.0b260514, all 3 alpha packages stamp 1.0.0a260514, and ag-ui remains at 1.0.0rc1 (freshly promoted). Date stamp reflects 2026-05-14 Pacific. - Released cohort: 1.3.0 -> 1.4.0 - Beta packages (21): 1.0.0b260507 -> 1.0.0b260514 - Alpha packages (3): 1.0.0a260507 -> 1.0.0a260514 - ag-ui: stays at 1.0.0rc1 (dep bound updated only) - Inter-package dependency lower bounds updated (>=1.3.0 -> >=1.4.0) - Fix chatkit StructuredInputItem exhaustiveness for openai-chatkit 1.6.4 - Update CHANGELOG compare links - uv.lock refreshed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-05-15 09:31:03 +09:00 -
Python: Fix A2A v1.0 non-streaming response and sample runtime issues (#5849)
- Fix non-streaming empty response by accumulating intermediate WORKING status updates and flushing them when an empty terminal event arrives - Fix sample agent_executor.py to enqueue Task before status events (required by v1.0 ActiveTask validation) - Fix create_jsonrpc_routes() calls to include required rpc_url param - Fix TYPE_CHECKING imports in sample agent_definitions.py - Add tests for non-streaming content accumulation behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-05-14 22:28:02 +00:00