feat(agent): tinyagents 1.5 migration wave — vendored SDK, dual-write sessions, goals/todos shadows, journals, middleware dedupe#4473
Conversation
…os, no-progress, session cutover) Ground-truth audit of post-tinyhumansai#4249 main + re-inventory of tinyagents 1.4.0/1.5.0. Re-evaluates the deletion ledger's 'never delete' list, adds thread goals / thread tasks migration onto graph::goals / graph::todos, and sequences the remaining ~29k-line reclaim (C0-C7). Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
…iles Adds verdicts for extract_tool/handoff, the four task-local context carriers, turn_checkpoint, memory_protocol, definition loader/builtins, and subagent_runner residuals; wires the carriers into C6. Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
…ignore Bumps the tinyagents dependency from 1.3.0 to 1.5.0 across Cargo.toml and Cargo.lock files. Updates related documentation to reflect the new version. Additionally, adds *.diff to .gitignore to exclude diff files from version control.
…to in-tree source vendor/tinyagents pinned at v1.5.0 (matches the crates.io requirement); [patch.crates-io] path override in root and app/src-tauri manifests so migration agents can modify SDK source in-tree and PR upstream from the submodule. Both worlds resolve tinyagents v1.5.0 (path); crate checks clean. Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
…NoProgressTracker Rewrite the repeated-tool-failure circuit breaker as a thin driver over tinyagents 1.5.0 harness::no_progress::NoProgressTracker instead of the in-house identical/varied/hard-reject failure ladder it replaces. The middleware now owns only OpenHuman-side policy: capture the per-call argument fingerprint in before_tool, feed each outcome into NoProgressTracker::record, and lower the returned NoProgress verdict into steering — Nudge -> SteeringCommand::Redirect (structured 'no progress since step X' corrective), Halt -> record root-cause summary in HaltSummarySlot + SteeringCommand::Pause + tracker.reset(). Continue is a no-op. Deletes the duplicated crate-side ladder constants/logic (NO_PROGRESS_FAILURE_THRESHOLD, HARD_REJECT_REPEAT_THRESHOLD, inline same_count/consecutive counters + summary wording). Unit tests adapted to the tracker-driven behavior (halt now emits Pause; a nudge Redirect precedes it). Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
The [patch.crates-io] path override made vendor/tinyagents part of the cargo graph; the Dockerfile now COPYs vendor/ (needed already at the dep-cache stage) and both docker jobs init just that submodule after checkout (targeted init skips the large tauri-cef fork the core image does not need). All other cargo-running CI jobs already checkout with submodules: recursive/true; the mobile crates do not depend on the core crate, so their submodules:false stays. Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
…ion + spawn-parallel graphs Adopt tinyagents 1.5.0 CompiledGraph::with_node_retry(RetryPolicy) on the delegation graph (build_delegation_graph) and the live spawn-parallel execution graph (run_spawn_parallel_execution_graph). Adapter-first and behavior-preserving: neither graph carried bespoke retry glue, so the policy is RetryPolicy::default().with_max_attempts(1) — a single attempt, identical to today's semantics — with backoff sleeping left off (the default). This lands the crate seam so raising the attempt cap or enabling backoff becomes a one-line gated follow-up rather than a rewrite. Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
…5.1)
Seed the per-turn EventSink with with_stream_id(run_id) so every durable
observation persists a restart-stable {run_id}-evt-{offset} event_id — the
id a late-attach replay reconstructs the timeline from. Mint the run id
once before the sink and thread it into attach_turn_journal (no longer
minted internally), and record the sub-agent task scope as the status
thread_id so FileStatusStore::list_by_thread answers.
Journal test now asserts ordered, stable {stream_id}-evt-{offset} ids, an
offset>0 late-attach tail replay, and list_by_thread/list_active/list_by_root
over the durable status store.
Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
CacheAlignMiddleware was a warn-only KV-cache-prefix diagnostic that scanned the system prompt for volatile tokens (uuid/jwt/iso8601/hex) and emitted a free-text `log::warn!`. Its structured, crate-native successor — `PromptCacheSegmentMiddleware` stamping content-fingerprinted `PromptSegment`s plus the crate `PromptCacheGuardMiddleware` recording `CacheLayoutEvent`s — is already installed on the shared runner and drained via `observability::surface_cache_layout_events`. The shadow was explicitly a "kept installed in parallel until parity is shown; deletion is a gated follow-up"; C3 lands that deletion. Removed: - `CacheAlignMiddleware` struct + `Middleware` impl and its install in `TurnContextMiddleware::install`. - The `cache_align` config field (+ its wiring in the session turn builder, `defaults()`, `is_empty()`). - The exclusive helper machinery: `VolatileFinding`, `detect_volatile_prompt_tokens`, `warn_if_cache_prompt_volatile`, `redact_volatile_token`, `is_uuid`/`is_jwt`/`is_hex_hash`/`is_iso8601`. MicrocompactMiddleware is intentionally retained (see report): the vendored tinyagents 1.5.0 ships no Microcompact equivalent and the local one is live on the session path (default keep_recent=5), so deleting it would drop tool-body-clearing behavior with no crate replacement. Updated the `defaults_enable_cache_align_and_the_byte_cap_only` test (now `defaults_enable_the_byte_cap_only`) and refreshed the now-stale "kept installed in parallel" comments across mod.rs / observability.rs. Gate: GGML_NATIVE=OFF cargo check (clean) + `cargo test --lib tinyagents::middleware` (25 passed). Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
…Rewrite (C3)
C3 step 4 asked to adopt `UnknownToolPolicy::Rewrite` and delete the
`__openhuman_unknown_tool__` sentinel + `UnknownToolRewriteMiddleware`. Ground
truth on this baseline: that deletion already landed in 01.2 — the sentinel
tool, its registration, and the rewrite middleware are gone from src/ and
tests (only historical comments remain). The live policy is already
`ReturnToolError`.
Flipping to `Rewrite { tool_name }` would be a regression, not a cleanup:
Rewrite needs a real catch-all target tool (the deleted sentinel was exactly
that) and, when it hits, silently retargets + executes that tool, emitting
`AgentEvent::UnknownToolCall { recovery: "rewrite:.." }` with NO injected tool
message. Two live consumers depend on the `ReturnToolError` path's injected
`unknown tool `<name>` (arguments: ..); valid tools: [..]` message:
- the tinyhumansai#4419 attempted-tool-name UX, and
- `agent::hooks::sanitize_tool_output`, which classifies the failure as
`unknown_tool` by matching the "unknown tool" substring.
The crate already preserves the original requested name + arguments verbatim on
`AgentEvent::UnknownToolCall`, projected by `OpenhumanEventBridge`.
No functional change — documents the decision at the `run_policy_for` site so a
future reader does not "finish" C3 by flipping to Rewrite and silently break
both consumers.
Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
…rst slice) Adapter-first, log-only. Adds src/openhuman/todos/graph_shadow.rs which mirrors every authoritative task-board write into the vendored tinyagents::graph::todos crate Store (ns graph.todos) and shadow-replays the crate claim_card CAS, warn-logging any divergence. Legacy TaskBoardStore + todos::ops stay the single source of truth; RPC shapes and product behavior are untouched. - graph_shadow.rs: total status mapping (7 variants, 1:1), full TaskBoardCard conversion, FileStore-backed crate store, spawn_mirror + spawn_shadow_claim (best-effort, tokio-runtime-guarded, no-op for scratch boards). - ops.rs: save_cards mirrors the persisted board; claim_card refactored to compute one ok/err verdict via an extracted apply_claim helper so the crate shadow observes the same not-found/wrong-status/single-InProgress outcomes. Legacy claim result and all existing tests unchanged. - Unit tests cover status mapping round-trip, card-field preservation, approval-mode mapping, scratch skip, crate mirror round-trip, the shared single-InProgress rejection, and the crate claim_card CAS contract. Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
Records the graph::todos adapter surface: what maps (dispatch, thread binding, CRUD ops, status aliases, single-InProgress, claim_card CAS) and what stays product residue (approval gate, DomainEvent emissions, threads.task_board_* / openhuman.todos_* RPC projections, scratch board, run lifecycle). Documents the single-writer constraint and the not-in-this-slice cutover steps. Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
Adapter-first mirror of the thread_goals domain onto the tinyagents 1.5.0 `graph::goals` crate store (issue tinyhumansai#4249, plan §C2). Legacy per-thread file-JSON store stays authoritative for reads; every goal mutation is also mirrored, faithfully (same goal_id/timestamps/counters), into the crate `Store` ns `graph.goals` at `{workspace}/tinyagents_store/kv`, byte-for-byte under the key the crate's own reader computes. - `crate_adapter.rs`: status/goal projections (Active/Paused/BudgetLimited/ Complete, completion contract, token-budget fields), put/get/delete mirror, a one-time idempotent migration helper (callable + logged, NOT wired to boot), and a shadow-mode surface gated OFF behind OPENHUMAN_THREAD_GOALS_CRATE_SHADOW (acts on legacy, logs divergence). - Wire flag-gated shadow mirror into the tool surface (goal_set/goal_complete) and host surface (set/complete/pause/resume/clear); RPC schemas untouched. - Single-writer constraint documented (core is the only mutator; crate Store has no cross-process CAS). - Focused unit tests for the adapter mapping + migration idempotency (thread_goals module: 37 passed). Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
Introduces AgentConfig::session_dual_write (serde default true) — the config knob that gates the live session-store dual-write (issue tinyhumansai#4249, sessions 04.1). The OPENHUMAN_SESSION_DUAL_WRITE env var remains a pure kill switch layered on top; this field is the default-driving flag so the store is populated by live turns for the 04.2 read cutover. Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
… config flag + kill switch (04.1)
Mirrors each already-persisted turn into {workspace}/tinyagents_store/
{kv,journal} alongside the authoritative legacy session_raw/*.jsonl
transcript, reusing session_import/convert.rs normalization so live and
imported records are shape-identical (per-session stream
session.{stem}.messages + sessions-ns descriptor upsert).
- live::write_live_turn performs the best-effort, non-fatal mirror after
the legacy JSONL append in session/turn/session_io.rs; store-write
failures are logged ([session-store]) and swallowed, never touching the
chat turn or legacy path.
- live::session_kv_store registers the session KV FileStore on each turn's
RunContext.stores (assemble path) under TINYAGENTS_SESSION_KV_STORE, so
the harness carries a handle to the same tree; reads stay 100% legacy
until 04.2.
- Gating unified on AgentConfig::session_dual_write (default ON) via
live::dual_write_enabled(config_enabled), with OPENHUMAN_SESSION_DUAL_WRITE
as a pure kill switch; session_kv_store self-gates on the same decision.
- Write-side parity test: drives the legacy JSONL writer and the live
mirror with the same turn and asserts the store journal renders the
identical JournalMessages the importer reads back (incl. reconstructed
openhuman_turn_usage + tool-call id), plus the config/kill-switch matrix.
Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
…perseded, unknown-tool already done Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (19)
📝 WalkthroughWalkthroughThis PR vendors ChangesTinyAgents vendoring and integration rollout
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant AgentConfig
participant LiveImport
participant SessionIO
participant EventSink
participant Journal
AgentConfig->>LiveImport: session_dual_write enabled
SessionIO->>LiveImport: dual_write_enabled(config_enabled)
LiveImport-->>SessionIO: mirror allowed or killed
Journal->>EventSink: with_stream_id(run_id)
SessionIO->>Journal: attach_turn_journal(run_id, thread_id)
sequenceDiagram
participant Tool as Tool Call
participant Middleware as RepeatedToolFailureMiddleware
participant Tracker as NoProgressTracker
participant Steering as SteeringHandle
Tool->>Middleware: after_tool(result/error)
Middleware->>Tracker: record(step, ToolAttempt)
Tracker-->>Middleware: NoProgress::Continue/Nudge/Halt
alt Nudge
Middleware->>Steering: SteeringCommand::Redirect
else Halt
Middleware->>Middleware: store halt summary
Middleware->>Steering: SteeringCommand::Pause
Middleware->>Tracker: reset
end
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5a1227ddf2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # immediately, and PR the diff upstream from the submodule. Keep the submodule | ||
| # version in lockstep with the `tinyagents` requirement above. After cloning: | ||
| # `git submodule update --init vendor/tinyagents` (worktrees included). | ||
| tinyagents = { path = "vendor/tinyagents" } |
There was a problem hiding this comment.
Run Rust CI when vendored TinyAgents changes
Because this patch makes both Cargo worlds resolve tinyagents from vendor/tinyagents, SDK changes can now change the compiled product without touching Cargo.toml, Cargo.lock, or src/**. I checked the PR CI path filters in .github/workflows/pr-ci.yml and they do not include vendor/tinyagents or .gitmodules, so a PR that only bumps the submodule pointer would skip the Rust quality/coverage lanes and the Playwright artifact build/cache despite changing a compiled dependency. Add the submodule path (and usually .gitmodules) to the Rust/Tauri/playwright filters and related artifact cache keys so vendored SDK updates are actually built and tested.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
Cargo.toml (1)
334-339: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAutomate the tinyagents lockstep check
The submodule pin and
tinyagents = "1.5.0"requirement are coupled only by comment today; add a CI assertion that comparesvendor/tinyagents/Cargo.toml’s version with the root andapp/src-tauri/Cargo.tomlrequirements.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Cargo.toml` around lines 334 - 339, Add a CI assertion for the tinyagents lockstep contract so it no longer relies on the comment in Cargo.toml. Create a check that reads the version from vendor/tinyagents/Cargo.toml and compares it against both the root tinyagents requirement and the app/src-tauri/Cargo.toml requirement, failing the build when they diverge. Use the existing tinyagents dependency declarations and the vendored submodule path as the identifiers to wire this into the current CI/test flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/tinyagents-full-migration-plan/00-baseline.md`:
- Around line 3-18: Update the baseline doc to match the current tinyagents
1.5.0 state: the section still references a 1.3.0 delta and an inventory
refreshed against 1.3.0, so rename that delta section in 00-baseline.md and
revise the gap notes for the newer API surface. Make sure the updated plan
explicitly covers the 1.4/1.5 additions referenced by the review, including
CompiledGraph::with_node_retry and NoProgressTracker.
In `@docs/tinyagents-full-migration-plan/CONTINUATION-2026-07.md`:
- Around line 15-19: The plan text is inconsistent with the repo’s pinned
baseline: the 00 baseline row and the C0 wording still reference 1.3.0/1.4/1.5
migration steps. Update the `CONTINUATION-2026-07` markdown so the baseline
section and any surrounding “ground truth” notes reflect the already-pinned
`tinyagents = 1.5.0`, and remove or rephrase the stale bump language to match
the current state. Focus on the baseline table entries and any adjacent
narrative that describes the version target.
---
Nitpick comments:
In `@Cargo.toml`:
- Around line 334-339: Add a CI assertion for the tinyagents lockstep contract
so it no longer relies on the comment in Cargo.toml. Create a check that reads
the version from vendor/tinyagents/Cargo.toml and compares it against both the
root tinyagents requirement and the app/src-tauri/Cargo.toml requirement,
failing the build when they diverge. Use the existing tinyagents dependency
declarations and the vendored submodule path as the identifiers to wire this
into the current CI/test flow.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c011176f-f29e-406f-a23f-cc273e072b5c
⛔ Files ignored due to path filters (2)
Cargo.lockis excluded by!**/*.lockapp/src-tauri/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (21)
.github/workflows/release-production.yml.github/workflows/release-staging.yml.gitignore.gitmodulesCargo.tomlDockerfileapp/src-tauri/Cargo.tomldocs/tinyagents-full-migration-plan/00-baseline.mddocs/tinyagents-full-migration-plan/01-tooling/README.mddocs/tinyagents-full-migration-plan/04-sessions/03-checkpointer.mddocs/tinyagents-full-migration-plan/10-registry.mddocs/tinyagents-full-migration-plan/CONTINUATION-2026-07.mddocs/tinyagents-full-migration-plan/HANDOFF-2026-07-03.mddocs/tinyagents-full-migration-plan/README.mddocs/tinyagents-migration-spec.mddocs/tinyagents-session-migration-design.mdgitbooks/developing/architecture/agent-harness.mdsrc/openhuman/agent_orchestration/spawn_parallel_graph.rssrc/openhuman/tinyagents/delegation.rssrc/openhuman/tinyagents/middleware.rsvendor/tinyagents
| Current status (2026-07-03): baseline dependency alignment is complete in both | ||
| Cargo worlds. `tinyagents 1.5.0` is resolved with the `sqlite` feature, | ||
| OpenHuman pins `rusqlite = "=0.40.0"`, both worlds patch through | ||
| `vendor/rusqlite-0.40.0` and `vendor/libsqlite3-sys-0.38.0`, and the SDK-gaps | ||
| inventory has been refreshed against the published 1.3.0 crate source. | ||
|
|
||
| ## Steps | ||
|
|
||
| 1. **Bump `tinyagents` to `"1.3"`** (done in both Cargo worlds — root and | ||
| 1. **Bump `tinyagents` to `"1.5.0"`** (done in both Cargo worlds — root and | ||
| `app/src-tauri/`). Known 1.1→1.2 break already handled | ||
| (`MessageDelta::text` ctor). Note: the `openai` crate feature was removed | ||
| after 1.2.0 (1.2.1+ features are only `sqlite`/`repl`) — we never enabled | ||
| it, so no impact. See "1.3.0 delta" below for new API this plan uses. | ||
| 2. **Align rusqlite to 0.40** in both worlds (`Cargo.toml` root and | ||
| `app/src-tauri/Cargo.toml`). OpenHuman pins `rusqlite = "=0.40.0"` and | ||
| enables `tinyagents = { version = "1.3", features = ["sqlite"] }`. | ||
| enables `tinyagents = { version = "1.5.0", features = ["sqlite"] }`. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -n 'NoProgressTracker|with_node_retry|1\.4\.0|1\.5\.0' docs/tinyagents-full-migration-plan/CONTINUATION-2026-07.md docs/tinyagents-full-migration-plan/HANDOFF-2026-07-03.md 2>/dev/nullRepository: tinyhumansai/openhuman
Length of output: 4144
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== baseline excerpts ==\n'
sed -n '1,120p' docs/tinyagents-full-migration-plan/00-baseline.md | cat -n
printf '\n== continuation excerpts ==\n'
sed -n '1,120p' docs/tinyagents-full-migration-plan/CONTINUATION-2026-07.md | cat -n
printf '\n== handoff excerpts ==\n'
sed -n '1,120p' docs/tinyagents-full-migration-plan/HANDOFF-2026-07-03.md | cat -nRepository: tinyhumansai/openhuman
Length of output: 31494
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== baseline references to delta/gaps ==\n'
rg -n '1\.3\.0 delta|SDK-gaps|NoProgressTracker|with_node_retry|1\.4\.0|1\.5\.0' docs/tinyagents-full-migration-plan/00-baseline.md docs/tinyagents-full-migration-plan/CONTINUATION-2026-07.md docs/tinyagents-full-migration-plan/HANDOFF-2026-07-03.mdRepository: tinyhumansai/openhuman
Length of output: 5066
Update 00-baseline.md to the 1.4/1.5 delta.
The baseline still points readers to a 1.3.0 delta and says the SDK-gaps inventory was refreshed against 1.3.0, but this plan is already on tinyagents 1.5.0. Rename that section and refresh the gap notes so the newer APIs (CompiledGraph::with_node_retry, NoProgressTracker) are covered.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/tinyagents-full-migration-plan/00-baseline.md` around lines 3 - 18,
Update the baseline doc to match the current tinyagents 1.5.0 state: the section
still references a 1.3.0 delta and an inventory refreshed against 1.3.0, so
rename that delta section in 00-baseline.md and revise the gap notes for the
newer API surface. Make sure the updated plan explicitly covers the 1.4/1.5
additions referenced by the review, including CompiledGraph::with_node_retry and
NoProgressTracker.
| | 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 | |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Update the plan text to match the already-pinned 1.5.0 baseline.
This still describes C0 as a 1.4 bump / later 1.5 bump and labels 00 baseline as 1.3.0, but the repo and handoff already pin tinyagents = 1.5.0. That makes the “ground truth” section self-contradictory for the next reader.
Also applies to: 135-143
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/tinyagents-full-migration-plan/CONTINUATION-2026-07.md` around lines 15
- 19, The plan text is inconsistent with the repo’s pinned baseline: the 00
baseline row and the C0 wording still reference 1.3.0/1.4/1.5 migration steps.
Update the `CONTINUATION-2026-07` markdown so the baseline section and any
surrounding “ground truth” notes reflect the already-pinned `tinyagents =
1.5.0`, and remove or rephrase the stale bump language to match the current
state. Focus on the baseline table entries and any adjacent narrative that
describes the version target.
…4473, wave-2 slices queued (spend-limit halt) Claude-Session: https://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e7bdbb7a1d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if !live::dual_write_enabled() { | ||
| // Config flag (default ON) gates the mirror; the env kill switch can | ||
| // still force it off. `self.config` is the effective per-agent config. | ||
| if !live::dual_write_enabled(self.config.session_dual_write) { |
There was a problem hiding this comment.
Serialize live session-store rewrites
Enabling the dual-write by default makes the existing fire-and-forget mirror run for normal turns, but write_live_turn rewrites the whole journal by deleting the stream file and re-appending all messages. If a user starts the next turn before the previous background task finishes, the older task can run last and replace the newer TinyAgents stream with a stale, shorter transcript even though the legacy JSONL is correct. Please serialize/queue these writes per session (or await them) before making the mirror default-on.
Useful? React with 👍 / 👎.
| log::debug!("[thread_goals] rpc=set thread_id={thread_id}"); | ||
| let goal = store::set(workspace_dir, thread_id, objective, token_budget).await?; | ||
| emit_updated(&goal); | ||
| super::crate_adapter::shadow_mirror_goal(workspace_dir, &goal).await; |
There was a problem hiding this comment.
Mirror all thread-goal writers
This mirrors the RPC/tool mutation path, but existing goal mutations bypass these ops entirely: the runtime calls store::resume, store::pause, store::account_usage, and continuation-suppression helpers directly, and agent_prepare_context bootstraps goals with store::set_if_absent. With OPENHUMAN_THREAD_GOALS_CRATE_SHADOW=1, a normal turn can advance usage or move a goal to budget_limited only in the legacy store, leaving graph.goals stale and making the shadow/parity corpus unreliable for cutover. Centralize the mirror in the store layer or add it after every direct writer.
Useful? React with 👍 / 👎.
… so interactive turns don't crash (tinyhumansai#4089) The tinyagents 1.5 migration (tinyhumansai#4473) moved the no-progress escalation ladder into the crate (`no_progress::NoProgressTracker`), which feeds a structured "no progress since step X" corrective back into the loop as a `NoProgress::Nudge` — giving the model one chance to change strategy before the same-strategy retry cap. OpenHuman's `RepeatedToolFailureMiddleware` delivered that nudge via `SteeringCommand::Redirect`. But `Redirect` is Background (sub-agent) only: the interactive-turn steering policy deliberately permits just `InjectMessage`/`Pause` so the user's live turn can't be redirected out from under them by a rogue steer (`orchestration.rs`). The middleware runs on *every* turn, so every interactive turn that hit the nudge aborted with `steering command redirect is not permitted by the run policy` — a tinyhumansai#4473 regression that red-lines the raw-tool-loop / monitor E2E coverage suites. Deliver the nudge as a system message via the `InjectMessage` lane instead. The corrective is trusted, system-generated advisory text, so `InjectMessage` is both permitted (on interactive *and* background) and semantically correct — the change-strategy steering tinyhumansai#4089 asks for now actually reaches the model on interactive chat instead of crashing it. Tests: the nudge fires once (as an InjectMessage carrying the "no progress" signal + the failing call name) on the 2nd identical failure, before the halt; and a regression assertion that the interactive steering policy permits the `InjectMessage` lane the nudge now uses (and still refuses `Redirect`). Closes tinyhumansai#4089. Claude-Session: https://claude.ai/code/session_01KcmdqJVpjmnH31HqTHRLwG
…teering Six Rust test failures surfaced by clean CI (merged without test parity): - middleware (production regression, tinyhumansai#4473): the no-progress ladder's Nudge sent SteeringCommand::Redirect, which is NOT in the Interactive steering allowlist (InjectMessage + Pause only). Every interactive turn where a tool failed twice with identical args or four times with varied errors aborted the whole turn with a Steering error instead of nudging then halting gracefully. Switch the nudge to InjectMessage(system) — equivalent (append + Continue) but within the interactive policy. Fixes the three agent *_raw_coverage_e2e panics (turn_xml_failures…, bus_turn_halts_on_repeated_tool_error…, no_progress_guard_uses_default_iteration_fallback_when_zero). - config schema catalog test: privacy-mode controllers (config_get/set_privacy_mode, added by tinyhumansai#4435/tinyhumansai#4446) were registered but the hand-maintained golden list in config_auth_app_state_connectivity_e2e.rs wasn't updated. Add the two entries. - api::config backend_url test: tinyhumansai#4153 intentionally made a bare `/v1` base on an unknown host classify as an OpenAI-compatible inference base (with its own passing sibling test); the older contradictory assertion wasn't updated. Align it to expect the fallback. - tinyagents middleware inventory tests: tinyhumansai#4444 added MemoryProtocolMiddleware (+1) and tinyhumansai#4473 removed CacheAlignMiddleware (-1), but the count literals were left at 13/11. Correct to 12/10 and drop cache-align from the comment. Claude-Session: https://claude.ai/code/session_014RLnG2QbdL3n9TLtfomdhB
…enial assertion
`turn_xml_failures_...` asserts the transcript surfaces a policy denial
("denied by policy 'round17-deny'"). The test set tool_result_budget_bytes: 96;
before the tinyagents 1.5 migration (tinyhumansai#4473) policy denials bypassed the
per-result budget, but the migration now routes them through
ToolOutputMiddleware.after_tool, so 96 bytes truncated the ~400-byte denial to a
stub and the assertion no longer matched. (This assertion was unreachable until
the steering fix in this branch let the turn run to completion.)
Raise the budget above the denial size — no assertion here depends on truncation
actually happening, and production's default budget is 16 KiB so real denials
are never truncated. Documented the underlying regression (denials should be
exempt from the budget) + the dead hard_reject fast-path as a follow-up in code.
Claude-Session: https://claude.ai/code/session_014RLnG2QbdL3n9TLtfomdhB
Summary
docs/tinyagents-full-migration-plan/CONTINUATION-2026-07.md(C0 baseline + parallel adapter-first slices), all landing in this PR.tinyagents1.3 → 1.5.0, vendors the SDK as a submodule atvendor/tinyagentswith[patch.crates-io]in both Cargo worlds;RepeatedToolFailureMiddlewarebecomes a thin driver over crateNoProgressTracker; cratewith_node_retryseam on delegation + spawn-parallel graphs; docker CI carries the submodule.session.{stem}.messages+ descriptor), flagagent.session_dual_write(default ON) with env kill switch; write-side parity test proves legacy JSONL ↔ store render identical transcripts.graph.goals(byte-identical keys, idempotent migration helper) and task board mirrored into crategraph.todoswithclaim_cardCAS shadow — both shadow-mode, legacy authoritative, divergence warn-logged.CacheAlignMiddlewaredeleted (−147 lines; crate cache guard already installed). Microcompact deletion refused — NOT crate-superseded (corrected in plan); unknown-tool sentinel already gone,ReturnToolErrorkept deliberately (fix(tinyagents): keep attempted tool name in the timeline for unavailable tools #4419 UX).{run_id}-evt-{offset}journal event ids, durable status store answeringlist_by_thread, late-attach replay proven from the store alone.Problem
The tinyagents migration (#4249) landed on 1.3; the crate has since shipped 1.4/1.5 with primitives that replace in-house code (
graph::goals,graph::todos,NoProgressTracker, resumable graph failures, durable journals). Remaining migration work also needs to modify SDK source and test against OpenHuman in one tree.Solution
v1.5.0; path patch keeps manifest requirement and vendored source in lockstep. Agents/devs can change SDK source in-tree and PR upstream from the submodule.max_attempts=1, tracker-driven nudge/halt with identical steering semantics) adopted now; escalation later.Submission Checklist
N/A: adapter-first mirrors + dependency vendoring; no user-facing feature rows added/removed## Related—N/A: no matrix rows affectedN/A: shadow/dual-write paths flag-gated with kill switches; legacy paths authoritativeCloses #NNNin the## Relatedsection —N/A: follow-up wave to #4249; no dedicated issueImpact
OPENHUMAN_SESSION_DUAL_WRITE, shadow flags default OFF where risky).tinyagents v1.5.0 (path: vendor/tinyagents); fresh clones/worktrees needgit submodule update --init vendor/tinyagents; docker core image build handled in release workflows.Related
docs/tinyagents-full-migration-plan/CONTINUATION-2026-07.md· Handoff:HANDOFF-2026-07-03.mdhttps://claude.ai/code/session_013uVSkcdR2eP7hW4xm54wb4
Summary by CodeRabbit
New Features
Bug Fixes