release: v0.3.7 session context convergence - #27
Conversation
📝 WalkthroughWalkthroughThe release restores recorded-session context usage, derives model context limits, protects TUI context updates with revisions, preserves assistant stream order during hydration, and suppresses duplicate completed responses. Release metadata and documentation now target v0.3.7. ChangesRuntime context restoration
Revision-safe projection and ordered replay
Release updates
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant RecordedSession
participant RuntimeHost
participant ThreadStore
participant TuiApp
participant SurfaceProjection
RecordedSession->>RuntimeHost: resume recorded thread
RuntimeHost->>ThreadStore: read latest context tokens
ThreadStore-->>RuntimeHost: return restored token usage
RuntimeHost->>SurfaceProjection: initialize usage and context limit
TuiApp->>SurfaceProjection: apply SurfaceProjectionSynced
SurfaceProjection-->>TuiApp: preserve newer context and ordered streams
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
2a33be1 to
85f9601
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
crates/orca-tui/src/types.rs (1)
1746-1758: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winClarify the context-revision/legacy-observation interaction.
should_apply_context = revision_advanced && (!self.context_observed || self.context_revision.is_some())is correct per the tests at Lines 5729-5771 (a stale snapshot never overwrites a newer legacyContextUpdatedvalue, and any snapshot after the first one always wins once a revision has been applied). The condition is hard to read from the code alone: the second clause exists only to let a legacy observation block exactly the first-ever typed snapshot, not later ones.Add an inline comment above this block naming the two intentional outcomes:
- A stale snapshot revision never overwrites a legacy context observation.
- Once one typed snapshot has been applied, the next advancing revision always wins over any legacy observation.
♻️ Proposed clarifying comment
+ // Legacy provider context events set `context_observed`. A snapshot with an + // advanced revision always wins once at least one snapshot has been applied + // (`context_revision.is_some()`); only the very first snapshot for a session + // can be blocked by a legacy observation that arrived before it. let revision_advanced = self .context_revision .is_none_or(|revision| projection.context_revision > revision);As per coding guidelines, this reasoning was already partly captured in the field doc comment on
context_revision(Lines 932-935); extending it to the exact boolean expression that implements it reduces the risk of a future regression to this correctness-sensitive path.🤖 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 `@crates/orca-tui/src/types.rs` around lines 1746 - 1758, Add an inline comment immediately above the context-revision logic in the relevant method, documenting that stale snapshots never overwrite legacy context observations and that, after the first typed snapshot is applied, every advancing revision takes precedence over legacy observations. Keep the existing boolean expression and behavior unchanged.
🤖 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 `@crates/orca-tui/src/surface_projection.rs`:
- Around line 559-569: Update the live reduction logic in reduce_typed_batch to
track whether any assistant stream for response.turn_id has state Discarded.
Even when response_matches_streamed_items returns true, emit
response_completed_event unless no discarded stream exists, preserving
reconciliation for discarded retries. Add a regression test covering a discarded
stream and a surviving stream matching the final response, asserting
AssistantResponseCompleted is emitted.
---
Nitpick comments:
In `@crates/orca-tui/src/types.rs`:
- Around line 1746-1758: Add an inline comment immediately above the
context-revision logic in the relevant method, documenting that stale snapshots
never overwrite legacy context observations and that, after the first typed
snapshot is applied, every advancing revision takes precedence over legacy
observations. Keep the existing boolean expression and behavior unchanged.
🪄 Autofix
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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1e987664-fec8-4732-8d36-2c5d47cf7187
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (15)
Cargo.tomlcrates/orca-core/src/config/mod.rscrates/orca-runtime/src/runtime_host.rscrates/orca-runtime/src/thread_store.rscrates/orca-runtime/src/thread_store/writer.rscrates/orca-tui/src/app.rscrates/orca-tui/src/surface_projection.rscrates/orca-tui/src/types.rscrates/orca-tui/src/ui.rsdocs/harness-contract.mddocs/production-roadmap.mddocs/releases/v0.3.7.mdnpm/orca/package.jsonsite/src/changelog/Changelog.tsxsite/src/shared.ts
| let response_matches_streams = | ||
| response_matches_streamed_items(response, assistant_streams.values()); | ||
| for stream in assistant_streams.values_mut().filter(|stream| { | ||
| stream.turn_id == response.turn_id | ||
| && stream.state == SurfaceAssistantStreamState::Open | ||
| }) { | ||
| stream.state = SurfaceAssistantStreamState::Completed; | ||
| } | ||
| projected.push(response_completed_event(response)); | ||
| if !response_matches_streams { | ||
| projected.push(response_completed_event(response)); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Fix: dedup check ignores discarded-stream retries and can suppress needed cleanup.
response_matches_streamed_items filters out Discarded streams before comparing them to the response's message/reasoning/plan items. When a turn has an earlier Discarded stream (a retry) whose partial content was already pushed into AppState.messages through ReasoningDelta/MessageDelta, and the surviving (non-discarded) stream happens to match the final response exactly, this function returns true and response_completed_event is not pushed.
AssistantResponseCompleted is the only mechanism that reconciles this in the live path: its handler, reconcile_assistant_response, calls retain_messages to remove all Reasoning/Assistant/ProposedPlan messages after the last user message and re-adds the canonical text. Skipping this event leaves the discarded stream's stale content visible in the transcript alongside the final content.
The existing test foreground_hydration_reconciles_completed_item_for_discarded_stream (in this same file) confirms that discarded-stream content requires exactly this reconciliation through AssistantResponseCompleted in the reconnect path. The live reduce_typed_batch path now has a gap: it can skip that same reconciliation.
Track whether any stream for this turn_id was discarded, and do not suppress the event in that case.
🐛 Proposed fix
SurfaceEvent::Assistant(AssistantPatch::ResponseCompleted { response }) => {
- let response_matches_streams =
- response_matches_streamed_items(response, assistant_streams.values());
+ let has_discarded_stream_for_turn = assistant_streams.values().any(|stream| {
+ stream.turn_id == response.turn_id
+ && stream.state == SurfaceAssistantStreamState::Discarded
+ });
+ let response_matches_streams = !has_discarded_stream_for_turn
+ && response_matches_streamed_items(response, assistant_streams.values());
for stream in assistant_streams.values_mut().filter(|stream| {
stream.turn_id == response.turn_id
&& stream.state == SurfaceAssistantStreamState::Open
}) {
stream.state = SurfaceAssistantStreamState::Completed;
}
if !response_matches_streams {
projected.push(response_completed_event(response));
}
}Add a regression test with a Discarded stream plus a surviving stream whose content exactly matches the response, and assert that AssistantResponseCompleted is still emitted.
Also applies to: 1376-1422
🤖 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 `@crates/orca-tui/src/surface_projection.rs` around lines 559 - 569, Update the
live reduction logic in reduce_typed_batch to track whether any assistant stream
for response.turn_id has state Discarded. Even when
response_matches_streamed_items returns true, emit response_completed_event
unless no discarded stream exists, preserving reconciliation for discarded
retries. Add a regression test covering a discarded stream and a surviving
stream matching the final response, asserting AssistantResponseCompleted is
emitted.
Orca v0.3.7
Orca v0.3.7 completes the session-context and TUI projection reliability
slice on top of v0.3.6's delegated execution and durable task-state work.
What Changed
first resumed turn. The context limit is derived from the configured model
window, while legacy usage records remain readable.
snapshot overwrite a newer provider context observation. The context footer
therefore remains accurate while the next durable surface batch arrives.
during snapshot and foreground hydration. A completed response that exactly
matches already streamed items is not projected a second time.
one immutable policy snapshot; transcript appends and rewrites share a
cross-process lock; retry and truncation diagnostics remain in task state;
and session completion publishes the complete task registry first.
Compatibility
Saved transcripts with older usage records remain readable. New context
revision and projection fields are runtime-internal and do not change CLI,
JSONL, app-server, ACP, provider, or task identifier contracts.
Verification
cargo fmt --all -- --checkcargo check --workspace --all-targets --lockedrevision-safe projection, assistant stream ordering, and duplicate response
suppression
cargo nextest run --workspace --all-targets --locked --profile ci --no-fail-fastwebsite build, SEO, and published-release verification gates
git diff --checkUpgrade
macOS and Linux native installer:
curl -fsSL https://orcaagent.dev/install.sh | \ INSTALL_DIR=/usr/local/bin ORCA_VERSION=0.3.7 shWindows PowerShell, including workspace sandbox setup:
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Release