Stabilize the v1.11.4 Tool execution contract - #959
Merged
Y1fe1Zh0u merged 9 commits intoAug 14, 2026
Conversation
Gemini reuses provider call identifiers across assistant turns, so a history-wide lookup allowed later calls to overwrite earlier tool names. Scope name resolution to the active assistant exchange while preserving provider wire identifiers. Constraint: Gemini provider call IDs are not globally unique across turns Rejected: Persist globally unique provider IDs | would alter provider wire identity and conflict with existing Runtime correlation Confidence: high Scope-risk: narrow Directive: Keep Tool Result name resolution exchange-local when modifying Gemini history lowering Tested: backend/tests/test_llm_single_step.py; LLM scoped tests; Ruff Not-tested: Live Gemini API
Synthetic poll calls belong to the original accepted Tool call but use a new runtime call ID. Record the origin call ID on the synthetic Assistant message and derive the poll execution entry from the frozen StepToolContext without replacing checkpoint state. Constraint: Keep the fix local to the reproduced async poll context mismatch. Rejected: Add a separate async lifecycle state machine | unnecessary for preserving the accepted Tool contract. Confidence: high Scope-risk: narrow Directive: Do not resolve the ToolProvider again for a poll generated from an accepted Tool call. Tested: 130 scoped Runtime Tool, node executor, LLM, and runtime schema tests; scoped Ruff; git diff --check. Not-tested: Real MCP provider and process-restart end-to-end execution.
Runtime Tool results already retain sanitized failure summaries and optional remediation, but the model boundary discarded the failure signal and remediation text. Carry one provider-neutral error bit, render actionable failure text, and map it to native Anthropic and Gemini representations. Constraint: Keep Runtime control fields such as model_action and side_effect_state out of the model protocol. Rejected: Serialize the complete internal Tool outcome | couples provider prompts to Runtime control metadata. Confidence: high Scope-risk: narrow Directive: Expected Tool failures should provide sanitized result_summary and safe_remediation at their source. Tested: 151 scoped model-step, provider-boundary, and Tool-step tests; scoped Ruff; git diff --check. Not-tested: Live Anthropic, Gemini, and OpenAI provider calls.
A model-visible MCP definition now carries a secret-free execution binding into the durable Tool context. The Tool step dispatches through that binding, resolves the exact assignment, and rejects route changes instead of re-selecting an endpoint by name. Readiness and binding creation share one database query, while provider payloads remain standard Tool schemas. Constraint: Live authorization, enablement, and credential values must still be checked at execution time. Rejected: Freeze decrypted credentials in the checkpoint | would persist secrets and prevent revocation or rotation. Rejected: Refactor the complete Tool registry | unnecessary for closing the execution-route correctness gap. Confidence: high Scope-risk: moderate Directive: Do not send _runtime_binding to model providers or replace exact assignment checks with name lookup. Tested: 969 Tool, Model Step, and agent_tools pytest cases; scoped Ruff; py_compile; git diff --check. Not-tested: Live MCP provider call and production database process restart.
The Runtime validator now enforces the JSON Schema keywords already used by production Tool definitions, so arguments rejected by the advertised contract cannot reach a handler. Failures remain bounded, value-free, and use the existing repairable Tool result path. Constraint: No new dependency and no attempt to implement the entire JSON Schema specification. Rejected: Add a general JSON Schema package | broader dependency and behavior change than required by the current Tool catalog. Confidence: high Scope-risk: moderate Directive: Add validator support when introducing a new schema keyword; unsupported schema contracts must not silently pass. Tested: 118 Runtime Tool validation, Tool Step, and builtin contract tests; scoped Ruff; git diff --check. Not-tested: Property-based comparison against a complete JSON Schema implementation.
Network reads and image generation now carry deadline policies that cover their declared provider timeout. Custom image generation retains its existing 600 second configurable upper bound instead of being cancelled by the generic Runtime default. Constraint: Provider-specific internal timeouts may remain shorter, but the Runtime wrapper must not expire first. Rejected: Read live Tool configuration inside the Tool Step deadline resolver | would reintroduce mutable routing policy after call acceptance. Confidence: high Scope-risk: narrow Directive: Keep builtin timeout declarations and Runtime deadline policy tests aligned when changing provider budgets. Tested: 171 Tool contract, Model Step, Tool Step, and builtin contract tests; scoped Ruff; git diff --check. Not-tested: Wall-clock calls to web and image providers.
Legacy checkpoints now return the reconstructed StepToolContext from every ordinary wait, unknown, A2A, group failure, and error exit. A resumed Tool node therefore reuses the accepted Workset instead of querying the current ToolProvider again. Constraint: Async poll continuation remains owned by the dedicated async-context repair. Rejected: Mutate graph state directly inside ToolStepService | would bypass the existing ToolStepResult checkpoint boundary. Confidence: high Scope-risk: narrow Directive: Any new ToolStep early return after legacy context resolution must propagate step_tool_context. Tested: 68 Tool Step tests plus targeted legacy unknown and A2A resume regressions; scoped Ruff; git diff --check. Not-tested: Production checkpoint database restart and legacy approval fixture outside current canonical schemas.
Unknown dynamic MCP receipts now use the existing audited Direct Chat reconciliation flow. A user must confirm whether the external action happened before the old receipt is settled and the Run may resume; the Runtime never replays the original MCP call automatically. Constraint: Dynamic MCP Tools are conservatively classified external_write with retry policy never. Rejected: Automatically retry an unknown MCP call | could duplicate an external side effect. Rejected: Add a separate MCP reconciler service | unnecessary while explicit human confirmation provides a real recovery outlet. Confidence: high Scope-risk: narrow Directive: Do not make unknown MCP receipts retryable without an explicit idempotency contract. Tested: 47 Tool ledger and Direct Chat runtime-state tests; 17 targeted unknown/reconciliation tests; scoped Ruff; git diff --check. Not-tested: Browser UI interaction and a live MCP server with an ambiguous transport outcome.
The integrated Tool fixes expose two stale assertions in the release test suite: network reads now use the declared 60-second Runtime budget, and the durable execution model already includes provider identity and contract version columns. Align those assertions and remove a duplicate import so the combined release branch can be verified as one unit. Constraint: Preserve the eight reviewed fix commits without folding or rewriting their history Rejected: Ignore the full-suite failures | they would leave the integration PR without a clean release-level regression result Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep deadline and schema assertions synchronized with the production Tool contract Tested: Full backend suite, 2357 passed; scoped Ruff excluding pre-existing agent_tools.py debt; git diff --check Not-tested: Live external MCP provider execution
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Original findings covered
Validation
Boundaries
Integration
This release PR combines the focused work from #952, #953, #954, #955, #956, #957, and #958 on top of v1.11.4.