Commit Graph

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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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.
  • 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>
  • 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>
  • 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.
  • 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.
  • [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>
  • 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.
  • 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>
  • 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>
  • 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>
  • 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>
  • 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.
  • 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.
  • Python: Bump versions for a release. Update CHANGELOG (#5385)
    * Bump versions for a release. Update CHANGELOG
    
    * Bump devui
  • 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>
  • 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>
  • 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>
  • 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
  • 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>
  • Python: [BREAKING] update to v1.0.0 (#5062)
    * updates to final deprecated pieces and versions
    
    * fix mypy
    
    * fix readme links
  • 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
  • Python: Update Python Packages for rc6 (#4979)
    * python package update
    
    * small fix
  • Python: [BREAKING] Reduce core dependencies and simplify optional integrations (#4904)
    * improved dependencies and some fixes
    
    * fix for mypy
    
    * improve mcp
  • 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>
  • 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
  • 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>
  • 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>
  • 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>
  • 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>
  • 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>
  • 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
  • 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>
  • 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
  • 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>
  • 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>
  • 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>