mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
feature/python-hosting
152 Commits
-
Python: add agent-framework-hosting-mcp channel (#6305)
* feat(python): add agent-framework-hosting-mcp channel Add a hosting channel that exposes the host target (agent or workflow) as a single Model Context Protocol tool over Streamable HTTP. The tool invocation routes through the host pipeline (ChannelContext.run/ run_stream) so sessions, linking, and run/response hooks apply. Maps the MCP request context to a ChannelSession isolation key and ChannelIdentity, and forwards streaming output as MCP progress notifications. Includes tests, README, and workspace registration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address MCP hosting channel review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-06-12 12:25:43 +02:00 -
Python: add agent-framework-hosting-a2a channel (#6306)
* feat(python): add agent-framework-hosting-a2a channel Add a hosting channel that exposes the host target (agent or workflow) as a peer agent over the Agent-to-Agent (A2A) protocol (JSON-RPC plus a served agent card). Requests are handled by a host-routed HostAgentExecutor that drives the host pipeline (ChannelContext.run/ run_stream) instead of wrapping the target directly, so sessions, linking, and run/response hooks apply. Maps the A2A conversation/context id to a ChannelSession isolation key and the caller to a ChannelIdentity; streaming emits incremental task artifacts. Includes tests, README, and workspace registration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address A2A hosting channel review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-06-12 12:20:54 +02:00 -
Simplify Python hosting core (#6492)
Remove linking, multicast, durable delivery, and host push machinery from the v1 hosting core. Keep those scenarios in a proposed follow-up ADR and update channel packages, samples, docs, tests, and workspace metadata around the smaller host/channel contract. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-06-12 08:34:08 +02:00 -
Python: add agent-framework-hosting-discord channel (#6081)
* Add Discord hosting channel Add an alpha agent-framework-hosting-discord package backed by Discord HTTP Interactions. The channel verifies signed slash-command requests, registers commands, runs hosted agents and ChannelCommand handlers, supports originating response hooks, streams by editing the original interaction response, and can push through Discord channel ids. Factor standard channel response-hook context application into hosting core so both host fan-out and originating channel replies use one helper. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address Discord review chunking feedback Ensure Discord command replies are chunked and streaming preview edits stay under Discord's content limit while final streamed replies continue through the chunked reply path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * small fix in init * updated lock --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-28 15:53:23 +02:00 -
Python: add agent-framework-hosting-entra identity-link helpers (#5644)
* feat(hosting-entra): add Entra (Azure AD) identity-linking channel New ``agent-framework-hosting-entra`` package implementing a Microsoft Entra OAuth-based identity-linking channel for the Hosting framework. Mounts a small set of routes (``/entra/login``, ``/entra/callback``, ``/entra/whoami``) that walk a user through an Entra/Azure AD authorization-code flow and stick the resulting verified identity (``oid`` / ``email`` / ``tid``) onto the host's identity table so later requests on any other channel (Responses, Telegram, …) can be linked to the same user. Surface (re-exported from ``agent_framework_hosting_entra``): - ``EntraChannel`` -- concrete ``Channel`` implementation. Owns the three Starlette routes, signs/verifies short-lived ``state`` tokens to bind the round-trip to the originating channel, exchanges the authorization code for an ID token via MSAL, and writes the verified identity into the host's identity store via the standard ``ChannelIdentity`` plumbing so cross-channel push (e.g. send a Telegram message to the user who completed the link from Responses) works without the channels having to coordinate directly. - 14 unit tests covering route wiring, ``state`` issue / verify, callback exchange happy + failure paths, and identity-store write. Registers the package in ``python/pyproject.toml`` ``[tool.uv.sources]`` and adds the matching pyright ``executionEnvironments`` entry. Stacks on PR-2 (Hosting core); independent of PR-3 / PR-4 / PR-6. The cross-channel sample (``local_identity_link/``) that demonstrates this end-to-end alongside Responses + Telegram lands in PR-8 (samples). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(hosting-entra): close IDOR + reflected-XSS + open-redirect on the OAuth flow Three SECURITY-CRITICAL fixes flagged in round-2 review. 1. IDOR on /auth/start (3198518308). Without authentication the endpoint accepted (channel, channel_id) from the query string and bound *whoever signed in* to that pair. An attacker could bind their own Entra oid to a victim's per-channel id (e.g. `telegram:<victim_chat_id>`), redirecting all of the victim's future inbound traffic to the attacker's isolation key. Fix: introduce link_token_secret + mint_start_url(channel, id, ...). When set, /auth/start requires `exp` + `sig` (HMAC-SHA256 over `channel|channel_id|expires_at`) before issuing the redirect. Channels that hand out start URLs (a Telegram /link command after verifying the inbound webhook signature) call mint_start_url so the token proves the (channel, id) pair was authorised by the channel that owns the surface. Unsigned mode is opt-in and logs a loud WARNING at startup *and* on every accepted request. 2. Reflected XSS on /auth/callback (3198520256, 3198527896). `error`, `error_description`, channel_key (from the unauthenticated /start query), and `upn` (from a Graph response) flowed straight into the text/html response body unescaped. With the IDOR above, an attacker could stash `<script>` payloads in `channel` or `id` and serve them from the auth host's origin (full XSS on the auth surface — cookies/storage of anything else mounted there). Fix: html.escape() every value before HTML output. 3. Open redirect on `return_to` (3198524746). Accepted any URL. Fix: `_validate_return_to` allows only relative paths starting with `/` (and not `//`) or absolute URLs whose host equals the configured `public_base_url` host. Validated at /start mint time AND defensively re-validated at /callback before redirect. 12 new tests cover signed-token rejection (missing/forged/expired), mint helper requirements, startup warning visibility, XSS escaping on both error and success paths, and the open-redirect allowlist (external rejected, relative accepted, same-origin accepted, protocol-relative `//evil.example/` rejected). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(hosting): drop redundant @pytest.mark.asyncio decorators asyncio_mode = "auto" is configured in pyproject.toml across the hosting packages, so individual @pytest.mark.asyncio decorators are unnecessary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-28 14:47:36 +02:00 -
Python: add agent-framework-hosting-activity-protocol channel (#5641)
* feat(hosting-activity-protocol): rename Bot Framework channel to ActivityProtocolChannel The existing Bot-Framework-via-Azure-Bot-Service channel was previously shipped under the name ``hosting-teams`` / ``TeamsChannel``. That name is misleading for what the channel actually does -- it speaks the Bot Framework Activity Protocol against Azure Bot Service, which fans out across MS Teams, Slack, Webex, Telegram-via-Bot-Service, etc., and does not provide any Teams-specific affordances. This PR renames the package atomically and frees the ``hosting-teams`` name for a future Teams-native channel built on ``microsoft-teams-apps`` (PR-5b, spec req #28). Renames (all in one commit): - Package: ``agent-framework-hosting-teams`` -> ``agent-framework-hosting-activity-protocol`` - Module: ``agent_framework_hosting_teams`` -> ``agent_framework_hosting_activity_protocol`` - Channel class: ``TeamsChannel`` -> ``ActivityProtocolChannel`` - Helper: ``teams_isolation_key`` -> ``activity_protocol_isolation_key`` (isolation key prefix ``teams:`` -> ``activity:``) - Channel name: ``"teams"`` -> ``"activity"``; default mount path ``/teams`` -> ``/activity`` - Internal helper: ``_parse_teams_activity`` -> ``_parse_activity`` - Worker task name + a couple of error strings updated for consistency Updates README.md and the module docstring to call out: - this is the channel-neutral Activity Protocol channel, - it surfaces what every Bot-Service-connected channel has in common (text in / text out), - a forthcoming ``agent-framework-hosting-teams`` package will layer Teams-specific affordances (adaptive cards, message extensions, dialogs, SSO, ...) on the same Bot Service transport. Workspace: registers ``agent-framework-hosting-activity-protocol`` in ``python/pyproject.toml`` and adds the matching pyright ``executionEnvironments`` entry. Behavior is unchanged. Pyright + mypy clean, 11 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * review: address PR-5 round 2 feedback - security (#3198327004): add `service_url_allowed_hosts` constructor option (default `botframework.com` + `smba.trafficmanager.net`) and reject inbound activities whose `serviceUrl` host falls outside it with HTTP 400 — without this gate a malicious caller could redirect outbound replies (and the attached bearer token) to an attacker-controlled host - security (#3198324219): add `inbound_auth_validator` async callback; log a loud WARNING at startup when no validator AND no operator reverse-proxy is configured so the dev-mode bypass cannot accidentally ship to production. Document the contract: prototype intentionally does not ship JWT validation (out of scope); operators must plug a validator or terminate auth in front of the channel - retry semantics (#3198328746): distinguish transient outbound failures (httpx network errors, non-2xx from Bot Service) — return 502 so Bot Service retries — from deterministic agent failures — return 200 so Bot Service does not retry the same broken activity in a loop - bug (#3198330424): fix the placeholder-failure deadlock. When `send_initial_placeholder` fails, `activity_id` stays `None`, the edit-worker loop exit condition (`accumulated == last_sent`) is unreachable while no PUT is possible, and the worker would deadlock on `wake.wait()` forever after `worker_done` is set. Now: skip the worker entirely on placeholder failure and POST a single final activity at the end with whatever accumulated - tests (#3198334465, #3187178091, #3198336045): add coverage for - `_is_service_url_allowed` allow/deny matrix + webhook 400 on disallowed serviceUrl - `inbound_auth_validator` allow/deny/raises paths - outbound `Authorization: Bearer <token>` header presence in production mode and absence in dev mode - the streaming path (`_stream_to_conversation`): placeholder + final edit, placeholder-failure fallback (with timeout guard against deadlock regression), and empty-stream `(no response)` placeholder replacement - retry-signal differentiation: outbound `httpx.ConnectError` → 502; deterministic `ValueError` from the agent → 200 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(hosting): drop redundant @pytest.mark.asyncio decorators asyncio_mode = "auto" is configured in pyproject.toml across the hosting packages, so individual @pytest.mark.asyncio decorators are unnecessary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(hosting-activity-protocol): add response hooks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(hosting-activity-protocol): mark constructor keyword args Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-28 14:37:18 +02:00 -
Python: add agent-framework-hosting-telegram channel (#5643)
* feat(hosting-telegram): add Telegram channel package New ``agent-framework-hosting-telegram`` package implementing the Telegram Bot API channel for the Hosting framework. Mounts a webhook endpoint (``POST /telegram/webhook``) and an in-process polling loop onto an ``AgentFrameworkHost`` and translates Telegram ``Update`` payloads to/from the channel-neutral ``ChannelRequest`` / ``HostedRunResult`` plumbing. Surface (re-exported from ``agent_framework_hosting_telegram``): - ``TelegramChannel`` -- concrete ``Channel`` implementation. Owns the webhook route + an optional ``getUpdates`` long-polling lifespan, parses Telegram ``Update``s into ``ChannelRequest`` (text, photo, document, voice, callback_query, …), runs the optional ``ChannelRunHook``, calls back into the ``ChannelContext`` to invoke the agent target, and posts the response back via ``sendMessage`` / ``sendChatAction`` / ``answerCallbackQuery`` on the Telegram Bot API. Honours ``DeliveryReport.include_originating`` so cross-channel pushes can target the originating Telegram chat without double-acking. - Native fields the channel doesn't lift onto ``ChannelRequest`` (e.g. ``chat.type``, ``message.message_id``, ``callback_query.data``) are attached to ``ChannelRequest.attributes`` so a ``ChannelRunHook`` can pick them up via the standard ``protocol_request=`` kwarg. - 13 unit tests covering route wiring, ``Update`` parsing across the common content shapes, hook composition, and originating vs non-originating delivery branches. Registers the package in ``python/pyproject.toml`` ``[tool.uv.sources]`` and adds the matching pyright ``executionEnvironments`` entry. Stacks on PR-2 (Hosting core); independent of PR-3 / PR-4. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(hosting-telegram): preserve in-chat ordering, ack-before-run, drain shutdown - Replace per-update task fan-out with per-chat asyncio.Queue + worker. Telegram only guarantees update ordering up to getUpdates; the previous code spawned one task per update, which broke ordering for adjacent updates in the same chat. Updates are now serialised per chat_id (so /start then "what's the weather" can't race) while different chats still process in parallel. - Webhook handler now acks (200) immediately and runs the agent in the per-chat worker. Telegram redelivers any update the webhook doesn't 200 within ~60 seconds, so a streamed agent reply that runs longer than that previously triggered a retry storm and duplicate replies. - _on_shutdown now drains everything: poll task → per-chat workers → webhook-spawned dispatcher tasks (the new ack-before-run path), then deletes the webhook + closes the HTTP client. Previously webhook tasks were not tracked at all, so an in-flight agent invocation could leak past app shutdown. - _enqueue_update extracts chat_id from message / edited_message / callback_query; updates with no resolvable chat fall back to a one-shot dispatcher task that's still tracked in _update_tasks for shutdown. - Webhook handler now also returns 400 on malformed JSON / non-object payloads instead of crashing the request. 4 new tests cover per-chat serial ordering, parallel-across-chats isolation, ack-before-run latency, and shutdown drain. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(hosting): drop redundant @pytest.mark.asyncio decorators asyncio_mode = "auto" is configured in pyproject.toml across the hosting packages, so individual @pytest.mark.asyncio decorators are unnecessary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(hosting-telegram): adapt push tests to hosted run result wrapper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(hosting-telegram): add response hooks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-28 14:28:30 +02:00 -
Python: add agent-framework-hosting-invocations channel (#5640)
* feat(hosting-invocations): add Invocations channel package New ``agent-framework-hosting-invocations`` package implementing the "Invocations" HTTP channel for the Hosting framework -- a lightweight JSON-over-HTTP shape (``POST /invocations``) for callers that want a single request/response without committing to the full OpenAI Responses envelope. Mounts onto an ``AgentFrameworkHost`` like any other channel. Surface (re-exported from ``agent_framework_hosting_invocations``): - ``InvocationsChannel`` -- concrete ``Channel`` implementation. Owns the Starlette route, parses inbound JSON into a ``ChannelRequest`` (``input`` / ``session`` / ``metadata`` / ``options``), runs the optional ``ChannelRunHook``, calls back into the ``ChannelContext`` to invoke the agent target, and returns a flat JSON envelope (or an SSE stream when ``stream=true``). - 8 unit tests covering route wiring, isolation-key passthrough, hook composition, sync vs streaming paths, and ack-only behaviour for non-originating ``DeliveryReport``s. Registers the package in ``python/pyproject.toml`` ``[tool.uv.sources]`` and adds the matching pyright ``executionEnvironments`` entry. Independent of PR-3 (Responses); both depend only on PR-2 (Hosting core). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * review: address PR-4 round 2 feedback - expand `_stream` docstring to call out the HTTP-200 + `event: error` SSE contract (status committed before generator runs; hard failures surface as the first SSE frame, not an HTTP code) - split chunked text on full-line terminators via `splitlines()` so embedded `\r` / `\r\n` no longer leak into `data:` framing on the wire, breaking EventSource consumers - on `get_final_response()` failure, emit `event: error` instead of silently swallowing — finalize is what triggers history-provider persistence on the agent side, so a 5xx / disk-full / context-provider error must reach the client - add tests covering `stream_transform_hook` (rewrite, drop, async), CRLF-in-chunk framing, and the finalize-error → no-`[DONE]` contract Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(hosting-invocations): rename stale ChatMessage docstring reference to Message Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(hosting-invocations): adapt to hosted run result wrapper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(hosting-invocations): add response hooks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-05-28 14:08:34 +02:00 -
Python: add agent-framework-hosting core package (#5638)
* feat(hosting): add agent-framework-hosting core package New ``agent-framework-hosting`` package implementing ADR 0026 / SPEC-002: the channel-neutral host that lets a single ``Agent`` (or ``Workflow``) fan out across multiple wire protocols ("channels") behind one Starlette ASGI app. Surface (re-exported from ``agent_framework_hosting``): - ``AgentFrameworkHost`` — wraps a hostable target, mounts channels onto an ASGI app, owns per-isolation-key ``AgentSession`` reuse, threads request context (``response_id`` / ``previous_response_id``) into context providers via an ``ExitStack`` of ``bind_request_context`` calls, and exposes an opt-in Hypercorn ``serve()`` helper (extra ``[serve]``). - ``Channel`` protocol + ``ChannelContribution`` — the surface a channel package implements (routes, lifespans, identity hooks, …). - ``ChannelRequest`` / ``ChannelSession`` / ``ChannelIdentity`` / ``ChannelPush`` / ``ChannelCommand[Context]`` / ``ChannelRunHook`` / ``ChannelStreamTransformHook`` / ``DeliveryReport`` / ``HostedRunResult`` / ``ResponseTarget`` / ``ResponseTargetKind`` / ``apply_run_hook`` — channel-side dataclasses + helpers. - ``IsolationKeys`` + ``ISOLATION_HEADER_USER`` / ``..._CHAT`` + ``get/set/reset_current_isolation_keys`` — the host's ASGI middleware reads the ``x-agent-{user,chat}-isolation-key`` headers off each inbound request and exposes them to the agent stack via a ``ContextVar`` so storage-side providers (e.g. ``FoundryHostedAgentHistoryProvider``) can apply per-tenant partitioning without channels having to forward anything. Includes 45 unit tests covering the host, channel contributions, isolation contextvar, and shared types. Registers the package in ``python/pyproject.toml`` ``[tool.uv.sources]`` and adds the matching pyright ``executionEnvironments`` entry for tests. Hypercorn is an optional dependency (``[serve]`` extra); the soft import in ``serve()`` is annotated for pyright since it isn't on the default install. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(hosting): address PR-2 review comments Source-code changes - _suppress_already_consumed: narrow contract — RuntimeError now logs at WARNING with exc_info; non-RuntimeError still logs at exception(). Docstring clarifies that any non-clean teardown is observable. - _BoundResponseStream: add aclose() and route __await__ through get_final_response() so the binding is always released — fixes contextvar leak when channels abandon the stream or use the await-the-stream convenience. - Lifespan: aggregate startup/shutdown callback errors; every callback runs, all failures are logged with their qualname, and the first error is re-raised so Starlette still aborts boot. - _build_run_kwargs: switch session-cache write to dict.setdefault so concurrent racers cannot orphan a session if create_session ever yields. - _deliver_response: introduce DeliveryReport.failed for push outages vs explicit "no link" drops; an outage no longer triggers an originating fallback so the channel can decide degraded behaviour. Test additions - tests/test_isolation.py (new): full coverage of IsolationKeys, the contextvar helpers, header constants, and end-to-end ASGI middleware lift / reset / passthrough. - tests/test_host.py: TestBindRequestContext, TestBoundResponseStream (aclose / __await__ / __getattr__ forwarding / double-close idempotency), TestWrapInputListMessages (list[Message] LAST precedence), TestLifespanAggregation (startup + shutdown). - tests/test_types.py: TestApplyRunHook (sync/async/None), and TestDeliveryReport (new failed field). - Updated test_push_exception_marks_skipped -> test_push_exception_lands_in_failed_no_fallback to match the new delivery contract. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(hosting): address PR-2 round-2 review comments - Refactor workflow checkpoint restoration into shared helpers (_restore_workflow_checkpoint for blocking; the streaming sibling drains the rehydration stream) so the blocking and streaming paths rehydrate identically — clarifies the previously inline _maybe_restore by hoisting the pattern next to the blocking call site. - Document that blocking workflow output is text-only by design; richer modalities ride the streaming AgentResponseUpdate channel, which preserves all content parts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * review: address PR-4 _host.py round 2 feedback These review comments were filed on PR-4 (#5640) but target lines that live in the hosting-core package (PR-2 / #5638), so the fixes land here and PR-4's stack will pick them up on rebase. - _suppress_already_consumed: narrow the RuntimeError catch to the two documented benign messages (`Inner stream not available`, `Event loop is closed`); any other RuntimeError now logs at ERROR with a full traceback so executor bugs / runner-context state errors / checkpoint RuntimeErrors during the post-run flush no longer masquerade as benign cleanup noise. Still no propagation (we're in an async-generator finally during teardown) — see the docstring. - _restore_workflow_checkpoint{,_streaming}: log a WARNING when a non-None latest checkpoint drains to zero events, so a stale or partially-written checkpoint_id surfaces as an operator signal instead of a silent state-loss. (The `deliver_response` "no destinations resolvable" vs "every destination errored" concern raised in 3198268038 is already addressed by the existing `failed` vs `skipped` distinction surfaced through `DeliveryReport.failed` — see lines 1080-1102 and the `DeliveryReport` docstring.) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(hosting): reject path-traversal patterns in checkpoint isolation_key The host's `_resolve_checkpoint_storage` joined `request.session.isolation_key` directly into the configured `checkpoint_location`. The key is caller- controlled — sourced from inbound headers (`x-agent-{user,chat}-isolation-key` injected by the Foundry runtime), from channel-supplied derivations such as `telegram:<chat_id>` / `entra:<oid>`, or from values set by a channel `run_hook`. A value like `../../../etc/foo` or an absolute path would let the resulting checkpoint directory escape the configured root (CWE-22). This matches the path-traversal class fixed upstream in #5851 for the foundry_hosting checkpoint storage. New `_checkpoint_path_for_isolation_key(root, isolation_key)` helper: - Uses a denylist (not allowlist) so legitimate namespaced keys (`telegram:42`, `entra:abc-def`) continue to pass through unmodified. - Rejects path separators (`/`, `\`), NUL, all-dot reductions (`.`, `..`, `...`, ...), absolute paths (`os.path.isabs`), and drive-letter prefixes (`os.path.splitdrive` plus an explicit `^[A-Za-z]:` check so payloads crafted on a POSIX host still fail closed if the resulting directory ever round-trips to Windows storage). - After joining, resolves both sides and verifies `target.is_relative_to(root)` as defence-in-depth. `_resolve_checkpoint_storage` now logs a WARNING and returns `None` for invalid keys rather than crashing the request — checkpointing is best- effort and we prefer dropping it to letting one malformed key abort an otherwise valid agent run. Tests: - `TestCheckpointPathForIsolationKey` exercises the helper directly with legitimate keys (alphanumeric, `:`-namespaced, dotted, 200-char), all rejected traversal patterns from #5851's MSRC repro list, and non-string input. - `TestHostWorkflowCheckpointingPathTraversal` verifies the end-to-end request path: a traversal key (`../escape`) and an in-key separator (`evil/sub`) both produce a successful agent response with no files written under `checkpoint_location`, and the traversal case logs a WARNING citing `isolation_key`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(hosting): address PR-2 round-3 review feedback + add response hooks Round-3 review comment fixes: - _types.py: drop the _EMPTY_MAPPING sentinel; ChannelIdentity.attributes uses plain dict() as the default — simpler, no extra symbol to track. - _host.py: drop the local `import asyncio` + `from typing import cast as _cast` inside `serve()`; rely on the module-level imports. - _host.py: switch `_log_incoming` to structured `extra={...}` payloads for both INFO and DEBUG so log aggregators get queryable fields. - _host.py: delete `_flat_context_providers` and stop descending into a `.providers` attribute. Aggregator providers (AggregateContextProvider / ContextProviderBase) are responsible for forwarding `response_context` to their children themselves; the host treats whatever `agent.context_providers` exposes as the final, flat list. - _host.py: stop collapsing agent / workflow output to text. `_invoke` forwards `AgentResponse.messages` (and `raw_response`) on the `HostedRunResult`. `_invoke_workflow` builds a per-event message list via a new `_workflow_output_to_messages` helper that preserves AgentResponse / AgentResponseUpdate / Message / Content branches and falls back to text only for arbitrary objects. - _host.py: `_workflow_event_to_update` carries Content payloads through unchanged so multi-modal workflow outputs (images, function-call metadata, ...) survive into channels. New features (per design discussion in the PR thread): - HostedRunResult: rebuilt around `messages: list[Message]` with `.text` / `.contents` as projections, a `raw_response` slot for the underlying AgentResponse, and a `replace(messages=..., raw_response=...)` clone helper used by the delivery layer for per-destination isolation. The `HostedRunResult(text="...")` ctor is preserved as a back-compat shim that synthesises a single assistant text message. - ResponseTarget: gain `echo_input: bool = False` (also exposed on `.channel(name, *, echo_input=...)` / `.channels([...], *, echo_input=...)`). When set, the host pushes the originating user message to each non-originating destination before the agent reply. Channels can filter or transform echoes via their response_hook. - DeliveryReport: add `echoed` / `echo_failed` tuples to surface per-destination outcomes of the new echo phase. Echo failures do not abort the corresponding response push on the same destination. - ChannelResponseHook + ChannelResponseContext + apply_response_hook: duck-typed `response_hook` attribute on channels for per-destination post-processing. Receives a clone of the HostedRunResult and a context carrying the request, channel name, destination identity, originating flag, and `is_echo` phase flag. Channels stay modality-aware (text-only wires flatten via the hook; card-capable channels render structured contents directly). - _deliver_response: clone-before-hook fan-out so a hook mutating one channel's payload cannot leak into another destination's view. Tests: - Update _FakeAgentResponse to expose `.messages` (single assistant text message synthesised from `text`) so existing tests pass unchanged on the new multi-modal _invoke path. - Replace the obsolete `test_bind_descends_one_level_into_providers_attribute` with a regression guard asserting the host does NOT descend into `.providers` (matches new contract). - New tests for HostedRunResult multi-modal preservation, echo_input fan-out with success + failure, response_hook applied per destination, per-destination mutation isolation, and is_echo phase observability. Docs: - spec 002: rewrite Canonical flow with the new input → run_hook → host → target → wrap → per-destination clone → response_hook → push pipeline; document multi-modality contract and per-destination cloning; add `echo_input` row to ResponseTarget table; rewrite HostedRunResult/HostedStreamResult row; add ChannelResponseHook / ChannelResponseContext / apply_response_hook table; log decisions Q28 (no host-side text collapse), Q29 (duck-typed response_hook), Q30 (opt-in `echo_input` on ResponseTarget). - ADR 0026: add ChannelResponseHook + multi-modality bullets; surface `echo_input` on the ResponseTarget bullet. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(hosting): drop HostedRunResult(text=...) back-compat shim; use from_text() Pre-release cleanup — no released callers to break, so consolidate on one canonical entry point plus a classmethod for the ergonomic single-text-message case: - HostedRunResult.__init__ takes ``messages`` positionally (required); no more ``text=`` kwarg overload, no more "synthesise an empty message when no args" path. - New HostedRunResult.from_text(text, *, role="assistant", raw_response=None) classmethod for the common "wrap a single text content as one message" case (tests, channels emitting plain strings, the echo-input phase wrapping a user's text turn). - ``_build_echo_payload`` uses ``HostedRunResult.from_text(raw, role="user")`` for the ``str`` and fallback branches; the other branches use the plain ctor with explicit ``Message`` lists. - Tests rewritten to use ``from_text("reply")`` everywhere ``HostedRunResult(text="reply")`` appeared. Added an explicit ``test_from_text_role_kwarg_overrides_default`` regression guard. - spec 002: HostedRunResult row updated to describe the ``from_text(text, *, role="assistant")`` classmethod instead of the removed back-compat shim. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(hosting-core): reshape HostedRunResult into generic typed envelope Replace the flattened multi-modal HostedRunResult (carrying messages/raw_response/.text projections) with a typed generic envelope around the target's full-fidelity output: class HostedRunResult(Generic[TResult]): result: TResult session: AgentSession | None - Agent targets produce HostedRunResult[AgentResponse]; channels read result.messages, result.text, result.value, result.response_id, result.usage_details directly off the underlying response. - Workflow targets produce HostedRunResult[WorkflowRunResult]; channels iterate result.get_outputs() and inspect result.get_final_state() themselves (the host no longer collapses workflow outputs onto a synthesised message list). - The echo-input phase synthesises a HostedRunResult[AgentResponse] wrapping the user's turn so the same per-destination delivery machinery applies. - replace() is now {result, session} only; the host's clone is shallow — channels that need to mutate result itself are responsible for their own deep copy. Rationale: the earlier shape pre-shaped target output (collapsing workflows onto a Message list, losing per-executor outputs, final state, and structured value affordances). Carrying the target output unchanged keeps the host modality-agnostic, gives channel authors static typing where they want it, and removes 30+ lines of host-side projection helpers. Also updates ADR 0026 + spec 002 (Q3, Q28, Q29 amended; new Q31 captures the generic-envelope decision and rationale). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(hosting-core): document echo vs response distinction for push channels The host already encodes the echo-vs-response phase via the underlying Message.role on the pushed HostedRunResult: - echo phase: payload.result.messages[*].role == "user" - response phase: payload.result.messages[*].role == "assistant" Both pushes go through the same ChannelPush.push(identity, payload) entry point. Channels distinguish either by inspecting role (which works for any push-capable channel) or — when a response_hook is wired — by branching on ChannelResponseContext.is_echo directly. Expand the ChannelPush Protocol docstring to make this discoverable for channel implementers (esp. chat bots that cannot impersonate the user on their wire and need to render echoes as quoted / prefixed blocks rather than as bot replies). Mirror the explanation into the spec's echo_input section. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(hosting-core): fix quickstart to use current Agent API ChatAgent was renamed to Agent and the preferred construction pattern is client.as_agent(...). Also drop the sibling channel import so the snippet imports only modules declared as dependencies of this package; point readers at the sibling packages instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(hosting-core): drop redundant @pytest.mark.asyncio decorators asyncio_mode = "auto" is configured in pyproject.toml, so individual @pytest.mark.asyncio decorators are unnecessary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(hosting): add authorization profiles + IdentityAllowlist seam to ADR/spec Composes `require_link` + `allowlist` into three named profiles (open, forced-link, allowlist) with the allowlist itself keyed on either the channel-native id (pre-link) or a verified IdP claim (post-link), plus `AnyOf`/`AllOf` combinators for mixed setups. Lifts the design into an explicit host seam (`host.authorize(...)` → `AuthorizationOutcome` of `Allowed` / `LinkRequired` / `Denied`) instead of leaving each channel to roll its own. Key contract bits: - Tri-state `AllowlistDecision` (ALLOW / DENY / ABSTAIN) so claim-based lists can ABSTAIN until claims are available without composition silently flipping that into DENY. - `AuthorizationContext` carries explicit `phase` + `claim_source` so allowlists can tell pre-link from post-link without overloading `verified_claims is None`. - Channel-side `allowlist: ... | Literal["inherit"] | None` with an explicit inheritance sentinel, so the host-level `default_allowlist` is opt-out, not opt-in. - Construction-time validator rejects silent-deny configurations (`LinkedClaimAllowlist` without a claim source) with a typed `ChannelConfigurationError`. - Group-chat denial mirrors the existing `LinkChallenge` DM-redirect pattern; only the redacted `user_message` reaches the wire, structured `log_details` stay in telemetry. Ships in two waves: the Protocol + `NativeIdAllowlist` + config validator land with the next core PR ahead of the linker; the full pipeline + `LinkedClaimAllowlist` enforcement land with the `IdentityLinker` core PR. Updates: ADR 0026 (summary bullet + conceptual-API table row + resolved Q16), spec 002 (new req #22, renumbered v1 fast-follow #23..#29 and stretch #30..#31, new "Authorization profiles and the IdentityAllowlist seam" subsection, inbound-ownership row, resolved Q32, follow-up entry). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(hosting): add DurableTaskRunner seam + runtime_mode auto-detect Introduces the explicit long-running vs ephemeral runtime distinction and a generic DurableTaskRunner Protocol that owns non-originating push dispatch — collapsing the previous deliveries[] per-destination state machine, SupportsDeliveryTracking provider capability, and Foundry update_item service ask down to a single immutable intended_targets[] write on the message. Spec / ADR: - New §"Runtime modes" with auto-detect markers + defaults matrix. - Rewrites §"Delivery tracking" → §"Intended targets + durable delivery": intent-only on the message, operational state lives in the runner. - New §"Durable task runner" defining DurableTaskRunner / RetryPolicy / TaskHandle / TaskStatus. - Drops §SupportsDeliveryTracking and §Foundry update_item gap. - Resolved Qs: 12, 18, 21, 26 revised; new 17/18/19 (ADR) and 33/34/35 (spec). Code: - New _runner.py with InProcessTaskRunner (asyncio + bounded retry, bounded terminal-status cache, register-after-start guard, shutdown drain). - _host.py: runtime_mode + durable_task_runner ctor params; auto-detect via FOUNDRY_HOSTING_ENVIRONMENT / AZURE_FUNCTIONS_ENVIRONMENT / AWS_LAMBDA_FUNCTION_NAME; HOSTING_PUSH_TASK_NAME handler registered eagerly so _deliver_response can be called outside the lifespan; _handle_push_task does echo-then-response inline per destination; _deliver_response now schedules one task per destination via the runner (DeliveryReport.pushed = scheduled; .failed = schedule-time outage only). - _types.py: new DurableTaskRunner Protocol + RetryPolicy / TaskHandle / TaskStatus; DeliveryReport drops echoed / echo_failed (echo outcome owned by the runner). - __init__.py exports the new public surface. Tests: 132 passing, 90% coverage. New test_runner.py covers InProcessTaskRunner success/retry/terminal-failure/cancellation/ register-after-start, runtime-mode auto-detect with synthetic env, and the warning-on-ephemeral-without-runner path. test_host.py delivery tests use a sync runner fake for deterministic assertions and validate the new "schedule succeeded vs runner backend unreachable" semantics. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(hosting): rubber-duck round-5 — strict ephemeral, codec seam, allowlist Wave-1, drop DeliveryReport Adopts the rubber-duck-approved package of changes from the round-5 review of PR #5638 (modulo DeliveryReport.failed — the value type is removed entirely now that durable delivery covers the failure surface, per user direction). Code: - Drop DeliveryReport value type; host-internal _deliver_response returns bool. Failure observability is now logs (in-process) / runner backend (durable adapters). - Strict ephemeral default: ephemeral runtime_mode with the default in-process runner raises RuntimeError; opt-in via allow_in_process_runner=True (warns). - ChannelPushCodec Protocol + DurableTaskPayloadMode enum + _validate_runner_codec_pairing so JSON-mode runners can be safely paired with channels via codecs; _handle_push_task accepts both object- and JSON-envelope shapes. - ResponseTarget.identity(...) / .identities([...]) builders + IDENTITIES kind for explicit caller-supplied recipients; field rename identities → _target_identities (private) with a target_identities property to resolve the classmethod collision. - Intent-only audit: _annotate_intended_targets writes hosting.intended_targets / skipped_targets / includes_originating / originating_channel onto assistant messages — single immutable write per the runner-owned operational-state model. - InProcessTaskRunner: 2-phase drain on shutdown (shutdown_grace_seconds, default 5.0) so a clean shutdown does not abandon work mid-retry; payload_mode = OBJECT class-level. - Echo idempotency: _handle_push_task tracks an echo_done cursor on runner-owned task state so a retry that fires after the echo phase succeeded does not double-echo. Wave-1 authorization seam (full landing): - New _authorization.py with AllowlistDecision tri-state, AuthorizationContext, IdentityAllowlist Protocol, AllowAll / NativeIdAllowlist (with async loader cache + channel-scope ABSTAIN) / LinkedClaimAllowlist (raise-until-Wave-2) / AnyOfAllowlists / AllOfAllowlists / CallableAllowlist built-ins, Allowed / LinkRequired / Denied outcomes, ChannelConfigurationError. - Host(default_allowlist=..., identity_linker=...) + per-channel allowlist parameter with 'inherit' / None semantics. - _validate_channel_authorization enforces all three rules at construction: claim-source requirement, linker presence for require_link=True (elevated from no-op — must not ship unenforced), and NativeIdAllowlist(channel=...) typo detection. Combinator-walking via _flatten_allowlists catches nested misconfigs. - host.authorize(...) for the native-id pipeline: open path returns Allowed with auto-issued <channel>:<native_id> isolation key (or the existing key when the identity has been seen); ABSTAIN on a claim-required allowlist maps to Denied(reason_code='allowlist_requires_link') until Wave 2 wires the linker to convert it to LinkRequired. Spec / ADR: - docs/specs/002-python-hosting-channels.md: Wave-1 status updated to reflect the linker-presence rule elevation and the host.authorize landing; new sub-sections (codec contract, drain, echo cursor); Qs 18 / 21 DeliveryReport references purged; new resolved Qs 36–40 covering the strict-ephemeral default, codec contract, DeliveryReport removal, echo cursor, and drain. - docs/decisions/0026-hosting-channels.md: Q12 DeliveryReport reference purged; Q16 updated to reflect Wave-1 landing; new resolved Qs 20 (codec contract) + 21 (strict ephemeral / drain / echo cursor). Tests: - New tests/test_authorization.py (35 cases) covering every Wave-1 built-in, the three validator rules, combinator decision semantics, and host.authorize across open / allow / deny / abstain-with-claim-dep / abstain-without-claim-dep paths plus existing-key reuse and verified-claims propagation. - tests/test_host.py: TestDeliverResponse rewritten for the bool return + runner.scheduled-count assertions; new tests for IDENTITIES variant + echo idempotency. - tests/test_runner.py: strict-ephemeral now expects RuntimeError; allow_in_process_runner opt-in tests; shutdown drain test; payload_mode default test. - tests/test_types.py: TestDeliveryReport removed; new TestDurableTaskPayloadMode + TestResponseTargetIdentities. Validation: 178 tests pass, 91% coverage, fmt + lint + pyright + mypy clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(hosting): add mermaid flow diagrams to ADR, spec, README Insert the 10 hosting flow diagrams reviewed in python/.user/hosting-diagrams.md into the public docs: - README: runtime topology (1a) + cross-link to the spec for the richer set. - ADR: runtime topology, channel contribution shape, and authorization decision (1a, 1b, 3) at the end of 'Conceptual API shape'. - Spec: all 10 diagrams — 1a/1b at the top of API Surface, 2 in Canonical flow, 3 in Authorization profiles, 4-7 in Scenarios 6-8, 8 in Codec contract, 9 in Echo idempotency, 10 in Scenario 9. Doc-only; no API or behaviour change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(hosting): add opt-in disk persistence via state_dir Long-running hosts (always-on container, single-VM bot, local dev) lose state on every restart today. Add an opt-in disk persistence layer under a new `state_dir` constructor parameter on `AgentFrameworkHost` that survives process restarts without taking on a heavyweight database dependency. Backed by `diskcache` (installed via the new `[disk]` optional extra). An OS-level advisory file lock guarantees single-owner semantics so two hosts pointed at the same directory cannot double-execute scheduled pushes. What persists when `state_dir` is set: - Pending durable-task records — scheduled-but-not-yet-completed pushes replay on the next host startup via `InProcessTaskRunner.resume()`. Records that crashed mid-attempt resume with the already-consumed retry budget (no full-budget re-grant). - `_session_aliases` — per-isolation-key session-id rewrites. - `_active` — most-recently-active channel per isolation key. - `_identities` — `ChannelIdentity` rows for fan-out targeting, including nested mutations of the form `self._identities[ik][channel] = identity`. The `state_dir` parameter accepts any of: - `None` — today's purely in-memory behaviour. - `str` / `PathLike` — single root; host auto-creates `runner/` and `sessions/` subfolders. - `HostStatePaths` TypedDict / plain mapping — per-component overrides routed to different roots. Unknown keys raise `ValueError` to surface typos early. Unpicklable push payloads raise `PushPayloadNotPicklable` eagerly from `schedule()` so issues surface at the call site rather than on the next restart. Corrupt on-disk records are quarantined-and-logged; the runner never crashes on resume. Live `AgentSession` objects stay in memory and are rehydrated lazily by the history provider on the next turn. - New modules: `_persistence.py` (lock + normalisation), `_state_store.py` (session-bookkeeping store). - Runner rewrite: 4-state model (`pending` / `succeeded` / `failed` / `cancelled`); the transient `running` state was a bug that caused resume to skip records that crashed mid-handler. - New tests: `test_runner_disk.py` (8 tests), `test_host_disk.py` (8 tests). 194 passed total. pyright + mypy + ruff clean. - README: new "Optional disk persistence" section with code samples. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(hosting): add checkpoints to state_dir + fix host docstring Three related polish changes on top of the disk-persistence landing: 1. Extend `state_dir` to cover workflow checkpoints. Adds `checkpoints` as a third `HostStatePaths` key. Single-path form (`state_dir="/foo"`) now also auto-derives `/foo/checkpoints/` for workflow targets (equivalent to passing `checkpoint_location="/foo/checkpoints"`). The mapping form lets workflow callers opt out by omitting the key, or route checkpoints to a different volume. Conflict / precedence rules: * Explicit `checkpoint_location` always wins over the state_dir derived path; a warning surfaces the double-config. * Single-path `state_dir` + non-Workflow target → checkpoints path silently ignored (no eager directory creation either). * Mapping form with `checkpoints` + non-Workflow target → warn (almost certainly dead config). * Derived path with a workflow that already has its own `checkpoint_storage` → same `RuntimeError` as the explicit parameter triggers, so ownership stays unambiguous. Checkpoint persistence uses `FileCheckpointStorage` from the framework core — no extra dependency. Only `runner` and `sessions` require the `[disk]` extra. 2. Move `AgentFrameworkHost.__init__` parameter docs from `Args:` to `Keyword Args:` for every parameter after the `*`. Only `target` remains under `Args:`. Brings the docstring in line with the actual signature (the params have always been keyword-only). 3. `HostStatePaths` already existed as a TypedDict but did not cover `checkpoints`; updated to document the new key with the same per-attribute docstring style as `runner` / `sessions` so editors can surface help on the keys. Validation: 201 tests pass (was 194; +7 checkpoint integration tests in test_host_disk.py). pyright + mypy + ruff + bandit clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(hosting): add core IdentityLinker authorization seam Fold the core IdentityLinker pieces into the hosting-core PR so the authorization surface no longer has a deferred Wave-2 placeholder. Provider-specific linkers (for example Entra OAuth helpers) can now plug into core without core depending on an IdP SDK. Core additions: - Add LinkChallenge, LinkedIdentity, LinkResolution, and IdentityLinker. IdentityLinker.resolve(identity) is a single-call decision that returns either a linked identity with verified claims or a challenge the channel can render. - Enable LinkedClaimAllowlist end-to-end. It now abstains pre-link and allows/denies post-link against verified claims, including multi-valued claims such as groups. - Add AuthPolicy factories for common allowlist shapes. - Extend Allowed with verified_claims and claim_source for audit/telemetry without requiring callers to re-derive how the decision was made. Host behavior: - identity_linker is now typed as IdentityLinker | None. - authorize() supports open, native-id, forced-link, and linked-claim profiles end-to-end. - require_link=True resolves via the linker and returns LinkRequired when the identity is not linked. - claim-based allowlists use channel-emitted verified_claims when present, or linker-resolved claims otherwise. - authorize() remains decision-only and does not mutate _identities/_active; identity registry writes remain on the actual request execution path. Docs/tests: - Remove Wave-1/Wave-2 language from core/spec/ADR surfaces touched here. - Update the spec/ADR to describe the core linker seam and provider-specific linker packages. - Add authorization tests for linker challenges, linked identities, linked claim allowlists, channel-emitted claims, AuthPolicy factories, and the no-mutation contract. Validation: 214 tests pass, pyright/mypy/ruff clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(hosting): add link-store path to state_dir Identity linking introduces host-adjacent state that needs the same state_dir treatment as runner, session, and checkpoint state. Add a links component to the host state paths so applications and linker packages have a typed, discoverable persistence location. Changes: - Extend HostStatePaths with links and include it in state_dir normalization (state_dir/links/ for the single-path form). - Add SupportsLinkStorePath, an optional protocol for identity linkers that accept a host-provided link-store path. - AgentFrameworkHost now offers state_dir links to compatible linkers, warns when an explicit links path is supplied without a linker, and warns when the configured linker manages persistence directly instead of implementing SupportsLinkStorePath. - Update README and spec text to document the link-store component and clarify that concrete linkers still own the storage format. - Add disk-state tests for compatible, missing, and non-configurable linkers. Validation: 217 tests pass, pyright/mypy/ruff clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>Eduard van Valkenburg ·
2026-05-22 14:55:56 +02:00 -
Python: bump package versions for 1.6.0 release (#6017)
* Python: bump package versions for 1.6.0 release - Released cohort (agent-framework, core, openai, foundry): 1.5.0 -> 1.6.0 - Beta packages (21 packages): 1.0.0b260519 -> 1.0.0b260521 - Alpha packages (azure-contentunderstanding, foundry-hosting, gemini, monty): 1.0.0a260518/19 -> 1.0.0a260521 - ag-ui stays at 1.0.0rc2, orchestrations at 1.0.0rc1 (dependency bounds updated) - Inter-package dependency lower bounds updated (>=1.5.0,<2 -> >=1.6.0,<2) - Update CHANGELOG compare links - uv.lock refreshed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: bump RC packages, add shell tool to changelog - ag-ui: 1.0.0rc2 -> 1.0.0rc3 - orchestrations: 1.0.0rc1 -> 1.0.0rc2 - Add shell tool (#5664) to CHANGELOG - uv.lock refreshed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-05-22 01:59:20 +00:00 -
Python: Shell tool with support for local and Docker (#5664)
* feat(tools): add cross-OS LocalShellTool in new agent-framework-tools package Introduces a safe, cross-OS local shell tool as the first citizen of a new agent-framework-tools workspace package. Supports persistent (default) and stateless modes across pwsh/powershell.exe/bash/sh, with policy denylist, allowlist, approval gating, process-tree kill on timeout, output truncation, and audit hooks. Integrates with existing provider get_shell_tool(func=...) factories via FunctionTool kind='shell'. See docs/decisions/0026-builtin-tools-local-shell.md for the full design. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(tools): security hardening for LocalShellTool Codifies what LocalShellTool does and does not defend against, and delegates the security-relevant lifecycle primitive to a battle-tested library instead of hand-rolled per-OS code. Changes: - Adopt psutil for cross-OS process-tree termination (executor + session). Replaces hand-rolled taskkill/killpg with one canonical implementation. - Resolve taskkill.exe to absolute %SystemRoot%\System32 path so PATH poisoning cannot redirect us to an attacker-supplied binary. - Reframe ShellPolicy docstring + ADR + README: denylist is a guardrail, not a security boundary. - Require acknowledge_unsafe=True to set approval_mode='never_require', making the unsafe path explicitly opt-in with a self-documenting name. - Add tests/test_security.py codifying named CVE-style cases. Defenses we DO claim are asserted; non-defenses (denylist bypasses via backslash insertion, variable expansion, interpreter escape, base64, alternative tools, PowerShell-native verbs) are documented as expected-to-pass tests so residual risk stays visible. - Add Threat Model + Confidence Strategy sections to ADR 0026. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(tools): add DockerShellTool sandboxed shell tier Adds a container-backed shell executor as the recommended pattern for untrusted-input shell workflows. The container provides the security boundary (--network none, non-root user, --read-only, --cap-drop ALL, no-new-privileges, memory/pids limits, tmpfs /tmp), so approval gating is optional unlike LocalShellTool. Also introduces a ShellExecutor Protocol so callers can plug in custom backends (Firecracker, SSH, WASI) without forking the framework. Removes the planned HyperlightShellExecutor follow-up from ADR 0026: Hyperlight is a WASM code sandbox with no kernel/userland/shell binary, so a Hyperlight-backed shell is not viable. Docker is the realistic sandbox tier for shell. Tests: 11 unit tests for argv builders + lifecycle (no Docker daemon required); 3 integration tests gated on is_docker_available(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(tools): backport shell-tool fixes from .NET parity review Applies the applicable subset of bug fixes accumulated during the .NET shell-tool PR review (microsoft/agent-framework#5604) to the Python shell tool. A1 - Quote workdir safely in _maybe_reanchor Previously _tool.py used double-quote interpolation when emitting the cd/Set-Location prefix, which expanded $VAR, $(), and backticks in the workdir path. A workdir containing shell metacharacters could trigger arbitrary command execution before the user command ran. Replaced with single-quote escaping helpers _quote_posix and _quote_powershell that emit literal-string forms safe for both hosts. A5/A6 - Consolidate truncation to a single byte-aware helper Extracted a shared truncate_head_tail / truncate_text_head_tail helper in _truncate.py. The new implementation distributes odd caps so head receives floor(cap/2) and tail receives ceil(cap/2) bytes, matching the .NET round-9 fix and ensuring no input bytes are silently dropped on the boundary. _session.py previously truncated by Python str length while the caller passed _max_output_bytes - the unit mismatch is now gone: raw byte buffers go through truncate_head_tail and decoded text goes through truncate_text_head_tail. Unit tests added for the truncate and quote helpers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(tools): tone down narrative and overconfident comments in shell tool The shell tool's docstrings and comments contained two patterns that the .NET review pushed back on: - Narrative framing about implementation history ("hard-won", "we sidestep", "design inspiration: ...", competitor framework name-drops in module docstrings). - Overstated security guarantees ("battle-tested", "reasonable for untrusted input", "recommended executor for any agent that runs commands from untrusted input", "destructive commands are blocked", "safe local shell tool", "blocks shell injection"). Rewrites the affected docstrings and comments to describe what the code does in neutral terms. Behaviour is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(tools): add ShellEnvironmentProvider for the Python shell tool Ports the .NET ShellEnvironmentProvider as a Python ContextProvider so agents using LocalShellTool or DockerShellTool can be primed with an accurate description of the shell they're talking to (family, version, OS, working directory, and which CLIs are available). The provider runs probes through any ShellExecutor, caches the resulting snapshot, and on every before_run extends the session instructions with a markdown block describing the shell idiom to use. A failed first probe leaves the cache empty so the next call retries (no permanent poisoning). Probe failures from a narrow set of expected error types (ShellCommandError, ShellExecutionError, ShellTimeoutError, and asyncio.TimeoutError from the per-probe timeout) are recorded as None fields in the snapshot. Other exceptions propagate. Tool names are validated against ^[A-Za-z0-9._-]+$ before being interpolated into a probe command. Includes 12 unit tests covering happy path, stderr fallback, timeout handling, expected/unexpected exception paths, malicious tool name rejection, case-insensitive deduplication, retry after failure, concurrent first-callers sharing one probe, and the default and custom formatter paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(tools): document ShellEnvironmentProvider and finish comment cleanup Add a README section introducing ShellEnvironmentProvider, soften two remaining overconfident security-boundary comments in _executor_base.py and the DockerShellTool class docstring, and add a sample (shell_with_environment_provider.py) that demonstrates the provider in stateless and persistent modes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(tools): move shell samples to python/samples/02-agents/tools The repository convention is to host samples under python/samples/ rather than inside the package directory. Move the two net-new shell samples (allow-list and environment-provider) to python/samples/02-agents/tools/ and drop the in-package samples/ directory; the existing top-level providers/openai/client_with_local_shell.py already covers the basic LocalShellTool walkthrough. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(tools): cover confine_workdir default and ShellResult.format_for_model Two new tests in test_local_shell_tool.py exercise the default confine_workdir=True behaviour on POSIX and PowerShell, asserting that 'cd' inside one persistent-mode call does not leak into the next. A new test_shell_result.py module provides direct unit coverage for every conditional branch of ShellResult.format_for_model (stdout, truncated, stderr, timed_out, exit_code) so regressions in the LLM-facing format are caught immediately. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(tools): address PR #5664 review feedback - _tool.py: detect PowerShell via is_powershell() helper instead of basename string match - _environment.py: use public ContextProvider import (no private _ prefix) - _session.py: trim _stdout_buf/_stderr_buf after copying to avoid unbounded retention across calls - _docker.py: short-circuit start()/close() in stateless mode; add configurable shell kwarg (default bash, e.g. 'sh' for alpine) - tests: parenthesized multi-line assert; alpine integration tests now pass shell='sh' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(tools): satisfy CI quality gates - pyupgrade: drop quoted self-class refs in __aenter__/method annotations - ruff format: reflow long lines per workspace style - pyright: assert psutil non-None in optional-import branch; lowercase mutable module globals; annotate _approval_mode as Literal so tool() Literal-typed kwarg is accepted; add ... body to ShellExecutor.run protocol; remove unused deprecated _kill_tree wrapper - tests: skip docker integration tests on win32 (Windows containers don't support --read-only / alpine images) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove DEFAULT_DENYLIST; document single-session ownership; fix bandit findings Mirrors the .NET PR #5604 cleanup: - Remove DEFAULT_DENYLIST from ShellPolicy. ShellPolicy() now ships with an empty deny-list; operators opt into site-specific patterns explicitly. No major agent framework uses regex matching as a primary security control; AutoGen v2 removed theirs. Approval gating + sandbox tier remain the real boundaries. - Rewrite module / class docstrings to frame ShellPolicy as a UX pre-filter, not a security control. - Add Single-session ownership paragraphs to ShellExecutor, ShellSession, LocalShellTool, and DockerShellTool: a persistent-mode tool is owned by exactly one conversation / agent session; do not share across users or concurrent conversations. - Tests now supply explicit deny patterns instead of relying on a default. - Address Pre-commit Hooks (bandit) CI failures: convert internal-invariant asserts to explicit RuntimeError, annotate intentional subprocess/shell usage with # nosec, document container-internal /tmp paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR #5664 round-2 review feedback Deny-list documentation drift: - README and the OpenAI/local-shell sample no longer claim a built-in deny-list of destructive commands. ShellPolicy is described as an optional, operator-supplied UX pre-filter; the real boundaries remain approval gating and the sandbox tier. Behavioural fixes called out in review: - ShellPolicy.evaluate() now denies empty / whitespace-only commands explicitly instead of returning allow with no rationale. - truncate_head_tail() raises ValueError for cap <= 0 instead of silently returning the full input with truncated=False, which previously could defeat output-capping in callers that mis-configured the budget. - LocalShellTool.as_function() / DockerShellTool.as_function() return the ShellCommandError text directly so the model sees a single, non-redundant 'Command rejected by policy: …' message instead of the prior duplicated 'Command blocked by policy: Command rejected …' wrapping. - ShellSession POSIX sentinel trailer now snapshots and restores the prior errexit (set -e) state around the trailer, so a user 'set -e' in the persistent shell is no longer permanently disabled by the next run(). Tests: - New test_shell_parse_rc.py covers the full _parse_rc() edge-case surface (zero, positive, negative, CRLF, no newline, missing prefix, empty input, non-digits, trailing garbage, partial digits). - test_policy.py asserts the new empty-command deny. - test_shell_truncate_and_quote.py asserts ValueError for cap=0 and cap<0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review feedback for shell tool - _resolve.py: reject empty/whitespace shell override string - _tool.py / _docker.py: mode-aware default tool description (persistent vs stateless) - _tool.py: fix misleading workdir docstring (re-anchor, not blocking) - _types.py: emit stream-agnostic [output truncated] marker - _policy.py: declare _denies/_allows as dataclass fields - _environment.py: use $(pwd) instead of $PWD in POSIX probe Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review feedback: shell override flag + probe timeout safety - _resolve.py: in stateless mode, ensure shell overrides end with -c/-Command so commands aren't misinterpreted as script-file paths. - ShellExecutor.run / LocalShellTool.run / DockerShellTool.run now accept an optional imeout kwarg; ShellEnvironmentProvider drops the outer asyncio.wait_for and lets the executor enforce the probe timeout internally, so cancellation no longer risks leaving a hung subprocess or corrupted session. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback: docker isolation + lifecycle robustness - pyproject.toml: bump agent-framework-core minimum from 1.2.0 to 1.2.2 to align with the rest of the workspace. - _docker.py: validate extra_run_args at construction time and reject flags that would dismantle the isolation defaults (--privileged, --cap-add, --security-opt, --network/--net, -v/--volume/--mount, --device, --pid, --ipc, --userns, --user, --read-only, --tmpfs, --add-host, --gpus, --cgroupns, --device-cgroup-rule); also documented the warning on the docstring. - _docker._stop_container: retry docker rm -f once and log a warning/error when it does not succeed, so operators can audit leaked containers instead of getting a silent success. - _docker._run_stateless timeout path: fall back to docker rm -f when docker kill fails or times out (--rm only reaps on clean exit), and log instead of silently swallowing communicate() errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: alliscode <bentho@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: alliscode <25218250+alliscode@users.noreply.github.com>
Ben Thomas ·
2026-05-22 00:29:59 +00:00 -
Python: feat: add agent-framework-monty (Monty-backed CodeAct provider) (#5915)
* Python: feat: add agent-framework-monty (Monty-backed CodeAct) New alpha package that wraps pydantic-monty (a Rust-based Python interpreter) behind the same CodeAct API surface as agent-framework-hyperlight, so users can swap providers with minimal code change. Public API (agent_framework_monty): - MontyCodeActProvider — ContextProvider that injects a run-scoped execute_code tool plus dynamic CodeAct instructions. - MontyExecuteCodeTool — standalone FunctionTool for mixed-tool agents or manual static wiring. - FileMount / FileMountInput / MountMode — public types mirroring the Hyperlight names, with Monty's mode (read-only/read-write/overlay) and write_bytes_limit on FileMount. Constructor kwargs (both classes) mirror Hyperlight where possible: tools, approval_mode, workspace_root, file_mounts; plus a Monty-only resource_limits forwarding ResourceLimits to Monty.start(). Filesystem flow: - workspace_root auto-mounts at /input (read-write), matching Hyperlight. - file_mounts accepts string shorthand, (host, mount) tuple, or FileMount with mode + write cap. - Files written under read-write mounts are scanned post-execution and returned as Content.from_data items (mirrors Hyperlight /output). - overlay mounts buffer writes in-memory; read-only mounts reject writes. Internals: - _monty_bridge.InlineCodeBridge ports the inline (non-durable) bridge from anthonychu/maf-codeact-monty-python; handles FunctionSnapshot / FutureSnapshot pause/resume, dispatches direct typed calls + the call_tool fallback, forwards mount/limits to Monty.start(...). - generate_type_stubs emits per-tool stubs so Monty's `ty` type-checker rejects bad calls before any host tool runs. Alpha-policy compliance (per python-package-management skill): - Added agent-framework-monty = { workspace = true } to root pyproject.toml. - Added row to python/PACKAGE_STATUS.md. - Added monty entry under Experimental in python/AGENTS.md. - NOT added to core[all]; NO agent_framework.monty lazy shim (deferred to beta promotion). Samples (three sets, import from agent_framework_monty directly): - samples/02-agents/context_providers/code_act/monty_code_act.py (provider pattern) + updated local README. - samples/02-agents/tools/monty_code_interpreter/ (standalone + manual-wiring + README). - samples/04-hosting/foundry-hosted-agents/responses/11_monty_codeact/ (full hosted-agent layout with uv-based pyproject.toml + Dockerfile, Azure Monitor wiring via APPLICATIONINSIGHTS_CONNECTION_STRING + enable_instrumentation, ENABLE_INSTRUMENTATION and ENABLE_SENSITIVE_DATA env vars). The alpha wheel is vendored into ./wheels/ (gitignored) via vendor-wheel.sh; new row added to the parent Responses-API README. Tests: - 28 hermetic unit tests (stubbed pydantic_monty). - 18 integration tests marked @pytest.mark.integration, auto-skipped when pydantic_monty is unimportable; exercise the real Monty runtime: print round-trip, last-expression value, direct typed tool dispatch, call_tool fallback, async tool, asyncio.gather parallelism, ty type-check rejection, OS blocked by default, workspace_root read+write capture, read-only / overlay mount semantics, resource_limits.max_duration_secs abort, approval gating end-to-end, full Agent run with a scripted chat client. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix: monty FileMount test compares against the normalized POSIX path The shorthand string mount goes through _normalize_mount_path, which rewrites Windows drive letters like 'C:\\Users\\...' into '/C:/Users/...' (POSIX-style). The Windows CI runners surfaced this because tmp_path resolves to a backslashed Windows path; the test was comparing against the raw str(host_a) instead of the normalized form. Compare against _normalize_mount_path(str(host_a)) so the assertion is platform-independent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix: address PR #5915 review feedback - _execute_code_tool docstring: clarify that the Monty backend supports scoped filesystem access via workspace_root / file_mounts (blocked by default). - _to_monty_mount: import pydantic_monty lazily through load_monty so missing-dependency errors surface as the same actionable RuntimeError the rest of the package raises (not a bare ImportError at module load). Renamed _load_monty -> load_monty for the same reason. - _python_type_repr: emit None for type(None) instead of Any, and normalize both typing.Union[...] and PEP-604 X | Y to PEP-604 syntax so Optional[X] / Union[..., None] / -> None signatures round-trip correctly through ty validation. Added a regression test. - _PrintCollector: track a running character count instead of recomputing sum(len(c) for c in self.chunks) per callback. Eliminates the O(n^2) cost on print-heavy code. - Instructions: mention that the value of the final expression is also returned alongside captured stdout (matches actual behavior). - 11_monty_codeact Dockerfile: pin ghcr.io/astral-sh/uv to 0.11.6 instead of :latest for reproducible builds. - 11_monty_codeact README: replace the bare "see parent README" pointer with sample-specific steps (./vendor-wheel.sh + uv sync + uv run), since the sample uses pyproject.toml + a vendored wheel rather than requirements.txt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: sample: 11_monty_codeact installs agent-framework-monty from PyPI Drop the vendored-wheel scaffolding now that agent-framework-monty is on PyPI as an alpha (1.0.0a*) release: - pyproject.toml: remove [tool.uv.sources] override; keep [tool.uv] prerelease = "allow" so uv pulls the alpha automatically. - Dockerfile: drop the COPY wheels/ step. - README: drop the ./vendor-wheel.sh setup step and the not-yet-on-PyPI warning. - Delete vendor-wheel.sh and the gitignored wheels/ directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix(monty): harden post-execution file capture against symlink escape Same class of issue as the MSRC-reported Hyperlight finding: the post-execution capture walked workspace_root with Path.rglob() + is_file() + read_bytes() - all of which follow symlinks. An attacker who controls the workspace (cloned repo, extracted archive, shared workspace) could pre-place `workspace/leak.txt -> /etc/passwd` or `workspace/outside_dir -> /etc/` and have host files surface as captured Content items. Monty's mount layer already rejects symlink reads from inside the sandbox across all three modes (verified empirically), so the runtime path was safe. This commit closes the post-execution scan path. Changes: - New `_iter_real_files(root)` walker that uses iterdir() + is_symlink() to skip symlinks at every directory level and yields only real files. Replaces the previous `host_root.rglob("*")` calls in both `_snapshot_writable_mounts` and `_capture_written_files`. - Use `Path.lstat()` instead of `Path.stat()` so size/mtime can never be taken from a symlink target. - Three new integration tests reproducing the MSRC attack shape against the workspace_root flow: symlink-to-file outside workspace, symlink-to-directory outside workspace, and a guard ensuring legitimate sandbox writes are still captured when symlinks are present. Per user request, hyperlight is untouched in this commit (separate fix). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix(monty): skip symlink regression tests when unsupported Apply the same Windows-CI safety guard as the hyperlight fix in PR #5919: the three symlink integration tests create symlinks via Path.symlink_to(), which fails with OSError / NotImplementedError on unprivileged Windows runners. Add a local _symlinks_supported helper (mirroring the one in packages/core/tests/core/test_skills.py) and pytest.skip when symlinks aren't available, so the tests no longer fail for environment reasons. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: fix(monty): address PR #5915 follow-up review feedback - _invoke_tool: drop the inspect.iscoroutinefunction(...) branch and always `await self.tool_map[name](**kwargs)`. Every entry in tool_map is `partial(FunctionTool.invoke, skip_parsing=True)` and FunctionTool.invoke is `async def`, so the branching was dead code - and on Python versions affected by cpython#98590, iscoroutinefunction(partial(bound_async_method, ...)) returns False, causing the bridge to take the asyncio.to_thread path, return an unawaited coroutine, and surface it as a JSON-serialization failure for every tool call. Added a regression test test_invoke_tool_awaits_partial_wrapped_async_method. - generate_type_stubs: skip tools whose name is not a valid Python identifier or is a Python keyword. FunctionTool.name has no upstream validation, so a name like "weird-name" produced a syntax error in the stubs and a name like "broken\n pass\nasync def injected" would inject arbitrary stub source. Non-identifier names stay reachable via `call_tool("weird-name", ...)` at runtime; they just don't get type-checked stubs. Added regression test test_generate_type_stubs_skips_non_identifier_tool_names. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>Eduard van Valkenburg ·
2026-05-20 00:35:23 +00:00 -
Python: Bump Python package versions for a release (#5964)
* Bump Python package versions to 1.5.0 for a release * Promote orchestrations to 1.0.0rc1 * ci(python-setup): merge dynamic exclude into existing workspace exclude The python-setup action injected exclude = [...] verbatim into [tool.uv.workspace], producing a duplicate 'exclude' key when the section already had a static exclude. Scope the rewrite to the [tool.uv.workspace] section and append the package to the existing array when present; idempotent if the package is already excluded. * Address Copilot review feedback: raise inter-package floors to 1.5.0 - foundry, foundry-local: agent-framework-openai >=1.4.0 -> >=1.5.0 - azure-contentunderstanding: agent-framework-foundry >=1.4.0 -> >=1.5.0 - azurefunctions: pin agent-framework-durabletask to >=1.0.0b260519,<2 Keeps lockstep cohort consistent and avoids mixed 1.4.x / 1.5.0 installs. * Re-include azurefunctions and durabletask in the uv workspace The pinned durabletask>=1.4.0 floor is enough to make resolution succeed; the workspace exclude was over-correction and broke CI samples and pyright type-checking (re-exports in agent_framework/azure/__init__.pyi plus samples/04-hosting/{azure_functions,durabletask}/ could not resolve their imports). Dropping them from agent-framework-core[all] still stands so the metapackage does not pull them. * Restore azurefunctions and durabletask in agent-framework-core[all] The durabletask floor pin keeps users on the safe 1.4.0, so they are once again included in the metapackage. Update CHANGELOG to reflect the pin rather than an [all] removal. * Raise uvicorn ceiling in ag-ui and devui to allow 0.42+ The root override-dependencies pins uvicorn[standard]>=0.34.0 (no upper) and the workspace lock resolves to 0.47.0. The package ceiling <0.42.0 meant the workspace was no longer testing the declared supported range. Bump to <1 so the lock fits within the declared bounds. Also picked up by validate-dependency-bounds: refresh stale orchestrations RC pin in devui dev deps.Evan Mattson ·
2026-05-20 09:20:53 +09:00 -
Python: bump package versions for 1.4.0 release (#5872)
* fixes * fixes * Python: bump package versions for 1.4.0 release Cuts the python-1.4.0 release. MINOR bump on the released cohort (agent-framework, agent-framework-core, agent-framework-openai, agent-framework-foundry: 1.3.0 -> 1.4.0), driven by breaking changes in experimental skills API and new features. All 21 beta packages stamp 1.0.0b260514, all 3 alpha packages stamp 1.0.0a260514, and ag-ui remains at 1.0.0rc1 (freshly promoted). Date stamp reflects 2026-05-14 Pacific. - Released cohort: 1.3.0 -> 1.4.0 - Beta packages (21): 1.0.0b260507 -> 1.0.0b260514 - Alpha packages (3): 1.0.0a260507 -> 1.0.0a260514 - ag-ui: stays at 1.0.0rc1 (dep bound updated only) - Inter-package dependency lower bounds updated (>=1.3.0 -> >=1.4.0) - Fix chatkit StructuredInputItem exhaustiveness for openai-chatkit 1.6.4 - Update CHANGELOG compare links - uv.lock refreshed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-05-15 09:31:03 +09:00 -
Python: bump package versions for 1.3.0 release (#5706)
* Python: bump package versions for 1.3.0 release MINOR bump on the released cohort (agent-framework, agent-framework-core, agent-framework-openai, agent-framework-foundry: 1.2.2 -> 1.3.0). All 22 beta packages stamp 1.0.0b260507 and all 3 alpha packages stamp 1.0.0a260507 per the lockstep convention. Date stamp reflects 2026-05-07 Pacific. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: bump foundry_local openai floor, fix devui orchestrations pin, clarify breaking scope - foundry_local: bump agent-framework-openai lower bound from >=1.1.0 to >=1.3.0 - devui: update stale agent-framework-orchestrations dev pin from 1.0.0b260402 to 1.0.0b260507 - CHANGELOG: clarify [BREAKING] applies to experimental skills API only Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert devui orchestrations pin to 1.0.0b260402 to avoid breaking DevUI Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Giles Odigwe ·
2026-05-08 08:57:02 +09:00 -
Python: bump package versions for 1.2.2 release (#5561)
* Python: bump package versions for 1.2.2 release PATCH bump (1.2.1 -> 1.2.2) for the released cohort. Five PRs land in this window: - agent-framework-openai: fix file_search citations breaking the assistant- message history roundtrip (#5557) — drives the released-tier PATCH - agent-framework-orchestrations: [BREAKING] standardize orchestration terminal outputs as AgentResponse (#5301) - agent-framework-core, agent-framework-declarative: preserve Workflow.run() shared state across calls, accept list[Message] in declarative start executor, and coerce Enum values when serializing PowerFx symbols (#5531) - agent-framework-foundry-hosting: add hosted Durable Workflow support (#5531) - agent-framework-azure-contentunderstanding: new alpha package — Azure AI Content Understanding context provider (#4829) - dependencies: workspace package dependency refresh (#5555) Per lockstep convention, all 21 beta packages stamp 1.0.0b260429 and all 4 alpha packages (now including the new contentunderstanding) stamp 1.0.0a260429. Date stamp reflects 2026-04-29 Pacific. Every non-core package floor on agent-framework-core is raised to >=1.2.2; the new contentunderstanding package's stale >=1.0.0 floor is brought into line. Two follow-on fixes bundled to keep validate-dependency-bounds-test green at lowest-direct resolution: - Bump agent-framework-azure-contentunderstanding's azure-ai-content understanding lower bound from >=1.0.0 to >=1.0.1 (1.0.0 ships without proper typing — pyright reports 65 unknown-type errors) - Add pyright ignore comments to core/foundry/__init__.pyi for the new alpha package's type-stub imports, since alpha packages are not in core's [all] extra and therefore aren't installed at lowest-direct * Python: add #5552 to 1.2.2 CHANGELOG Add the streaming-span observability fix to the Fixed section. PR is on upstream/main but not yet pulled into origin/main; the code itself will land via the PR merge. * Python: address PR #5561 review feedback on dependency bounds Two packaging fixes flagged in review: 1. agent-framework-azure-contentunderstanding: add agent-framework-foundry as a runtime dependency. The package's README directs users to `pip install agent-framework-azure-contentunderstanding --pre` and the basic example imports `FoundryChatClient` from `agent_framework.foundry`, so the documented install path was failing with ImportError. Pulling agent-framework-foundry into deps makes the advertised entry path self-contained. 2. agent-framework-foundry: bump agent-framework-openai lower bound from >=1.1.0 to >=1.2.2,<2. Foundry imports private modules from agent_framework_openai (`_chat_client.py:22`, `_agent.py:34`), so resolvers were free to pair foundry==1.2.2 with older OpenAI versions that lack this release's coordinated Responses/history fix. Lockstep the floor with the released cohort to prevent mismatched installs. Both changes pass `validate-dependency-bounds-test` lower + upper at their respective packages.
Evan Mattson ·
2026-04-29 17:51:48 +09:00 -
Python: Update package dependencies (#5555)
* Update dependencies * Preserve mcp[ws] and uvicorn[standard] extras in override-dependencies Bare-package overrides on mcp and uvicorn dropped the [ws] and [standard] extras (and their transitive deps like httptools, watchfiles) from the generated lock. Re-add the extras to the overrides so the lock matches what workspace packages actually request.
Evan Mattson ·
2026-04-29 06:18:03 +00:00 -
[Python] Add agent-framework-azure-ai-contentunderstanding package (#4829)
* feat: add agent-framework-azure-contentunderstanding package Add Azure Content Understanding integration as a context provider for the Agent Framework. The package automatically analyzes file attachments (documents, images, audio, video) using Azure CU and injects structured results (markdown, fields) into the LLM context. Key features: - Multi-document session state with status tracking (pending/ready/failed) - Configurable timeout with async background fallback for large files - Output filtering via AnalysisSection enum - Auto-registered list_documents() and get_analyzed_document() tools - Supports all CU modalities: documents, images, audio, video - Content limits enforcement (pages, file size, duration) - Binary stripping of supported files from input messages Public API: - ContentUnderstandingContextProvider (main class) - AnalysisSection (output section selector enum) - ContentLimits (configurable limits dataclass) Tests: 46 unit tests, 91% coverage, all linting and type checks pass. * fix: update CU fixtures with real API data, fix test assertions - Replace synthetic fixtures with real CU API responses (sanitized) - Update test assertions to match real data (Contoso vs CONTOSO, TotalAmount vs InvoiceTotal, field values from real analysis) - Add --pre install note in README (preview package) - Document unenforced ContentLimits fields (max_pages, duration) * chore: add connector .gitignore, update uv.lock * refactor: rename to azure-ai-contentunderstanding, fix CI issues Align naming with Azure SDK convention and AF pattern: - Directory: azure-contentunderstanding -> azure-ai-contentunderstanding - PyPI: agent-framework-azure-contentunderstanding -> agent-framework-azure-ai-contentunderstanding - Module: agent_framework_azure_contentunderstanding -> agent_framework_azure_ai_contentunderstanding CI fixes: - Inline conftest helpers to avoid cross-package import collision in xdist - Remove PyPI badge and dead API reference link from README (package not published yet) * feat: add samples (document_qa, invoice_processing, multimodal_chat) - document_qa.py: Single PDF upload, CU context provider, follow-up Q&A - invoice_processing.py: Structured field extraction with prebuilt-invoice - multimodal_chat.py: Multi-file session with status tracking - Add ruff per-file-ignores for samples/ directory - Update README with samples section, env vars, and run instructions * feat: add remaining samples (devui_multimodal_agent, large_doc_file_search) - S3: devui_multimodal_agent/ — DevUI web UI with CU-powered file analysis - S4: large_doc_file_search.py — CU extraction + OpenAI vector store RAG - Update README and samples/README.md with all 5 samples * feat: add file_search integration for large document RAG Add FileSearchConfig — when provided, CU-extracted markdown is automatically uploaded to an OpenAI vector store and a file_search tool is registered on the context. This enables token-efficient RAG retrieval for large documents without users needing to manage vector stores manually. - FileSearchConfig dataclass (openai_client, vector_store_name) - Auto-create vector store, upload markdown, register file_search tool - Auto-cleanup on close() - When file_search is enabled, skip full content injection (use RAG instead) - Update large_doc_file_search sample to use the integration - 4 new tests (50 total, 90% coverage) * fix: add key-based auth support to all samples Follow established AF pattern: check for API key env var first, fall back to AzureCliCredential. Supports AZURE_OPENAI_API_KEY and AZURE_CONTENTUNDERSTANDING_API_KEY environment variables. * FEATURE(python): add analyzer auto-detection, file_search RAG, and lazy init _context_provider.py: - Make analyzer_id optional (default None) with auto-detection by media type prefix: audio->audioSearch, video->videoSearch, else documentSearch - Add _ensure_initialized() for lazy client creation in before_run() - Add FileSearchConfig-based vector store upload - Fix: background-completed docs in file_search mode now upload to vector store instead of injecting full markdown into context messages - Add _pending_uploads queue for deferred vector store uploads devui_file_search_agent/ (new sample): - DevUI agent combining CU extraction + OpenAI file_search RAG azure_responses_agent (existing sample fix): - Add AzureCliCredential support and AZURE_AI_PROJECT_ENDPOINT fallback Tests (19 new), Docs updated (AGENTS.md, README.md) * feat(cu): MIME sniffing, media-aware formatting, unified timeout, vector store expiration - Add three-layer MIME detection (fast path → filetype binary sniff → filename fallback) to handle unreliable upstream MIME types (e.g. mp4 sent as application/octet-stream). Adds filetype>=1.2,<2 dependency. - Media-aware output formatting: video shows duration/resolution + all fields as JSON; audio promotes Summary as prose; document unchanged. - Unified timeout for all media types (removed file_search special-case that waited indefinitely for video/audio). All files use max_wait with background polling fallback. - Vector store created with expires_after=1 day as crash safety net. - Add 8 MIME sniffing tests (TestMimeSniffing class). * fix: merge all CU content segments for video/audio analysis CU's prebuilt-videoSearch and prebuilt-audioSearch analyzers split long media files into multiple `contents[]` segments. Previously, `_extract_sections()` only read `contents[0]`, causing truncated duration, missing transcript, and incomplete fields for any video/audio longer than a single scene. Now iterates all segments and merges: - duration: global min(startTimeMs) → max(endTimeMs) - markdown: concatenated with `---` separators - fields: same-named fields collected into per-segment list - metadata (kind, resolution): taken from first segment Single-segment results (documents, short audio) are unaffected. Update test fixture to realistic 3-segment video structure and expand assertions to verify multi-segment merging. Add documentation for multi-segment processing and speaker diarization limitation. * refactor: improve CU context provider docs and remove ContentLimits - Improve class docstring: clarify endpoint (Azure AI Foundry URL with example), credential (AzureKeyCredential vs Entra ID), and analyzer_id (prebuilt/custom with auto-selection behavior and reference links) - Add SUPPORTED_MEDIA_TYPES comments explaining MIME-based matching behavior and add missing file types per CU service docs - Use namespaced logger to align with other packages - Remove ContentLimits and related code/tests - Rename DEFAULT_MAX_WAIT to DEFAULT_MAX_WAIT_SECONDS for clarity * feat: support user-provided vector store in FileSearchConfig - Add vector_store_id field to FileSearchConfig (None = auto-create) - Track _owns_vector_store to only delete auto-created stores on close() - Remove vector_store_name; use internal _DEFAULT_VECTOR_STORE_NAME - Add inline comments for private state fields - Document output_sections default in docstring - Update AGENTS.md, samples, and tests * fix: remove ContentLimits from README code block * refactor: create CU client in __init__ instead of __aenter__ Follow Azure AI Search provider pattern: create the client eagerly in __init__, make __aenter__ a no-op. This ensures __aexit__/close() is always safe to call and eliminates the _ensure_initialized() workaround. * docs: add file_search param to class docstring * feat: introduce FileSearchBackend abstraction for cross-client support Replace direct OpenAI client usage with FileSearchBackend ABC: - OpenAIFileSearchBackend: for OpenAIChatClient (Responses API) - FoundryFileSearchBackend: for FoundryChatClient (Azure Foundry) - Shared base _OpenAICompatBackend for common vector store CRUD FileSearchConfig now takes a backend instead of openai_client. Factory methods from_openai() and from_foundry() for convenience. BREAKING: FileSearchConfig(openai_client=...) -> FileSearchConfig.from_openai(...) * refactor: FileSearchBackend abstraction + caller-owned vector store * fix: file_search reliability and sample improvements - Poll vector store indexing (create_and_poll) to ensure file_search returns results immediately after upload - Set status to failed when vector store upload fails - Skip get_analyzed_document tool in file_search mode to prevent LLM from bypassing RAG - Simplify sample auth: single credential, direct parameters - Use from_foundry backend for Foundry project endpoints * perf: set max_num_results=10 for file_search to reduce token usage * fix: move import to top of file (E402 lint) * chore: remove unused imports * fix: align azure-ai-contentunderstanding with MAF coding conventions - Add module-level docstrings to __init__.py and _context_provider.py - Use Self return type for __aenter__ (with typing_extensions fallback) - Use explicit typed params for __aexit__ signature - Add sync TokenCredential to AzureCredentialTypes union - Pass AGENT_FRAMEWORK_USER_AGENT to ContentUnderstandingClient - Remove unused ContentLimits from public API and tests - Fix FileSearchConfig tests to match refactored backend API - Fix lifecycle tests to match eager client initialization * refactor: improve CU context provider API surface and fix CI - Refactor _analyze_file to return DocumentEntry instead of mutating dict - Remove TokenCredential from AzureCredentialTypes (fixes mypy/pyright CI) - Remove OpenAIFileSearchBackend/FoundryFileSearchBackend from public API (internal to FileSearchConfig factory methods) - Remove DocumentStatus from public exports (implementation detail) - Update file_search comments to reflect backend-agnostic design - Add DocumentStatus enum, analysis/upload duration tracking - Add combined timeout for CU analysis + vector store upload * fix: improve file_search samples and move tool guidelines to context provider - Delete redundant devui_file_search_agent sample (duplicate of azure_openai variant) - Move tool usage guidelines from sample agent instructions into context provider (extend_instructions in step 6, applied automatically for all file_search users) - Fix file_search purpose: use from_foundry() for Azure OpenAI (purpose="assistants") - Add filename hint in upload instructions for targeted file_search queries - Reduce max_num_results from 10 to 3 in both devui samples - Simplify agent instructions in both samples (remove tool-specific guidance) * feat: improve source_id, integration tests, and content assertions - Rename DEFAULT_SOURCE_ID to "azure_ai_contentunderstanding" (matches azure_ai_search convention) - Improve source_id docstring to describe default value - Clarify _detect_and_strip_files docstring (CU-supported files) - Add invoice.pdf test fixture from Azure CU samples repo - Refactor integration tests to use invoice.pdf directly (assert instead of skip when fixture missing) - Add URI content test (Content.from_uri with external URL) - Add "CONTOSO LTD." content assertion to all integration tests - Use max_wait=None in integration tests (wait until complete) * feat: reject duplicate filenames, add integration tests and sample comments - Reject duplicate document keys in before_run (skip + warn LLM to rename) - Update _derive_doc_key docstring to document uniqueness constraint - Add unit tests for duplicate filename rejection (cross-turn and same-turn) - Add integration test for data URI content (from_uri with base64) - Add integration test for background analysis (max_wait timeout + resolve) - Add filename recommendation comments to all samples' Content.from_data() * chore: improve doc key derivation, comments, and README - Replace hash-based doc key with uuid4 for anonymous uploads (O(1), no payload traversal) - Remove hashlib import (no longer needed) - Add File Naming section to README (filename importance, duplicate rejection) - Improve inline comments (_derive_doc_key, _extract_binary, URL parsing) * test: strengthen _format_result assertions with exact expected strings - Replace loose 'in' checks with exact 'assert formatted == expected' for both multi-segment and single-segment format tests - Add object-type fields (ShippingAddress, Speakers) to test data to cover nested dict/list serialization - Add position-based ordering assertions to verify structural correctness (header -> markdown -> fields across segments) * refactor: move invoice.pdf to shared sample_assets directory - Move invoice.pdf from tests/cu/test_data/ to python/samples/shared/sample_assets/ as single source of truth - Add INVOICE_PDF_PATH constant in test_integration.py pointing to the shared location - Update document_qa.py, invoice_processing.py, large_doc_file_search.py to use invoice.pdf instead of sample.pdf * refactor: reorganize samples into numbered dirs and simplify auth - Move script samples into 01-get-started/ with numbered prefixes (01_document_qa, 02_multimodal_chat, 03_invoice_processing, 04_large_doc_file_search) - Move devui samples into 02-devui/ with 01-multimodal_agent and 02-file_search_agent/{azure_openai_backend,foundry_backend} - Move invoice.pdf to CU package-local samples/shared/sample_assets/ - Replace kwargs dicts with direct constructor calls; support both API key (AZURE_OPENAI_API_KEY) and AzureCliCredential - Update README sample table with new paths * fix: resolve CI lint errors (D205, RUF001, E501) - Fix D205: single-line docstring summary for _detect_and_strip_files - Fix RUF001: replace EN DASH with HYPHEN-MINUS in segment headers - Fix E501: wrap long assertion lines in tests - Also includes samples reorg and auth simplification * refactor: overhaul samples — FoundryChatClient, sessions, remove get_analyzed_document Samples: - Switch all samples from deprecated AzureOpenAIResponsesClient to FoundryChatClient - Add 02_multi_turn_session.py showing AgentSession persistence across turns - Rewrite 03_multimodal_chat.py with real PDF + audio + video (parallel analysis), per-modality follow-ups, cross-document question, elapsed time, user prompts, and input token counts - Renumber: 02->03 multimodal, 03->04 invoice, 04->05 file_search Context provider: - Remove get_analyzed_document tool -- full content is in conversation history via InMemoryHistoryProvider, no retrieval tool needed - Remove follow-up turn instructions about tools - Only list_documents tool remains (for status queries) - Update README to reflect tool removal * feat: add 05_background_analysis sample and fix 04 session/max_wait - Add 05_background_analysis.py demonstrating non-blocking CU analysis with max_wait=1s, status tracking via list_documents(), and automatic background task resolution on subsequent turns - Fix 04_invoice_processing.py: add max_wait=None and AgentSession - Rename 05→06 large_doc_file_search - Update README sample table * docs: update README and fix sample 06 README: - Switch Quick Start from AzureOpenAIResponsesClient to FoundryChatClient - Add AgentSession to Quick Start example - Fix status values: pending -> analyzing/uploading/ready/failed - Fix env var: AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME -> AZURE_OPENAI_DEPLOYMENT_NAME - Update samples section with new paths, link to samples/README.md - Update multi-segment description to reflect per-segment fields Sample 06: - Fix from_openai -> from_foundry for Azure endpoints - Add AgentSession and max_wait=None * docs: rewrite README — concise format, prerequisites, CU link * fix: resolve pyright errors in _format_result segment cast * docs: add numbered section comments and fresh sample output to all samples - Add numbered section comments (# 1. ..., # 2. ...) per SAMPLE_GUIDELINES - Re-run all 6 samples and update expected output with real results - Fix duplicate sample output blocks in 04 and 05 - Update README code example to use public invoice URL * feat: add load_settings support for env var configuration - Make endpoint optional in constructor — auto-loads from AZURE_CONTENTUNDERSTANDING_ENDPOINT env var via load_settings() - Add ContentUnderstandingSettings TypedDict - Add env_file_path/env_file_encoding params for .env file support - Add 4 unit tests: env var loading, explicit override, missing endpoint error, missing credential error - Update README with env var auto-resolution docs - Follows framework convention used by all other packages * docs: polish README — fix duplicate env var, add Next steps, service limits link * chore: trim invoice fixture from 199K to 33 lines Keep only VendorName, InvoiceTotal, DueDate, InvoiceDate, InvoiceId fields and first 500 chars of markdown. Strip spans/source/coordinates. Reduces fixture from 6.6MB to 1.2KB. * feat: per-file analyzer_id override via additional_properties - Read analyzer_id from Content.additional_properties for per-file override - Resolution order: per-file > provider-level > auto-detect by media type - Update class docstring documenting filename and analyzer_id properties - Update sample 04 to demonstrate per-file override (prebuilt-invoice) - Add unit test for per-file analyzer override * Trim PDF test fixture and clarify unique filename requirement - Trim analyze_pdf_result.json from 4427 to 23 lines by removing pages, words, lines, paragraphs, sections, spans, and source fields that are not used by any unit test. - Add docstring note that filename must be unique within a session; duplicate filenames are rejected and the file will not be analyzed. * Update python/packages/azure-ai-contentunderstanding/agent_framework_azure_ai_contentunderstanding/_context_provider.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update python/packages/azure-ai-contentunderstanding/agent_framework_azure_ai_contentunderstanding/_context_provider.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update python/packages/azure-ai-contentunderstanding/samples/02-devui/02-file_search_agent/azure_openai_backend/agent.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update python/packages/azure-ai-contentunderstanding/samples/02-devui/01-multimodal_agent/agent.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update python/packages/azure-ai-contentunderstanding/samples/01-get-started/06_large_doc_file_search.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix AGENTS.md to match implementation; remove unused variable in test helper AGENTS.md: - Remove _ensure_initialized() reference (client is created in __init__) - Fix multi-segment docs: segments kept as list, not merged into fields - Remove get_analyzed_document() reference (only list_documents registered) - Update sample names to match current directory structure test_context_provider.py: - Simplify _make_data_uri() — remove unused 'encoded' variable * Fix premature file_search instruction for background-completed docs - Change _resolve_pending_tasks() instruction from 'Use file_search' to 'being indexed' since the upload hasn't completed yet at that point. - Add LLM instruction on upload failure in step 1b so the agent can inform the user the document isn't searchable. * fix: wrap long line in devui agent instructions (E501) * Fix Copilot review: unused logger, stray code in README, await cancelled tasks - _file_search.py: Remove unused logger and logging import - 01-multimodal_agent/README.md: Remove accidentally pasted Python script - _context_provider.py close(): Await cancelled tasks before closing client to prevent 'Task destroyed but pending' warnings * Sanitize doc keys and fix duplicate filename re-injection - Add _sanitize_doc_key() to strip control characters, collapse whitespace, and cap length at 255 chars — prevents prompt injection via crafted filenames in extend_instructions() calls. - Track accepted doc_keys in step 3 so step 5 only injects content for files actually analyzed this turn, not pre-existing duplicates. - Soften duplicate upload instruction wording (remove IMPORTANT/caps). * fix: add type annotation to tasks_to_cancel for pyright * Move per-session mutable state to state dict for session isolation Previously _pending_tasks, _pending_uploads, and _uploaded_file_ids were stored on self, shared across all sessions. This caused cross-session leakage: Session A's background task results could be injected into Session B's context. Now these are stored in the per-session state dict. Global copies (_all_pending_tasks, _all_uploaded_file_ids) are kept on self only for best-effort cleanup in close(). Add 2 new TestSessionIsolation tests verifying that background tasks and resolved content stay within their originating session. * Remove unused AnalysisSection enum values Only MARKDOWN and FIELDS are handled by _extract_sections(). Remove FIELD_GROUNDING, TABLES, PARAGRAPHS, SECTIONS to avoid exposing dead options to users. * Recursively flatten object/array field values for cleaner LLM output - Use SDK .value property with recursive extraction for object/array fields - Object: AmountDue -> {Amount: 610, CurrencyCode: USD} (was raw SDK dict) - Array: LineItems -> list of flattened items (was raw SDK list) - Update invoice fixture with object/array fields from prebuilt-invoice - Add 3 unit tests for object, array, and nested object field extraction * Preserve sub-field confidence; compare full expected JSON in tests * Remove incorrect MIME aliases (audio/mp4, video/x-matroska) * feat: add AnalysisInput, content_range, warnings, and category support - Use SDK AnalysisInput model instead of raw body dict for begin_analyze - Forward content_range from additional_properties to CU (page/time ranges) - Extract CU warnings with code/message/target (ODataV4Format) into output - Include content-level category from classifier analyzers - Add 5 new tests: warnings, category, content_range forwarding - Fix pyright with explicit casts; fix en-dash lint (RUF002) * fix: falsy-0 bug in duration calc; improve test coverage - Fix start_time_ms=0 treated as falsy by 'or' short-circuit, use 'is None' checks instead for duration and segment time extraction - Update warnings test to use RAI ContentFiltered codes - Enrich warnings extraction to include code/message/target (ODataV4Format) - Add multi-segment video category test with per-segment assertions * refactor: split _context_provider.py into focused modules - Extract _constants.py: SUPPORTED_MEDIA_TYPES, MIME_ALIASES, analyzer maps - Extract _detection.py: file detection, MIME sniffing, doc key derivation - Extract _extraction.py: result extraction, field flattening, LLM formatting - _context_provider.py delegates via thin wrappers (793 lines, was 1255) - Update test imports to use _constants.py for SUPPORTED_MEDIA_TYPES * docs: update AGENTS.md with DocumentStatus, FileSearchBackend, and _file_search.py * refactor: replace AnalysisSection enum with Literal type for simpler DX - Remove AnalysisSection(str, Enum) class, replace with Literal["markdown", "fields"] type alias - Users can now pass plain strings: output_sections=["markdown"] — no extra import needed - AnalysisSection type alias still exported for type annotation use - Update all samples, tests, and internal code to use string literals - Address PR review feedback (eavanvalkenburg) * refactor: replace asyncio.Task with continuation tokens for serializable state - Replace state["_pending_tasks"] (asyncio.Task — not serializable) with state["_pending_tokens"] (dict of continuation token strings) so the framework can persist session state to disk/storage - Resume pending analyses via Azure SDK continuation_token mechanism - Fix: resumed pollers have stale cached status (done() always False), use asyncio.wait_for(poller.result()) with 10s min timeout instead - Remove _background_poll(), _all_pending_tasks, and task cancellation - Address PR review feedback (eavanvalkenburg): state must be serializable * fix: resolve CI lint (RUF052) and mypy (call-overload) errors * feat: add structured output (Pydantic model) to invoice processing sample - Use response_format=InvoiceResult for schema-constrained LLM output - Use output_sections=["fields"] only (no markdown needed for structured output) - Add LowConfidenceField model with confidence values - Add comments about prebuilt-invoice extensive schema vs simplified model - Address PR review feedback (eavanvalkenburg): use structured response * fix: use FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_MODEL env vars in all samples Replace AZURE_AI_PROJECT_ENDPOINT → FOUNDRY_PROJECT_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME → FOUNDRY_MODEL across all sample .py and README.md files. Address PR review feedback (eavanvalkenburg). * refactor: remove background_analysis sample, use FoundryChatClient in DevUI - Remove 05_background_analysis.py (per reviewer feedback — discuss max_wait design separately from samples) - Renumber 06_large_doc_file_search.py → 05_large_doc_file_search.py - Replace AzureOpenAIResponsesClient with FoundryChatClient in all DevUI samples - Replace client.as_agent() with Agent(client=client, ...) everywhere - Add max_wait comments explaining interactive vs batch usage - Update README.md and AGENTS.md - Address PR review feedback (eavanvalkenburg) * fix: vector_stores API moved from beta namespace in OpenAI SDK * docs: add comments about multi-file support and CU service limits in file_search sample * fix: broken markdown links after sample removal and renumbering * fix: migrate BaseContextProvider to ContextProvider (non-deprecated) * fix: Message(text=) -> Message(contents=[]) for API compatibility * Inline _constants.py into consuming modules Remove _constants.py and move constants to where they are used: - SUPPORTED_MEDIA_TYPES, MIME_ALIASES → _detection.py - MEDIA_TYPE_ANALYZER_MAP, DEFAULT_ANALYZER → _context_provider.py Addresses review feedback to reduce file count. * Mark package as alpha per package management skill - Version: 1.0.0b260401 → 1.0.0a260401 - Classifier: Development Status 4 - Beta → 3 - Alpha - Add to PACKAGE_STATUS.md as alpha Follows the alpha package checklist from python-package-management skill. * Replace extend_instructions with extend_messages for status notifications Status/error/result notifications now use extend_messages (conversation context) instead of extend_instructions (system prompt). This avoids system prompt bloat and keeps behavioral directives separate from event notifications. - 11 extend_instructions calls → extend_messages (role='user') - 1 extend_instructions retained: tool usage guidelines (behavioral) - 6 test assertions updated to check context_messages All 84 unit tests + 5 live integration tests pass. * Fix lint: E402 import order, ISC004 implicit string concatenation - Move constants after all imports to fix E402 - Wrap multi-line strings in parentheses inside contents=[] to fix ISC004 * Fix lint: remove unused json import in invoice sample * Fix CI: apply ruff format + fix E501 line length after reformatting ruff format expands Message() calls to multi-line, pushing string indentation deeper. Break long strings to fit within 120 char limit after formatting. Also removes unused json import in sample. * Address review feedback: keyword-only args, accept pre-built client, remove wrappers - All __init__ args now keyword-only (matches FoundryChatClient pattern) - New 'client' param accepts pre-built ContentUnderstandingClient - core dep bound: >=1.0.0rc5 → >=1.0.0,<2 - Self import moved after local imports - Removed 9 static method wrappers; callsites use module functions directly - Tests updated to import derive_doc_key and format_result directly * fix: remove duplicate ContentUnderstandingClient instantiation The client was being created twice — once inside the if/else block and again unconditionally after it. The second instantiation overwrote the pre-built client path and failed type checking when credential was None. * rename: azure-ai-contentunderstanding → azure-contentunderstanding Package: agent-framework-azure-ai-contentunderstanding → agent-framework-azure-contentunderstanding Module: agent_framework_azure_ai_contentunderstanding → agent_framework_azure_contentunderstanding Directory: packages/azure-ai-contentunderstanding → packages/azure-contentunderstanding Per agreement with PM and MAF team to drop 'AI' from the package name. * feat: add ContentUnderstanding re-export to agent_framework.foundry namespace Enables: from agent_framework.foundry import ContentUnderstandingContextProvider Exports: ContentUnderstandingContextProvider, FileSearchConfig, FileSearchBackend, AnalysisSection, DocumentStatus Updates all samples and README to use the foundry namespace import. * fix: add missing copyright headers to standalone sample scripts * chore: remove .vscode/settings.json and add to .gitignore * refactor: reuse FoundryChatClient.client for vector store ops in file_search sample Address review feedback from TaoChenOSU: - 05_large_doc_file_search.py: use client.client instead of manually constructing AsyncAzureOpenAI; remove openai dependency - azure_openai_backend/agent.py: import reorder only (AIProjectClient kept — required for sync vector store creation in DevUI) * fix: skip closing client when caller passes pre-built client When a ContentUnderstandingClient is passed via client=, the caller owns its lifecycle. Added _owns_client flag so close() only closes the client when we created it internally. --------- Co-authored-by: yungshinlin <yungshin@msn.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>Yung-Shin Lin ·
2026-04-28 20:55:59 +00:00 -
Python: bump package versions for 1.2.1 release (#5536)
* Python: bump package versions for 1.2.1 release PATCH bump (1.2.0 -> 1.2.1) for the released cohort. The release window covers two PRs, no new public APIs: - agent-framework-core: prevent inner_exception from being lost in AgentFrameworkException (#5167) - samples: add requirements.txt and .env.example to the a2a/ hosting sample for pip-based setup (#5510) Per lockstep convention, all 21 beta packages stamp 1.0.0b260428 and all 3 alpha packages stamp 1.0.0a260428, regardless of per-package code churn. Every non-core package floor on agent-framework-core is raised to >=1.2.1 to keep cohort signaling consistent. Date stamp reflects the local (Asia) cut date 2026-04-28. * Python: silence pyright unknown-type warnings in hosted-env detection `azure.ai.agentserver.core` is probed at runtime via `importlib.util.find_spec` and is not a declared dependency. The existing `# pyright: ignore[reportMissingImports]` suppresses the missing-import warning, but at `lowest-direct` resolution pyright still reports the imported symbol (`AgentConfig`) and its members (`from_env`, `is_hosted`) as unknown, breaking `validate-dependency-bounds-test` for `packages/core`. Extend the existing ignore to cover `reportUnknownVariableType` on the import and `reportUnknownMemberType` on the call site so the bounds check returns to green. Behavior is unchanged. Latent since #5455 (shipped in 1.2.0). * Python: raise agent-framework-gemini lower bound to google-genai>=1.65.0 The Gemini chat client references several `google.genai.types` symbols (`FileSearch`, `ThinkingLevel`, `SearchTypes`, `McpServer`, `StreamableHttpTransport`, plus call-site keyword args `mcp_servers` and `search_types`) that are not present at the lower bound of `google-genai>=1.0.0`. At `lowest-direct` resolution this caused `validate-dependency-bounds-test` to fail for `packages/gemini` with eleven `reportAttributeAccessIssue` / `reportUnknownVariableType` errors. Walking the upstream `google.genai.types` API: - `GoogleMaps`, `AuthConfig`: present from 1.40.0 - `FileSearch`: introduced in 1.49.0 - `ThinkingLevel`: introduced in 1.55.0 - `SearchTypes`, `McpServer`, `StreamableHttpTransport`: introduced in 1.65.0 Bump the lower bound to 1.65.0 — the minimum version that exposes every symbol the package actually uses. Keep the `<2.0.0` upper cap unchanged. With this bump `validate-dependency-bounds-test` passes for both lower and upper resolution scenarios across all 27 workspace packages. Latent since #4847 (Gemini package introduction in 1.1.0); aggravated by subsequent feature additions that pulled in newer `types.*` symbols. * Python: add dependabot bumps to 1.2.1 CHANGELOG Catalog the 15 dependabot dependency updates that merged on `upstream/main` between python-1.2.0 and the 1.2.1 cut window under a new Changed section: - Workspace dev/runtime deps: `rich`, `prek`, `python-multipart`, `pyasn1`, `pytest` (ag-ui, devui, lab), `uv` (lab) - Frontend deps: `vite` (devui, chatkit), `postcss` (devui, chatkit, handoff), `picomatch` (devui, handoff) CHANGELOG-only — no source or pyproject.toml changes. PRs themselves merged upstream independently of this release branch and will be brought in via the PR merge.
Evan Mattson ·
2026-04-28 18:23:26 +09:00 -
Python: Bump prek from 0.3.8 to 0.3.9 in /python (#5228)
* Bump prek from 0.3.8 to 0.3.9 in /python Bumps [prek](https://github.com/j178/prek) from 0.3.8 to 0.3.9. - [Release notes](https://github.com/j178/prek/releases) - [Changelog](https://github.com/j178/prek/blob/master/CHANGELOG.md) - [Commits](https://github.com/j178/prek/compare/v0.3.8...v0.3.9) --- updated-dependencies: - dependency-name: prek dependency-version: 0.3.9 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Fix CI: bump prek to 0.3.9 in lab package and update uv.lock Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/f17751e5-c5a8-4d42-9555-6bf708a2ef47 Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com>
dependabot[bot] ·
2026-04-28 09:08:58 +00:00 -
Update rich requirement in /python (#5227)
Updates the requirements on [rich](https://github.com/Textualize/rich) to permit the latest version. - [Release notes](https://github.com/Textualize/rich/releases) - [Changelog](https://github.com/Textualize/rich/blob/master/CHANGELOG.md) - [Commits](https://github.com/Textualize/rich/compare/v13.7.1...v15.0.0) --- updated-dependencies: - dependency-name: rich dependency-version: 15.0.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
dependabot[bot] ·
2026-04-28 07:26:03 +00:00 -
Python: Bump uv from 0.11.3 to 0.11.6 in /python/packages/lab (#5469)
* Bump uv from 0.11.3 to 0.11.6 in /python/packages/lab Bumps [uv](https://github.com/astral-sh/uv) from 0.11.3 to 0.11.6. - [Release notes](https://github.com/astral-sh/uv/releases) - [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/uv/compare/0.11.3...0.11.6) --- updated-dependencies: - dependency-name: uv dependency-version: 0.11.6 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> * Fix CI: update uv from 0.11.3 to 0.11.6 in python/pyproject.toml and regenerate uv.lock Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/a1a7c648-b26f-44e7-bace-d56ed8489053 Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com> * Fix code quality CI: update uv-pre-commit rev from 0.11.3 to 0.11.6 in .pre-commit-config.yaml Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/cdfdd211-9f1e-4570-bc7c-86fd15240e91 Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com>
dependabot[bot] ·
2026-04-28 07:24:43 +00:00 -
Python: Bump pytest from 9.0.2 to 9.0.3 in /python/packages/lab (#5470)
* Bump pytest from 9.0.2 to 9.0.3 in /python/packages/lab Bumps [pytest](https://github.com/pytest-dev/pytest) from 9.0.2 to 9.0.3. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/9.0.2...9.0.3) --- updated-dependencies: - dependency-name: pytest dependency-version: 9.0.3 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> * Update pytest from 9.0.2 to 9.0.3 across all workspace packages Fix dependency conflict: agent-framework workspace packages were pinning pytest==9.0.2 while agent-framework-lab required pytest==9.0.3, causing uv dependency resolution to fail. Updated all pyproject.toml files and regenerated uv.lock to use pytest==9.0.3 consistently. Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/d274f7c5-b5ed-4b18-8eab-4db3cfd9d1bf Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com>
dependabot[bot] ·
2026-04-28 07:24:23 +00:00 -
Python: Bump Python package versions for 1.2.0 release (#5468)
* Bump Python package versions for 1.2.0 release Released tier bumps 1.1.1 -> 1.2.0 (core, openai, foundry, root) to reflect additive public APIs landed since 1.1.0: functional workflow API (#4238) and FunctionTool SKIP_PARSING sentinel (#5424). All beta packages stamped 1.0.0b260424, alpha packages 1.0.0a260424. All 26 non-core agent-framework-core floors raised to >=1.2.0,<2. CHANGELOG consolidates the never-tagged 1.1.1 entries with the post-merge additions into [1.2.0]. * Update CHANGELOG footer links for 1.2.0 Advance [Unreleased] comparison base from python-1.1.0 to python-1.2.0 and add a [1.2.0] reference link comparing python-1.1.0...python-1.2.0 so the heading links resolve correctly. * Fix CHANGELOG: restore [1.1.1] section and add proper [1.2.0] Previous commit incorrectly renamed the [1.1.1] header to [1.2.0], which wiped the historical 1.1.1 entries and wrongly attributed them to 1.2.0. This restores [1.1.1] to its origin/main content and adds a new [1.2.0] section above containing only the commits in python-1.1.1..HEAD: - #4238 functional workflow API - #5142 GitHub Copilot OpenTelemetry - #2403 A2A bridge support - #5070 oauth_consent_request events in Foundry clients - #5447 FoundryAgent hosted agent sessions - #5459 hosting server dependency upgrade + types - #5389 AG-UI reasoning/multimodal parsing fix - #5440 stop [TOOLBOXES] warning spam - #5455 user agent prefix fix Also corrects the [1.2.0] compare base to python-1.1.1 (not 1.1.0) and adds the missing [1.1.1] reference link.
Evan Mattson ·
2026-04-24 19:54:59 +09:00 -
Python: Bump Python package versions for a release. (#5432)
* Bump Python version for a release. * Revert lockstep bumps on unchanged connectors Per PR review: only connectors that changed (or whose published metadata changed) should get new versions. Keeps released tier at 1.1.1, a2a/ag-ui at 1.0.0b260422, foundry-hosting at 1.0.0a260422; reverts the 19 unchanged betas and 2 unchanged alphas to 1.0.0b260421/1.0.0a260421. Reverts all 26 non-core agent-framework-core floors to >=1.1.0,<2 since no connector actually depends on a 1.1.1 API or bug fix. * Restore lockstep prerelease bumps and raise core floors to >=1.1.1 Reverses the lean-revert: all beta packages stamped 1.0.0b260423 and alpha packages stamped 1.0.0a260423 (Asia date, matching release cut time). All 26 non-core packages raise agent-framework-core lower bound from >=1.1.0,<2 to >=1.1.1,<2 to signal the validated cohort for this release. CHANGELOG date updated to 2026-04-23.
Evan Mattson ·
2026-04-23 16:40:14 +09:00 -
Python: Bump versions for a release. Update CHANGELOG (#5385)
* Bump versions for a release. Update CHANGELOG * Bump devui
Evan Mattson ·
2026-04-21 15:14:42 +09:00 -
Python: Foundry hosted agent V2 (#5379)
* Python: Wrapper + Samples 1st (#5177) * Experiment * Update dependency and add non streaming * Add more samples * Rename samples * Add invocations * Comments 1 * Comments 2 * Comments 3 * Improve README * Add local shell sample * WIP: Add eval and memory samples * Update user agent prefix * Update user agent prefix doc * Update dependency (#5215) * Add tests and more content types (#5235) * Add tests * fix tests and sample * Fix formatting * Remove function approval contents * Python: Refine samples and upgrade packages (#5261) * Refine samples and upgrade pacakges * Upgrade to a new package that fixes a bug * Update model env var * Move samples (#5281) * Python: Upgrade agentserver packages (#5284) * Upgrade agentserver packages * Fix new types * Python: Add special handling for workflows (#5298) * Add special handling for workflows * Address comments * Improve samples (#5372) * Python: Add more types (#5378) * Add more type supports * Upgrade packages * Remove TODOs in README * Fix README * Comments and mypy * User agent scoped * Fix README * Fix pre commit * Fix pre commit 2 * Fix pre commit 3 * Fix pre commit 4 * Fix pre commit 5 * Fix pre commit 6 * Add azure-monitor-opentelemetry to dev deps Fixes Samples & Markdown CI failure. The PR's new transitive dep on azure-monitor-opentelemetry-exporter (via azure-ai-agentserver-core) makes pyright resolve the azure.monitor.opentelemetry namespace, flipping the check_md_code_blocks diagnostic for `configure_azure_monitor` from reportMissingImports (filtered) to reportAttributeAccessIssue (not filtered). Installing the umbrella azure-monitor-opentelemetry package in dev makes pyright resolve the symbol correctly, matching the install guidance the observability README already gives users. --------- Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
Tao Chen ·
2026-04-21 05:21:27 +00:00 -
Python: Add Hyperlight CodeAct package and docs (#5185)
* initial work on code_mode * updated samples * updates to codeact * udpated codeact * Draft CodeAct ADR and sample updates Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * initial implementation and adr and feature * Python: Limit Hyperlight wasm backend to Python <3.14 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Fix CI for Hyperlight CodeAct PR Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Run Hyperlight integration when available Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Address Hyperlight review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Simplify Hyperlight file mount inputs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Accept Path host paths in Hyperlight mounts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: Fix Hyperlight mount typing for CI Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * temp run integration test * Python: Strengthen Hyperlight real sandbox tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * added additional tests * Python: Simplify Hyperlight CodeAct API Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * set tests as non-integration * Retry Hyperlight allowed-domain registration Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Gate Hyperlight integration tests by runtime support Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix Hyperlight skip test on Python 3.14 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Delay Hyperlight runtime probe until test execution Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Relax Hyperlight Windows integration stdout assertion Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Scan Hyperlight output directory for artifacts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Retry Hyperlight output artifact collection Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Harden Hyperlight integration output assertions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Retry Hyperlight read-back check in integration test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify Hyperlight integration write assertion Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Avoid pathlib in Hyperlight integration sandbox Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use socket network check in Hyperlight sandbox Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Replace blocked Azure AI Search blog link Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clarify Hyperlight guest stdlib limits Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use _socket in Hyperlight integration sandbox Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Handle Hyperlight mounted file paths Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Broaden Hyperlight sandbox path fallbacks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Search Hyperlight guest mounts recursively Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Split Hyperlight mount coverage Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Split Hyperlight live network tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix Hyperlight file-write test on Windows Enable the sandbox filesystem by providing a workspace_root so /output is mounted. Remove os.path.exists assertion (unsupported in WASM guest) and fix Content data assertion to use .uri. Skip the network integration test on Windows where the WASM sandbox lacks the encodings.idna codec. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review: ADR intro, manual wiring sample, doc clarifications - Add CodeAct introduction section to ADR for unfamiliar readers - Clarify 'less runtime efficient' con with specific overhead description - Add note in Python impl doc clarifying ADR vs impl doc split - Explain why before_run hooks must be per-run (CRUD, concurrency, approval) - Rename code_interpreter variable to codeact in E2E sample - Add manual static wiring sample (codeact_manual_wiring.py) - Add 'when to use which pattern' guidance to samples README Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR #5185 review comments and add .NET CodeAct design doc - Fix async callback: _make_sandbox_callback returns sync wrapper with thread + asyncio.run() bridge (was broken with real Wasm FFI) - Fix stale output: clear output_dir before each sandbox.run() call - Fix blocking event loop: _run_code now async with asyncio.to_thread() - Revert _agents.py options['tools'] injection (unnecessary; provider uses context.extend_tools()) - Revert SessionContext.options docstring back to read-only - Add real-sandbox test fixtures (shared/restored/fresh) - Add 8 new real-sandbox tests for callback round-trip, stale output, event loop non-blocking, basic execution, stdout/stderr, errors, snapshot/restore, and tool registration - Add comprehensive .NET HyperlightCodeActProvider design document Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update hyperlight README with code snippets and remove Public API section Replace bare export list with Quick Start code examples covering the context provider, standalone tool, manual static wiring, and file mounts / network access patterns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-04-17 00:49:44 +00:00 -
Python: Add GeminiChatClient (#4847)
* Add agent-framework-gemini package * Add AGENTS.md documentation * Add LICENSE file * Add README.md for agent-framework-gemini package * Add Google Gemini API keys to .env.example * Add Google Gemini chat client implementation * Add tests for GeminiChatClient * Add Google Gemini agent examples * Fix client inheritence order * Update Gemini agent examples * Update documentation * Update AGENTS.md * Add tests for JSON string handling in GeminiChatClient * Add final response assembly test in GeminiChatClient * Add tests for handling empty candidates in GeminiChatClient * Improve Pydantic response handling in GeminiChatClient * Add tests for function result resolution and callable tool normalization * Add test for function result resolution when call_id is generated * Refactor GeminiChatClient to correct inheritance order Also updates constructor parameter order for environment file handling * Enhance documentation and clarify Gemini-specific fields * Update ThinkingConfig with new attributes and type * Add tests for GoogleSearch and GoogleMaps configs * Suppress valid-type mypy error on GeminiChatOptionsT * Move service_url method near overrides * Order _prepare_config kwargs by base then Gemini-specific * Use FunctionCallingConfigMode for clarity and type safety * Fix code_execution doc * Add agent-framework-gemini to project dependencies * Remove package from core dependencies Initial release will be done without agent-framework-gemini in core[all]. * Move integration tests into one file * Remove __init__.py file from gemini tests directory * Introduce RawGeminiChatClient as lightweight chat client Updated GeminiChatClient to inherit from RawGeminiChatClient, maintaining full functionality with added features. * Updated variable names from `model_id` to `model` Across the codebase, including environment variables and client initialization. Adjusted related tests and sample scripts to reflect this change, ensuring consistency in the usage of the Gemini model identifier. * Update AGENTS.md * Update Gemini package to alpha status * Fix docstrings in Gemini tests * Change 'model_id' to 'model' in response handling * Fix model property change in response handling * Add built-in tool factory methods to Gemini client Replaces boolean tool options (code_execution, google_search_grounding, google_maps_grounding) with static factory methods that return types.Tool objects: get_code_interpreter_tool, get_web_search_tool, get_mcp_tool, get_file_search_tool, and get_maps_grounding_tool. Simplifies _prepare_tools to a single translation boundary between FunctionTool (framework) and FunctionDeclaration (Gemini API), with types.Tool objects passed through unchanged. * Surface code execution parts _parse_parts now maps executable_code and code_execution_result parts to text Content objects so callers can see the code run and its output. Unknown part types log at debug level rather than being silently dropped. * Update Gemini client documentation * Unify Gemini model name Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> * Update Agent Framework core version Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> * Add Python 3.14 in classifiers * Replace kwargs with parameters in tool factories * Refactor chat options handling in Gemini client * Add tests for handling unknown and consumed keys * Update Gemini documentation Now reflects new options and built-in tool factory methods * Change build system to flit Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> * Fix build system in pyproject.toml * Fix type checking for generate_content_stream --------- Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
Björn Holtvogt ·
2026-04-14 10:18:26 +00:00 -
Python: Bump Python version to 1.0.1 for a release (#5196)
* Bump Python version to 1.1.0 for a release * Fix changelog * 1.0.1 instead of 1.1.0 * Update CHANGELOG.md * update version and changelog * Bump lower bounds
Evan Mattson ·
2026-04-10 12:23:21 +09:00 -
Bump mcp[ws] from 1.26.0 to 1.27.0 in /python (#5119)
Bumps [mcp[ws]](https://github.com/modelcontextprotocol/python-sdk) from 1.26.0 to 1.27.0. - [Release notes](https://github.com/modelcontextprotocol/python-sdk/releases) - [Changelog](https://github.com/modelcontextprotocol/python-sdk/blob/main/RELEASE.md) - [Commits](https://github.com/modelcontextprotocol/python-sdk/compare/v1.26.0...v1.27.0) --- updated-dependencies: - dependency-name: mcp[ws] dependency-version: 1.27.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
dependabot[bot] ·
2026-04-10 00:13:40 +00:00 -
Python: [BREAKING] update to v1.0.0 (#5062)
* updates to final deprecated pieces and versions * fix mypy * fix readme links
Eduard van Valkenburg ·
2026-04-02 15:26:30 +00:00 -
Python: [BREAKING] Python: move Azure AI embeddings to Foundry (#5056)
* renamed AzureAIINferenceEmbeddings and lazy load azure-cosmos and env var rename * updated coverage * fix readme
Eduard van Valkenburg ·
2026-04-02 11:26:35 +00:00 -
Python: Update Python Packages for rc6 (#4979)
* python package update * small fix
Giles Odigwe ·
2026-03-30 21:12:37 +00:00 -
Python: [BREAKING] Reduce core dependencies and simplify optional integrations (#4904)
* improved dependencies and some fixes * fix for mypy * improve mcp
Eduard van Valkenburg ·
2026-03-25 18:03:43 +00:00 -
Python: [BREAKING] Python: Provider-leading client design & OpenAI package extraction (#4818)
* Python: Provider-leading client design & OpenAI package extraction Major refactoring of the Python Agent Framework client architecture: - Extract OpenAI clients into new `agent-framework-openai` package - Core package no longer depends on openai, azure-identity, azure-ai-projects - Rename clients for discoverability: OpenAIResponsesClient → OpenAIChatClient, OpenAIChatClient → OpenAIChatCompletionClient - Unify `model_id`/`deployment_name`/`model_deployment_name` → `model` param - New FoundryChatClient for Azure AI Foundry Responses API - New FoundryAgent/FoundryAgentClient for connecting to pre-configured Foundry agents - Remove OpenAIBase/OpenAIConfigMixin from non-deprecated client MRO - Deprecate AzureOpenAI* clients, AzureAIClient, OpenAIAssistantsClient - Reorganize samples: azure_openai+azure_ai+azure_ai_agent → azure/ - ADR-0020: Provider-Leading Client Design Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: missing Agent imports in samples, .model_id → .model in foundry_local sample Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: CI failures — mypy errors, coverage targets, sample imports - azure-ai mypy: add type ignores for TypedDict total=, model arg, forward ref - Coverage: replace core.azure/openai targets with openai package target - project_provider: add type annotation for opts dict Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: populate openai .pyi stub, fix broken README links, coverage targets Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fixes * updated observabilitty * reset azure init.pyi * fix errors * updated adr number * fix foundry local * fixed not renamed docstrings and comments, and added deprecated markers to old classes * fix tests and pyprojects * fix test vars * updated function tests * update durable * updated test setup for functions * Fix Foundry auth in workflow samples Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Stabilize Python integration workflows Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update hosting samples for Foundry Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Trigger full CI rerun Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Trigger CI rerun again Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * trigger rerun * trigger rerun * fix for litellm * undo durabletask changes * Move Foundry APIs into foundry namespace Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix Foundry pyproject formatting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Split provider samples by Foundry surface Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Restore hosting sample requirements Also fix the Foundry Local sample link after the provider sample move. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * updated tests * udpated foundry integration tests * removed dist from azurefunctions tests * Use separate Foundry clients for concurrent agents Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix client setup in azfunc and durable * disabled two tests * updated setup for some function and durable tests * improved azure openai setup with new clients * ignore deprecated * fixes * skip 11 * remove openai assistants int tests --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-03-25 09:56:29 +00:00 -
Python: Bump Python version to 1.0.0rc5 and 1.0.0b260319 for a release. (#4807)
* Bump Python version to 1.0.0rc5 and 1.0.0b260319 for a release. * update missed pkg versions * Update changelog
Evan Mattson ·
2026-03-20 10:35:47 +09:00 -
Python: Simplify Python Poe tasks and unify package selectors (#4722)
* updated automation tasks and commands, with alias for the time being * Restore aggregate test exclusions Preserve the legacy all-tests scope for test --all by excluding lab and devui from the default aggregate sweep, while still allowing explicit package selection. Also ignore hidden/generated test directories such as .mypy_cache during aggregate discovery. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * updated versions in pre-commit --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-03-18 18:39:11 +00:00 -
Python: fix thread serialization for multi-turn tool calls (#4684)
* Python: strip fc_id from loaded history * Move fc_id replay handling into Responses client Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove unnecessary pytest asyncio marker Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add Responses integration test for fc_id replay Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * removed old arg --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-03-17 10:00:04 +00:00 -
Python: chore(python): improve dependency range automation (#4343)
* chore(python): improve dependency range automation - tighten dependency bounds and coding standards guidance\n- add dependency range validation workflow, reporting, and issue automation\n- update related tests and dependency pins for compatibility Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * updated text and pyarrow * new lock * fixed workflow * updated deps * fix tiktoken * chore(python): refine dependency validation workflows Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(python): add high-level dependency validation comments Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * WIP * added additional comments and excludes * added dev dependency handling and workflow and updates to package ranges * added readme and simplified commands * fix markers * chore(python): address dependency review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tighten dependency bounds, remove stale overrides, restore Python 3.10 support - Apply dependency bound policy across all packages: stable >=1.0 deps use >=floor,<next_major; pre-1.0/prerelease deps use validated hard-bounded ranges - Remove stale root tool.uv.override-dependencies (uvicorn, websockets, grpcio) - Lower github_copilot requires-python to >=3.10 with github-copilot-sdk gated behind python_version >= 3.11 marker; import raises ImportError on 3.10 - Skip github_copilot pyright/mypy/test tasks on Python <3.11 - Use version-conditional pyrightconfig for samples on Python 3.10 - Add compatibility fix in core responses client for older openai typed dicts - Normalize uv.lock prerelease mode and refresh dev dependencies - Update CODING_STANDARD.md, DEV_SETUP.md, and package management skill docs Closes #902 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * small tweaks * add note in workflow * fix workflows and several versions * fix duplicate --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-03-13 12:32:37 +00:00 -
Python: Implement annotation-based context compaction (#4469)
* Implement annotation-based context compaction Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Handle missing compaction attributes in BaseChatClient Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix CI typing and bandit issues Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Optimize incremental compaction annotation pass Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refinement * Python: add ToolResultCompactionStrategy and CompactionProvider Add ToolResultCompactionStrategy that collapses older tool-call groups into short summary messages (e.g. [Tool calls: get_weather]) while keeping the most recent groups verbatim. This mirrors the .NET ToolResultCompactionStrategy from PR #4533. Add CompactionProvider as a context-provider that auto-applies compaction before each agent turn and stores compacted history in session state after each turn. Includes tests and samples for both features. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refinement and alignment with dotnet PR * updated tool result compaction * updated tool result compaction * Python: add ToolResultCompactionStrategy, CompactionProvider, and skip_excluded - ToolResultCompactionStrategy collapses older tool-call groups into [Tool results: func_name: result] summaries with bidirectional tracing (same pattern as SummarizationStrategy). - CompactionProvider as BaseContextProvider with separate before_strategy and after_strategy parameters. before_strategy compacts loaded context; after_strategy compacts stored history via history_source_id. - InMemoryHistoryProvider gains skip_excluded flag to filter out messages marked as excluded by compaction strategies. - Tests, samples, and exports updated. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fixed checks * fix mypy * Fix: ensure summary messages from both strategies get full compaction annotations SummarizationStrategy was not calling annotate_message_groups after inserting its summary message, so the summary lacked core group annotations (id, kind, index, has_reasoning, _excluded). Added the missing call. ToolResultCompactionStrategy already had it. Added tests verifying both strategies produce fully annotated summaries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * updated propagation * fix mypy --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-03-11 19:23:00 +00:00 -
Dmytro Struk ·
2026-03-11 18:53:38 +00:00 -
Python: Fix Python pyright package scoping and typing remediation (#4426)
* Fix Python pyright package scoping and typing remediation Implements issue #4407 by removing the root pyright include, adding package-level pyright includes, and resolving pyright/mypy typing issues across Python packages. Also cleans unnecessary casts and applies line-level, rule-specific ignores where external libraries are too dynamic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Reduce pyright cost in handoff cloning Simplify cloned_options construction in HandoffAgentExecutor to avoid expensive TypedDict narrowing/inference in _handoff.py, which was causing pyright to spend a long time in orchestrations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix types * Fix lint and type-check regressions Resolve current Python package check failures across lint, pyright, and mypy after recent code changes, including purview/declarative pyright issues and multiple ruff simplification findings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fixed hooks * Stabilize package tests and test tasks Resolve cross-package non-integration test failures, simplify streaming type flow, harden locale/culture handling, and standardize package test poe tasks to exclude integration tests where applicable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * lots of small fixes * Fix current Python test regressions Address current failing unit tests in azure-ai, bedrock, and azure-cosmos while keeping Bedrock parsing logic inline (no new static helper methods). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * small fixes * small fixes * removed pydantic from json * final updates * fix core * fix tests * fix obser --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-03-05 15:32:24 +00:00 -
Dmytro Struk ·
2026-03-04 16:49:48 +00:00 -
Python: Fix workflow tests pyright warnings (#4362)
* Fix workflow tests pyright warnings * Update uv.lock * Fix pyright * Comments * Update root pyproject pyright setting * Update core pyproject pyright setting * Update core pyproject pyright setting
Tao Chen ·
2026-03-03 21:52:05 +00:00 -
Python: Add Azure Cosmos history provider package (#4271)
* Created cosmos history provider * add marker * Python: address Cosmos PR feedback - address provider/test/sample review feedback and cleanup typing - add cosmos integration test coverage and skip gating - add dedicated cosmos emulator jobs to python merge/integration workflows - switch cosmos workflow execution to package poe integration-tests task Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: handle empty Cosmos session id - replace default partition fallback for empty session_id - log warning and generate GUID when session_id is empty - update unit tests to validate GUID fallback behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix sample * fix cross partition query --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-03-03 12:29:32 +00:00 -
Python: Tuning auto sample validation workflow (#4218)
* Tuning validate-01-get-started * Add gh token * Add model * enable debug log * bump up timeout for testing purposes * Test cli is working * Fix end quote * Run gh auth * Run gh auth trail 2 * Run gh auth trail 3 * Test token * Add zcure login * Add zcure login 2 * Add zcure login 3 * Add zcure login 4 * Extract common actions * Extract common actions 2 * Correct env vars * Print outputs to action console * Disable end-to-end samples * Fix ruff errors * Fix ruff errors 2 * Revert workflow changes to fix tests * Revert workflow changes to fix tests 2 * Revert workflow changes to fix tests 3 * Revert workflow changes to fix tests 4
Tao Chen ·
2026-02-27 11:45:10 +09:00 -
Update Python package versions to rc2 (#4258)
- Bump core and azure-ai to 1.0.0rc2 - Bump preview packages to 1.0.0b260225 - Update dependencies to >=1.0.0rc2 - Add CHANGELOG entries for changes since rc1 - Update uv.lock Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Dmytro Struk ·
2026-02-25 19:37:44 +00:00 -
Python: updated integration tests and guidance (#4181)
* updated integration tests and guidance * fixed merge test * updated integration tests * fix: remove duplicate --dist loadfile flag from pytest-xdist config Only one --dist mode can be active at a time; the second value silently overrides the first. Keep --dist worksteal (dynamic load balancing) and remove the redundant --dist loadfile from all workflow files and pyproject.toml configs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: add keep-in-sync notes for merge and integration test workflows Both python-merge-tests.yml and python-integration-tests.yml share the same parallel job structure. Added sync reminders in workflow file comments, the python-testing SKILL.md, and CODING_STANDARD.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: remove RUN_INTEGRATION_TESTS flag Integration test gating now uses two mechanisms: - `@pytest.mark.integration` for test selection via `-m` filtering - `skip_if_*_disabled` for credential/service availability checks The RUN_INTEGRATION_TESTS env var was redundant since the marker handles selection and the skip decorators already check for actual credentials. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: sync missing env vars from merge-tests to integration-tests Add OPENAI_EMBEDDINGS_MODEL_ID and AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME to python-integration-tests.yml to match python-merge-tests.yml. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: remove remaining RUN_INTEGRATION_TESTS from embedding tests and docs Missed test_openai_embedding_client.py and vector-stores README in the earlier cleanup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * set functions tests to 3.10 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Eduard van Valkenburg ·
2026-02-24 09:35:46 +00:00 -
Python: Updated package versions for RC release (#4068)
* Updated package versions for RC release * Update python/packages/redis/pyproject.toml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Small fix --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Dmytro Struk ·
2026-02-19 16:11:48 +00:00