mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
copilot/fix-dotnet-test-failure
807 Commits
-
Python: [BREAKING] Migrate agent-framework-a2a to a2a-sdk v1.0 (#5752)
* Python: Migrate agent-framework-a2a to a2a-sdk v1.0 Upgrade the a2a-sdk dependency from v0.3.x to v1.0.0 and migrate all source, tests, samples, and documentation to the v1.0 API. Key changes: - Dependency: a2a-sdk>=1.0.0,<2 (was >=0.3.5,<0.3.24) - Types are now protobuf-based: Part replaces TextPart/FilePart/DataPart - Enums use SCREAMING_SNAKE_CASE (e.g. TaskState.TASK_STATE_COMPLETED) - Roles: Role.ROLE_AGENT, Role.ROLE_USER - Client: SendMessageRequest wrapper, subscribe() replaces resubscribe() - Server: A2AStarletteApplication replaced by Starlette + route factories - DefaultRequestHandler now requires agent_card parameter - TaskUpdater: final parameter removed, add_artifact gains last_chunk - AgentCard.url removed; use supported_interfaces with AgentInterface - Stream yields StreamResponse with WhichOneof('payload') Closes #5661 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review: validate fallback URL, remove unused task_id vars - Raise ValueError with clear message when transport negotiation fails and no fallback URL is available (neither url arg nor supported_interfaces) - Remove unused task_id local in status_update branch - Inline artifact_event.task_id directly in artifact_update branch Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>Giles Odigwe ·
2026-05-11 22:46:12 +00:00 -
Python: bump package versions for 1.3.0 release (#5706)
* Python: bump package versions for 1.3.0 release MINOR bump on the released cohort (agent-framework, agent-framework-core, agent-framework-openai, agent-framework-foundry: 1.2.2 -> 1.3.0). All 22 beta packages stamp 1.0.0b260507 and all 3 alpha packages stamp 1.0.0a260507 per the lockstep convention. Date stamp reflects 2026-05-07 Pacific. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: bump foundry_local openai floor, fix devui orchestrations pin, clarify breaking scope - foundry_local: bump agent-framework-openai lower bound from >=1.1.0 to >=1.3.0 - devui: update stale agent-framework-orchestrations dev pin from 1.0.0b260402 to 1.0.0b260507 - CHANGELOG: clarify [BREAKING] applies to experimental skills API only Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert devui orchestrations pin to 1.0.0b260402 to avoid breaking DevUI Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-05-08 08:57:02 +09:00 -
Python: Upgrade github-copilot-sdk to v1.0.0b2 with new features (#5665)
* Upgrade github-copilot-sdk to v1.0.0b1 and implement new features - Bump github-copilot-sdk dependency from 0.2.1 to 1.0.0b1 - Fix breaking type renames: ErrorClass -> ToolExecutionCompleteError, Result -> ToolExecutionCompleteResult - Add instruction_directories support in GitHubCopilotOptions (session-level) - Add copilot_home support in GitHubCopilotSettings (client-level) - Add sample: github_copilot_with_instruction_directories.py - Update README with new env var and sample entry - Add 8 new unit tests covering the new features (103 total, 96% coverage) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * mypy fix * small fix * Address PR feedback: fix resume path, remove copilot_home from Options, bump to beta.2 - Forward runtime_options through _resume_session (fixes silent drop of instruction_directories/model/etc on resumed sessions) - Remove copilot_home from GitHubCopilotOptions (client-level setting only consumed at startup, not per-call) - Bump github-copilot-sdk from 1.0.0b1 to 1.0.0b2 - Add test for instruction_directories override on resumed sessions - Update existing resume test to match new _resume_session signature Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-05-07 21:43:47 +00:00 -
Python: Add ClassSkill for class-based skill definitions (#5678)
* Python: Add ClassSkill for class-based skill definitions Add ClassSkill abstract base class with decorator-based resource and script discovery, porting .NET's AgentClassSkill (PRs #5027 and #5183) to Python. - Add ClassSkill(Skill, ABC) with instructions abstract property, cached content/resources/scripts properties - Add @ClassSkill.resource and @ClassSkill.script static method decorators for auto-discovery of methods and properties - Extract _build_skill_content() and _create_resource_element() shared helpers from InlineSkill for reuse - Add _discover_marked_members() for scanning class hierarchies - Add _make_method_name() for Python-to-skill name conversion - Add class_based_skill sample (UnitConverterSkill) - Update mixed_skills sample with TemperatureConverterSkill - Add 58 new tests covering ClassSkill, decorator discovery, property resources, inheritance, kwargs forwarding, and duplicate detection - Export ClassSkill from agent_framework public API Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: replace try/except/continue with assignment to satisfy bandit B112 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * address PR review feedback - Walk cls.__mro__ in _discover_marked_members for inherited property resources - Use inspect.getattr_static for MRO-aware is_property check - Return defensive copies from resources/scripts properties - Raise TypeError on wrong decorator stacking order (@resource above @property) - Log warning instead of silently swallowing descriptor errors during discovery - Validate explicit name= at decoration time via _validate_member_name - Add tests for all of the above Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix temperature converter skill: make resource necessary for script Refactor TemperatureConverterSkill so the agent must read the formulas resource (factor/offset) before calling the script, aligning with the volume-converter pattern. - Resource: numeric factor/offset table instead of symbolic formulas - Script: generic linear transform (value * factor + offset) - Instructions: updated to reflect new workflow Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SergeyMenshykh ·
2026-05-07 19:39:12 +00:00 -
Python: Fix
MCPStreamableHTTPToolleakingasyncio.CancelledErrorwhen MCP server is unreachable (#5687)* fix: wrap asyncio.CancelledError in ToolException in _connect_on_owner (#5667) asyncio.CancelledError is a BaseException (not Exception) in Python 3.8+. When an MCP server is unreachable, the MCP library's internal anyio task group raises CancelledError, which escaped all three 'except Exception' handlers in _connect_on_owner(). This propagated through _run_lifecycle_owner -> _run_on_lifecycle_owner -> connect -> __aenter__, bypassing user except Exception blocks entirely. Fix: change the three except-Exception clauses in _connect_on_owner to 'except (Exception, asyncio.CancelledError)' so spurious CancelledErrors from the MCP transport layer are caught and wrapped in ToolException, consistent with the method's documented contract. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(mcp): propagate genuine task CancelledError in connect() (#5667) On Python >= 3.11, check task.cancelling() > 0 before wrapping CancelledError as ToolException in the three except blocks inside _connect_on_owner(). When the current task is being cancelled by its caller, the CancelledError now propagates after cleanup, consistent with the existing pattern at _mcp.py:560-564 and _runner.py:115-120. On Python < 3.11 task.cancelling() is unavailable, so MCP-internal CancelledErrors still cannot be reliably distinguished from caller-driven cancellation; they continue to be wrapped as ToolException with a comment documenting the trade-off. Tests: - Add cleanup assertion to transport-creation CancelledError test - Add MCPStdioTool variants exercising the 'command' message branches for both transport-creation and initialize CancelledError paths - Add Python 3.11+-gated tests verifying genuine task cancellation propagates (and still cleans up) for transport and initialize stages Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(mcp): log CancelledError with exc_info before wrapping in ToolException (#5667) CancelledError inherits from BaseException (not Exception) on Python >= 3.8, so the 'inner_exception=ex if isinstance(ex, Exception) else None' guard always yields None for CancelledError. This means ToolException.__init__ calls logger.log(level, message, exc_info=None), dropping the traceback. Add an explicit logger.debug(error_msg, exc_info=ex) before each raise ToolException(...) in the three CancelledError handlers so the full traceback is preserved in debug logs when MCP-internal cancellation is wrapped rather than propagated. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5667: Python: [Bug]: Error Handling Issue regarding Python MCPStreamableHTTPTool Class * refactor(_mcp): extract cancellation helper, fix session error msg and exc_info - Extract _should_propagate_cancelled_error() helper to eliminate duplicated genuine-cancellation detection logic across the three connect() except blocks - Fix session-creation ToolException message to include exception details (e.g. 'Failed to create MCP session: <ex>') matching the transport and initialize failure paths - Change exc_info=ex to exc_info=True in all three logger.debug() calls for idiomatic logging - Add tests for _should_propagate_cancelled_error helper - Add regression test asserting session error message includes exception text - Add test verifying logger.debug is called with exc_info=True Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: factor out _close_and_check_cancelled helper in _connect_on_owner Addresses review comment on PR #5687: 1. Add _close_and_check_cancelled() helper method that combines _safe_close_exit_stack() + _should_propagate_cancelled_error() into a single await-able call. This eliminates the duplicated close-then-check pattern that appeared identically in all three connect phases (transport, session, initialize), reducing future drift risk. 2. Comments 2 and 3 (missing {ex} in session error message and non-idiomatic exc_info=ex) were already addressed in the current code: all error messages include {ex} and all logger.debug calls use exc_info=True. 3. Add test_connect_genuine_cancellation_during_session_creation_propagates to cover the previously untested genuine-cancellation path in the session-creation phase (transport and initialize phases already had tests). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5667: review comment fixes --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evan Mattson ·
2026-05-07 17:58:30 +00:00 -
Python: Add
base_urlparameter toAnthropicClientandRawAnthropicClient(#5685)* feat(anthropic): add base_url parameter to AnthropicClient and RawAnthropicClient Add base_url support to AnthropicSettings TypedDict, RawAnthropicClient, and AnthropicClient so users can point the client at Foundry or other Anthropic-compatible endpoints without having to construct AsyncAnthropic manually. - Add base_url field to AnthropicSettings (resolved from ANTHROPIC_BASE_URL env var) - Add base_url parameter to RawAnthropicClient.__init__ and pass it to AsyncAnthropic - Add base_url parameter to AnthropicClient.__init__ and forward to super - Add unit tests for base_url on both client classes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Add `base_url` parameter to `AnthropicClient` and `RawAnthropicClient` Fixes #5683 * test: add ANTHROPIC_BASE_URL env fallback tests for issue #5683 Add unit tests verifying that both AnthropicClient and RawAnthropicClient pick up base_url from the ANTHROPIC_BASE_URL environment variable via load_settings when base_url is not passed explicitly as a constructor arg. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(anthropic): explicit base_url kwarg beats ANTHROPIC_BASE_URL env var (#5683) Add regression tests asserting that when both ANTHROPIC_BASE_URL is set in the environment *and* an explicit base_url kwarg is passed to AnthropicClient / RawAnthropicClient, the explicit kwarg wins. This closes the priority-ordering contract (explicit arg > env var) that the existing tests left implicit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evan Mattson ·
2026-05-07 17:57:09 +00:00 -
Python: Add support for function approval flow in Foundry hosted agent (#5666)
* Add support for function approval flow in Foundry hosted agent * Address comments * Address comments * Address comments
Tao Chen ·
2026-05-07 14:55:26 +00:00 -
Python: Core: notify agent of external AgentModeProvider mode changes (#5650)
When the operating mode is changed externally (e.g. via a slash-command handler calling set_agent_mode), the agent's chat history still shows the prior set_mode tool call near the end. Updating only the system instructions is insufficient — models tend to anchor on the recent tool call and ignore the new mode. Mirror the .NET AgentModeProvider behavior: when set_agent_mode detects an actual mode change, record the previous mode in provider state. On the next before_run, the provider pops that flag and injects a user-role notification message announcing the switch, so the most recent context unambiguously reflects the current mode. The agent-driven set_mode tool path bypasses this so it does not trigger a redundant notification on its own change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-07 02:58:38 +00:00 -
Python: Remove bespoke Foundry toolbox helpers; standardize on MCP for toolbox consumption (#5671)
* Remove Foundry toolbox helpers; standardize on MCP for toolbox consumption - Remove RawFoundryChatClient.get_toolbox() and its fetch_toolbox import - Remove fetch_toolbox, select_toolbox_tools, get_toolbox_tool_name, get_toolbox_tool_type, FoundryHostedToolType, ToolboxToolSelectionInput from agent_framework_foundry._tools - Remove ExperimentalFeature.TOOLBOXES from _feature_stage.py (no consumers) - Drop toolbox re-exports from agent_framework_foundry/__init__.py and agent_framework.foundry namespace - Update _sanitize_foundry_response_tool docstring to remove toolbox framing; sanitization logic itself is unchanged - Update _agent.py docstring: 'toolbox-fetched MCP' → 'hosted MCP' - Delete tests/test_toolbox.py (all tests covered removed helpers) - Update test_foundry_chat_client.py: rename/redoc tests that mentioned toolbox but test sanitization that remains - Delete foundry_chat_client_with_toolbox.py (bespoke toolbox API sample) - Delete foundry_toolbox_context_provider.py (relied on select_toolbox_tools) - Rename foundry_chat_client_with_toolbox_mcp.py → foundry_chat_client_with_toolbox.py (canonical MCP pattern) - Rewrite 04_foundry_toolbox/main.py to use MCPStreamableHTTPTool - Update provider/README, context_providers/README, 04_foundry_toolbox/README Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(samples): update 06_files sample to consume toolbox via MCP (#5670) Replace removed get_toolbox/select_toolbox_tools APIs with MCPStreamableHTTPTool, using allowed_tools=["code_interpreter"] to select only the code interpreter from the toolbox endpoint. Update .env.example and README to use FOUNDRY_TOOLBOX_ENDPOINT instead of TOOLBOX_NAME. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): remove non-existent toolbox helper APIs from README (#5670) Remove the 'fetch, optionally filter, and pass tools directly' pattern from the FoundryChatClient toolbox documentation, as select_toolbox_tools and get_toolbox were removed. Only the MCP endpoint pattern is documented. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(foundry): remove residual toolbox docstring references and reproduction report Remove REPRODUCTION_REPORT.md (workflow artifact that should not be committed), and update two remaining docstring references that still said 'toolbox reads' /'toolbox definition' after the toolbox helpers were removed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Remove bespoke Foundry toolbox helpers; standardize on MCP for toolbox consumption Fixes #5670 * fix(#5670): resolve toolbox endpoint from TOOLBOX_NAME fallback; add namespace regression tests - Add _resolve_toolbox_endpoint() helper in 04_foundry_toolbox/main.py and 06_files/main.py that prefers FOUNDRY_TOOLBOX_ENDPOINT but falls back to deriving the MCP URL from FOUNDRY_PROJECT_ENDPOINT + TOOLBOX_NAME — fixing the startup KeyError when agents are deployed via azd provision (which injects TOOLBOX_NAME, not FOUNDRY_TOOLBOX_ENDPOINT). - Update 04_foundry_toolbox/.env.example to use FOUNDRY_TOOLBOX_ENDPOINT (consistent with 06_files). - Add TOOLBOX_NAME env var to 06_files/agent.yaml so deployed agents have it available for the fallback derivation. - Update both READMEs to document the two ways to supply the toolbox endpoint. - Add test_foundry_namespace_no_longer_exposes_toolbox_helpers() with negative assertions for FoundryHostedToolType, get_toolbox_tool_name, get_toolbox_tool_type, and select_toolbox_tools — guarding against accidental re-introduction of removed symbols. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(samples): fail fast on empty FOUNDRY_TOOLBOX_ENDPOINT; add unit tests Addresses review feedback for #5670: - In _resolve_toolbox_endpoint() (04_foundry_toolbox/main.py and 06_files/main.py) change the walrus-operator check from a truthy test to an explicit 'is not None' guard. An explicitly set empty string now raises ValueError immediately with a clear message instead of silently falling through to the fallback URL construction. - Add tests/samples/hosting/test_toolbox_endpoint.py covering both sample modules: (a) FOUNDRY_TOOLBOX_ENDPOINT set → returned as-is (b) FOUNDRY_TOOLBOX_ENDPOINT set to empty string → ValueError (c) fallback constructs URL from FOUNDRY_PROJECT_ENDPOINT + TOOLBOX_NAME, stripping trailing slashes (d) neither variable group set → KeyError Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback: remove extraneous test and docstring content - Remove test_foundry_namespace_no_longer_exposes_toolbox_helpers (no longer warranted) - Remove docstring from _agent.py _prepare_tools_for_openai (extraneous) - Trim _chat_client.py _prepare_tools_for_openai docstring to one-liner (toolbox references no longer relevant) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: remove remaining extraneous docstring from RawFoundryChatClient._prepare_tools_for_openai Address review comment on PR #5671: reviewer noted the description isn't warranted now that toolbox helpers have been removed. Matches the pattern in RawFoundryAgentChatClient which has no docstring. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evan Mattson ·
2026-05-06 23:56:16 +00:00 -
Python: [Breaking] Restructure agent skills to use multi-source architecture (#5584)
* migrate skills to multi source architecture * Fix ruff lint errors in skills module (ASYNC240, SIM108, E501) - Use anyio.Path for async file I/O in _FileSkillResource.read() - Use noqa: ASYNC240 for pure string os.path calls in async context - Restore pre-commit if/else pattern in InlineSkillScript.run() - Break long lines to fit 120-char limit in _skills.py and test_skills.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: collapse multi-line lambdas to single lines to fix pyright errors The pyright ignore comments only suppress errors on the same line, so multi-line lambdas left arguments on continuation lines uncovered. Collapse both lambdas to single lines matching the existing load_skill lambda pattern. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: replace untyped lambdas with typed inner functions to fix pyright errors Python lambdas cannot have type annotations, so pyright reports reportUnknownLambdaType and reportUnknownArgumentType errors that cannot be suppressed with inline ignore comments. Replace the lambdas for read_skill_resource and run_skill_script with typed inner async functions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address PR review feedback on docs and prompt template - Update with_prompt_template() docstring to document the {resource_instructions} placeholder requirement - Remove stray backslashes after {resource_instructions} and {runner_instructions} in DEFAULT_SKILLS_INSTRUCTION_PROMPT - Update subprocess_script_runner docstring to reflect FileSkillScript.full_path usage Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: replace dict[str, Skill] with Sequence[Skill] in SkillsProvider Replace internal dict-based skills storage with Sequence[Skill] to eliminate silent duplicate overwrites and simplify the code. Add _find_skill helper for case-insensitive linear lookup. Also fix pyright errors in tests by adding isinstance assertions before accessing .function on SkillResource/SkillScript base types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: add read-time resource path validation in _FileSkillsSource Move security validation (path-traversal and symlink guards) for file-based skill resources into _FileSkillsSource, restoring the read-time checks that existed in main via _read_file_skill_resource. - Add _get_validated_resource_path static method on _FileSkillsSource that validates containment, existence, and symlink safety - _FileSkillsSource.get_skills() validates resource paths at discovery time via _get_validated_resource_path before passing to _FileSkillResource - Move _normalize_resource_path, _is_path_within_directory, and _has_symlink_in_path from module-level into _FileSkillsSource as static methods (only used there) - _FileSkillResource remains a simple path-to-content reader - Add tests for _get_validated_resource_path security checks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: reject str/Path in SkillsProvider constructor to prevent str-as-Sequence ambiguity Since str is a Sequence, passing a path string to the source parameter would silently be treated as a sequence of characters instead of a file source. Add an explicit TypeError with a helpful message pointing callers to SkillsProvider.from_paths(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR #5584 review feedback - Remove .NET reference from _FileSkillResource docstring - Fix inconsistent resource name example (references/FAQ.md -> references/FAQ) - Simplify SkillsProvider usage in code_defined_skill sample (pass single skill directly) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * remove skillsproviderbuilder * Update python/packages/core/agent_framework/_skills.py Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> * fix: remove dead code and fix sync function call in InlineSkillResource.read() - Change await self.function() to self.function() for sync functions without **kwargs; async results are handled by inspect.isawaitable() - Remove unreachable raise ValueError since __init__ already validates Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * remove full_path unnecessary property * replace anyio with asyncio.to_thread for file I/O in _FileSkillResource Replace anyio.Path usage with asyncio.to_thread + pathlib.Path since anyio is not a direct dependency of core (transitive via mcp). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * simplify awaitable check to return directly Use 'return await result' instead of assigning then returning. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * address PR review feedback for skills refactoring - Replace anyio with asyncio.to_thread + pathlib.Path for file I/O - Simplify awaitable check to return directly - Remove unnecessary function None guard in InlineSkillResource.read() - Add assert for type narrowing on self.function Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * address PR review feedback for skills refactoring - Replace anyio with asyncio.to_thread + pathlib.Path for file I/O - Simplify awaitable checks to return directly - Remove unnecessary function None guard in InlineSkillResource.read() - Use typing.cast instead of assert for type narrowing - Add caching behavior note to SkillsProvider docstring Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: move name/description from abstract properties to Skill.__init__ Replace abstract properties for name and description on the Skill ABC with a base __init__ that validates and stores them as regular attributes. This simplifies custom Skill subclasses (only content remains abstract) and centralizes validation in the base class, consistent with SkillResource and SkillScript base classes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
SergeyMenshykh ·
2026-05-06 09:45:06 +00:00 -
Python: Add Python parity for InvokeMcpTool in declarative workflow (#5630)
* Add Python parity for HttpRequestAction in declarative workflow * Ran pyupgrade and pright to fix CI issues * Fix conversation ID dot parsing for http executor * Removed unnecessary export command * Initial implementation of invoke mcp tool in python * Update sample to support require approval to be toggled by environment variable. * Fix cache and PR comments * Update python/samples/03-workflows/declarative/invoke_mcp_tool/main.py Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> --------- Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
Peter Ibekwe ·
2026-05-05 20:16:03 +00:00 -
Python: fix(bedrock): don't send toolChoice when no tools are configured (#5172)
* fix(bedrock): don't send toolChoice when no tools are configured BedrockChatClient was sending toolConfig.toolChoice even when no tools were configured (tools=None). AWS Bedrock requires toolConfig.tools to be present whenever toolChoice is specified, causing a 400 validation error. Only set toolChoice when tool_config has a 'tools' key present. Fixes #5165 Signed-off-by: bahtya <bahtyar153@qq.com> * test: add tests for toolChoice without tools - test_prepare_options_tool_choice_auto_without_tools_omits_tool_config - test_prepare_options_tool_choice_required_without_tools_omits_tool_config Verifies that toolConfig is omitted when tool_choice is set but no tools are provided, preventing ParamValidationError from Bedrock. * fix: address maintainer feedback — remove stray test file, raise ValueError for required without tools 1. Remove test_addition.py — stray duplicate of tests already in python/packages/bedrock/tests/test_bedrock_client.py, missing all necessary imports and would fail with NameError. 2. Change tool_choice='required' handling to raise ValueError when no tools are configured instead of silently falling through. Using 'required' without tools is a logical contradiction — the model must invoke a tool but none exist — so surfacing this as a ValueError helps callers catch the misconfiguration early. 3. Update the corresponding test to expect ValueError instead of silently omitted toolConfig. --------- Signed-off-by: bahtya <bahtyar153@qq.com>
bahtyar ·
2026-05-05 19:15:37 +00:00 -
Python: information-flow control prompt injection defense (#5331)
* Python: Information-flow control based prompt injection defense (#5024) * fides integration * documentation * documentation * documentation * human-approval on policy violation * numenous hyena 'works' * IFC based implementation * minor edits in documentation * rebasing the branch and running the email example * Add security tests for IFC middleware * Fix Role.TOOL NameError in approval handling * tiered labelling scheme * 3 tier labelling scheme in middleware * Adapt security middleware to list[Content] tool results * Refactor SecureAgentConfig as context provider and address Copilot review comments * Update FIDES docs to reflect context provider pattern and update code for ContextProvider rename * Fix security examples: use OpenAIChatClient instead of non-existent AzureOpenAIChatClient * Address PR review: consolidate security modules, remove ContentLineage, update docs * remove unrelated files * remove comment from _tools.py and rename decision file * Fix CI failures: Bandit B110, broken md links, hosted approval passthrough * apply template to decision doc 0024 * minor fixes to decision doc 0024 --------- Co-authored-by: Aashish <t-akolluri@microsoft.com> * Python: follow up FIDES security flow (#5330) * Python: follow up FIDES security flow Refine the secure approval path, mark the security classes with the FIDES experimental feature label, and clean up the related docs/tests. Also fix workspace-level validation regressions uncovered while running the full Python check suite. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: remove FIDES GitHub MCP sample Drop the GitHub MCP security sample from the FIDES follow-up branch while keeping the remaining security docs and samples intact. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review: fix paths and update FIDES implementation (#5352) * Python: updated import naming and comment from review (#5421) * updated import naming and comment from review * Add approval replay None call-id test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Address PR 5331 comments and track sesssion while calling Agent in email_security_example (#5446) * Address PR review: fix paths and update FIDES implementation * Address PR comments and add session tracking in email example in samples * Fix session creation and resolve merge conflict in docstring example * Resolve merge conflict in docstring example * Python: add test for empty-message pruning in approval result replacement (#5617) Adds test coverage for the second-pass logic in `_replace_approval_contents_with_results` that removes messages whose `contents` list becomes empty after first-pass content removal. Addresses review comment on PR #5331: https://github.com/microsoft/agent-framework/pull/5331#discussion_r3129039445 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: shrutitople <shruti.tople@gmail.com> Co-authored-by: Aashish <t-akolluri@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-05 18:08:08 +00:00 -
Python: Core: add experimental session-mode harness context provider (#5611)
* Python: Core: add experimental session-mode harness context provider Introduces the _harness namespace and the first context provider: SessionModeContextProvider, with get_session_mode / set_session_mode helpers and a DEFAULT_MODE_SOURCE_ID constant. Behind @experimental(ExperimentalFeature.HARNESS). Also folds in a small _sessions.py cleanup (try/except ImportError -> contextlib.suppress) touched while developing the harness. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Core: align session-mode harness with .NET AgentModeProvider Mirror the default mode descriptions and instruction template used by the .NET AgentModeProvider so the cross-language harness UX is consistent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Core: address review feedback on session-mode harness - json.dumps tool outputs to stay valid for arbitrary mode names - normalize configured mode keys (lower+strip) so custom-cased configs work - raise TypeError instead of silently replacing non-dict session state - mark get_session_mode/set_session_mode as @experimental(HARNESS) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Core: rename SessionModeContextProvider to AgentModeProvider Match the .NET AgentModeProvider class name for cross-language consistency. Helpers renamed accordingly: get_session_mode -> get_agent_mode, set_session_mode -> set_agent_mode. The default source_id is now "agent_mode". Construction pattern stays Pythonic (kwargs, not an options object). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Core: address AgentModeProvider review feedback - default_mode now defaults to None and falls back to the first configured mode, decoupling the kwarg from the built-in 'plan'/'execute' set. - get_agent_mode catches ValueError when a previously persisted mode is no longer in available_modes and resets to the default mode (matching the non-string recovery branch). Added regression coverage for both behaviors. 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-05 10:09:19 +00:00 -
Python: Fix hyperlight WasmSandbox cross-thread Drop and harden hosted-agent sample (#5603)
* update hyperlight to beta and move samples, add hosted agent sample * Python: Fix hyperlight WasmSandbox cross-thread Drop and harden sample Root cause: when a worker-side closure raised, the exception's __traceback__ retained frame locals that included the partially constructed PyO3 sandbox. Future.result() re-raised that exception on the caller thread, and when the caller's exception was eventually GC'd the frame locals were released off-thread, dec_ref'ing the unsendable sandbox from the wrong thread and tripping the PyO3 panic '_native_wasm::WasmSandbox is unsendable, but is being dropped on another thread'. Fix: * Add _SandboxWorker._run_on_worker which catches every exception on the worker, drops __traceback__ there, deletes the original exception, and re-raises a fresh instance on the caller thread. initialize and execute route through it; dispose keeps its bare-submit semantics. * Add an opt-in diagnostic module _drop_diagnostic (no-op unless HYPERLIGHT_TRACE_DROPS=1) that installs a sys.unraisablehook and dumps owner-thread + per-thread stacks on any future cross-thread unsendable Drop. Useful for triaging similar PyO3 regressions. * Tests: cross-thread invocation, traceback-leak isolation, _SandboxEntry attribute-shape check, and a stale-reference stress test driven through asyncio.to_thread. Sample (samples/04-hosting/foundry-hosted-agents/responses/06_hyperlight_codeact): * Dockerfile installs agent-framework-* from in-tree source with python/ as build context so unreleased fixes can be validated end-to-end. * call_server.py pins the Responses API version. * main.py enables include_detailed_errors=True so future tool failures surface the actual exception text instead of a bare 'Error: Function failed.' string. * README.md documents the in-tree-package build and the Hyperlight hypervisor requirement (/dev/kvm on Linux, MSHV on Windows). Hosted environments without hypervisor passthrough surface 'No Hypervisor was found for Sandbox'; this is a hosting constraint, not a hyperlight bug. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: remove _drop_diagnostic from hyperlight package The diagnostic module was useful while bisecting the cross-thread Drop bug, but it is no longer needed now that _SandboxWorker._run_on_worker prevents the panic at the source. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: address PR review feedback on hyperlight - Use lazy agent_framework.hyperlight import in sample main.py. - Env-driven endpoint (FOUNDRY_AGENT_ENDPOINT) in call_server.py; remove personal URLs. - Align agent.yaml model deployment with manifest (gpt-4.1-mini). - Tighten Dockerfile requirements guard; drop dangling deploy.ps1 reference. - Preserve exception args when sanitizing tracebacks in _run_on_worker. - Add public _SandboxWorker.is_alive(); update test to avoid private attr. - Add namespace coverage tests for agent_framework.hyperlight lazy loader. - Add prominent note: Foundry hosted-agent runtime does not yet support Hyperlight (no hypervisor exposed); container works locally with /dev/kvm. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: bump hyperlight-sandbox dependencies to 0.4.x Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: renumber hyperlight codeact sample to 08 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Coerce worker exception args to strings for cross-thread safety Stringify exc.args on the worker thread before propagating, so any PyO3 unsendable object captured in args (e.g. via a caller-supplied callback or underlying SDK) cannot be Dropped on the calling thread. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * moved sample --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-05 10:06:16 +00:00 -
Python: Core: add experimental todo-list harness context provider (#5612)
* Python: Core: add experimental todo-list harness context provider Adds TodoListContextProvider with pluggable TodoStore backends: TodoSessionStore (in-session) and TodoFileStore (JSONL on disk). Public types: TodoItem, TodoInput. Behind @experimental(ExperimentalFeature.HARNESS). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Core: align todo harness instructions with .NET TodoProvider Reformat DEFAULT_TODO_INSTRUCTIONS to mirror the .NET TodoProvider DefaultInstructions wording and structure, and bring the class docstring closer to the .NET XML <remarks> block. Keeps Python tool names in snake_case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Core: address review feedback on todo harness - mark TodoStore as @experimental(HARNESS) for surface consistency - TodoSessionStore.load_state now raises ValueError on malformed items - TodoFileStore now namespaces persisted state by source_id - TodoFileStore now safely encodes session_id/owner and verifies path containment (matches FileHistoryProvider pattern) - per-(session, source_id) asyncio.Lock around read-modify-write to avoid races Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Core: rename TodoListContextProvider to TodoProvider Match the .NET TodoProvider class name for cross-language consistency. Other public types (TodoStore, TodoSessionStore, TodoFileStore, TodoItem, TodoInput) are unchanged. Construction stays Pythonic (kwargs, not an options object). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Core: address TodoProvider review feedback - TodoStore.load_state/save_state are now async; TodoFileStore performs disk I/O via asyncio.to_thread so the event loop is no longer blocked while the per-session mutation lock is held. - TodoSessionStore now raises ValueError for malformed top-level state (non-dict / non-list 'items' / non-int 'next_id') to match the TodoFileStore contract instead of silently re-defaulting. - Both stores now clamp next_id to max(item.id) + 1 after load to make ID collisions impossible after recovery or reconfiguration. - TodoFileStore writes atomically by writing a sibling temp file and os.replace-ing it so a crash mid-write cannot truncate the state file. - TodoFileStore.load_state no longer creates parent directories for sessions that never write; mkdir is deferred to save_state. - TodoProvider mutation locks now live in a weakref.WeakKeyDictionary keyed by AgentSession, so locks for GC'd sessions are evicted instead of leaking in long-running services. Tests cover each change including a TodoFileStore-backed end-to-end provider flow, atomic-write recovery, and lock GC eviction. 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-05 08:39:41 +00:00 -
Python: Fix incorrect workflow timings in DevUI by adding
created_atto executor events (#5615)* fix(devui): add created_at to custom output item events for correct workflow timings (#5545) CustomResponseOutputItemAddedEvent and CustomResponseOutputItemDoneEvent lacked a created_at field, causing the frontend to synthesize timestamps using integer-second precision with a forced +1s minimum gap between events. This made instant workflows appear to take 3+ seconds in the DevUI timeline. Fix: - Add optional created_at: float | None field to both custom event models - Populate created_at=float(time.time()) in the mapper for executor_invoked, executor_completed, and executor_failed events Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(devui): use event created_at for accurate workflow timeline timings workflow-view.tsx synthesized _uiTimestamp using Math.max(baseTimestamp, lastTimestamp + 1) with integer-second precision, forcing a minimum 1-second gap between every sequential event. This made instant workflows appear to take several seconds in the DevUI timeline. The fix prefers event.created_at (a float Unix timestamp populated by the backend mapper for all executor events) and only falls back to the synthetic timestamp when created_at is absent. This matches the pattern already used in devuiStore.ts:addDebugEvent. Added a regression test in test_mapper.py verifying that the mapper attaches created_at to all executor lifecycle events (invoked, completed, failed). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(devui): address review feedback for issue #5545 - Read data.timestamp (ISO string) and response.created_at in addition to top-level created_at when deriving _uiTimestamp, so response.workflow_event.completed events get a real server timestamp instead of a synthesized one - Change uniqueTimestamp tiebreaker: when a real server timestamp is available use Math.max(eventTimestamp, lastTimestamp) rather than lastTimestamp + 1, eliminating artificial 1-second gaps while still preserving monotonic ordering - Apply the same fix in the HIL streaming path (second setOpenAIEvents call in workflow-view.tsx) - Add assert event.created_at > 0 to regression test to guard against zero or negative timestamps - Add test_custom_output_item_event_models_have_created_at_field model- level test so removing the field produces a clear named failure rather than a downstream ValidationError Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(#5545): guard NaN timestamps, fix fallback ID uniqueness, add regression tests - workflow-view.tsx (×2): Wrap data.timestamp ISO→number conversion in a Number.isFinite() guard. Python's datetime.now().isoformat() emits microseconds without a trailing 'Z' (e.g. '2024-01-15T12:34:56.123456'), which some JS engines cannot parse, returning NaN. NaN !== undefined is true so the eventTimestamp !== undefined guard did not catch it, poisoning _uiTimestamp and resetting the monotonic ordering seed (NaN || 0 → 0). - execution-timeline.tsx: Replace uiTimestamp in the fallback syntheticItemId with the per-executor runNumber counter. Two runs of the same executor within the same second previously received identical _uiTimestamp values and therefore identical syntheticItemIds, causing their output buckets, state, and run entries to collide (execution-timeline.tsx:360–408). - Add missing test_workflow_timings_bug.py source file (only a stale .pyc existed). Three regression tests: · test_custom_event_models_lack_created_at_field – model field guard · test_workflow_executor_events_lack_created_at – mapper populates created_at · test_rapid_workflow_events_have_no_top_level_timestamps – confirms data.timestamp format that requires the frontend NaN guard Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5545: Python: [Bug]: Workflow timings in DevUI are incorrect * devui: move timing regression tests into test_mapper.py, remove dedicated bug file - Delete test_workflow_timings_bug.py; tests belong in existing module files - The two tests already present in test_mapper.py (test_executor_events_carry_created_at_timestamp and test_custom_output_item_event_models_have_created_at_field) cover the same ground as the first two tests in the deleted file - Add test_executor_completed_maps_to_output_item_done_event to test_mapper.py, replacing the third test from the deleted file with a generic, issue-agnostic name and docstring Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5545: review comment fixes --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evan Mattson ·
2026-05-05 05:59:08 +00:00 -
fix(openai): drop completed continuation_token from shared options in tool loop (#5462)
Fixes #5394. When `background=True` is combined with local function tools, `FunctionInvocationLayer` calls `_inner_get_response(options=mutable_options)` repeatedly with the same dict reference across loop iterations. Once the first poll retrieves a completed background response, `continuation_token` stays in `mutable_options`, so every subsequent iteration takes the `continuation_token is not None` branch and `GET`s the same completed response instead of `POST`ing the tool results. The loop exits after `max_iterations` with empty text and the model never sees any tool output. After the retrieve, if the returned `ChatResponse.continuation_token` is `None` (the background response is no longer in progress), pop `continuation_token` and `background` from the shared options dict in place. The next loop iteration then falls through to the normal `responses.create`/`parse` path and posts tool results. The diagnosis and a verified runtime monkeypatch are in the issue; this is the same fix moved in-tree. Co-authored-by: Yufeng He <40085740+universeplayer@users.noreply.github.com>
Yufeng He ·
2026-05-04 21:22:56 +00:00 -
Python: Support GPT-5 verbosity option and restore Foundry agent_reference (#5619)
* Python: Support GPT-5 verbosity option and restore Foundry agent_reference Adds verbosity as a typed Literal["low","medium","high"] field on OpenAIChatOptions (Responses API) and OpenAIChatCompletionOptions (Chat Completions API), set in the same way as the existing reasoning options. For the Responses API, top-level verbosity is translated to the nested text.verbosity shape the OpenAI service expects. The same field flows through to FoundryChatClient via the existing FoundryChatOptions alias. Also fixes #5582: PR #5447 removed the agent_reference injection from RawFoundryAgentChatClient._prepare_options, so first-turn calls against a Foundry Prompt Agent went out without model and without agent_reference and were rejected by the Responses API with "Missing required parameter: 'model'". Restores the injection on the non-preview path (allow_preview=False) and adds a guard test that asserts the preview path does not inject agent_reference, since the preview SDK injects it via project_client.get_openai_client(agent_name=...). Closes #5516 Closes #5582 * Python: Address Copilot review on PR #5619 - Foundry verbosity sample docstring: replace the misleading "set deployment name on model=" instruction with the actual env-var pattern the sample relies on (FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL). - _build_agent_reference docstring: clarify the helper is used for both Prompt Agents and HostedAgents on the non-preview path. - Add a Responses API test that locks in the documented precedence rule: when both top-level verbosity and text["verbosity"] are supplied, the top-level value wins. * Python: Drop redundant Foundry verbosity sample and list OpenAI sample in README - Remove samples/02-agents/providers/foundry/foundry_chat_client_verbosity.py per review feedback. The verbosity functionality is identical across the OpenAI and Foundry clients (FoundryChatOptions is an alias of OpenAIChatOptions), so a single sample on the OpenAI side is sufficient. - Add the new client_verbosity.py entry to the OpenAI samples README.
Evan Mattson ·
2026-05-04 21:21:40 +00:00 -
Python: Core: add experimental memory harness context provider (#5613)
* Python: Core: add experimental memory harness context provider Adds MemoryContextProvider with topic-indexed long-term memory and chat-driven compaction. Pluggable MemoryStore backends include MemoryFileStore. Public types: MemoryIndexEntry, MemoryTopicRecord. Behind @experimental(ExperimentalFeature.HARNESS). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Core: address review feedback on memory harness - mark MemoryStore as @experimental(HARNESS) for surface consistency - safely encode owner id and verify path containment (matches FileHistoryProvider pattern) - namespace MemoryFileStore on-disk layout by source_id to avoid cross-provider collisions - before_run computes index_entries once and only rewrites MEMORY.md when content changes - asyncio locks around topic/state read-modify-write to avoid concurrent-write races Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR feedback: harden memory store IO + consolidation behavior - Atomic writes via os.replace + temp sibling for topic, state, and index files so crashes/disk-full failures cannot leave a truncated half-written file. - Stop creating directories on read paths: list_topics/read_state/search_transcripts and get_messages return empty when nothing has been written. mkdir is deferred to the actual save path (write_topic/write_state/save_messages). - Escape lines that look like markdown headings on render and unescape them on parse, so a memory or summary containing '## Summary'/'## Memories' cannot tamper with the topic file structure. - Narrow extraction/consolidation chat-client failure handling to ChatClientException, asyncio.TimeoutError, and OSError. Programmer errors (AttributeError, TypeError, ...) now propagate so misconfigured clients fail loudly. - Log a payload-prefix preview for every silent shape branch in _extract_memories and _consolidate_topic so unparsable extractor output is debuggable instead of invisible. - Restructure _run_consolidation: read maintenance state and topic snapshot under the state lock, run the LLM consolidation loop without holding the state lock, and only advance last_consolidated_at/sessions_since_consolidation if at least one topic succeeded. Transient consolidation failures now leave the maintenance window in place so the next after_run retries instead of silently sliding forward. - Add regression tests for: markdown-marker round-trip, atomic-write recovery on os.replace failure, no-mkdir on pure read paths, transient consolidation failure preserves state, and propagation of programmer errors. 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-04 21:19:50 +00:00 -
Python: Add Python parity for HttpRequestAction in declarative workflow (#5599)
* Add Python parity for HttpRequestAction in declarative workflow * Ran pyupgrade and pright to fix CI issues * Fix conversation ID dot parsing for http executor * Removed unnecessary export command
Peter Ibekwe ·
2026-05-01 23:04:07 +00:00 -
Python: Enforce approval_mode in Claude and GitHub Copilot agents (#5562)
* Python: Enforce approval_mode in Claude and GitHub Copilot agents Tools declared with approval_mode="always_require" were bypassed by the ClaudeAgent and GitHubCopilotAgent because their SDK-managed tool-calling loops invoke FunctionTool.invoke() directly via package-supplied handlers, skipping the standard _try_execute_function_calls approval gate. Per discussion on #5494, the fix lives in the agents (not in FunctionTool): any flag added to the tool itself can be spoofed by code with the same level of access, so the security boundary is the agent that owns the tool-calling loop. - Add on_function_approval option to ClaudeAgentOptions and GitHubCopilotOptions. Callback receives a FunctionCallContent describing the pending call and returns bool (sync or async). - Gate FunctionTool.invoke() inside each agent's existing tool-handler closure when approval_mode == "always_require". Default policy is deny; callbacks that raise also deny safely. - Deny path returns a tool-error to the model (Claude: text content; Copilot: ToolResult(result_type="failure", error="approval_denied")) so the LLM can react gracefully instead of silently failing. - Tests for both agents covering: deny by default, sync False, sync True, async True, callback-raises -> deny, no-op for never_require tools. - Samples demonstrating sync, async, and deny-by-default flows for both agents. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review: preserve empty arg dicts, reject runtime approval override - _resolve_function_approval no longer collapses {} into None when building the FunctionCallContent passed to the callback (Claude + Copilot). - Claude _apply_runtime_options and Copilot _run_impl/_stream_updates now raise ValueError if on_function_approval is supplied via per-run options, instead of silently ignoring it. Approval policy must be set at agent construction time. - Drop unnecessary # type: ignore[attr-defined] on Content.name/.arguments in samples (Content is a unified class with both attributes defined). - Add regression tests for the new runtime-options validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * warning when non callback handler and approval needed --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-01 14:11:28 +00:00 -
Python: Reduce flaky integration tests and improve CI signal quality (#5454)
* Enable Ollama integration tests in CI and rename report to Integration Test Report - Install Ollama, cache models (qwen2.5:0.5b + nomic-embed-text), and start server in the Misc integration job for both workflow files - Set OLLAMA_MODEL and OLLAMA_EMBEDDING_MODEL env vars so the 5 Ollama tests are no longer skipped - Rename Flaky Test Report to Integration Test Report throughout (job names, artifact names, cache keys, file names, script titles/docstrings) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Bump Ollama model to qwen2.5:1.5b for better instruction following The 0.5b model was too small to reliably follow simple prompts like 'Say Hello World', causing test assertion failures. The 1.5b model follows instructions more reliably while still being small enough for fast CI pulls (~1GB). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Re-enable reliable streaming integration tests Remove the hard skip on test_03_reliable_streaming tests that was temporarily disabled for instability investigation. CI infrastructure (Azurite, DTS emulator, Redis, func CLI) is already in place. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Re-enable skipped Functions/DurableTask tests and bump timeout to 480s - Remove hard skips from 4 tests in test_11_workflow_parallel.py - Remove hard skip from test_conditional_branching in test_06_dt_multi_agent_orchestration_conditionals.py - Increase pytest --timeout from 360 to 480 for Functions+DurableTask CI job - Updated in both python-merge-tests.yml and python-integration-tests.yml Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Re-skip failing Functions/DurableTask tests with specific root causes - test_11_workflow_parallel (4 tests): xdist worker crashes during execution - test_conditional_branching: orchestration fails with RuntimeError, not a timeout - Keep 480s timeout bump for remaining Functions tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix auth routing in samples 06/11: api_key -> credential for Azure OpenAI Both samples passed a bearer token provider via api_key= which caused the client to route to api.openai.com instead of Azure OpenAI, resulting in 401 Unauthorized. Changed to credential= which correctly triggers Azure routing and picks up AZURE_OPENAI_ENDPOINT from the environment. - samples/azure_functions/11_workflow_parallel/function_app.py: 1 fix - samples/durabletask/06_multi_agent_orchestration_conditionals/worker.py: 2 fixes - Re-enable 4 parallel workflow tests and 1 conditional branching test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Re-skip parallel workflow tests: xdist worker distribution issue The 4 parallel workflow tests crash because xdist worksteal distributes them across separate workers, each spawning its own func process against shared emulators. Auth fix (api_key->credential) was valid and stays. test_conditional_branching now passes with the auth fix. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix E501 line-too-long in azurefunctions parallel test skip reasons Wrap skip reason strings to stay within 120 char line limit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add retry logic and port-conflict fix for Ollama CI setup - Kill any auto-started Ollama before launching serve (fixes port conflict: 'address already in use') - Retry ollama pull up to 3 times with 15s backoff (fixes 429 rate limit failures) - Applied to both python-merge-tests.yml and python-integration-tests.yml Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix flaky integration tests and re-enable skipped tests - Foundry agent: add allow_preview=True to custom client test - Foundry hosting: raise max_output_tokens 50->200, add temperature, relax assertion in test_temperature_and_max_tokens - Foundry embedding: update skip reason with root cause (endpoint mismatch) - OpenAI file search: fix vector store indexing race condition by polling file_counts before querying; fix get_streaming_response -> get_response(stream=True) - Azure OpenAI file search: remove skip (transient 500 resolved) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove temperature from foundry hosting test (unsupported by CI model) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Stabilize Ollama tool call integration tests with no-arg function Use a no-argument greet() function instead of hello_world(arg1) for integration tests. The 1.5B model in CI is unreliable at generating correct tool call arguments, causing 'Argument parsing failed' errors. A no-arg function eliminates this flakiness entirely. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Increase reliable streaming test timeouts from 30s to 60s The LLM call through Azure OpenAI + Redis streaming pipeline can exceed 30s in CI due to cold starts or throttling. Raise to 60s to reduce flaky timeouts while still bounded by pytest's 120s per-test limit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Re-enable workflow parallel tests with xdist_group marker The tests were skipped because xdist distributes module tests across workers, each spawning their own func process (port conflicts). Adding xdist_group forces all tests in this module onto a single worker so the module-scoped function_app_for_test fixture works correctly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert "Re-enable workflow parallel tests with xdist_group marker" This reverts commit
455c28da62. * Rename flaky_report to integration_test_report and add try/finally cleanup - Rename scripts/flaky_report/ to scripts/integration_test_report/ to reflect expanded scope beyond flaky-test detection - Update workflow references in both CI files - Wrap file search integration tests in try/finally to ensure vector store cleanup runs even on test failure or timeout Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix Ollama pull failure propagation and Azure OpenAI vector store readiness - Ollama CI: fail the step immediately if model pull fails after 3 retries instead of silently proceeding to tests - Azure OpenAI file search: add the same vector-store readiness polling that was applied to the non-Azure OpenAI tests, preventing eventual consistency race conditions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * remove load_dotenv from test file --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>Giles Odigwe ·
2026-05-01 00:41:39 +00:00 -
Python: Fix hosted MCP replay producing orphan function_call_output (#5581)
* Python: Fix hosted MCP replay producing orphan function_call_output Resolves part of #5546. After a turn ran a hosted MCP / Foundry-toolbox-MCP tool, the next turn's replayed input array carried a function_call_output with an mcp_* call_id and no matching function_call, and the Responses API returned a 400. Two layers covered here: * Chat-client serialize layer (packages/openai): adds mcp_server_tool_call and mcp_server_tool_result cases to _prepare_message_for_openai and _prepare_content_for_openai. Pairs are coalesced via a post-pass into a single mcp_call input item carrying both arguments and output. Orphan results are dropped (debug-logged) rather than serialized as orphan function_call_output, which is what the Responses API rejected. * Host read layer (packages/foundry_hosting): _item_to_message and _output_item_to_message now route custom_tool_call_output whose call_id.startswith("mcp_") to Content.from_mcp_server_tool_result. Non-mcp_ call_ids continue to produce Content.from_function_result. Symmetric with the host write-side choice for hosted-MCP results. Two further fixes (agentserver SDK additions, host write-side single-item emission) remain tracked on the issue and depend on an SDK release. * Python: Fix pyright unknown-type in _stringify_mcp_output cast(Sequence[Any], output) after the isinstance check so pyright stops flagging the loop variable as unknown. Also normalizes a couple of em-dashes in docstrings I introduced in the prior commit. * Python: Harden _stringify_mcp_output for dict-shaped MCP outputs Address Copilot review on PR #5581. Today the helper falls back to str() for any non-string, non-text-attribute entry, which produces Python repr (single-quoted dicts) for the canonical MCP raw-JSON text-content shape `{"type": "text", "text": "..."}` and any other dict-shaped output. Three small changes: * List-entry path: prefer plain string entries, then `.text` attribute (Content objects), then `entry["text"]` for Mapping entries in the canonical MCP shape, then JSON-encode anything else. * Final fallback: `json.dumps(output, default=str)` so Mappings and scalars produce valid JSON rather than Python repr. * Two new unit tests covering the dict-with-text shape and the non-text-dict JSON fallback. * Python: Suppress mypy redundant-cast on _stringify_mcp_output narrowing The cast is needed by pyright (reportUnknownVariableType) but mypy considers it redundant after the preceding isinstance narrowing. Pyright's behavior is correct for the strict-mode reporting we run, so keep the cast and silence mypy on the line.
Evan Mattson ·
2026-04-30 21:01:52 +00:00 -
Python: Support OpenAI and Gemini
allowed_toolstool choice (#5322)* Support OpenAI allowed_tools in ToolMode (#5309) Add allowed_tools field to ToolMode TypedDict, enabling users to restrict which tools the model may call via the OpenAI allowed_tools tool_choice type. This preserves prompt caching by keeping all tools in the tools list while limiting which ones the model can invoke. - Add allowed_tools: list[str] to ToolMode TypedDict - Add validation in validate_tool_mode() (only valid when mode == "auto") - Convert to OpenAI API format in _prepare_options() - Add tests for validation and API payload generation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Support OpenAI `allowed_tools` tool choice in Python SDK Fixes #5309 * Fix #5309: Validate allowed_tools shape and add Chat Completions client support - validate_tool_mode now checks allowed_tools is a non-string sequence of strings and normalizes to list[str], raising ContentError for invalid types - Add missing allowed_tools branch in _chat_completion_client._prepare_options so allowed_tools is emitted as the OpenAI allowed_tools wire format instead of being silently dropped - Add tests for invalid allowed_tools types (string, int, mixed), empty list, tuple normalization, and Chat Completions client payload generation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: support allowed_tools with mode 'required' in addition to 'auto' OpenAI's allowed_tools tool_choice type supports both mode 'auto' and 'required'. Update validation, client conversion, and tests to allow both modes instead of restricting to 'auto' only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use Gemini VALIDATED mode for allowed_tools, warn in unsupported providers - Use FunctionCallingConfigMode.VALIDATED instead of ANY when allowed_tools is set with auto mode in Gemini, preserving optional tool-call semantics. - Handle allowed_tools in required mode with required_function_name precedence. - Fix allowed_names guard to use identity check (is not None) so empty lists are preserved. - Bump google-genai minimum to >=1.32.0 (VALIDATED added in that version). - Add warnings in Anthropic and Bedrock when allowed_tools is set but not supported. - Add Gemini unit tests for allowed_tools with auto, required, empty list, and required_function_name precedence scenarios. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: Chat Completions API does not support allowed_tools, add integration tests - Chat Completions API (_chat_completion_client.py) now warns and falls back to plain mode when allowed_tools is set, since the /chat/completions endpoint does not support the allowed_tools type. - Add allowed_tools integration test param to both OpenAIChatClient (Responses API) and OpenAIChatCompletionClient parametrized option tests. - Update Chat Completions unit tests to reflect the warn-and-fallback behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: remove unused walrus operator variable in chat completion client Remove assigned-but-never-used variable 'allowed' flagged by ruff F841. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-04-29 17:43:47 +00:00 -
Python: bump package versions for 1.2.2 release (#5561)
* Python: bump package versions for 1.2.2 release PATCH bump (1.2.1 -> 1.2.2) for the released cohort. Five PRs land in this window: - agent-framework-openai: fix file_search citations breaking the assistant- message history roundtrip (#5557) — drives the released-tier PATCH - agent-framework-orchestrations: [BREAKING] standardize orchestration terminal outputs as AgentResponse (#5301) - agent-framework-core, agent-framework-declarative: preserve Workflow.run() shared state across calls, accept list[Message] in declarative start executor, and coerce Enum values when serializing PowerFx symbols (#5531) - agent-framework-foundry-hosting: add hosted Durable Workflow support (#5531) - agent-framework-azure-contentunderstanding: new alpha package — Azure AI Content Understanding context provider (#4829) - dependencies: workspace package dependency refresh (#5555) Per lockstep convention, all 21 beta packages stamp 1.0.0b260429 and all 4 alpha packages (now including the new contentunderstanding) stamp 1.0.0a260429. Date stamp reflects 2026-04-29 Pacific. Every non-core package floor on agent-framework-core is raised to >=1.2.2; the new contentunderstanding package's stale >=1.0.0 floor is brought into line. Two follow-on fixes bundled to keep validate-dependency-bounds-test green at lowest-direct resolution: - Bump agent-framework-azure-contentunderstanding's azure-ai-content understanding lower bound from >=1.0.0 to >=1.0.1 (1.0.0 ships without proper typing — pyright reports 65 unknown-type errors) - Add pyright ignore comments to core/foundry/__init__.pyi for the new alpha package's type-stub imports, since alpha packages are not in core's [all] extra and therefore aren't installed at lowest-direct * Python: add #5552 to 1.2.2 CHANGELOG Add the streaming-span observability fix to the Fixed section. PR is on upstream/main but not yet pulled into origin/main; the code itself will land via the PR merge. * Python: address PR #5561 review feedback on dependency bounds Two packaging fixes flagged in review: 1. agent-framework-azure-contentunderstanding: add agent-framework-foundry as a runtime dependency. The package's README directs users to `pip install agent-framework-azure-contentunderstanding --pre` and the basic example imports `FoundryChatClient` from `agent_framework.foundry`, so the documented install path was failing with ImportError. Pulling agent-framework-foundry into deps makes the advertised entry path self-contained. 2. agent-framework-foundry: bump agent-framework-openai lower bound from >=1.1.0 to >=1.2.2,<2. Foundry imports private modules from agent_framework_openai (`_chat_client.py:22`, `_agent.py:34`), so resolvers were free to pair foundry==1.2.2 with older OpenAI versions that lack this release's coordinated Responses/history fix. Lockstep the floor with the released cohort to prevent mismatched installs. Both changes pass `validate-dependency-bounds-test` lower + upper at their respective packages.
Evan Mattson ·
2026-04-29 17:51:48 +09:00 -
Python: Fix spans not correctly nested when using streaming (#5552)
* Fix spans not correctly nested when using streaming * fix pre commit * Address comments
Tao Chen ·
2026-04-29 08:21:28 +00:00 -
Python: Fix file_search citations breaking assistant history roundtrip (#5557)
* Python: Fix file_search citations breaking assistant history roundtrip The Responses API rejects 'input_file' inside an assistant message, but the SDK was emitting it whenever an assistant Message contained a hosted_file content (which is what file_search citations become). Three coordinated fixes: 1. _prepare_content_for_openai now skips hosted_file for the assistant role instead of mapping to input_file (which the API rejects there). 2. The streaming response.output_text.annotation.added handler attaches file_citation, container_file_citation, and file_path as annotations on text content, matching the non-streaming path. Previously streaming produced standalone HostedFileContent items that always tripped (1). 3. output_text serialization preserves Annotation objects on roundtrip via a new _annotations_to_output_text helper instead of hardcoding 'annotations' to []. file_search citations now survive multi-agent forwarding. Closes #5556. * Address PR review - _annotations_to_output_text: fan out one entry per annotated_region for url_citation/container_file_citation (Annotation.annotated_regions is a Sequence; the API form carries one start/end per entry). - Validate region span bounds are ints before emitting; skip otherwise. - Add test for the file_path branch (annotation with file_id only). - Add test verifying streamed citation events coalesce onto surrounding text via _finalize_response so span indices reference the merged text, not the empty-text streaming carrier.
Evan Mattson ·
2026-04-29 07:38:19 +00:00 -
Python: Feature/hosted dwf (#5531)
* Fix declarative Workflow.as_agent() by accepting list[Message] in start executor The declarative start executor (JoinExecutor) only advertised dict and str in its input_types, so WorkflowAgent.__init__ rejected it with 'Workflow's start executor cannot handle list[Message]'. Add list[Message] to the JoinExecutor handler annotation and add a matching branch in DeclarativeActionExecutor._ensure_state_initialized that extracts the last user-message text and falls through to the string-input initialization path, so =System.LastMessageText works end-to-end via as_agent(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Populate Conversation.messages from list[Message] trigger When Workflow.as_agent() is invoked with a list[Message], the start executor now populates Conversation.messages / Conversation.history / System.conversations.{id}.messages with prior turns only (excluding the latest user message), and surfaces the latest user message via Inputs.input and System.LastMessage*. This matches InvokeAzureAgent's contract that the messages binding holds prior turns and the executor itself appends the new user input before invoking, avoiding double-append of the trailing user turn while preserving full history (incl. assistant/system/tool roles and multi-modal content) for downstream actions. * Coerce Enum values when serializing PowerFx symbols MessageRole and other str-subclass Enums passed isinstance(v, str) and were forwarded to pythonnet unchanged. pythonnet then raised 'MessageRole value cannot be converted to System.String' for every PowerFx primitive when ConditionGroup/Expr eval walked the symbol table containing Conversation.messages. Reduce Enum members to their underlying value before the primitive check so eval sees plain strings/ints. * Foundry hosting: pass full conversation history to workflow agents _handle_inner_workflow only forwarded the latest user turn to WorkflowAgent.run, even though _handle_inner_agent already prepends history fetched from Foundry storage to the messages it sends a regular agent. Declarative workflows reset Conversation.messages on every run (state.initialize), so checkpoint replay alone does not give them prior turns - the host has to pass them in, the same way it does for non-workflow agents. Mirror that contract: fetch context.get_history() and pass [*history, *input_messages] to the workflow agent. * feat(workflows): support combined message + checkpoint_id for multi-turn continuation Allow Workflow.run(message=..., checkpoint_id=...) so callers can restore prior workflow state from a checkpoint AND deliver a new message to the start executor in a single call. The existing reset_context logic already preserves shared state when checkpoint_id is set, so this gives us 'fresh start executor invocation with prior state intact' - exactly what hosted multi-turn declarative workflows need. - _workflow.py: drop the message+checkpoint_id mutual exclusion and update _execute_with_message_or_checkpoint to do both (restore then execute) when both are provided. - _agent.py: in _run_core's checkpoint branch, also forward input_messages so WorkflowAgent.run(messages, checkpoint_id=...) works end-to-end. Falls back to the legacy 'restore only' behavior when messages are absent. - _declarative_base.py: detect continuation in _ensure_state_initialized by checking whether DECLARATIVE_STATE_KEY already exists in shared state; if so, refresh inputs/LastMessage* and append non-user trigger messages instead of calling state.initialize() (which would wipe Conversation/Local/System). - foundry_hosting/_responses.py: collapse the host's two-call pattern (restore-only, then fresh run) into a single combined call now that the underlying APIs support it. - tests: drop the assertion that combined message+checkpoint_id raises. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Pivot: preserve workflow state across run() calls Replace the prior 'combined message + checkpoint_id in one run()' approach with a cleaner default: Workflow.run no longer wipes shared state or runner- context messages between calls. Iteration counting and per-run kwargs still reset on a fresh-message run; checkpoint and responses runs are continuations that preserve everything. This lets a WorkflowAgent be invoked repeatedly on the same instance and maintain multi-turn context (e.g. accumulated Conversation.messages) without asking developers to opt in. Hosted-agent multi-turn pattern becomes two explicit calls: restore-from-checkpoint (drive to idle), then run-with-message. Key changes: - _workflow.py: drop _state.clear() and reset_for_new_run() from run(). Reset iteration count and run kwargs on fresh-message runs only. Restore 'Cannot provide both message and checkpoint_id' validation. Add async guard: fresh-message run with un-drained pending executor messages from a prior run is invalid. - _runner.py: clear _state before import_state in restore_from_checkpoint so restore is authoritative (import_state merges, not replaces). - _agent.py: revert checkpoint branch to restore-only (no message forward). - _responses.py (foundry_hosting): two-call host pattern - restore checkpoint silently, then run with new user input. - tests: state-preservation is the new default; rebuild Workflow for clean slate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix CI lint and mypy issues from prior pivot commit - _workflow.py: collapse nested if (SIM102), drop redundant assignment (RET504) - _declarative_base.py: remove unused last_user_msg = tail assignment whose Message | None type clashed with the prior Message-typed branch Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review: fix Inputs.input update and checkpoint storage path - _declarative_base.py: continuation branch was writing 'Inputs.input' via state.set, which routes to the Custom namespace and never updates the PowerFx-visible Workflow.Inputs.input. Update state_data['Inputs'] in place via get_state_data / set_state_data so =Workflow.Inputs.input and =inputs.input see the new turn's user text on continuation. - _declarative_base.py: refresh docstring to clarify that on a list[Message] trigger, Conversation.messages excludes the current user message at the start of the turn (agent executors append it before invoking the inner agent). - _responses.py: when previous_response_id is supplied (no conversation_id), the prior checkpoint lives under <storage>/<previous_response_id> but new checkpoints must land under <storage>/<current_response_id> for the next turn to find them. Hold onto restore_storage from the get_latest lookup and pass it to the restore-only run; pass write_storage (current id) to the message-delivery run and to checkpoint cleanup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix pyright errors in _declarative_base.py for CI - Replace state._state.get(...) protected access with new public is_initialized() method on DeclarativeWorkflowState (also clearer intent for the continuation detection use case). - Add narrow pyright ignores for the Any-typed trigger paths that pyright cannot fully narrow (the list[Message] isinstance loop and the fallback-DefaultTransform branch). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address Copilot review batch: tests + Workflow.reset escape hatch * Add Workflow.reset() public method as recovery escape hatch when an in-flight run aborted (e.g. WorkflowConvergenceException) and the workflow is not checkpointed. Update the in-flight messages guard's error message to point callers at it. * Add test_workflow_run_inflight_messages_guard exercising both the guard (sync + streaming) and the reset() recovery path. * Add test_workflow_reset_rejects_concurrent_runs to lock down the in-progress guard on reset. * Add test_as_agent_continuation_preserves_prior_state covering the is_continuation branch in _ensure_state_initialized: stamps a marker between calls and asserts it survives, while Inputs.input and System.LastMessageText refresh to the new turn. * Add test_powerfx_safe.py regression tests for the Enum branch in _make_powerfx_safe (str-subclass, int-subclass, plain Enum, and Enums nested in dict/list). * Drop redundant @pytest.mark.asyncio on test_as_agent_round_trip_with_last_message_text (asyncio_mode='auto'). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Skip restore-only pre-pass when checkpoint has pending request_info Address Copilot review on _responses.py: the restore-only checkpoint replay populates self._agent.pending_requests for any request_info events captured in the checkpoint. The follow-up run(input_messages) call would then route through WorkflowAgent._process_pending_requests, which expects function-response content and rejects plain text input as 'unexpected content while awaiting request info responses'. Workflows resumed from a checkpoint that was idle-with-pending-requests would therefore fail every subsequent plain-text user turn. Inspect the loaded checkpoint and skip the pre-pass when its pending_request_info_events dict is non-empty. Workflows that don't use request_info (the current sample set) are unaffected; workflows that do will fall through to a fresh-message run rather than silently corrupting the routing state. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Loosen azure-ai-agentserver-* pins to major version The exact-version pins on azure-ai-agentserver-{core,responses,invocations} forced foundry-hosting consumers to upgrade in lockstep with every beta bump from upstream. Switch to '>=current,<next-major' so we pick up patch and feature updates within the same major series without a coordinated release. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Drop Workflow.reset(); checkpointing is the recovery path The in-flight-messages guard prevented silent misbehavior, but the companion Workflow.reset() escape hatch only cleared _messages while leaving iteration count, executor-local state, and shared State mutations in an indeterminate condition after a mid-run failure. That gave a false sense of recovery. Recovery from a mid-run failure is supported only via checkpoint restoration. Keep the guard and reframe its error message accordingly; remove reset() and its tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address Tao's review on PR 5531 - Rename Workflow._run_workflow_with_tracing parameter is_fresh_message_run -> is_continuation (default False, inverted). Fresh-message turns reset per-run accounting; continuations (checkpoint restores, responses replays) preserve it. - Simplify the in-flight-messages guard: _validate_run_params already enforces that 'message' is mutually exclusive with 'checkpoint_id' and 'responses', so the additional checks were dead code. - foundry_hosting _responses: move the restore-only pre-pass above emit_created/emit_in_progress; restore is preparation, not run progress. Drop the skip-restore gate (state preservation requires unconditional restore) and instead clear agent.pending_requests after the restore-only call. Collapse over-conditioned check. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Don't clear pending_requests after restore-only pre-pass Pending requests in the restored checkpoint represent genuinely outstanding HITL requests. The next user input may carry function responses (Responses API `function_call_output` items become FunctionResultContent / FunctionApprovalResponseContent), which `WorkflowAgent._process_pending_requests` correctly extracts and matches against the populated `pending_requests`. Clearing them after restore would silently drop that state and force the next turn to be treated as a fresh input even when the caller is responding to the outstanding requests. 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: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
Ben Thomas ·
2026-04-29 00:51:49 +00:00 -
Python: [BREAKING] Standardize orchestration terminal outputs as AgentResponse (#5301)
* Fix orchestration outputs so as_agent() returns the final answer only. Align other orchestration outputs * Fix orchestration output issues from review comments 1. Sample cleanup: Remove commented-out FoundryChatClient block and update prerequisites to reference OPENAI_CHAT_MODEL_ID instead of FOUNDRY_* vars. 2. Sequential approval output: Change _EndWithConversation.end_with_agent_executor_response from a no-op sink to yield response.agent_response. When the last participant is AgentApprovalExecutor (via with_request_info), _EndWithConversation is the output executor so the yield produces the terminal answer. When the last participant is a regular AgentExecutor, _EndWithConversation is not in output_executors so the yield is silently filtered out. 3. Forward data events through WorkflowExecutor: _process_workflow_result now also forwards 'data' events from sub-workflows so that emit_intermediate_data=True on AgentExecutor works correctly when wrapped in AgentApprovalExecutor. 4. Concurrent docstring: Update _AggregateAgentConversations docstring to say 'deterministic participant order' instead of 'completion order'. 5. Add test_concurrent_intermediate_outputs_emits_data_events verifying that ConcurrentBuilder(intermediate_outputs=True) emits per-participant data events alongside the single aggregated output event. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add tests for sequential workflow with_request_info and intermediate_outputs (#5301) Address PR review comments 2, 3, and 5: - Add test_sequential_request_info_last_participant_emits_output: Verifies that when the last participant is wrapped via with_request_info() (AgentApprovalExecutor), the workflow still emits a terminal output after approval, exercising the _EndWithConversation.end_with_agent_executor_response fallback path. - Add test_sequential_request_info_with_intermediate_outputs_emits_data_events: Verifies that emit_intermediate_data=True works correctly through AgentApprovalExecutor wrapping—WorkflowExecutor._process_result already forwards data events from sub-workflows, so intermediate agent responses surface as data events in the parent workflow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix pyright type errors from AgentResponse output refactor (#5301) Update cast() calls in _group_chat.py and _magentic.py to use WorkflowContext[Never, AgentResponse] instead of the old WorkflowContext[Never, list[Message]], matching the updated method signatures in _base_group_chat_orchestrator.py. Fix _sequential.py _EndWithConversation.end_with_agent_executor_response to declare WorkflowContext[Any, AgentResponse] so yield_output accepts AgentResponse[None]. Fix _workflow_executor.py data event forwarding to handle nullable executor_id. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix pyright reportUnknownVariableType in _agent.py (#5301) Extract event.data into a typed local variable before the isinstance check to avoid pyright narrowing it to AgentResponse[Unknown]. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix pyright reportMissingImports for orjson in file history samples (#5301) Add pyright: ignore[reportMissingImports] to orjson imports that are already guarded by try/except ImportError, matching the existing pattern used elsewhere in the samples. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5301: review comment fixes * Address review feedback for #5301: review comment fixes * Revert sequential_workflow_as_agent sample to FoundryChatClient Reverts the mistaken switch from FoundryChatClient to OpenAIChatClient in the sequential workflow as agent sample. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address ultrareview feedback: emit_data_events rename + WorkflowAgent reasoning conversion Layered on top of the prior review-feedback work in this branch. Renames: - AgentExecutor.emit_intermediate_data -> emit_data_events (mechanical rename; orchestration semantics live at the orchestration layer, not the general-purpose executor). Forwarded through MagenticAgentExecutor, AgentApprovalExecutor, and all orchestration call sites. - HandoffAgentExecutor._check_terminate_and_yield -> _should_terminate (pure predicate; no longer yields anything). HandoffBuilder docstring rewritten to describe the new per-agent AgentResponse output contract. WorkflowAgent reasoning-content conversion: - Add _rewrite_text_to_reasoning(contents) and _msg_as_reasoning(msg) helpers; the as_agent() path now reframes text content from data events as text_reasoning Content blocks before merging into the AgentResponse. - Consumers iterate msg.contents and branch on content.type — same path they already use for Claude thinking and OpenAI reasoning. No new field on Message/AgentResponse/WorkflowEvent. - Streaming branch constructs fresh AgentResponseUpdate instances instead of mutating shared payloads (regression test added). - Helper _msg_maybe_reasoning consolidates the conditional rewrite at three call sites in the non-streaming conversion. Tests: - TestWorkflowAgentReasoningHelpers + TestWorkflowAgentDataEventReasoningConversion add 9 new tests covering helpers, non-streaming, streaming, mixed content, already-reasoning passthrough, and mutation-safety regression. - Updated test_sequential_as_agent_with_intermediate_outputs_includes_chain to assert text_reasoning content for intermediate agents. * Fix pyright: widen event.data to Any to avoid partial-unknown narrowing The streaming conversion path narrowed event.data via isinstance against generic AgentResponse, producing AgentResponse[Unknown] and tripping reportUnknownVariableType/reportUnknownMemberType. Binding data: Any before the check keeps runtime behavior identical while restoring a fully known type for downstream access. * Clean up design * Scope to agent output semantics only * yield AgentResponseUpdate streaming, AgentResponse non-streaming * Fix mypy/pyright: widen cast types at GroupChat callsites Eight callsites in _group_chat.py still cast to WorkflowContext[Never, AgentResponse] but the base orchestrator methods now accept the wider WorkflowContext[Never, AgentResponse | AgentResponseUpdate] (mode-aware yields). W_OutT is invariant, so the narrower cast is not assignable. Magentic was widened in the same commit; this catches the GroupChat callsites that were missed. * Python: skip flaky Foundry / Foundry Hosting integration tests (#5553) These two integration tests have been failing in the merge queue across multiple unrelated PRs (5301, 5531). Both are marked `@pytest.mark.flaky` with 3 retries, but all attempts fail back-to-back. Skipping both with a reason pointing to #5553 so they can be fixed properly without continuing to block unrelated merges. - packages/foundry_hosting/tests/test_responses_int.py::TestOptions::test_temperature_and_max_tokens - packages/foundry/tests/foundry/test_foundry_embedding_client.py::TestFoundryEmbeddingIntegration::test_text_embedding_live Also includes a one-line uv.lock specifier-ordering normalization auto-applied by the poe-check pre-commit hook. --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evan Mattson ·
2026-04-29 00:35:36 +00:00 -
[Python] Add agent-framework-azure-ai-contentunderstanding package (#4829)
* feat: add agent-framework-azure-contentunderstanding package Add Azure Content Understanding integration as a context provider for the Agent Framework. The package automatically analyzes file attachments (documents, images, audio, video) using Azure CU and injects structured results (markdown, fields) into the LLM context. Key features: - Multi-document session state with status tracking (pending/ready/failed) - Configurable timeout with async background fallback for large files - Output filtering via AnalysisSection enum - Auto-registered list_documents() and get_analyzed_document() tools - Supports all CU modalities: documents, images, audio, video - Content limits enforcement (pages, file size, duration) - Binary stripping of supported files from input messages Public API: - ContentUnderstandingContextProvider (main class) - AnalysisSection (output section selector enum) - ContentLimits (configurable limits dataclass) Tests: 46 unit tests, 91% coverage, all linting and type checks pass. * fix: update CU fixtures with real API data, fix test assertions - Replace synthetic fixtures with real CU API responses (sanitized) - Update test assertions to match real data (Contoso vs CONTOSO, TotalAmount vs InvoiceTotal, field values from real analysis) - Add --pre install note in README (preview package) - Document unenforced ContentLimits fields (max_pages, duration) * chore: add connector .gitignore, update uv.lock * refactor: rename to azure-ai-contentunderstanding, fix CI issues Align naming with Azure SDK convention and AF pattern: - Directory: azure-contentunderstanding -> azure-ai-contentunderstanding - PyPI: agent-framework-azure-contentunderstanding -> agent-framework-azure-ai-contentunderstanding - Module: agent_framework_azure_contentunderstanding -> agent_framework_azure_ai_contentunderstanding CI fixes: - Inline conftest helpers to avoid cross-package import collision in xdist - Remove PyPI badge and dead API reference link from README (package not published yet) * feat: add samples (document_qa, invoice_processing, multimodal_chat) - document_qa.py: Single PDF upload, CU context provider, follow-up Q&A - invoice_processing.py: Structured field extraction with prebuilt-invoice - multimodal_chat.py: Multi-file session with status tracking - Add ruff per-file-ignores for samples/ directory - Update README with samples section, env vars, and run instructions * feat: add remaining samples (devui_multimodal_agent, large_doc_file_search) - S3: devui_multimodal_agent/ — DevUI web UI with CU-powered file analysis - S4: large_doc_file_search.py — CU extraction + OpenAI vector store RAG - Update README and samples/README.md with all 5 samples * feat: add file_search integration for large document RAG Add FileSearchConfig — when provided, CU-extracted markdown is automatically uploaded to an OpenAI vector store and a file_search tool is registered on the context. This enables token-efficient RAG retrieval for large documents without users needing to manage vector stores manually. - FileSearchConfig dataclass (openai_client, vector_store_name) - Auto-create vector store, upload markdown, register file_search tool - Auto-cleanup on close() - When file_search is enabled, skip full content injection (use RAG instead) - Update large_doc_file_search sample to use the integration - 4 new tests (50 total, 90% coverage) * fix: add key-based auth support to all samples Follow established AF pattern: check for API key env var first, fall back to AzureCliCredential. Supports AZURE_OPENAI_API_KEY and AZURE_CONTENTUNDERSTANDING_API_KEY environment variables. * FEATURE(python): add analyzer auto-detection, file_search RAG, and lazy init _context_provider.py: - Make analyzer_id optional (default None) with auto-detection by media type prefix: audio->audioSearch, video->videoSearch, else documentSearch - Add _ensure_initialized() for lazy client creation in before_run() - Add FileSearchConfig-based vector store upload - Fix: background-completed docs in file_search mode now upload to vector store instead of injecting full markdown into context messages - Add _pending_uploads queue for deferred vector store uploads devui_file_search_agent/ (new sample): - DevUI agent combining CU extraction + OpenAI file_search RAG azure_responses_agent (existing sample fix): - Add AzureCliCredential support and AZURE_AI_PROJECT_ENDPOINT fallback Tests (19 new), Docs updated (AGENTS.md, README.md) * feat(cu): MIME sniffing, media-aware formatting, unified timeout, vector store expiration - Add three-layer MIME detection (fast path → filetype binary sniff → filename fallback) to handle unreliable upstream MIME types (e.g. mp4 sent as application/octet-stream). Adds filetype>=1.2,<2 dependency. - Media-aware output formatting: video shows duration/resolution + all fields as JSON; audio promotes Summary as prose; document unchanged. - Unified timeout for all media types (removed file_search special-case that waited indefinitely for video/audio). All files use max_wait with background polling fallback. - Vector store created with expires_after=1 day as crash safety net. - Add 8 MIME sniffing tests (TestMimeSniffing class). * fix: merge all CU content segments for video/audio analysis CU's prebuilt-videoSearch and prebuilt-audioSearch analyzers split long media files into multiple `contents[]` segments. Previously, `_extract_sections()` only read `contents[0]`, causing truncated duration, missing transcript, and incomplete fields for any video/audio longer than a single scene. Now iterates all segments and merges: - duration: global min(startTimeMs) → max(endTimeMs) - markdown: concatenated with `---` separators - fields: same-named fields collected into per-segment list - metadata (kind, resolution): taken from first segment Single-segment results (documents, short audio) are unaffected. Update test fixture to realistic 3-segment video structure and expand assertions to verify multi-segment merging. Add documentation for multi-segment processing and speaker diarization limitation. * refactor: improve CU context provider docs and remove ContentLimits - Improve class docstring: clarify endpoint (Azure AI Foundry URL with example), credential (AzureKeyCredential vs Entra ID), and analyzer_id (prebuilt/custom with auto-selection behavior and reference links) - Add SUPPORTED_MEDIA_TYPES comments explaining MIME-based matching behavior and add missing file types per CU service docs - Use namespaced logger to align with other packages - Remove ContentLimits and related code/tests - Rename DEFAULT_MAX_WAIT to DEFAULT_MAX_WAIT_SECONDS for clarity * feat: support user-provided vector store in FileSearchConfig - Add vector_store_id field to FileSearchConfig (None = auto-create) - Track _owns_vector_store to only delete auto-created stores on close() - Remove vector_store_name; use internal _DEFAULT_VECTOR_STORE_NAME - Add inline comments for private state fields - Document output_sections default in docstring - Update AGENTS.md, samples, and tests * fix: remove ContentLimits from README code block * refactor: create CU client in __init__ instead of __aenter__ Follow Azure AI Search provider pattern: create the client eagerly in __init__, make __aenter__ a no-op. This ensures __aexit__/close() is always safe to call and eliminates the _ensure_initialized() workaround. * docs: add file_search param to class docstring * feat: introduce FileSearchBackend abstraction for cross-client support Replace direct OpenAI client usage with FileSearchBackend ABC: - OpenAIFileSearchBackend: for OpenAIChatClient (Responses API) - FoundryFileSearchBackend: for FoundryChatClient (Azure Foundry) - Shared base _OpenAICompatBackend for common vector store CRUD FileSearchConfig now takes a backend instead of openai_client. Factory methods from_openai() and from_foundry() for convenience. BREAKING: FileSearchConfig(openai_client=...) -> FileSearchConfig.from_openai(...) * refactor: FileSearchBackend abstraction + caller-owned vector store * fix: file_search reliability and sample improvements - Poll vector store indexing (create_and_poll) to ensure file_search returns results immediately after upload - Set status to failed when vector store upload fails - Skip get_analyzed_document tool in file_search mode to prevent LLM from bypassing RAG - Simplify sample auth: single credential, direct parameters - Use from_foundry backend for Foundry project endpoints * perf: set max_num_results=10 for file_search to reduce token usage * fix: move import to top of file (E402 lint) * chore: remove unused imports * fix: align azure-ai-contentunderstanding with MAF coding conventions - Add module-level docstrings to __init__.py and _context_provider.py - Use Self return type for __aenter__ (with typing_extensions fallback) - Use explicit typed params for __aexit__ signature - Add sync TokenCredential to AzureCredentialTypes union - Pass AGENT_FRAMEWORK_USER_AGENT to ContentUnderstandingClient - Remove unused ContentLimits from public API and tests - Fix FileSearchConfig tests to match refactored backend API - Fix lifecycle tests to match eager client initialization * refactor: improve CU context provider API surface and fix CI - Refactor _analyze_file to return DocumentEntry instead of mutating dict - Remove TokenCredential from AzureCredentialTypes (fixes mypy/pyright CI) - Remove OpenAIFileSearchBackend/FoundryFileSearchBackend from public API (internal to FileSearchConfig factory methods) - Remove DocumentStatus from public exports (implementation detail) - Update file_search comments to reflect backend-agnostic design - Add DocumentStatus enum, analysis/upload duration tracking - Add combined timeout for CU analysis + vector store upload * fix: improve file_search samples and move tool guidelines to context provider - Delete redundant devui_file_search_agent sample (duplicate of azure_openai variant) - Move tool usage guidelines from sample agent instructions into context provider (extend_instructions in step 6, applied automatically for all file_search users) - Fix file_search purpose: use from_foundry() for Azure OpenAI (purpose="assistants") - Add filename hint in upload instructions for targeted file_search queries - Reduce max_num_results from 10 to 3 in both devui samples - Simplify agent instructions in both samples (remove tool-specific guidance) * feat: improve source_id, integration tests, and content assertions - Rename DEFAULT_SOURCE_ID to "azure_ai_contentunderstanding" (matches azure_ai_search convention) - Improve source_id docstring to describe default value - Clarify _detect_and_strip_files docstring (CU-supported files) - Add invoice.pdf test fixture from Azure CU samples repo - Refactor integration tests to use invoice.pdf directly (assert instead of skip when fixture missing) - Add URI content test (Content.from_uri with external URL) - Add "CONTOSO LTD." content assertion to all integration tests - Use max_wait=None in integration tests (wait until complete) * feat: reject duplicate filenames, add integration tests and sample comments - Reject duplicate document keys in before_run (skip + warn LLM to rename) - Update _derive_doc_key docstring to document uniqueness constraint - Add unit tests for duplicate filename rejection (cross-turn and same-turn) - Add integration test for data URI content (from_uri with base64) - Add integration test for background analysis (max_wait timeout + resolve) - Add filename recommendation comments to all samples' Content.from_data() * chore: improve doc key derivation, comments, and README - Replace hash-based doc key with uuid4 for anonymous uploads (O(1), no payload traversal) - Remove hashlib import (no longer needed) - Add File Naming section to README (filename importance, duplicate rejection) - Improve inline comments (_derive_doc_key, _extract_binary, URL parsing) * test: strengthen _format_result assertions with exact expected strings - Replace loose 'in' checks with exact 'assert formatted == expected' for both multi-segment and single-segment format tests - Add object-type fields (ShippingAddress, Speakers) to test data to cover nested dict/list serialization - Add position-based ordering assertions to verify structural correctness (header -> markdown -> fields across segments) * refactor: move invoice.pdf to shared sample_assets directory - Move invoice.pdf from tests/cu/test_data/ to python/samples/shared/sample_assets/ as single source of truth - Add INVOICE_PDF_PATH constant in test_integration.py pointing to the shared location - Update document_qa.py, invoice_processing.py, large_doc_file_search.py to use invoice.pdf instead of sample.pdf * refactor: reorganize samples into numbered dirs and simplify auth - Move script samples into 01-get-started/ with numbered prefixes (01_document_qa, 02_multimodal_chat, 03_invoice_processing, 04_large_doc_file_search) - Move devui samples into 02-devui/ with 01-multimodal_agent and 02-file_search_agent/{azure_openai_backend,foundry_backend} - Move invoice.pdf to CU package-local samples/shared/sample_assets/ - Replace kwargs dicts with direct constructor calls; support both API key (AZURE_OPENAI_API_KEY) and AzureCliCredential - Update README sample table with new paths * fix: resolve CI lint errors (D205, RUF001, E501) - Fix D205: single-line docstring summary for _detect_and_strip_files - Fix RUF001: replace EN DASH with HYPHEN-MINUS in segment headers - Fix E501: wrap long assertion lines in tests - Also includes samples reorg and auth simplification * refactor: overhaul samples — FoundryChatClient, sessions, remove get_analyzed_document Samples: - Switch all samples from deprecated AzureOpenAIResponsesClient to FoundryChatClient - Add 02_multi_turn_session.py showing AgentSession persistence across turns - Rewrite 03_multimodal_chat.py with real PDF + audio + video (parallel analysis), per-modality follow-ups, cross-document question, elapsed time, user prompts, and input token counts - Renumber: 02->03 multimodal, 03->04 invoice, 04->05 file_search Context provider: - Remove get_analyzed_document tool -- full content is in conversation history via InMemoryHistoryProvider, no retrieval tool needed - Remove follow-up turn instructions about tools - Only list_documents tool remains (for status queries) - Update README to reflect tool removal * feat: add 05_background_analysis sample and fix 04 session/max_wait - Add 05_background_analysis.py demonstrating non-blocking CU analysis with max_wait=1s, status tracking via list_documents(), and automatic background task resolution on subsequent turns - Fix 04_invoice_processing.py: add max_wait=None and AgentSession - Rename 05→06 large_doc_file_search - Update README sample table * docs: update README and fix sample 06 README: - Switch Quick Start from AzureOpenAIResponsesClient to FoundryChatClient - Add AgentSession to Quick Start example - Fix status values: pending -> analyzing/uploading/ready/failed - Fix env var: AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME -> AZURE_OPENAI_DEPLOYMENT_NAME - Update samples section with new paths, link to samples/README.md - Update multi-segment description to reflect per-segment fields Sample 06: - Fix from_openai -> from_foundry for Azure endpoints - Add AgentSession and max_wait=None * docs: rewrite README — concise format, prerequisites, CU link * fix: resolve pyright errors in _format_result segment cast * docs: add numbered section comments and fresh sample output to all samples - Add numbered section comments (# 1. ..., # 2. ...) per SAMPLE_GUIDELINES - Re-run all 6 samples and update expected output with real results - Fix duplicate sample output blocks in 04 and 05 - Update README code example to use public invoice URL * feat: add load_settings support for env var configuration - Make endpoint optional in constructor — auto-loads from AZURE_CONTENTUNDERSTANDING_ENDPOINT env var via load_settings() - Add ContentUnderstandingSettings TypedDict - Add env_file_path/env_file_encoding params for .env file support - Add 4 unit tests: env var loading, explicit override, missing endpoint error, missing credential error - Update README with env var auto-resolution docs - Follows framework convention used by all other packages * docs: polish README — fix duplicate env var, add Next steps, service limits link * chore: trim invoice fixture from 199K to 33 lines Keep only VendorName, InvoiceTotal, DueDate, InvoiceDate, InvoiceId fields and first 500 chars of markdown. Strip spans/source/coordinates. Reduces fixture from 6.6MB to 1.2KB. * feat: per-file analyzer_id override via additional_properties - Read analyzer_id from Content.additional_properties for per-file override - Resolution order: per-file > provider-level > auto-detect by media type - Update class docstring documenting filename and analyzer_id properties - Update sample 04 to demonstrate per-file override (prebuilt-invoice) - Add unit test for per-file analyzer override * Trim PDF test fixture and clarify unique filename requirement - Trim analyze_pdf_result.json from 4427 to 23 lines by removing pages, words, lines, paragraphs, sections, spans, and source fields that are not used by any unit test. - Add docstring note that filename must be unique within a session; duplicate filenames are rejected and the file will not be analyzed. * Update python/packages/azure-ai-contentunderstanding/agent_framework_azure_ai_contentunderstanding/_context_provider.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update python/packages/azure-ai-contentunderstanding/agent_framework_azure_ai_contentunderstanding/_context_provider.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update python/packages/azure-ai-contentunderstanding/samples/02-devui/02-file_search_agent/azure_openai_backend/agent.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update python/packages/azure-ai-contentunderstanding/samples/02-devui/01-multimodal_agent/agent.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update python/packages/azure-ai-contentunderstanding/samples/01-get-started/06_large_doc_file_search.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix AGENTS.md to match implementation; remove unused variable in test helper AGENTS.md: - Remove _ensure_initialized() reference (client is created in __init__) - Fix multi-segment docs: segments kept as list, not merged into fields - Remove get_analyzed_document() reference (only list_documents registered) - Update sample names to match current directory structure test_context_provider.py: - Simplify _make_data_uri() — remove unused 'encoded' variable * Fix premature file_search instruction for background-completed docs - Change _resolve_pending_tasks() instruction from 'Use file_search' to 'being indexed' since the upload hasn't completed yet at that point. - Add LLM instruction on upload failure in step 1b so the agent can inform the user the document isn't searchable. * fix: wrap long line in devui agent instructions (E501) * Fix Copilot review: unused logger, stray code in README, await cancelled tasks - _file_search.py: Remove unused logger and logging import - 01-multimodal_agent/README.md: Remove accidentally pasted Python script - _context_provider.py close(): Await cancelled tasks before closing client to prevent 'Task destroyed but pending' warnings * Sanitize doc keys and fix duplicate filename re-injection - Add _sanitize_doc_key() to strip control characters, collapse whitespace, and cap length at 255 chars — prevents prompt injection via crafted filenames in extend_instructions() calls. - Track accepted doc_keys in step 3 so step 5 only injects content for files actually analyzed this turn, not pre-existing duplicates. - Soften duplicate upload instruction wording (remove IMPORTANT/caps). * fix: add type annotation to tasks_to_cancel for pyright * Move per-session mutable state to state dict for session isolation Previously _pending_tasks, _pending_uploads, and _uploaded_file_ids were stored on self, shared across all sessions. This caused cross-session leakage: Session A's background task results could be injected into Session B's context. Now these are stored in the per-session state dict. Global copies (_all_pending_tasks, _all_uploaded_file_ids) are kept on self only for best-effort cleanup in close(). Add 2 new TestSessionIsolation tests verifying that background tasks and resolved content stay within their originating session. * Remove unused AnalysisSection enum values Only MARKDOWN and FIELDS are handled by _extract_sections(). Remove FIELD_GROUNDING, TABLES, PARAGRAPHS, SECTIONS to avoid exposing dead options to users. * Recursively flatten object/array field values for cleaner LLM output - Use SDK .value property with recursive extraction for object/array fields - Object: AmountDue -> {Amount: 610, CurrencyCode: USD} (was raw SDK dict) - Array: LineItems -> list of flattened items (was raw SDK list) - Update invoice fixture with object/array fields from prebuilt-invoice - Add 3 unit tests for object, array, and nested object field extraction * Preserve sub-field confidence; compare full expected JSON in tests * Remove incorrect MIME aliases (audio/mp4, video/x-matroska) * feat: add AnalysisInput, content_range, warnings, and category support - Use SDK AnalysisInput model instead of raw body dict for begin_analyze - Forward content_range from additional_properties to CU (page/time ranges) - Extract CU warnings with code/message/target (ODataV4Format) into output - Include content-level category from classifier analyzers - Add 5 new tests: warnings, category, content_range forwarding - Fix pyright with explicit casts; fix en-dash lint (RUF002) * fix: falsy-0 bug in duration calc; improve test coverage - Fix start_time_ms=0 treated as falsy by 'or' short-circuit, use 'is None' checks instead for duration and segment time extraction - Update warnings test to use RAI ContentFiltered codes - Enrich warnings extraction to include code/message/target (ODataV4Format) - Add multi-segment video category test with per-segment assertions * refactor: split _context_provider.py into focused modules - Extract _constants.py: SUPPORTED_MEDIA_TYPES, MIME_ALIASES, analyzer maps - Extract _detection.py: file detection, MIME sniffing, doc key derivation - Extract _extraction.py: result extraction, field flattening, LLM formatting - _context_provider.py delegates via thin wrappers (793 lines, was 1255) - Update test imports to use _constants.py for SUPPORTED_MEDIA_TYPES * docs: update AGENTS.md with DocumentStatus, FileSearchBackend, and _file_search.py * refactor: replace AnalysisSection enum with Literal type for simpler DX - Remove AnalysisSection(str, Enum) class, replace with Literal["markdown", "fields"] type alias - Users can now pass plain strings: output_sections=["markdown"] — no extra import needed - AnalysisSection type alias still exported for type annotation use - Update all samples, tests, and internal code to use string literals - Address PR review feedback (eavanvalkenburg) * refactor: replace asyncio.Task with continuation tokens for serializable state - Replace state["_pending_tasks"] (asyncio.Task — not serializable) with state["_pending_tokens"] (dict of continuation token strings) so the framework can persist session state to disk/storage - Resume pending analyses via Azure SDK continuation_token mechanism - Fix: resumed pollers have stale cached status (done() always False), use asyncio.wait_for(poller.result()) with 10s min timeout instead - Remove _background_poll(), _all_pending_tasks, and task cancellation - Address PR review feedback (eavanvalkenburg): state must be serializable * fix: resolve CI lint (RUF052) and mypy (call-overload) errors * feat: add structured output (Pydantic model) to invoice processing sample - Use response_format=InvoiceResult for schema-constrained LLM output - Use output_sections=["fields"] only (no markdown needed for structured output) - Add LowConfidenceField model with confidence values - Add comments about prebuilt-invoice extensive schema vs simplified model - Address PR review feedback (eavanvalkenburg): use structured response * fix: use FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL env vars in all samples Replace AZURE_AI_PROJECT_ENDPOINT → FOUNDRY_PROJECT_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME → FOUNDRY_MODEL across all sample .py and README.md files. Address PR review feedback (eavanvalkenburg). * refactor: remove background_analysis sample, use FoundryChatClient in DevUI - Remove 05_background_analysis.py (per reviewer feedback — discuss max_wait design separately from samples) - Renumber 06_large_doc_file_search.py → 05_large_doc_file_search.py - Replace AzureOpenAIResponsesClient with FoundryChatClient in all DevUI samples - Replace client.as_agent() with Agent(client=client, ...) everywhere - Add max_wait comments explaining interactive vs batch usage - Update README.md and AGENTS.md - Address PR review feedback (eavanvalkenburg) * fix: vector_stores API moved from beta namespace in OpenAI SDK * docs: add comments about multi-file support and CU service limits in file_search sample * fix: broken markdown links after sample removal and renumbering * fix: migrate BaseContextProvider to ContextProvider (non-deprecated) * fix: Message(text=) -> Message(contents=[]) for API compatibility * Inline _constants.py into consuming modules Remove _constants.py and move constants to where they are used: - SUPPORTED_MEDIA_TYPES, MIME_ALIASES → _detection.py - MEDIA_TYPE_ANALYZER_MAP, DEFAULT_ANALYZER → _context_provider.py Addresses review feedback to reduce file count. * Mark package as alpha per package management skill - Version: 1.0.0b260401 → 1.0.0a260401 - Classifier: Development Status 4 - Beta → 3 - Alpha - Add to PACKAGE_STATUS.md as alpha Follows the alpha package checklist from python-package-management skill. * Replace extend_instructions with extend_messages for status notifications Status/error/result notifications now use extend_messages (conversation context) instead of extend_instructions (system prompt). This avoids system prompt bloat and keeps behavioral directives separate from event notifications. - 11 extend_instructions calls → extend_messages (role='user') - 1 extend_instructions retained: tool usage guidelines (behavioral) - 6 test assertions updated to check context_messages All 84 unit tests + 5 live integration tests pass. * Fix lint: E402 import order, ISC004 implicit string concatenation - Move constants after all imports to fix E402 - Wrap multi-line strings in parentheses inside contents=[] to fix ISC004 * Fix lint: remove unused json import in invoice sample * Fix CI: apply ruff format + fix E501 line length after reformatting ruff format expands Message() calls to multi-line, pushing string indentation deeper. Break long strings to fit within 120 char limit after formatting. Also removes unused json import in sample. * Address review feedback: keyword-only args, accept pre-built client, remove wrappers - All __init__ args now keyword-only (matches FoundryChatClient pattern) - New 'client' param accepts pre-built ContentUnderstandingClient - core dep bound: >=1.0.0rc5 → >=1.0.0,<2 - Self import moved after local imports - Removed 9 static method wrappers; callsites use module functions directly - Tests updated to import derive_doc_key and format_result directly * fix: remove duplicate ContentUnderstandingClient instantiation The client was being created twice — once inside the if/else block and again unconditionally after it. The second instantiation overwrote the pre-built client path and failed type checking when credential was None. * rename: azure-ai-contentunderstanding → azure-contentunderstanding Package: agent-framework-azure-ai-contentunderstanding → agent-framework-azure-contentunderstanding Module: agent_framework_azure_ai_contentunderstanding → agent_framework_azure_contentunderstanding Directory: packages/azure-ai-contentunderstanding → packages/azure-contentunderstanding Per agreement with PM and MAF team to drop 'AI' from the package name. * feat: add ContentUnderstanding re-export to agent_framework.foundry namespace Enables: from agent_framework.foundry import ContentUnderstandingContextProvider Exports: ContentUnderstandingContextProvider, FileSearchConfig, FileSearchBackend, AnalysisSection, DocumentStatus Updates all samples and README to use the foundry namespace import. * fix: add missing copyright headers to standalone sample scripts * chore: remove .vscode/settings.json and add to .gitignore * refactor: reuse FoundryChatClient.client for vector store ops in file_search sample Address review feedback from TaoChenOSU: - 05_large_doc_file_search.py: use client.client instead of manually constructing AsyncAzureOpenAI; remove openai dependency - azure_openai_backend/agent.py: import reorder only (AIProjectClient kept — required for sync vector store creation in DevUI) * fix: skip closing client when caller passes pre-built client When a ContentUnderstandingClient is passed via client=, the caller owns its lifecycle. Added _owns_client flag so close() only closes the client when we created it internally. --------- Co-authored-by: yungshinlin <yungshin@msn.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>Yung-Shin Lin ·
2026-04-28 20:55:59 +00:00 -
Python: bump package versions for 1.2.1 release (#5536)
* Python: bump package versions for 1.2.1 release PATCH bump (1.2.0 -> 1.2.1) for the released cohort. The release window covers two PRs, no new public APIs: - agent-framework-core: prevent inner_exception from being lost in AgentFrameworkException (#5167) - samples: add requirements.txt and .env.example to the a2a/ hosting sample for pip-based setup (#5510) Per lockstep convention, all 21 beta packages stamp 1.0.0b260428 and all 3 alpha packages stamp 1.0.0a260428, regardless of per-package code churn. Every non-core package floor on agent-framework-core is raised to >=1.2.1 to keep cohort signaling consistent. Date stamp reflects the local (Asia) cut date 2026-04-28. * Python: silence pyright unknown-type warnings in hosted-env detection `azure.ai.agentserver.core` is probed at runtime via `importlib.util.find_spec` and is not a declared dependency. The existing `# pyright: ignore[reportMissingImports]` suppresses the missing-import warning, but at `lowest-direct` resolution pyright still reports the imported symbol (`AgentConfig`) and its members (`from_env`, `is_hosted`) as unknown, breaking `validate-dependency-bounds-test` for `packages/core`. Extend the existing ignore to cover `reportUnknownVariableType` on the import and `reportUnknownMemberType` on the call site so the bounds check returns to green. Behavior is unchanged. Latent since #5455 (shipped in 1.2.0). * Python: raise agent-framework-gemini lower bound to google-genai>=1.65.0 The Gemini chat client references several `google.genai.types` symbols (`FileSearch`, `ThinkingLevel`, `SearchTypes`, `McpServer`, `StreamableHttpTransport`, plus call-site keyword args `mcp_servers` and `search_types`) that are not present at the lower bound of `google-genai>=1.0.0`. At `lowest-direct` resolution this caused `validate-dependency-bounds-test` to fail for `packages/gemini` with eleven `reportAttributeAccessIssue` / `reportUnknownVariableType` errors. Walking the upstream `google.genai.types` API: - `GoogleMaps`, `AuthConfig`: present from 1.40.0 - `FileSearch`: introduced in 1.49.0 - `ThinkingLevel`: introduced in 1.55.0 - `SearchTypes`, `McpServer`, `StreamableHttpTransport`: introduced in 1.65.0 Bump the lower bound to 1.65.0 — the minimum version that exposes every symbol the package actually uses. Keep the `<2.0.0` upper cap unchanged. With this bump `validate-dependency-bounds-test` passes for both lower and upper resolution scenarios across all 27 workspace packages. Latent since #4847 (Gemini package introduction in 1.1.0); aggravated by subsequent feature additions that pulled in newer `types.*` symbols. * Python: add dependabot bumps to 1.2.1 CHANGELOG Catalog the 15 dependabot dependency updates that merged on `upstream/main` between python-1.2.0 and the 1.2.1 cut window under a new Changed section: - Workspace dev/runtime deps: `rich`, `prek`, `python-multipart`, `pyasn1`, `pytest` (ag-ui, devui, lab), `uv` (lab) - Frontend deps: `vite` (devui, chatkit), `postcss` (devui, chatkit, handoff), `picomatch` (devui, handoff) CHANGELOG-only — no source or pyproject.toml changes. PRs themselves merged upstream independently of this release branch and will be brought in via the PR merge.
Evan Mattson ·
2026-04-28 18:23:26 +09:00 -
Python: Bump prek from 0.3.8 to 0.3.9 in /python (#5228)
* Bump prek from 0.3.8 to 0.3.9 in /python Bumps [prek](https://github.com/j178/prek) from 0.3.8 to 0.3.9. - [Release notes](https://github.com/j178/prek/releases) - [Changelog](https://github.com/j178/prek/blob/master/CHANGELOG.md) - [Commits](https://github.com/j178/prek/compare/v0.3.8...v0.3.9) --- updated-dependencies: - dependency-name: prek dependency-version: 0.3.9 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Fix CI: bump prek to 0.3.9 in lab package and update uv.lock Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/f17751e5-c5a8-4d42-9555-6bf708a2ef47 Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com>
dependabot[bot] ·
2026-04-28 09:08:58 +00:00 -
Bump vite from 7.1.12 to 7.3.2 in /python/packages/devui/frontend (#5127)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.1.12 to 7.3.2. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 7.3.2 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
dependabot[bot] ·
2026-04-28 08:08:21 +00:00 -
Python: Bump uv from 0.11.3 to 0.11.6 in /python/packages/lab (#5469)
* Bump uv from 0.11.3 to 0.11.6 in /python/packages/lab Bumps [uv](https://github.com/astral-sh/uv) from 0.11.3 to 0.11.6. - [Release notes](https://github.com/astral-sh/uv/releases) - [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/uv/compare/0.11.3...0.11.6) --- updated-dependencies: - dependency-name: uv dependency-version: 0.11.6 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> * Fix CI: update uv from 0.11.3 to 0.11.6 in python/pyproject.toml and regenerate uv.lock Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/a1a7c648-b26f-44e7-bace-d56ed8489053 Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com> * Fix code quality CI: update uv-pre-commit rev from 0.11.3 to 0.11.6 in .pre-commit-config.yaml Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/cdfdd211-9f1e-4570-bc7c-86fd15240e91 Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com>
dependabot[bot] ·
2026-04-28 07:24:43 +00:00 -
Python: Bump pytest from 9.0.2 to 9.0.3 in /python/packages/lab (#5470)
* Bump pytest from 9.0.2 to 9.0.3 in /python/packages/lab Bumps [pytest](https://github.com/pytest-dev/pytest) from 9.0.2 to 9.0.3. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/9.0.2...9.0.3) --- updated-dependencies: - dependency-name: pytest dependency-version: 9.0.3 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> * Update pytest from 9.0.2 to 9.0.3 across all workspace packages Fix dependency conflict: agent-framework workspace packages were pinning pytest==9.0.2 while agent-framework-lab required pytest==9.0.3, causing uv dependency resolution to fail. Updated all pyproject.toml files and regenerated uv.lock to use pytest==9.0.3 consistently. Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/d274f7c5-b5ed-4b18-8eab-4db3cfd9d1bf Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com>
dependabot[bot] ·
2026-04-28 07:24:23 +00:00 -
Bump postcss from 8.5.6 to 8.5.10 in /python/packages/devui/frontend (#5484)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.10. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.5.6...8.5.10) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.10 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
dependabot[bot] ·
2026-04-28 07:24:05 +00:00 -
Bump picomatch in /python/packages/devui/frontend (#4921)
Bumps and [picomatch](https://github.com/micromatch/picomatch). These dependencies needed to be updated together. Updates `picomatch` from 4.0.3 to 4.0.4 - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4) Updates `picomatch` from 2.3.1 to 2.3.2 - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4) --- updated-dependencies: - dependency-name: picomatch dependency-version: 4.0.4 dependency-type: indirect - dependency-name: picomatch dependency-version: 2.3.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
dependabot[bot] ·
2026-04-28 06:35:09 +00:00 -
Python: Update hosting agent samples + fixes (#5485)
* Update foundry hosting samples * Add file data type support * Fix file content and add more tests * Fix README * Address comments * Fix int tests * remove temp
Tao Chen ·
2026-04-28 04:24:05 +00:00 -
Python: Add
requirements.txtand.env.exampleto thea2a/sample for pip-based setup (#5510)* Add requirements.txt and .env.example to a2a sample Beginners following the a2a/ sample had no pip-based install path: the directory lacked requirements.txt and .env.example, unlike every other 04-hosting/ sample. - Add requirements.txt with editable local package paths matching the pattern used in azure_functions/ and similar hosting samples - Add .env.example documenting FOUNDRY_PROJECT_ENDPOINT, FOUNDRY_MODEL, and A2A_AGENT_HOST - Update README Quick Start to cover both pip (.venv) and uv workflows Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Add `requirements.txt` and `.env.example` to the `a2a/` sample for pip-based setup Fixes #5395 * fix(a2a-sample): address PR review feedback for issue #5395 - Remove 'from repo root' wording from Option B uv heading in README to avoid contradicting the 'run from this directory' instruction - Fix A2A_AGENT_HOST default in .env.example from 5001 to 5000 to match function-tools flow; add clarifying comments about port usage - Add note for pip users explaining they can replace 'uv run python' with 'python' once the virtual environment is activated Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5395: Python: [Samples][Python] a2a/ sample missing requirements.txt — beginners cannot install dependencies --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evan Mattson ·
2026-04-27 22:22:07 +00:00 -
Python: fix: prevent inner_exception from being lost in AgentFrameworkException (#5167)
* fix: prevent inner_exception from being lost in AgentFrameworkException The __init__ method unconditionally called super().__init__() after the conditional call with inner_exception, effectively overwriting the exception args and losing the inner_exception reference. Add else branch so super().__init__() is only called once with the correct arguments. Fixes #5155 Signed-off-by: bahtya <bahtyar153@qq.com> * test: add explicit tests for AgentFrameworkException inner_exception handling - test_exception_with_inner_exception: verifies args include inner exception - test_exception_without_inner_exception: verifies args only contain message - test_exception_inner_exception_none_explicit: verifies explicit None Covers both branches of the if/else in __init__. * fix: export AgentFrameworkException from package Bahtya --------- Signed-off-by: bahtya <bahtyar153@qq.com>
bahtyar ·
2026-04-27 04:53:06 +00:00 -
Python: Bump Python package versions for 1.2.0 release (#5468)
* Bump Python package versions for 1.2.0 release Released tier bumps 1.1.1 -> 1.2.0 (core, openai, foundry, root) to reflect additive public APIs landed since 1.1.0: functional workflow API (#4238) and FunctionTool SKIP_PARSING sentinel (#5424). All beta packages stamped 1.0.0b260424, alpha packages 1.0.0a260424. All 26 non-core agent-framework-core floors raised to >=1.2.0,<2. CHANGELOG consolidates the never-tagged 1.1.1 entries with the post-merge additions into [1.2.0]. * Update CHANGELOG footer links for 1.2.0 Advance [Unreleased] comparison base from python-1.1.0 to python-1.2.0 and add a [1.2.0] reference link comparing python-1.1.0...python-1.2.0 so the heading links resolve correctly. * Fix CHANGELOG: restore [1.1.1] section and add proper [1.2.0] Previous commit incorrectly renamed the [1.1.1] header to [1.2.0], which wiped the historical 1.1.1 entries and wrongly attributed them to 1.2.0. This restores [1.1.1] to its origin/main content and adds a new [1.2.0] section above containing only the commits in python-1.1.1..HEAD: - #4238 functional workflow API - #5142 GitHub Copilot OpenTelemetry - #2403 A2A bridge support - #5070 oauth_consent_request events in Foundry clients - #5447 FoundryAgent hosted agent sessions - #5459 hosting server dependency upgrade + types - #5389 AG-UI reasoning/multimodal parsing fix - #5440 stop [TOOLBOXES] warning spam - #5455 user agent prefix fix Also corrects the [1.2.0] compare base to python-1.1.1 (not 1.1.0) and adds the missing [1.1.1] reference link.
Evan Mattson ·
2026-04-24 19:54:59 +09:00 -
Python: Surface
oauth_consent_requestevents from Responses API in Foundry clients (#5070)* Fix Foundry clients not surfacing oauth_consent_request events (#5054) Override _parse_chunk_from_openai in both RawFoundryChatClient and RawFoundryAgentChatClient to intercept response.output_item.added events with item.type == 'oauth_consent_request'. The consent link is validated (HTTPS required) and converted to Content.from_oauth_consent_request, which the AG-UI layer already knows how to emit as a CUSTOM event. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review feedback for #5054 OAuth consent parsing - Extract shared helper (try_parse_oauth_consent_event) to avoid duplicated logic between RawFoundryChatClient and RawFoundryAgentChatClient - Use urllib.parse.urlparse() for HTTPS validation instead of case-sensitive startswith check - Sanitize log messages to avoid leaking consent_link tokens; log only item id - Add model=self.model to ChatResponseUpdate to match parent behavior - Add assertions on role, raw_representation, and model in happy-path tests - Add test for empty-string consent_link - Add test verifying non-oauth events delegate to super() Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Handle response.oauth_consent_requested top-level event (#5054) Add support for the top-level response.oauth_consent_requested stream event in addition to the response.output_item.added variant. The service may emit either form; handle both so the consent link is reliably surfaced. Extract _validate_consent_link helper within _oauth_helpers.py to reduce nesting. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5054: Python: [Bug]: `FoundryAgent` (Responses API) Does Not Surface `oauth_consent_request` as a CUSTOM AG-UI Event * Address review feedback: defensive getattr and dedicated helper tests (#5054) - Use getattr(event, 'type', None) in try_parse_oauth_consent_event for defensive access against malformed events without a type attribute - Add test_oauth_helpers.py with unit tests for _validate_consent_link and try_parse_oauth_consent_event covering edge cases: - HTTPS URL with empty netloc (https:///path) - Warning log messages for rejected consent links - Event objects missing 'type' attribute Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5054: Python: [Bug]: `FoundryAgent` (Responses API) Does Not Surface `oauth_consent_request` as a CUSTOM AG-UI Event * Fix mypy: match _parse_chunk_from_openai signature with superclass Add seen_reasoning_delta_item_ids parameter to _parse_chunk_from_openai overrides in both RawFoundryChatClient and RawFoundryAgentChatClient to match the updated superclass signature on main. Update super() calls and test assertions accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
Giles Odigwe ·
2026-04-24 09:59:14 +00:00 -
Python: (core): Add functional workflow API (#4238)
* Add functional workflow api * cleanup * More cleanup * address copilot feedback * Address PR feedbacK * updates * PR feedback * Address review comments on functional workflow samples - Swap 05/06 get-started samples: agent workflow first (motivates why workflows exist), simple text workflow second - Rename text_pipeline → text_workflow, poem_pipeline → poem_workflow - Add @step to agent workflow sample (05) to demonstrate caching - Switch agent samples to AzureOpenAIResponsesClient with Foundry - Remove .as_agent() from agent_integration.py to focus on the key difference between inline agent calls vs @step-cached calls - Add commented-out Agent.run example in hitl_review.py - Add clarifying comment in _functional.py that event streaming is buffered (not true per-token streaming) - Add naive_group_chat.py functional sample: round-robin group chat as a plain Python loop - Update READMEs to reflect new file names and group chat sample Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix pyright type errors * Address PR review comments on functional workflow API 1. Allow request_info inside @step: Auto-inject RunContext into step functions that declare a RunContext parameter (by type or name 'ctx'), and expose get_run_context() for programmatic access. 2. Handle None responses: Log a warning when a response value is None, and document the behavior in request_info docstring. 3. Add executor_bypassed event type: Replace executor_invoked + executor_completed with a single executor_bypassed event when a step replays from cache, making cached vs live execution explicit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add regression tests for PR review comments on functional workflow API The three review comments (request_info in @step, None response handling, executor_bypassed event type) were already addressed in 7da7db4e. This commit adds cross-cutting regression tests that exercise the interactions between these features: - HITL in step with caching: preceding step bypassed on resume - Full checkpoint lifecycle with HITL step (interrupt -> resume -> restore) - None response inside step-level request_info logs warning - WorkflowInterrupted from step does not emit executor_failed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR #4238 review comments on functional workflow API Comment 1 (request_info in @step): Already supported. Added comment in StepWrapper.__call__ explaining why WorkflowInterrupted (BaseException) safely bypasses the except Exception handler. Comment 2 (None response): Added docstring to _get_response clarifying the (found, value) return tuple semantics and None handling. Comment 3 (bypass event type): executor_bypassed is already a dedicated event type in WorkflowEventType. Updated comment at the bypass site to make the deliberate event type choice explicit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add experimental API warnings to functional workflow module Mark all public classes and decorators (workflow, step, RunContext, FunctionalWorkflow, StepWrapper, FunctionalWorkflowAgent) as experimental and subject to change or removal. * Address PR #4238 review comments from @eavanvalkenburg - RunContext docstring leads with purpose (opt-in handle for HITL, custom events, state) so readers importing it from the public surface understand its role before the mechanics (#2993513452). - Rename `06_first_functional_workflow.py` to `06_functional_workflow_basics.py`; the previous filename was confusing since it followed `05_functional_workflow_with_agents.py` (#2993531979). - Simplify `05_functional_workflow_with_agents.py` to call agents directly without a @step wrapper; the step-vs-no-step contrast lives in `03-workflows/functional/agent_integration.py`, keeping the get-started sample minimal (#2993525532). - Switch functional samples to `FoundryChatClient` for consistency with the rest of 01-get-started and 03-workflows (follow-up on #2876988570). - Use walrus in `hitl_review.py` final-state assertion (#2993572182). - Add expected-output block to `basic_streaming_pipeline.py` (#2993557609). - Clarify in `parallel_pipeline.py` that `@step` composes with `asyncio.gather` (#2993597282). - `naive_group_chat.py` threads `list[Message]` between turns instead of stringifying the transcript, preserving role/authorship (#2993583231). Drive-by: pre-commit hook sorts an unrelated import block in `samples/04-hosting/foundry-hosted-agents/responses/02_local_tools/main.py`. * Fix 10 functional-workflow API bugs from /ultrareview pass - bug_001: `ctx.request_info()` without an explicit `request_id` now derives a deterministic `auto::<index>` id from the call-counter, so HITL resume works correctly on the documented default path. A uuid was regenerated on every replay, making resume impossible. - bug_002: `StepWrapper.__call__` no longer deepcopies arguments on the cache-hit replay branch. The copy is only performed on the live-execution path (for the event log) and falls back to the original mapping if deepcopy fails, so steps whose args aren't deepcopyable (locks, sockets, sessions) can still resume from checkpoint. - bug_007: `_set_responses` now prunes each resolved `request_id` from `_pending_requests`, and the cache-hit branch in `request_info` does the same. Previously, answered requests were re-serialized into every subsequent checkpoint and the final checkpoint falsely claimed pending requests even after the workflow completed. - bug_008: `_compute_signature_hash` now mixes the function's `co_code` and `co_names` into the checkpoint signature, so changes to the workflow body invalidate older checkpoints even when steps are accessed via module / class attributes (which `_discover_step_names` can't see statically). `RunContext._record_observed_step` records observed step names for diagnostics. - bug_010: `FunctionalWorkflow.run()` docstring corrected — says "at least one of message/responses/checkpoint_id" and explicitly notes `responses` may be combined with `checkpoint_id` (the validator already allowed this). - bug_013: `FunctionalWorkflowAgent` now surfaces `request_info` events as `FunctionApprovalRequestContent` items (mirroring graph `WorkflowAgent`), threads `responses=` and `checkpoint_id=` through to the underlying workflow, and exposes `pending_requests`. Previously `.as_agent()` returned empty `AgentResponse` for HITL workflows — effectively unusable. - bug_014: `FunctionalWorkflow` now clears `_last_message`, `_last_step_cache`, and `_last_pending_request_ids` on clean completion. `run()` validates that `responses=` keys intersect the currently-pending request set (or raises with a clear error) instead of silently replaying against stale singleton state from a prior run. - bug_015: `FunctionalWorkflow.as_agent` signature now matches graph `Workflow.as_agent`: accepts `name`, `description`, `context_providers`, and `**kwargs`. `FunctionalWorkflowAgent` stores the overrides. - bug_017: `RunContext.set_state` raises `ValueError` for underscore- prefixed keys (the framework's `_step_cache` / `_original_message` keys would silently clobber user state on checkpoint save and user underscore-prefixed state was dropped on restore). Docstring documents the reserved prefix. - merged_bug_003: Workflow function arity is validated at decoration time. Multiple non-ctx parameters raise `ValueError` immediately (previously every arg past the first was silently dropped at call time). Passing a non-None `message` to a ctx-only workflow raises `ValueError` instead of silently discarding the message. Test coverage: +18 regression tests covering every fix. Full workflow suite now 766 passed, 1 skipped, 2 xfailed; full core suite 2338 passed. * Deslop functional.py fix commit - Remove dead instrumentation added in the prior commit that was never consumed: `RunContext._observed_step_names`, `RunContext._record_observed_step`, `FunctionalWorkflow._runtime_step_names`, and `FunctionalWorkflowAgent._extra_kwargs`. The signature hash relies on `co_code` alone, which covers the attribute-access case without the collection-scaffolding. - Trim over-explanatory comments that restated what the code does or what it no longer does. Keep only the comments that answer "why" for the non-obvious bits (deterministic id contract, defensive deepcopy, stale replay guard). - Compress the `_compute_signature_hash` and FunctionalWorkflow `__init__` block docstrings without losing the user-facing reasoning. Net -49 lines. Regression lock preserved (766 passed, 1 skipped, 2 xfailed). * Fix functional workflow review feedback --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <copilot@github.com>
Evan Mattson ·
2026-04-24 09:41:20 +00:00 -
Python: update FoundryAgent for hosted agent sessions (#5447)
* fixes to FoundryAgent to connect to new hosted agents Co-authored-by: Copilot <copilot@github.com> * fix mypy Co-authored-by: Copilot <copilot@github.com> * Python: remove Foundry service session helpers Remove the public hosted-agent service session CRUD helpers from FoundryAgent and drop the related feature-stage inventory entry. Update the hosted-agent sample to create and delete service sessions directly through the preview AIProjectClient APIs, and tighten a few test harnesses surfaced by full workspace validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix from merge * fix hosted env detection Co-authored-by: Copilot <copilot@github.com> * reverted sample update * fix tests and code Co-authored-by: Copilot <copilot@github.com> * remove aenter * skipping some tests Co-authored-by: Copilot <copilot@github.com> --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-04-24 09:25:03 +00:00 -
Python: Add OpenTelemetry integration for GitHubCopilotAgent (#5142)
* Python: Add OpenTelemetry integration for GitHubCopilotAgent - Split GitHubCopilotAgent into RawGitHubCopilotAgent (core, no OTel) and GitHubCopilotAgent(AgentTelemetryLayer, RawGitHubCopilotAgent) with tracing - Add default_options property to expose model for span attributes - Export RawGitHubCopilotAgent from all public namespaces - Add github_copilot_with_observability.py sample and update README * Python: Fix OTEL_SERVICE_NAME default in GitHub Copilot README Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Python: Add unit tests for RawGitHubCopilotAgent.default_options property * Python: Address review feedback on GitHubCopilotAgent OTel integration - Add middleware param to GitHubCopilotAgent.run() overloads so per-call middleware is explicitly forwarded through AgentTelemetryLayer - Remove github_copilot_with_observability.py sample per feedback; replace with inline snippet + link to observability samples in README * Python: Address review feedback on log_level and session kwargs typing - Add middleware param to RawGitHubCopilotAgent.run() overloads for interface compatibility with AgentTelemetryLayer - Fix import in README observability snippet to use agent_framework.github * Python: Add AgentMiddlewareLayer to GitHubCopilotAgent MRO Follow FoundryAgent pattern: AgentMiddlewareLayer runs outside the telemetry span so middleware execution time is not captured in traces. Overloads removed as AgentMiddlewareLayer.run() handles dispatch via MRO. * Python: Add explicit __init__ to GitHubCopilotAgent for auto-complete and docstrings * Python: Address review feedback on middleware warning and test assertions - Add assert "timeout" not in opts to test_default_options_includes_model_for_telemetry to document the intentional asymmetry where timeout is extracted into _settings and not returned in default_options. - Replace silent del middleware with a logged warning when per-run middleware is passed to RawGitHubCopilotAgent, making it clear that the GitHub Copilot SDK handles tool execution internally and chat/function middleware cannot be injected. * Python: Use Self for __aenter__ return type in RawGitHubCopilotAgent Address review feedback: use typing.Self (3.11+) / typing_extensions.Self (3.10) for __aenter__ so subclasses like GitHubCopilotAgent get the correct return type from async context manager usage. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Dineshsuriya D ·
2026-04-24 08:44:44 +00:00 -
Python: feat: Add Agent Framework to A2A bridge support (#2403)
* feat: Add Agent Framework to A2A bridge support - Implement A2A event adapter for converting agent messages to A2A protocol - Add A2A execution context for managing agent execution state - Implement A2A executor for running agents in A2A environment - Add comprehensive unit tests for event adapter, execution context, and executor - Update agent framework core A2A module exports and type stubs - Integrate thread management utilities for async execution - Add getting started sample for A2A agent framework integration - Update dependencies in uv.lock This integration enables agent framework agents to communicate and execute within the A2A (Agent to Agent) infrastructure. * fix: Update references from agent_thread_storage to _agent_thread_storage in A2A executor tests * Refactor A2A agent framework and improve code structure - Reordered imports in various files for consistency and clarity. - Updated `__all__` definitions to maintain a consistent order across modules. - Simplified method signatures by removing unnecessary line breaks. - Enhanced readability by adjusting formatting in several sections. - Removed redundant comments and example scenarios in the execution context. - Improved handling of agent messages in the event adapter. - Added type hints for better clarity and type checking. - Cleaned up test cases for better organization and readability. * fix: Lint fix new line added * test: Add unit tests for AgentThreadStorage and InMemoryAgentThreadStorage * refactor: Update type hints to use new syntax for Union and List * fix: Validate RequestContext for context_id and message before execution * Refactor tests and remove A2aExecutionContext references - Deleted the test file for A2aExecutionContext as it is no longer needed. - Updated A2aExecutor tests to remove dependencies on A2aExecutionContext and adjusted method calls accordingly. - Modified event adapter tests to use ChatMessage instead of AgentRunResponseUpdate. - Removed A2aExecutionContext from imports in agent_framework.a2a module and updated type hints accordingly. * Refactor A2AExecutor tests and remove event adapter - Updated test cases to use A2AExecutor instead of A2aExecutor for consistency. - Removed mock_event_adapter fixture and related tests as A2aEventAdapter is deprecated. - Consolidated event handling tests into TestA2AExecutorEventAdapter. - Adjusted imports in various files to reflect the removal of deprecated components. - Ensured all references to A2aExecutor are updated to A2AExecutor across the codebase. * refactor: Remove AgentThreadStorage and InMemoryAgentThreadStorage classes from threads and tests * feat: A2AExecutor to have its own override able save and get threads methods for persistent storage. * fix: linter bugs * removed unnecessary changes form core package * new line added * Refactor A2AExecutor tests and update imports - Consolidated mock agent fixtures in test_a2a_executor.py to simplify agent mocking. - Removed redundant tests related to thread storage and agent types, focusing on A2AExecutor's core functionality. - Updated test assertions to reflect changes in message handling with new Message and Content classes. - Enhanced integration tests to ensure compatibility with the new agent framework structure. - Added A2AExecutor to the module exports in __init__.py and __init__.pyi for better accessibility. * Update A2A documentation: enhance usage examples for A2AAgent and A2AExecutor * Updated uv lock * Fix metadata assertion in TestA2AExecutorHandleEvents and reorder load_dotenv call in agent_framework_to_a2a.py * Update agent card configuration: add default input and output modes, and fix agent creation method * Fix assertion for metadata in TestA2AExecutorHandleEvents * Fix formatting issues in TestA2AExecutorExecute and TestA2AExecutorIntegration * Enhance A2AExecutor documentation with examples and clarify agent execution process * Revert uv lock to main * Refactor A2AExecutor: Improve formatting and streamline constructor parameters * Apply suggestions from code review Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> * Refactor A2AExecutor to use SupportsAgentRun and enhance logging; update agent framework sample for flight and hotel booking capabilities * Enhance A2AExecutor with streaming support and custom run arguments; update tests for initialization and execution scenarios * Enhance A2AExecutor event handling with streamed artifact tracking; update tests for new behavior * Refactor A2AExecutor to enforce type hints for stream and run_kwargs attributes * Refactor A2AExecutor and tests: replace AsyncMock with MagicMock for response stream handling; clean up imports in agent_framework_to_a2a.py * refactor: streamline imports and improve code readability across multiple files * feat: enhance A2AExecutor cancel method with context validation and fixed review comments * feat: implement get_uri_data utility function for extracting base64 data from data URIs and update references * fix: update import path for get_uri_data utility function in A2AExecutor and A2AAgent * fix: correct error message handling in A2AExecutor and update test assertions --------- Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
Shubham Kumar ·
2026-04-24 08:35:40 +00:00 -
Python: Upgrade hosting server dependency and add more type support (#5459)
* Upgrade hosting server dependency and add more type support * Comments
Tao Chen ·
2026-04-24 07:27:17 +00:00 -
Python: Fix AG-UI reasoning role and multimodal media parsing to follow specification (#5389)
* Fix AG-UI reasoning role and multimodal media value field parsing Fix two spec compliance issues in the AG-UI integration: 1. ReasoningMessageStartEvent now uses role='reasoning' instead of role='assistant', matching the AG-UI specification for reasoning messages. 2. _parse_multimodal_media_part now reads the 'value' field from source dicts (with fallback to 'data' for backward compatibility), matching the current AG-UI InputContentSource specification. Bump ag-ui-protocol dependency from ==0.1.13 to >=0.1.16,<0.2 to pick up the SDK fix that accepts role='reasoning' in ReasoningMessageStartEvent. Fix pre-existing pyright reportMissingImports errors for orjson in sample files, and fix import ordering in foundry-hosted-agents sample. Fixes #5340 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Fix AG-UI reasoning role and multimodal media parsing to follow specification Fixes #5340 * Remove unintended .maf-runtime-ready marker file Address PR review feedback: the .maf-runtime-ready file is not referenced anywhere in the repo and was left over from automation. Fixes #5340 * Python: Fix duplicate AG-UI multimodal 'value' parsing in snapshot path The snapshot normalization path used a second copy of the multimodal source parsing logic that still read the deprecated 'data' field. When clients sent base64 media with source={"type": "base64", "value": ...}, the snapshot event emitted by the server dropped the payload, causing AG-UI-compatible clients to crash on ingest. Extract the shared source-field extraction into _extract_multimodal_source_fields so both _parse_multimodal_media_part and the snapshot _legacy_binary_part stay in sync with the AG-UI spec. Add snapshot-path regression tests covering value-only, value-preferred-over-data, and the legacy data-field fallback. Addresses review feedback on #5389 from @Rickyneer. --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evan Mattson ·
2026-04-24 04:12:34 +00:00 -
Python: Fix user agent prefix (#5455)
* Fix hosting user agent missing * Fix other providers * Add more tests * comments * Fix tests
Tao Chen ·
2026-04-23 23:40:38 +00:00