mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
d08cec5379f2b0cb03e2854890ce5dc4d322fc55
497 Commits
-
Tao Chen ·
2026-06-15 09:40:21 -07:00 -
Tao Chen ·
2026-06-11 16:54:42 -07:00 -
Tao Chen ·
2026-06-11 15:28:27 -07:00 -
Tao Chen ·
2026-06-11 15:27:36 -07:00 -
Python: Integrate shell tool into harness agent (#6451)
* Integrate shell tool into AgentHarness * Validate shell_executor exposes as_function() with a clear TypeError Addresses PR review feedback: a public factory should fail fast with an actionable error rather than a cryptic AttributeError when an incompatible shell_executor is supplied. Validation happens upfront, regardless of whether the client supports shell tools. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Type shell harness params via TYPE_CHECKING import Addresses PR review feedback: type shell_executor and shell_environment_provider_options instead of Any, using a TYPE_CHECKING import from agent_framework_tools.shell. The import never executes at runtime, so there is no circular dependency, and the lazy runtime import of ShellEnvironmentProvider is retained. Since ShellExecutor is a protocol without as_function(), the validated getattr result is invoked directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
westey ·
2026-06-11 20:51:59 +00:00 -
Tao Chen ·
2026-06-11 11:43:41 -07:00 -
Tao Chen ·
2026-06-11 11:14:36 -07:00 -
Python: Add tool approval middleware (#6414)
* Add Python tool approval middleware Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix tool approval restored state handling Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Gate hidden approvals on explicit approval responses Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Handle string inputs in approval replay scan Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Cover argument-scoped approval rules Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Refine tool approval state and budgets Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix tool approval PR CI failures Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert DevUI Aspire README link change Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-06-11 17:35:44 +00:00 -
Python: [Generated by SRE Agent] Fix MCP allowed_tools empty list handling (#6296)
* Fix MCP allowed_tools empty list handling When allowed_tools is set to an empty list [], the falsy check 'if not self.allowed_tools' incorrectly treats it as unconfigured (same as None), causing all tools to be exposed. Change to an explicit 'is None' check so that an empty list correctly results in no tools being allowed. Co-authored-by: Azure SRE Agent <noreply@microsoft.com> * Clarify allowed_tools docstring: None vs [] semantics Per Eduard's review on PR #6296: explicitly document that None exposes all tools and [] exposes none, across all four MCPTool / MCPStdioTool / MCPStreamableHTTPTool / MCPWebsocketTool docstrings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * allowed_tools docstring: recommend load_tools=False for full disable Per Eduard's follow-up on PR #6296: `load_tools=False` is the cleaner idiom when you don't want to expose any tools. Reframe `allowed_tools=[]` in the docstring as a runtime guard / inspection-only path and cross-reference `load_tools`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Azure SRE Agent <noreply@microsoft.com> Co-authored-by: Giles Odigwe <79032838+giles17@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
chetantoshniwal ·
2026-06-11 06:46:46 +00:00 -
Tao Chen ·
2026-06-10 22:20:10 -07:00 -
Tao Chen ·
2026-06-10 16:36:15 -07:00 -
Python: HarnessAgent: Disable compaction when max tokens not provided (#6410)
* HarnessAgent: Disable compaction when max tokens not provided * Fix regression. * Address PR comments * Require max_output_tokens to be positive Reject max_output_tokens=0 (must be positive), mirroring max_context_window_tokens. Addresses PR review feedback. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
westey ·
2026-06-10 13:57:23 +00:00 -
Python: Parse MCP CallToolResult.structuredContent field to prevent tool results returning None (#6421)
* Parse structuredContent from MCP CallToolResult (#3313) The _parse_tool_result_from_mcp method only iterated over the content field from CallToolResult, ignoring the structuredContent field entirely. MCP servers that return JSON data via structuredContent (e.g., Power BI MCP) appeared to return None. Add handling for structuredContent: when present, serialize it as JSON text and append it to the result list. This preserves the data for the LLM while maintaining backward compatibility with existing behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Parse MCP CallToolResult.structuredContent field to prevent tool results returning None Fixes #3313 * Address review feedback: add default=str to json.dumps and remove .checkpoints/ - Add default=str to json.dumps for structuredContent serialization so non-JSON-serializable values (e.g. bytes) degrade gracefully instead of raising TypeError - Remove all .checkpoints/ runtime artifacts from the repository - Add **/.checkpoints/ to .gitignore to prevent future accidental commits - Add test for non-serializable structuredContent values Fixes #3313 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #3313: Python: MCP CallToolResult.structuredContent field is not parsed, causing tool results to return None --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-06-10 12:51:09 +00:00 -
Python: [BREAKING] Add sampling guardrails to MCP tools (#6413)
* Add sampling guardrails to MCP tools Add approval, token, and request-count controls to the MCP sampling callback used when an MCPTool is configured with a chat client. - Add `sampling_approval_callback`, `sampling_max_tokens`, and `sampling_max_requests` parameters to `MCPTool` and its `MCPStdioTool`, `MCPStreamableHTTPTool`, and `MCPWebsocketTool` subclasses, positioned directly after `client`. - Gate each server-initiated `sampling/createMessage` request behind the approval callback, which denies by default when no callback is provided. - Clamp the requested `maxTokens` to `sampling_max_tokens` and enforce a per-session request count via `sampling_max_requests`. - Log incoming sampling requests at WARNING level (counts only). - Export `SamplingApprovalCallback` from the public API. - Add tests, a sample, and documentation updates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Make sampling denial message context-aware Distinguish the deny-by-default case (no approval callback configured) from an explicit denial by a configured `sampling_approval_callback`, so the returned ErrorData message is accurate for callback-driven denials and exceptions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-06-10 10:17:36 +00:00 -
Python: bump package versions for 1.8.1 release (#6420)
* Python: bump package versions for 1.8.1 release * Python: bump agent-framework-foundry-hosting for 1.8.1 release * Python: bump ag-ui and azurefunctions for 1.8.1 release * Remove incorrect agent-framework-foundry changelog entry for #6259 * Add [1.8.1] changelog compare link and update [Unreleased] base --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Copilot ·
2026-06-09 21:27:42 +00:00 -
Tao Chen ·
2026-06-09 11:02:17 -07:00 -
Python: [Generated by SRE Agent] docs: clarify checkpoint storage security model and deserialization trust boundaries (#6295)
* docs: clarify checkpoint storage security model and deserialization trust boundaries Add Security Model documentation sections to the checkpoint encoding and Azure Functions serialization modules explaining: - Checkpoint storage is a trusted data source requiring access controls - The RestrictedUnpickler allowlist is defense-in-depth, not a security boundary - Developer responsibilities for securing storage backends - Guidance on using allowed_types and strip_pickle_markers Co-authored-by: Azure SRE Agent <noreply@microsoft.com> * Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Azure SRE Agent <noreply@microsoft.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
chetantoshniwal ·
2026-06-09 16:53:48 +00:00 -
Tao Chen ·
2026-06-09 09:38:45 -07:00 -
Tao Chen ·
2026-06-09 09:27:21 -07:00 -
Python: Filter MCP tool kwargs to declared params via allowlist (#6399)
* Filter MCP tool kwargs to declared params via allowlist Previously MCPTool combined framework runtime kwargs (from FunctionInvocationContext.kwargs) with the LLM-supplied arguments and stripped only a hardcoded denylist of known framework keys before forwarding to the MCP server. Any new framework-injected kwarg leaked to the server unless the denylist was updated. Switch to an allowlist built from each tool's declared parameters (inputSchema.properties). Only declared params are forwarded; everything else is stripped. Add an `additional_tool_argument_names` constructor argument so users can opt extra names back in, globally (Sequence[str]) and/or per remote tool name (Mapping with reserved "*" global key). The existing denylist is kept as a safety net for framework-named params a server declares in its schema; explicitly opted-in extras always win. The reserved _meta handling is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address MCP allowlist review comments and fix reload arg loss - Fix pyright reportUnknownArgumentType in _load_tools (cast schema properties). - Register declared param names before the existing-tool skip guard so that tool-list reloads preserve the allowlist for already-loaded tools (previously unchanged tools silently dropped all declared args after a background reload). - Handle bare-string values in an additional_tool_argument_names mapping instead of iterating their characters. - Clarify the framework denylist comment: explicit extras override the denylist. - Make the extras-override-denylist test unambiguous (opt in a denylisted name). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-06-09 07:37:11 +00:00 -
Python: Fix per-service-call history persistence with server-storing clients (#6310)
* Fix per-service-call history persistence with server-storing clients When an Agent set require_per_service_call_history_persistence=True together with a HistoryProvider, and the chat client stored history server-side by default (e.g. OpenAIChatClient, STORES_BY_DEFAULT=True), the external history provider was silently never persisted. Unify persistence on the per-service-call middleware: when the flag is set and a HistoryProvider exists, the middleware is always installed and owns persistence. service_stores_history now only selects middleware behavior: - service does not store: load providers and drive the function loop with a local sentinel conversation id, or - service stores: skip loading (the service owns history) and persist each service call while the real conversation id flows through. Also rationalize chat-options handling in _prepare_run_context: - _merge_options now skips None overrides and strips remaining None values, so an unset `store` is never forwarded and the service decides its own default. - Resolve `store` and `conversation_id` once from a single combined view (effective_options) instead of probing both default and runtime dicts; the auto-injection and per-service-call resolution now agree on conversation_id. Fixes #5798 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Correct as_agent() docstring: persistence is per service call, not once per run Address PR review: when the client stores history server-side, the per-service-call middleware still persists after each model call; only provider loading is skipped. The previous "persist once per run()" wording contradicted the implementation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review: docs, missing-conversation-id warning, and tests - Clarify that require_per_service_call_history_persistence is a no-op when no HistoryProvider is present (docstrings in _agents.py and _clients.py). - Warn on every service call when the client stores history server-side but returns no conversation_id, so the (uncommon) loss of cross-turn resumability cannot fail silently. - Add tests: storing client + existing conversation_id does not raise and the id propagates; two runs on the same session keep persisting with a stable service_session_id and no provider loading; storing-without-conversation-id warns per call. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-06-09 05:47:57 +00:00 -
Tao Chen ·
2026-06-08 16:30:59 -07:00 -
Tao Chen ·
2026-06-08 13:42:42 -07:00 -
Tao Chen ·
2026-06-05 16:29:19 -07:00 -
Python: feat(python): Add MCP client OTel spans per GenAI semantic conventions (#6349)
* feat(python): Add MCP client OTel spans per GenAI semantic conventions Implement MCP client spans per the OTel GenAI Semantic Conventions for MCP (https://opentelemetry.io/docs/specs/semconv/gen-ai/mcp/#client). Operations instrumented: - initialize: CLIENT span capturing MCP session setup - tools/list: CLIENT span for tool listing (per-page) - prompts/list: CLIENT span for prompt listing (per-page) - tools/call: CLIENT span (nested under execute_tool when called via FunctionTool) - prompts/get: CLIENT span Span attributes follow the MCP semantic conventions: - Required: mcp.method.name - Conditional: error.type, gen_ai.tool.name, gen_ai.prompt.name - Recommended: gen_ai.operation.name, mcp.protocol.version, mcp.session.id, network.transport, server.address, server.port Transport-specific attributes per subclass: - MCPStdioTool: network.transport=pipe - MCPStreamableHTTPTool: network.transport=tcp, network.protocol.name=http - MCPWebsocketTool: network.transport=tcp, network.protocol.name=websocket All span creation gated behind OBSERVABILITY_SETTINGS.ENABLED. Closes #3624 Closes #4697 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: simplify MCP spans — remove enrichment logic and protocol version caching - Always create nested CLIENT spans for tools/call instead of enriching the parent execute_tool span - Remove _ACTIVE_TOOL_EXECUTION_SPAN contextvar (no longer needed) - Remove enrich_span_with_mcp_attributes() helper - Remove _otel_error_type preservation in FunctionTool.invoke() - Remove _mcp_protocol_version instance variable; protocol version is only set on the initialize span where it is available Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Refine copilot solution * fix: enable automatic exception recording on MCP spans Remove record_exception=False and set_status_on_exception=False from create_mcp_client_span. Let OTel handle exception recording and status setting automatically. The manual set_mcp_span_error calls for tools/call still correctly set error.type (which OTel's automatic handling doesn't touch), so tool_error is preserved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Reduce number of lines * Add comment to sample * test: address PR review comments on MCP observability tests - Fix initialize test to call mocked session.initialize() and read protocolVersion from the result instead of hardcoding it - Add tools/call McpError error-path test - Add prompts/get McpError error-path test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix export error --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tao Chen ·
2026-06-05 19:23:01 +00:00 -
Python: Refactor workflow as agent pending request handling (#6259)
* WIP: Refactor Workflow as agent pending request handling * WIP: debugging empty message bug * Working: Workflow as agent with function approval * Address Copilot comments * Fix mypy * Address comments and fix pipeline * Request info non function approval now becomes function call * Revert uv.lock * Fix mypy * Bump min version of azure-ai-project * Remove RequestInfoFunctionArgs * fix tests * Fix failing tests * Fix sample
Tao Chen ·
2026-06-05 17:23:19 +00:00 -
Python: MCP long-running task support in Python (#6319)
* MCP long-running task support in Python * Fix pyupgrade and AGENTS.md reconnect description - pyupgrade: drop forward-reference string annotations in _mcp.py (Python 3.10+ resolves them natively now that MCPTaskOptions is defined before use). - AGENTS.md: align reconnect description with current behavior. Phase 1 (initial tools/call) does NOT retry on connection loss; raises 'connection lost; task state unknown' instead, so a server that accepted the request but lost the response cannot start the operation twice. Phase 2 (tasks/get / tasks/result) still reconnects once against the same task_id. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix bandit nosec marker for CI pipeline * Address PR feedbacks * Clarifiied comments and addressed more PR feedbacks. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Peter Ibekwe ·
2026-06-05 00:04:55 +00:00 -
Python: bump package versions for 1.8.0 release (#6351)
- Released cohort (core, openai, foundry, root): 1.7.0 -> 1.8.0 - agent-framework-github-copilot: promote to RC (1.0.0rc1) - agent-framework-orchestrations: rc2 -> rc3 (bug fix) - Beta/alpha packages with changes: a2a, anthropic, azurefunctions, bedrock, foundry-hosting, mistral bumped to new date stamp (260604) - Inter-package dependency bounds updated for changed packages - CHANGELOG.md and PACKAGE_STATUS.md updated Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-06-04 23:03:24 +00:00 -
Python: Fix compaction message-id collisions and tool-loop summary persistence (#6299)
* Fix compaction message-id collisions and tool-loop summary persistence Fixes two bugs in the compaction strategies: - #5237: incremental group annotation assigned message ids by position within the re-annotated slice, so moving the re-annotation start back to a previous group start restarted ids at 0 and produced collisions (e.g. a user message reusing an assistant message's id), merging groups and causing tool-result compaction to wrongly exclude messages. group_messages/_ensure_message_ids now take an id_offset and guard against existing-id collisions; annotate_message_groups threads the slice start index through as the offset. - #4991: the function-invocation loop copied the message list each iteration, so summaries inserted by compaction landed in a throwaway copy and were lost across tool-loop iterations (only the persistent excluded flags survived). _prepare_messages_for_model_call now compacts the list in place when messages is a list, so inserted summaries persist. Adds regression tests (incremental id uniqueness, existing-id collision avoidance, idempotency, and tool-loop summary persistence including streaming and conversation-id modes). Also adds a summarization.py sample demonstrating SummarizationStrategy directly with a real client, and reworks advanced.py with tool-call groups and a real summarizer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Guard incremental message-id assignment against prefix-id collisions Addresses PR review on #5237: _ensure_message_ids only guarded against collisions within the re-annotated slice. A preexisting (e.g. user-supplied) id in the preserved prefix could still be reassigned in the suffix when the id was numerically out of position, merging groups across the re-annotation boundary again. group_messages/_ensure_message_ids now accept reserved_ids, and annotate_message_groups passes the preserved prefix's ids so auto-assigned suffix ids never collide across the full list. Adds a regression test reproducing the out-of-position prefix-id collision. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-06-04 08:37:59 +00:00 -
Python: run sync tools off the event loop (#5773)
* fix: run sync tools off event loop * chore: silence harness tool marker type check
Yufeng He ·
2026-06-04 04:42:08 +00:00 -
Python: Add MCP-based skills discovery (McpSkillsSource) (#6169)
* Add MCP-based skills discovery (McpSkill, McpSkillsSource, McpSkillResource) Implement Agent Skills discovery over MCP following the SEP-2640 convention: - McpSkillsSource: reads skill://index.json to discover skills served by an MCP server - McpSkill: lazily fetches SKILL.md content via resources/read on demand - McpSkillResource: wraps MCP resource results (text and binary) - Path traversal protection in get_resource for defense in depth - Samples for Foundry Toolbox and standalone MCP skills server - Comprehensive unit tests (514 lines) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review comments: rename to MCP* convention, fix error handling and samples - Rename McpSkill/McpSkillResource/McpSkillsSource to MCPSkill/MCPSkillResource/MCPSkillsSource - Add data-URI prefix stripping for blob resource decoding - Let non-McpError exceptions propagate from get_resource() - Fix contradictory test comment - Use interactive input() in mcp_based_skill sample - Remove misleading sample output block Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Restore debug logging for McpError in get_resource() Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use AzureCliCredential in Foundry toolbox skills sample for consistency Replace DefaultAzureCredential with AzureCliCredential to match the credential convention used in all other samples. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use MCPStreamableHTTPTool in MCP skills sample Replace raw mcp library imports (ClientSession, streamable_http_client) with the framework's MCPStreamableHTTPTool to keep MCP server connections consistent regardless of whether skills are enabled. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Branch on McpError.error.code so only not-found errors return empty Previously _try_read_index() and get_resource() swallowed every McpError as 'no skills available', making auth failures, server crashes, and connection drops indistinguishable from a server that simply has no skills. Now only two codes are treated as not-found: - -32002 (MCP-spec Resource not found) - -32601 (METHOD_NOT_FOUND — server lacks resources/read) All other McpError codes and non-McpError exceptions propagate with a warning log, surfacing real failures visibly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add tests for non-McpError and non-not-found error propagation in MCP skills Cover the re-raise branch in MCPSkill.get_resource for plain ConnectionError/TimeoutError, the generic McpError (code 0) propagation on get_resource, and TimeoutError propagation in _try_read_index. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert "Use MCPStreamableHTTPTool in MCP skills sample" This reverts commit
f31ed0ded9. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Introduce MCP_SKILLS experimental feature for MCP skill classes Add a separate MCP_SKILLS feature ID to ExperimentalFeature enum and use it for MCPSkillResource, MCPSkill, and MCPSkillsSource, since their promotion timeline is partly outside of our control. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>semenshi-m ·
2026-06-03 18:09:50 +00:00 -
Python: progressive tool exposure via FunctionInvocationContext (#6233)
* Python: progressive tool exposure via FunctionInvocationContext Add first-class progressive tool exposure to the Python core function-calling loop. Tools can now add or remove real FunctionTool schemas at runtime via the injected FunctionInvocationContext, taking effect on the next iteration of the loop. - FunctionInvocationContext gains a live `tools` list plus experimental `add_tools()` / `remove_tools()` helpers (feature: PROGRESSIVE_TOOLS). - The function-calling loop establishes a run-local, normalized tools list and threads it into the context at both invocation paths so mutations propagate. - Add a sample (dynamic_tool_exposure.py) and a tools samples README, including a note that CodeAct providers (Monty/Hyperlight) use their own provider-level tool management instead. Supersedes #3877. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Validate non-negative input in dynamic_tool_exposure sample tools Address review feedback: factorial and fibonacci now return an error message for negative n instead of producing incorrect results. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Make add_tools atomic and surface swallowed function errors Address review feedback on progressive tool exposure: - add_tools now validates the full batch against a throwaway copy before committing, so a duplicate-name clash partway through a sequence leaves the live tool list unchanged (all-or-nothing). - _auto_invoke_function now logs a warning (with traceback) when a tool raises, so contract errors such as a duplicate-name ValueError from add_tools are debuggable without enabling include_detailed_errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Avoid retaining tracebacks when logging swallowed function errors Logging with exc_info=exc fed the exception traceback to the logging machinery, whose frame references created reference cycles collected lazily by the cyclic GC. On Windows that could drop a hyperlight WasmSandbox on a non-owning thread ("unsendable, dropped on another thread"), crashing the xdist worker. Log a pre-formatted message with the exception repr instead, so no traceback object is retained. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * added missing decorator --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-06-03 09:01:07 +00:00 -
Python: Promote agent-framework-declarative package to RC (#6256)
* Promote agent-framework-declarative package to RC * Update missed package status file.
Peter Ibekwe ·
2026-06-02 19:30:05 +00:00 -
Python: Fix OTLP HTTP base-endpoint losing /v1/{signal} auto-append (#5913)
* Python: Fix OTLP HTTP base-endpoint losing /v1/{signal} auto-append Per the OTel spec, OTEL_EXPORTER_OTLP_ENDPOINT is a *base* URL for HTTP — the SDK auto-appends /v1/traces, /v1/metrics, /v1/logs when it reads the env var directly. Signal-specific endpoint env vars are *full* URLs used verbatim. _get_exporters_from_env read the base endpoint and forwarded it as the constructor ``endpoint=`` argument, which the SDK always treats as a full signal URL. As a result, with OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 and HTTP protocol, the exporter sent to http://localhost:4318 instead of http://localhost:4318/v1/traces (and likewise for metrics/logs). Replicate the spec's auto-append here when falling back to the base endpoint under HTTP. gRPC behavior is unchanged. * Python: Fix mypy type errors in OTLP endpoint assignment Pre-declare traces_endpoint, metrics_endpoint, logs_endpoint as str | None before the if/else block. Mypy inferred str from the if-branch f-string assignments and then rejected the str | None expressions in the else-branch as incompatible.Dineshsuriya D ·
2026-06-02 09:59:50 +00:00 -
Python: feat(evals): Foundry Adaptive Evals integration (rubric-generation) (#6101)
* Python: feat(evals): RubricScore type + EvalScoreResult.dimensions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: feat(foundry-evals): RubricDimension + GeneratedEvaluatorRef + accept in evaluators= Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: feat(evals): parse rubric_scores from output items + assertion helpers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: feat(evals): BaseAgent.as_eval_source / Workflow.as_eval_source Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: feat(foundry-evals): EvalGenerationSource + generate_rubric helper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: feat(foundry-evals): YAML config loader + sample Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix(evals): address PR review feedback Addresses 4 Copilot review comments on PR #6101: 1. assert_dimension_score_at_least: drop the (not evaluator or found_any) guard so require_applicable=True correctly raises when the named evaluator produces no entries for the dimension. Adds TestRubricAssertions covering the regression. 2. GeneratedEvaluatorRef docstring: reword to describe actual behaviour (pinning recommended, not required) so it matches the dataclass default and FoundryEvals warning path. 3. _poll_generation_job: switch from asyncio.get_event_loop() to get_running_loop() and bound the per-iteration sleep by remaining time, matching _poll_eval_run. 4. generate_rubric: type category as Literal['quality','safety'] and validate at the entry point with a ValueError; drop the silent 'invalid -> quality' rewrite in _generation_job_to_ref. Adds a regression test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: feat(foundry-evals): hosted-agent-aware rubric generation * Auto-detect hosted Foundry agents in agent_as_eval_source: when the agent's chat_client exposes a string agent_name (the convention used by RawFoundryAgentChatClient for PromptAgents/HostedAgents), emit a type='agent' EvalGenerationSource so the service fetches instructions and tools from the agent registry instead of relying on the local wrapper (which holds neither for hosted agents). * Add hosted_agent_version kwarg and a new agent_version field on EvalGenerationSource so PromptAgent runs can pin to a specific hosted version for reproducible rubric generation. * Add force_prompt_source escape hatch to bypass auto-detection and always emit a rendered prompt dossier - useful when the local wrapper carries overrides the service-side agent doesnt see. * Fix _to_sdk_source for dataset sources: SDK ctor takes name=/version=, not dataset_name=/dataset_version=. The mismatch would raise TypeError against the real azure-ai-projects 2.3.0a* SDK; only unmocked integration paths were affected. Tests cover: auto-detection happy path, versionless hosted agent, explicit hosted_agent_version forwarding, force_prompt_source override, non-string chat_client attrs (MagicMock test doubles) not mis-detected, agent_version forwarded through _to_sdk_source, and the corrected dataset SDK kwarg names. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry-evals): accept canonical dimension_scores key per docs The published Foundry rubric-evaluator output (Microsoft Learn 'Rubric evaluators' reference) places per-dimension breakdowns under properties.dimension_scores, not properties.rubric_scores. The parser now tries dimension_scores first and falls back to rubric_scores for preview-build compatibility, and tolerates non-list payloads (e.g. MagicMock auto-attrs) by trying the next candidate when parsing yields zero entries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(foundry-evals): add manual create_rubric_evaluator Adds FoundryEvals.create_rubric_evaluator as the agent-framework surface over project_client.beta.evaluators.create_version. This is the manual counterpart to generate_rubric: callers supply RubricDimension instances (authored locally, ported from another framework, or hand-tuned) and we POST a RubricBasedEvaluatorDefinition. The service auto-attaches the non-editable residual dimension (general_quality for quality, general_policy_compliance for safety). Per the Microsoft Learn 'Rubric evaluators' reference, the auto-generation path (create_generation_job) is primarily a portal/UI feature; external SDK clients with rich local agent context are better served by manual create_version. This keeps generate_rubric for users who want to round-trip through a Foundry-registered agent. Validation up front: weight must be in [1,10], ids unique, descriptions non-empty, pass_threshold in [0,1]. The returned GeneratedEvaluatorRef is identical in shape to one obtained from generate_rubric, so downstream evaluators= lists work unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * samples(foundry-evals): manual rubric sample + namespace re-exports Adds evaluate_with_manual_rubric_sample.py demonstrating the end-to-end dev scenario for FoundryEvals.create_rubric_evaluator: hand-author a list of RubricDimension, register via create_rubric_evaluator, then use the pinned GeneratedEvaluatorRef alongside built-in evaluators in an agent regression run. Also re-exports RubricDimension, GeneratedEvaluatorRef, build_sources, and load_evals_config from agent_framework.foundry (both the lazy runtime shim and the type stub) so the rubric samples can import everything from a single namespace; the auto-generate sample was previously broken because the shim was missing build_sources / load_evals_config. Updates the foundry-evals README with a chooser entry for the two rubric paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(foundry-evals): remove rubric creation flows; keep consumption only Reframes agent-framework as a pure consumer of Foundry rubric evaluators: scoring against rubrics that already exist (authored in the Foundry portal or via the dedicated SDK / REST surface) instead of creating them from the SDK. Removed creation surface area: - FoundryEvals.generate_rubric (auto-generate path) and create_rubric_evaluator (manual path), plus all _GenerationSdkTypes / _ManualRubricSdkTypes / _to_sdk_dimensions / _coalesce_generation_sources / _to_sdk_source / _poll_generation_job / _generation_job_to_ref / _evaluator_version_to_ref / _get_beta_evaluators / _import_*_sdk_types helpers. - EvalGenerationSource (the input source discriminator), RubricDimension (the input dimension type), agent_as_eval_source / workflow_as_eval_source / _detect_hosted_foundry_agent helpers, and the YAML-config loader (_evals_config.py with RubricGenerationSpec / RubricSourceSpec / parse_evals_config / load_evals_config / build_sources). - BaseAgent.as_eval_source / Workflow.as_eval_source plus the _render_agent_dossier / _render_workflow_dossier helpers in core. These existed only to feed the now-removed generation pipeline. - Samples evaluate_with_generated_rubric_sample.py, evaluate_with_manual_rubric_sample.py, and evaluators.yaml. Replaced with a short README section showing how to reference an existing rubric evaluator via GeneratedEvaluatorRef. Kept (consumption surface): - GeneratedEvaluatorRef, slimmed to (name, version, display_name). Still accepted alongside built-in evaluator strings in FoundryEvals(evaluators=[...]). Versionless refs still warn. - RubricScore on EvalScoreResult.dimensions plus EvalResults.assert_dimension_score_at_least for per-dimension CI gates. - _parse_dimension_entries / _extract_rubric_scores output parsing (both canonical dimension_scores and the legacy rubric_scores key). Tests: 160/160 foundry unit tests and 71/71 core local-eval tests pass; pyright is clean across changed files. The pre-existing tests/core/test_telemetry.py::test_detect_hosted_fallback_import_error failure is unrelated and reproduces on the prior commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * samples(foundry-evals): add evaluate_with_rubric_sample Adds a runnable end-to-end sample showing how to consume a pre-existing rubric evaluator created in Foundry: reference it with GeneratedEvaluatorRef(name, version), mix it with built-in evaluators in FoundryEvals, and gate CI with assert_dimension_score_at_least on a specific dimension. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry-evals): satisfy mypy on _fetch_output_items mypy infers OutputItemListResponse.sample as dict[str, object] | None while pyright correctly infers the typed Sample model. Cast to Any so both type checkers accept the attribute access pattern, rename the local to avoid shadowing the inner-loop sample binding, and drop the now-stale pyright suppressions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry-evals): drop unpublished rubric-evaluators learn.microsoft.com link The Adaptive Evals authoring docs are not yet published on Microsoft Learn, so the link 404s. Keep the descriptive text without the broken hyperlink; we can re-add it once the docs ship. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(foundry-evals): hoist repeated local imports to module top Per code review feedback (eavanvalkenburg): the test file repeated 'from agent_framework_foundry._foundry_evals import ...' inside 22 test bodies and 'from agent_framework_foundry import GeneratedEvaluatorRef' inside 8 more. Move all of them to the existing top-level imports; the symbols are the same across tests and the local imports were redundant. 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-06-01 23:01:56 +00:00 -
Python: Fix core observability unsafe serialization of function-call arguments containing dataclass/framework objects (#6026)
* fix: safely serialize function-call arguments in core observability Apply make_json_safe() to content.arguments in _to_otel_part() before building the otel message dict, so that dataclass/framework payloads (e.g. workflow request_info events) do not cause a TypeError when _capture_messages() calls json.dumps(). Lift make_json_safe() into agent_framework._serialization (no new external deps — dataclasses/datetime only) so the core observability path can use it without a dependency on the ag-ui adapter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(core): safely serialize workflow request_info payloads in observability (#5733) - Add make_json_safe() helper to recursively convert non-serializable objects - Use make_json_safe() in _to_otel_part() for function_call arguments - Fix CustomPayload test class to use @dataclass (resolves B903 lint error) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(serialization): guard callability and normalize dict keys in make_json_safe (#5733) - Use callable(getattr(obj, method, None)) instead of hasattr() so that non-callable attributes named model_dump/to_dict/dict do not raise TypeError at runtime. - Wrap each call in try/except TypeError to handle callables with mandatory arguments gracefully. - Convert dict keys to str() so that non-string keys (e.g. datetime, int) cannot cause json.dumps to raise TypeError. - Add regression tests for both scenarios. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address observability serialization review feedback --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evan Mattson ·
2026-06-01 21:41:52 +00:00 -
Python: refresh dev dependencies and validate runtime bounds (#6238)
Updates third-party dev dependencies across the Python workspace and validates that all runtime dependency bounds still hold at both ends. Dev dependency bumps (root, lab, declarative, durabletask): - uv 0.11.6 -> 0.11.17, ruff 0.15.8 -> 0.15.15, pytest-asyncio 1.3.0 -> 1.4.0, mcp 1.27.0 -> 1.27.2, azure-monitor-opentelemetry 1.8.7 -> 1.8.8, poethepoet 0.42.1 -> 0.46.0, prek 0.3.9 -> 0.4.3, types-python-dateutil and types-PyYaml stub bumps. - Transitive Dependabot items swept via lock: idna 3.11 -> 3.17, pip 26.0.1 -> 26.1.2. Deliberately excluded: - opentelemetry-sdk stays 1.40.0: azure-monitor-opentelemetry (incl. 1.8.8) hard-pins opentelemetry-sdk==1.40. - mypy stays 1.20.0 and pyright stays 1.1.408: the 2.1.0 / 1.1.409 bumps introduce new diagnostics that fail type checking and need dedicated PRs. - rich kept as a range: agentlightning (lab[lightning]) forces rich==13.9.4. Code/formatting changes driven by the ruff upgrade: - devui lifespan now uses try/finally so shutdown cleanup always runs (ruff RUF075). - Removed unused TYPE_CHECKING imports in core and foundry flagged by ruff 0.15.15. - Reapplied ruff 0.15.15 formatting to the files it changed. Validation: validate-dependency-bounds-test "*" passes (31/31 lower + 31/31 upper); typing 62/62; lint 31/31; devui tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-06-01 17:53:56 +00:00 -
Python: Add background agent support to harness agent (#6155)
* Add background agent support to harness agent * Address PR comments
westey ·
2026-06-01 17:20:39 +00:00 -
Python: coalesce code interpreter history chunks (#5801)
* fix: coalesce code interpreter history chunks * fix: narrow content item list types * fix: remove redundant content list casts
Yufeng He ·
2026-06-01 13:26:20 +00:00 -
Python: consolidate MCP reliability fixes (#6145)
* Python: consolidate MCP reliability fixes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix MCP cleanup and metadata typing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Satisfy MCP metadata mypy typing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix Pyright metadata mapping type 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-29 07:21:14 +00:00 -
Python: Adding AgentFileStore and FileAccessProvider to support file access operations. (#6099)
* Adding AgentFileStore and FileAccessProvider to support file ased operations for agents. * Address PR review feedback on FileAccessProvider - Probe symlinks on the unresolved candidate path so in-root symlinks cannot silently pass and out-of-root symlinks surface the correct error message. - Validate matching_lines elements in FileSearchResult.from_dict and raise a clean ValueError for non-mapping entries. - Cap search regex pattern length (256 chars) via a new _compile_search_regex helper to mitigate ReDoS, and surface the cap in the file_access_search_files tool description. - Skip non-UTF-8 files during filesystem search instead of aborting the entire directory walk. - Replace the module-scope trailing string in the data-processing sample with comments to avoid Ruff B018. - Remove the checked-in working/region_totals.md sample artifact so the save flow works from a clean checkout. - Expand the Windows stdout reconfiguration comment in task_runner.py for clarity. - Add tests for invalid/oversize regex, non-UTF-8 file search, and in-root symlink rejection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix mypy redundant-cast in FileSearchResult.from_dict Use cast(list[object], ...) instead of cast(list[Any], ...) so the cast represents a real type change (lists are invariant) and is no longer flagged by mypy as redundant, while still satisfying pyright's reportUnknownVariableType. Matches the existing pattern in _memory.py. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tighten path normalization and directory resolution in FileAccess - _normalize_relative_path now strips surrounding whitespace up front so leading/trailing spaces never leak into file segments, and rejects trailing path separators for file paths so 'foo/' is no longer silently coerced to 'foo'. - FileSystemAgentFileStore._resolve_safe_directory_path normalizes with is_directory=True and maps an empty normalized result to the root. This matches InMemoryAgentFileStore so whitespace-only directory inputs resolve to the root instead of raising. - Added tests for whitespace stripping, trailing-separator rejection, and whitespace-only directory listing on the filesystem store. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Harden FileAccess search and atomic save in store API - Add wall-clock timeout (10s) around regex scans so a pathological pattern (e.g. `(a+)+`) below the length cap cannot stall the event loop. - Offload the InMemoryAgentFileStore regex scan to a worker thread, matching the filesystem store. - Fail closed when `Path.is_symlink` raises during the safe-path probe so a permission error cannot silently bypass the symlink/reparse-point rejection. - Add `overwrite: bool = True` to `AgentFileStore.write_file`; the in-memory store performs the check under the existing lock and the filesystem store uses `open(mode='x')` so concurrent callers cannot race past `overwrite=False`. - `file_access_save_file` now relies on the atomic store call instead of a separate `file_exists` round-trip. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix Python 3.10 timeout handling and add directory arg to list/search tools - Catch asyncio.TimeoutError in _run_search_with_timeout. In Python 3.10 asyncio.wait_for raises asyncio.exceptions.TimeoutError, which is distinct from the builtin TimeoutError (the two were unified in 3.11). Catching the asyncio alias works on every supported version. - Add an optional directory parameter to file_access_list_files and file_access_search_files so agents can enumerate / scope searches to nested folders, not just the store root. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address FileAccess review feedback: case, errors, signal, TOCTOU - InMemoryAgentFileStore now stores (display_name, content) so list_files and search_files return the original-case names callers wrote, matching the behaviour of FileSystemAgentFileStore on case-preserving filesystems and removing the silent in-memory vs. on-disk contract divergence. - FileSystemAgentFileStore.read_file raises ValueError instead of letting UnicodeDecodeError bubble for binary / non-UTF-8 input, restoring symmetry with search_files (which still skips) and giving the tool layer a recoverable type to translate. - Tool wrappers now catch ValueError and OSError around every operation and surface them as readable strings, so 'you used ..' and 'the file already exists' are both reported to the model the same way instead of the former crashing out as an unhandled exception. - _search_files_sync logs per skipped non-UTF-8 file at WARNING and an aggregate INFO summary so operators can distinguish 'no matches' from 'half the corpus was unreadable'. - FileSystemAgentFileStore softens its docstrings to acknowledge the inherent probe-then-open TOCTOU window. On POSIX both read and write now pass O_NOFOLLOW so the kernel refuses if the leaf segment becomes a symlink between the probe and the open. Windows has no equivalent flag; the limitation is documented. - Tests cover: case preservation on list/search, ValueError on non-UTF-8 read at the store and tool layer, tool-layer string responses for path-traversal and oversized-regex inputs, search-skip log output, symlink rejection on delete/search/list, and symlinked intermediate directory rejection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address FileAccess nit comments: docstrings, enumerate, opt-in delete approval - Expand FileSearchMatch/FileSearchResult.to_dict docstrings to explain why the override is needed (__slots__ defeats the mixin's __dict__ iteration) and why exclude/exclude_none are accepted-but-ignored (mixin signature compatibility for callers like to_json). - Use enumerate(lines, start=1) in _search_file_content so the +1 below is no longer needed; rename loop variable to line_number for clarity. - Add opt-in require_delete_approval: bool = False on FileAccessProvider. When True, file_access_delete_file is registered with approval_mode 'always_require' so the host must approve every delete. Default False preserves current behaviour and matches the .NET reference, but deployments that want a safer-by-default posture can enable it. - Add tests covering both delete approval modes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * FileAccess: require delete approval by default Flip the default for FileAccessProvider(require_delete_approval=...) from False to True so destructive deletes are gated by host approval out of the box. Callers that want the previous autonomous behaviour (which matches the .NET reference) can pass require_delete_approval=False. Tests updated accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fixing linkinspector by installing Chrome for puppeteer first. --------- 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-28 20:09:50 +00:00 -
Tao Chen ·
2026-05-28 20:03:46 +00:00 -
Python: [Breaking] Refactor Skill API to async resource and script lookup (#6135)
Port of .NET commit
08541ee5a9. Replace property-based Skill.content/resources/scripts with async by-name lookup methods: - content property -> async get_content() -> str - resources property -> async get_resource(name) -> SkillResource | None - scripts property -> async get_script(name) -> SkillScript | None SkillsProvider now always includes all three tools (load_skill, read_skill_resource, run_skill_script) and both instruction blocks regardless of whether any skills have resources or scripts. ClassSkill retains resources/scripts properties as overridable hooks for subclass reflection-based discovery. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>semenshi-m ·
2026-05-28 15:54:20 +00:00 -
Bump Python package versions for 1.7.0 release (#6142)
Bumps the released 1.6.0 packages agent-framework, agent-framework-core, agent-framework-foundry, and agent-framework-openai to 1.7.0, with root continuing to exactly pin agent-framework-core[all]. Bumps the changed prerelease packages agent-framework-a2a, agent-framework-chatkit, agent-framework-declarative, agent-framework-devui, and agent-framework-foundry-hosting to the 260528 date stamp, raises core floors on the packages included in this release, raises Foundry's OpenAI floor alongside OpenAI, and raises ChatKit's openai-chatkit floor to the minimum version required by the current typed API usage. No beta cohort bump was applied; the absent mistal/mistral package was intentionally not bumped because no such package exists in this branch.
Evan Mattson ·
2026-05-28 19:45:31 +09:00 -
Python: Align c# and python TodoProvider tool names (#6107)
* Align c# and python TodoProvider tool names * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Address PR review: remove __slots__ and add typed schemas for tool params - Remove __slots__ from TodoItem, TodoInput, and TodoCompleteInput classes (not needed for low-instance-count objects and hinders dev scenarios) - Add _TodoAddItemSchema and _TodoCompleteItemSchema TypedDicts to provide proper JSON schema for todos_add and todos_complete tool parameters - Use typing_extensions for Python 3.10 compatibility Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
westey ·
2026-05-28 08:40:13 +00:00 -
feat(a2a): add A2AAgentSession with reference_task_ids and input-required support (#5980)
* feat(a2a): link follow-up messages via reference_task_ids Track the task_id from A2A responses (task, status_update, artifact_update, and message payloads) on session.state and include it as reference_task_ids on subsequent outgoing messages. This enables remote agents to correlate follow-up messages as task refinements per the A2A spec. Resolves #5938 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(a2a): add A2AAgentSession for typed protocol state tracking Introduce A2AAgentSession (subclass of AgentSession) with context_id, task_id, and task_state properties. This follows the DurableAgentSession pattern and mirrors the .NET A2AAgentSession design. - Track task_id, context_id, and task_state from all response payload types - Validate context_id consistency (raise on mismatch) - Auto-assign server-generated context_id when not set - Only A2AAgentSession gets reference tracking (no state dict fallback) - Plain AgentSession continues to work without reference tracking - Add serialization support (to_dict/from_dict) - Export via agent_framework.a2a and agent_framework_a2a Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * style: remove unnecessary string annotation (pyupgrade) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use AgentSession.from_dict for state deserialization Avoids importing private _deserialize_state, matching the DurableAgentSession pattern. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: track context_id from message payloads in A2AAgentSession Previously, context_id was only captured from task, status_update, and artifact_update payloads. Message-only responses (which carry context_id but may lack task_id) were silently lost. This fix: - Captures msg.context_id in the message handler - Persists session state when either last_task_id or last_context_id is present (not only when task_id is truthy) - Only updates task_id/task_state when a task_id was actually returned - Adds a test for message-only context_id tracking Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * addressed comments * Gate status content to INPUT_REQUIRED/terminal states (match .NET) Match .NET's GetUserInputRequests pattern: only emit TaskStatusUpdateEvent message content when state is INPUT_REQUIRED or terminal. Intermediate status text (WORKING, SUBMITTED) is no longer surfaced to callers. When state is INPUT_REQUIRED, set additional_properties['input_required'] = True so callers can distinguish input requests from final responses. Closes #5937 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: remove message task_id tracking, defensive fallbacks, and input_required flag - Do not track task_id from Message payloads (simple interactions without task tracking) - Remove 'or last_task_id' fallback from status_update and artifact_update handlers (spec guarantees task_id is always set) - Remove additional_properties['input_required'] flag (content gating to INPUT_REQUIRED/terminal states is the signal itself) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-05-28 08:36:49 +00:00 -
Python: Add a HarnessAgent with available features and sample (#6041)
* Add a HarnessAgent with available features and sample * Fix formatting * Address PR comments and fix mypy error * Add web search support to HarnessAgent * Fix build warning * Apply suggestions from code review Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> * Address PR comments * Address PR comments * Address further PR comments. * Fix markdown broken link --------- Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
westey ·
2026-05-27 14:54:00 +01:00 -
Python: feat(foundry): add to_prompt_agent / deploy_as_prompt_agent (experimental) (#5959)
* feat(foundry): add experimental to_prompt_agent converter Adds `to_prompt_agent(agent)`, an experimental converter (`ExperimentalFeature.TO_PROMPT_AGENT`) that turns an Agent Framework `Agent` into a Foundry `PromptAgentDefinition` ready to publish via `AIProjectClient.agents.create_version(...)`. Behaviour: * `agent.client` must be a `FoundryChatClient` (or subclass); otherwise `TypeError` is raised. The model deployment name is lifted from the bound client so the same Agent definition used for local runs can be published as a hosted prompt agent without restating the model. * Foundry SDK tool instances (from `FoundryChatClient.get_*_tool()`) are passed through unchanged. AF `FunctionTool`s (and `@tool`-decorated callables) are emitted as Foundry `FunctionTool` declarations. * Local AF MCP tools cannot be expressed in a `PromptAgentDefinition`; the converter raises `ValueError` and points at `FoundryChatClient.get_mcp_tool()` for hosted MCP servers. * The converter walks both `agent.default_options["tools"]` and `agent.mcp_tools` because `normalize_tools()` splits local MCP off into its own list. Re-exported through the `agent_framework.foundry` lazy-loading namespace (updates both `__init__.py` and the `__init__.pyi` type stub). Adds a portable-agent sample showing the same `Agent` driven through both `agent.run(...)` and `to_prompt_agent(agent)`, and a README section covering the new converter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(samples): remove snippet tags from portable agent sample Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(samples): inline FoundryChatClient and enable prompt-agent publish Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(samples): drop async credential context manager Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): trim README to_prompt_agent example to publish-only flow Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): note FoundryAgent runs @tool callables for deployed prompt agents Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): address review comments on to_prompt_agent converter * Construct `PromptAgentDefinition` `Tool` from a dict via `**tool_item` unpacking rather than the positional Mapping constructor \u2014 cleaner and matches the typical Pydantic / Azure SDK pattern. * Drop the redundant `isinstance(mcp_tool, MCPTool)` guard in `_convert_tools`; the parameter is already typed `Iterable[MCPTool]` so the second `raise` was unreachable. The remaining single `raise` fires for every entry as intended. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): match Agent.__init__ model resolution in to_prompt_agent * Read the model from `agent.default_options.get("model")` first, falling back to `agent.client.model`. This mirrors the order `Agent.__init__` uses (`_agents.py:740`) when assembling default_options, so the model the agent runs with is the same model the converter publishes \u2014 e.g. when the caller passes `default_options={"model": "..."}` to override the bound client. * Updated the missing-model error message to point at both the client and the default_options paths. * Added tests: * tool-only agent with no `instructions` produces a definition where `instructions` is `None` and is omitted from the dict payload (`Agent.__init__` strips None values from default_options before storing them). * `default_options['model']` wins over the bound client's model. * Fallback to client.model when default_options has no model. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(foundry): add deploy_as_prompt_agent helper + samples Adds `deploy_as_prompt_agent(agent)`, a convenience wrapper around `to_prompt_agent` that reuses the bound FoundryChatClient's project client to call `project_client.agents.create_version(...)`. Defaults `agent_name` / `description` from `agent.name` / `agent.description` so the Agent stays the single source of truth. * Exposed from `agent_framework_foundry` and the lazy-loading `agent_framework.foundry` namespace (including the .pyi stub). * Marked experimental with the existing `ExperimentalFeature.TO_PROMPT_AGENT` tag. * Tests cover the happy path, name/description defaulting, explicit override, no-name error, metadata + description forwarding, extra kwargs passthrough, and the experimental metadata. Samples: * Renamed the existing sample to `creating_prompt_agents.py`, drops 'portable' wording, presents `deploy_as_prompt_agent` first as the recommended path and `to_prompt_agent` + `AIProjectClient` as the two-step alternative, and adds a cleanup step that deletes the published agent so re-runs stay idempotent. * New `using_prompt_agents.py` shows the end-to-end loop: deploy the agent, connect to it with `FoundryAgent` passing the same local `@tool` callable, run a query against the deployed prompt agent, then clean up. README updated to introduce `deploy_as_prompt_agent` as the recommended path and link to both runnable samples. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): restore missing-model ValueError in to_prompt_agent The check was accidentally dropped while reworking docstrings in the previous commit. Test `test_to_prompt_agent_rejects_missing_model` exercises this path and was failing on CI as a result. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): rename deploy_as_prompt_agent -> create_prompt_agent Renames the helper across the foundry package, core lazy-loader stubs, tests, README and samples. The new name better matches the action performed (a prompt-agent definition is created in Foundry) and is consistent with the surrounding ''create_*'' API surface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): drop create_prompt_agent, enrich to_prompt_agent params Remove the create_prompt_agent helper and consolidate on to_prompt_agent. Expose every PromptAgentDefinition parameter that has either an Agent Framework equivalent (sourced from default_options) or no equivalent (accepted as a keyword argument). * default_options-sourced (with kwarg overrides): temperature, top_p, string tool_choice * kwarg-only Foundry knobs: reasoning, text, structured_inputs, rai_config, ToolChoiceParam tool_choice Precedence is always: explicit keyword > default_options entry > unset. Tests cover every path (defaults, default_options, kwargs, kwarg override). Samples and README rewritten around the enriched to_prompt_agent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): single source of truth for prompt-agent options Stop duplicating the generation-parameter surface between FoundryChatOptions and to_prompt_agent. Translate every field with an Agent Framework equivalent (temperature, top_p, tool_choice, reasoning, response_format/text/verbosity) from agent.default_options via a new RawFoundryChatClient helper _prepare_prompt_agent_options. Only Foundry-specific fields with no AF equivalent — structured_inputs and rai_config — remain as keyword arguments on to_prompt_agent. - tool_choice is dropped when there are no tools (mirrors _prepare_options semantics and avoids polluting tool-less prompt agents with Agent.__init__'s 'auto' default). - response_format Pydantic models route through openai.lib._parsing._responses.type_to_text_format_param; dict shapes go through the existing _prepare_response_and_text_format helper. - default_options is not mutated; text dict is defensively copied. Tests, README, and creating_prompt_agents.py sample updated to reflect the new single-source model. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): consolidate prompt-agent sample Drop creating_prompt_agents.py (the publish-only variant) and rename using_prompt_agents.py to foundry_prompt_agents.py so the single sample covers the full convert -> publish -> connect -> run loop. Update the README link list accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(foundry): run local Agent + deployed agent in same sample Add an agent.run() call against the local Agent before publishing, then run the deployed prompt agent on the same query. Expand the docstring with a compare-and-contrast covering runtime/latency, configurability, and persistence/sharing differences between the two execution paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(foundry): cover conflicting response_format + text.format in to_prompt_agent Exercises the ValueError path when a Pydantic response_format would overwrite an explicit text.format mapping with a different shape. Lifts _chat_client.py coverage from 89% to 90%. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(foundry): move _prepare_prompt_agent_options into _to_prompt_agent Lift the translation helper off RawFoundryChatClient and into the _to_prompt_agent module as a module-private function that takes the client as its first argument. The chat client no longer needs to carry a method whose only consumer is the prompt-agent converter, while still serving as the source of the request-path helper (_prepare_response_and_text_format) that the converter reuses for dict-shaped response_format values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(python): codify GA terminology + post-run docs review Add two pieces of guidance to python/AGENTS.md: * Terminology - reserve 'GA' for hosted services; use 'released' or 'stable' for Agent Framework code/features to match the feature-lifecycle stages. * Maintaining Documentation - review AGENTS.md and skills at the end of every run and update any guidance the conversation made stale; before adding a new principle, ask the user to confirm it should be captured. Also pulls in a docstring fix in foundry_prompt_agents.py that swaps the stray 'GA' for 'released', applying the new terminology rule. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * address PR review: strict=True default, Tool._deserialize dispatch, sample cleanup safety - FunctionTool published as strict=True so the server-side schema validation matches what the local FoundryAgent(tools=[same_callable]) dispatcher enforces. AF FunctionTool has no 'strict' attribute, so the safer default is used uniformly instead of silently downgrading to a permissive contract. - _validate_mapping_tool now dispatches through ProjectsTool._deserialize so dict-shaped tools rehydrate to the concrete subclass (FunctionTool, WebSearchTool, ...) via the 'type' discriminator instead of returning a generic Tool. Added a test that asserts isinstance(WebSearchTool) and a new test for the function-typed dict path. - foundry_prompt_agents.py sample now wraps credential + project client in async with and the create_version / run flow in try/finally so a failure on connect or run still deletes the published prompt agent rather than leaving an orphaned, billable resource in the user's Foundry project. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(ci): correct linkspector ignorePattern typo (./pulls -> ./pull) GitHub PR URLs use the singular segment /pull/N (compare to /issues/N for issues). The existing './pulls' ignore pattern never matched anything as a result, so legitimately stale PR links (e.g. PRs deleted from forks) surface as linkspector failures on unrelated PRs. This is the same convention the './issues' rule above already follows. Fixes the markdown-link-check failure on a dangling link in dotnet/src/Microsoft.Agents.AI.DurableTask/CHANGELOG.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-27 13:31:21 +00:00 -
Python: Add a BackgroundAgentsProvider for python (#6069)
* Add a BackgroundAgentsProvider for python * Address PR comments and fix linting warnings * Address PR comment
westey ·
2026-05-27 09:12:01 +00:00 -
Python: Align ModeProvider tool names and instructions (#6071)
* Align ModeProvider tool names and instructions * Address PR comments
westey ·
2026-05-26 14:37:34 +00:00