26b28b43863feeeefc9ddc696f91d589e773bb89
82 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ee27065359 |
Python: Update agentserver to x.1.0b1 (#7621)
* Update agentserver to 2.1.0 * Update agentserver responses and invocations to x.1.0b1 * Pass platform context to state store provider * Pass user id * Correct requirements.txt * Fix unit tests * Fix unit tests |
||
|
|
e85b3c8ba8 |
Python: Fix FHA session ID translation (#7608)
* Fix FHA session ID traslation * Fix tests * Address comments and fix tests * Fix typing * Show how to use user created sessions * Update README |
||
|
|
8d379168b2 |
Python: Improve python sample validation workflow (#7350)
* Add skill to replace hardcoded foundry project endpoint and model * Include more samples and fix migration samples part 1 * Fix migration samples * Replace Foundry hosted agent validation skill * Fix hosted agent file sample * Fix agent result format * Reorganize jobs * Update discovery heuristic for apps * Split agents into even more jobs * Add toolbox endpoint * Add more pre configured resources * Fix using deployed agent sample * Add sample status * Add playbook * Exclude hidden folder in sample discovery * Install autogen dependencies * Grant azure search RBAC role * Increase timeout for magentic * Build search resouce id deterministically * Remove grant in the workflow * Move azure cli login closer to when the sample actually runs * Refactor playbook * Fix using deployed agent sample * Actually save the playbooks * Fix action syntax error * Fix magentic sample * Address copilot comments * Fix link inspection * Address comments * Correct README * Fix playbook path * Remove trailing space |
||
|
|
5cc1b8e3c3 |
Python: Add hosted agent sample for the agent harness (#7010)
* Python: Add hosted agent sample for the agent harness * Disable file providers and fix call_server usage in hosted harness sample Addresses PR review: disable the harness file-memory and file-access providers so the headless sample doesn't expose file tools or write outside storage/, and correct the app.py docstring to match call_server.py (which takes no prompt argument). * Python: update hosted harness sample for current APIs --------- Co-authored-by: Evan Mattson <evan.mattson@microsoft.com> |
||
|
|
43309018be |
.NET and Python: Extract Durable Task and Azure Functions integrations (#7465)
* Extract Durable Task and Azure Functions integrations Remove the migrated implementations, samples, tests, documentation, and repository wiring now owned by microsoft/agent-framework-durable-extension. Preserve Python compatibility through the agent_framework.azure shim and agent-framework-core[all], and leave customer-facing redirects to the new repository. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6181dcf9-857b-43ea-9fd2-fcd6b175ffdd * Fix feature registry validation after extraction Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6181dcf9-857b-43ea-9fd2-fcd6b175ffdd * Narrow external feature package paths Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6181dcf9-857b-43ea-9fd2-fcd6b175ffdd --------- Copilot-Session: 6181dcf9-857b-43ea-9fd2-fcd6b175ffdd |
||
|
|
25ec4c3b5c |
Python: Support archive-type MCP skills (source, toolbox, sample) (#7121)
* Python: Support archive-type MCP skills in MCPSkillsSource Add `archive`-type skill support to `MCPSkillsSource` so an MCP server can advertise packaged skills (ZIP / TAR / gzip-compressed TAR) that are downloaded, safely unpacked to a local directory, and served like file-based skills, while keeping the guarantee that MCP-delivered scripts are never executed. - Dispatch `skill://index.json` entries by `type`: `skill-md` (existing, fetched on demand) and `archive` (new). Unknown types are skipped. - `_ArchiveEntryLoader` downloads, extracts, and prunes archive skills and delegates discovery to an internal `FileSkillsSource` created with no script extensions and no runner, so bundled scripts surface as read-only resources only. - Hardened stdlib extraction: path-traversal (zip-slip) guard, non-regular TAR member skipping, and file-count / uncompressed-size / download-size limits. - Configure via `archive_*` constructor kwargs (no options object, per Python conventions); use `CachingSkillsSource` for refresh rather than a source level refresh interval. - Fix `FileSkillsSource` to treat `None` extensions as "use defaults" and an empty tuple as "discover none" (an empty tuple previously fell back to defaults). Port of .NET PR #6631. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d * Propagate non-not-found archive download errors in MCPSkillsSource Only swallow "resource not found" MCP errors when downloading an archive resource; re-raise every other error (auth failure, INTERNAL_ERROR, connection drop, timeout) so a transient transport failure is not silently turned into a missing skill. This matches the existing failure model used by `_try_read_index` and `MCPSkill.get_resource`, and avoids a failed `CachingSkillsSource` refresh overwriting a previously cached list with a partial result. Add tests asserting archive-download INTERNAL_ERROR and ConnectionError propagate out of `get_skills`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d * Python: Expose archive skill options on FoundryToolbox and demo in sample - FoundryToolbox.as_skills_provider() now forwards the MCPSkillsSource archive options (archive_skills_directory, archive_resource_extensions, archive_resource_search_depth, archive_max_file_count, archive_max_size_bytes, archive_max_uncompressed_size_bytes). Only explicitly-set options are forwarded so unset ones keep the MCPSkillsSource defaults. This lets a hosted toolbox agent redirect archive extraction to a writable directory (the default is under the cwd, which may be read-only in a container). - Add unit tests covering default (no options forwarded) and override forwarding. - Update the 12_foundry_toolbox_mcp_skills sample to demonstrate all three progressive-disclosure stages with an archive skill: escalation-policy now ships a references/refund-matrix.md resource and is uploaded as a ZIP archive; main.py disables load_skill and read_skill_resource approval and points archive extraction at a temp directory. README, toolbox.yaml, and ignore files updated accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4f14f83d-1868-45c1-be1a-12f49a58ac36 * Python: Fix ty type error in toolbox archive-option test Cast provider._source to _FoundryToolboxSkillsSource before accessing the private _archive_options, so the ty checker (which runs over tests) resolves the concrete type instead of the SkillsSource base. Replaces the mypy-style type: ignore that ty did not honor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4f14f83d-1868-45c1-be1a-12f49a58ac36 * Rework archive-type skill support in MCPSkillsSource to unpack archives entirely in memory instead of extracting them to a local directory, and apply reviewer feedback. * Python: Raise on archive member path-traversal (zip-slip) Treat a `..` path-traversal member in an archive skill as a hostile archive and reject the whole skill, matching how the file-count and uncompressed-size limits reject a malformed archive (previously the member was silently skipped while the rest of the skill still loaded). - `_normalize_archive_member_name` now raises `ValueError` on a `..` escape; benign degenerate entries (empty, `.`, `/`) still return None (skipped) and absolute paths are still neutralized to relative. The raise propagates to `_ArchiveEntryLoader._build_skill`, which already skips the skill on error. - Update tests: traversal cases now assert a raise, and add an end-to-end test that a zip-slip archive drops the whole skill. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d * Python: Revert archive skill demo in toolbox MCP skills sample Restore the 12_foundry_toolbox_mcp_skills sample to its pre-PR, skill-md-only form (matching the .NET Agent_Step26_FoundryToolboxMcpSkills sample, which uses skill-md and no ZIP archive): - Revert main.py, toolbox.yaml, README.md, .azdignore, .dockerignore, and escalation-policy/SKILL.md to the single-file SKILL.md version. - Remove the archive demo files added by this PR (.gitignore and escalation-policy/references/refund-matrix.md). - Soften two README notes so they no longer claim archive skills are unsupported/silently dropped (this PR adds archive support); instead frame single-file SKILL.md as a focus choice and point to the archive_* options. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d * Python: Clarify archive framing in mcp_based_skill sample README The mcp_based_skill sample is a generic MCP consumer that discovers whatever the server advertises; it does not itself demonstrate archive skills. Reword the archive note so it reads as an MCPSkillsSource capability rather than a sample feature, and fix the stale "unpacked to a local directory" claim to "unpacked in memory" (matching the in-memory extraction implementation). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d Copilot-Session: 4f14f83d-1868-45c1-be1a-12f49a58ac36 |
||
|
|
28389df805 |
Python: Move SessionStore to core and persist Foundry Responses sessions (#7306)
* Python: Move session persistence into core Move SessionStore and durable msgspec-backed storage into core, restore sessions in Foundry Responses hosting with per-user isolation, and document the serialization design. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Address session persistence review feedback Harden scoped file paths and corruption recovery, preserve session serialization compatibility, clarify dependency placement, and add reproducible benchmark evidence. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Preserve session snapshot compatibility Deep-copy in-memory session writes and retain existing Telegram session keys so stored conversations continue resolving. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Simplify Foundry session isolation Add experimental FoundrySessionStore backed by Agent Server request context, remove resolver plumbing, and centralize v2 user isolation for sessions, checkpoints, and approvals. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Reduce Foundry session helper layering Inline the single-use request user accessor while keeping separate context validation, fingerprint, and directory helpers for their distinct callers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Clarify Foundry request context validation Separate fail-fast request validation from context retrieval so Responses no longer appears to discard a returned context. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Share Foundry request context helpers Move protocol validation and user-scope derivation into a dedicated request-context module, leaving the session-store module focused on storage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Restore Foundry checkpoint storage paths Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Simplify Foundry session storage paths Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Persist Foundry sessions under hosted home Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Make hosted path test platform independent Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Address session persistence review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Isolate Foundry session path handling Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Clarify Foundry session path terminology Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Align Foundry sessions with Responses continuity Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Finalize Foundry Responses session persistence Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Add session store feature usage telemetry Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Fix hosted per-call history persistence Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c --------- Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c |
||
|
|
80eb2570c7 | Remove indices in FHA sample names (#7405) | ||
|
|
59b979213a |
Python: Fix stale agent.json references in A2A sample (#7281)
Co-authored-by: Amit Dhawan <amit.dhawan@barco.com> |
||
|
|
0796af0c26 |
Python: add progressive A2A hosting adapters (#7258)
* Python: add progressive A2A hosting adapters Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 * Python: address A2A adapter review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 --------- Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 |
||
|
|
848443ac68 |
[BREAKING] Python: Ensure session isolation for FHA invocation impl (#7158)
* Ensure session isolation for FHA invocation impl * Fix type check errors * Add user isolation to sample |
||
|
|
d08200d00e |
Python: Bump package versions for 1.12.0 release (#7238)
* Bump Python package versions for 1.12.0 release Bump packages represented in the 1.12.0 changelog, promote Foundry Hosting, Azure Content Understanding, Gemini, Mistral, Monty, and Tools to beta, and apply the requested beta cohort date stamp. Root and core move to 1.12.0, released and RC packages use their selected increments, alpha packages including Hosting MCP use the 260721 stamp, and core floors are raised only for proven consumers. Copilot-Session: 2dd9980a-b869-4c16-8642-75b7a6d6ebdf * fix version in readme * Add Responses conversation ID changes to release notes Include the breaking Hosting Responses conversation ID helper changes from #7234 in the Python 1.12.0 changelog. Copilot-Session: 2dd9980a-b869-4c16-8642-75b7a6d6ebdf |
||
|
|
a70fe21298 |
[BREAKING] Python: add Responses conversation ID helper (#7234)
* Python: add Responses conversation ID helper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2dd9980a-b869-4c16-8642-75b7a6d6ebdf * Python: make Responses session flag optional Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2dd9980a-b869-4c16-8642-75b7a6d6ebdf * Python: correlate Responses session return types Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2dd9980a-b869-4c16-8642-75b7a6d6ebdf * Python: clarify Responses conversation parameter Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2dd9980a-b869-4c16-8642-75b7a6d6ebdf * Python: clarify streaming conversation parameter Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2dd9980a-b869-4c16-8642-75b7a6d6ebdf * Python: include conversation in created event Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2dd9980a-b869-4c16-8642-75b7a6d6ebdf * Python: warn on nonstandard Responses IDs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2dd9980a-b869-4c16-8642-75b7a6d6ebdf |
||
|
|
a1f3e536bc |
Python: Add MCP hosting helpers (#7209)
* Python: Add MCP hosting helpers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 * Python: Address MCP hosting review comments Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 * renamed to AgentMCPTool |
||
|
|
c218067646 |
Python: Consolidate dependency updates (#7204)
* Bump uv from 0.11.28 to 0.11.29 in /python Bumps [uv](https://github.com/astral-sh/uv) from 0.11.28 to 0.11.29. - [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.28...0.11.29) --- updated-dependencies: - dependency-name: uv dependency-version: 0.11.29 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Bump zuban from 0.8.2 to 0.9.0 in /python Bumps [zuban](https://github.com/zubanls/zubanls-python) from 0.8.2 to 0.9.0. - [Release notes](https://github.com/zubanls/zubanls-python/releases) - [Commits](https://github.com/zubanls/zubanls-python/compare/v0.8.2...v0.9.0) --- updated-dependencies: - dependency-name: zuban dependency-version: 0.9.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * PR #7146: Bump ty from 0.0.55 to 0.0.60 in /python * Bump ruff from 0.15.20 to 0.15.22 in /python Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.20 to 0.15.22. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.20...0.15.22) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.15.21 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Bump mypy from 2.2.0 to 2.3.0 in /python Bumps [mypy](https://github.com/python/mypy) from 2.2.0 to 2.3.0. - [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md) - [Commits](https://github.com/python/mypy/compare/v2.2.0...v2.3.0) --- updated-dependencies: - dependency-name: mypy dependency-version: 2.3.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Bump prek from 0.4.8 to 0.4.10 in /python Bumps [prek](https://github.com/j178/prek) from 0.4.8 to 0.4.10. - [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.4.8...v0.4.10) --- updated-dependencies: - dependency-name: prek dependency-version: 0.4.10 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Bump azure-ai-projects from 2.2.0 to 2.3.0 in /python Bumps azure-ai-projects from 2.2.0 to 2.3.0. --- updated-dependencies: - dependency-name: azure-ai-projects dependency-version: 2.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Bump types-python-dateutil in /python Bumps [types-python-dateutil](https://github.com/python/typeshed) from 2.9.0.20260518 to 2.9.0.20260716. - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-python-dateutil dependency-version: 2.9.0.20260716 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Bump mypy from 2.2.0 to 2.3.0 in /python Bumps [mypy](https://github.com/python/mypy) from 2.2.0 to 2.3.0. - [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md) - [Commits](https://github.com/python/mypy/compare/v2.2.0...v2.3.0) --- updated-dependencies: - dependency-name: mypy dependency-version: 2.3.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Bump botocore from 1.43.45 to 1.43.49 in /python Bumps [botocore](https://github.com/boto/botocore) from 1.43.45 to 1.43.49. - [Commits](https://github.com/boto/botocore/compare/1.43.45...1.43.49) --- updated-dependencies: - dependency-name: botocore dependency-version: 1.43.49 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * PRs #7144/#7147: Align lab uv and ruff pins * Regenerate lockfile for Python Dependabot PRs #7144-#7153 * Python: Support azure-ai-projects 2.3 session operations (#7150) * Python: Apply Ruff 0.15.22 suppression updates (#7147) * Python: Update tests for ty 0.0.60 (#7146) * Python: Update Foundry samples for azure-ai-projects 2.3 (#7150) * Python: Address dependency rollup review comments --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
b5e635ed4d |
Python: isolate hosted session snapshots (#7141)
* Python: isolate hosted session snapshots Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 75d26ffd-7dc7-46b3-9966-9aaebb7b6bc3 * Python: avoid duplicate conversation snapshots Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 75d26ffd-7dc7-46b3-9966-9aaebb7b6bc3 * added some notes in the docstring |
||
|
|
1036fa7438 |
Python: docs: add self-hosting sample snippets (#7104)
* docs: add self-hosting sample snippets Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 636b7fb2-381a-4d62-b5cf-d029efa3ad20 * docs: use stable hosting sample ranges Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 636b7fb2-381a-4d62-b5cf-d029efa3ad20 * docs: address hosting sample review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 636b7fb2-381a-4d62-b5cf-d029efa3ad20 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
bc59c72170 |
Python: Add A2A hosting helpers (#7050)
* Python: Add A2A hosting helpers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 * Python: Preserve final A2A streaming output Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 * Python: Clarify A2A conversion boundary Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 * Python: Document A2A sample auth boundary Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
5ab8877ba5 |
Python: HITL respond-URL addressing from inside workflows (#7001)
* feat(durabletask): surface HITL respond-URL addressing to workflow executors
Let a workflow notify a human reviewer (e.g. email an approval link) from inside the
graph, without the caller threading the instanceId/requestId by hand.
- durabletask: the orchestrator injects host_context {instance_id, workflow_name,
request_path_prefix} into each activity input; CapturingRunnerContext surfaces it as
host_metadata. No new core API.
- azurefunctions: WorkflowHitlContext.from_context(ctx) builds the canonical
respond/status URLs (returns None in-process so callers degrade gracefully).
Re-exported through the agent_framework.azure lazy namespace.
- Nested sub-workflows: the address context (root instance + workflow name +
accumulated {executor}~{ordinal}~ prefix) propagates down call_sub_orchestrator via a
new SUBWORKFLOW_ADDRESS_KEY marker, so an executor at any depth builds a URL that
targets the addressable top-level instance with a qualified request id. The per-child
ordinal matches the read-side enumerate() index used by the status/respond endpoints.
The marker is stripped from untrusted input alongside SUBWORKFLOW_INPUT_KEY
(confused-deputy / info-leak guard).
- Samples 12 and 13 reworked into the retry-safe two-step notify pattern: the emitter
generates an explicit request id and a downstream NotifyExecutor builds the URL and
notifies, so failed upstream retries never produce a dead link.
Tests: unit coverage for the metadata round-trip, address/ordinal agreement (fan-out at
depth and nested prefix accumulation), marker stripping, and URL building; integration
tests assert the helper-built URL equals the server respondUrl and resumes the run, for
both the flat (12) and nested (13) samples.
* refactor(durabletask): read back request_info id instead of generating one in samples
Add WorkflowHitlContext.pending_request_id(ctx), an async helper that returns the
id request_info just generated (read from the runner context's pending request-info
events). This works on any host via the core RunnerContext protocol method, so it
needs no core change.
Samples 12 and 13 now call request_info() and read the id back to forward to the
NotifyExecutor, instead of minting a uuid by hand and passing request_id=. The
read-back happens in the same activity execution that generated the id, so the
pending request event and the notify message still commit together with the same id
(retry-safe; failed upstream retries notify no one).
* docs(azurefunctions): document request_info id read-back and notify safety
Tighten pending_request_id docstring to require calling it immediately after request_info, and explain why that is safe on the durable host (each executor runs in its own activity with its own runner context, so the pending set only holds this executor's requests and the newest is the one just emitted). Document the two-step notify pattern in the 12 and 13 sample READMEs, including the downstream-notifier retry safety and the nested address-prefix propagation.
* fix(python): resolve ty typing error and address PR review comments
- test_subworkflow_orchestration: replace the mypy-only type:ignore[arg-type] with a cast so the ty checker passes too (the other four checkers already honored the ignore).
- samples 12/13 README: guard the notify snippet against None before build_respond_url to match the documented graceful-degradation behavior.
- integration tests 12/13: reword comments that implied request_info now generates an explicit uuid4; it generates the id internally by default.
* fix(python): honor configurable Functions route prefix and address HITL PR review
- Resolve the route prefix from host.json (extensions.http.routePrefix, default api) in a new azurefunctions _routes module, used by both the server endpoints and WorkflowHitlContext, so a custom or empty routePrefix no longer 404s respond/status URLs (was hardcoded /api/ in four places).
- Extract respond/status URL construction into one shared builder called from _app.py and _hitl_context.py, removing the sync-by-test duplication.
- Broaden loopback detection (localhost, 127.0.0.0/8, 0.0.0.0, ::1, [::1]) via a _is_loopback helper so local links use http.
- Pin the host_context key names as shared constants in durabletask so producer and azurefunctions consumer cannot drift.
- Reword a stale base_url comment to reference WEBSITE_HOSTNAME.
- Add unit tests for the route module and loopback handling.
* refactor(azurefunctions): derive server-side HITL URLs from the request URL
The run and status endpoints now derive the base URL and route prefix from the incoming request URL (the value the host actually routed) via split_request_url, so the caller-visible respond/status URLs no longer depend on reading host.json on the server. The in-workflow helper keeps reading host.json since it has no request context. Replaces strip_route_prefix and updates its tests.
* test(durabletask): enforce sub-workflow ordinal and read-index agreement
Extract the read-side subworkflows grouping into a shared _index_subworkflows helper (used by the orchestrator) and add test_readside_index_matches_dispatch_ordinal, which round-trips a fan-out through that helper and asserts subworkflows[executor][ordinal] resolves to the child the dispatch stamped that ordinal onto. Turns the previously comment-only write-ordinal / read-index invariant into a shared, CI-enforced one.
* fix(azurefunctions): suppress bandit B104 on loopback host set
|
||
|
|
56e9a8f74c |
Python: Make foundry toolbox MCP skills sample self-contained (#7099)
* Python: Make foundry toolbox MCP skills sample self-contained Rework sample 12 (foundry_toolbox_mcp_skills) so users can build it from zero with azd, mirroring samples 04 and 09: - Bundle two single-file SKILL.md skills (support-style, escalation-policy) and a skills-only toolbox.yaml (with one connectionless code_interpreter tool, required by `azd ai toolbox create`). - Rewrite the README as an azd-native, from-zero guide (create skills -> create toolbox -> set TOOLBOX_ENDPOINT -> run) and fix the stale MCPSkillsSource API description to match main.py. - Switch config from TOOLBOX_NAME to the versioned TOOLBOX_ENDPOINT (.env.example, agent.yaml, agent.manifest.yaml); add .azdignore. Also enable the sample to run unattended behind ResponsesHostServer: - Forward disable_load_skill_approval / disable_read_skill_resource_approval / disable_run_skill_script_approval from FoundryToolbox.as_skills_provider() to the underlying SkillsProvider, so load_skill needs no approval round-trip (the Responses host runs without an AgentSession, which the default approval flow requires). main.py now uses as_skills_provider(disable_load_skill_approval=True). - Add unit tests covering the default and overridden approval behaviour. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4f14f83d-1868-45c1-be1a-12f49a58ac36 * Python: Address PR review on toolbox MCP skills sample - Remove the unused parameters section from agent.manifest.yaml (TOOLBOX_ENDPOINT is supplied via environment_variables, matching sample 04). - README: state the sample is self-contained directly instead of contrasting with the C# sample. - README: describe skill discovery behaviour without naming the internal MCPSkillsSource class. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4f14f83d-1868-45c1-be1a-12f49a58ac36 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
7ca8bb55b6 |
Python: Add Telegram hosting helpers and samples (#7047)
* Python: Add Telegram hosting helpers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 * Python: Exclude Telegram samples from aggregate typing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 * Python: Address Telegram helper review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5d6987cd-1b67-4ba1-8b54-3c50da6e7607 * Python: Serialize Telegram webhook sessions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d76a9c32-d170-426d-a64f-b70958b08b12 |
||
|
|
54617557e6 |
Update Foundry branding (#6999)
Replace user-facing Azure AI Foundry branding with Microsoft Foundry across docs, samples, comments, and display text while preserving technical identifiers. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> |
||
|
|
c8fb491644 |
Python: docs: add env example files for durabletask samples (#5948)
* docs: add env example files for durabletask samples * docs: clarify env example values and comments * docs: set default Redis URL in streaming sample env example |
||
|
|
1aca7601b8 |
Python: Add hosting protocol helper surface (#6891)
* Add Python hosting protocol helper surface Introduce AgentFrameworkState and SessionStore for app-owned hosting routes, add Responses run conversion/rendering helpers, and update the local Responses sample to use native FastAPI routing with streaming support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix CI failures, session continuity, and streaming model reporting - Fix constrained TargetT TypeVar in AgentFrameworkState: split __init__ into per-shape overloads (instance/sync factory/async factory/awaitable) since a bound TypeVar combined with one big Callable/Awaitable union parameter was unsolvable across pyright/pyrefly/ty/zuban. - Fix _FakeAgent test fixtures to structurally satisfy SupportsAgentRun (matching attribute types and overloaded run()), which the above surfaced. - Add SessionStore.put() to alias an additional session id to an already-resolved session, and use it in the local_responses sample to fix a real session-continuity bug: previous_response_id rotates every turn, so without aliasing the newly minted response id, turn 3+ of a conversation silently lost all prior history. Verified against a live Foundry model across a 3-turn conversation. - Fix responses_stream_events_from_run to report the real model instead of the "agent" fallback: AgentResponse.from_updates never carries a raw representation forward, so capture model from the individual streamed updates' raw representations instead. Verified live. - Add response_model=None to the sample's FastAPI route (it could not boot at all: FastAPI tried to build a Pydantic response model from the JSONResponse | StreamingResponse return annotation). - Map responses_to_run's ValueError to HTTP 400 instead of a 500. - Add HTTP round-trip integration tests (packages/hosting-responses) that exercise the same FastAPI + AgentFrameworkState + Responses helper wiring as the sample via httpx.ASGITransport, including a regression test for the session-continuity fix. - Add Workflow-target test coverage, SessionStore.put/reset_session tests, and TypeError-path coverage to packages/hosting/tests/hosting/test_state.py. - Extend call_server.py / call_server_af.py to a third conversation turn so they actually exercise the continuity chain (previous scripts stopped at turn 2, which would never have revealed the bug above). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify session-continuity aliasing: fold put() into get() Per feedback: the growth of SessionStore was not the problem -- it's intentional, since OpenAI's previous_response_id is designed to let a caller continue (fork) from any earlier response, not just the latest one, so every response id has to stay independently resolvable. That part stays as-is. What was too complex was the call site: routes had to manually fetch a session and then conditionally alias it with a separate put() call. Folded that into a single get(session_id, alias=...) call instead: - SessionStore.get() gains an optional `alias` keyword that registers an additional id for the same session in the same call (no-op if alias is None or equal to session_id). Removed the separate put() method. - AgentFrameworkState.get_session() passes `alias` through. - local_responses sample and the HTTP round-trip integration tests now do `await state.get_session(lookup_id, alias=response_id)` instead of pulling the store out and orchestrating get()/put() by hand. - Documented that this in-memory SessionStore intentionally never evicts (by design, to support forking), and that a storage-backed replacement (Redis, a database, ...) is responsible for its own TTL/eviction policy. Verified against a live Foundry model across a 3-turn previous_response_id chain after the simplification. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Refine hosting state helpers Split the shared state surface into AgentState and WorkflowState, keep SessionStore and CheckpointStore as plain storage, and make state helpers responsible for get-or-create behavior. Update the Responses sample and HTTP round-trip tests to store the post-run session explicitly under the minted response id, and support WorkflowBuilder/orchestration-style builders via structural build() support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix hosting state test protocol fakes Widen fake agents' get_session service_session_id parameter to match the SupportsAgentRun protocol under the Python 3.11 test typing checkers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify Responses stream helper naming Rename responses_stream_events_from_run to responses_stream_from_run across exports, tests, docs, and the local Responses sample to align with the generic <protocol>_stream_from_run helper convention. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add state-level storage setters Add AgentState.set_session and WorkflowState.set_checkpoint_storage so app code can pair get-or-create helpers with explicit post-run storage without reaching into the underlying stores. Update Responses docs, tests, and sample to use state.set_session. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify WorkflowState checkpoint handling Remove CheckpointStore from WorkflowState so workflow checkpointing uses the existing CheckpointStorage abstraction directly. Keep WorkflowState focused on resolving workflow targets, including builders, and update hosting docs/tests accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Rename Responses streaming run helper Rename responses_stream_from_run to responses_from_streaming_run across the hosting-responses exports, tests, docs, and local Responses sample. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Align Python hosting spec with protocol helpers Rewrite SPEC-002 to match the accepted helper-first hosting ADR and the implementation PR: AgentState, WorkflowState, SessionStore, Responses helpers, app-owned security/state responsibilities, and the minimal FastAPI Responses shape. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove old Python hosting channel implementation Remove the unreleased AgentFrameworkHost/channel implementation, the old hosting-telegram package, and old host/channel samples. Keep agent-framework-hosting focused on AgentState, WorkflowState, and SessionStore, and keep hosting-responses focused on helper-first Responses conversion. Update SPEC-002 to match the accepted helper-first ADR and the implementation surface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Restore helper-first workflow sample Rebuild the local Responses workflow sample on the protocol-helper surface, add production-readiness cautions to the local hosting samples, and align file-backed workflow checkpoint/cursor storage under one sample storage root. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address hosting helper review feedback Handle streaming failures as terminal Responses SSE events, guard concurrent target/session initialization, and scope workflow sample checkpoint storage per continuation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clarify Responses sample continuation behavior Document unknown conversation_id behavior in the agent sample and make the workflow sample explicitly reject conversation_id while continuing to use responses_session_id for previous_response_id. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clarify Responses sample option policy Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
2aae66d063 |
Python: use writable runtime directory for Foundry Skills sample (#6606)
* fix: use writable skills download directory * fix: handle empty skills download directory override --------- Co-authored-by: malsabbagh05 <malsabbagh05@users.noreply.github.com> Co-authored-by: Tao Chen <taochen@microsoft.com> |
||
|
|
2889475bce |
docs: add prerequisite commands for Python hosting samples (#5935)
Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> |
||
|
|
b31c8981a4 |
Python: Add multi-tenant hosting hosting security consideration to a2a sample (#6983)
* Add multi-tenant hosting hosting security consideration to a2a sample * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
81e425b44f |
Python: [BREAKING] Durable Task multi-workflow hosting and sub-workflows (#6696)
* feat(durabletask): add workflow naming helpers (multi-workflow phase 0)
Foundation for hosting multiple workflows (and later sub-workflows) on one
durable task host. Adds a host-agnostic naming module that derives the stable
durable names a hosted workflow registers under.
- New `_workflows/naming.py`:
- `workflow_orchestrator_name(name)` -> `dafx-{name}` (orchestration name,
aligned byte-for-byte with .NET `WorkflowNamingHelper`).
- `workflow_name_from_orchestrator(name)` -> reverse, `None` when not prefixed.
- `validate_workflow_name(name)` -> rejects empty / malformed / auto-generated
`WorkflowBuilder-<uuid>` names (validate-and-reject rather than silently
sanitize, since the name becomes a durable identity and an HTTP route segment).
- `is_auto_generated_workflow_name(name)`, `DURABLE_NAME_PREFIX`.
- Export the helpers from the package public API.
- Mark `WORKFLOW_ORCHESTRATOR_NAME` deprecated in favor of per-workflow names
(kept functional; the single-workflow path still uses it until phase 1).
- 39 unit tests covering round-trips and validation.
Design: docs/design/durabletask-multiworkflow-and-subworkflows.md
* feat(durabletask): host multiple workflows per worker with scoped names (phase 1)
Enables hosting more than one MAF workflow on a single standalone Durable Task
worker, and aligns both hosts on workflow-scoped durable names so two co-hosted
workflows that reuse an executor id cannot collide.
Naming (shared, host-agnostic):
- orchestration: dafx-{workflowName} (matches .NET; the name DT tooling surfaces)
- non-agent activity / agent entity: dafx-{workflowName}-{executorId} (scoped)
- New naming helpers workflow_scoped_executor_id / workflow_executor_activity_name.
Standalone worker (agent-framework-durabletask):
- configure_workflow is now additive: stores workflows keyed by Workflow.name,
rejects duplicate / auto-generated (WorkflowBuilder-<uuid>) / invalid names,
registers one orchestrator per workflow plus its scoped activities/entities.
- The shared orchestrator dispatches scoped names derived from workflow.name.
- New registered_workflow_names property.
Client (DurableWorkflowClient):
- Optional default workflow_name on the client; start/run/stream accept a per-call
workflow_name and target dafx-{name}.
- Opt-in ownership validation on status/HITL methods: when a workflow name is
resolvable, an instance whose orchestration name does not match is treated as
not-found (status -> None, pending -> [], send_hitl_response / await -> raise),
mirroring the Azure Functions route-scoping check.
Azure Functions host (agent-framework-azurefunctions):
- Registration now uses the same scoped names so the shared orchestrator's
dispatch matches (single workflow per app for now; flat workflow/* routes kept).
- Workflow name is validated up front; workflow agents register under the scoped
entity id; _is_workflow_orchestration scopes to dafx-{workflow.name}.
Samples + tests:
- Durable Task and Azure Functions workflow samples now name their workflow.
- Unit tests cover multi-workflow registration, name validation, client targeting,
and ownership; integration tests target the named workflows.
WORKFLOW_ORCHESTRATOR_NAME remains exported (deprecated). This is a hard switch:
in-flight single-workflow instances created before upgrade (under the old
workflow_orchestrator name) will not resume.
Design: docs/design/durabletask-multiworkflow-and-subworkflows.md
* feat(azurefunctions): host multiple workflows per app with per-workflow routes (phase 2)
Completes multi-workflow hosting on the Azure Functions host, building on the
shared scoped-naming foundation from the worker phase.
AgentFunctionApp:
- New `workflows=` parameter accepting a list (keyed by each `Workflow.name`) or a
name->Workflow mapping; the existing `workflow=` is a single-workflow alias.
Both may be combined. Duplicate names and mapping-key/name mismatches are rejected.
- Each workflow registers its own `dafx-{name}` orchestration, workflow-scoped
activities/entities, and per-workflow HTTP routes:
`workflow/{name}/run`, `workflow/{name}/status/{instanceId}`,
`workflow/{name}/respond/{instanceId}/{requestId}`. Routes are always
per-workflow (even for a single workflow) so callers don't change URLs as an app
grows from one workflow to many.
- Route ownership check is per-workflow (`_is_owned_orchestration(status, name)`):
a leaked instance id for another orchestration -- or another workflow -- is
treated as not-found, extending the route-scoping defense.
- `get_agent(context, name, workflow_name=...)` resolves a workflow agent under its
scoped id; bare `agents=` registration keeps the standalone surface. New
`workflows` introspection property; `.workflow` now returns the sole workflow
(or None when several are hosted).
- Removed the now-unused flat-URL helper `_build_status_url` (handlers inline
per-workflow URLs).
Samples + tests:
- Azure Functions workflow samples (09-12) name their workflow; integration tests
target the per-workflow routes.
- Unit tests cover multi-workflow registration, duplicate/mapping/auto-name
rejection, and per-workflow ownership.
Note: sample README / demo.http route docs are updated in the docs phase.
Design: docs/design/durabletask-multiworkflow-and-subworkflows.md
* feat(durabletask): sub-workflows via durable child orchestrations (phase 3)
Run WorkflowExecutor nodes as durable child orchestrations on both hosts.
- Protocol: add call_sub_orchestrator to WorkflowOrchestrationContext, implemented by the durabletask and Azure Functions adapters.
- Registration: planner classifies WorkflowExecutor as subworkflow_executors; collect_hosted_workflows walks nested workflows (parent first, deduped by name). Both hosts recursively register every nested workflow's orchestration/agents/activities once; only top-level workflows get HTTP routes. Names validated up front before any registration side effects.
- Orchestrator: dispatch WorkflowExecutor nodes via call_sub_orchestrator(dafx-{innerName}) with deterministic child instance ids ({instanceId}::{executorId}::{counter}), a trusted-input marker carrying nesting depth (bounded at 25), and outputs routed as messages (default) or parent outputs (allow_direct_output).
- Tests: registration/collect, orchestrator prepare/process/unwrap, recursive registration on both hosts. Sample: 11_subworkflow.
* feat(durabletask): sub-workflow HITL via qualified request ids (phase 4)
Surface a nested sub-workflow's human-in-the-loop request behind the top-level instance (B2 single addressing surface).
- Orchestrator records dispatched sub-workflow child instance ids in its custom status (subworkflows map) before suspending in task_all, so the read side can reach a child's pending request while the parent is paused.
- Read side (durabletask client get_pending_hitl_requests; AF status route) recurses into nested child statuses, qualifying each nested request id as {executorId}::{requestId} (accumulated for deeper nesting).
- Write side (durabletask client send_hitl_response; AF respond route) splits a qualified id on '::', resolves the owning child orchestration via the parent's subworkflows map, and raises the event on the leaf child with the bare request id. Unknown/inactive sub-workflow -> error/404.
- Shared SUBWORKFLOW_REQUEST_SEPARATOR ('::') in naming so both hosts and the client agree. respondUrl/respond always targets the top-level instance.
- Tests: TestSubworkflowHitl (durabletask client, 7), TestAgentFunctionAppSubworkflowHitl (AF, 7). Sample: 12_subworkflow_hitl (HITL pause inside an embedded sub-workflow).
* docs(durabletask): ADR + sample route docs for multi-workflow and sub-workflows (phase 5)
- Add ADR-0030 capturing the multi-workflow and sub-workflow hosting decisions (naming, scoped inner names, per-workflow routes, child-orchestration sub-workflows, hard-switch migration, B2 sub-workflow HITL, scoped agent addressing) with considered alternatives; mark the design doc as implemented and link the ADR.
- Update Azure Functions workflow samples (09-12) README/demo.http to the per-workflow route shape (workflow/{name}/run|status|respond) introduced in phase 2.
- Extend the durabletask sample catalog with the workflow hosting patterns (08-12), including the new 11_subworkflow and 12_subworkflow_hitl samples.
* fix(durabletask): harden sub-workflow hosting + add sub-workflow integration tests
Post-review hardening of the multi-workflow / sub-workflow durable hosting:
- Trust boundary: strip the reserved sub-workflow envelope key from untrusted
client input at both host boundaries (DurableWorkflowClient.start_workflow and
the AF start route) so a forged envelope cannot reach the trusted pickle path.
- Nested HITL addressing: qualify nested pending requests by (executorId, ordinal)
using a '~' separator (was '::', which collided with core's auto::N functional
request ids); the parent status subworkflows map is now a per-executor list so
multiple children dispatched in one superstep stay independently addressable.
- Reject two different workflow instances that share a name (the same instance
reused by sibling nodes is still deduped); validate executor ids (separator-free,
length-bounded) when hosting durably.
- Remove the arbitrary sub-workflow nesting depth cap: a WorkflowExecutor wraps a
concrete Workflow so the nesting tree is finite at build time, and the durable
instance-id length limit is the natural ceiling (matches .NET, which has none).
Tests/samples:
- New durabletask integration tests for sub-workflow composition (11) and nested
sub-workflow HITL (12); new no-agent AF sub-workflow HITL sample (13) + test.
- Exempt no-agent samples from the model-credential gate in both integration
conftests so the nested-HITL plumbing is covered deterministically.
- Update durabletask sample 12 docs to the new qualified-id format.
Validated: 484 unit tests; durabletask integration 08/09/11/12 and AF 12/13 pass
against the live emulators; pyright 0 errors; ruff clean.
* fix(durabletask): address PR review feedback on naming, typing, and docs
- Unquote df.DurableOrchestrationClient annotations so pyupgrade passes.
- Narrow the split_subworkflow_request_id result before unpacking in a naming test so the strict type checkers pass.
- Correct the durabletask sample catalog to the {executor}~{ordinal}~{requestId} qualified id format.
- Reword the Azure Functions sub-workflow sample intro so it does not imply a difference from a same-numbered sample.
- Drop internal shorthand (B2, phase labels) from code comments.
* fix(durabletask): reject case-insensitive workflow name collisions
The route ownership guard compares the durable orchestration name with casefold(), but registration kept raw names as distinct keys. Hosting 'Orders' and 'orders' therefore succeeded while either workflow's status/respond route could operate on the other's instances. Reject case-insensitive name collisions at registration (within a composition via collect_hosted_workflows, and across registration calls via the case-folded _registered_orchestrations map and the top-level guard in both hosts) so the case-folded ownership boundary stays real. Single names of any case remain valid; only collisions are rejected.
* docs(durabletask): remove multiworkflow/subworkflow ADR and design docs
Drop the ADR and design exploration documents and the dangling docstring reference to them.
* refactor(durabletask): simplify workflow client status parsing and drop deprecated orchestrator-name symbols
Extract a shared _parse_custom_status helper in DurableWorkflowClient to remove duplicated custom-status JSON parsing across three call sites.
Drop the now-unused single-workflow compatibility shims WORKFLOW_ORCHESTRATOR_NAME and WorkflowRegistrationPlan.orchestrator_name, replaced by per-workflow workflow_orchestrator_name(name).
* fix(core): drop WORKFLOW_ORCHESTRATOR_NAME from agent_framework.azure re-exports
The constant was removed from agent-framework-durabletask, but the core azure lazy-loading namespace still re-exported it, breaking pyright in packages/core. Remove it from both the runtime _IMPORTS map and the .pyi stub.
* fix(durabletask): atomic multi-workflow registration and bubble sub-workflow events
Make configure_workflow / AgentFunctionApp registration atomic: check every cross-call name collision before mutating any state, so a colliding nested sub-workflow no longer leaves a host partially configured (with the top-level name stuck in the registry). Applied to both the standalone worker and the Functions app.
Bubble sub-workflow intermediate events: a workflow run as a child orchestration now returns a SUBWORKFLOW_RESULT_KEY envelope carrying its outputs plus event timeline, and the parent re-tags the child's intermediate events with the WorkflowExecutor node id and republishes them, matching the in-process WorkflowExecutor contract. Top-level runs still return a bare outputs list.
Adds cross-registration atomicity tests on both hosts and unit tests for the result envelope and event bubbling. Resolves review threads on _worker.py, orchestrator.py, and test coverage.
* fix(azurefunctions): widen workflow orchestrator wrapper return type
The shared run_workflow_orchestrator now returns list | dict (the sub-workflow result envelope), so the azurefunctions _workflow.py wrapper that delegates to it must widen its Generator return annotation to match. Caught by the package-level pyright in CI (Package Checks), which type-checks the whole package, not just the files changed in the previous commit.
|
||
|
|
fc10ef31bd |
Python: Add FHA declarative workflow sample (#6897)
* Add FHA declarative workflow sample * Address comments * Address comments |
||
|
|
0260ea0e61 |
Python: implement ADR-0029 service_session_id lifecycle mapping (#6724)
* python: implement ADR-0029 service_session_id lifecycle mapping - Extend AgentSession service_session_id to support structured values - Add agent-owned conversation id extraction for chat forwarding and telemetry - Migrate A2A durable continuation state to A2AServiceSessionId - Keep A2AAgentSession as compatibility shim and mark it deprecated - Update core/a2a tests and package guidance Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix service_session_id type fallout across packages Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix remaining test typing signatures for service_session_id Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix hosting test stubs for widened get_session type Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix remaining test stubs for get_session union type Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify A2A session state handling Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix import * Fix hosting-telegram test get_session typing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
08a09e7ebb |
Python: Update FHA samples after v2 changes (#6841)
* Update FHA samples after v2 changes * Add missing pakcage pin * Address comments |
||
|
|
7f3a2aec38 |
[BREAKING] Python: Foundry Hosted Agent V2 protocol upgrade (#6811)
* Upgrade to FHA protocol v2 + toolbox integration
* Scope checkpoints and approval storage by user id
* Add toolbox skills integration
* Fix formatting
* Add httpx lower and upper bound
* Update foundry-hosting package version
* Remove custom http client
* Revert "Remove custom http client"
This reverts commit
|
||
|
|
6dfcbc5c62 |
Python: support stable + preview Azure AI Search (Foundry IQ) API versions (#6603)
Update agent-framework-azure-ai-search to work across the stable/GA azure-search-documents SDK (12.0.0, api-version 2026-04-01) and the preview SDK (12.1.0b1, api-version 2026-05-01-preview) for both semantic and agentic modes. - Bump the dependency to azure-search-documents>=12.0.0,<13 and the package to 1.0.0b260618. - Add an api_version parameter (threaded into SearchClient, SearchIndexClient, and KnowledgeBaseRetrievalClient) plus STABLE_API_VERSION/PREVIEW_API_VERSION constants, re-exported from agent_framework.azure. - Auto-detect preview-only agentic features (output mode, low/medium reasoning effort) via _preview_features_active(), which requires both the preview SDK and a preview api-version; defaults (extractive + minimal) work on both channels and preview-only options raise an actionable error otherwise. - Make knowledge-base imports SDK-version resilient and fix the 12.x surface (k -> k_nearest_neighbors, defensive additional_properties). - Update tests (pass on both SDKs), docs, samples, CHANGELOG, and uv.lock. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
a1c37b69e0 |
[Generated by SRE Agent] Clarify identifier security guidance (#6510)
Co-authored-by: Azure SRE Agent <noreply@microsoft.com> Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> |
||
|
|
b8b43798b9 |
Python: Update FHA with toolbox sample with more auth methods (#6713)
* Update FHA with toolbox sample with more auth methods * Clean up * Clean up other samples |
||
|
|
d75f2286f4 |
Python: Add Telegram channel for agent-framework-hosting (#6698)
* Python: Add Telegram channel for agent-framework-hosting - Add agent-framework-hosting-telegram package with TelegramChannel supporting polling and webhook transports, streaming edits with Telegram Bot API rate limiting, per-chat serial workers, and multi-modal inbound/outbound (text, photo, document, voice) - Add local_telegram sample demonstrating multi-channel hosting with a TelegramChannel alongside ResponsesChannel, using per-chat FileHistoryProvider and a run_hook for Telegram persona temperature - Fix test layout: move tests to tests/hosting_telegram/ (no __init__.py) - Remove old [tool.mypy] section and mypy poe task; source type-checking is handled by pyright via shared_tasks - Update uv.lock, pyproject.toml workspace sources, and PACKAGE_STATUS.md Fixes #6588 Refs #6265 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Address Telegram channel CI failures and review feedback - Fix webhook secret validation to use constant-time compare_digest - Harden webhook update parsing: require integer chat IDs and guard slash-only commands - Fix streaming edge cases in TelegramChannel: - prevent edit worker deadlocks when text exceeds 4096 chars - prevent deadlock when placeholder send fails (message_id stays None) - enforce edit throttling with minimum interval sleep - honor send_typing_action=False in streaming mode - always forward final multimodal output (e.g. images), while avoiding duplicate text sends - Expand Telegram tests for slash-only command handling, non-int chat IDs, and streaming behavior (long text, final images, typing toggle) - Fix sample/docs feedback: - rename sample package to agent-framework-hosting-sample-local-telegram - switch sample uv.sources from feature branch to main - align docs/tool names with lookup_weather - fix broken links and server run instructions in README/call_server.py - align local_telegram app docstrings with reasoning hook behavior and strip model in responses_hook Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Fix TelegramChannel streaming to iterate contents for multimodal support - Remove stale PR reference from module docstring - Add Google-style docstring to TelegramChannel.__init__ documenting all keyword args - Fix _stream_to_chat to iterate update.contents instead of using getattr(update, 'text', None); text chunks are extracted from Content items with type='text', non-text content in updates is correctly ignored (images etc. are forwarded via the final response) - Update _FakeStreamUpdate test helper to use contents list matching the real AgentResponseUpdate API; add from_text/from_image class methods - Update _FakeResponseStream to accept _FakeStreamUpdate objects directly - Add test verifying multimodal stream updates don't corrupt text accumulator Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Split local_telegram into simple Telegram-only and new multi-channel sample local_telegram is now a focused Telegram-only sample: - Removes ResponsesChannel and all responses_hook code - Removes call_server.py (no HTTP endpoint to call) - Uses a deterministic lookup_weather tool (hash-based, not random) - Single run_hook that strips model and raises reasoning effort - Drops agent-framework-hosting-responses dependency New local_multi_channel sample shows running both channels at once: - ResponsesChannel + TelegramChannel sharing a FileHistoryProvider - Cross-channel session resumption via previous_response_id - call_server.py moved here (the Responses endpoint lives here now) - Demonstrates the multi-channel coordination story Update README table to list both samples with clear descriptions. Also delete personal_assistant/.venv which was not tracked but caused pyright to crawl the entire installed venv (thousands of files), making sample pyright checks hang indefinitely. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Fallback when Telegram final edit fails - only mark final edit as sent after a confirmed 2xx edit response - fall back to sendMessage when final edit returns a non-success status - add regression test covering failed final edit fallback behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Fix optional await_args typing in telegram test - assert await_args is not None before reading kwargs in streaming fallback test - resolves test-typing failures across mypy/pyright/ty/zuban for hosting-telegram Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
f2d02e58b3 |
Python: Add hosting core and Responses channel (#6580)
* Add Python hosting core and Responses channel Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address hosting core review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Adopt source pyright typing setup for hosting packages Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Cover ResponsesChannel custom path routing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Align hosting tests with package layout Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix hosting workflow fixture imports in aggregate tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Apply useful Responses channel hardening Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix hosting package typing checks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix hosting pyright under Python 3.11 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Avoid static diskcache dependency in hosting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix aggregate typing and Docker test resilience Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify local Responses workflow sample Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clarify generic hosting is not Foundry hosting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert "Clarify generic hosting is not Foundry hosting" This reverts commit 73b584d919053bed43a258d75dc2b76406e9c181. * Clarify isolation key source flexibility Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clarify isolation header reuse boundary Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Support multimodal Responses channel outputs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Preserve multimodal streaming Responses output Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Stream Responses output items from updates Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Improve Responses streaming output handling * Tighten Responses channel default option handling - Restore full option parsing in parse_responses_request: known fields are remapped (max_output_tokens→max_tokens, parallel_tool_calls→ allow_multiple_tool_calls), transport/session keys excluded, None values dropped, everything else forwarded as-is so run_hook can inspect the full set. - Add a default _strip_options_hook on ResponsesChannel that removes all parsed options before reaching the agent. Callers cannot inject generation params (temperature, instructions, tools, …) unless the host explicitly allows it. - A custom run_hook replaces the default entirely and receives the full ChannelRequest.options plus the raw protocol_request. - Update tests to cover remap, default-strip, and custom-hook paths. - Clarify host debug-log docstring to match new option flow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
7051a4920d |
Python: Add MCP as a hard dep in Foundry Hosting (#6634)
* Add MCP as a hard dep in Foundry Hosting * Pin GitHub SDK * Fix formatting * Fix formatting |
||
|
|
148f57020a |
Python: host MAF workflows on a standalone Durable Task worker (#6418)
* feat(durabletask): host MAF workflows on a standalone Durable Task worker
Add a host-agnostic workflow execution engine to agent-framework-durabletask so a MAF Workflow can run as a durable orchestration outside Azure Functions:
- WorkflowOrchestrationContext protocol + DurableTaskWorkflowContext adapter, the superstep orchestrator, serialization helpers, capturing runner context, and the shared non-agent activity body (including the yield-output classifier so intermediate executors are not surfaced as final outputs).
- DurableAIAgentWorker.configure_workflow auto-registers agent executors as entities, non-agent executors as activities, and the workflow orchestrator.
- plan_workflow_registration centralizes the 'what to register' decision so it can be shared across hosts.
- run_agent_coroutine runs all agent coroutines on one persistent event loop, fixing a cross-loop hang when shared chat clients/credentials bind their asyncio primitives to a dead loop.
- DurableWorkflowClient (start/await workflow + HITL discover/respond); DurableAIAgentClient stays agent-only.
* refactor(azurefunctions): delegate workflow execution to agent-framework-durabletask
AgentFunctionApp now reuses the shared orchestrator, activity body, and registration planner from agent_framework_durabletask instead of maintaining its own copies; _workflow.py becomes a thin host-specific adapter (AzureFunctionsWorkflowContext).
- Run agent entity coroutines on the shared persistent event loop, fixing the cross-loop hang.
- Relocate state-diff unit tests to the durabletask package; update entity loop tests.
* feat(core): expose durabletask workflow symbols via agent_framework.azure
Lazily re-export WORKFLOW_ORCHESTRATOR_NAME and DurableWorkflowClient from the agent_framework.azure namespace so standalone hosts can import them without depending on internal module paths.
* docs(samples): add standalone durabletask workflow and HITL samples
Add two samples under samples/04-hosting/durabletask demonstrating MAF workflows on a standalone Durable Task worker (no Azure Functions):
- 08_workflow: conditional spam-detection workflow started via DurableWorkflowClient.start_workflow / await_workflow_output.
- 09_workflow_hitl: content-moderation workflow that pauses with ctx.request_info and is resumed via DurableWorkflowClient.get_pending_hitl_requests / send_hitl_response.
Also add the durabletask workflow integration test (test_08_dt_workflow).
* fix: address PR review feedback
- Sanitize HITL external-event responses with strip_pickle_markers in the orchestrator (defense-in-depth for callers that bypass DurableWorkflowClient).
- Raise WorkflowConvergenceException when max_iterations is reached with pending messages, matching the core WorkflowRunner instead of silently returning partial output.
- Route falsy 'sent' messages (use 'is not None' instead of truthiness).
- Normalize None shared_state_snapshot/source_executor_ids in execute_workflow_activity.
- Cast Any returns in AzureFunctionsWorkflowContext to satisfy mypy/pyright.
- Fix sample docstrings to reference DurableWorkflowClient.
* fix: resolve pyright Package Checks errors
- Use typed locals instead of cast in AzureFunctionsWorkflowContext (mypy sees Any, pyright sees concrete types -> avoid reportUnnecessaryCast).
- Annotate shared_state_snapshot and cast partially-typed durabletask SDK returns / HITL custom-status parsing to satisfy reportUnknownVariableType/reportUnknownMemberType.
- Drop the dead deserialize/serialize re-export in _workflow.py and mark the intentional private _extract_message_content re-export.
* fix(durabletask): agent-executor identity and typed workflow input
Register each workflow agent entity under the executor id that the orchestrator dispatches to (instead of the agent name), so AgentExecutor(agent, id=...) works when the id differs from agent.name. The azure-functions host mirrors this.
Reconstruct the start executor declared input type from the workflow initial JSON payload in the shared engine (mirroring in-process delivery) instead of string-coercing it per host. Untrusted input is stripped of pickle markers before reconstruction to prevent deserialization RCE.
* fix(samples): type durable workflow start executors for reconstructed input
The HITL and parallel workflow samples no longer hand-parse a JSON string. Their start executors now declare their real input type (ContentSubmission / DocumentInput), which the durable engine reconstructs from the client payload before delivery.
* test(durabletask): unit coverage for registration, client, worker, and input coercion
Add unit tests for plan_workflow_registration, DurableWorkflowClient, the agent-executor identity registration (entity keyed by executor id), and the typed initial-input coercion including pickle-marker neutralization.
* test(durabletask): HITL and parallel durable workflow integration tests
Add an integration test for the standalone durabletask HITL workflow sample via a new workflow_client fixture. Re-enable the Azure Functions parallel workflow test, consolidated into one end-to-end case so the work-stealing xdist scheduler cannot spawn multiple func hosts for this sample.
* refactor(durabletask): group workflow modules into a _workflows subpackage
Move the eight workflow modules into a private _workflows/ subpackage and drop the redundant _workflow_ prefix (orchestrator.py, registration.py, activity.py, client.py, context.py, dt_context.py, runner_context.py, serialization.py). The public API and __all__ are unchanged; only direct internal-module imports were repointed (package __init__, the worker, the azure-functions shared shim, and the affected unit tests).
* fix(durabletask): harden workflow type resolution and HITL response handling
- resolve_type returns only real classes (avoids issubclass TypeError in reconstruct_to_type)
- re-wait on HITL responses rejected by pickle-marker sanitization instead of dropping the request and losing the run
- American spelling in strip_pickle_markers docstring
- unit tests for resolve_type
* fix(durabletask): treat async edge conditions as not-matched on the synchronous host
The durabletask orchestrator evaluates edge conditions synchronously and does not support async edge conditions. Such an edge is now treated as not matched (the edge is not traversed) rather than assuming a result. Adds unit coverage; full async-condition support will be handled separately.
* fix(durabletask): reconstruct typed workflow outputs at the host boundary
await_workflow_output and the Azure Functions status endpoint now decode the checkpoint-encoded outputs the shared activity produces, via a shared deserialize_workflow_output helper. The client returns the original objects; the AF endpoint emits clean domain JSON instead of checkpoint-marker dicts, keeping the two hosts consistent.
* fix(durabletask): address review findings on workflow hosting
- AF: register workflow agents through add_agent(entity_id=...) so they remain tracked in app.agents / get_agent() (restores documented behavior) while keying by the executor id the orchestrator dispatches to; mirrors DurableAIAgentWorker.add_agent.
- async bridge: treat the shared loop as reusable only while its backing thread is alive, so a dead loop thread is replaced instead of hanging future.result() forever.
- client: add get_runtime_status; the standalone HITL sample now stops polling and reports the real terminal state instead of a generic timeout.
- tests: guard send_hitl_response pickle-marker stripping and add get_runtime_status coverage.
* fix(durabletask): wait indefinitely for HITL responses, matching core
The durable workflow host previously raced HITL responses against a 72h timer and failed the orchestration on elapse. MAF core's request_info has no timeout concept (it waits for the response), and the .NET durable host waits too, so the durable Python host now does the same: it stays paused until a response arrives. Removes the hitl_timeout_hours parameter and DEFAULT_HITL_TIMEOUT_HOURS constant from both hosts. A configurable timeout can be added later once core defines the contract (what happens on elapse).
* feat(durabletask): typed workflow event streaming and async client API
Add a brokerless workflow event stream to the durable host. Each non-agent executor runs inside a durable activity that captures its real WorkflowEvents (with data payloads); the orchestrator replays them into the orchestration custom status after each superstep, and the client streams them back as typed WorkflowEvent objects with reconstructed data. Agent executors contribute synthesized invoked/completed lifecycle events.
Add async client methods run_workflow (start with optional wait) and stream_workflow (typed event iterator), plus is_replaying plumbing through the orchestration context protocol and both host adapters so live status is published only on non-replay execution.
* docs(samples): standalone durabletask workflow streaming sample
Add sample 10_workflow_streaming demonstrating the async DurableWorkflowClient API on a standalone Durable Task worker: run_workflow(wait=False) to start without blocking, then stream_workflow to consume typed WorkflowEvent objects as a WriterAgent -> ReviewerAgent -> publish pipeline runs.
* refactor(durabletask): internal-only checkpoint codec and host-scoped workflow event streaming
Two related hardening changes to the durable workflow hosting layer, plus a
rebase-restored improvement.
Internal-only serialization codec (MSRC follow-up):
- Rename serialize_value/deserialize_value -> _serialize_value/_deserialize_value
in the shared durabletask serialization module and update all call sites, so the
pickle-backed checkpoint codec is unambiguously framework-internal. Untrusted
input is still neutralized with strip_pickle_markers at the HTTP boundary.
- Remove the duplicate agent_framework_azurefunctions._serialization module and
import strip_pickle_markers from the shared durabletask module instead. Move its
unique serialization/strip-marker tests into the durabletask test suite.
Scope workflow event streaming to hosts that can carry it:
- Add WorkflowOrchestrationContext.supports_event_streaming. The standalone
DurableTask host returns True (no custom-status size cap, has a stream_workflow
consumer); the Azure Functions host returns False.
- The orchestrator now accumulates and publishes the WorkflowEvent timeline to the
orchestration custom status only when the host supports streaming. On Azure
Functions the custom status returns to its pre-streaming shape
({state[, pending_requests]}), which fixes orchestrator failures with
"The size of the JSON-serialized payload must not exceed 16 KB" and stops leaking
pickle markers into the HTTP status response. The Azure Functions status endpoint
never consumed the event stream.
Workflow start endpoint:
- Accept text/plain raw request bodies (fall back from get_json to the raw body),
restoring an improvement from main that the rebase conflict resolution dropped.
* fix(azurefunctions): scope workflow status/respond endpoints to the workflow orchestrator
The workflow/status/{instanceId} and workflow/respond/{instanceId}/{requestId}
HTTP endpoints resolved durable instances by ID only. The durable client looks up
IDs across every orchestration in the task hub (agent entities, any
user-registered orchestrations, and other apps sharing the hub), so a caller
holding one instance ID could read another orchestration's status -- including
pending HITL request payloads -- or inject external events into it.
Add AgentFunctionApp._is_workflow_orchestration() and gate both endpoints on it:
an instance whose orchestration name is not WORKFLOW_ORCHESTRATOR_NAME now returns
404 instead of leaking state or accepting events. send_hitl_response now fetches
the orchestration status and validates ownership before raising the external
event. Legitimate workflow instances are unaffected.
Mirrors the .NET fix in PR #6608.
* fix(durabletask): resolve CI typing failures
- serialization: rename _serialize_value/_deserialize_value back to
serialize_value/deserialize_value to follow the package convention for
cross-module internal helpers (matches strip_pickle_markers, resolve_type).
The leading underscore tripped pyright reportPrivateUsage on cross-module
imports under the strict source gate; internal-only status is preserved by
not exporting them from the public API.
- Remove type-ignore comments pyright flags as unnecessary
(reportUnnecessaryTypeIgnoreComment) in _worker.py, orchestrator.py,
serialization.py.
- test_08_dt_workflow: add AgentClientFactoryProtocol and annotate the
agent_client_factory fixture as type[AgentClientFactoryProtocol] (matching
test_01-07) so mypy/ty stop reporting "type has no attribute create".
- samples (08_workflow, 09_workflow_hitl): pass structured output via
FoundryChatOptions[Any](response_format=...) instead of a plain dict so the
samples pyright (basic) config accepts default_options.
---------
Co-authored-by: Gavin Aguiar <80794152+gavin-aguiar@users.noreply.github.com>
|
||
|
|
6e95517659 |
Python: Split type checkers by target (pyright source, 5 checkers on tests/samples) (#6443)
* Python: Split type checkers by target (pyright source, 5 checkers on tests/samples) Rework the typing setup along the lines of the 'too many type checkers' approach: - Pyright (strict) is now the sole source-code type checker; mypy is removed from source and its [tool.mypy] block becomes a relaxed profile used only for tests/samples. - Tests are checked by all five checkers (pyright relaxed, mypy, pyrefly, ty, zuban); samples by pyright, pyrefly, and ty. All run in a relaxed/ basic profile so authors aren't forced into over-annotation. - Add pyrightconfig.tests.json and bump sample pyright configs to basic. - Unify test/sample typing onto the same parallel fan-out used by source pyright via run_command_items in task_runner.py. - Make version-conditional imports symmetric: keep or drop the '# type: ignore' on both branches so results match across interpreter versions (local vs CI). - Update SKILL.md, DEV_SETUP.md, and CODING_STANDARD.md for the five gating checkers and pyright on source+tests+samples. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Fix merge regressions from main (typing + runtime) Merging main into the type-checker split branch surfaced regressions that the new five-checker test suite and unit tests caught: Runtime fixes: - anthropic: restore the dropped `cache_read_input_token_count` mapping in _parse_usage_from_anthropic (lost during merge conflict resolution). - gemini: _get_function_calling_mode test helper returned str(enum) ('FunctionCallingConfigMode.AUTO') instead of the enum value ('AUTO'). - openai: _response_id_from_token test helper was an infinite self-recursion; return token['response_id']. - orchestrations: reset output_events per approval iteration so the terminal output assertion counts only the final run. - core: drop a stale duplicate harness test whose message ('non-negative') contradicted the source ('positive'). - purview: import PolicyLocation/PolicyScope/ProtectionScopeActivities/ ExecutionMode used by the processor tests. Type-checker fixes (tests, relaxed profile): - core: pyright/mypy/pyrefly/ty/zuban green-ups across the harness, MCP, observability and types tests. - anthropic/openai: route provider-namespaced UsageDetails keys through a dict cast (extra_items TypedDict unsupported by mypy/ty). - purview: typed model constructors and cache-mock casts. - ag-ui: annotate WorkflowContext[Any, Any] so yield_output accepts test payloads, guard Optional forwarded_props, and ty-ignore intentional bad args. Source pyright (sole source checker) flagged unnecessary ignores newly introduced by merged code in core _tools.py and declarative _declarative_base.py. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Isolate per-package mypy cache in test-typing fan-out The parallel test-typing fan-out runs many mypy processes concurrently, all defaulting to a single shared ./.mypy_cache. Concurrent writes corrupt the cache and mypy aborts with INTERNAL ERROR (intermittently, depending on worker timing) -- which is why CI's Test Typing job failed on a shifting set of packages while a single-package run was fine. Give each mypy invocation an isolated cache dir keyed by its target paths so incremental caching still works per package without races. Other checkers (zuban/pyrefly/ty/pyright) maintain their own caches and are unaffected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Make lab pyright-only on source (drop source mypy) Lab was the last package still running mypy on its source code, requiring mypy-only `# type: ignore` comments that pyright (the sole source checker everywhere else) flags as unnecessary. Align lab with the rest of the monorepo: - Remove the lab source mypy poe tasks (mypy-gaia/lightning/tau2) and the now-dead strict [tool.mypy] config block. - Drop the 'Run lab mypy' CI step; lab source is type-checked by pyright only. Lab tests remain covered by the workspace test-typing fan-out (mypy, pyrefly, ty, zuban, pyright over tests using the relaxed root config). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Fix test-typing regressions from latest main merge A fresh merge from main brought in new test code never run under the five-checker test-typing suite. Green up across the affected packages: - core: narrow Optional span.attributes with 'and' guards in span filters and assert+cast the json.loads(...attributes[...]) reads (test_observability); match the existing as_agent ignore on the protocol-typed fixture (test_clients). - openai: align new streaming tests with the established chat_options dict pattern (ChatOptions TypedDict isn't assignable to dict), route Optional .annotations[0] access through a small _first_annotation helper (mirrors the file's assert-not-None convention), and annotate a mapped ResponseStream. - foundry_hosting: annotate error: dict[str, Any] = body.get(...) or {} (zuban needs the annotation). - foundry: narrow ignores for the live AIProjectClient credential arg (pyrefly) and connections.get_default (zuban) SDK type gaps. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * updated pyright version * pyright fix * Python: Fix source typing for pyright 1.1.410 Pyright 1.1.410 tightened several checks. Apply the same source fixes as upstream PR #6275: - anthropic: import AsyncAnthropicBedrock from anthropic.lib.bedrock and AsyncAnthropicVertex from anthropic.lib.vertex (no longer re-exported from the anthropic top-level package -> reportPrivateImportUsage). - core _types.py: cast the transform-hook result to UpdateT (reportAssignmentType). - core _workflows/_events.py: annotate the @contextmanager helper as Generator[None] instead of Iterator[None] (reportDeprecated). - redis: build the combined filter expression with an explicit loop instead of reduce(and_, ...), which pyright could no longer fully type (drops the now unused functools.reduce / operator.and_ imports). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Accept plain-text body in Azure Functions workflow/run endpoint The workflow_orchestrator already accepts plain strings as well as JSON objects via context.get_input(), but the start_workflow_orchestration HTTP handler only accepted JSON and returned 400 for any non-JSON body. This made the functions integration tests that POST text/plain to /api/workflow/run (e.g. test_09_workflow_shared_state) fail consistently with 400 != 202. Fall back to the raw request body (decoded as UTF-8) when the body is not JSON, rejecting only a truly empty body. The JSON path is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
caa75f7cdd |
Python: Add Foundry Toolbox MCP skills hosted agent sample (#6363)
* Add 12_foundry_toolbox_mcp_skills hosted agent sample Demonstrates using MCPSkillsSource with a Foundry Toolbox MCP endpoint to discover and serve skills via SkillsProvider (progressive disclosure). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix env var reference in README and reuse local var in main.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Require AZURE_AI_MODEL_DEPLOYMENT_NAME and use placeholder in .env.example Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Document Toolbox MCP skills vs Foundry Skills in sample README Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Reference 12_foundry_toolbox_mcp_skills in parent README Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: SergeyMenshykh <SergeMenshikh@outlook.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
9cafd7e58b |
Python: Refactor workflow as agent pending request handling (#6259)
* WIP: Refactor Workflow as agent pending request handling * WIP: debugging empty message bug * Working: Workflow as agent with function approval * Address Copilot comments * Fix mypy * Address comments and fix pipeline * Request info non function approval now becomes function call * Revert uv.lock * Fix mypy * Bump min version of azure-ai-project * Remove RequestInfoFunctionArgs * fix tests * Fix failing tests * Fix sample |
||
|
|
dbc312a78a |
Python: Fix toolbox consent flow in hosted agent (#6249)
* Fix toolbox consent flow in hosted agent * Resolve conflict * Make unused tool as comment * Fix tests |
||
|
|
5affc9c333 |
Python: Reorganize A2A samples and use package A2AExecutor (#6165)
* Reorganize A2A samples: client demos in 02-agents, use package A2AExecutor - Move client samples (agent_with_a2a, a2a_agent_as_function_tools) to samples/02-agents/a2a/ - Add new concept samples: polling, stream reconnection, protocol selection - Replace sample agent_executor.py with package-level A2AExecutor (stream=True) - Update 04-hosting/a2a to focus on server-side, point to 02-agents for clients - Add README.md for the new 02-agents/a2a/ sample collection Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix streaming artifact coalescing and address PR review feedback A2AExecutor fix: - Generate a stable artifact_id per stream in _run_stream so all streaming chunks share the same ID, enabling proper append=True coalescing per the A2A spec (TaskArtifactUpdateEvent with same artifactId). - Previously, item.message_id was None for OpenAI/Foundry streaming updates, causing the SDK to generate a new random UUID per token (100+ separate artifacts instead of 1 appended artifact). Sample improvements: - Replace join workaround with response.text now that coalescing works - Add background=True to stream reconnection resume call (required for continuation token emission on in-progress tasks) - Fix type ignore specificity in polling sample Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
e532ced950 |
Add hosting samples overview README (#5407)
Co-authored-by: whenpoem <187613766+whenpoem@users.noreply.github.com> |
||
|
|
d74d26c917 |
Python: Show more authentication methods in Foundry Toolbox MCP (#5719)
* Show more authentication methods in Foundry Toolbox MCP * Remove hardcoded toolbox version num * Add Foundry MCP OAuth consent handling * Use message instead of the dedicated item type * Go back to using OAuthConsentRequestOutputItem * WIP: sample testing * Update error code * Address review on Foundry Toolbox MCP samples Reviewed feedback addressed: - Drop the branch-pinned `git+https://...@feature/...` entries from `04_foundry_toolbox/requirements.txt`; restore the simple comment + `mcp` runtime dep. The git pins were only useful while iterating on the PR and shouldn't ship. (eavanvalkenburg) - Fix the `/toolsets/` typo in both `04_foundry_toolbox/README.md` and `06_files/README.md`. Verified empirically against the research_toolbox in the test workspace: the toolbox MCP gateway lives at `/toolboxes/{name}/mcp?api-version=v1` and requires the `Foundry-Features: Toolboxes=V1Preview` header. `/toolsets/{name}/mcp` returns 403 with `preview_feature_required: Toolsets=V1Preview` (a different opt-in feature). - Wrap `httpx.AsyncClient(...)` in `async with ... as http_client:` in both samples so the connection pool is cleaned up. (Copilot reviewer) - Make the `TOOLBOX_NAME` env var consistent in both samples. Previously the tool name silently fell back to `"toolbox"` when `TOOLBOX_NAME` was unset, but `resolve_toolbox_endpoint()` still required `TOOLBOX_NAME` and would raise `KeyError`. The samples now resolve the endpoint once and derive the tool name from the resolved URL when `TOOLBOX_NAME` isn't set, so the local tool name always matches the upstream toolbox identity regardless of which env var the user set. (Copilot reviewer) - Rename `_responses.is_consent_error` to `consent_url_from_error`: the helper returns `str | None` (the consent URL), not a bool, so the new name matches behavior. Update the test class accordingly. (eavanvalkenburg) - Tighten `_handle_inner_agent`'s lazy-entry catch from `Exception` to `AgentFrameworkException`, the type the MCP layer actually wraps consent errors in via `MCPStreamableHTTPTool.__aenter__` → `ToolExecutionException(inner_exception=mcp_error)`. Network failures, cancellations, and other non-framework exceptions now propagate normally instead of being briefly caught and re-raised. The test helper `_make_consent_error` is updated to use `ToolExecutionException` so it matches the real-world wrapping. (eavanvalkenburg) - Clarify the `github_pat` description in `agent.manifest.yaml` to note it's only needed when the PAT-based connection (`github-mcp-pat-conn`) is chosen; users selecting the OAuth2 connection (`github-mcp-oauth-conn`) can leave it empty. (Copilot reviewer) Validation: ran both samples end-to-end against a real Foundry toolbox (`research_toolbox`) -- the samples connect successfully and the agent lists the toolbox's MCP tools (`api_specs___fetch_azure_rest_api_docs`, etc.). `uv run poe test -P foundry_hosting` passes (119 tests), pyright + mypy clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: fix broken Foundry samples link in 04_foundry_toolbox README The previous URL pointed to an old location of the toolbox supported-scenarios doc; the doc moved to /samples/python/hosted-agents/SUPPORTED_TOOLBOX_SCENARIOS.md and the old /samples/python/toolbox/azd path now 404s. Caught by the markdown-link-check CI step. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
72a6157c6a |
[BREAKING] Python: Enable instrumentation by default (#5865)
* Enable instrumentation by default * Update samples * Optimization when span is not recording * Address Copilot comments * Revert uv.lock * Add warning * Formatting * Fix mypy * Add disable_instrumentation() with sticky user-intent semantics Add a public disable_instrumentation() entry point so users can explicitly opt out of Agent Framework telemetry, with a sticky-disable flag that makes the user's intent "leading" — no framework code path (foundry's configure_azure_monitor, configure_otel_providers, enable_instrumentation, enable_sensitive_telemetry, or direct OBSERVABILITY_SETTINGS.enable_* writes) can re-enable instrumentation until the user explicitly clears the disable with enable_instrumentation(force=True) / enable_sensitive_telemetry(force=True). Also addresses the two remaining unresolved review threads on the PR: 1. test_observability_settings_defaults_instrumentation_true pins the new "ENABLE_INSTRUMENTATION defaults to True when env unset" behavior. 2. test_enable_instrumentation_reads_env_sensitive_data restores coverage for the post-import load_dotenv() fallback path. Implementation: - ObservabilitySettings.enable_instrumentation / enable_sensitive_data become properties backed by _enable_*. While _user_disabled is True, the getters return False and the setters drop True writes (defense in depth so third- party writes can't subvert the disable). - Public is_user_disabled read-only property lets integrations (e.g. foundry's configure_azure_monitor) cheaply check the disable state without poking at privates. - enable_instrumentation() and enable_sensitive_telemetry() short-circuit with an info log when disabled; gain a force=True kwarg that clears the disable. - configure_otel_providers() still creates providers / exporters / views so a later force-enable can use them, but logs an info message when called while disabled. - Foundry's FoundryChatClient.configure_azure_monitor and FoundryAgent.configure_azure_monitor early-return when the user has disabled, so Azure Monitor's global providers aren't installed unnecessarily. Tests: 11 new tests covering default-on, env re-read at call time, sticky behavior against each re-enable surface (enable_instrumentation, enable_sensitive_telemetry, configure_otel_providers, direct attribute writes), force=True override, re-arming the disable, and the __all__ export. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: document disable_instrumentation() and force=True paths Add a "Disabling instrumentation" section to the observability sample README that walks through: - The distinction between the ENABLE_INSTRUMENTATION env var (initial, non-sticky) and disable_instrumentation() (process-wide, sticky). - Why the sticky semantics matter: framework integrations like FoundryChatClient.configure_azure_monitor() can call enable_instrumentation() as part of their setup, and the user's opt-out needs to win. - All five surfaces guarded by the sticky disable (property reads, public enable functions, configure_otel_providers, direct attribute writes, is_user_disabled-aware integrations). - The force=True escape hatch on both enable_instrumentation() and enable_sensitive_telemetry(). - How third-party integrations should consult OBSERVABILITY_SETTINGS.is_user_disabled. - The limits of the disable (does not tear down existing providers / in-flight spans / third-party instrumentation, does not persist across processes). Cross-links the new section from the ENABLE_INSTRUMENTATION row in the env vars table. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: soften disable_instrumentation() overclaim about telemetry guarantees Replace 'no telemetry will be emitted no matter what' (which is too strong, since callers can still pass force=True or mutate private attributes) with language framing the disable as a user-intent contract that library and framework code is expected to honor: the framework actively short-circuits the public enable paths, force=True and private-attribute writes are acknowledged as out-of-contract escape hatches that integrations should not use on the user's behalf. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: correct observability Dependencies section - opentelemetry-sdk is no longer a hard dependency; it is lazily imported by create_resource(), create_metric_views(), and configure_otel_providers() with a clear ImportError when missing. Day-to-day instrumentation works with opentelemetry-api alone provided some other component configures the global OpenTelemetry providers (Azure Monitor, an APM agent, application bootstrap, etc.). - opentelemetry-semantic-conventions-ai is no longer used anywhere in the source; remove it from the listed dependencies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: replace stale observability migration guide with current PR's only relevant migration The old guide documented the move away from setup_observability(otlp_endpoint=...) which was an earlier-release API change unrelated to this PR and stale enough that it's more confusing than helpful at this point. Replace it with a short note on the single migration this PR introduces: callers of enable_instrumentation(enable_sensitive_data=True) should switch to enable_sensitive_telemetry(). Cross-link to the Disabling instrumentation section for the rare 'force on without enabling sensitive data' use case where enable_instrumentation() still applies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
4609535e22 |
Python: feat: add agent-framework-monty (Monty-backed CodeAct provider) (#5915)
* Python: feat: add agent-framework-monty (Monty-backed CodeAct)
New alpha package that wraps pydantic-monty (a Rust-based Python
interpreter) behind the same CodeAct API surface as
agent-framework-hyperlight, so users can swap providers with minimal
code change.
Public API (agent_framework_monty):
- MontyCodeActProvider — ContextProvider that injects a run-scoped
execute_code tool plus dynamic CodeAct instructions.
- MontyExecuteCodeTool — standalone FunctionTool for mixed-tool agents
or manual static wiring.
- FileMount / FileMountInput / MountMode — public types mirroring the
Hyperlight names, with Monty's mode (read-only/read-write/overlay)
and write_bytes_limit on FileMount.
Constructor kwargs (both classes) mirror Hyperlight where possible:
tools, approval_mode, workspace_root, file_mounts; plus a Monty-only
resource_limits forwarding ResourceLimits to Monty.start().
Filesystem flow:
- workspace_root auto-mounts at /input (read-write), matching Hyperlight.
- file_mounts accepts string shorthand, (host, mount) tuple, or
FileMount with mode + write cap.
- Files written under read-write mounts are scanned post-execution and
returned as Content.from_data items (mirrors Hyperlight /output).
- overlay mounts buffer writes in-memory; read-only mounts reject writes.
Internals:
- _monty_bridge.InlineCodeBridge ports the inline (non-durable) bridge
from anthonychu/maf-codeact-monty-python; handles FunctionSnapshot /
FutureSnapshot pause/resume, dispatches direct typed calls + the
call_tool fallback, forwards mount/limits to Monty.start(...).
- generate_type_stubs emits per-tool stubs so Monty's `ty` type-checker
rejects bad calls before any host tool runs.
Alpha-policy compliance (per python-package-management skill):
- Added agent-framework-monty = { workspace = true } to root
pyproject.toml.
- Added row to python/PACKAGE_STATUS.md.
- Added monty entry under Experimental in python/AGENTS.md.
- NOT added to core[all]; NO agent_framework.monty lazy shim (deferred
to beta promotion).
Samples (three sets, import from agent_framework_monty directly):
- samples/02-agents/context_providers/code_act/monty_code_act.py
(provider pattern) + updated local README.
- samples/02-agents/tools/monty_code_interpreter/ (standalone +
manual-wiring + README).
- samples/04-hosting/foundry-hosted-agents/responses/11_monty_codeact/
(full hosted-agent layout with uv-based pyproject.toml + Dockerfile,
Azure Monitor wiring via APPLICATIONINSIGHTS_CONNECTION_STRING +
enable_instrumentation, ENABLE_INSTRUMENTATION and
ENABLE_SENSITIVE_DATA env vars). The alpha wheel is vendored into
./wheels/ (gitignored) via vendor-wheel.sh; new row added to the
parent Responses-API README.
Tests:
- 28 hermetic unit tests (stubbed pydantic_monty).
- 18 integration tests marked @pytest.mark.integration, auto-skipped
when pydantic_monty is unimportable; exercise the real Monty
runtime: print round-trip, last-expression value, direct typed
tool dispatch, call_tool fallback, async tool, asyncio.gather
parallelism, ty type-check rejection, OS blocked by default,
workspace_root read+write capture, read-only / overlay mount
semantics, resource_limits.max_duration_secs abort, approval
gating end-to-end, full Agent run with a scripted chat client.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Python: fix: monty FileMount test compares against the normalized POSIX path
The shorthand string mount goes through _normalize_mount_path, which
rewrites Windows drive letters like 'C:\\Users\\...' into
'/C:/Users/...' (POSIX-style). The Windows CI runners surfaced this
because tmp_path resolves to a backslashed Windows path; the test was
comparing against the raw str(host_a) instead of the normalized form.
Compare against _normalize_mount_path(str(host_a)) so the assertion is
platform-independent.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Python: fix: address PR #5915 review feedback
- _execute_code_tool docstring: clarify that the Monty backend supports
scoped filesystem access via workspace_root / file_mounts (blocked by
default).
- _to_monty_mount: import pydantic_monty lazily through load_monty so
missing-dependency errors surface as the same actionable RuntimeError
the rest of the package raises (not a bare ImportError at module load).
Renamed _load_monty -> load_monty for the same reason.
- _python_type_repr: emit None for type(None) instead of Any, and
normalize both typing.Union[...] and PEP-604 X | Y to PEP-604 syntax
so Optional[X] / Union[..., None] / -> None signatures round-trip
correctly through ty validation. Added a regression test.
- _PrintCollector: track a running character count instead of
recomputing sum(len(c) for c in self.chunks) per callback. Eliminates
the O(n^2) cost on print-heavy code.
- Instructions: mention that the value of the final expression is also
returned alongside captured stdout (matches actual behavior).
- 11_monty_codeact Dockerfile: pin ghcr.io/astral-sh/uv to 0.11.6
instead of :latest for reproducible builds.
- 11_monty_codeact README: replace the bare "see parent README" pointer
with sample-specific steps (./vendor-wheel.sh + uv sync + uv run),
since the sample uses pyproject.toml + a vendored wheel rather than
requirements.txt.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Python: sample: 11_monty_codeact installs agent-framework-monty from PyPI
Drop the vendored-wheel scaffolding now that agent-framework-monty is on
PyPI as an alpha (1.0.0a*) release:
- pyproject.toml: remove [tool.uv.sources] override; keep [tool.uv]
prerelease = "allow" so uv pulls the alpha automatically.
- Dockerfile: drop the COPY wheels/ step.
- README: drop the ./vendor-wheel.sh setup step and the
not-yet-on-PyPI warning.
- Delete vendor-wheel.sh and the gitignored wheels/ directory.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Python: fix(monty): harden post-execution file capture against symlink escape
Same class of issue as the MSRC-reported Hyperlight finding: the
post-execution capture walked workspace_root with Path.rglob() +
is_file() + read_bytes() - all of which follow symlinks. An attacker
who controls the workspace (cloned repo, extracted archive, shared
workspace) could pre-place `workspace/leak.txt -> /etc/passwd` or
`workspace/outside_dir -> /etc/` and have host files surface as
captured Content items.
Monty's mount layer already rejects symlink reads from inside the
sandbox across all three modes (verified empirically), so the runtime
path was safe. This commit closes the post-execution scan path.
Changes:
- New `_iter_real_files(root)` walker that uses iterdir() +
is_symlink() to skip symlinks at every directory level and yields
only real files. Replaces the previous `host_root.rglob("*")` calls
in both `_snapshot_writable_mounts` and `_capture_written_files`.
- Use `Path.lstat()` instead of `Path.stat()` so size/mtime can never
be taken from a symlink target.
- Three new integration tests reproducing the MSRC attack shape
against the workspace_root flow: symlink-to-file outside workspace,
symlink-to-directory outside workspace, and a guard ensuring
legitimate sandbox writes are still captured when symlinks are
present.
Per user request, hyperlight is untouched in this commit (separate fix).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Python: fix(monty): skip symlink regression tests when unsupported
Apply the same Windows-CI safety guard as the hyperlight fix in PR #5919:
the three symlink integration tests create symlinks via Path.symlink_to(),
which fails with OSError / NotImplementedError on unprivileged Windows
runners. Add a local _symlinks_supported helper (mirroring the one in
packages/core/tests/core/test_skills.py) and pytest.skip when symlinks
aren't available, so the tests no longer fail for environment reasons.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Python: fix(monty): address PR #5915 follow-up review feedback
- _invoke_tool: drop the inspect.iscoroutinefunction(...) branch and
always `await self.tool_map[name](**kwargs)`. Every entry in
tool_map is `partial(FunctionTool.invoke, skip_parsing=True)` and
FunctionTool.invoke is `async def`, so the branching was dead code -
and on Python versions affected by cpython#98590,
iscoroutinefunction(partial(bound_async_method, ...)) returns False,
causing the bridge to take the asyncio.to_thread path, return an
unawaited coroutine, and surface it as a JSON-serialization failure
for every tool call. Added a regression test
test_invoke_tool_awaits_partial_wrapped_async_method.
- generate_type_stubs: skip tools whose name is not a valid Python
identifier or is a Python keyword. FunctionTool.name has no upstream
validation, so a name like "weird-name" produced a syntax error in
the stubs and a name like "broken\n pass\nasync def injected"
would inject arbitrary stub source. Non-identifier names stay
reachable via `call_tool("weird-name", ...)` at runtime; they just
don't get type-checked stubs. Added regression test
test_generate_type_stubs_skips_non_identifier_tool_names.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
||
|
|
3bbc81554b |
Python: Improve the handling of intermediate outputs for workflows and orchestrations (#5623)
* Improve the handling of intermediate outputs for workflows and orchestrations
* Address PR review feedback on intermediate output forwarding
- Switch workflow.as_agent() forwarding to an explicit allowlist of {output,
intermediate, data, request_info} so orchestration-internal events
(group_chat, handoff_sent, magentic_orchestrator) stay inside the workflow
instead of leaking into agent responses via str(data) coercion.
- Stop raising on intermediate AgentResponseUpdate in non-streaming run();
surface the partial as a Message with text_reasoning content. The defensive
raise still applies to terminal output events, where Update payloads would
corrupt message ordering.
- Extend the DevUI workflow-event mapper so intermediate yields wrapping
plain strings, Messages, and list[Message] render as visible output items
instead of generic completed-trace events.
- Add orchestration coverage for GroupChat, Handoff, and Magentic builders
(default vs intermediate_outputs=True; structural where end-to-end is heavy).
* Lift output-designation policy into a value type
Replace the ``Workflow._output_executors`` list and the
``RunnerContext.should_label_as_intermediate`` Protocol method with a single
immutable ``OutputDesignation`` value type owned by ``Workflow``. Thread the
designation as a parameter through the existing call chain (Runner ->
EdgeRunner -> Executor -> WorkflowContext) so ``yield_output`` consults the
threaded snapshot directly rather than calling back into the runner context.
Removes the ``InProcRunnerContext._workflow`` back-reference and the
``WorkflowBuilder.build()`` assignment that wired it up. Adds the public
predicate ``Workflow.is_terminal_executor(executor_id)`` for external
observers; ``OutputDesignation`` itself stays package-internal.
Key decisions
- ``OutputDesignation.designated`` is ``frozenset[str] | None`` -- ``None``
preserves legacy "every yield is type='output'" behavior, any frozenset
(including empty) opts into strict mode. The ``DeprecationWarning`` for
legacy mode at build time is unchanged.
- ``output_designation`` is an optional parameter on ``Runner``,
``EdgeRunner.send_message``, ``EdgeRunner._execute_on_target``,
``Executor.execute``, ``Executor._create_context_for_handler``, and
``WorkflowContext.__init__``. Each defaults to legacy ``OutputDesignation()``
so direct callers (Azure Functions ``CapturingRunnerContext``,
``test_runner`` recording fixtures) keep working without ceremony.
- The workflow-level filter in ``_run_core`` reads ``self._output_designation``
live, preserving today's semantics where mutating the designation after
build still affects subsequent runs (used by two existing tests).
- ``Workflow.to_dict()`` continues to emit ``"output_executors":
list[str] | None`` (sorted from the frozenset). Checkpoint format unchanged.
Files changed
- _workflow.py: add ``OutputDesignation`` dataclass; replace
``_output_executors`` with ``_output_designation``; add
``is_terminal_executor``; delete ``_should_yield_output_event``.
- _runner_context.py: drop ``should_label_as_intermediate`` Protocol method
and ``InProcRunnerContext`` impl; drop ``_workflow`` back-reference.
- _workflow_builder.py: remove ``context._workflow = workflow`` assignment.
- _runner.py, _edge_runner.py, _executor.py, _workflow_context.py: thread
``output_designation`` parameter through the call chain.
- tests/workflow/test_output_designation.py (new): three-state coverage of
the value type plus the public predicate delegation.
- tests/workflow/test_workflow_builder.py, test_validation.py,
test_workflow.py, test_runner.py and
orchestrations/tests/test_orchestration_intermediate_vs_terminal.py:
switch probes from ``_output_executors`` set checks to
``get_output_executors`` / ``is_terminal_executor``; update two
post-build mutation tests to set ``_output_designation`` instead.
Verification
- core/tests/workflow/, orchestrations/tests/, azurefunctions/tests/:
1119 passed, 42 skipped, 2 xfailed.
- ``uv run poe lint``: clean.
- ``uv run poe typing``: only the pre-existing
``_AGENT_FORWARDED_EVENT_TYPES`` pyright warning from 394bcd607 remains.
Notes for next iteration
- The builder's own ``_output_executors`` attribute (``list[Executor |
SupportsAgentRun]``) is intentionally untouched; the issue scoped the
rename to the workflow attribute.
- Adjacent review candidates (twin ``WorkflowAgent`` translators,
``_AGENT_FORWARDED_EVENT_TYPES`` kind classifier,
``_event_origin_context`` ContextVar removal, ``WorkflowEvent`` ADT
split, legacy-mode removal) remain out of scope.
* Add explicit workflow output designation
Key decisions
- Extend the internal OutputDesignation value type from terminal-only membership to output/intermediate/hidden classification. Legacy mode remains outputs=None, so workflows built without output_executors or intermediate_executors still label every yield_output as type='output'.
- WorkflowBuilder now accepts intermediate_executors. Providing either designation enters explicit mode; output executors emit output, intermediate executors emit intermediate, and unlisted yield_output payloads are hidden from caller-facing events while remaining in executor_completed data.
- Empty explicit designation, duplicate entries, overlaps, unknown executors, and designated executors without workflow output annotations fail build validation. Existing orchestration builders pass intermediate-capable participants through intermediate_executors to preserve current intermediate_outputs behavior until participant-oriented designation lands.
Files changed
- packages/core/agent_framework/_workflows/_workflow.py, _workflow_builder.py, _workflow_context.py, _validation.py, _events.py
- packages/core/tests/workflow/test_output_designation.py, test_output_executors_contract.py, test_strict_mode_event_labeling.py, test_validation.py, test_workflow.py, test_workflow_agent_intermediate.py
- packages/orchestrations/agent_framework_orchestrations/_sequential.py, _concurrent.py, _group_chat.py, _magentic.py
- packages/core/AGENTS.md
Verification
- uv run pytest packages/core/tests/workflow packages/orchestrations/tests packages/devui/tests/devui/test_mapper.py -q
- uv run pytest packages/azurefunctions/tests -q
- uv run poe lint
- uv run poe typing fails only on pre-existing packages/core/agent_framework/_workflows/_agent.py _AGENT_FORWARDED_EVENT_TYPES private-use pyright error.
Notes for next iteration
- issues/03-core-workflow-explicit-designation.md was moved to issues/done but issues/ remains untracked and intentionally excluded from this commit.
- Slice 4 should tighten workflow.as_agent() mapping for hidden emissions and streaming-only update payloads; Slice 5 should replace orchestration intermediate_outputs with participant-oriented designation.
* Tighten workflow-as-agent output mapping
Key decisions
- Treat AgentResponseUpdate as a streaming-only payload across the workflow.as_agent() adapter, so non-streaming agent runs now reject both terminal output and intermediate workflow events carrying updates.
- Keep streaming classification behavior explicit: terminal update payloads remain normal text content, while intermediate update payloads are rewritten to text_reasoning content.
- Add explicit-mode coverage proving hidden yield_output emissions do not appear in non-streaming AgentResponse messages or streaming AgentResponseUpdate chunks.
Files changed
- packages/core/agent_framework/_workflows/_agent.py
- packages/core/tests/workflow/test_workflow_agent_intermediate.py
Verification
- uv run pytest packages/core/tests/workflow/test_workflow_agent_intermediate.py -q
- uv run pytest packages/core/tests/workflow/test_workflow_agent.py packages/core/tests/workflow/test_workflow_agent_intermediate.py -q
- uv run pytest packages/core/tests/workflow packages/orchestrations/tests packages/devui/tests/devui/test_mapper.py -q
- uv run poe lint
- uv run poe typing fails only on the pre-existing packages/core/agent_framework/_workflows/_agent.py _AGENT_FORWARDED_EVENT_TYPES private-use pyright error.
Blockers or notes for next iteration
- issues/04-workflow-as-agent-output-mapping.md was moved to issues/done/ but issues/ remains untracked and intentionally excluded from this commit.
- Slice 5 should replace orchestration intermediate_outputs with participant-oriented designation.
* Add orchestration participant output designation
Key decisions
- Replace orchestration intermediate_outputs with participant-oriented output_participants and intermediate_participants across Sequential, Concurrent, GroupChat, Magentic, and Handoff builders.
- Keep synthetic final executors terminal by default for Concurrent, GroupChat, and Magentic; keep Sequential's final participant terminal by default; keep Handoff participants terminal by default.
- Centralize participant designation validation for empty explicit designation, duplicates, overlaps, and unknown participants, then map validated participants to workflow output/intermediate executors.
Files changed
- packages/orchestrations/agent_framework_orchestrations/_participant_designation.py
- packages/orchestrations/agent_framework_orchestrations/_sequential.py
- packages/orchestrations/agent_framework_orchestrations/_concurrent.py
- packages/orchestrations/agent_framework_orchestrations/_group_chat.py
- packages/orchestrations/agent_framework_orchestrations/_magentic.py
- packages/orchestrations/agent_framework_orchestrations/_handoff.py
- packages/orchestrations/tests/test_orchestration_intermediate_vs_terminal.py
- packages/orchestrations/tests/test_magentic.py
Blockers or notes for next iteration
- issues/05-orchestration-participant-designation.md was moved to issues/done/ but issues/ remains untracked and intentionally excluded from this commit.
- Slice 7 should migrate samples and docs away from intermediate_outputs to the new participant designation API.
- uv run poe typing still fails only on the pre-existing packages/core/agent_framework/_workflows/_agent.py _AGENT_FORWARDED_EVENT_TYPES private-use pyright error.
* Migrate samples to explicit output designation
Key decisions
- Replace sample usage of the removed orchestration intermediate_outputs boolean with participant-oriented intermediate_participants designation.
- Update raw workflow guidance to show output_executors together with intermediate_executors, and document that unlisted yields are hidden in explicit designation mode.
- Keep orchestration final outputs terminal while streaming designated participant responses as intermediate progress, including workflow.as_agent() samples where intermediates map to text_reasoning content.
- Refresh workflow and orchestration README guidance plus the changelog reference so public docs no longer point users at intermediate_outputs.
Files changed
- CHANGELOG.md
- packages/orchestrations/README.md
- samples/README.md
- samples/03-workflows/README.md
- samples/03-workflows/control-flow/intermediate_vs_terminal_outputs.py
- samples/03-workflows/orchestrations/README.md
- samples/03-workflows/orchestrations/group_chat_agent_manager.py
- samples/03-workflows/orchestrations/group_chat_philosophical_debate.py
- samples/03-workflows/orchestrations/group_chat_simple_selector.py
- samples/03-workflows/orchestrations/magentic.py
- samples/03-workflows/orchestrations/magentic_human_plan_review.py
- samples/03-workflows/orchestrations/sequential_chain_only_agent_responses.py
- samples/03-workflows/agents/group_chat_workflow_as_agent.py
- samples/03-workflows/agents/magentic_workflow_as_agent.py
- samples/03-workflows/agents/sequential_workflow_as_agent.py
- samples/semantic-kernel-migration/orchestrations/group_chat.py
- samples/semantic-kernel-migration/orchestrations/magentic.py
Blockers or notes for next iteration
- issues/07-samples-and-docs-explicit-output-designation.md was moved to issues/done/ but issues/ remains untracked and intentionally excluded from this commit.
- issues/06-devui-intermediate-event-rendering.md remains present and appears already satisfied by existing DevUI mapper/tests from the prior implementation slice.
- PRD-explicit-workflow-output-designation.md remains untracked and intentionally excluded from this commit.
* Render DevUI intermediate workflow outputs
Key decisions
- Preserve workflow output designation metadata on visible DevUI output messages and text deltas so intermediate/data emissions remain distinguishable from terminal output.
- Render intermediate workflow message items in the execution timeline using executor metadata, while excluding them from the final workflow result aggregation.
- Keep terminal output message rendering unchanged and retain legacy data events on the intermediate compatibility path.
Files changed
- packages/devui/agent_framework_devui/_mapper.py
- packages/devui/frontend/src/components/features/workflow/execution-timeline.tsx
- packages/devui/frontend/src/components/features/workflow/workflow-view.tsx
- packages/devui/frontend/src/types/openai.ts
- packages/devui/tests/devui/test_mapper.py
Blockers or notes for next iteration
- issues/06-devui-intermediate-event-rendering.md was moved to issues/done/ but issues/ remains untracked and intentionally excluded from this commit.
- PRD-explicit-workflow-output-designation.md remains untracked and intentionally excluded from this commit.
- uv run poe typing still fails only on the pre-existing packages/core/agent_framework/_workflows/_agent.py _AGENT_FORWARDED_EVENT_TYPES private-use pyright error.
* Fix mypy
* Clarify orchestration participant output config
* Rename participant output kwargs for clarity
output_participants -> final_output_from, intermediate_participants ->
intermediate_output_from. The old names read like categories of
participant; the new names make it clear the kwarg designates which
participants' outputs surface as final vs. intermediate events.
* Rename core workflow output kwargs with deprecation shim
Adds final_output_from / intermediate_output_from as canonical kwargs on
Workflow and WorkflowBuilder. Old output_executors / intermediate_executors
kwargs continue to work but emit DeprecationWarning via a shared coalesce
helper that also rejects supplying both. Wire-format keys in to_dict()
stay as output_executors / intermediate_executors so checkpoint
compatibility is preserved.
Internal call sites in orchestrations and samples updated to the new
names so users following sample code learn the canonical vocabulary;
legacy callers still work with a one-shot warning.
* Suppress pyright reportPrivateUsage on cross-module sentinel import
* Update docstrings
* Propagate sub-workflow intermediate outputs, fix handoff/sequential intermediate-only designation, and shore up tests, sample, and docstrings around the intermediate output contract.
* Add canonical workflow output_from selection
Key decisions:\n- Make output_from the canonical workflow-output allow-list and keep output_executors/final_output_from as deprecated compatibility aliases.\n- Treat empty output_from/intermediate_output_from lists as explicit selections and keep validation responsible for empty, duplicate, overlap, and unknown selections.\n- Remove the branch-only public intermediate_executors WorkflowBuilder kwarg while preserving legacy wire keys in to_dict().\n\nFiles changed:\n- packages/core/agent_framework/_workflows/_workflow.py\n- packages/core/agent_framework/_workflows/_workflow_builder.py\n- packages/core/agent_framework/_workflows/_workflow_context.py\n- packages/core/agent_framework/_workflows/_agent.py\n- packages/core/agent_framework/_workflows/_agent_executor.py\n- packages/core/tests/workflow/* output-selection coverage updates\n- packages/core/AGENTS.md\n- issues/done/001-canonical-list-based-output-selection.md\n\nBlockers/notes:\n- Orchestration builders still pass final_output_from internally; follow-up issue 004 should migrate them to output_from.\n- Legacy omitted-selection behavior and explicit all/all_other literals are left for issues 002 and 003.
* Add explicit all workflow output selection
Key decisions:
- Treat output_from='all' as an explicit workflow-output selection sentinel and expand it at build time to executors with declared workflow output types.
- Keep omitted output selections in legacy all-output mode with a deprecation warning that names output_from and intermediate_output_from and points to output_from='all'.
- Reject intermediate_output_from='all' at construction because the all-output literal is output-only for this issue.
Files changed:
- packages/core/agent_framework/_workflows/_workflow_builder.py
- packages/core/tests/workflow/test_output_executors_contract.py
- issues/done/002-explicit-all-output-and-legacy-migration.md
Blockers/notes:
- all_other intermediate-output selection remains for issue 003.
- Workflow-as-agent/orchestration parity remains for issue 004.
* Add all-other intermediate output selection
Key decisions:
- Treat intermediate_output_from='all_other' as an explicit intermediate-output selection sentinel and expand it at build time after the workflow graph is complete.
- Expand all_other to output-capable executors not selected by output_from; omitted or empty output_from selects no workflow outputs, while output_from='all' leaves an empty intermediate selection.
- Keep output_from='all_other' invalid so all_other remains intermediate-output-only and runtime classification still receives concrete executor-id sets.
Files changed:
- packages/core/agent_framework/_workflows/_workflow_builder.py
- packages/core/tests/workflow/test_output_executors_contract.py
- issues/done/003-all-other-intermediate-output-selection.md
Blockers/notes:
- Workflow-as-agent and orchestration parity remains for issue 004.
- Full documentation updates remain for issue 005.
* Add orchestration output selection parity
Key decisions:
- Expose output_from on sequential, concurrent, group chat, handoff, and magentic builders while keeping final_output_from as a deprecated compatibility alias.
- Resolve orchestration participant selections through the same explicit rules as workflows: output_from='all', intermediate_output_from='all_other', hidden unselected participant payloads, and overlap/duplicate/unknown/invalid-literal validation.
- Continue preserving documented orchestration defaults by always designating each pattern's terminal internal executor where applicable.
Files changed:
- packages/orchestrations/agent_framework_orchestrations/_participant_output_config.py
- packages/orchestrations/agent_framework_orchestrations/_sequential.py
- packages/orchestrations/agent_framework_orchestrations/_concurrent.py
- packages/orchestrations/agent_framework_orchestrations/_group_chat.py
- packages/orchestrations/agent_framework_orchestrations/_handoff.py
- packages/orchestrations/agent_framework_orchestrations/_magentic.py
- packages/orchestrations/agent_framework_orchestrations/_orchestration_request_info.py
- packages/orchestrations/tests/test_orchestration_intermediate_vs_terminal.py
- issues/done/004-workflow-as-agent-and-orchestration-parity.md
Blockers/notes:
- Full documentation and sample migration wording remains for issue 005.
- Existing tests that intentionally use final_output_from now emit the new deprecation warning.
* Document workflow output selection contract
Key decisions:
- Use Workflow Output and Intermediate Output as the developer-facing terms for selected caller-facing emissions.
- Document output_from and intermediate_output_from as the canonical API, with output_from as an allow-list and unselected payloads hidden unless explicitly selected as intermediate.
- Add scenario and invalid-selection tables for workflow and orchestration docs, including legacy omission warnings, output_from='all', intermediate_output_from='all_other', list selections, invalid literals, overlap, duplicates, unknown selections, and empty explicit selections.
- Migrate samples away from final_output_from and output_executors except where compatibility aliases are explicitly documented.
Files changed:
- packages/core/AGENTS.md
- packages/orchestrations/README.md
- packages/orchestrations/agent_framework_orchestrations/_handoff.py
- packages/orchestrations/agent_framework_orchestrations/_sequential.py
- samples/03-workflows/README.md
- samples/03-workflows/control-flow/intermediate_vs_terminal_outputs.py
- samples/03-workflows/human-in-the-loop/agents_with_approval_requests.py
- samples/03-workflows/orchestrations/README.md
- samples/04-hosting/foundry-hosted-agents/responses/05_workflows/main.py
- scripts/sample_validation/create_dynamic_workflow_executor.py
- issues/done/005-document-output-selection-contract.md
Blockers/notes:
- Direct full Ruff on scripts/sample_validation/create_dynamic_workflow_executor.py still reports pre-existing docstring/print/line-length issues outside this docs migration; syntax-focused checks for changed files pass.
- No remaining AFK issue files are present under issues/.
* Latest updates
* Typing fixes
* Cleanup
|
||
|
|
da308f5f1e |
Python: New Foundry Hosted Agents samples: RAG, Skills, and Memory (#5822)
* WIP: Add rag sample; need deployment testing * Rag sample ready * Add Foundry Skills sample * WIP: Foundry memory * Done: Foundry Memory * Address Copilot comments * Fix README * Restore uv.loack |