Part of the v0.58.7 → HEAD TinyAgents-migration audit (see parent issue). The tinyagents crate runs after_tool hooks in reverse registration order (tinyagents-1.3.0/src/harness/middleware/mod.rs:318-326, .iter().rev()); two of our registrations assume the opposite, with comments asserting parity the code doesn't deliver.
A. Progressive-disclosure handoff is dead code
TurnContextMiddleware::install (src/openhuman/tinyagents/middleware.rs:283-300) registers HandoffMiddleware before ToolOutputMiddleware, with a comment asserting handoff runs first. Reverse order means the 16 KiB output budget truncates first; a capped payload (~4k tokens) can never cross the 50k-token handoff threshold (subagent_runner/handoff.rs:38). The entire ResultHandoffCache/extract_from_result machinery (ops/runner.rs:604-680, ops/graph.rs:256-262) is unreachable — integrations_agent's oversized Composio payloads are hard-truncated with nothing to drill into (legacy tool_source.rs stashed the raw result).
B. ToolOutcomeCaptureMiddleware sees pre-cap content
It's pushed after context_mw.install (src/openhuman/tinyagents/mod.rs:1371), so its after_tool runs before summarization/tokenjuice/caps — despite its doc "Runs last… records the final (summarized/capped) content" (middleware.rs:1375-1376). Effect: the sink holds the full raw output of every tool call in memory for the whole turn (multi-MB), and failure classification / ToolCallRecord.output_summary see pre-cap content. (MemoryProtocolMiddleware is already pushed first for exactly this reason — the pattern exists.)
Fix plan
- Flip the registration order in
TurnContextMiddleware::install so effective after_tool order is: handoff (sees raw) → summarizer/tokenjuice/caps → capture (sees final). Fix the comments to state the crate's reverse-order rule explicitly.
- Move the
ToolOutcomeCaptureMiddleware push before context_mw.install in assemble_turn_harness.
- Add a seam unit test that registers sentinel middlewares and asserts the effective execution order — so a future crate change or refactor can't silently invert it again.
- e2e: oversized scripted tool result → assert the model-visible message carries the handoff pointer and the drill-down tool can retrieve the stashed payload.
Acceptance criteria
- A >50k-token tool result produces a handoff pointer, not a blind truncation; the cache is populated.
ToolCallOutcome/failure classification record post-cap content; memory held per call is bounded.
- Order-assertion test in place.
Part of the v0.58.7 → HEAD TinyAgents-migration audit (see parent issue). The tinyagents crate runs
after_toolhooks in reverse registration order (tinyagents-1.3.0/src/harness/middleware/mod.rs:318-326,.iter().rev()); two of our registrations assume the opposite, with comments asserting parity the code doesn't deliver.A. Progressive-disclosure handoff is dead code
TurnContextMiddleware::install(src/openhuman/tinyagents/middleware.rs:283-300) registersHandoffMiddlewarebeforeToolOutputMiddleware, with a comment asserting handoff runs first. Reverse order means the 16 KiB output budget truncates first; a capped payload (~4k tokens) can never cross the 50k-token handoff threshold (subagent_runner/handoff.rs:38). The entireResultHandoffCache/extract_from_resultmachinery (ops/runner.rs:604-680,ops/graph.rs:256-262) is unreachable — integrations_agent's oversized Composio payloads are hard-truncated with nothing to drill into (legacytool_source.rsstashed the raw result).B.
ToolOutcomeCaptureMiddlewaresees pre-cap contentIt's pushed after
context_mw.install(src/openhuman/tinyagents/mod.rs:1371), so itsafter_toolruns before summarization/tokenjuice/caps — despite its doc "Runs last… records the final (summarized/capped) content" (middleware.rs:1375-1376). Effect: the sink holds the full raw output of every tool call in memory for the whole turn (multi-MB), and failure classification /ToolCallRecord.output_summarysee pre-cap content. (MemoryProtocolMiddlewareis already pushed first for exactly this reason — the pattern exists.)Fix plan
TurnContextMiddleware::installso effectiveafter_toolorder is: handoff (sees raw) → summarizer/tokenjuice/caps → capture (sees final). Fix the comments to state the crate's reverse-order rule explicitly.ToolOutcomeCaptureMiddlewarepush beforecontext_mw.installinassemble_turn_harness.Acceptance criteria
ToolCallOutcome/failure classification record post-cap content; memory held per call is bounded.