Skip to content

Keep native chat /clear in the same conversation - #26579

Merged
brennanb2025 merged 7 commits into
mainfrom
brennanb2025/nc-clear-same-conversation
Oct 8, 2026
Merged

brennanb2025 merged 7 commits into
mainfrom
brennanb2025/nc-clear-same-conversation

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 50 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​2268 $\color{#cf222e}{\Huge{\mathbf{−}}}$​1490 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​778
Prod 99 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1592 $\color{#cf222e}{\Huge{\mathbf{−}}}$​712 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​880

ELI5

Clearing a native chat currently creates another conversation and moves its tab, changing the addresses used by drafts, queued cards and phone rows. The replacement bookkeeping makes a simple context reset depend on relocating the conversation.

/clear now keeps the same chat and tab. Earlier messages remain above one “Context cleared” divider, and the next send starts a fresh agent context. Drafts, attachments, tab placement and queued-card IDs keep their existing keys.

What Changed

Clear refuses while the agent is working or awaiting an answer. Once idle, it releases the provider, proves its release and rechecks admission, then commits an empty provider handle chain, the record boundary, divider, exact ordinary-message-card pause, waiting-command withdrawal and completed command in one transaction. Fresh provider proof creates the first link in that new chain without replacement ancestry. The previous provider session is no longer owned by this chat and can be adopted from provider history elsewhere.

Provider readers use the chain head. The boundary remains for Claude’s stable fresh-context ID and interrupted-start transcript check, suffix-only rewind, restart offers, goal and usage resets, and bounded mail delivery after an in-flight clear. Codex starts a new thread; ACP starts a new session. Rewind preserves the earlier journal and divider, and changes only the current context. Waiting command cards, including /compact, are withdrawn inside that transaction. Ordinary message cards keep their IDs and order and need the next accepted user turn, Resume or Send now; rewinding that accepted turn does not revive the pause.

A /compact arriving during clear waits behind the same conversation lane and receives the existing in-flight-operation refusal; replay still returns a previously recorded answer.

Removed replacement conversation creation, tab moves, queued-card copying, current replacement publication and permanent cleared-chat send refusal. Current-host orchestration forwarding is removed separately in #26610. Existing client readers for older hosts’ replacement results remain because remote hosts and clients update independently.

Why

Conversation identity and provider context have separate lifetimes. Resetting the chain releases the discarded provider context directly and uses the ordinary record codec and ownership index, without an archive, another stored copy or new stream operation. The record boundary still answers which clear owns rewind and mail delivery; the journal supplies its visible divider.

Linked Issue

N/A — maintainer follow-up from a native chat audit.

Visual Proof

Isolated hidden-renderer Codex stand-in: the same tab/session and earlier messages remain above one divider, then the next turn uses a new thread. Durable storage goes from an empty chain after clear to one fresh creation without replacement ancestry; the stand-in records two starts and zero resumes. The captures precede the final main sync, which preserves this visible flow and is covered by the final automated checks. They include unrelated first-launch tips.

Before:

01-before-clear.png

After:

04-after-clear.png

Testing

  • I manually tested these changes locally — hidden Electron stand-in clear/next-send; screenshots inspected and four permitted config hashes unchanged. Rendered draft/image/queue Resume, orchestration custody and real-provider checks are not claimed.
  • Automated tests added/updated for clear rollback/replay, release of old provider ownership, fresh creation without ancestry, provider launch, queue pause/lift, rewind, mail, restart and mobile-scoped calls.
  • Head 5f2c39efb62d includes semantic merge 594b078af979, the rewind mock-target correction and the module splits needed to keep existing line limits, and incorporates fixed main ff4a51c872e, including queued /compact. Focused tests pass 66/66 across four files: ordinary cards around a compact card retain exact pause membership, withdrawal and the context reset roll back together, connected/reconnecting client publications drop the command, clear refuses Working before provider release, and compact arriving during clear is serialized and refused without a card or send.
  • All 351 mobile tests in 22 explicit files passed. Both required real-Claude suites passed 13/13 once at the semantic merge, with the four permitted config hashes unchanged; subsequent corrections change only renderer test imports and move the unchanged consume-error class and replay assertions to dedicated modules; Claude source is unchanged. The full root batch covered 1,897 tests in 141 explicit files: 1,896 passed and one rewind-fixture case failed because main’s new test mocked the module this PR extracted. The corrected complete fixture suite then passed 29/29, with all assertions retained; no failures remain. All four fresh serial queued Node/web/CLI/mobile typechecks passed. After the module split, a fresh Node check and 96 queue/rewind cases in six suites plus 38 consume-store cases passed. Final pre-push checks pass 21/22. The only failure is five mobile import-cycle warnings reproduced independently on exact fixed main ff4a51c872e with the same installed dependencies; all five file/line/column keys match. Both lockfiles are restored to verified committed bytes and the worktree is clean. Frozen installs succeeded in the owned root and mobile directories; both lockfiles remain unchanged.
  • Earlier hidden stand-in QA verifies the visible same-conversation divider and fresh next context. New queued compact/clear rendering, live real Codex/ACP/Pi, Windows/Linux UI, SSH disconnect, phone and paired-app flows remain unverified.

Review

The earlier complete review of 6cf1a71a320 found zero P0–P3 issues. Its P3 dead stored-card pause fallback had been removed; the accepted older-app two-minute rewind hold remains disclosed and bounded. Subsequent a0ff6c2f5d8 resolution review was clean and completed CI had 21 successful and 14 skipped checks; skips are not passes. Main then landed queued /compact and made that head conflict. The coordinator authorized this semantic merge onto fixed ff4a51c872e; local gates are complete with only the proven main mobile-cycle warnings. The resolution review of 5f2c39efb62 found no issues, and its CI finished with 21 passed, 14 skipped and none failed (run); skips are not passes.

Agent skill upstream boundary

  • Not applicable; no upstream skill-installer source or fixtures copied.

Notes

Differences from the common pattern:

  • Temporary: a desktop app built from main between v1.4.222 and this change, connected to a newer host, can keep Send disabled for up to 2 minutes after rewinding past a /clear; updating the app removes it. The existing timeout releases the hold and preserves its returned draft and history; the supported-client-floor cleanup removes this limitation.

  • Intended: the current provider context lives in the record’s ordinary chain; a clear releases every earlier handle while the journal keeps visible conversation history. The boundary stays only for operations that need the identity of that clear.

  • Intended: earlier messages remain visible and rewind cannot cross the divider, per the product decision.

  • Intended: clear preserves the existing refusal while the agent is working and releases only an idle provider before resetting context.

  • Intended: ordinary waiting message cards require user action after clear, with exact membership and existing acceptance/Resume settlement; waiting command cards are withdrawn as in main.

  • Intended: the existing compact separator renders one completed boundary without another notice.

  • Intended: clearing a supervised worker discards its provider instruction preamble while task and custody identity remain; automatic reinjection is outside this change.

  • Temporary: old-host replacement readers remain for mixed remote client/host versions; remove them when supported hosts include in-place clear. Older clients can ignore the optional context floor and retain earlier goal/usage until new facts arrive; remove that limit when the supported-client floor advances.

Checklist

  • Focused on in-place clear and necessary lifecycle readers.
  • Explained the problem, user-facing change, mechanism and choice of design.
  • Accurate clear screenshots attached; the final sync preserves this visible flow.
  • Self-reviewed ownership release, transaction fences and queue lifetime.
  • Cross-platform, SSH, folder workspace, mobile and mixed-version behavior considered.
  • Latest semantic sync: local gates, resolution-only review and exact-head CI complete and classified.

@brennanb2025
brennanb2025 changed the base branch from brennanb2025/nc-clear-inplace to main October 8, 2026 18:55
@brennanb2025
brennanb2025 force-pushed the brennanb2025/nc-clear-same-conversation branch from 5c6a2cd to bda2c6d Compare October 8, 2026 18:55
@brennanb2025

brennanb2025 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor Author

Clearing a native chat used to create a second conversation and move its tab, so drafts, queued cards, phone rows and orchestration addresses depended on replacement bookkeeping. /clear now retains the same conversation, tab and earlier messages above one divider; the next send starts a fresh provider context. Stop and release are proved before one atomic record/journal/receipt commit, and the ordinary provider chain resets so the old provider session can be adopted from history elsewhere.

The maintainer decision removed the requirement for older desktop builds to read the new storage form, so #26545 is closed. This rework uses the ordinary chain and ownership index without an archive or parallel ownership rules; the record boundary remains only where fresh launch, suffix rewind and mail need the clear’s identity. Earlier lifecycle review fixes for rollback/replay, queue pause/lift and bounded mail remain; the fresh rework review found no blocking issues, and its dead stored-card pause fallback is removed. After the single main sync, the final review found zero P0–P3 issues and independently passed 1,351 tests across 111 files, excluding five inherited todos.

Accepted temporary limitation: a desktop app built from main between v1.4.222 and this change, connected to a newer host, can keep Send disabled for up to two minutes after rewinding past a /clear; updating the app removes it. The bounded historical-hook test proves timeout release, retained history and returned draft. Older-host replacement readers remain for independently updated hosts and clients; clearing a supervised worker still discards its old instruction preamble, and automatic reinjection is deferred. #26610 removes current-host orchestration forwarding separately.

Author validation on the final head: 1,092 root tests in 91 files, 168 mobile tests in ten files, all four fresh queued project typechecks and 13 tests in the two required real-Claude suites pass. Local pre-push checks pass 21 of 22; the five unchanged mobile import-cycle warnings reproduce on exact synced main with the same dependencies. Hidden stand-in live QA verifies the same tab/session, earlier transcript, one divider and a fresh provider thread; screenshots are embedded in the body. The permitted configuration hashes match and all recorded rig processes/profiles were cleaned up. Live draft/image/queue Resume, Run/mail/custody/read/stop, SSH/paired, phone-device and Windows/Linux UI flows are not claimed.

Update after the last main sync (head 5f2c39efb62). Main landed #25704, which lets a /compact sent while the agent is working wait in line as a queued card. Combined behaviour, as it now reads for a user:

  • /clear is still refused while the agent is working, with main's plain sentence; nothing is stopped for it.
  • A /compact card still waiting when you /clear is removed in the same step as the divider (the context it would have compacted is gone). Your other waiting messages stay, in order, paused until your next message or Resume.
  • A /compact sent while a /clear is still running gets the same "wait for the conversation operation to finish" refusal an ordinary send gets.

Resolution review of the merge (git show --remerge-diff): no issues. Author validation on this head: 66 focused tests, the full root batch, 351 mobile tests, all four project typechecks and the 13 real-Claude tests pass; pre-push 21 of 22, the one failure being the five mobile import-cycle warnings that reproduce on main.

All CI checks finished on head 5f2c39efb62: 21 passed, 14 skipped, none failed or pending. Skipped jobs (rendered end-to-end, real IME/WSL, Git compatibility, managed hooks, provider contracts, Linux floor builds, main-only mobile tests) are path-filtered or main-only and are not claimed as passes. CI run.

@brennanb2025
brennanb2025 marked this pull request as ready for review October 8, 2026 20:00
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c49d7a52-ad25-469d-8d1c-1e9ef4f38e14
📥 Commits

Reviewing files that changed from the base of the PR and between a0ff6c2 and 5f2c39e.

📒 Files selected for processing (34)
  • config/scripts/vitest-sqlite-runtime-files.mjs
  • src/main/native-chat/agent-session-attachments/agent-session-attachment-claims.test.ts
  • src/main/native-chat/agent-session-journal/journal-context-clear.ts
  • src/main/native-chat/agent-session-journal/journal-context-controller.ts
  • src/main/native-chat/agent-session-journal/journal-queued-messages.ts
  • src/main/native-chat/agent-session-journal/queued-message-consume-error.ts
  • src/main/native-chat/agent-session-journal/queued-message-pause.test.ts
  • src/main/native-chat/agent-session-journal/queued-message-table.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-clear-queued-command.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-mutation-plans.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-compact.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-message-rig-provider.test-fixture.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-mutations.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-rewind-replay.test-fixture.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-rewind.test.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-command-admission.test.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-command-admission.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-command-controller.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-command.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-compaction.ts
  • src/main/runtime/agent-session-conversation-clear-commit.test.ts
  • src/main/runtime/rpc/methods/structured-agent-session.ts
  • src/renderer/src/components/native-chat/NativeChatNoticeRow.tsx
  • src/renderer/src/components/native-chat/NativeChatTranscriptRow.tsx
  • src/renderer/src/components/native-chat/use-structured-agent-session.queued-gating.test.tsx
  • src/renderer/src/components/native-chat/use-structured-agent-session.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/shared/agent-session-conversation-command.ts
💤 Files with no reviewable changes (2)
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-mutations.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/zh.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/ja.json

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

/clear now records a provider-context boundary in the existing conversation instead of creating a replacement session. Journal, provider launch, mailbox, queued-message, and rewind paths use that boundary to distinguish current context. The renderer and mobile client display a context-cleared notice, and the tests cover rewind, restart, tab identity, and older-client behavior.

Priority: ⬇️ Low

Merge Risk: 🔵 Low · up to 5f2c3

Rewind may appear available while a dispatch is unsettled, but the host rejects it safely. This is a bounded usability risk rather than a blocker to merging.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 34.38% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 64 functions across 68 files. (6 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title clearly and concisely describes the primary change: native chat /clear now preserves the same conversation.
Description check Passed The description is comprehensive and covers the user impact, implementation, rationale, visual proof, testing, compatibility limits, review notes, and checklist. The Linked Issue section is marked N/A…
Full details: Docstring Coverage

Explanation

Docstring coverage is 34.38% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 64 functions across 68 files. (6 skipped: 6 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ab38699b-e6b7-468e-b42f-3d70c51e1ded
📥 Commits

Reviewing files that changed from the base of the PR and between 04ac6d6 and 6cf1a71.

📒 Files selected for processing (143)
  • config/scripts/vitest-sqlite-database-runtime-files.mjs
  • config/scripts/vitest-sqlite-runtime-files.mjs
  • mobile/src/session/MobileNativeChatMessage.test.ts
  • mobile/src/session/MobileNativeChatMessage.tsx
  • mobile/src/session/mobile-native-chat-message-styles.ts
  • src/main/acp/acp-structured-context-clear.test.ts
  • src/main/acp/acp-structured-launch-resolution.test.ts
  • src/main/claude/claude-structured-effort-default-at-rest.test.ts
  • src/main/claude/claude-structured-launch-resolution.test.ts
  • src/main/claude/claude-structured-launch-resolution.ts
  • src/main/claude/claude-structured-session-id.ts
  • src/main/codex/codex-structured-launch-resolution.test.ts
  • src/main/native-chat/agent-session-attachments/agent-session-attachment-claims.test.ts
  • src/main/native-chat/agent-session-journal/journal-context-clear.ts
  • src/main/native-chat/agent-session-journal/journal-context-controller.ts
  • src/main/native-chat/agent-session-journal/journal-context-rewind.ts
  • src/main/native-chat/agent-session-journal/journal-derived-turn-scope.ts
  • src/main/native-chat/agent-session-journal/journal-epoch-replacement.ts
  • src/main/native-chat/agent-session-journal/journal-queued-messages.ts
  • src/main/native-chat/agent-session-journal/journal-reducer.ts
  • src/main/native-chat/agent-session-journal/journal-restart-reconciliation.ts
  • src/main/native-chat/agent-session-journal/journal-rewind-submission-retirement.ts
  • src/main/native-chat/agent-session-journal/journal-row-schema.ts
  • src/main/native-chat/agent-session-journal/journal-row-writer.ts
  • src/main/native-chat/agent-session-journal/journal-stop-and-resume-rows.ts
  • src/main/native-chat/agent-session-journal/journal-stop-turn-end.ts
  • src/main/native-chat/agent-session-journal/journal-store.ts
  • src/main/native-chat/agent-session-journal/queued-message-context-clear.test.ts
  • src/main/native-chat/agent-session-journal/queued-message-pause.test.ts
  • src/main/native-chat/agent-session-journal/queued-message-pause.ts
  • src/main/native-chat/agent-session-journal/queued-message-table.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-at-rest-commands.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-attach.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-attachment-admission.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-child-exit.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-clear-rewind.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-ended-child-failure.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-stop-event.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-mutation-plans.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-operation-settlement.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-options-read.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-options-read.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-card-holds.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-command.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-message-rig-provider.test-fixture.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-message-rig.test-fixture.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-messages.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-mutations.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-stop-row.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-registered-definition.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-restart-context-clear.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-restart-resume-set.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-rewind.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-rewind.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-send-block.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-send-preparation.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-send-preparation.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-stop-cause.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-unsent-send-hold.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-working-at-teardown.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-command-admission.test.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-command-admission.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-command-controller.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-command.test.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-command.ts
  • src/main/native-chat/agent-session-wire/structured-conversation-replacements.test.ts
  • src/main/native-chat/agent-session-wire/structured-rewind-journal-body.ts
  • src/main/native-chat/agent-session-wire/structured-rewind-recovery.ts
  • src/main/pi/rpc-launch-resolution.test.ts
  • src/main/runtime/agent-session-conversation-clear-commit.test.ts
  • src/main/runtime/agent-session-conversation-command-record.ts
  • src/main/runtime/agent-session-conversation-receipts.ts
  • src/main/runtime/agent-session-provider-handle-transition.test.ts
  • src/main/runtime/agent-session-record-store.ts
  • src/main/runtime/agent-session-rewind-completion.ts
  • src/main/runtime/agent-session-tab-table.ts
  • src/main/runtime/claude-structured-startup-unanswered-control-request.test.ts
  • src/main/runtime/orca-runtime-prune-mobile-session-tab-group-layout.ts
  • src/main/runtime/orca-runtime-restore-structured-agent-session-tabs-once.ts
  • src/main/runtime/orca-runtime-runtime-id.ts
  • src/main/runtime/orca-runtime-structured-session-restore.test.ts
  • src/main/runtime/orchestration/agent-facing-parity.test.ts
  • src/main/runtime/orchestration/structured-mailbox-pointer-delivery.test.ts
  • src/main/runtime/orchestration/structured-mailbox-pointer-delivery.ts
  • src/main/runtime/orchestration/structured-mailbox-pointer-host.test.ts
  • src/main/runtime/orchestration/structured-mailbox-pointer-host.ts
  • src/main/runtime/orchestration/structured-pointer-operation-id.test.ts
  • src/main/runtime/orchestration/structured-pointer-operation-id.ts
  • src/main/runtime/rpc/methods/structured-agent-session.ts
  • src/main/runtime/rpc/methods/structured-chat-tab-table.test-fixture.ts
  • src/main/runtime/rpc/methods/structured-chat-tab-table.test.ts
  • src/main/runtime/structured-agent-session-startup-tab-restore.test.ts
  • src/main/runtime/structured-chat-coordinator-mail-rig.test-fixture.ts
  • src/main/runtime/structured-chat-coordinator-mail.test.ts
  • src/main/runtime/structured-chat-dispatch-worker-lifecycle.test.ts
  • src/main/runtime/structured-chat-dispatch-worker-mail.test.ts
  • src/main/runtime/structured-claude-pending-rewind.test.ts
  • src/main/runtime/structured-claude-scripted-runtime-test-support.ts
  • src/main/runtime/structured-conversation-tab-replacement.test.ts
  • src/main/runtime/structured-conversation-tab-replacement.ts
  • src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.tsx
  • src/renderer/src/components/native-chat/NativeChatNoticeRow.tsx
  • src/renderer/src/components/native-chat/NativeChatTranscriptRow.tsx
  • src/renderer/src/components/native-chat/structured-agent-session-message-projection.ts
  • src/renderer/src/components/native-chat/use-native-chat-rewind.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-rewind.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-command-write.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-context-usage.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-rewind.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-thread-goal.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-transport-state.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/shared/agent-session-context-clear.test.ts
  • src/shared/agent-session-context-clear.ts
  • src/shared/agent-session-conversation-command.ts
  • src/shared/agent-session-journal-schemas.ts
  • src/shared/agent-session-journal-types.ts
  • src/shared/agent-session-provider-context.test.ts
  • src/shared/agent-session-provider-context.ts
  • src/shared/agent-session-record.ts
  • src/shared/agent-session-resume-marker.ts
  • src/shared/agent-session-rewind.ts
  • src/shared/agent-session-thread-goal.ts
  • src/shared/agent-session-wire.ts
  • src/shared/native-chat-context-usage.ts
  • src/shared/native-chat-provider-retry-runs.ts
  • src/shared/native-chat-types.ts
  • src/shared/structured-agent-session-composer.ts
  • src/shared/structured-agent-session-context-usage.ts
  • src/shared/structured-agent-session-live-turn.ts
  • src/shared/structured-agent-session-message-projection.ts
  • src/shared/structured-agent-session-owed-work.ts
  • src/shared/structured-agent-session-projection.ts
  • src/shared/structured-agent-session-status-block.ts
  • tests/e2e/cross-version-wire/agent-session-clear-old-client.unit.test.ts
  • tests/e2e/cross-version-wire/agent-session-clear-old-tab-mirror.unit.test.ts
💤 Files with no reviewable changes (7)
  • src/main/native-chat/agent-session-wire/structured-conversation-replacements.test.ts
  • src/main/runtime/structured-conversation-tab-replacement.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
  • src/main/runtime/orca-runtime-prune-mobile-session-tab-group-layout.ts
  • src/main/runtime/orca-runtime-runtime-id.ts
  • src/main/runtime/structured-conversation-tab-replacement.ts
  • src/main/runtime/orca-runtime-restore-structured-agent-session-tabs-once.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.

Comment on lines +40 to +47
* derive for it.
*/
show(sessionId: string, tabId?: string): void {
if (this.tabBySession.has(sessionId)) {
return
}
const derived = structuredAgentSessionTabId(sessionId)
const held = (candidate: string): boolean => this.sessionByTab.has(candidate)
this.put(tabId ?? (held(derived) ? reopenedTabId(sessionId, held) : derived), sessionId)
this.put(tabId ?? derived, sessionId)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Keep a fallback when another session holds the derived tab ID.

This change removes the fallback in show() that minted a -reopened ID when the derived ID was already in use. A held derived ID was the normal case for data written by earlier builds. On those builds, /clear ran move(source, replacement), which gave the source's tab ID structured-agent-session-<source> to the replacement session. The store loads that persisted mapping into AgentSessionTabTable. If a user then reveals the old source conversation from history, show(source) passes the derived ID to put(). put() finds that the replacement owns the ID and throws agent_session_conflict / tabIdTaken. Before this change, the source got a reopened tab. Now the reveal fails for every conversation an earlier build cleared. The new tests do not cover this path, because every clear now keeps the same session.

Restore the fallback, but only for the case without a reserved ID.

🐛 Proposed fix
   show(sessionId: string, tabId?: string): void {
     if (this.tabBySession.has(sessionId)) {
       return
     }
     const derived = structuredAgentSessionTabId(sessionId)
-    this.put(tabId ?? derived, sessionId)
+    if (tabId !== undefined) {
+      this.put(tabId, sessionId)
+      return
+    }
+    // Records from earlier builds can hold this id on a /clear replacement.
+    let candidate = derived
+    for (let suffix = 1; this.sessionByTab.has(candidate); suffix++) {
+      candidate = suffix === 1 ? `${derived}-reopened` : `${derived}-reopened-${suffix}`
+    }
+    this.put(candidate, sessionId)
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* derive for it.
*/
show(sessionId: string, tabId?: string): void {
if (this.tabBySession.has(sessionId)) {
return
}
const derived = structuredAgentSessionTabId(sessionId)
const held = (candidate: string): boolean => this.sessionByTab.has(candidate)
this.put(tabId ?? (held(derived) ? reopenedTabId(sessionId, held) : derived), sessionId)
this.put(tabId ?? derived, sessionId)
* derive for it.
*/
show(sessionId: string, tabId?: string): void {
if (this.tabBySession.has(sessionId)) {
return
}
const derived = structuredAgentSessionTabId(sessionId)
if (tabId !== undefined) {
this.put(tabId, sessionId)
return
}
// Records from earlier builds can hold this id on a /clear replacement.
let candidate = derived
for (let suffix = 1; this.sessionByTab.has(candidate); suffix++) {
candidate = suffix === 1 ? `${derived}-reopened` : `${derived}-reopened-${suffix}`
}
this.put(candidate, sessionId)

Comment on lines +61 to +67
const boundary =
getStructuredAgentSessionHost()?.deps.store.getRecord(sessionId)?.providerContextBoundary
return {
submissions: boundary
? snapshot.submissions.filter((submission) => submission.fence > boundary.afterFence)
: snapshot.submissions
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
# Find how a submission's fence is assigned at accept vs. handover.
rg -nP -C4 '\bfence\b' src/main/native-chat/agent-session-journal/journal-submission*.ts src/main/native-chat/agent-session-journal/journal-reducer.ts | head -200
rg -nP -C3 'handedOverAt|handoverRecorded' src/main/native-chat/agent-session-journal | head -80

Repository: stablyai/orca

Length of output: 22740


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- relevant definitions and references ---'
rg -n -F --glob '*.ts' -- 'readPointerSessionFacts' src/main
rg -n -F --glob '*.ts' -- 'decideStructuredPointerAttempt' src/main
rg -n -F --glob '*.ts' -- 'agentSessionCurrentContextRows' src/main
rg -n -F --glob '*.ts' -- 'appendSubmission' src/main/native-chat/agent-session-journal
rg -n -F --glob '*.ts' -- 'resolveDispatch' src/main/native-chat/agent-session-journal
printf '%s\n' '--- journal submission and dispatch implementations ---'
sed -n '1,190p' src/main/native-chat/agent-session-journal/journal-submission-fold.ts
sed -n '1,180p' src/main/native-chat/agent-session-journal/journal-dispatch-reducer.ts
printf '%s\n' '--- pointer host and decision logic ---'
sed -n '1,180p' src/main/runtime/orchestration/structured-mailbox-pointer-host.ts
rg -n -C8 -F --glob '*.ts' -- 'decideStructuredPointerAttempt' src/main
printf '%s\n' '--- current-context filtering ---'
rg -n -C12 -F --glob '*.ts' -- 'agentSessionCurrentContextRows' src/main

Repository: stablyai/orca

Length of output: 42350


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- references ---'
rg -n -F --glob '*.ts' -- 'readPointerSessionFacts' src/main || true
rg -n -F --glob '*.ts' -- 'decideStructuredPointerAttempt' src/main || true
rg -n -F --glob '*.ts' -- 'agentSessionCurrentContextRows' src/main || true
printf '%s\n' '--- journal submission fold ---'
sed -n '1,190p' src/main/native-chat/agent-session-journal/journal-submission-fold.ts
printf '%s\n' '--- dispatch reducer ---'
sed -n '1,180p' src/main/native-chat/agent-session-journal/journal-dispatch-reducer.ts
printf '%s\n' '--- pointer host ---'
sed -n '1,180p' src/main/runtime/orchestration/structured-mailbox-pointer-host.ts
printf '%s\n' '--- pointer decision context ---'
rg -n -C12 -F --glob '*.ts' -- 'decideStructuredPointerAttempt' src/main || true
printf '%s\n' '--- current context context ---'
rg -n -C16 -F --glob '*.ts' -- 'agentSessionCurrentContextRows' src/main || true

Repository: stablyai/orca

Length of output: 42668


🏁 Script executed:

printf '%s\n' '--- caller and fence flow ---'
rg -n -C10 -F --glob '*.ts' -- 'appendSubmission({' src/main
rg -n -C10 -F --glob '*.ts' -- 'resolveDispatch({' src/main/native-chat src/main/runtime
rg -n -C10 -F --glob '*.ts' -- 'acquire' src/main/native-chat/agent-session-journal src/main/runtime/orchestration
printf '%s\n' '--- pointer symbols ---'
rg -n -C20 -F --glob '*.ts' -- 'readPointerSessionFacts' src/main
rg -n -C20 -F --glob '*.ts' -- 'decideStructuredPointerAttempt' src/main
rg -n -C20 -F --glob '*.ts' -- 'currentContextClearOperationId' src/main
printf '%s\n' '--- boundary and accepted-sequence symbols ---'
rg -n -C14 -F --glob '*.ts' -- 'providerContextBoundary' src/main
rg -n -C12 -F --glob '*.ts' -- 'acceptedSequence' src/main/native-chat/agent-session-journal

Repository: stablyai/orca

Length of output: 45663


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- pointer decision implementation ---'
sed -n '1,190p' src/main/runtime/orchestration/structured-pointer-operation-id.ts
printf '%s\n' '--- context-clear implementation ---'
sed -n '1,220p' src/shared/agent-session-context-clear.ts
printf '%s\n' '--- submission writer and store append contract ---'
sed -n '1,180p' src/main/native-chat/agent-session-journal/journal-submission-writer.ts
sed -n '70,125p' src/main/native-chat/agent-session-journal/journal-store-contracts.ts
sed -n '300,370p' src/main/native-chat/agent-session-journal/journal-store.ts
printf '%s\n' '--- send path and fence inputs ---'
rg -n -C12 -F --glob '*.ts' -- 'expectedRuntimeFence' src/main/native-chat src/main/runtime/orchestration
rg -n -C12 -F --glob '*.ts' -- 'appendSubmission(submission' src/main/native-chat src/main/runtime
rg -n -C12 -F --glob '*.ts' -- 'runtimeFence' src/main/native-chat/agent-session-wire | head -240
printf '%s\n' '--- boundary creation and fields ---'
rg -n -C14 -F --glob '*.ts' -- 'providerContextBoundary' src/main/native-chat src/main/runtime src/shared

Repository: stablyai/orca

Length of output: 45661


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- exact pointer decision file ---'
nl -ba src/main/runtime/orchestration/structured-pointer-operation-id.ts | sed -n '35,175p'
printf '%s\n' '--- exact context-clear file ---'
nl -ba src/shared/agent-session-context-clear.ts | sed -n '1,180p'
printf '%s\n' '--- exact append implementation ---'
nl -ba src/main/native-chat/agent-session-journal/journal-store.ts | sed -n '325,360p'
nl -ba src/main/native-chat/agent-session-journal/journal-submission-writer.ts | sed -n '1,115p'
printf '%s\n' '--- send path definitions ---'
rg -n -F --glob '*.ts' -- 'function sendAgentTurn' src/main
rg -n -F --glob '*.ts' -- 'function performSend' src/main
rg -n -F --glob '*.ts' -- 'handoverRecorded' src/main/native-chat/agent-session-wire

Repository: stablyai/orca

Length of output: 17821


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- pointer resolver callers ---'
rg -n -C18 -F --glob '*.ts' -- 'resolveStructuredPointerOperation(' src/main/runtime
printf '%s\n' '--- current fence and pointer host contract ---'
rg -n -C14 -F --glob '*.ts' -- 'currentFence(sessionId' src/main
rg -n -C14 -F --glob '*.ts' -- 'expectedRuntimeFence:' src/main/runtime/orchestration
printf '%s\n' '--- send context fence assignment ---'
nl -ba src/main/native-chat/agent-session-wire/structured-agent-session-turns.ts | sed -n '130,180p'

Repository: stablyai/orca

Length of output: 42039


Keep post-clear pointer submissions visible until handover.

structured-mailbox-pointer-delivery.ts reads the lease fence before sending, and performSend records that fence before the dispatch row updates it. While the cleared chat is at rest, that fence can equal boundary.afterFence. The filter then removes the pending submission.

decideStructuredPointerAttempt returns park only when it finds the matching pending submission. If the filter removes it, the resolver can mint another operation for the same batch.

Use the accepted-sequence current-context boundary for submissions after the clear. Retain the existing fence fallback when a rewind removed the clear marker, so older submissions remain excluded.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0fe97197-992c-4f0c-8672-217a82d13ffd
📥 Commits

Reviewing files that changed from the base of the PR and between 6cf1a71 and a0ff6c2.

📒 Files selected for processing (2)
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-transport-state.ts
💤 Files with no reviewable changes (1)
  • src/main/native-chat/agent-session-wire/structured-agent-session-host.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.

queueSendsNext,
backgroundTasks
backgroundTasks,
conversationBusy: Boolean(turnId || backgroundTasks.isMonitoring)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
# Inspect unanswered-dispatch and background-task state calculations, plus their renderer use.
rg -n -C 6 '\bhasUnansweredStructuredAgentSessionDispatch\b|\bstructuredSessionBackgroundTasksView\b|\bconversationBusy\b' \
  src/shared src/renderer/src/components/native-chat

Repository: stablyai/orca

Length of output: 39133


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- transport state ---'
nl -ba src/renderer/src/components/native-chat/use-structured-agent-session-transport-state.ts | sed -n '1,110p'
printf '%s\n' '--- session state construction and rewind call ---'
nl -ba src/renderer/src/components/native-chat/use-structured-agent-session.ts | sed -n '130,245p'
printf '%s\n' '--- unanswered dispatch rule ---'
nl -ba src/shared/structured-agent-session-unanswered-dispatch.ts | sed -n '1,100p'
printf '%s\n' '--- main-agent working rule ---'
nl -ba src/shared/structured-agent-session-main-agent-working.ts | sed -n '1,60p'
printf '%s\n' '--- rewind definitions and callers ---'
rg -n -C 8 --glob '*.{ts,tsx}' 'useStructuredAgentSessionRewind|rewind.*blocked|blocked.*rewind|rewindBehind|rewind' src/renderer src/shared src/main 2>/dev/null | head -n 500
printf '%s\n' '--- host admission/rewind terms ---'
rg -n -C 8 --glob '*.{ts,tsx}' 'conversation.*rewind|rewind.*conversation|rewind.*busy|busy.*rewind|rewind.*admission' src 2>/dev/null | head -n 300

Repository: stablyai/orca

Length of output: 42325


🏁 Script executed:

printf '%s\n' '--- target hook ---'
nl -ba src/renderer/src/components/native-chat/use-structured-agent-session-transport-state.ts | sed -n '1,90p'
printf '%s\n' '--- rewind hook references ---'
rg -n -C 10 --glob '*.{ts,tsx}' 'useStructuredAgentSessionRewind|rewindBehind|rewind.*blocked|blocked.*rewind' src/renderer src/shared
printf '%s\n' '--- host rewind handlers and admission ---'
rg -n -C 10 --glob '*.{ts,tsx}' 'rewind|rewindBehind|conversationBusy|hasUnansweredStructuredAgentSessionDispatch|isStructuredAgentSessionMainAgentWorking' src/main src/shared src/renderer | head -n 800

Repository: stablyai/orca

Length of output: 42301


Include unanswered dispatches in conversationBusy.

An unanswered dispatch can make isWorking true before a provider turn exists. conversationBusy can still be false when no background task is monitoring, so the renderer leaves rewind unblocked.

Suggested fix
--- "a/src/renderer/src/components/native-chat/use-structured-agent-session-transport-state.ts"
+++ "b/src/renderer/src/components/native-chat/use-structured-agent-session-transport-state.ts"
@@ -71,6 +71,6 @@
     /** Working only because the queue is about to send: nothing is in flight to stop yet. */
     queueSendsNext,
     backgroundTasks,
-    conversationBusy: Boolean(turnId || backgroundTasks.isMonitoring)
+    conversationBusy: Boolean(isWorking || backgroundTasks.isMonitoring)
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
conversationBusy: Boolean(turnId || backgroundTasks.isMonitoring)
conversationBusy: Boolean(isWorking || backgroundTasks.isMonitoring)

@brennanb2025
brennanb2025 merged commit bb44f74 into main Oct 8, 2026
35 checks passed
brennanb2025 added a commit that referenced this pull request Oct 9, 2026
Main's #26579 keeps a native chat in the same session across /clear, so a
message's sender id still names the live chat. Remove the host's
orchestration-root projection, the optional status field, and the renderer's
lineage lookup and feed capability probe that only served it.
brennanb2025 added a commit that referenced this pull request Oct 9, 2026
…e, clickable on the queued card too (#26357)

* feat(native-chat): name an agent's message by its current title, and open it from the queued card

The sender line on another agent's message and on its queued card now shows the
name Orca shows for that agent right now (its sidebar agent row or chat tab
name), falling back to the name recorded when it was sent. The queued card's
names open the sender, as the transcript row's already do.

* fix(orchestration): name a CLI agent sender by its tab's own name, not just its agent

A terminal agent's recorded sender name used only a manual tab rename, else the
agent type, so mail from CLI agents read as "Codex" or "Claude". The host now
names every sender the way Orca shows it: a chat by its rename or saved name, a
terminal agent by its sidebar agent row's name (rename, quick command, generated
or meaningful live title; a split pane only by its own title). The task title and
generic agent label are fallbacks. The renderer shows the live own name, else the
recorded one.

* fix(orchestration): preserve known sender names in message snapshots

* Preserve sender names across chat clears and terminal reuse

* fix: keep sender links on the recipient host across older runtimes

* test: type sender naming fixtures with their declared identities

* Fix sender ownership publication after clearing a chat

* Drop /clear sender lineage now that /clear keeps the same conversation

Main's #26579 keeps a native chat in the same session across /clear, so a
message's sender id still names the live chat. Remove the host's
orchestration-root projection, the optional status field, and the renderer's
lineage lookup and feed capability probe that only served it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant