feat(tools)!: preserve typed failure facts through task delivery - #22
Open
danielkov wants to merge 5 commits into
Open
feat(tools)!: preserve typed failure facts through task delivery#22danielkov wants to merge 5 commits into
danielkov wants to merge 5 commits into
Conversation
Add bounded diagnostics and task-scoped frozen observations, authenticate native Runlet error restoration, and preserve selected outcomes across cancellation and approval continuations. BREAKING CHANGE: ToolError adds Diagnostic; tool contexts and task snapshots add observation fields; TurnTaskUpdate::Detached now boxes its snapshot. Legacy ToolError serde remains readable.
Keep originating session/task identity on queued updates; preserve unsurfaced background delivery; transfer frozen individual approval outcomes and prior cancellation winners. Update expected typed failure projections in integration recordings. BREAKING CHANGE: LoopDriver::cancel_pending_approval_for is async. Retained task-manager wrappers must delegate close_suspended_task.
danielkov
changed the base branch from
feat/responses-retry-observability
to
main
September 5, 2026 20:40
danielkov
force-pushed
the
feat/typed-tool-failures
branch
from
September 5, 2026 20:40
c0252df to
eb42a95
Compare
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
Preserve true failed and cancelled tool outcomes with bounded, typed retry, receipt, and possible-effects facts through Compose, task-manager projections, and LoopDriver delivery. Keep native child diagnostics separate from task-owned observations, including cancellation races and approval continuations.
Motivation
Stringified errors lose actionable failure identity, while error-shaped successful values misclassify execution. Cancellation can also discard facts already observed or replace an already-selected result with a synthetic cancellation.
Impact
This is a breaking Rust API change:
ToolErrorgains a boxedDiagnosticvariant, tool contexts and task snapshots gain observation fields,TurnTaskUpdate::Detachedboxes its snapshot, andLoopDriver::cancel_pending_approval_forbecomes async so callers await terminal ownership. LegacyToolErrorwire variants retain their previous shapes and remain readable; retry values move to neutral core with the existing loop reexports preserved.This provides transport and producer APIs; effects interpretation, host producer integration, and crate release remain separate.
Technical details
Closed diagnostic data
A versioned, finite envelope carries typed retry accounting, bounded host receipt IDs, and conservative effects observations. Strict readers reject malformed or unknown diagnostic data with sanitized errors. Diagnostics contain no raw provider messages, paths, recursive causes, or arbitrary JSON.
Native Compose failures
Runlet catch details include an advisory projection and a per-run random capability. Explicit rethrow restores the saved native error only when token, code, and message match; two-argument
failremains a new generic failure. The bounded registry fails closed on entropy, collision, capacity, or numeric-representation failure, and cannot be caught into success. The existing lockedgetrandom0.4.3 package is pinned with no default features and enabled only for Runlet. Lua preserves native external-error identity.Terminal ownership and observations
Task-owned publishers freeze when a terminal outcome wins. Approval suspension retains logical-call identity and frozen facts, while an approved continuation gets a fresh publisher and still permits host-approved input patches. Registration and terminal event enqueue avoid cancellation/drop gaps. Queued updates retain originating session/task identity; interruption drains only selected session/call updates and preserves background delivery policy. Individual approval closure terminalizes the retained task and transfers its selected result directly, including a cancellation that won before denial or approval. Approved-start failure transfers an existing terminal winner before synthesizing an error. Success, native failure, and cancellation retain their actual selected outcome.