{{ message }}
Repository navigation
Commit e83e40e
authored
Session History shows OpenCode, Grok, OMP and Pi chats as chats and refuses a second terminal writer (stablyai#27183)
* refactor(chat): answer transcript adoption and Session History from the agent registration
Claude and Codex's transcript importers and Session History ownership (row id,
resume-command grammar) move onto their runtime registrations as required-nullable
fields; every other agent writes null. agentSession.agents publishes the derived
transcriptAdoption/sessionHistory flags, and a client reads a host that omits them
(or lists nothing) as the old build's answer. Strict parity: only Claude and Codex
answer yes anywhere.
* refactor(chat): one Session History ownership index, binaries from row agents, fork offer from fork argv
Review round 1: the duplicate-adoption check and Session History ownership read one
index keyed by the registration's row id (an importer now requires sessionHistory);
resume-command binaries derive from rowAgents through the TUI agent config; the
Resume in New CLI offer asks getAgentForkArgv instead of naming Claude and Codex.
Strict parity: only Claude and Codex answer yes.
* feat(chat): Session History owns OpenCode, Grok, OMP and Pi native chats
An OpenCode, Grok, OMP or Pi native chat's conversation listed in Session
History as a plain terminal row, and resuming it ran the agent's CLI as a
second writer to the conversation the chat was still using. Each agent's
registration now fills `sessionHistory`, so those rows show as the chat
(its name, opening the chat) and Orca refuses a terminal resume of an owned
conversation, as it already did for Claude and Codex.
- OpenCode lists under `opencode` and `opencode2` (2.x) rows by its ses_ id;
`-s/--session`, `-c/--continue` resume, `--fork` does not.
- Grok: `-r/--resume/--load` and `-c`; a non-UUID value names a title, so it
is read as target-less; `--fork-session` does not resume.
- OMP: `-r/--resume/--session` take an id, any prefix of it, or the session
file's path; bare `--resume` and `-c` are target-less.
- Pi: rows are listed by the session file name's id while the chat holds the
file's path; `--session <id|prefix|path>`, `-c`, `-r` (picker).
- An optional `resumeTargetMatches` on the registration covers prefix and path
targets; it defaults to exact equality.
- Each agent now reads every token naming its own binary, so another agent's
name earlier in a command (`claude --model pi`, `cd ~/src/codex && claude
--resume X`) no longer hides a resume. For Claude and Codex this only ever
refuses more than before.
- A renamed OpenCode chat tab names its `opencode2` row too.
* fix(chat): show owned rows only to clients that open the chat, without a resume command
- The list and search projection now asks, per owning agent, whether the
requesting client opens that agent's chat. Current mobile renders only Claude
and Codex chats, so it no longer receives OpenCode/Grok/OMP/Pi rows owned by a
chat (a tap there opened an empty terminal and showed agent_session_conflict).
Claude and Codex keep their rule: any client that reads structured sessions.
- An owned search hit opens its chat, so it no longer carries a terminal resume
command (all agents; `orca` CLI search stopped printing one for a chat).
- OpenCode/Grok/OMP/Pi flags match case-sensitively, as their CLIs read them,
so `rg foo src/pi -C 3` is not `pi -c`. Claude and Codex still fold case.
- A test feeds every resume command Orca builds for an owned row of each agent
(Session History, live-tab argv; posix, PowerShell, cmd) into the guard.
* fix(chat): keep the resume guard linear and skip chat-tab lookups with no move
- Each agent binary mention in a command now reads its arguments only up to
that agent's next mention, which reads the rest, so every token is parsed
once per agent. A 200 KB text naming agents throughout took 9.4 s on the
host's main process; it now takes about 90 ms. Every refusal before still
holds: a later mention still reads its own resume.
- Right-clicking a native chat tab looks up its Session History row only when
the agent's CLI can fork a conversation, the one move a chat tab offers, so
OpenCode, Grok, OMP and Pi chat tabs run no list or rescan for nothing.
Claude and Codex are unchanged.
* fix(chat): read each shell command once in the resume guard
The guard tokenizes the text once and splits it into shell commands at
&&, ||, ;, |, & and newlines (a newline after a line-continuation mark stays
inside its command). In each command, each agent reads its arguments from its
first binary token to the command's end; a later token naming it is an
argument. A `claude` path inside a Claude command no longer ends that command,
so `--session-id <owned>` still cancels a fork after it, and a binary-named
path between a resume and its fork flag keeps the fork a fork. Binary names
are looked up once per token, which keeps a 16 MB send to about 2 s.
Against main's parser, a Claude/Codex command is now allowed only when main
refused it for a flag in a later shell command (`claude ; echo --resume X`).
* fix(chat): end a resume-guard command at a bare carriage return
A PTY's Enter, and many orca terminal send texts, end lines with \r. The guard
now treats \r and \r\n as line breaks like \n, including after a line
continuation mark, so a later line's resume is read as its own command.
* refactor(chat): drop the transcript-adoption and Session History wire flags
agentSession.agents no longer publishes transcriptAdoption or sessionHistory, so
there is no new field for older and newer peers to reconcile. Their only
consumers were renderer gates that could answer from what they already have:
"Resume in New Native Chat" eligibility goes back to main's rule (adopting a CLI
conversation is Claude/Codex-only, and the host still refuses any other agent from
its registration's transcriptImport). Removes the AgentSessionDeclaredCapabilities
split, the older-host decoder shim and the generic host-flag reader.
* refactor(chat): keep main's Claude/Codex rule for the CLI fork offer
"Resume in New CLI" and the chat-tab menu read the agent name again instead of
building a synthetic provider session to ask the fork builder, and the chat-tab
lookup loses its host Session History flag gate. Only Claude and Codex CLIs fork,
so only their chat tabs look up a row, exactly as on main: no new list requests.
* refactor(chat): one registration-aware ownership index, no registration union
- listStructuredProviderSessionOwnership reads each record's registration for its
Session History row id; the callback parameter and its one-function wrapper
module are gone (no import cycle: checked value and type imports).
- StructuredAgentCliConversations is a plain type: transcriptImport is nullable
and sessionHistory is required, since every registered agent now owns its rows.
The "importer needs history" union and its null checks go.
- A test pins that no two registrations claim the same Session History row agent,
since the owner lookup takes the first match.
* fix(chat): read resume commands into words as a shell does
Separators glued to a word (`opencode -s id; echo`, `cd /x&&claude -r id`) now end the
command, and quotes are removed inside a word, so `--session="id"` reads as the id. Applies
to every agent, Claude and Codex included. The acp-and-pi allowed() helper now asserts.
* fix(chat): count an agent's name only where a shell would run it
terminal.send checks agent prompts too, and agentPrompt does not keep the text from a shell (it
falls back to a plain PTY write), so prompt text like "Fix the Pi --resume flag" was refused.
The resume check now reads each command's program: its first word past VAR=x prefixes, a path,
and env/exec/command/sudo/npx/bunx/pnpm dlx. Every command Orca's builders produce, Claude and
Codex included and with a user's command override, is still refused.
* refactor(chat): compare resume ids in any case; Claude uses the shared option reader
The default target match now ignores case (ids are UUIDs or ses_ ids), so Grok's override,
which only repeated it, is gone. Claude folds its flags and reads them with
resumeInvocationFromOptions instead of repeating the `=` handling.
* perf(chat): read terminal text in one linear pass
A repeated regex group overflowed the stack on a 16 MB word. A sticky-regex scanner reads words,
quoted runs and separators in one pass; an unclosed quote is searched for once per quote kind.
* refactor(chat): read a command's resume only when its program is an agent
* fix(chat): read an agent run under nohup, time or wsl as the command's program
* chore: restore pnpm-lock.yaml
* fix(chat): keep the CLI's own title on OpenCode, Grok, OMP and Pi chat rows
Session History shows these agents' chat conversations under the title their CLI saved, as it does
for their terminal conversations; the chat tab's name and renames stay on the tab. Claude and Codex
rows keep the chat's name, as on main.
* feat(chat): Resume in New CLI for Grok and Pi chats
A Grok or Pi chat's Session History row and tab menu now offer "Resume in New CLI", like Claude and
Codex: the CLI opens a copy of the conversation (grok --resume <id> --fork-session, pi --fork <file>)
and the chat keeps its own. OpenCode's interactive CLI and OMP have no way to open a copy, so their
chats keep only Resume.
* fix(chat): offer Resume in New CLI only when the copy command can be built
A Pi chat found by search on a remote Orca server has no session file path, so its copy command
can't be built; the row no longer offers the button there.
* fix(chat): refuse pi --session-id of a conversation a chat owns
`pi --session-id <id>` reopens that session when it exists, so it is a second writer like --session.1 parent 2b62a3d commit e83e40e
39 files changed
Lines changed: 1996 additions & 333 deletions
File tree
- src
- main
- acp
- ai-vault
- claude
- codex
- grok
- ipc
- native-chat
- agent-session-wire
- omp
- opencode
- pi
- runtime
- rpc/methods
- renderer/src/components
- right-sidebar
- tab-bar
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |

0 commit comments