Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
294 commits
Select commit Hold shift + click to select a range
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
e751c7e
fix(native-chat): the conversation outlives its agent
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
9123568
fix(native-chat): a request that failed reads as failed
brennanb2025 Sep 25, 2026
0efca93
docs(native-chat): say what an attach's open conversation and unconfi…
brennanb2025 Sep 25, 2026
36067f3
test(native-chat): a verdict change republishes the mobile status pro…
brennanb2025 Sep 25, 2026
a47a902
refactor(native-chat): the store's retention trigger keeps its flag c…
brennanb2025 Sep 25, 2026
69540f8
Merge remote-tracking branch 'origin/brennanb2025/chat-accept-then-de…
brennanb2025 Sep 25, 2026
918091d
test(native-chat): a user message the provider journaled keeps its se…
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
eaf1436
fix(native-chat): a restart offer ends when the chat's agent starts a…
brennanb2025 Sep 25, 2026
5b93c44
fix(runtime): end a transcript stream when its client unsubscribes
brennanb2025 Sep 25, 2026
40f3d35
fix(native-chat): a late provider-session update keeps a failed recov…
brennanb2025 Sep 25, 2026
80ccb33
test(orchestration): the preamble's host stub is typed, not cast
brennanb2025 Sep 25, 2026
97a5321
test(native-chat): the terminal-bell check asserts the renamed verdic…
brennanb2025 Sep 25, 2026
4c67270
Merge remote-tracking branch 'origin/brennanb2025/chat-accept-then-de…
brennanb2025 Sep 25, 2026
7805005
Merge remote-tracking branch 'origin/brennanb2025/chat-accept-then-de…
brennanb2025 Sep 25, 2026
dfe35eb
fix(native-chat): a failed turn ranks like a completion for attention
brennanb2025 Sep 25, 2026
3d3c52b
Merge remote-tracking branch 'origin/brennanb2025/chat-failed-reads-f…
brennanb2025 Sep 25, 2026
0a3f255
fix(native-chat): one fact ends a restart offer: the chat moved on si…
brennanb2025 Sep 25, 2026
4c45865
test(native-chat): an older build reads the restart offer this build …
brennanb2025 Sep 25, 2026
1887bef
fix(native-chat): read a restart offer against where the journal stoo…
brennanb2025 Sep 26, 2026
a862d71
test(native-chat): wait for the listing's retire write before reading…
brennanb2025 Sep 26, 2026
8caf8d7
refactor(native-chat): every journal row states which turn it belongs to
brennanb2025 Sep 26, 2026
0871b27
fix(native-chat): keep the terminal-backed chat's read error over its…
brennanb2025 Sep 26, 2026
6cde2a7
fix(native-chat): a start retries the exit settlement a failed journa…
brennanb2025 Sep 26, 2026
a96f475
fix(native-chat): a failed main agent reads failed while its subagent…
brennanb2025 Sep 26, 2026
9530e8d
perf(native-chat): answer the owner check without opening the chat
brennanb2025 Sep 26, 2026
2f39e1b
fix(native-chat): a read waiting on the session lock opens nothing on…
brennanb2025 Sep 26, 2026
b35ee58
test(native-chat): pin stated turn scopes, the upcast of unscoped row…
brennanb2025 Sep 26, 2026
d4d9d71
fix(native-chat): /compact is a message the chat sends, run as a turn…
brennanb2025 Sep 26, 2026
4ad06ca
fix(native-chat): read a failed resume's chat before calling it retry…
brennanb2025 Sep 26, 2026
1aaf776
test(native-chat): type the provider event sink the settlement test r…
brennanb2025 Sep 26, 2026
9d9a8ae
docs(native-chat): the worktree ps outcome comment no longer claims o…
brennanb2025 Sep 26, 2026
daaf0cf
fix(native-chat): say the structured read keeps trying only where it …
brennanb2025 Sep 26, 2026
20318fe
fix(native-chat): rows group under the turn their record names, not t…
brennanb2025 Sep 26, 2026
42307c8
test(native-chat): await the send's settlement instead of polling for…
brennanb2025 Sep 26, 2026
48cdb21
docs(native-chat): the status-store listing rule names provider-journ…
brennanb2025 Sep 26, 2026
9d9dd98
fix(native-chat): a restart offer resumes any time after the quit, an…
brennanb2025 Sep 26, 2026
e7458c1
fix(native-chat): a /compact is not a request the sidebar, notificati…
brennanb2025 Sep 26, 2026
bab2cef
fix(orchestration): route no mail to a structured worker its orchestr…
brennanb2025 Sep 26, 2026
75f5607
fix(native-chat): a failed retry names the user's prompt, not Orca's …
brennanb2025 Sep 26, 2026
50a3316
test(native-chat): pin what a conversation command's admission refuse…
brennanb2025 Sep 26, 2026
cf8e2fe
Merge remote-tracking branch 'origin/brennanb2025/chat-conversation-o…
brennanb2025 Sep 26, 2026
15b2efa
Merge remote-tracking branch 'origin/brennanb2025/chat-failed-reads-f…
brennanb2025 Sep 26, 2026
09e359f
test(native-chat): tests merged from the base state which turn their …
brennanb2025 Sep 26, 2026
bbec1b6
fix(native-chat): a refused send notifies failed through the completi…
brennanb2025 Sep 26, 2026
7a5e202
fix(orchestration): read the released row optionally, as the authorit…
brennanb2025 Sep 26, 2026
33c42e3
chore(native-chat): one import per module and no unexplained casts in…
brennanb2025 Sep 26, 2026
3e561ee
test(claude): pin which turn a Claude row joins, including a subagent…
brennanb2025 Sep 26, 2026
c0ea360
fix(native-chat): the status bar drops a restart offer the chat moved…
brennanb2025 Sep 26, 2026
60826fc
Merge remote-tracking branch 'origin/brennanb2025/chat-failed-reads-f…
brennanb2025 Sep 26, 2026
b8526e4
fix(native-chat): a refused steer is read from the turn its handover …
brennanb2025 Sep 26, 2026
b680294
Merge remote-tracking branch 'origin/brennanb2025/chat-conversation-o…
brennanb2025 Sep 26, 2026
e6dadd1
Merge main into PR 1
brennanb2025 Sep 26, 2026
a96d3fc
fix(mobile): the native-chat controller contract carries the turn jou…
brennanb2025 Sep 26, 2026
8cbdd44
fix(native-chat): the live turn is the running turn, not the newest u…
brennanb2025 Sep 26, 2026
4e391e1
test(native-chat): a turn the provider opened keeps its own clock
brennanb2025 Sep 26, 2026
70736fd
fix(native-chat): a running turn no message opened draws its status o…
brennanb2025 Sep 26, 2026
a6c7153
fix(native-chat): every copy of a row carries the main agent's own st…
brennanb2025 Sep 26, 2026
7b6eafb
test(native-chat): pin the worktree ps verdict across host and phone …
brennanb2025 Sep 26, 2026
a73c33a
test(mobile): name the parity table's row for its role
brennanb2025 Sep 26, 2026
f6d9c8a
Merge PR 1's latest head (main merged in) into the conversation-outli…
brennanb2025 Sep 26, 2026
e10362b
test(native-chat): a roster of idle or finished children does not kee…
brennanb2025 Sep 26, 2026
159b971
fix(native-chat): a request that settles while the user is asked some…
brennanb2025 Sep 26, 2026
20978d6
fix(orchestration): a task dispatched into a resting structured worke…
brennanb2025 Sep 26, 2026
ff274a7
fix(native-chat): a command's wait ends when its child does
brennanb2025 Sep 26, 2026
eed0954
fix(native-chat): keep refusing sends during a command on an older host
brennanb2025 Sep 26, 2026
ed8dd9f
Merge remote-tracking branch 'origin/brennanb2025/chat-conversation-o…
brennanb2025 Sep 26, 2026
b7ebbdb
Merge remote-tracking branch 'origin/brennanb2025/chat-failed-reads-f…
brennanb2025 Sep 26, 2026
742bda7
docs(native-chat): comments stop describing the hold this PR removed
brennanb2025 Sep 26, 2026
93ee58a
fix(native-chat): the completion says when the user is being asked
brennanb2025 Sep 26, 2026
b36d188
fix(native-chat): a restart offer keeps the start its own continuatio…
brennanb2025 Sep 26, 2026
7214f65
fix(native-chat): a rewound turn still names the message that opened it
brennanb2025 Sep 26, 2026
26fc397
fix(native-chat): Stop ends only the command it names
brennanb2025 Sep 26, 2026
d242e5e
Merge remote-tracking branch 'origin/brennanb2025/chat-accept-then-de…
brennanb2025 Sep 26, 2026
ca3e68f
fix(native-chat): an agent gets a full idle window after its owed wor…
brennanb2025 Sep 26, 2026
194fc33
test(claude): the options-read fixture runs a live child
brennanb2025 Sep 26, 2026
86d7365
test(native-chat): host tests reach its collaborators through a typed…
brennanb2025 Sep 26, 2026
e17c80e
fix(worktree-status): a departed agent's failure yields to live work …
brennanb2025 Sep 26, 2026
fb53224
refactor(orchestration): one owner answers a structured worker's custody
brennanb2025 Sep 26, 2026
ccb0610
Merge remote-tracking branch 'origin/brennanb2025/chat-conversation-o…
brennanb2025 Sep 26, 2026
e6922a5
Merge remote-tracking branch 'origin/brennanb2025/chat-conversation-o…
brennanb2025 Sep 27, 2026
1c48bf1
Merge remote-tracking branch 'origin/brennanb2025/chat-failed-reads-f…
brennanb2025 Sep 27, 2026
d7ce43a
refactor(orchestration): owed work is an open dispatch on the worker'…
brennanb2025 Sep 27, 2026
6374f35
Merge main into PR 1
brennanb2025 Sep 27, 2026
0f89353
docs(agent-status): a departed agent's failure ranks below live work …
brennanb2025 Sep 27, 2026
724b961
Merge main into PR 1
brennanb2025 Sep 27, 2026
9fa4452
fix(native-chat): a restart offer knows its continuations by a tag in…
brennanb2025 Sep 27, 2026
4d36cd3
Merge remote-tracking branch 'origin/brennanb2025/chat-accept-then-de…
brennanb2025 Sep 27, 2026
8e37dc9
test(runtime): the legacy-worker reveal test judges its stale snapsho…
brennanb2025 Sep 27, 2026
6545e9c
fix(native-chat): a message held behind /compact is drawn where it wa…
brennanb2025 Sep 27, 2026
8eef3fe
fix(native-chat): a phone's send during /compact answers without wait…
brennanb2025 Sep 27, 2026
7f8eda9
perf(native-chat): a rewind places provider items with one pass over …
brennanb2025 Sep 27, 2026
c39151d
fix(native-chat): a view never restarts a chat whose last start failed
brennanb2025 Sep 27, 2026
14dc4db
fix(native-chat): a message waiting behind /compact is drawn after it…
brennanb2025 Sep 27, 2026
897768d
Merge PR 1's latest head (main merged in) into the conversation-outli…
brennanb2025 Sep 27, 2026
be2d4e1
fix(native-chat): the idle sweep reads owed work every tick
brennanb2025 Sep 27, 2026
309777a
Merge remote-tracking branch 'origin/brennanb2025/chat-conversation-o…
brennanb2025 Sep 27, 2026
0fc424a
fix(native-chat): a continuation handed to the agent stays sent
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
8fea3f0
test(cross-version): load the phone row readers without mobile's tool…
brennanb2025 Sep 27, 2026
8c966c7
test(cross-version): keep the checkout path-guard message and justify…
brennanb2025 Sep 27, 2026
1474464
fix(native-chat): a command ends only by its own provider answer or i…
brennanb2025 Sep 27, 2026
6a316b9
fix(native-chat): a command's settle answers its message before endin…
brennanb2025 Sep 27, 2026
09e94b8
fix(native-chat): "Worked for" counts from the handover, not the send
brennanb2025 Sep 27, 2026
158ca0a
test(native-chat): give the failed-start and stale-turn waits a loade…
brennanb2025 Sep 27, 2026
43e5c9f
test(native-chat): the interrupted create's own retry continues again
brennanb2025 Sep 27, 2026
301762e
docs(native-chat): three comments that still had views starting agents
brennanb2025 Sep 27, 2026
8f66a25
test(native-chat): pin the open's and the send's start and row counts…
brennanb2025 Sep 27, 2026
61cd62e
fix(native-chat): a second Stop on a command ends its child; one comp…
brennanb2025 Sep 27, 2026
dcc85e6
Merge PR 1's latest head into the conversation-outlives-agent branch
brennanb2025 Sep 27, 2026
da2ba05
Merge PR 1's latest head (its view-start test pinned at open and send…
brennanb2025 Sep 27, 2026
2a21363
test(native-chat): a reader's open settles the turn a failed exit set…
brennanb2025 Sep 27, 2026
0217612
test(native-chat): the view-start test's starting window outlasts two…
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
e463c6a
refactor(native-chat): the provider's translator ends a command's tur…
brennanb2025 Sep 27, 2026
6bf458f
test(native-chat): pin a command's end to real /compact frames and to…
brennanb2025 Sep 27, 2026
320a4ff
Merge remote-tracking branch 'origin/brennanb2025/chat-conversation-o…
brennanb2025 Sep 27, 2026
065d98f
Merge remote-tracking branch 'origin/brennanb2025/chat-failed-reads-f…
brennanb2025 Sep 27, 2026
dc4b176
test(native-chat): tests merged from the base state which turn their …
brennanb2025 Sep 27, 2026
a72cec4
refactor(native-chat): drop the child-end waiter nothing waits on
brennanb2025 Sep 27, 2026
199e2d6
fix(native-chat): a command holds the queue only while its child runs it
brennanb2025 Sep 27, 2026
446d65f
fix(native-chat): a Claude /compact succeeds only on its compaction b…
brennanb2025 Sep 27, 2026
d5716f3
Merge main into PR 1
brennanb2025 Sep 27, 2026
f92abe2
fix(native-chat): a Claude child's exit says why the turn it ended st…
brennanb2025 Sep 27, 2026
3ea60f2
Merge remote-tracking branch 'origin/brennanb2025/chat-accept-then-de…
brennanb2025 Sep 27, 2026
4bf6080
fix(native-chat): a message waiting behind /compact draws below its l…
brennanb2025 Sep 27, 2026
ea4dbfb
fix(native-chat): only a running command holds a message below its li…
brennanb2025 Sep 27, 2026
740ed1f
Merge main into PR 1
brennanb2025 Sep 28, 2026
f74a642
Merge PR 1's latest head (main merged in) into the conversation-outli…
brennanb2025 Sep 28, 2026
fb34994
test(codex): the claim test names its notification params as a record
brennanb2025 Sep 28, 2026
69ff6df
test(native-chat): a read that reaches a crashed chat before the star…
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
cec2d77
Merge PR 1's latest head into the conversation-outlives-agent branch
brennanb2025 Sep 28, 2026
f4963ad
docs(native-chat): drop the removed dispatch hold from six comments
brennanb2025 Sep 28, 2026
fcad779
Merge PR 1 into #22944
brennanb2025 Sep 28, 2026
5479e31
test(native-chat): rest the owner-status chat through the idle sweep,…
brennanb2025 Sep 28, 2026
57735e6
fix(native-chat): show the structured pane's retrying line when a rea…
brennanb2025 Sep 28, 2026
5b9379d
fix(native-chat): a send the provider never received after a restart …
brennanb2025 Sep 28, 2026
fd6b1f4
Merge remote-tracking branch 'origin/brennanb2025/chat-conversation-o…
brennanb2025 Sep 28, 2026
e9e2b3a
Merge remote-tracking branch 'origin/brennanb2025/chat-failed-reads-f…
brennanb2025 Sep 28, 2026
f7639bf
fix(native-chat): a failed Codex compaction's late completion writes …
brennanb2025 Sep 28, 2026
3e789fc
test(native-chat): the mid-command exit case resumes its next child a…
brennanb2025 Sep 28, 2026
9da7cd0
fix(native-chat): a /clear that never committed no longer locks the chat
brennanb2025 Sep 28, 2026
ea99997
fix(native-chat): a Codex rewind the provider did not keep no longer …
brennanb2025 Sep 28, 2026
f1bf5b4
test(native-chat): a clear retried after a crash starts no second rep…
brennanb2025 Sep 28, 2026
d89674a
chore(native-chat): the clear rerun comment claims only the stable re…
brennanb2025 Sep 28, 2026
1b2f025
Merge remote-tracking branch 'origin/main' into brennanb2025/chat-con…
brennanb2025 Sep 28, 2026
4cd918b
test(native-chat): wait for a send's background start before the refu…
brennanb2025 Sep 28, 2026
97e7925
Merge remote-tracking branch 'origin/main' into brennanb2025/chat-con…
brennanb2025 Sep 28, 2026
aceb39f
Merge remote-tracking branch 'origin/main' into brennanb2025/chat-con…
brennanb2025 Sep 28, 2026
e6aaca2
fix(native-chat): a start a message waited on gets one failure row, t…
brennanb2025 Sep 28, 2026
7913e6f
Merge #22835's final head into #23059
brennanb2025 Sep 28, 2026
537d795
Merge origin/main (#22835 squash, #23502, #23537) into #23059
brennanb2025 Sep 28, 2026
ebbb88c
Merge origin/main (#23560, #23520, #23109) into #23059
brennanb2025 Sep 28, 2026
436d177
Merge origin/main (#23546) into #23059
brennanb2025 Sep 28, 2026
d6d4b29
Merge #23059's head (main merged after #22835) into #23524
brennanb2025 Sep 28, 2026
066b4ee
Merge origin/main (#23116) into #23059
brennanb2025 Sep 28, 2026
90b68d3
fix(native-chat): a /compact whose start failed says to run /compact …
brennanb2025 Sep 28, 2026
acdd559
Merge origin/main (#23608, #23682, #23456, #23605, #23618, #23702, #2…
brennanb2025 Sep 29, 2026
7b9fb3f
fix(native-chat): a Codex /compact ends only on its turn's completion…
brennanb2025 Sep 29, 2026
caa5be6
test(native-chat): main's crash-turn test states its row's turn, and …
brennanb2025 Sep 29, 2026
1e6c37d
test(native-chat): main's new journal tests state each row's turn
brennanb2025 Sep 29, 2026
9c847cb
Merge origin/main (#23573, #23621, #23801, #23802, #23799, #23765, #2…
brennanb2025 Sep 29, 2026
bda9ff1
Merge origin/main (#23808) into #23059
brennanb2025 Sep 29, 2026
077454c
Merge origin/main (#23671, #23026, #22090, #23816, #23815, #23499, #2…
brennanb2025 Sep 29, 2026
321a58a
fix(native-chat): draw a queued turn's message after the earlier turn…
brennanb2025 Sep 29, 2026
7b2f2d9
test(native-chat): run #23026's Stop tests against #23059's command t…
brennanb2025 Sep 29, 2026
898daae
fix(native-chat): typecheck main's Stop and restore-grouping code aga…
brennanb2025 Sep 29, 2026
54b147e
Merge #23059's head (898daaef37c) into #23524
brennanb2025 Sep 29, 2026
8a44a4e
fix(native-chat): say a /clear cut off by a restart left the chat unc…
brennanb2025 Sep 29, 2026
84fc7ff
fix(native-chat): a retried /clear finishes onto the conversation its…
brennanb2025 Sep 29, 2026
8995771
refactor(native-chat): stop recording that Codex acknowledged a rewind
brennanb2025 Sep 29, 2026
1e087ec
fix(native-chat): a /clear retried under a new operation id finishes …
brennanb2025 Sep 29, 2026
b67389a
fix(native-chat): a /clear retry never repeats a failed start or wait…
brennanb2025 Sep 29, 2026
4974af9
fix(native-chat): a /clear retry finishes only a replacement that sta…
brennanb2025 Sep 29, 2026
dc4ca58
Merge origin/main (d60f999f94b, #23059 squashed) into #23524
brennanb2025 Sep 29, 2026
9d3f676
refactor(native-chat): a record's identity fields are built in one place
brennanb2025 Sep 29, 2026
3bffed3
feat(native-chat): the store commits a /clear and its new conversatio…
brennanb2025 Sep 29, 2026
990bff2
fix(native-chat): /clear starts nothing; the new chat's first message…
brennanb2025 Sep 29, 2026
8b0f189
test(native-chat): drop the /clear retry wording test; no start runs …
brennanb2025 Sep 29, 2026
c9b008b
Merge origin/main (28073327354, #23923) into brennanb2025/chat-clear-…
brennanb2025 Sep 29, 2026
66e9658
test(native-chat): another window and a phone read a /clear's replace…
brennanb2025 Sep 29, 2026
7da6f8d
test(native-chat): a never-started replacement closes as settled
brennanb2025 Sep 29, 2026
a6534ad
Merge #23524's head (c9b008b873e) into the /clear lazy-start branch
brennanb2025 Sep 29, 2026
f26e803
fix(native-chat): /clear settles an interrupted Codex rewind the way …
brennanb2025 Sep 29, 2026
d57545b
fix(native-chat): a chat whose agent is not running keeps its `/` com…
brennanb2025 Sep 29, 2026
386f986
Merge origin/main (29c49aec31b) into brennanb2025/clear-starts-on-fir…
brennanb2025 Sep 29, 2026
9199f97
test(native-chat): queued drafts around /clear follow what a /clear n…
brennanb2025 Sep 29, 2026
18624fb
fix(native-chat): /clear opens the new conversation under its own lock
brennanb2025 Sep 29, 2026
5b6cd57
Merge origin/main (a57863ba167) into brennanb2025/clear-starts-on-fir…
brennanb2025 Sep 29, 2026
85a12cb
test(native-chat): queued drafts reach a /clear replacement that neve…
brennanb2025 Sep 29, 2026
4581395
fix(native-chat): /clear stops the old agent before it records the clear
brennanb2025 Sep 30, 2026
0c7cdef
fix(native-chat): give every chat write press its own operation id
brennanb2025 Sep 29, 2026
869b03f
fix(native-chat): answer a /clear pressed again after it committed wi…
brennanb2025 Sep 29, 2026
85fa9bb
test(native-chat): scope the prompt-cancel tests' journal rows to the…
brennanb2025 Sep 29, 2026
19ae463
test(native-chat): give the repeated prompt Cancel its own host test …
brennanb2025 Sep 29, 2026
b044e60
chore(reliability): drop the deleted mobile id-retention test from th…
brennanb2025 Sep 29, 2026
b0ccff4
fix(native-chat): a Claude chat at rest reads its `/` menu from Claud…
brennanb2025 Sep 30, 2026
e338bca
fix(native-chat): a Claude chat at rest keeps /model, /effort, /clear…
brennanb2025 Sep 30, 2026
7251f4e
fix(native-chat): an at-rest `/` scan keeps any newer answer and neve…
brennanb2025 Sep 30, 2026
d6c17bd
fix(native-chat): a failed at-rest `/` scan no longer discards an old…
brennanb2025 Sep 30, 2026
ee31bbe
Merge remote-tracking branch 'origin/main' into brennanb2025/clear-fi…
brennanb2025 Sep 30, 2026
d22b8cb
test(native-chat): open the at-rest command host on main's shared jou…
brennanb2025 Sep 30, 2026
75cefde
Merge origin/main into brennanb2025/chat-op-id-per-action
brennanb2025 Sep 30, 2026
f98f6aa
test(native-chat): a repeated draft press under its own id is answere…
brennanb2025 Sep 30, 2026
5f67247
fix(native-chat): the host joins a second Stop of a turn it is still …
brennanb2025 Sep 30, 2026
ed59598
Merge origin/main into brennanb2025/chat-op-id-per-action
brennanb2025 Sep 30, 2026
1b0e726
fix(mobile): keep the Stop's fence narrowed, and type the held card a…
brennanb2025 Sep 30, 2026
45734b8
Merge brennanb2025/clear-starts-on-first-send into brennanb2025/chat-…
brennanb2025 Sep 30, 2026
7801b8f
test(native-chat): open the repeat-press host on the shared journal d…
brennanb2025 Sep 30, 2026
d4e7d53
Merge origin/main (f37a84993e8) into #23935
brennanb2025 Sep 30, 2026
b0a654a
fix(native-chat): a second Stop of a turn an earlier Stop answered fo…
brennanb2025 Sep 30, 2026
54bce9f
Merge brennanb2025/clear-starts-on-first-send into brennanb2025/chat-…
brennanb2025 Sep 30, 2026
25541b7
fix(native-chat): a /compact or /clear pressed again is answered from…
brennanb2025 Sep 30, 2026
f5e0ace
Revert "fix(native-chat): a /compact or /clear pressed again is answe…
brennanb2025 Sep 30, 2026
7e95063
fix(native-chat): a Stop writes its one note only when it stopped som…
brennanb2025 Sep 30, 2026
8867990
chore: the repeated-Stop capability's comments say what it now means
brennanb2025 Sep 30, 2026
59c1445
Merge remote-tracking branch 'origin/main' into brennanb2025/clear-fi…
brennanb2025 Sep 30, 2026
9366ef7
refactor(agent-session): the transaction queue opens the session stor…
brennanb2025 Sep 30, 2026
36708c2
Merge origin/main (b4b708c2c4c) into #23935
brennanb2025 Sep 30, 2026
7508af3
test: open the store on the journal database and pass the close cause…
brennanb2025 Sep 30, 2026
86acc5e
Merge remote-tracking branch 'origin/main' into brennanb2025/clear-st…
brennanb2025 Sep 30, 2026
e3619c2
refactor(native-chat): a provider's at-rest commands are one adapter …
brennanb2025 Sep 30, 2026
58e63a1
test: the startup-reconcile tab close passes the close cause main now…
brennanb2025 Sep 30, 2026
37bc020
Merge brennanb2025/clear-starts-on-first-send into brennanb2025/chat-…
brennanb2025 Sep 30, 2026
4380ad8
test(native-chat): the command-start test's client mock knows the rep…
brennanb2025 Sep 30, 2026
13a6333
Merge remote-tracking branch 'origin/brennanb2025/clear-starts-on-fir…
brennanb2025 Sep 30, 2026
65bde90
fix(native-chat): a Stop keeps the fence it was pressed at while the …
brennanb2025 Sep 30, 2026
3e11a8f
test(native-chat): a Stop keeps its pressed fence against either kind…
brennanb2025 Sep 30, 2026
10d019f
Merge main into PR 1 (after #24231)
brennanb2025 Oct 1, 2026
62d506a
Merge main into PR 1
brennanb2025 Oct 1, 2026
a974746
Merge PR 1 (#23935) into PR 2
brennanb2025 Oct 1, 2026
2423599
Merge main into PR 2 (after #23935 landed)
brennanb2025 Oct 1, 2026
317f968
Merge main into PR 2 (after #24235)
brennanb2025 Oct 1, 2026
d64c14e
fix(native-chat): keep the repeated-Stop rules through #24235's sessi…
brennanb2025 Oct 1, 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
5 changes: 2 additions & 3 deletions config/reliability-gates.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,7 @@
"oracle": "Inject adapter acknowledgement loss, RPC response loss, caller replacement, logical-client close after response, auth recovery with a written request, missing journal submissions, legacy pending rows, stale fences, operation expiry, mobile remount, and durable-journal capacity. Assert one provider dispatch or one operation id for every ambiguous retry, fresh identity only after rejection, and no eviction of ambiguous mobile ids.",
"commands": [
"ORCA_BACKGROUND_LAUNCH=1 pnpm test src/shared/agent-session-operation-ledger.test.ts src/shared/structured-agent-session-send-disposition.test.ts src/main/runtime/agent-session-operation-admission.test.ts src/main/native-chat/agent-session-wire/structured-agent-session-refusal-retry.test.ts src/main/native-chat/agent-session-wire/structured-agent-session-send.test.ts src/main/runtime/orchestration/structured-mailbox-pointer-delivery.test.ts src/main/runtime/orchestration/structured-mailbox-pointer-host.test.ts src/main/runtime/orchestration/structured-pointer-operation-id.test.ts src/renderer/src/components/native-chat/use-structured-agent-session-outbox.test.tsx src/renderer/src/components/native-chat/use-structured-agent-session.test.tsx src/renderer/src/components/native-chat/NativeChatStructuredSessionDelivery.test.tsx src/renderer/src/lib/launch-structured-agent-session.test.ts",
"ORCA_BACKGROUND_LAUNCH=1 pnpm --dir mobile test ../mobile/src/session/mobile-native-chat-image-attachment.test.ts ../mobile/src/session/use-mobile-native-chat-image-attachments.test.ts ../mobile/src/session/mobile-structured-send-operation-journal.test.ts ../mobile/src/session/mobile-structured-session-operation-retention.test.ts ../mobile/src/session/mobile-structured-send-delivery.test.ts ../mobile/src/session/use-mobile-structured-agent-session-send.test.tsx ../mobile/src/session/use-mobile-structured-agent-session.test.tsx ../mobile/src/transport/mobile-relay-rpc-session.test.ts ../mobile/src/transport/rpc-client-delivery-ambiguity.test.ts ../mobile/src/transport/stable-logical-rpc-client.test.ts"
"ORCA_BACKGROUND_LAUNCH=1 pnpm --dir mobile test ../mobile/src/session/mobile-native-chat-image-attachment.test.ts ../mobile/src/session/use-mobile-native-chat-image-attachments.test.ts ../mobile/src/session/mobile-structured-send-operation-journal.test.ts ../mobile/src/session/mobile-structured-send-delivery.test.ts ../mobile/src/session/use-mobile-structured-agent-session-send.test.tsx ../mobile/src/session/use-mobile-structured-agent-session.test.tsx ../mobile/src/transport/mobile-relay-rpc-session.test.ts ../mobile/src/transport/rpc-client-delivery-ambiguity.test.ts ../mobile/src/transport/stable-logical-rpc-client.test.ts"
],
"testFiles": [
"src/shared/agent-session-operation-ledger.test.ts",
Expand All @@ -967,7 +967,6 @@
"mobile/src/session/mobile-native-chat-image-attachment.test.ts",
"mobile/src/session/use-mobile-native-chat-image-attachments.test.ts",
"mobile/src/session/mobile-structured-send-operation-journal.test.ts",
"mobile/src/session/mobile-structured-session-operation-retention.test.ts",
"mobile/src/session/mobile-structured-send-delivery.test.ts",
"mobile/src/session/use-mobile-structured-agent-session-send.test.tsx",
"mobile/src/session/use-mobile-structured-agent-session.test.tsx",
Expand Down Expand Up @@ -1046,7 +1045,7 @@
"date": "2026-09-12",
"runner": "local",
"platform": "macos",
"command": "ORCA_BACKGROUND_LAUNCH=1 pnpm --dir mobile test ../mobile/src/session/mobile-native-chat-image-attachment.test.ts ../mobile/src/session/use-mobile-native-chat-image-attachments.test.ts ../mobile/src/session/mobile-structured-send-operation-journal.test.ts ../mobile/src/session/mobile-structured-session-operation-retention.test.ts ../mobile/src/session/mobile-structured-send-delivery.test.ts ../mobile/src/session/use-mobile-structured-agent-session-send.test.tsx ../mobile/src/session/use-mobile-structured-agent-session.test.tsx ../mobile/src/transport/mobile-relay-rpc-session.test.ts ../mobile/src/transport/rpc-client-delivery-ambiguity.test.ts ../mobile/src/transport/stable-logical-rpc-client.test.ts",
"command": "ORCA_BACKGROUND_LAUNCH=1 pnpm --dir mobile test ../mobile/src/session/mobile-native-chat-image-attachment.test.ts ../mobile/src/session/use-mobile-native-chat-image-attachments.test.ts ../mobile/src/session/mobile-structured-send-operation-journal.test.ts ../mobile/src/session/mobile-structured-send-delivery.test.ts ../mobile/src/session/use-mobile-structured-agent-session-send.test.tsx ../mobile/src/session/use-mobile-structured-agent-session.test.tsx ../mobile/src/transport/mobile-relay-rpc-session.test.ts ../mobile/src/transport/rpc-client-delivery-ambiguity.test.ts ../mobile/src/transport/stable-logical-rpc-client.test.ts",
"result": "passed",
"durationSeconds": 2.37,
"summary": "Ten focused mobile session, attachment, and transport files passed 113 tests."
Expand Down
69 changes: 44 additions & 25 deletions mobile/src/session/mobile-structured-agent-session-cancel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { activeStructuredAgentSessionTurnId } from '../../../src/shared/structur
import type { RpcClient } from '../transport/rpc-client'
import {
requestStructuredAgentSessionMutation,
retainStructuredSessionOperationId,
type StructuredAgentSessionMutationCallResult
} from './mobile-structured-agent-session-rpc'

Expand All @@ -27,55 +26,75 @@ export async function requestMobileStructuredAgentSessionCancel(args: {
sessionId: string | null
enabled: boolean
stateRef: { readonly current: StructuredAgentSessionState }
sessionKey: string
operationIds: Map<string, string>
promptCancelSupported: boolean | null
prompt?: PromptIdentity
/** Whether the host answers a repeated Stop of a turn quietly; null until the status probe answers. */
hostAnswersRepeatedStops: boolean | null
/** Stops still on their way, by what they stop; against a host that does not answer a repeat
* quietly, a press for the same one joins it here. */
inFlight: Map<string, Promise<boolean>>
onSendError: (message: string) => void
}): Promise<boolean> {
const { client, enabled, onSendError, operationIds, sessionId, sessionKey, stateRef } = args
const { client, enabled, inFlight, onSendError, sessionId, stateRef } = args
const current = stateRef.current
const turnId = activeStructuredAgentSessionTurnId(current.items)
if (!client || !sessionId || !enabled || current.fence === null || !turnId) {
onSendError('Stop not sent')
return false
}
// Check the capability before fields enter either the fingerprint or operation key.
// Check the capability before fields enter the fingerprint.
const fields = {
turnId,
...(args.prompt && args.promptCancelSupported === true ? { prompt: args.prompt } : {})
}
const key = `${sessionKey}:agentSession.cancel:${JSON.stringify(fields)}`
const clientOperationId = retainStructuredSessionOperationId(
operationIds,
key,
operationIds.get(key)
)
// Every press is its own Stop: a kept id would be answered from the last one and stop nothing.
const fence = current.fence
const stop = () => sendStop({ client, sessionId, fence, fields, onSendError })
if (args.hostAnswersRepeatedStops === true) {
return stop()
}
// Temporary, for a host that predates the quiet repeated Stop: remove once none is supported.
const key = `${sessionId}:agentSession.cancel:${JSON.stringify(fields)}`
const joined = inFlight.get(key)
if (joined) {
return joined
}
const stopping = stop()
inFlight.set(key, stopping)
// Gone once it settles, so the next press is a new Stop.
void stopping.finally(() => {
if (inFlight.get(key) === stopping) {
inFlight.delete(key)
}
})
return stopping
}

async function sendStop(input: {
client: RpcClient
sessionId: string
fence: number
fields: Record<string, unknown>
onSendError: (message: string) => void
}): Promise<boolean> {
const result: StructuredAgentSessionMutationCallResult<AgentSessionCancelResult> =
await requestStructuredAgentSessionMutation<AgentSessionCancelResult>({
client,
client: input.client,
method: 'agentSession.cancel',
fingerprintMethod: 'agentSession.cancel',
sessionId,
expectedRuntimeFence: current.fence,
fields,
clientOperationId
sessionId: input.sessionId,
expectedRuntimeFence: input.fence,
fields: input.fields
})
// Cancel's plan recovers no unknown ledger row, so an id the host answered that
// way earns the same refusal until it expires; keeping it leaves Stop unusable.
// Transport doubt proves nothing about delivery, so it stays a replay.
if (result.status !== 'unknown' || result.hostReportedOperationUnknown === true) {
operationIds.delete(key)
}
if (result.status === 'accepted') {
return true
}
if (result.status === 'unknown') {
onSendError('Stop unconfirmed — check chat before retrying')
input.onSendError('Stop unconfirmed — check chat before retrying')
} else if (result.status === 'refused') {
onSendError(result.message)
input.onSendError(result.message)
} else if (result.status === 'failed') {
onSendError(result.message)
input.onSendError(result.message)
}
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { describe, expect, it } from 'vitest'
import {
AGENT_SESSION_PROMPT_CANCEL_RUNTIME_CAPABILITY,
AGENT_SESSION_QUESTION_ANSWERS_RUNTIME_CAPABILITY,
AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY
AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY,
AGENT_SESSION_REPEATED_STOP_RUNTIME_CAPABILITY
} from '../../../src/shared/protocol-version'
import { structuredAgentSessionHostSupport } from './mobile-structured-agent-session-host-support'

Expand All @@ -11,16 +12,40 @@ describe('structuredAgentSessionHostSupport', () => {
expect(structuredAgentSessionHostSupport([])).toEqual({
promptCancel: false,
questionAnswers: false,
queuedMessages: false
queuedMessages: false,
quietRepeatedStop: false
})
expect(
structuredAgentSessionHostSupport([AGENT_SESSION_QUESTION_ANSWERS_RUNTIME_CAPABILITY])
).toEqual({ promptCancel: false, questionAnswers: true, queuedMessages: false })
).toEqual({
promptCancel: false,
questionAnswers: true,
queuedMessages: false,
quietRepeatedStop: false
})
expect(
structuredAgentSessionHostSupport([AGENT_SESSION_PROMPT_CANCEL_RUNTIME_CAPABILITY])
).toEqual({ promptCancel: true, questionAnswers: false, queuedMessages: false })
).toEqual({
promptCancel: true,
questionAnswers: false,
queuedMessages: false,
quietRepeatedStop: false
})
expect(
structuredAgentSessionHostSupport([AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY])
).toEqual({ promptCancel: false, questionAnswers: false, queuedMessages: true })
).toEqual({
promptCancel: false,
questionAnswers: false,
queuedMessages: true,
quietRepeatedStop: false
})
expect(
structuredAgentSessionHostSupport([AGENT_SESSION_REPEATED_STOP_RUNTIME_CAPABILITY])
).toEqual({
promptCancel: false,
questionAnswers: false,
queuedMessages: false,
quietRepeatedStop: true
})
})
})
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
AGENT_SESSION_PROMPT_CANCEL_RUNTIME_CAPABILITY,
AGENT_SESSION_QUESTION_ANSWERS_RUNTIME_CAPABILITY,
AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY
AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY,
AGENT_SESSION_REPEATED_STOP_RUNTIME_CAPABILITY
} from '../../../src/shared/protocol-version'

/** Structured-session features the connected host advertised; null until the status probe answers. */
Expand All @@ -10,6 +11,8 @@ export type StructuredAgentSessionHostSupport = {
questionAnswers: boolean
/** Mid-turn sends queue as host-held drafts; an older host keeps today's immediate path. */
queuedMessages: boolean
/** A Stop that stopped nothing adds no row, so a repeated Stop is quiet. */
quietRepeatedStop: boolean
}

export function structuredAgentSessionHostSupport(
Expand All @@ -18,6 +21,7 @@ export function structuredAgentSessionHostSupport(
return {
promptCancel: capabilities.includes(AGENT_SESSION_PROMPT_CANCEL_RUNTIME_CAPABILITY),
questionAnswers: capabilities.includes(AGENT_SESSION_QUESTION_ANSWERS_RUNTIME_CAPABILITY),
queuedMessages: capabilities.includes(AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY)
queuedMessages: capabilities.includes(AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY),
quietRepeatedStop: capabilities.includes(AGENT_SESSION_REPEATED_STOP_RUNTIME_CAPABILITY)
}
}
49 changes: 2 additions & 47 deletions mobile/src/session/mobile-structured-agent-session-rpc.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
import {
AGENT_SESSION_MAX_OPERATION_REPLAY_AGE_MS,
AGENT_SESSION_OPERATION_FUTURE_SKEW_MS,
parseAgentSessionOperationTimestamp
} from '../../../src/shared/agent-session-host-authority'
import type {
AgentSessionMutationResult,
AgentSessionWireRefusalCode
Expand Down Expand Up @@ -36,11 +31,7 @@ export type StructuredAgentSessionMutationCallResult<TValue> =
* it, so the same request can never be accepted there. An auth refusal does not set it:
* it says nothing about an earlier delivery of the same id. */
| { status: 'failed'; message: string; hostRejectedByRequestSchema?: true }
/** `hostReportedOperationUnknown` separates a host answer about the id from doubt
* about the effect. Whether that id can still be retried is the method's own
* question: a plan that recovers an unknown ledger row replays or reruns it, one
* that does not refuses the same id until the row expires. */
| { status: 'unknown'; hostReportedOperationUnknown?: true }
| { status: 'unknown' }

export type StructuredAgentSessionMutationResult<TValue> =
| { status: 'accepted'; value: TValue; sameFence: boolean }
Expand Down Expand Up @@ -108,42 +99,6 @@ export async function callAgentSession<TResult>(
return response.result as TResult
}

function isReplayableStructuredSessionOperationId(operationId: string, now: number): boolean {
const timestamp = parseAgentSessionOperationTimestamp(operationId)
return (
timestamp !== null &&
timestamp <= now + AGENT_SESSION_OPERATION_FUTURE_SKEW_MS &&
now - timestamp <= AGENT_SESSION_MAX_OPERATION_REPLAY_AGE_MS
)
}

/**
* Retains transient non-send mutation ids while the host can still replay them. Structured sends
* use the durable journal because delivery ambiguity itself does not expire.
*/
export function retainStructuredSessionOperationId(
operationIds: Map<string, string>,
key: string,
operationId?: string,
now: number = Date.now()
): string {
const retainedOperationId =
operationId && isReplayableStructuredSessionOperationId(operationId, now)
? operationId
: structuredSessionOperationId(now)
operationIds.delete(key)
operationIds.set(key, retainedOperationId)
for (const [retainedKey, retainedId] of operationIds) {
if (retainedKey === key) {
continue
}
if (!isReplayableStructuredSessionOperationId(retainedId, now)) {
operationIds.delete(retainedKey)
}
}
return retainedOperationId
}

export function timeoutForDeadline(deadline: number | undefined): number | null {
if (deadline === undefined) {
return STRUCTURED_SEND_TIMEOUT_MS
Expand Down Expand Up @@ -205,7 +160,7 @@ export async function requestStructuredAgentSessionMutation<TValue>(args: {
(method === 'agentSession.cancel' || method === 'agentSession.conversationCommand') &&
result.refusal.code === 'agent_session_operation_unknown'
) {
return { status: 'unknown', hostReportedOperationUnknown: true }
return { status: 'unknown' }
}
return result.ok
? { status: 'accepted', value: result.value }
Expand Down
53 changes: 22 additions & 31 deletions mobile/src/session/mobile-structured-composer-command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ function setup() {
client: { sendRequest } as unknown as RpcClient,
sessionId: 'session',
fence: 1,
sessionKey: 'session:1',
pending: { current: false },
operationIds: new Map(),
controller: {
agent: 'codex',
snapshot: [],
Expand Down Expand Up @@ -61,41 +59,34 @@ describe('mobile structured conversation commands', () => {
expect.objectContaining({ command: text.slice(1) }),
expect.anything()
)
expect(input.operationIds.size).toBe(0)
}
)
it('retains the exact operation ID after an unknown response', async () => {
const { input, sendRequest } = setup()
sendRequest.mockResolvedValueOnce({
ok: true,
result: { ok: true, value: { command: 'compact', state: 'unknown' } }
})
expect(await dispatchMobileStructuredCommand(input)).toBe('unknown')
expect(await dispatchMobileStructuredCommand(input)).toBe('accepted')
expect(sendRequest.mock.calls[0]?.[1]).toEqual(sendRequest.mock.calls[1]?.[1])
})
it('retains operation identity when the host explicitly reports an unknown ledger outcome', async () => {
const { input, sendRequest } = setup()
sendRequest.mockResolvedValueOnce({
ok: true,
result: {
ok: false,
refusal: { code: 'agent_session_operation_unknown', message: 'unconfirmed' }
it.each([
[
'the host reports the command unconfirmed',
{ ok: true, result: { ok: true, value: { command: 'compact', state: 'unknown' } } }
],
[
'the host cannot say what became of it',
{
ok: true,
result: {
ok: false,
refusal: { code: 'agent_session_operation_unknown', message: 'unconfirmed' }
}
}
} as never)
expect(await dispatchMobileStructuredCommand(input)).toBe('unknown')
expect(await dispatchMobileStructuredCommand(input)).toBe('accepted')
expect(sendRequest.mock.calls[0]?.[1]).toEqual(sendRequest.mock.calls[1]?.[1])
})
it('retains operation identity when the host fails after starting the command', async () => {
],
[
'the host fails after starting it',
{ ok: false, error: { code: 'runtime_error', message: 'settlement failed' } }
]
])('sends the next press as a new command after %s', async (_case, answer) => {
const { input, sendRequest } = setup()
sendRequest.mockResolvedValueOnce({
ok: false,
error: { code: 'runtime_error', message: 'settlement failed' }
} as never)
sendRequest.mockResolvedValueOnce(answer)
expect(await dispatchMobileStructuredCommand(input)).toBe('unknown')
expect(await dispatchMobileStructuredCommand(input)).toBe('accepted')
expect(sendRequest.mock.calls[0]?.[1]).toEqual(sendRequest.mock.calls[1]?.[1])
// Only the operation id differs between the two requests.
expect(sendRequest.mock.calls[1]?.[1]).not.toEqual(sendRequest.mock.calls[0]?.[1])
})
it.each(['attachments', 'old host', 'arguments', 'pending work'])(
'guards %s without provider dispatch',
Expand Down
Loading
Loading