Skip to content

feat(tools)!: preserve typed failure facts through task delivery - #22

Open
danielkov wants to merge 5 commits into
mainfrom
feat/typed-tool-failures
Open

feat(tools)!: preserve typed failure facts through task delivery#22
danielkov wants to merge 5 commits into
mainfrom
feat/typed-tool-failures

Conversation

@danielkov

@danielkov danielkov commented Sep 5, 2026

Copy link
Copy Markdown
Owner

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: ToolError gains a boxed Diagnostic variant, tool contexts and task snapshots gain observation fields, TurnTaskUpdate::Detached boxes its snapshot, and LoopDriver::cancel_pending_approval_for becomes async so callers await terminal ownership. Legacy ToolError wire 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 fail remains 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 locked getrandom 0.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.

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
danielkov changed the base branch from feat/responses-retry-observability to main September 5, 2026 20:40
@danielkov
danielkov force-pushed the feat/typed-tool-failures branch from c0252df to eb42a95 Compare September 5, 2026 20:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant