feat(session): host-agnostic transcript view, legacy-session importer and turn-state store - #233
Conversation
Introduces a new view module under the transcript subsystem that provides structured rendering of conversation transcripts. The module includes caching, project context, prompt tools, subagent handling, and resolution logic, along with comprehensive tests for ordering, subagent anchoring, and view generation. This enables efficient and flexible transcript display for downstream consumers. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce the transcript import subsystem with support for scanning, conversion, and live import operations, along with a structured view layer for rendering transcripts. These modules enable importing external conversation data into the session format and provide a composable view abstraction for displaying transcript content, including subagent and prompt tool integration. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce a new transcript import module that allows converting external conversation formats into the internal transcript representation. This includes support for live imports, conversion logic, and operational primitives, along with comprehensive tests to ensure correctness. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce a turn state module that tracks the lifecycle of individual turns within a session, along with a transcript import pipeline that can reconstruct session state from external formats. The turn state provides a structured way to manage turn-level metadata and transitions, while the import system enables loading session data from live sources and other representations. This lays the groundwork for more robust session replay and analysis capabilities. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replace deeply nested `if let Some(...)` blocks with the `let`-chain syntax stabilised in Rust 1.83, reducing indentation and making control flow more linear. The change also adds the `hex` crate dependency, re-exports the `import` module as public, and updates the module’s README to reflect the new public API surface. No behaviour is altered. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4da8b33031
ℹ️ 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".
… gate stays clean Co-authored-by: Medulla <medulla@tinyhumans.ai>
Tiny Sweeper review
Last completed reportTiny Sweeper reviewTiny Sweeper reviewed this change across 6 lane(s) and found 0 active actionable finding(s). Detailed lane evidence and any incomplete work are listed below. State: Incomplete Review snapshot
Completeness: Incomplete What changedThe review could not produce a supported behavioral summary; inspect the cited changed surface and lane details below. FeaturesNone identified with supported citations. TestsNo supported feature-to-test mapping was produced. Test execution is not inferred.
FindingsNo active actionable findings. Could not review: crates/tinyagents-session/Cargo.toml, crates/tinyagents-session/src/lib.rs, crates/tinyagents-session/src/transcript.rs, crates/tinyagents-session/src/transcript/import/README.md, crates/tinyagents-session/src/transcript/import/convert.rs, crates/tinyagents-session/src/transcript/import/convert_test.rs, crates/tinyagents-session/src/transcript/import/live.rs, crates/tinyagents-session/src/transcript/import/live_test.rs, crates/tinyagents-session/src/transcript/import/mod.rs, crates/tinyagents-session/src/transcript/import/ops.rs, crates/tinyagents-session/src/transcript/import/ops_test.rs, crates/tinyagents-session/src/transcript/import/scan.rs, crates/tinyagents-session/src/transcript/import/types.rs, crates/tinyagents-session/src/transcript/view/cache.rs, crates/tinyagents-session/src/transcript/view/cache_tests.rs, crates/tinyagents-session/src/transcript/view/mod.rs, crates/tinyagents-session/src/transcript/view/project.rs, crates/tinyagents-session/src/transcript/view/prompt_tools.rs, crates/tinyagents-session/src/transcript/view/prompt_tools_tests.rs, crates/tinyagents-session/src/transcript/view/resolve.rs, crates/tinyagents-session/src/transcript/view/subagents.rs, crates/tinyagents-session/src/transcript/view/transcript_ordering_tests.rs, crates/tinyagents-session/src/transcript/view/transcript_subagent_anchor_tests.rs, crates/tinyagents-session/src/transcript/view/transcript_view_subagent_tests.rs, crates/tinyagents-session/src/transcript/view/transcript_view_tests.rs, crates/tinyagents-session/src/transcript/view/types.rs, crates/tinyagents-session/src/turn_state/mod.rs, crates/tinyagents-session/src/turn_state/shape_test.rs, crates/tinyagents-session/src/turn_state/store.rs, crates/tinyagents-session/src/turn_state/store_test.rs, crates/tinyagents-session/src/turn_state/types.rs, tinysweeper/tests Before merge
How this fits togetherflowchart LR
n0["run_ledger<br/>changed"]:::changed
n1["scoped"]:::impacted
n2["child_of"]:::impacted
n3["...al_chain_stays_under_the_filesystem_limit"]:::impacted
n4["delivery_pages_past_the_session_ledger_cap"]:::impacted
n5["next_generation"]:::impacted
n6["...ply_nested_delegation_chain_stays_bounded"]:::impacted
n3 -->|calls| n1
n3 -->|tests| n1
n3 -->|calls| n2
n3 -->|tests| n2
n3 -->|calls| n5
n3 -->|tests| n5
n4 -->|uses| n0
n6 -->|calls| n1
n6 -->|tests| n1
n6 -->|calls| n2
n6 -->|tests| n2
classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Agent review detailscritique
security
tests
commits
description
e2e
Evidence and run details
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5bedabd1b1
ℹ️ 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".
There was a problem hiding this comment.
tinysweeper found nothing blocking, but could not review everything, so this is not an approval: crates/tinyagents-session/Cargo.toml, crates/tinyagents-session/src/lib.rs, crates/tinyagents-session/src/transcript.rs, crates/tinyagents-session/src/transcript/import/README.md, crates/tinyagents-session/src/transcript/import/convert.rs, crates/tinyagents-session/src/transcript/import/convert_test.rs, crates/tinyagents-session/src/transcript/import/live.rs, crates/tinyagents-session/src/transcript/import/live_test.rs and 24 more.
$0.0106 · 212,317 in / 1,448 out · 107,572 cached (51%) · ladder/vectors, deepseek/deepseek-v4-flash · 1,082 embedded
description: $0.0083 · 100,777 in / 68 out · 0 cached (0%) · deepseek/deepseek-v4-flash
Use saturating_add for the page end calculation to avoid overflow when offset is very large. Clear pending messages in the projector when a new request starts, preventing stale state from persisting across requests. Fix the retained-row dropping logic to only skip messages that form a contiguous prefix, so that later duplicate messages are no longer incorrectly removed. Also correct the import guard to compare the stored marker version against the expected import version, ensuring the guard accurately reflects whether an import is needed. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
…re name deduplication Sort turn state timestamps with proper RFC 3339 date comparison instead of lexicographic string ordering, preventing incorrect sort results when timestamps have different timezone offsets or sub-second precision. Add SHA-256 based deduplication suffix to sanitized store names when the original name contains characters that are stripped, avoiding collisions between distinct names that sanitize to the same value. Serialize live transcript writes with a global mutex to prevent interleaved writes from concurrent tasks. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce a `get_page_scoped` function and supporting plumbing that allows callers to filter transcript pages by an owning agent ID. This enables shared thread IDs to be used safely across multiple agents by projecting only the transcripts owned by a specific agent, preventing cross-agent data leakage. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
…convert.rs,crates/tinyagents-se Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformat several multi-line conditional expressions and function signatures across the transcript import and view modules to improve readability by breaking long lines at logical points, with no change in behaviour. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
… functions Add the tokio crate with the sync feature to support asynchronous synchronization primitives, and export the newly added `project_thread_scoped` and `resolve_files_scoped` functions from the transcript view module to make them available to downstream consumers. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3030f385d0
ℹ️ 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".
| } | ||
| let raw_dir = found[0].parent()?.to_path_buf(); | ||
| let roots = order_root_files(workspace_dir, thread_id, found); | ||
| let subs = discover_subagent_files(&raw_dir, thread_id, &roots); |
There was a problem hiding this comment.
Scope discovered subagent files to the owning root
Although the new root filter addresses the earlier thread-ID collision, the freshly added scoped path still passes every subagent whose metadata has the same thread_id into the projection. When two agents share a caller-supplied thread ID, discover_subagent_files therefore includes the other agent's children, and build_children attaches their messages to the selected agent's history. Derive children from the filtered roots or otherwise verify their owning root/session before returning them.
Useful? React with 👍 / 👎.
| lifecycle: TurnLifecycle, | ||
| now_rfc3339: &str, | ||
| ) -> Result<bool, String> { | ||
| let Some(mut snapshot) = self.get_turn(thread_id, request_id)? else { |
There was a problem hiding this comment.
Make turn settlement atomic with progress writes
get_turn releases the global store lock before settle_turn later calls put, so the progress bridge can write a newer timeline between those operations and then have it overwritten by the stale snapshot copied here. Conversely, a delayed progress write after settlement can replace Completed with Streaming, recreating the live-looking state this method is intended to eliminate. Perform the read-modify-write under one lock and prevent non-terminal writes from downgrading a terminal snapshot.
Useful? React with 👍 / 👎.
| transcript, | ||
| thread_id, | ||
| synthesized, | ||
| Vec::new(), |
There was a problem hiding this comment.
Preserve imported run links during live descriptor upserts
When an imported session already has run_ids joined from agent_runs, the next mirrored turn rebuilds the descriptor with an empty vector and then overwrites the same KV key. That permanently discards the imported run-to-session links even though the new turn has no replacement linkage data. Preserve the existing descriptor's IDs or repeat the ledger join before the upsert.
Useful? React with 👍 / 👎.
Wave 2 extraction from OpenHuman into
tinyagents-session. Stacked onoh-extract-leaves(#230); the pin sits on that branch, so this PR's base is that branch, notmain.What moves
transcript::view(wasopenhuman-core/src/threads/transcript_view): projection ofsession_raw/*.jsonlinto typed display items, thread/generation/sub-agent resolution, the bounded newest-first page cache,get_page.TOOL_RESULT_FAILURES_METADATA_KEYnow lives here (pub const, value"openhuman_tool_failures"unchanged) so the host's writer imports the same constant the projector reads.project_thread/project_recordsare public.transcript::import(wasopenhuman-core/src/agent/session_import): scan + convert +run_import,write_live_turn,shadow_read_compare,open_session_stores. Seam:convert::JournalProjector = fn(TranscriptMessage) -> JournalMessage, supplied by the host so journal records keep the host's sidecar metadata;plain_journal_messageis the neutral default. The config flag and kill-switch env decisions stay with the host (write_live_turnjust does the work).turn_state::{store, types}(wasopenhuman-core/src/threads/turn_state): the per-turn snapshot store and its wire/storage types. RPC payload structs, theClassifiedFailureconversion and theAgentProgressmirror stay in the host.Compatibility
Nothing on disk changes format. Literal-JSON fixture tests pin
TurnState,JournalMessage,ItemLedgerRecordand the ledger key (sha256hex, now lowercase-hex-encoded by hand because sha2 0.11 has noLowerHex).log::calls becametracing::with the same messages and prefixes.New dependencies of
tinyagents-session:tinytools-agent(text-dialect result parsing in the projector),sha2,glob,hex,parking_lot,tempfile(now a normal dependency: atomic snapshot writes).Tests
cargo test -p tinyagents-session: 228 unit + 2 integration pass.cargo fmt --all -- --checkandcargo clippy -p tinyagents-session --all-targets -- -D warningsclean. Tests that need host message types (ChatMessage, the session codec) stay in OpenHuman.