main
1189 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7a2b8038cc |
[BREAKING] Python: Bump package versions for 1.15.0 release (#7812)
* Bump Python package versions for 1.15.0 release Prepare the CHANGELOG-selected Python packages for the 1.15.0 release. Root and core move to 1.15.0; changed stable extensions receive package-specific minor or patch bumps; changed beta packages receive the 260821 stamp; no beta cohort bump is applied. Core dependency floors use the conservative policy for co-released packages. Release validation also adds the six dependency required by the supported Azure Cosmos SDK floor and retains cross-platform-compatible development-tool pins. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 98e979bd-1d07-41fd-946d-00db8a93e248 * Remove hook-only formatting changes Keep the Python 1.15.0 release commit scoped to package metadata, release notes, dependency floors, and the lockfile. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 98e979bd-1d07-41fd-946d-00db8a93e248 * Minimize release lockfile changes Restore the upstream PyPI-backed lockfile and retain only package versions and dependency metadata changed by the Python 1.15.0 release. Also preserve the development-tool upgrades already present on main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 98e979bd-1d07-41fd-946d-00db8a93e248 * Retain OpenAI core compatibility floor Keep agent-framework-openai 1.13.1 compatible with core 1.13 because its streaming tool-call index fix uses the existing additional_properties API and does not require core 1.15. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 98e979bd-1d07-41fd-946d-00db8a93e248 * Raise OpenAI version and core floor Bump agent-framework-openai to 1.14.0 and require core 1.15.0 so the new dependency requirement is signaled as a minor release. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 98e979bd-1d07-41fd-946d-00db8a93e248 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 98e979bd-1d07-41fd-946d-00db8a93e248 |
||
|
|
c6a0e90250 |
Python: correct MCP tool argument filtering documentation (#7801)
* Python: correct MCP tool argument filtering documentation The documentation for MCPTool's outbound argument filtering did not match its behavior. The comment on _prepare_call_kwargs stated that framework runtime kwargs are "stripped so it is never forwarded to the MCP server", and packages/core/AGENTS.md repeated the same claim. In practice, runtime kwargs (FunctionInvocationContext.kwargs, seeded from function_invocation_kwargs) are merged with the model-supplied arguments in _call_tool_with_runtime_kwargs before the filter runs, so provenance is no longer distinguishable at that point. The allowlist is built from the tool's declared inputSchema.properties as advertised by the server, plus names opted in through additional_tool_argument_names. A runtime kwarg is therefore forwarded whenever the server declares a property of the same name, without the model supplying it. Update the comments, docstrings and docs to describe the actual rule, and point each transport at its appropriate channel for values that should not become tool arguments (env for stdio, header_provider for streamable HTTP). Also narrow the docstring of test_call_tool_forwards_only_declared_arguments, which claimed more than it asserts (it covers undeclared names only), and add a companion test pinning the declared-name behavior so the documented rule stays verifiable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: address review feedback on MCP argument filtering docs Corrects and tightens the documentation added in the previous commit. - header_provider does not withhold values from the outbound argument filter; it reads the runtime kwargs without consuming them. The earlier wording recommended it as a way to keep a value out of tool arguments, which is wrong. Replaced in four places with the pattern that does work: source the credential outside function_invocation_kwargs, for example by reading a ContextVar inside the provider, which still allows a different value per request. - Note the _meta key and the framework denylist as exceptions wherever the docs say server-declared names are forwarded. - Rework test_call_tool_forwards_runtime_kwargs_the_server_declares to invoke the generated FunctionTool with a FunctionInvocationContext, so it exercises the real runtime-kwargs path instead of calling call_tool directly. Verified by mutation: removing the merge in _call_tool_with_runtime_kwargs now fails the test. - Add a test covering the recommended ContextVar pattern. - Condense the transport docstring notes, which had grown into three near-duplicate blocks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
7b7b9a128c |
Python: Foundry Hosted Agent Resiliency Support (#7670)
* Migrate FHA to responses==2.0.0b1 and add Foundry state store * Fix session id error * Fix tests * Improve tests * Fix copilot comments * Address comments * Revert sample changes * Address comments * Add ContextScopedStoreProvider * Fix type check * Fix type check * LRA on top of state store * Temp disable state store user isolation * Simulate shutdown * Remove sim shutdown * Add sample * refine resiliency sample * Add steerable conversation support * Revert uv.lock * Add last_checkpoint_id and checkpoint existence check * Tighted resilient-recovery states * Tests for tightened resilient-recovery states * Make cancellation effective even when the iterator is stuck * Add more tests and fix sample * Small adjustment after review * Fix typing * Fix typing * Close driver background task in case of exceptions raised in the consumer * Handle usage content * xfail an integration test due to a known gap * Fix formatting --------- Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> |
||
|
|
6a58888f3a |
Python: Bump uv from 0.11.32 to 0.12.5 in /python (#7780)
* Bump uv from 0.11.32 to 0.12.5 in /python Bumps [uv](https://github.com/astral-sh/uv) from 0.11.32 to 0.12.5. - [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.32...0.12.5) --- updated-dependencies: - dependency-name: uv dependency-version: 0.12.5 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Align lab uv pin to 0.12.5 and update uv.lock 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> |
||
|
|
59ecceba03 |
Python: A2UI (Agent-to-UI) support for the AG-UI adapter (#7423)
* Python: A2UI (Agent-to-UI) support for the AG-UI adapter Adds an in-package _a2ui module to agent-framework-ag-ui delivering progressive-streaming, error-recovery, and sub-agent-based A2UI surface generation, reusing the shared ag-ui-a2ui-toolkit. Includes example agents, a unit suite, and two bridge fixes (strip unanswered tool calls from replayed history; suppress the terminal MESSAGES_SNAPSHOT for A2UI runs to keep streamed order stable). Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI review feedback — declarative wiring, no agent swap Reworks A2UI so it no longer swaps the agent object mid-run, and fixes the issues that swap caused. - Drive A2UI through a dedicated runner used only for the stream call; keep the original agent bound so protected-state-key computation, approval resolution, and continuation serialization still read its real context_providers and client (no more provider-namespace or approval middleware loss). - Hand the forwarded AG-UI context to the runner directly instead of stamping it onto run-option additional_properties. That channel leaked the slice to the provider SDK on any run carrying AG-UI context, including non-A2UI runs where nothing stripped it back. Removes the stamp/strip/read helpers and the dead .NET-shaped path. - Suppress the terminal MESSAGES_SNAPSHOT off whether A2UI actually drove the run, not the literal tool names, so an unrelated user tool named "generate_a2ui" keeps its snapshot. - Fail loud with an install hint when A2UI is requested but the toolkit isn't installed, instead of advertising render_a2ui with no executor. - Include the agent's own default tools in the no-double-injection check so an already-wired agent doesn't crash on a duplicate tool name. - Execute ordinary developer tools called in the same turn as generate_a2ui (the declaration-only tool poisons the inner batch invocation), so a "look up data then render it" turn no longer skips the backend call. - Attribute nameless streaming argument deltas by the provider tool-call index so interleaved parallel calls don't cross-contaminate; the OpenAI chat client preserves that index on the content. Adds tests for the mixed-batch execution, index-based fragment attribution, and the default-tool duplicate check. Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI review round 2 — mixed-batch pipeline, client tools, snapshot - Mixed-batch (a tool called in the same turn as generate_a2ui): execute server tools through the agent's real function-invocation pipeline (client function_middleware + config), the same path approval-resume uses, instead of a direct tool.invoke() that bypassed middleware/context/session. - Look up mixed-batch tools across incoming AND the agent's own default tools, so a server tool wired only on the agent (no runtime tools=) still executes. - Leave declaration-only client tools (func=None) as user-input requests instead of synthesizing a local result, preserving the resumable client-tool flow. - Recognize a manually enable_a2ui()-wrapped agent when deciding to suppress the terminal MESSAGES_SNAPSHOT, so the ordering fix also covers that path. - Remove .NET-specific comments from the Python module. Adds tests: server-tool execution runs through middleware, default-tool execution, client declaration-only tool left as user-input. Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI review round 2 — fold context wrapper, typed runner Consolidates A2UI wiring into one owner, per review: - Fold the context-prepend (former AGUIContextAgent) into A2UIAgent, which now prepends the forwarded catalog + guidelines as a system message itself. Removes the extra agent type (matching the langgraph/strands adapters, which have no separate context agent). - Make A2UIAgent the typed runner interface: it carries the render tool(s) to strip (drop_tool_names) and is recognized via is_a2ui_runner(). plan_a2ui_injection now returns the runner (or None) instead of a bare dict, so no private plan keys leak into the host and the host no longer tracks activation separately — is_a2ui_runner() covers both the auto-injected and manual enable_a2ui() paths. Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI — bridge test for client tool + generate_a2ui in one turn End-to-end through run_agent_stream: a turn that calls a declaration-only client tool alongside generate_a2ui surfaces the client tool as a resumable frontend tool call (START/ARGS/END, no server-synthesized result) so the frontend executes and resumes it, the A2UI surface still renders, the run finishes, and no terminal MESSAGES_SNAPSHOT is emitted (manual enable_a2ui path). Confirms the mixed-batch client-tool contract on the AG-UI wire, not just at the agent level. Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI review round 3 — manual-path delegation, per-request context, facade - A2UIAgent delegates client / default_options / context_providers to the wrapped agent, so a manually enable_a2ui()-wrapped runner keeps the inner agent's configured tools, provider-owned state protection, and approval middleware that the auto-injected path already preserves. - Take the AG-UI context slice per run (a2ui_context kwarg the host passes each request) instead of only at construction, so a reused runner never serves stale catalog/guidelines. - Remove the deleted AGUIContextAgent from the package facade's __all__ and lazy exports (it no longer resolves) and drop the remaining doc references to it. Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI review round 3 — mixed-batch reuses the core invocation controls Reworks server-tool execution batched with generate_a2ui so it goes through the shared function-invocation owner faithfully instead of a partial re-implementation: - Pass the run's invocation session and the full function-middleware pipeline (static client middleware plus runtime middleware) into the execution. - Honor function_invocation_configuration["enabled"] and the shared per-request max_function_calls budget, tracked cumulatively across A2UI planner rounds, so a side-effecting tool cannot run once per round or run while invocation is disabled. - Preserve non-result control contents (e.g. a function_approval_request for an always_require tool) and the executor's termination signal instead of filtering to function_result, and surface them on the wire. - Stop the run instead of re-entering the planner whenever the turn carries calls it cannot safely replay — client tools awaiting the frontend, deferred/over-budget or approval-pending server tools, or a termination request — so an unanswered assistant tool_call is never replayed as unbalanced history. Tests: cumulative budget cap across rounds, invocation-disabled skip, approval request surfaced + run stops, and the bridge test now asserts the planner is not re-entered. Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI review round 4 — core batch executor, budget/iteration parity - Add a core-owned execute_function_call_batch() to agent_framework._tools that builds the function-middleware pipeline (static + runtime, normalizing bare objects and expanding MiddlewareBundles via categorize_middleware), normalizes config, threads the invocation session, and returns a structured result (results / control / should_terminate). A2UI's mixed-batch server execution now delegates to it instead of reproducing the pipeline/session/result handling, so a runtime `middleware=<bare>` or a bundle no longer raises or is silently skipped, and future core policy changes stay in one place. - Charge generate_a2ui against the per-request max_function_calls budget (each is a render-subagent invocation) and cap the planner rounds by max_iterations, so a generate-only planner can no longer run more render calls than the configured limits. Tests: generate-only planner honors the call budget and max_iterations; the mixed-batch budget test accounts for generate also charging. Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI review round 5 — force tools off on the final narration turn The final narration turn started a fresh inner_agent.run() with tools still enabled, so after the planner rounds/budget were spent it could execute another full batch of server/default tools and exceed max_function_calls / max_iterations. Set tool_choice="none" on that turn so it is a pure narration with no tool execution, matching the core loop's budget-exhausted final response. Test: the final narration turn's options carry tool_choice="none". Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI review round 5 — move the budget lifecycle into a core owner Add a core-owned FunctionCallBudget to agent_framework._tools that owns the per-request accounting the core loop enforces: the invocation toggle, the cumulative max_function_calls budget, the max_iterations round cap, and the tools-off final-response options. execute_function_call_batch now takes a budget and returns the deferred (unrun) calls. A2UIAgent's planner loop no longer reimplements any of this — it holds one budget object and asks it (rounds_remaining / take / exhausted / final_response_options), so server tools, generate_a2ui, the round cap, and the final tools-off turn all go through the single core owner. This removes the split that let the final turn start a fresh budget, and keeps mixed A2UI turns aligned with core policy changes. Tests: core budget primitive (take/exhausted/rounds/final-options); invocation disabled now runs no server tool AND no surface (matches the core loop). Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI review round 5 follow-up — keep budgeting local, narrate on budget exhaustion Per review, the core is not the place for a second budget abstraction: remove the FunctionCallBudget class from agent_framework._tools (execute_function_call_batch, which was the requested shared executor, stays). A2UIAgent honors the inner agent's function-invocation configuration locally again — the invocation toggle, the cumulative max_function_calls budget (charged by server tools and generate_a2ui), and the max_iterations round cap. Also fix the reported gap: when the call budget is exhausted (e.g. max_function_calls=1 spent on the first generate_a2ui), the run now breaks to the tools-off final narration turn instead of returning after the surface, so it produces a closing assistant response — matching the iteration-cap path and the core loop. Calls awaiting external resolution (client tools, deferred, approval, termination) still end the run without that final turn, since a follow-up run resumes them. Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI — feed the current surface to the budget-exhausted final narration On budget exhaustion the loop broke before appending this round's assistant tool_call(s) and results to history, so the tools-off final narration turn saw only the original user messages and could not narrate the generate_a2ui result it had just produced. Append the round's assistant/tool pair before breaking so the final turn receives it. The test now asserts the final turn's messages include the just-produced surface. Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI — keep batch execution in the adapter; fix CI typing Per review, don't add A2UI-specific abstractions to core: remove execute_function_call_batch / FunctionCallBatchExecution from agent_framework._tools. A2UIAgent's _execute_server_tools now runs the mixed batch inline using the framework's existing helpers (_try_execute_function_call_groups plus categorize_middleware for bare/bundle middleware normalization) with the run's session, config, and middleware — the same helpers the AG-UI approval path uses — so nothing adapter-specific lives in core. Also fix the CI typing check: annotate the A2UI test doubles and helpers so mypy, pyrefly, and ty pass over the test module (mixed-shape result tuples, a nullable envelope helper, and duck-typed fakes passed where protocols are expected). Signed-off-by: ran <ran@copilotkit.ai> * Python: A2UI — propagate MiddlewareFailure through the inline server-tool path; generic non-leaking error results; fix ty test typing - _execute_server_tools now re-raises MiddlewareFailure so a fail-closed authorization/guardrail abort stops the run instead of being folded into an error result that would still render a surface (matches the core loop). - Ordinary execution failures return core's generic 'Error: Function failed.' message; the raw exception text rides the non-model-visible exception field and is only exposed when include_detailed_errors is enabled, so credentials/ provider payloads/tenant data cannot leak to the model. - Add ty suppressions on the two duck-typed test constructors (ty does not honor mypy-style '# type: ignore[arg-type]') to clear the Test Typing Checks gate. - Cover both behaviors with tests (MiddlewareFailure aborts without rendering; tool error result is generic and non-leaking). --------- Signed-off-by: ran <ran@copilotkit.ai> Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> |
||
|
|
a7fea02070 |
Python: Bump ruff from 0.16.0 to 0.16.3 in /python (#7781)
* Bump ruff from 0.16.0 to 0.16.3 in /python Bumps [ruff](https://github.com/astral-sh/ruff) from 0.16.0 to 0.16.3. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.16.0...0.16.3) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.16.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Align lab ruff pin to 0.16.3 and refresh uv.lock Co-authored-by: moonbox3 <35585003+moonbox3@users.noreply.github.com> * Revert unintended ruff rule-name rewrites in python/pyproject.toml 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> |
||
|
|
d1dbce7138 |
Python: Bump mypy from 2.3.0 to 2.3.1 in /python (#7784)
* Bump mypy from 2.3.0 to 2.3.1 in /python Bumps [mypy](https://github.com/python/mypy) from 2.3.0 to 2.3.1. - [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md) - [Commits](https://github.com/python/mypy/compare/v2.3.0...v2.3.1) --- updated-dependencies: - dependency-name: mypy dependency-version: 2.3.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Regenerate uv.lock for mypy 2.3.1 and align lab dev pin 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> |
||
|
|
007a2d7a05 |
Python: FoundryEvals always emits arguments field for tool calls (#7734)
* Python: always emit arguments field for tool calls in AgentEvalConverter
FoundryEvals uploaded tool_call content items without an arguments
field when a tool call had no model-supplied arguments. Foundry's
tool-aware evaluators (task_adherence, tool_output_utilization,
tool_call_accuracy) require the arguments field to always be present,
so zero-argument tool calls caused evaluation to fail with
FAILED_EXECUTION. Default to an empty object instead of omitting the
field.
* Python: only default arguments to {} when None, not on falsy values
Addresses Copilot review feedback: a truthiness check would also
overwrite valid but falsy parsed arguments (e.g. 0, "", False) with
{}. Use an explicit None check so only missing arguments are defaulted.
|
||
|
|
24a383613b |
Python: feat: forward function_invocation_kwargs through DevUI to agent.run (#7779)
DevUI's /v1/responses endpoint builds agent.run() kwargs by hand and only
passed stream/session, so tools that read request-scoped values via
FunctionInvocationContext.kwargs (tenant id, auth token, user id)
silently received nothing when the agent was run through DevUI. The same
agent works correctly outside DevUI via agent.run(..., function_invocation_kwargs=...).
Forward function_invocation_kwargs from the request into agent.run() in
AgentFrameworkExecutor._execute_agent. Accepts both channels already used
on the request payload:
- extra_body.function_invocation_kwargs (the channel already used for
response_id / checkpoint_id)
- top-level extra field (AgentFrameworkRequest has ConfigDict(extra="allow"))
Top-level takes precedence when both are set. Non-dict / missing values
are silently ignored for backward compatibility. No frontend / model
changes.
Adds a parametrized regression test in test_execution.py covering all
three cases (extra_body, top-level, absent).
Fixes #7344
|
||
|
|
4e754a636d |
[BREAKING] Python: Consolidate OTel GenAI Semantic Conventions versions (#7673)
* Consolidate OTel GenAI Semantic Conventions versions * Address comments * Refinement * Further constraint v1.26.0 attrs * Fix tests and typing * Address copilot comments * Fix tests * Fix typing * Fix typing * Rewording |
||
|
|
aeaabe5abf |
Python: fix MCP tool argument shadowing the remote tool name (#7799)
* Python: fix MCP tool argument shadowing the remote tool name The generated MCP function held the remote tool name as the default of a keyword-only parameter. Tool arguments are splatted into that function, so an argument named `_remote_tool_name` bound to the parameter instead of `**kwargs` and changed which remote tool was called. Move the remote tool name into a factory closure so it is no longer part of the generated function's signature, matching the prompt path which already binds the name positionally via `partial`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4cb58e38-4af2-485d-b734-7d70972959f2 * Guard await_args before indexing in MCP regression test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4cb58e38-4af2-485d-b734-7d70972959f2 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4cb58e38-4af2-485d-b734-7d70972959f2 |
||
|
|
2054d62702 |
Python: fix(github-copilot): forward telemetry config to client (#7625)
* fix(github-copilot): forward telemetry config to client * Python: fix telemetry settings typing for github_copilot `load_settings` does not coerce dict-typed fields, so GITHUB_COPILOT_TELEMETRY and .env values reach the agent as plain strings. Declaring `GitHubCopilotSettings.telemetry` as `dict[str, Any]` therefore misstated the runtime contract and failed the test typing checks where a string is assigned. Widen the annotation to `dict[str, Any] | str | None` and fix the union arm resolution in `_check_override_type`: parameterized generics are not `type` instances, so they were dropped from the allowed set and a valid dict override was rejected at runtime. Arms without a runtime class, such as `Literal`, now skip validation instead of narrowing it incorrectly. Also drive the telemetry string tests through the documented environment variable path rather than mutating `_settings` directly, and cover the valid-JSON-but-not-an-object case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 657d2953-4112-4a01-889b-c0c6863630c1 * Python: resolve settings override types through generic origins Python 3.10 reports parameterized generics such as `dict[str, Any]` as instances of `type`, so the union arm resolution kept the alias and `isinstance` raised `TypeError: isinstance() argument 2 cannot be a parameterized generic` on that interpreter. Resolve every annotation through `get_origin` first via a shared `_runtime_class` helper, which also removes the same latent failure for a non-union parameterized generic field, and return `None` for annotations such as `Literal[...]` that have no runtime class so validation is skipped rather than narrowed incorrectly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 657d2953-4112-4a01-889b-c0c6863630c1 --------- Co-authored-by: Giles Odigwe <gilesodigwe@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 657d2953-4112-4a01-889b-c0c6863630c1 |
||
|
|
ecc1430977 |
Python: defer turn-scoped after_run providers to the agent loop boundary (#7289)
* Python: defer turn-scoped after_run providers to the agent loop boundary Each AgentLoopMiddleware iteration is a full agent run, so CompactionProvider.after_run fired per iteration and rewrote persisted history mid-task (#7236). Providers can now opt into turn scope with after_run_once_per_turn; iterations defer them via a contextvar, and the loop fires them once at the boundary. CompactionProvider opts in; HistoryProvider keeps its incremental per-run persistence. * Python: key loop suppression to the looping agent and pass run options through Two review follow-ups: the contextvar now carries the agent instance so a nested agent.run() inside a loop iteration is not suppressed as if it were an iteration, and the boundary SessionContext forwards the original run options to turn-scoped providers. * fix(core): carry the loop-iteration stamp in run options, not a contextvar The contextvar marker leaked in two ways. Held across a streamed yield it bled into the caller's context, suppressing turn-scoped providers on an unrelated same-agent run while the stream was paused, and a reset from a different consuming task raised on the token. Keyed to the agent instance, it also swallowed the boundary flush of a nested loop on the same agent with its own session. Stamp the runs the loop drives through their options instead. Run options reach only the inner runs (they never enter the model request), a nested or concurrent run starts with fresh options and keeps its own turn, and there is no token to reset, so stream consumption is safe from any task. * Python: annotate custom option keys in the after_run provider test * fix: nosec the loop-iteration options key (bandit B105 false positive) * Python: fix: suppress the loop-token key lint with ruff: ignore * Python: fix: silence the two pyright private-usage flags the repo's own idiom covers --------- Co-authored-by: Giles Odigwe <79032838+giles17@users.noreply.github.com> Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> |
||
|
|
26b28b4386 |
Python: Avoid unchanged AG-UI predictive state snapshots (#7766)
* Python: Avoid unchanged AG-UI predictive state snapshots Only emit the coalesced snapshot when predictive updates were actually pending or a deterministic state update was returned. Assisted-by: Codex <codex@openai.com> * Python: Exercise the predictive update path in snapshot tests Use the handler streaming API to create pending state and narrow snapshot events by their concrete type. Assisted-by: Codex <codex@openai.com> |
||
|
|
435201b71b |
Python: Fix A2A input handling in orchestrations (#7761)
* fix(a2a): reject empty invocations explicitly Key decisions: - Keep A2A continuation authority explicit; durable session task state only enriches diagnostics. - Raise AgentInvalidRequestException with participant and available task context instead of inventing input. - Leave AgentExecutor and Group Chat production contracts unchanged. Files changed: - packages/a2a/agent_framework_a2a/_agent.py - packages/a2a/tests/test_a2a_agent.py - packages/a2a/tests/test_a2a_group_chat.py Notes for next iteration: - No blockers. INPUT_REQUIRED pause/resume remains a separate task. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(a2a): pause group chat for remote input Key decisions: - Translate A2A INPUT_REQUIRED task content into the existing Content user-input-request contract. - Use the remote task ID as stable request correlation for streamed and finalized responses. - Reuse AgentExecutor request handling so caller input resumes the same task without a workflow-specific A2A path. Files changed: - packages/a2a/agent_framework_a2a/_agent.py - packages/a2a/tests/test_a2a_agent.py - packages/a2a/tests/test_a2a_group_chat.py Notes for next iteration: - Checkpoint restoration of pending A2A input is now unblocked. - The local issue file could not be moved because repository issue files are restricted by content exclusion policy. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(a2a): restore pending input from checkpoints Key decisions: - Keep normalized INPUT_REQUIRED content durable by excluding transport-only protobuf raw representations. - Restore through the existing AgentExecutor checkpoint and request-response path without a new schema or continuation API. - Cover file-backed restoration in streaming and non-streaming Group Chat runs, including unrelated-response rejection and exact task resumption. Files changed: - packages/a2a/agent_framework_a2a/_agent.py - packages/a2a/tests/test_a2a_group_chat.py Notes for next iteration: - The local issue file could not be moved because repository issue files are restricted by content exclusion policy. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(handoff): lock textless target context Key decisions: - Exercise the built Handoff workflow in streaming and non-streaming modes instead of bypassing routing, sessions, or termination. - Keep the slice test-only because current production already carries the initial task to a textless handoff target without synthetic user input. - Revisit the source to verify its handoff function call retains a matching result and user-turn termination sees only caller messages. Files changed: - packages/orchestrations/tests/test_handoff.py Notes for next iteration: - No production defect was reproduced. - The local issue file could not be moved because repository issue files are restricted by content exclusion policy. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(handoff): use resolved IDs in event assertions * fix(workflows): preserve A2A input request semantics * fix(workflows): preserve input request correlation * fix(a2a): deduplicate message-less input requests * fix(workflows): preserve specialized input requests * test(openai): use current web search model --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
26b9200c21 |
Python: Preserve AG-UI tool message IDs across snapshots (#7510)
* fix(ag-ui): preserve streamed tool message IDs * fix(ag-ui): align approval and MCP tool message IDs * fix(ag-ui): ensure unique tool segment IDs * fix(ag-ui): keep tool and text snapshot IDs unique --------- Co-authored-by: Evan Mattson <evan.mattson@microsoft.com> |
||
|
|
8be7c93063 |
Python: Preserve structured instructions when merging chat options (#7730)
* Python: Preserve structured instructions when merging chat options `instructions` is declared as `str` on `ChatOptions`, but chat clients may widen it to a provider-native structured form. Three merge paths combined it with an f-string, which coerced any non-string value to its `repr`, turning structured metadata into literal text before any client could see it: - `merge_chat_options` (`_types.py`) - `_merge_options` (`_agents.py`, agent defaults + per-run options) - provider-contributed instructions in `_prepare_session_and_messages` (`_agents.py`) The last of these is the reported case: once any context provider (for example `SkillsProvider`) contributes instructions, structured instructions were replaced by their `repr`, so the model received Python dict syntax as its system prompt and Anthropic prompt caching silently stopped working. Add a shared `_append_instructions` helper that concatenates strings as before and otherwise extends element-wise, always appending so the leading portion stays unchanged for providers that treat it as a stable, structure-sensitive prefix. A lone mapping is treated as a single element rather than iterated into its keys. On the Anthropic side, `_extract_structured_instructions` now normalizes bare strings into text blocks, since appended instructions arrive alongside caller-supplied blocks. Fixes #7700 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f428b149-a306-484a-b423-4e9de69f0b90 * Python: address review feedback on structured instructions fix Parameterize the Anthropic regression test over both the with- and without-SkillsProvider configurations so the structure-preserving behavior is asserted in the baseline case too. Normalize structured instructions in `_get_instructions_from_options` so telemetry records the instruction text for provider-native block shapes, extracting only `text` values to keep provider metadata out of spans. Use `cast` for the structured `default_options` in both regression tests so the test type checkers resolve the client options type correctly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f428b149-a306-484a-b423-4e9de69f0b90 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> Copilot-Session: f428b149-a306-484a-b423-4e9de69f0b90 |
||
|
|
ec407cf56f |
Python: fix: preserve Agent additional_properties in HandoffBuilder clones (#7755)
HandoffAgentExecutor clones each participant agent to attach handoff tools, but the clone rebuilt the Agent without forwarding additional_properties, so middleware and integrations observing context.agent.additional_properties during handoff runs saw an empty dict while the original agent retained its configuration. Pass a deepcopy of the original agent's additional_properties into the clone so handoff-executed agents keep their configured metadata and the original agent stays untouched. Fixes #7750 |
||
|
|
da11daebe5 |
Python: fix: prevent superlinear history growth by deduplicating messages in save_messages (#7242)
* fix: prevent superlinear history growth by deduplicating messages in save_messages * fix: address review feedback for history deduplication * fix: Prevent superlinear history growth by deduplicating messages * fix: add list[Message] type hints * fix(sessions): resolve deduplication churn and collapsing of identical message * fix(sessions): replace uuid/seen-set dedup with sequence aware filtering * fix: use forward-scan sequence alignment in filter_new_messages * fix(core): annotate new_msgs type to resolve pyright errors --------- Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com> Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> |
||
|
|
e74ac4613c |
fix(python): coerce JSON workflow resume payloads (#7684)
AG-UI clients send plain JSON, but structured response types were only accepted as already-built instances, and core's coercion stopped at the outer object, letting raw dicts sit inside typed fields. Coercion now walks declared annotations and returns the input untouched whenever it cannot satisfy them. |
||
|
|
e6536fb459 |
Python: Align AG-UI run continuity (#7662)
* Python: Align AG-UI run continuity Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: aadad05d-2646-405f-8c62-a7a223abfc92 * Python: Refine AG-UI continuation ownership Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: aadad05d-2646-405f-8c62-a7a223abfc92 * Python: Persist AG-UI checkpoint ownership Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: aadad05d-2646-405f-8c62-a7a223abfc92 --------- Copilot-Session: aadad05d-2646-405f-8c62-a7a223abfc92 |
||
|
|
58da0cc253 |
Python: add MiddlewareFailure, a first-class fatal signal for function middleware (#7562)
* feat(core): first-class fatal signal (MiddlewareFailure) for function middleware The function-invocation loop converts every exception raised by function middleware into a tool-error result and keeps looping, so middleware that needs fail-closed semantics (enforcement layers, guardrails) had no loud escape: the agent-hooks feature simulated one by mutating shared run state, raising MiddlewareTermination, and re-raising the real failure two hops away at the run boundary. Introduce MiddlewareFailure (a MiddlewareException sibling of MiddlewareTermination) as the loop's explicit fail-closed escape: - _auto_invoke_function re-raises it (both the direct and the pipeline path) instead of absorbing it into a tool-error result; ordinary exceptions keep the absorb-and-continue contract. - A failing call fails the whole parallel batch: in-flight sibling tool tasks are cancelled and awaited before the failure propagates. - Every existing MiddlewareTermination absorb site (agent/chat pipelines, _execute_single_function_call, harness loop, purview) passes it through untouched by construction, and agent/chat middleware exceptions already propagate, so one exception type gives uniform fail-loud semantics across all three categories. Migrate the agent-hooks feature to the new signal: delete the _RunState.halted back-channel and its three run-boundary re-raise checks, drop the halted arm of the termination special case in the function middleware (the approval-request pass-through moves to the single approval check on the normal path), and fail partial installs loudly. Tool-seam host_error blocks keep surfacing as InterceptionBlocked at the run boundary via the exception cause chain (one deny surface at every seam, pinned by tests). Spec 004 gains the middleware-failure invariants and matrix rows. Closes #7522 Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * fix(core): harden tool-seam unwrap and pin review findings Review round follow-ups for the MiddlewareFailure feature: - Only agent-hooks' own tagged tool-seam halts (_ToolSeamBlockFailure) authorize re-raising the chained InterceptionBlocked at the run boundary; a third-party MiddlewareFailure with a crafted InterceptionBlocked cause now propagates as raised instead of laundering an attacker-shaped interception record into the feature's deny surface (regression test added, verified by mutation). - Document that middleware must not catch MiddlewareFailure (docstring and spec 004): swallowing it converts a fail-closed abort back into a running, possibly unguarded loop. - Pin the trailing termination re-raise in the agent-hooks function middleware: an inner short-circuit is bracketed and still propagates, skipping outer middleware post-code (test fails with the re-raise removed). Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * fix(core): acyclic tool-seam unwrap chain; document cooperative batch cancellation Address two automated-review findings on the MiddlewareFailure PR, both confirmed empirically: - _reraise_tool_seam_block created a two-object exception-chain cycle (block.__cause__ -> wrapper -> block) by re-raising the chained InterceptionBlocked `from` its transport wrapper. Detach the wrapper's back-links and re-raise bare, recording the wrapper as the block's __context__ — acyclic, both exceptions still visible in tracebacks. Regression test walks the chain and pins finiteness (verified to fail against the cyclic re-raise). - Batch cancellation is cooperative: a synchronous tool body already running in a worker thread (asyncio.to_thread) cannot be interrupted by task cancellation and may complete its side effects after the failure reached the caller; its result is discarded either way and propagation is not delayed behind it. Narrow the stated contract (MiddlewareFailure docstring, loop comment, spec 004) and pin it with a blocking-sync-sibling regression test. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * fix(core): settle dangling calls on service-managed conversations on abort Address maintainer review on the MiddlewareFailure PR: - A MiddlewareFailure escaping a tool batch on a service-managed conversation left the hosted thread ending in unresolved function_call items: _update_continuation_state persists session.service_session_id when the model turn completes (before tool execution), and probe-verified the next run sends only the new user message against that conversation — OpenAI-style continuations reject such a request, so a routine policy abort left the session permanently stuck. Both loops now settle the thread before propagating: one error function_result per dangling call, submitted with tool_choice="none" in a single extra request whose response is discarded; a settlement failure never masks the abort, and runs without a service-managed conversation make no extra request. Pinned by three regression tests (non-streaming, streaming, and the no-conversation no-cost case); spec 004 and the MiddlewareFailure docstring updated. - Make the three tool-bracket escape tuples in the agent-hooks function middleware identical (MiddlewareTermination, MiddlewareFailure, CancelledError): a MiddlewareFailure raised inside the post/error-bracket emit bodies is unreachable today, but the uniform tuples remove the need to reason about why they would differ, and preserve the exact exception (including the private tool-seam tag) if the emitter ever surfaces one. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * fix(core): advance settled continuation; settle approved-replay aborts Address maintainer review on the MiddlewareFailure settlement path, both probe-verified (branch rebased onto current main first): - Advance the persisted continuation to the settlement response. For response-ID continuations (OpenAI Responses store=True, where the response id is the continuation handle) the settlement response is the first endpoint whose chain includes the synthetic tool outputs; leaving session.service_session_id on the pre-settlement response made the settlement ineffective — the next run would continue from the still-unresolved turn. The settlement response now runs through _update_function_invocation_continuation_state (a no-op for stable conversation-object ids). Pinned by a regression test that fails with the advance removed. - Cover the approval-resolution phase: a MiddlewareFailure raised while an approved tool is replayed escapes loudly (probe-verified, already the case) but executed before the loops' settlement seams, leaving the original — already service-persisted — call unresolved. _resolve_approval_responses now takes a settle_dangling_calls callback invoked with the approved batch on abort; the settlement helper became a layer method taking explicit calls (approval-response wrappers unwrap to their underlying calls, hosted-tool approvals are left to their provider protocol) and carries its own best-effort containment. Pinned by deny-during- replay regression tests in both response modes, mutation-verified. Spec 004 invariants and matrix rows updated accordingly. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> --------- Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> |
||
|
|
00d7102c54 |
Python: fix(workflows): preserve all trace contexts in FanInEdgeRunner aggregation (#7557)
* fix(workflows): preserve all trace contexts in FanInEdgeRunner aggregation FanInEdgeRunner collected trace contexts and source span IDs using the singular backward-compat properties (msg.trace_context / msg.source_span_id), which return only the first element of the plural lists. When a message arriving at a fan-in already carries multiple trace contexts (e.g. from a prior fan-in aggregation), all but the first were silently dropped. Iterate over the plural fields (trace_contexts / source_span_ids) and extend the aggregated lists so every trace context and source span ID from every source message is preserved. This keeps distributed tracing links intact for nested fan-in topologies. Added test_fan_in_preserves_multiple_trace_contexts_per_message that sends a message with two trace contexts through a fan-in and asserts all three contexts (2 + 1) reach the target executor. * fix: address Copilot review comments on trace context aggregation 1. Pair trace_contexts and source_span_ids per-message (via zip) instead of flattening independently. This prevents misalignment when a message has mismatched counts — orphans are dropped per-message rather than shifting all subsequent pairs out of alignment. 2. Remove TraceCapturingAggregator's override of Executor.execute() (documented as "do not override"). Capture trace data from the WorkflowContext passed to the handler instead. --------- Co-authored-by: weed33834 <weed33834@users.noreply.github.com> Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> |
||
|
|
af4347a61d |
Python: Restrict workflow type deserialization (#7500)
Resolve request-info type names only from exact caller-provided mappings or already-loaded module namespaces. Remove payload-selected imports and add focused regression coverage for both request and response type fields. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a53fe20b-c3f0-4583-badc-d5deac7c1049 |
||
|
|
925d722acf |
Python: clarify skill script argument guidance (#7695)
* Python: clarify skill script argument guidance * test: harden skill argument guidance coverage |
||
|
|
6a3633e54a |
Python: Add a global workflow checkpoint type registry (#7636)
* Add a glocal checkpoint type registry * Update samples * Revert uv.lock * Address comments * Revert uv.lock * Revert uv.lock |
||
|
|
648a31ade6 |
Python: Surface A2A preview consent URLs (#7606)
* fix(foundry-hosting): surface A2A consent URLs * Use non-hashing membership Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Tao Chen <williamchan444307762@hotmail.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Tao Chen <taochen@microsoft.com> |
||
|
|
11592495db | docs: fix Agent Lightning installation link (#7693) | ||
|
|
9c3a1a4af7 |
Python: Enhance _OutputItemTracker to prevent duplicate function call streaming (#7486)
* Python: Enhance _OutputItemTracker to prevent duplicate function call streaming * Handle empty function call metadata arguments Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9b232bff-6a8c-4b02-addd-89de57a82f6a * Python: Refactor _OutputItemTracker to manage outstanding function calls and update tests for call ID reuse --------- Copilot-Session: 9b232bff-6a8c-4b02-addd-89de57a82f6a |
||
|
|
228754d7fa |
Python: Fix AG-UI url source dropping attachments when the URL is in source.value (#7655)
The ag-ui-protocol `InputContentUrlSource` carries the URL in `source.value`, but `_extract_multimodal_source_fields` only read `source.url`/`source.uri` for url-typed sources, so attachments sent in the spec shape were dropped during the AG-UI to MAF conversion. The base64 branch already read `source.value` correctly. Read `source.value` first, keeping `url`/`uri` as fallbacks for the non-spec shape. Adds tests for both. Fixes #7653 |
||
|
|
8461667fe4 |
fix: deduplicate streamed DevUI tool calls (#7652)
Refs #7651 🐛 - Generated by Copilot |
||
|
|
e289320027 |
Python: Add approval storage and improve truth checks (#7631)
* Add approval storage and improve truth checks * Address PR comments * Update spec * Revert changes to agui since it is already handled in another pr * Add missed change |
||
|
|
ae7fa3389c |
Python: Bump Python package versions for 1.14.0 release (#7661)
* Bump Python package versions for 1.14.0 release Bump the CHANGELOG-selected packages for the 1.14.0 release: minor versions for root/core, AG-UI, Foundry, OpenAI, and orchestrations due to additive public APIs; patch versions for declarative and GitHub Copilot fixes; and Pacific-date prerelease stamps only for changed alpha/beta packages. No beta cohort bump was applied. Core dependency floors follow the strict policy and remain unchanged because no dependent package requires a new 1.14 API. Release validation also identified and corrected missing AG-UI and Copilot Studio runtime dependencies and aligned GitHub Copilot metadata with its Python 3.11 SDK requirement. Lab is intentionally skipped because its changes are development-only, and the moved Azure Functions and Durable Task packages are documented but no longer versioned here. * Raise AG-UI core dependency floor |
||
|
|
4aa737eee5 |
Python: [BREAKING] Require building functional workflow instances (#7521)
* Harden functional workflow continuation authority Use a versioned opaque single-use token on WorkflowRunResult, validate it before request correlation, consume it immediately before replayed user code, and rotate it on each pause. Carry the same explicit authority through streaming and non-streaming FunctionalWorkflowAgent responses. Files changed: functional workflow/runtime result APIs, functional HITL regression tests, core agent guidance, and the functional HITL sample. Next iteration: enforce pending-state overlap and token-authorized abandonment, then document and test checkpoint authorization boundaries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Enforce one pending functional continuation Reject fresh messages and checkpoint restores while an in-memory continuation is pending. Add token-authorized abandonment on FunctionalWorkflow and FunctionalWorkflowAgent, and clear retained replay state atomically when authority is consumed while preserving the active message for token rotation and checkpoints. Files changed: functional workflow runtime and agent adapter, functional lifecycle regression tests, and core workflow guidance. Next iteration: preserve and document authorized checkpoint continuation boundaries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Preserve authorized functional checkpoint continuation Treat checkpoint restore as a host- and storage-authorized path independent of process-local continuation tokens, and issue fresh authority whenever restored execution pauses again. Cover default and per-run storage, deterministic and custom request IDs, token rotation, and checkpoint-plus-response restore. Files changed: functional workflow and checkpoint interface guidance, functional checkpoint lifecycle tests, the functional HITL sample, and core workflow guidance. Next iteration: run the final repository-wide Python validation gates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Validate Python continuation hardening Run the complete Python workspace checks, aggregate coverage suite, repository hooks, and core package build from the final combined worktree. Keep the validation iteration code-neutral because all gates pass without corrective changes. Files changed: none; this commit records the final validation gate. Blockers: none. Next iteration: no remaining AFK tasks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Handle functional checkpoint continuation failures Publish retained continuation state only after checkpoint persistence succeeds, and cover reuse after a transient save failure. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a8f47743-1cdc-4924-8e1b-667d0d790b78 * Address functional continuation review findings Add owner recovery for lost tokens, harden malformed token validation, preserve consistent failure surfaces, and keep agent pending state aligned with resumable workflow state. Document process-local single-use continuation semantics and extend regression coverage across direct, streaming, checkpoint, and agent paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a8f47743-1cdc-4924-8e1b-667d0d790b78 * Handle functional continuation cancellation Release the workflow run guard when cancellation interrupts resumed user code while keeping the single-use continuation token consumed. Replace sample assertions with explicit runtime checks and add cancellation regression coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a8f47743-1cdc-4924-8e1b-667d0d790b78 * Simplify functional workflow instance isolation Remove continuation-token handling and align functional workflows with the graph workflow ownership model: one stateful instance per logical caller or session. Add create_instance() for independent callers, document the ownership contract, and cover pending-state isolation between instances. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a8f47743-1cdc-4924-8e1b-667d0d790b78 * Scope functional workflow checkpoint storage Do not inherit checkpoint storage when creating an independent workflow instance. Allow hosts to provide an explicitly caller-scoped storage adapter and document that shared checkpoint access requires host authorization and tenant isolation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a8f47743-1cdc-4924-8e1b-667d0d790b78 * Require building functional workflow instances Make @workflow return a stateless FunctionalWorkflowDefinition and require build() before run() or as_agent(). This aligns functional workflows with the graph definition/build lifecycle and prevents module-level decorated definitions from retaining caller state. Move checkpoint configuration to build(), export the definition type, migrate samples, and cover isolated built instances. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a8f47743-1cdc-4924-8e1b-667d0d790b78 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a8f47743-1cdc-4924-8e1b-667d0d790b78 |
||
|
|
8c4da3c3b9 |
Python: Harden AG-UI approval lifecycle and resume semantics (#7594)
* Route local approvals through lifecycle owner Key decisions: - Add an internal typed approval lifecycle with pending, claimed, executing, and settled states. - Keep authorization separate from execution; only LocalPendingToolTransitionOwner invokes approved local calls. - Register server-owned occurrences before canonical ResumeDecision claims and retain one replayable result under the original call identity. Files changed: - packages/ag-ui/agent_framework_ag_ui/_approval_lifecycle.py - packages/ag-ui/agent_framework_ag_ui/_approval_state.py - packages/ag-ui/agent_framework_ag_ui/_agent_run.py - packages/ag-ui/tests/ag_ui/test_approval_lifecycle.py - packages/ag-ui/tests/ag_ui/test_approval_result_event.py - packages/ag-ui/tests/ag_ui/test_agent_wrapper_comprehensive.py Verification: - 952 AG-UI tests passed. - Focused lifecycle/public tracer passed with warnings treated as errors. - Ruff format/check and AG-UI Pyright passed. - git diff --check passed. Notes for next iteration: - The function-calling-loop scenario mapping is inaccessible under the organization content-exclusion policy and could not be updated. - The workspace Poe package fan-out is blocked by the pre-existing missing packages/durabletask/pyproject.toml; equivalent package-local checks were run. * Make approval batches occurrence-safe Key decisions: - Give each local approval a scoped logical occurrence identity and share one occurrence across trusted thread aliases. - Validate complete Resume Decision batches before applying claims, then account for accepted, rejected, and cancelled occurrences independently. - Preserve sibling authority and original result identity across failures, mixed decisions, and reused raw call IDs. Files changed: - packages/ag-ui/agent_framework_ag_ui/_approval_lifecycle.py - packages/ag-ui/agent_framework_ag_ui/_approval_state.py - packages/ag-ui/agent_framework_ag_ui/_agent_run.py - packages/ag-ui/tests/ag_ui/test_approval_lifecycle.py - packages/ag-ui/tests/ag_ui/test_agent_wrapper_comprehensive.py Verification: - 959 AG-UI tests passed with 90% lifecycle branch coverage. - 30 focused lifecycle/public tracer tests passed with warnings treated as errors. - Ruff format/check and AG-UI Pyright passed. - git diff --check passed. Notes for next iteration: - The function-calling-loop scenario mapping remains inaccessible under the organization content-exclusion policy. - Workspace typing fan-out remains blocked by the pre-existing missing packages/durabletask/pyproject.toml; package-local Pyright passed, while package-local MyPy retains three unrelated baseline errors. * Make approval resume retries idempotent Key decisions: - Retain terminal decisions and outcomes by scoped occurrence so identical accepted and rejected retries reproject results without granting execution authority again. - Reject conflicting names, arguments, decisions, wrong-scope lookups, and expired authority before an execution intent can reach the local transition owner. - Keep protocol normalization in the runner while using server-owned lifecycle context to canonicalize retries and preserve existing AG-UI wire aliases. Files changed: - packages/ag-ui/agent_framework_ag_ui/_approval_lifecycle.py - packages/ag-ui/agent_framework_ag_ui/_agent_run.py - packages/ag-ui/tests/ag_ui/test_approval_lifecycle.py - packages/ag-ui/tests/ag_ui/test_agent_wrapper_comprehensive.py - packages/ag-ui/tests/ag_ui/test_endpoint.py Verification: - 965 AG-UI tests passed with 90% approval lifecycle coverage. - 18 focused lifecycle, hostile-resume, wrong-thread, and endpoint retry tests passed with runtime and deprecation warnings treated as errors. - Ruff format/check and AG-UI package-local Pyright passed. - git diff --check passed. Notes for next iteration: - Terminal retention is process-local and unbounded until the later bounded-retention issue adds its explicit policy. - The function-calling-loop scenario mapping remains inaccessible under the organization content-exclusion policy. * Separate approval execution ownership Key decisions: - Carry explicit local, hosted, deferred in-run, or unavailable ownership on every approval occurrence and authorized intent. - Keep lifecycle authorization separate from execution; local calls execute only through the local adapter while hosted and setup-injected decisions forward through owner-specific adapters. - Leave declaration-only calls pending when no transition owner can act, and settle forwarded outcomes against the original occurrence without local fallback. Files changed: - packages/ag-ui/agent_framework_ag_ui/_approval_lifecycle.py - packages/ag-ui/agent_framework_ag_ui/_approval_state.py - packages/ag-ui/agent_framework_ag_ui/_agent_run.py - packages/ag-ui/tests/ag_ui/test_approval_lifecycle.py - packages/ag-ui/tests/ag_ui/test_endpoint.py Verification: - 967 AG-UI tests passed with 92% package coverage and 89% approval lifecycle coverage. - 94 focused lifecycle, hosted, deferred-owner, hostile-resume, and approval tests passed. - Ruff format/check and package-local Pyright passed. - git diff --check passed. Notes for next iteration: - Executing-without-outcome recovery remains for the indeterminate execution-window issue. - The function-calling-loop scenario mapping remains inaccessible under the organization content-exclusion policy. - Workspace Poe fan-out remains blocked by the pre-existing missing packages/durabletask/pyproject.toml; equivalent package-local checks passed. * Represent approval execution uncertainty Key decisions: - Distinguish reserved claims from execution windows that may have started an external side effect. - Recover non-idempotent execution failures as indeterminate and reject identical retries without another invocation. - Permit claim release only under an explicit safe policy and execution retry only with a predeclared idempotency key shared by local and forwarded owners. Files changed: - packages/ag-ui/agent_framework_ag_ui/_approval_lifecycle.py - packages/ag-ui/tests/ag_ui/test_approval_lifecycle.py - packages/ag-ui/tests/ag_ui/test_endpoint.py Verification: - 972 AG-UI tests passed with 92% line coverage and 89% package branch coverage. - 23 focused lifecycle, duplicate-resume, hosted-owner, and public settlement-window tests passed. - Package-local Ruff and Pyright passed; git diff --check passed. Notes for next iteration: - The function-calling-loop scenario mapping remains inaccessible under the organization content-exclusion policy. - Workspace Poe fan-out remains blocked by the pre-existing missing packages/durabletask/pyproject.toml; equivalent package-local checks passed. * Reconcile approval snapshots with lifecycle state Key decisions: - Keep Approval State authoritative and emit typed snapshot reconciliation keyed by logical occurrence identity. - Retire settled, rejected, cancelled, expired, indeterminate, and missing controls while preserving nonterminal authority. - Reconcile stale snapshots before hydration or resume, and retain lifecycle deduplication when snapshot saves fail. Files changed: - packages/ag-ui/agent_framework_ag_ui/_approval_lifecycle.py - packages/ag-ui/agent_framework_ag_ui/_agent_run.py - packages/ag-ui/agent_framework_ag_ui/_snapshot_session.py - packages/ag-ui/tests/ag_ui/test_approval_lifecycle.py - packages/ag-ui/tests/ag_ui/test_endpoint.py Verification: - 975 AG-UI tests passed with 92% package coverage and 89% approval lifecycle coverage. - Package-local Ruff and Pyright passed; git diff --check passed. Notes for next iteration: - The function-calling-loop scenario mapping remains inaccessible under the organization content-exclusion policy. - Workspace Poe fan-out remains blocked by the pre-existing missing packages/durabletask/pyproject.toml; equivalent package-local checks passed. * Bound process-local approval lifecycle state Key decisions: - Protect pending, claimed, executing, and indeterminate occurrences from eviction while retaining terminal outcomes for a configurable 15-minute process-local deduplication window. - Serialize complete approval batches by logical occurrence locks so aliases share atomic decisions and independent batches can progress concurrently. - Fail capacity, claim, and settlement conflicts explicitly, and emit redacted structured lifecycle telemetry without tool names, arguments, or approval payloads. - Remove legacy LRU eviction paths so active Approval State and middleware state are never silently discarded. Files changed: - packages/ag-ui/agent_framework_ag_ui/_approval_lifecycle.py - packages/ag-ui/agent_framework_ag_ui/_approval_state.py - packages/ag-ui/agent_framework_ag_ui/_agent_run.py - packages/ag-ui/tests/ag_ui/test_approval_lifecycle.py - packages/ag-ui/tests/ag_ui/test_approval_state.py Verification: - 982 AG-UI tests passed with 92% package coverage and 91% approval lifecycle coverage. - 34 focused lifecycle and storage tests passed with RuntimeWarning and DeprecationWarning treated as errors. - Package-local Ruff and Pyright passed; git diff --check passed. Notes for next iteration: - The function-calling-loop scenario mapping remains inaccessible under the organization content-exclusion policy. - Workspace Poe fan-out remains blocked by the pre-existing missing packages/durabletask/pyproject.toml; equivalent package-local checks passed. * Complete approval lifecycle cutover Key decisions: - Make ApprovalLifecycle the sole owner of trusted aliases, occurrence metadata, authority transitions, and retained outcomes. - Remove the parallel mutable pending-approval registry and route local, hosted, deferred, cancellation, replay, and snapshot reconciliation through lifecycle occurrences. - Encapsulate middleware Approval State behind copy-isolated store methods while keeping AG-UI protocol normalization and event projection in the runner. Files changed: - packages/ag-ui/AGENTS.md - packages/ag-ui/agent_framework_ag_ui/_agent.py - packages/ag-ui/agent_framework_ag_ui/_agent_run.py - packages/ag-ui/agent_framework_ag_ui/_approval_lifecycle.py - packages/ag-ui/agent_framework_ag_ui/_approval_state.py - packages/ag-ui/tests/ag_ui/test_agent_wrapper_comprehensive.py - packages/ag-ui/tests/ag_ui/test_approval_lifecycle.py - packages/ag-ui/tests/ag_ui/test_approval_result_event.py - packages/ag-ui/tests/ag_ui/test_approval_state.py - packages/ag-ui/tests/ag_ui/test_endpoint.py - packages/ag-ui/tests/ag_ui/test_run.py Verification: - 964 package-local AG-UI tests passed with 92% coverage and 90% approval lifecycle coverage. - 85 warning-strict focused approval tests passed. - Package-local Ruff and Pyright passed; git diff --check passed. Notes for next iteration: - The function-calling-loop scenario mapping remains inaccessible under the organization content-exclusion policy. - Workspace Poe fan-out remains blocked by the pre-existing missing packages/durabletask/pyproject.toml; equivalent package-local checks passed. * Align AG-UI approval resumes with protocol * Align workflow approvals with AG-UI resumes * Address AG-UI approval review findings * fix AG-UI test typing checks * fix AG-UI approval retention and cancellation retries |
||
|
|
5fafa18569 | Python: track agent-hooks feature usage (#7558) | ||
|
|
ee27065359 |
Python: Update agentserver to x.1.0b1 (#7621)
* Update agentserver to 2.1.0 * Update agentserver responses and invocations to x.1.0b1 * Pass platform context to state store provider * Pass user id * Correct requirements.txt * Fix unit tests * Fix unit tests |
||
|
|
9645d33cde |
Python: Fix Cosmos memory provider calling renamed add_cosmos toolkit API (#7635)
* Python: Fix Cosmos memory provider calling renamed add_cosmos toolkit API The Agent Memory Toolkit renamed AsyncCosmosMemoryClient.add_cosmos to upsert_memory with an identical signature. The provider declares azure-cosmos-agent-memory>=0.2.0b3 with no upper bound, so a resolved install can expose either name. after_run swallows write errors and only logs a warning, so on a post-rename toolkit the agent turn still looks successful while long-term memory silently stops receiving turns. Resolve the write method once per after_run, preferring upsert_memory and falling back to add_cosmos, so both ends of the declared range keep working. Same treatment for the emulator test's direct seed call. Fixes #7633 * Ponytail comment erased Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Clarify TODO comment regarding memory method rename Updated TODO comment to include author and clarify context , to resolve linting error --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
9a06fa3f42 |
Python: fix(python): add release_session API to prevent BackgroundAgentsProvider memory leaks (#7450)
* fix: add release_session API to prevent BackgroundAgentsProvider memory leaks * fix: address Copilot review comments on release_session * fix(harness): make background agent session release race-safe and bounded * fix (harness): address release_session and review feedback |
||
|
|
e926ad2859 |
Python: fix streaming transcript duplication with message injection and per-service-call persistence (#7605)
* Fix ordering issue when streaming with content injection and per-service-call persistence * Update spec * Address PR comment * revert uv.lock changes |
||
|
|
7cfa905486 |
Python: scope under-specified approve-for-session permission decisions (#7607)
* Python: scope under-specified approve-for-session permission decisions
PermissionDecisionApproveForSession carries an optional `approval` (tool
prompts) and an optional `domain` (URL prompts), so it can be constructed
with neither. A bare PermissionDecisionApproveForSession() serializes to
{"kind": "approve-for-session"}, which the Copilot CLI cannot interpret: it
dereferences the absent approval and crashes the CLI process with "Cannot
read properties of undefined (reading 'commandIdentifiers')", taking the
whole run down rather than failing a single tool call.
Wrap the resolved permission handler so such decisions are scoped using the
request that triggered them: shell prompts become an approval for that
prompt's command identifiers, MCP prompts an approval for that server and
tool, URL prompts an approval for that URL's domain, and so on.
The decision is only ever narrowed, never widened. When the prompt reports
can_offer_session_approval=False, or the request kind has no session-scoped
approval (such as a hook prompt), the decision is downgraded to a single-use
approval and a warning is logged. Decisions that already specify a scope are
forwarded unchanged, and handler exceptions still propagate so the SDK's
deny-on-error behavior is preserved.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1b45752e-b602-4117-8304-3c8a8b877e3e
* Fix test-suite type-checker errors for permission-decision normalizer
The permission-handler wrapper returned PermissionHandlerType (the sync-or-async
union), so awaiting its result in tests was rejected by the stricter CI type
checkers (pyrefly, ty, zuban). Give the wrapper a dedicated
AsyncPermissionHandlerType return type, and narrow the awaited result with an
isinstance assert before accessing its scope in the async-handler test.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1b45752e-b602-4117-8304-3c8a8b877e3e
* Add regression tests for extension permission approval normalization
Cover the two previously-untested branches of _derive_session_approval:
extension-management preserves the request operation, and
extension-permission-access preserves the extension name. Both assert the
serialized approval payload as well.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1b45752e-b602-4117-8304-3c8a8b877e3e
* Scope URL session approvals only for parser-unambiguous URLs
The URL branch derived the persisted domain with Python's urlparse, but the
Copilot CLI parses URLs with WHATWG semantics. The two disagree on crafted
authorities -- e.g. a backslash before the '@' in
'https://example.com<backslash>@evil.com' resolves to example.com under the CLI
but evil.com under urlparse -- so trusting urlparse could persist a session-wide
approval for an unrelated, attacker-chosen domain, widening authorization.
Add _derive_url_session_domain, which returns a domain only when the URL
contains none of the characters WHATWG and urlparse handle differently
(backslash, tab, newline, carriage return); any ambiguity (or a URL with no
host) narrows the decision to a single-use PermissionDecisionApproveOnce.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1b45752e-b602-4117-8304-3c8a8b877e3e
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1b45752e-b602-4117-8304-3c8a8b877e3e
|
||
|
|
3221011427 | fix(core): warn when advertised MCP archives are rejected (#7622) | ||
|
|
3aadac53c8 |
Python: fix(redis): honour a max_messages retention limit of zero (#7470)
* Python: fix(redis): honour a max_messages retention limit of zero RedisHistoryProvider documents None as the sentinel for unlimited storage, so max_messages=0 must retain nothing. It retained everything: trimming to -max_messages emits LTRIM key 0 -1, which is Redis's "keep the whole list", and the count > max_messages guard is true for any non-empty list, so the trim ran on every save and did nothing. Negative values were worse than a no-op. max_messages=-5 emitted LTRIM key 5 -1, deleting the five oldest messages on every save while the list still grew without bound. Handle a limit of zero by deleting the key, which is what clear() in this class already does, and reject negative values in __init__ alongside the three ValueErrors it already raises for invalid configuration. None and positive limits are unchanged. * Python: never write the payload when Redis retention is disabled Addresses the automated review on #7470. With max_messages=0 the previous change still RPUSHed every message and deleted the key afterwards, so the payload reached Redis - and any AOF or replica stream - before being removed, and was briefly visible to other readers. Short-circuit instead: drop any existing history and return before serializing, so nothing is written at all. Also documents the new ValueError in the Raises: section, and asserts in the test that the pipeline is never used. * Python: leave stored history alone when Redis retention is disabled max_messages=0 deleted the session key. _redis_key omits source_id, so two providers with the default prefix share {key_prefix}:{session_id}, and the after-run pass persists in reverse provider order - a zero-retention provider listed first would drop a co-located provider's just-written history on every turn. Return before serializing instead: no payload reaches Redis, an AOF or a replica, and stored history is left as it is. Removing stored history is what clear() is for. --------- Co-authored-by: Chinmay V <203952148+chinmayv095@users.noreply.github.com> |
||
|
|
35c6b880f7 |
Python: Preserve Mistral prompt-cache usage details (#7597)
* Fix Mistral cached token usage Map prompt cache hits from Mistral chat usage into the standard usage details. Add regression coverage for regular and streaming responses. * Validate Mistral cached token usage * fix(mistral): satisfy strict cached token typing Narrow prompt token details before reading cached_tokens so the Mistral package passes strict Pyright without changing runtime validation.\n\nAddresses https://github.com/microsoft/agent-framework/pull/7597#discussion_r3750712320 |
||
|
|
3a5d00be54 |
Python: add checkpointing support to AgentFrameworkWorkflow.run() in agent-framework-ag-ui (#6646)
* Python: add checkpointing support to AgentFrameworkWorkflow.run() in ag-ui The ag-ui AgentFrameworkWorkflow.run() previously accepted only a RunAgentInput payload and exposed no way to use the core workflow's checkpointing/state-persistence, unlike the core agent-framework workflow implementations. This left ag-ui workflows without resumable execution. Add optional checkpoint_storage and checkpoint_id keyword arguments to run(), threaded through run_workflow_stream() into the core Workflow.run(). This delegates to the existing core capability instead of reinventing it and keeps the public surface consistent with Workflow.run(): - checkpoint_storage enables checkpoint creation at each superstep boundary. - checkpoint_id resumes a run from a persisted checkpoint; incoming messages are forwarded only as request-info responses (never as a new start-executor message) to honor the core's message/checkpoint_id mutual exclusivity, and responses + checkpoint_id performs a restore-then-send in one call. Both can also be supplied via the input_data keys __ag_ui_checkpoint_storage and __ag_ui_checkpoint_id so the FastAPI endpoint (which calls run(input_data) positionally) can opt in without changing its call site; explicit keyword arguments take precedence. Checkpoint resume bypasses the AG-UI thread snapshot hydration early-returns so it always reaches the core restore path. Backward compatible: run(input_data) keeps working unchanged, and the non-checkpoint path still calls run_workflow_stream(input_data, workflow) with its original two-argument convention. Adds focused tests covering checkpoint creation, resume-from-checkpoint, input-data-keyed params, and the unchanged default path. Fixes #6632. * Import Executor from the public agent_framework API in ag-ui workflow test * Fix ag-ui checkpoint resume: preserve thread snapshot, coerce resume responses; fix CI lint/typing A checkpoint-only resume no longer clobbers the stored AG-UI thread snapshot: the snapshot builder is seeded with the prior stored history so the saved snapshot keeps the earlier replayable transcript plus the newly produced output. Resume responses are now coerced against the post-restore pending requests on a checkpoint restore, so a JSON function_approval_response resumes through AG-UI after a cold restore instead of failing with a response-type mismatch. Also update the test-double workflow run() overrides to match the new keyword-only parent signature and re-sort the workflow test imports so ruff and the typing checkers pass. * Coerce ag-ui resume responses without a second checkpoint restore Reading pending request_info events for resume-response coercion previously restored the checkpoint into the live workflow, which invoked every executor's on_checkpoint_restore hook. workflow.run(checkpoint_id=...) then restored again, running those hooks a second time. Custom restore hooks are not required to be idempotent, so this could duplicate restoration work or break workflows that expect exactly one restore per resume. Load the persisted WorkflowCheckpoint directly from storage (runtime override or the workflow's build-time context storage) and read its pending_request_info_events instead. This exposes the same post-restore pending set for the resume contract and response coercion without mutating workflow state or running any restore hook, leaving workflow.run(checkpoint_id=...) as the single restore per resume. Add a regression test asserting on_checkpoint_restore runs exactly once on a checkpointed ag-ui resume. * Python: rework AG-UI workflow checkpointing onto public configuration surfaces Checkpoint storage is now configured on AgentFrameworkWorkflow (or the FastAPI endpoint) instead of being smuggled through input_data keys, and a run resumes by supplying its checkpoint id in the AG-UI forwarded props. With storage always in hand, resume-response coercion reads the pending request set straight from the persisted checkpoint via the public CheckpointStorage.load(), replacing the private runner-context fallback, and the core run call forwards checkpoint arguments directly, relying on core validation for conflicting parameters. Requesting a resume without configured storage now fails with a clear error. * Assign endpoint checkpoint storage in a single place The raw-workflow branch assigned checkpoint_storage at construction and the wiring block assigned it again. Construct the wrapper bare and let the wiring block own the assignment; the existing-storage guard keeps allowing a pre-wrapped runner without storage to adopt the endpoint's. --------- Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com> Co-authored-by: Evan Mattson <evan.mattson@microsoft.com> |
||
|
|
5e52c6a718 |
Python: Fix ClaudeAgent reusing one SDK client across distinct fresh sessions (#7404)
* Python: Fix ClaudeAgent reusing one SDK client across distinct fresh sessions RawClaudeAgent kept a single mutable ClaudeSDKClient on the agent instance and reused it across distinct fresh AgentSession objects, because a fresh session passes session_id=None and the old reuse check treated that as "keep the current client". Two independent fresh sessions on one shared agent instance therefore shared a single provider conversation, so the second session continued the first session's conversation. Treat a fresh (None) continuation id as always requiring a new client, so an unbound session never inherits an existing provider conversation. Legitimate continuity is preserved: once a session runs, its service_session_id is written back, so later runs pass a real id and resume correctly. Guard client selection/creation with an asyncio.Lock so concurrent runs cannot race between the check and the client assignment. Add regression tests asserting two fresh sessions produce two clients and that an explicit continuation id still resumes the existing client. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 598a9fe1-28c5-4db1-88fd-e14acd9340af * Python: Bind Claude SDK client ownership to each run Replace the single mutable ClaudeSDKClient stored on the agent with a per-run client. Because a ClaudeSDKClient represents exactly one provider conversation, sharing one across distinct sessions collapsed them onto the same conversation and, for concurrent runs, let a fresh session disconnect a client another run was still streaming from. _acquire_client now returns a per-run client (owned) that resumes the framework session's provider conversation when one exists, and _get_stream releases it in a finally once the run completes. An injected client is reused verbatim and left to the caller. The streaming loop moves into _stream_run so the client is a local per-run value rather than shared agent state, which keeps distinct sessions isolated even under concurrency. Continuity is preserved: a session's service_session_id is written back after each run and forwarded as the resume id on subsequent runs. Replace the client-lifecycle tests with per-run ownership and end-to-end isolation tests (two fresh sessions get two separate clients, each disconnected). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 598a9fe1-28c5-4db1-88fd-e14acd9340af * Python: Close remaining Claude session-isolation gaps Address three shared-state gaps in the Claude adapter surfaced in review: - Run-scope structured output: carry the run's structured_output through a per-run state holder and a per-run finalizer instead of storing it on the agent, so a concurrent run cannot overwrite another run's value before its finalizer reads it. - Bind an injected client to one session: an injected ClaudeSDKClient is a single Claude conversation, so bind it to the first session that uses it and raise AgentInvalidRequestException if a different session tries to reuse it. A no-session run reuses the bound session so multi-turn continuity still works; multi-session callers must omit client= or use one agent per session. - Serialize the injected-client path with an asyncio.Lock so concurrent runs cannot race its connect or interleave queries on the one shared client. Owned per-run clients stay lock-free. Update and extend the tests accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 598a9fe1-28c5-4db1-88fd-e14acd9340af * Python: Bind injected Claude client on provider conversation identity Compare an injected client's binding on the session's service_session_id (the Claude conversation identity) rather than the framework-local session_id, falling back to session_id only when the incoming session has no provider id yet. A reconstructed session from get_session(service_session_id=...) carries a fresh session_id but the same provider conversation, so it now continues the bound conversation instead of raising. Sessions targeting a different conversation are still rejected. Add regression tests for reconstructed-same-conversation continuation and different-conversation rejection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 598a9fe1-28c5-4db1-88fd-e14acd9340af --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 598a9fe1-28c5-4db1-88fd-e14acd9340af |
||
|
|
30996433ac |
Python: Restore Gemini thought_signature on approval replays (#7546)
Gemini 3.x rejects a request whose functionCall parts lack a thought_signature. The signature was carried as base64 protected_data on a text_reasoning content and re-attached by adjacency, which requires the carrier to immediately precede its call. An approval round trip replays the call with no carrier at all, so the next turn failed with a 400. Track signatures in a bounded per-client call_id map populated at parse time from the resolved call_id, and backfill only when the emitted part has no signature. Also stop clearing the held signature on contents that emit no Part, so an approval response or an unsigned thought summary between the carrier and its call no longer drops it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: dd0909cd-c7c3-42cb-aef1-1e9a3e64d917 |
||
|
|
e85b3c8ba8 |
Python: Fix FHA session ID translation (#7608)
* Fix FHA session ID traslation * Fix tests * Address comments and fix tests * Fix typing * Show how to use user created sessions * Update README |
||
|
|
db979b616a |
Python: Improve Json parsing for declarative workflow (#7550)
* Json parsing improvement * Fix PR comments * Address PR comments. |
||
|
|
d0a4165f17 |
[BREAKING] Python: Migrate FHA to responses==2.0.0b1 and add Foundry state store (#7533)
* Migrate FHA to responses==2.0.0b1 and add Foundry state store * Fix session id error * Fix tests * Improve tests * Fix copilot comments * Address comments * Revert sample changes * Address comments * Add ContextScopedStoreProvider * Fix type check * Fix type check * Export ContextScopedStoreProvider |