24 KiB
TinyAgents Migration — Continuation Plan (2026-07-03)
Status: supersedes the ordering in README.md for remaining work. Written
after a ground-truth audit of main (post-#4249), a re-inventory of the
TinyAgents crate (1.4.0 published, 1.5.0 tagged), and a critical
re-evaluation of the 99-deletion-ledger.md "Never delete" list.
1. Where we actually are (ground truth, main @ 2026-07-03)
The "finish TinyAgents harness migration" PR (#4249 → #4399) has landed. Per-workstream state:
| Workstream | State |
|---|---|
| 00 baseline | Done (1.3.0 + sqlite, rusqlite 0.40) — needs re-bump to 1.4/1.5 |
| 01 tooling | Mostly done. Live: crate-internal tool side-lookup (01.1), tool_filter.rs 299 + tool_prep.rs 344 (01.3) |
| 02 models | Mostly done. Live: reliable.rs 900 (gated on re-architecture), ThinkingForwarder residual seams |
| 03 context/cache | Done. context/ is 1.3k of product prompt/stats state |
| 04 sessions | Primary unfinished work. Live path is 100% legacy: transcript.rs 1347, migration.rs 373, session_io.rs 463, session_db/ 4.5k, subagent_sessions/ 653, session_import/ 1.9k. Crate Store/AppendStore used only by the write-only importer. 04.3 checkpointer swap IS done in code (tinyagents/checkpoint.rs deleted) — the 04.3 doc text is stale |
| 05 events | 05.2 engine deletion done. progress_tracing (817 + 477 langfuse + 719 tests) still the live web-progress exporter; journal projection not at parity |
| 06 cost | Not wired: no BudgetMiddleware/BudgetLimits/RunTree in the shared runner. Blocker: UsageRecorded de-duplication |
| 07 subagents | Diagnostic-skeleton graph only; procedural runner still live. running_subagents.rs has grown to 1931 lines (target ≤300); JsonlTaskStore adopted for detached lifecycle records; run_queue/ + spawn_depth_context.rs still live |
| 08 orchestration | 08.1/08.2/08.4 done. Live: 08.3 durable interrupts for approvals, 08.5 worktree_context.rs fallback thread |
| 09 embeddings | Done |
| 10 registry | Pending — CapabilityRegistry unused in src/ |
| 11 testing | Conformance pass green on 2026-07-02 baseline |
Crate APIs available but unused in src/: JsonlTaskStore (now partially
adopted), BudgetMiddleware, ContextualToolSelectionMiddleware (only its
shadow), UnknownToolPolicy, CapabilityRegistry.
2. Crate delta: 1.4.0 / 1.5.0 (the upgrade this plan targets)
- 1.4.0 (published 2026-07-02)
graph::goals— durable per-threadThreadGoal: completion contract, token budget, Active/Paused/BudgetLimited/Complete,goal_gate_nodeself-driving loop,run_continuation_tick,note_user_turn, model toolsgoal_get/goal_set/goal_complete, hostgoal_pause/resume/clear. Persists on harnessStorensgraph.goals.graph::todos—TaskBoardkanban (Todo→Ready→InProgress→Done, Blocked, AwaitingApproval), single-InProgressinvariant,claim_cardCAS, single multiplexerTodoTool. Persists nsgraph.todos.- Graph resilience:
CompiledGraph::with_node_retry(RetryPolicy), opt-in backoff sleeping, failure-boundary checkpoints +CompiledGraph::retry(thread)resumable failures,GraphEvent::NodeRetryScheduled.
- 1.5.0 (tagged 2026-07-03, not yet on crates.io)
harness::no_progress::NoProgressTracker— extracted from OpenHuman PR #4389. Pure state machine:record(step, &ToolAttempt) -> Continue/Nudge/Halt; identical-failure ladder, varied-failure backstop, fast-trip on hard policy rejects.
- Known crate limitation relevant here:
Storehas no compare-and-set, so goals/todos mutations must funnel through one process (fine — the core is the single writer).
3. Re-evaluated component verdicts (revises 99-deletion-ledger.md)
The old "Never delete" list over-protects. Revised verdicts, ordered by reclaimable lines (non-test; tests roughly double each figure):
Migrate to crate, then delete locally (upstream-extraction candidates)
Precedent: NoProgressTracker was extracted upstream from #4389 and shipped
in 1.5.0. Same play for:
| Component | Lines (~generic) | Notes |
|---|---|---|
pformat.rs + dispatcher.rs + harness/parse.rs |
1941 (~1900) | Tool-call dialect machinery (P-format encoder, permissive XML/JSON parser with key-drift recovery). Zero DomainEvent coupling. Delete gate: 04.2 read-cutover (no live path parses provider text) |
multimodal.rs |
1690 (~1550) | [IMAGE:]/[FILE:] marker → provider content blocks, mime allowlist, PDF extraction, fetch gating, truncation budget. Only the marker convention is product |
progress_tracing.rs + langfuse.rs |
1294 (~1200) | Crate already ships Langfuse exporters + journals. Delete gate: 05.3 journal-backed web-progress parity |
tool_result_artifacts/ |
588 (~500) | Already built on crate Store; overflow-to-artifact is a generic harness concern. Product residue: PII scrub hook |
hooks.rs + stop_hooks.rs trait machinery |
543 (~450) | PostTurnHook/StopHook traits are pure harness; product hook bodies stay |
host_runtime.rs adapter core |
456 (~350) | Native/Docker RuntimeAdapter overlaps crate workspace isolation |
ArgRecoveryMiddleware, RepeatedToolFailureMiddleware core |
~300 | Latter becomes a thin driver over crate NoProgressTracker (1.5.0) |
tool_filter.rs fuzzy ranker |
299 (~250) | Generic ranking; Composio input types stay product |
triage/ evaluator+routing+decision core |
~800 of 3779 | Generic "LLM triage node" (tiered fallback, cache, verdict parse). envelope.rs/escalation.rs/events.rs stay product (Composio, DomainEvents, agent ids) |
Replace with crate features, then delete (no upstreaming needed)
| Component | Lines | Replaced by |
|---|---|---|
thread_goals/ |
2185 | graph::goals (1.4.0). OpenHuman keeps RPC schemas + UI projection over the crate store |
agent/task_board.rs + tools/todo.rs mechanics |
604 + ~430 | graph::todos TaskBoard + TodoTool (1.4.0). RPC shapes (threads.task_board_*, openhuman.todos_*) become projections |
task_dispatcher/ executor mechanics |
~450 of 1494 | claim_card CAS + graph runner node; DomainEvent emission + channel bindings stay |
6 duplicate middlewares in tinyagents/middleware.rs (2448 total): OpenHumanToolExposureShadow, CacheAlign, Microcompact, CostBudget, PromptCacheSegment (partial), ToolPolicyMiddleware (local) |
~900 | Crate ContextualToolSelectionMiddleware, cache guard, compaction, BudgetMiddleware, ToolAllowlistMiddleware. All are self-acknowledged shadows/parity holds |
spawn_depth_context.rs |
92 | Crate RecursionPolicy/RecursionStack |
| legacy session stack (04.2 phase 4) | ~9000 incl. tests | Crate Store/AppendStore/StoreChatHistory |
Confirmed product — keep (ledger was right)
archivist/ (memory/learning policy — only the hook-scheduling shell ~200
lines is generic), bus.rs, schemas.rs, error.rs, turn_origin.rs,
memory_context.rs, debug/, library/, progress.rs event vocabulary,
prompts content (the section/render machinery ~600 lines is generic but
decoupling is low-value), preference/run_workflow/delegate_to_personality
tools, approval/MemoryProtocol/CliRpcOnly/ToolOutcomeCapture
middlewares.
Cross-cutting gate for the coupled middle tier (session turn/builder, triage escalation, task dispatch): DomainEvent subscribers and JSON-RPC shapes — these must become projections before their hosts can shrink.
Coverage sweep: harness files previously unreferenced by any plan doc (2026-07-03)
A basename grep of agent/harness/** against this plan folder found these
non-test files with no verdict anywhere. Assigned now (tests follow parents):
| File | Lines | Verdict |
|---|---|---|
subagent_runner/extract_tool.rs |
612 | [migrate/delete] — generic progressive-disclosure Q&A over handoff-cached payloads; pairs with handoff.rs. Goes with the C5 overflow-to-artifact/handoff extraction |
subagent_runner/handoff.rs |
287 | [migrate/delete] — generic oversized-result handoff cache (crate tool-output/artifact overlap). C5 |
subagent_runner/types.rs |
232 | [shrink] — spawn options/outcome/error taxonomy largely maps to crate SubAgentPolicy/OrchestrationTaskKind. C6 |
subagent_runner/autonomous.rs |
29 | [keep] — approval-gating override policy for unattended skill runs |
fork_context.rs |
226 | [delete-via-crate] — task-local parent-context carrier working around the Tool trait; replace with ToolExecutionContext/RunContext fields (same play that deleted worktree_context.rs). C6 |
sandbox_context.rs |
94 | [delete-via-crate] — same task-local pattern (sandbox_mode carrier). C6 |
task_recency_context.rs |
106 | [delete-via-crate] — same pattern (Composio recency window). C6 |
turn_attachments_context.rs |
71 | [delete-via-crate] — same pattern (vision-attachment forwarding). C6 |
session/turn_checkpoint.rs |
105 | [delete] with the C1 session cutover (turn checkpointing rides crate checkpoints) |
memory_protocol.rs |
386 | [keep] — product memory-protocol state machine (#4116) behind MemoryProtocolMiddleware |
builtin_definitions.rs |
273 | [keep] — product agent-definition data facade |
definition_loader.rs |
295 | [keep] — product TOML definition loader |
archivist/{hook_impl,recap,tree_ingest}.rs |
592 | [keep] — archivist internals, verdict inherited from §3 |
The four task-local context carriers (fork_context, sandbox_context,
task_recency_context, turn_attachments_context, ~500 lines) are one
C6 work item: extend the crate execution context instead of task-locals.
4. Continuation workstreams (execution order)
Sized for /goal execution like the original folders; each step lands code +
tests + deletions + a ledger tick.
C0 — Crate bump to 1.4 (then 1.5 when published)
- Bump both Cargo worlds to
tinyagents = "1.4"; re-verify sqlite chain. - When 1.5.0 publishes: bump again; rewrite
RepeatedToolFailureMiddlewareas a driver overharness::no_progress::NoProgressTracker; delete the in-house identical-failure ladder. - Adopt
with_node_retry+CompiledGraph::retryon the delegation and spawn-parallel graphs (replaces bespoke retry glue; complements 08.3). - Update
00-baseline.md"1.3.0 delta" → 1.4/1.5 delta; refreshdocs/tinyagents-sdk-gaps.md(goals/todos and no-progress close two OpenHuman-convergence items).
C1 — Sessions cutover (04.2 phases 2–4) — biggest single unlock
The importer (session_import/) already proves shape parity. Execute:
- 04.1 live dual-writes (turns append
session.{stem}.messages+ descriptor upsert alongside legacy JSONL). - Shadow reads + parity fixtures (11-fixture matrix), then flip reads.
- Retire:
transcript.rs(1347+978),migration.rs(373+170),session_io.rs(463),session_db/generic parts (~1.6k),subagent_sessions/(653);session_import/one release later. - Then (unblocked by "no live path parses provider text"): delete
dispatcher.rs+parse.rs+pformat.rs(~1.9k + tests), after upstreaming the dialect machinery (C5) or accepting native-only. ~11k lines total. - Fix the stale 04.3 doc (checkpointer swap already landed;
checkpoint.rsis gone).
C2 — Thread goals + thread tasks onto graph::goals/graph::todos
- Adapter:
thread_goals/store.rs+runtime.rs+continuation.rs→ crateThreadGoal+goal_gate_node+run_continuation_tick; keepthread_goals/schemas.rsRPC shapes as projections; mapgoal_get/set/completemodel tools + host pause/resume/clear. - One-time migration of existing goal rows into ns
graph.goals. task_board.rs→ crateTaskBoard;tools/todo.rs→ crateTodoTool;task_dispatcher/claim/poll loop →claim_cardCAS + runner node. DomainEvent emissions +threads.task_board_*/openhuman.todos_*RPC become read-side projections of the crate store.- Single-writer constraint honoured (core is the only mutator; document it).
- Delete:
thread_goals/{store,runtime,continuation}.rsmechanics,task_board.rs, todo CRUD mechanics, dispatcher executor mechanics (~3.2k + tests).
C3 — Middleware de-duplication (01.1/01.3/06 finish)
- Flip
ContextualToolSelectionMiddlewarefrom shadow to owner (parity logs are already accumulating); deleteOpenHumanToolExposureShadowMiddleware, thentool_filter.rsmechanics +tool_prep.rsselection half. - De-duplicate
UsageRecorded(single owner: crate event → bridge records once), then install crateBudgetMiddleware/BudgetLimits; delete localCostBudgetMiddleware+turn_subagent_usage.rstask-local (206) in favour ofRunTreerollup. DeleteCORRECTED by C3 execution (2026-07-03):CacheAlign+MicrocompactCacheAligndeleted (warn-only, crate cache guard already installed — commit onfeat/tinyagents-c3-middleware-dedupe).Microcompactis NOT crate-superseded — tinyagents 1.5.0 has no tool-result body-clearing equivalent and the local one is live on the session turn path — moved to the C5 upstream-extraction batch (extract a crate microcompact first, then delete locally).AdoptCORRECTED by C3 execution: the sentinel +UnknownToolPolicy::RewriteUnknownToolRewriteMiddlewarewere already deleted in 01.2; live policy isUnknownToolPolicy::ReturnToolError, which preserves the attempted tool name + args (#4419 UX). Rewrite mode would regress (needs a catch-all target tool); rationale comment added atrun_policy_for. Done — no further action. Net:tinyagents/middleware.rs2448 → ~1500 (Microcompact stays until C5).
C4 — Events/progress projection (05.3) then delete progress_tracing
- Journal-backed web-progress projection (
HarnessEventJournal+HarnessStatusStore+ late-attachreplay_from). - Parity vs
SpanCollectorspans; then deleteprogress_tracing.rs+progress_tracing/(~2k incl. tests) — Langfuse rides crate exporters. - DomainEvent/AgentProgress become projections (ledger final clause).
C5 — Upstream extraction batch (tinyagents PRs, then local deletes)
In crate-repo PRs, mirroring the NoProgressTracker precedent, in value order:
multimodalattachment resolver (~1550) — marker convention stays here.- Tool-call dialect layer (
pformat/parser) (~1900) — enables C1 step 4 to be a pure delete. - Overflow-to-artifact tool-result store (~500).
- PostTurnHook/StopHook trait machinery (~450); host runtime adapter (~350); fuzzy tool ranker (~250); ArgRecovery (~150); triage evaluator core (~800) as a generic "LLM triage node". Each: crate PR → bump → local adapter shrinks to product residue → delete.
C6 — Subagents finish (07)
- Absorb
ops/runner.rs(1212) +ops/graph.rs(1039) into named pipeline nodes (07.1); procedural runner retired. running_subagents.rs1931 → ≤300: status/tombstone persistence fully onJsonlTaskStore+orchestrate_*tools (07.2).- Steering: crate
SteeringRegistryowns lanes; split then deleterun_queue/(317);spawn_depth_context.rs→RecursionPolicy(07.3). - Replace the four task-local context carriers (
fork_context,sandbox_context,task_recency_context,turn_attachments_context, ~500 lines) with typed fields on the crate execution context (see §3 coverage sweep); shrinksubagent_runner/types.rsonto crateSubAgentPolicy/task types.
C7 — Remaining gated items
- 08.3 durable approval interrupts (now easier with 1.4.0 resumable
failures); 08.5 drop the
worktree_action_dirfallback thread, deleteworktree_context.rsremnant wiring. - 10 CapabilityRegistry projection + fail-closed diagnostics.
- 02.2
reliable.rs: unchanged verdict — gated on routing non-turn provider calls through the crate harness; do not force. ThinkingForwarder: delete when crateModelDeltagrows reasoning + tool-name-on-start (file upstream issue; sdk-gaps §3).
5. Expected reclaim
| Phase | Local lines deleted (incl. tests, rough) |
|---|---|
| C1 sessions + dialect | ~11,000 |
| C2 goals/todos | ~4,000 |
| C3 middleware dedupe | ~1,500 |
| C4 progress tracing | ~2,000 |
| C5 upstream batch | ~6,000 |
| C6 subagents | ~4,500 |
| Total | ~29,000 (of ~57k in agent/ + ~11k adapter + ~9k session/goals modules) |
6. Rules (unchanged)
Approval/security/sandbox/credential boundaries inviolate; JSON-RPC contracts
stable unless a migration note lands; adapter → proven parity → delete;
explicit git add <paths>; verify branch before commit. Tests deferred per
workstream slice with a final conformance pass (11).