Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
224 commits
Select commit Hold shift + click to select a range
c867bd2
refactor(native-chat): remove the unused terminal handoff
brennanb2025 Sep 25, 2026
eab4ef1
fix(native-chat): never let the pre-stop snapshot hold a chat's stop
brennanb2025 Sep 25, 2026
abafbbc
refactor(native-chat): drop helpers only the terminal handoff called
brennanb2025 Sep 25, 2026
3cbf6b5
docs(native-chat): stop citing the removed handoff in lifecycle comments
brennanb2025 Sep 25, 2026
e048579
test(native-chat): type the stalled snapshot drain without a cast
brennanb2025 Sep 25, 2026
b50c574
test(native-chat): pin that a start dead before proving owes no settl…
brennanb2025 Sep 25, 2026
12efdef
fix(native-chat): keep the owner-status read behind an in-flight attach
brennanb2025 Sep 25, 2026
42d10ee
refactor(terminal): remove the agent-session PTY write gate
brennanb2025 Sep 25, 2026
0483915
refactor(native-chat): drop the transcript helpers only the handoff c…
brennanb2025 Sep 25, 2026
d0f4dae
fix(native-chat): stop calling a starting chat "mid-handoff"
brennanb2025 Sep 25, 2026
faecece
test(native-chat): type the stand-in roster decoder without a cast
brennanb2025 Sep 25, 2026
250250e
refactor(codex): name the pinned rollout lookup for what it does
brennanb2025 Sep 25, 2026
b588185
refactor(native-chat): type the owner-status reply as the host sends it
brennanb2025 Sep 25, 2026
35742fd
refactor(native-chat): normalize terminal-handoff lease values once a…
brennanb2025 Sep 25, 2026
54ce5fc
refactor(native-chat): stop threading the owner kind through a reserv…
brennanb2025 Sep 25, 2026
713b126
test(native-chat): pin the legacy-lease rewrite with a transaction th…
brennanb2025 Sep 25, 2026
44d7977
fix(native-chat): name a chat write by its target, not the owner gene…
brennanb2025 Sep 25, 2026
6dad39a
fix(native-chat): every journal append reaches the chats that are open
brennanb2025 Sep 25, 2026
97bf3bb
test(native-chat): an epoch replacement reaches the open chat
brennanb2025 Sep 25, 2026
427dc8d
test(native-chat): each row reaches an open chat once, and a live han…
brennanb2025 Sep 25, 2026
2bd44f5
test(native-chat): give the legacy-lease store test a tab id so the b…
brennanb2025 Sep 25, 2026
f79eb9b
test(worktree-activation): restore the OMP surfaced-agent resume test
brennanb2025 Sep 25, 2026
50d2e33
perf(native-chat): a publish behind a delivered commit reads nothing
brennanb2025 Sep 25, 2026
bd72b13
test(native-chat): state why the teardown test's fake journal is safe…
brennanb2025 Sep 25, 2026
fa9b76a
docs(native-chat): say mutation admission checks only the writer lease
brennanb2025 Sep 25, 2026
5435973
docs(native-chat): drop the send rebase from comments that still desc…
brennanb2025 Sep 25, 2026
8fd4558
Merge #22811 into the PR 1 base
brennanb2025 Sep 25, 2026
12dde37
Merge #22812 into the PR 1 base
brennanb2025 Sep 25, 2026
c753e8a
fix(native-chat): a message is accepted, then delivered
brennanb2025 Sep 25, 2026
82f9bfd
fix(native-chat): settle queued messages only for the child that ended
brennanb2025 Sep 25, 2026
f3e52d2
fix(native-chat): an adoption that fails to import keeps the conversa…
brennanb2025 Sep 25, 2026
29a340b
perf(native-chat): the recovering open reads the journal once
brennanb2025 Sep 25, 2026
c7a652f
fix(native-chat): an attach that fails after indexing its child leave…
brennanb2025 Sep 25, 2026
34d0bb0
fix(native-chat): a withdrawn message shows no error, and a rejection…
brennanb2025 Sep 25, 2026
46b6472
fix(orchestration): a structured worker whose agent outlasts the prea…
brennanb2025 Sep 25, 2026
283819d
fix(native-chat): a message rejected while its chat was closed reads …
brennanb2025 Sep 25, 2026
40dabe8
test(orchestration): name why the readiness settlement fakes are cast
brennanb2025 Sep 25, 2026
31444bf
fix(native-chat): keep each pane's own fence on frames so a failed re…
brennanb2025 Sep 25, 2026
494d8c7
docs(native-chat): drop the fence from the admission the send effects…
brennanb2025 Sep 25, 2026
0e74529
docs(native-chat): give the fence move on release the reason that sti…
brennanb2025 Sep 25, 2026
6c16f35
docs(native-chat): stop citing a write fence check in launch and mail…
brennanb2025 Sep 25, 2026
d2f646b
refactor(native-chat): the provider child is its own record
brennanb2025 Sep 25, 2026
25fa38a
Merge remote-tracking branch 'origin/main' into brennanb2025/chat-wri…
brennanb2025 Sep 25, 2026
aa56b50
fix(native-chat): the delivery loop alone settles a message its start…
brennanb2025 Sep 25, 2026
d23cca4
Merge #22812 and main into PR 1
brennanb2025 Sep 25, 2026
4993696
refactor(native-chat): a stopped child ends on the one reading of its…
brennanb2025 Sep 25, 2026
a2ad8f2
feat(native-chat): the host says it accepts a send before any agent h…
brennanb2025 Sep 25, 2026
48def96
refactor(native-chat): an attach never opens a journal of its own
brennanb2025 Sep 25, 2026
da65d57
fix(native-chat): a moved fence resends nothing on a host that accept…
brennanb2025 Sep 25, 2026
0184a3d
refactor(native-chat): a child's end says whether the user or the hos…
brennanb2025 Sep 25, 2026
12577d8
fix(native-chat): a chat whose only work is a queued message is not o…
brennanb2025 Sep 25, 2026
a59eed9
test(native-chat): type the queued-message fixtures in the resume-off…
brennanb2025 Sep 25, 2026
ccaf412
fix(native-chat): a start that dies while a message waits on it is th…
brennanb2025 Sep 25, 2026
0efca93
docs(native-chat): say what an attach's open conversation and unconfi…
brennanb2025 Sep 25, 2026
74d6506
test(native-chat): pin what a failed start settles, and what a resume…
brennanb2025 Sep 25, 2026
9c671f1
test(native-chat): the failed-start pins fail on what the message bec…
brennanb2025 Sep 25, 2026
80ccb33
test(orchestration): the preamble's host stub is typed, not cast
brennanb2025 Sep 25, 2026
227e135
fix(native-chat): a Stop that names no turn stops what the conversati…
brennanb2025 Sep 26, 2026
6fdeb89
fix(native-chat): Stop is there from the moment a message is sent
brennanb2025 Sep 26, 2026
6ceaa52
fix(native-chat): Stop before a turn is gated on its own host capability
brennanb2025 Sep 26, 2026
9de2655
test(native-chat): a build advertises conversation stop exactly where…
brennanb2025 Sep 26, 2026
e6dadd1
Merge main into PR 1
brennanb2025 Sep 26, 2026
6374f35
Merge main into PR 1
brennanb2025 Sep 27, 2026
724b961
Merge main into PR 1
brennanb2025 Sep 27, 2026
c39151d
fix(native-chat): a view never restarts a chat whose last start failed
brennanb2025 Sep 27, 2026
9613178
test(native-chat): start the child the loop waits on with an attach, …
brennanb2025 Sep 27, 2026
0224459
fix(native-chat): settle a gone generation's turn wherever a conversa…
brennanb2025 Sep 27, 2026
2276cef
test(native-chat): prove the next child's start settles the turn an e…
brennanb2025 Sep 27, 2026
9275869
test(native-chat): count a failed start's rows by row, not by text
brennanb2025 Sep 27, 2026
158ca0a
test(native-chat): give the failed-start and stale-turn waits a loade…
brennanb2025 Sep 27, 2026
8f66a25
test(native-chat): pin the open's and the send's start and row counts…
brennanb2025 Sep 27, 2026
ad04c3b
fix(native-chat): settle a gone generation's turn at every open but a…
brennanb2025 Sep 27, 2026
05b8b93
test(native-chat): hold the create's start open until the views bind
brennanb2025 Sep 27, 2026
0477775
Merge PR 1 into S
brennanb2025 Sep 27, 2026
d5716f3
Merge main into PR 1
brennanb2025 Sep 27, 2026
c263d83
fix(native-chat): Stop reads the one working rule every session list …
brennanb2025 Sep 27, 2026
ad5bfa3
test(native-chat): a rate-limit retry pins only that no turn opens, n…
brennanb2025 Sep 27, 2026
f13f6cc
Merge PR 1 into S
brennanb2025 Sep 27, 2026
d5b3a4f
fix(native-chat): Stop leaves a message waiting on its Retry, and doe…
brennanb2025 Sep 27, 2026
5f1f71f
test(native-chat): the chat's Stop and a session list read the main a…
brennanb2025 Sep 27, 2026
ccde2c9
refactor(mobile): the chat reads the main agent's working state throu…
brennanb2025 Sep 27, 2026
f75fe04
fix(codex): a Stop naming no turn never interrupts an earlier turn
brennanb2025 Sep 27, 2026
db36d0a
fix(native-chat): a Stop naming no turn never says a turn had already…
brennanb2025 Sep 27, 2026
740ed1f
Merge main into PR 1
brennanb2025 Sep 28, 2026
8276562
Merge PR 1 into S
brennanb2025 Sep 28, 2026
27a3398
fix(native-chat): one Stop the host could not settle no longer refuse…
brennanb2025 Sep 28, 2026
7002b1b
refactor(native-chat): drop the composer's second error formatter
brennanb2025 Sep 28, 2026
cb5ce82
test(native-chat): pin the reason on a message rejected while its cha…
brennanb2025 Sep 28, 2026
ed6ab4b
Merge PR 1 into S
brennanb2025 Sep 28, 2026
a322c8a
test(native-chat): read Stop operation ids without a cast
brennanb2025 Sep 28, 2026
20402c8
fix(native-chat): a Stop whose answer was lost no longer swallows the…
brennanb2025 Sep 28, 2026
c6e5e65
refactor(native-chat): a Stop naming no target keeps its operation id…
brennanb2025 Sep 28, 2026
cc20a86
test(native-chat): read the Stop fences without a cast
brennanb2025 Sep 28, 2026
61f99b8
test(native-chat): pin the new id for a named cancel the host could n…
brennanb2025 Sep 28, 2026
cf106f1
fix(native-chat): a Stop pressed after a new message stops it, even w…
brennanb2025 Sep 28, 2026
f2e5b04
fix(native-chat): Stop no longer blinks off as Claude opens the turn …
brennanb2025 Sep 28, 2026
04c0885
Merge main into S
brennanb2025 Sep 28, 2026
e207887
fix(native-chat): a message a Stop withdrew comes back to its sender'…
brennanb2025 Sep 28, 2026
1431167
fix(native-chat): withdrawn text put back during an IME composition i…
brennanb2025 Sep 28, 2026
2b49021
test(native-chat): pin that only a withdrawn message comes back to th…
brennanb2025 Sep 28, 2026
c4ddc1f
test(native-chat): set up the composer's window API for every describ…
brennanb2025 Sep 28, 2026
badb424
docs(native-chat): note that the withdrawn check reads the legacy rea…
brennanb2025 Sep 28, 2026
2489cdd
test(native-chat): pin that text put back mid-composition shows once,…
brennanb2025 Sep 28, 2026
1f89467
Merge main into S
brennanb2025 Sep 28, 2026
ba56ccd
feat(native-chat): host-owned queued-message draft store in the sessi…
brennanb2025 Sep 28, 2026
7f7290a
feat(native-chat): queued-messages wire contract, dark capability, an…
brennanb2025 Sep 28, 2026
76f9037
feat(native-chat): queue a capable mid-turn send as a draft, drain it…
brennanb2025 Sep 28, 2026
77aea97
test(native-chat): pin mid-turn queueing against the real host
brennanb2025 Sep 28, 2026
fdc3a48
test(native-chat): read the queued receipt ids before the wait closures
brennanb2025 Sep 28, 2026
6932694
chore(native-chat): SAFETY rationales on the sqlite row casts and a c…
brennanb2025 Sep 28, 2026
0c8c7c8
fix(native-chat): queued-draft bookkeeping never costs a publish, an …
brennanb2025 Sep 28, 2026
45f091d
fix(native-chat): a Stop that withdraws a consumed draft's send gives…
brennanb2025 Sep 28, 2026
3bb4a69
perf(native-chat): the queued-draft drain takes no serialized step wh…
brennanb2025 Sep 28, 2026
f916070
fix(native-chat): a clear withdraws queued text only for a caller tha…
brennanb2025 Sep 28, 2026
3eb7abb
fix(native-chat): a draft pause that commits no journal row still rea…
brennanb2025 Sep 28, 2026
fbbaec3
fix(native-chat): a failed clear wakes the queued drain, a failed Sto…
brennanb2025 Sep 28, 2026
c33375c
refactor(native-chat): the draft store notifies through the journal's…
brennanb2025 Sep 28, 2026
cedee2c
fix(native-chat): a Stop with no drafts writes nothing, and a failed …
brennanb2025 Sep 28, 2026
ddeb509
fix(native-chat): a capable Stop with no drafts writes nothing
brennanb2025 Sep 28, 2026
6e8023f
refactor(native-chat): Stop and /clear never withdraw queued drafts; …
brennanb2025 Sep 28, 2026
3a58616
feat(native-chat): a restart hold lifts like a Stop's, and paused car…
brennanb2025 Sep 28, 2026
6414f7d
fix(native-chat): only a client's own send lifts a Stop's queue pause
brennanb2025 Sep 28, 2026
b8c3d64
fix(native-chat): a Stop's queue pause lifts when the user's send sta…
brennanb2025 Sep 28, 2026
5d2a3c5
fix(native-chat): a consumed draft's turn starting lifts a Stop's que…
brennanb2025 Sep 28, 2026
f740887
fix(native-chat): queue a capable send behind a /compact and re-scope…
brennanb2025 Sep 28, 2026
af4bb4e
feat(native-chat): queued mid-turn drafts become editable cards above…
brennanb2025 Sep 28, 2026
2c02203
fix(native-chat): queued-draft restore survives a lost answer and an …
brennanb2025 Sep 28, 2026
ff433c4
fix(native-chat): a lost Stop never lands on newer work; the steer ch…
brennanb2025 Sep 28, 2026
02a0366
fix(native-chat): a send the host visibly holds as a draft frees the …
brennanb2025 Sep 28, 2026
2398bf4
fix(native-chat): Steer hands focus to the composer like Edit and Delete
brennanb2025 Sep 28, 2026
0eee8a3
fix(native-chat): a lost /clear stops replaying within seconds, so se…
brennanb2025 Sep 28, 2026
c79ea84
refactor(native-chat): queued drafts stay paused cards; no draft text…
brennanb2025 Sep 28, 2026
0390989
test(native-chat): drop the removed tabId option from the queued gati…
brennanb2025 Sep 28, 2026
5c4837a
fix(native-chat): paused cards caption per published reason; first ca…
brennanb2025 Sep 28, 2026
e348e0d
fix(native-chat): a paused or returned card's Send tooltip no longer …
brennanb2025 Sep 28, 2026
95baa2e
fix(native-chat): show the queue follow-ups switch only when the host…
brennanb2025 Sep 28, 2026
c9aaac1
fix(settings): find the Queue follow-ups switch when searching "queue"
brennanb2025 Sep 28, 2026
8a6f0d7
Merge origin/main (with #23026 squash-merged) into mid-turn-queue-host
brennanb2025 Sep 29, 2026
a10d106
Merge the rebuilt mid-turn-queue-host (main with #23026) into mid-tur…
brennanb2025 Sep 29, 2026
a7d6903
fix(native-chat): a returned queued card carries the typed rejection …
brennanb2025 Sep 29, 2026
9bacfea
fix(native-chat): say why Stop keeps a dispatching queue send that is…
brennanb2025 Sep 29, 2026
7e6d31f
Merge commit 'a7d690335cf' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
39a75e3
fix(native-chat): word a returned queued card from its typed rejectio…
brennanb2025 Sep 29, 2026
0598a54
fix(native-chat): fit the queue to main's typed rejections and compac…
brennanb2025 Sep 29, 2026
f2d79c8
Merge commit '0598a54620d' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
b4403cc
fix(native-chat): a returned queued card's words leave out sending again
brennanb2025 Sep 29, 2026
c7d637f
fix(native-chat): a queued send in doubt that survives a Stop waits f…
brennanb2025 Sep 29, 2026
d453127
fix(native-chat): a withdrawn send the host returns as a card is not …
brennanb2025 Sep 29, 2026
925f61c
fix(native-chat): a send stops asking the host to queue it once the h…
brennanb2025 Sep 29, 2026
5527f12
fix(native-chat): draft bookkeeping can never roll back the journal r…
brennanb2025 Sep 29, 2026
5b234d4
fix(native-chat): a draft a Stop or restart took back waits again ins…
brennanb2025 Sep 29, 2026
e2b11bd
fix(native-chat): Delete and Send on a queued card answer at once dur…
brennanb2025 Sep 29, 2026
fd8ad79
fix(native-chat): a re-sent returned card drops the refusal it came b…
brennanb2025 Sep 29, 2026
5d077cb
perf(native-chat): the queue gate reads pending prompts without rende…
brennanb2025 Sep 29, 2026
5868371
fix(native-chat): a Stop that fails leaves the queued cards as it fou…
brennanb2025 Sep 29, 2026
348a8c9
docs(native-chat): confirmed cancellation is no longer a queue rollou…
brennanb2025 Sep 29, 2026
9ee2441
docs(native-chat): the Claude fold receipt and turn-owner bars have l…
brennanb2025 Sep 29, 2026
3fca898
Merge commit '9ee2441655a' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
dc716df
test(native-chat): type the returned-card restore test's hook props
brennanb2025 Sep 29, 2026
ab80175
fix(native-chat): a draft a Stop put back stays visible as a card
brennanb2025 Sep 29, 2026
3a92694
fix(native-chat): Send on a queued card during a /compact is refused …
brennanb2025 Sep 29, 2026
4f8deb3
fix(native-chat): a Stop that fails after reaching the agent keeps th…
brennanb2025 Sep 29, 2026
987ca50
fix(native-chat): an unanswered capability probe no longer rewrites a…
brennanb2025 Sep 29, 2026
0b1fa80
fix(native-chat): a skipped draft settlement heals on the next drain …
brennanb2025 Sep 29, 2026
80d97d3
fix(native-chat): a queued send in flight when Stop lands is never re…
brennanb2025 Sep 29, 2026
b9229ac
fix(native-chat): one id is never recorded as a submission twice
brennanb2025 Sep 29, 2026
a9b2d39
fix(native-chat): a waiting draft whose first send the agent echoed i…
brennanb2025 Sep 29, 2026
3316172
feat(native-chat): a submission names the queued draft it hands off
brennanb2025 Sep 29, 2026
f2efb10
refactor(native-chat): every queued draft goes out under a fresh subm…
brennanb2025 Sep 29, 2026
7126a9f
Merge commit 'f2efb102bd3' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
f9f5feb
refactor(native-chat): a queued send is matched to its hand-off by qu…
brennanb2025 Sep 29, 2026
14ea5a6
test(native-chat): read the outbox only after the replayed send's ans…
brennanb2025 Sep 29, 2026
88e4398
fix(native-chat): an echo withdraws a draft only if its rejected hand…
brennanb2025 Sep 29, 2026
8441381
fix(native-chat): a skipped echo withdrawal is re-derived before the …
brennanb2025 Sep 29, 2026
b05dcaf
fix(native-chat): a rolled-back journal append leaves no draft state …
brennanb2025 Sep 29, 2026
0aa2b6d
fix(native-chat): a replay of a deleted queued card answers withdrawn…
brennanb2025 Sep 29, 2026
2737b2b
Merge remote-tracking branch 'origin/main' into mid-turn-queue-host
brennanb2025 Sep 29, 2026
15d95ce
fix(native-chat): a queued send records what it sent instead of waiti…
brennanb2025 Sep 29, 2026
e159d14
Merge commit '0aa2b6dcca7' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
af1ee83
test(native-chat): a replayed send of a deleted card is spent, with n…
brennanb2025 Sep 29, 2026
fc42eb2
Merge commit '2737b2bd25b' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
63456cf
refactor(native-chat): name the queue's pause-lift for what it releases
brennanb2025 Sep 29, 2026
0b2a926
chore(native-chat): one import of the mutation helpers
brennanb2025 Sep 29, 2026
02d8b9a
fix(native-chat): a Stop marks a queue send without rewriting its sta…
brennanb2025 Sep 29, 2026
43dcc08
docs(native-chat): no send waits on an unknown queued-messages capabi…
brennanb2025 Sep 29, 2026
5ff29c6
test(native-chat): one import of the outbox module in the owner-chang…
brennanb2025 Sep 29, 2026
9f94e12
test(native-chat): read a stale outbox entry without a JSON round-trip
brennanb2025 Sep 29, 2026
db0a4c9
Merge commit '0b2a926205e' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
0cd95a8
fix(native-chat): keep a first attempt's recorded delivery a literal
brennanb2025 Sep 29, 2026
b4da190
fix(native-chat): an interrupted send attempted before a Stop reads a…
brennanb2025 Sep 29, 2026
aca86ec
feat(native-chat): a Stop pauses the whole queue, derived from the jo…
brennanb2025 Sep 29, 2026
aa49808
Merge commit 'aca86ecd388' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
900bb7e
feat(native-chat): a /clear's replacement queue reads paused because …
brennanb2025 Sep 29, 2026
a5aa8e6
feat(native-chat): a paused queue shows one header row with Resume; c…
brennanb2025 Sep 29, 2026
d87c54e
test(native-chat): the coalescer keeps the pause of the latest list
brennanb2025 Sep 29, 2026
5007abf
Merge commit '900bb7e758d' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
3793bfb
test(native-chat): fit the queue tests to the queue-level pause types
brennanb2025 Sep 29, 2026
386d3d0
fix(native-chat): a queue pause covers only the cards it paused
brennanb2025 Sep 29, 2026
432e7da
perf(native-chat): the queue's pause reads the latest person's turn i…
brennanb2025 Sep 29, 2026
1b26237
fix(native-chat): each Resume press is its own operation, and a pause…
brennanb2025 Sep 29, 2026
d9ca984
fix(native-chat): a card handed off after a restart belongs to the pr…
brennanb2025 Sep 29, 2026
aa5305a
fix(native-chat): the paused-queue row shows only over cards Resume c…
brennanb2025 Sep 29, 2026
b7951dd
test(native-chat): Resume reports itself in flight until it settles
brennanb2025 Sep 29, 2026
98ed5a7
fix(native-chat): a queue pause shows only while Resume would send so…
brennanb2025 Sep 29, 2026
9db820e
Merge commit '98ed5a718c5' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
00007c9
fix(native-chat): a queue pause counts only cards Resume would actual…
brennanb2025 Sep 29, 2026
7d4b0c3
fix(native-chat): a returned card that blocks the paused cards hides …
brennanb2025 Sep 29, 2026
a276b5e
Merge commit '7d4b0c3a9d9' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
e4e6365
test(native-chat): build the pause-only batch through the typed helper
brennanb2025 Sep 29, 2026
248333f
fix(native-chat): a Stop pauses a card its withdrawal sent back even …
brennanb2025 Sep 29, 2026
ce5b984
test(native-chat): pin the per-row hook's pause retirement; skip the …
brennanb2025 Sep 29, 2026
7ae9f13
Merge commit 'ce5b9840b3a' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
a7658be
fix(native-chat): the queued area is one bordered box, and the Steer …
brennanb2025 Sep 29, 2026
465a501
Merge origin/main (#23059 and 12 more) into mid-turn-queue-host
brennanb2025 Sep 29, 2026
5e16277
Merge remote-tracking branch 'origin/main' into mid-turn-queue-host
brennanb2025 Sep 29, 2026
026e09b
test(native-chat): match main's append and dispatch shapes in the que…
brennanb2025 Sep 29, 2026
7f7df31
fix(native-chat): read a compaction's settled submission through the …
brennanb2025 Sep 29, 2026
0b98dcb
Merge commit '026e09b2c39' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
63689e6
test(native-chat): a queued card Steered into a turn joins it under t…
brennanb2025 Sep 29, 2026
36bb2c4
Merge commit '7f7df31bad4' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
2c6a46a
Merge remote-tracking branch 'origin/main' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
56cdc70
Merge remote-tracking branch 'origin/main' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
429909d
Merge remote-tracking branch 'origin/main' into mid-turn-queue-desktop
brennanb2025 Sep 29, 2026
64d9ecf
fix(native-chat): queued messages sit above running shells and agents…
brennanb2025 Sep 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ const NativeChatComposerPane = forwardRef<NativeChatComposerHandle, NativeChatCo
onSwitchToTerminal,
readTerminalScreen,
launchSeed,
structuredTransport
structuredTransport,
steerQueued
},
ref
): React.JSX.Element {
Expand Down Expand Up @@ -342,6 +343,8 @@ const NativeChatComposerPane = forwardRef<NativeChatComposerHandle, NativeChatCo
dismissPicker: dismiss,
interrupt,
send,
hasAttachments: imageAttachments.length > 0,
...(steerQueued ? { steerQueued } : {}),
setActiveSuggestion,
setDraft,
setCaret,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,58 @@ describe('NativeChatMessageList turns from the turn record', () => {
expect(follows(screen.getByText('Say DONE'), activity!)).toBe(true)
})

it.each(['settled', 'running'] as const)(
"a queued card Steered into a %s turn joins it, under the opener's bar, with no bar of its own",
(phase) => {
// Steer hands the draft over under a fresh submission id, linked by `queuedMessageId`; the
// host scopes its row to the turn it joined.
const steer = agentJournalSubmissionKey('handed-off')
const running = phase === 'running'
const items = [
say('u1', 'user', 'List three fruits'),
running
? item('t1', {
kind: 'turn',
turnId: 't1',
state: 'running',
userItemId: 'u1',
startedAt: 1_000
})
: settledTurn('t1', 'u1', 4, 1_000),
say('t1-narration', 'assistant', 'Thinking about fruit.', inTurn('t1')),
say(steer, 'user', 'Make it four', inTurn('t1')),
say('t1-answer', 'assistant', 'Apple, banana, cherry, date.', inTurn('t1'))
]
const { container } = render(
journalList(
items,
[
{
clientMessageId: 'handed-off',
fence: 1,
payloadFingerprint: 'steer',
dispatchState: 'accepted',
providerItemId: null,
reason: null,
submittedAt: 2_000,
resolvedAt: 2_100,
queuedMessageId: 'draft-1'
}
],
running ? { isWorking: true, workingStartedAt: 1_000 } : {}
)
)

const bars = container.querySelectorAll<HTMLElement>('[data-native-chat-turn-status]')
expect(bars).toHaveLength(1)
const opener = screen.getByText('List three fruits')
const steered = screen.getByText('Make it four')
expect(follows(bars[0]!, opener)).toBe(true)
expect(follows(steered, bars[0]!)).toBe(true)
expect(follows(screen.getByText('Apple, banana, cherry, date.'), steered)).toBe(true)
}
)

it("keeps a steer on its way into an ordinary running turn above that turn's activity", () => {
const steer = agentJournalSubmissionKey('steer')
const items = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import {
AlertCircle,
CornerDownRight,
ListEnd,
MoreHorizontal,
Pencil,
Send,
Trash2
} from 'lucide-react'
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { ShortcutKeyCombo } from '@/components/ShortcutKeyCombo'
import { translate } from '@/i18n/i18n'
import { structuredAgentSessionAttemptFailureParts } from '../../../../shared/structured-agent-session-send-disposition'
import { classifyDispatchRejection } from '../../../../shared/structured-agent-session-dispatch-rejection'
import { readAgentSessionFailureFact } from '../../../../shared/agent-session-failure'
import { agentSessionWriteNoticeText } from './agent-session-write-notice-text'
import { QUEUED_MESSAGE_PAUSED_SEND_FAILED } from '../../../../shared/agent-session-wire'
import { isMacPlatform } from './native-chat-shortcut'
import type { QueuedMessageCard } from './structured-agent-session-queued-cards'

/** The visible caption under the text; the default waiting hold needs none. */
export function queuedMessageCardCaption(card: QueuedMessageCard): string | null {
switch (card.hold) {
case 'returned': {
// Read exactly as a rejected submission: the typed fact decides, the reason is the fallback.
const reason = card.returnedReason ?? null
// A consumed draft whose submission a Stop withdrew is not a failure of the
// message — say what happened rather than "not sent".
if (
classifyDispatchRejection({ reason, rejection: card.returnedRejection }).category ===
'withdrawn'
) {
return translate(
'components.native-chat.queuedMessages.withdrawnHold',
'Stopped before it was sent'
)
}
return agentSessionWriteNoticeText(
structuredAgentSessionAttemptFailureParts(
{ kind: 'rejected', reason },
// The card's own Send is the retry, so the words leave out sending again.
{ retryControl: true },
readAgentSessionFailureFact(card.returnedRejection)
)
)
}
case 'paused':
// A card's own hold; the queue's pause is the list's header. Markers localize, and an absent
// or unknown one (newer host) is a plain pause, never shown raw.
if (card.pausedReason === QUEUED_MESSAGE_PAUSED_SEND_FAILED) {
return translate(
'components.native-chat.queuedMessages.pausedSendFailed',
"Couldn't send — press Send to retry."
)
}
return translate('components.native-chat.queuedMessages.paused', 'Paused')
case 'behind-returned':
return translate(
'components.native-chat.queuedMessages.behindReturnedHold',
'Waiting — a message ahead needs attention'
)
case 'awaiting-answer':
return translate(
'components.native-chat.queuedMessages.awaitingAnswerHold',
'Waiting for your answer'
)
case 'turn':
case 'queue-paused':
// Plainly queued; a paused queue's header row carries the why.
return null
}
}

/** Steer names the mid-turn jump, also while the whole queue is paused; a card held on its own
* or returned is not waiting on the turn, so its action and tooltip are plainly Send. */
export function queuedMessageCardSendNow(card: QueuedMessageCard): {
/** Steer's ↳, or Send's paper plane. */
steers: boolean
label: string
hint: string
} {
if (card.hold === 'paused' || card.hold === 'returned') {
return {
steers: false,
label: translate('components.native-chat.queuedMessages.send', 'Send'),
hint: translate('components.native-chat.queuedMessages.sendHint', 'Send this message now')
}
}
return {
steers: true,
label: translate('components.native-chat.queuedMessages.steer', 'Steer'),
hint: translate(
'components.native-chat.queuedMessages.steerHint',
'Submit without interrupting the model'
)
}
}

export function NativeChatQueuedMessageCard({
card,
showsSteerShortcut,
onSteer,
onDelete,
onEdit,
onTurnOffQueueing
}: {
card: QueuedMessageCard
/** Only the newest card answers Cmd/Ctrl+Enter; only it may show the chord. */
showsSteerShortcut: boolean
onSteer: () => void
onDelete: () => void
onEdit: () => void
onTurnOffQueueing: () => void
}): React.JSX.Element {
const caption = queuedMessageCardCaption(card)
const returned = card.state === 'returned'
const sendNow = queuedMessageCardSendNow(card)
const isMac = isMacPlatform()
return (
<li
data-queued-message-id={card.messageId}
data-queued-message-state={card.state}
className="flex items-center gap-2 px-2.5 py-1.5"
>
{returned || card.pausedReason === QUEUED_MESSAGE_PAUSED_SEND_FAILED ? (
<AlertCircle className="size-3.5 shrink-0 text-destructive" aria-hidden />
) : (
<ListEnd className="size-3.5 shrink-0 text-muted-foreground" aria-hidden />
)}
<div className="min-w-0 flex-1">
<p className="truncate text-sm" title={card.text}>
{card.text}
</p>
{caption ? (
<p
className={
returned
? 'truncate text-xs text-destructive'
: 'truncate text-xs text-muted-foreground'
}
>
{caption}
</p>
) : null}
</div>
<Tooltip>
<TooltipTrigger asChild>
<Button type="button" variant="ghost" size="xs" onClick={onSteer}>
{sendNow.steers ? <CornerDownRight className="size-3" /> : <Send className="size-3" />}
{sendNow.label}
</Button>
</TooltipTrigger>
<TooltipContent side="top" sideOffset={4}>
<span className="flex items-center gap-2">
<span>{sendNow.hint}</span>
{showsSteerShortcut ? (
<ShortcutKeyCombo keys={[isMac ? '⌘' : 'Ctrl', isMac ? '⏎' : 'Enter']} />
) : null}
</span>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
variant="ghost"
size="icon-xs"
aria-label={translate('components.native-chat.queuedMessages.delete', 'Delete')}
onClick={onDelete}
>
<Trash2 className="size-3.5" />
</Button>
</TooltipTrigger>
<TooltipContent side="top" sideOffset={4}>
{translate('components.native-chat.queuedMessages.delete', 'Delete')}
</TooltipContent>
</Tooltip>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
type="button"
variant="ghost"
size="icon-xs"
aria-label={translate(
'components.native-chat.queuedMessages.moreActions',
'More actions'
)}
>
<MoreHorizontal className="size-3.5" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onSelect={onEdit}>
<Pencil />
{translate('components.native-chat.queuedMessages.editMessage', 'Edit message')}
</DropdownMenuItem>
<DropdownMenuItem onSelect={onTurnOffQueueing}>
{translate(
'components.native-chat.queuedMessages.turnOffQueueing',
'Turn off queueing'
)}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</li>
)
}
Loading
Loading