Files
orca/src/shared/structured-agent-cli-conversation-adoption.ts
T
NeilandZrzzzz a1c6e1273d Continue remote CLI conversations in Chat UI on paired servers (#33954)
* Enable continuing remote CLI conversations in Chat UI

* fix(native-chat): send the host's own pane key; ask older hosts to update

On a paired host the desktop names a pane by its mirrored surface key, but
the host matches cliSource against its own agent-status rows, so every
remote "Continue in Chat UI" create was refused as unreadable. Translate
the key with toHostSessionPaneKey before sending.

A resume launch's join identity now includes its execution host, so a
remote resume never joins an in-flight resume of the same conversation id
on another host.

A verified host that lacks resume-history now shows the pane-header action
disabled, with "Update Orca on this host to continue in Chat UI." in its
tooltip and accessible name, instead of hiding it.

---------

Co-authored-by: Zrzzzz <1160026659@qq.com>
2026-10-26 07:17:41 -07:00

39 lines
1.6 KiB
TypeScript

/** Adoption order by Session History row agent; registration tests require a transcript importer for every target.
* Conversations stay on their recording host, which validates importer availability before adoption. */
export const CLI_CONVERSATION_ADOPTING_AGENTS = {
claude: ['claude'],
codex: ['codex'],
grok: ['grok'],
omp: ['omp'],
opencode: ['opencode'],
// OpenCode 2 chats require 2.x; ordinary OpenCode chats can adopt when their installed opencode is 2.x.
opencode2: ['opencode2', 'opencode'],
pi: ['pi']
} as const
/** A Session History row agent whose conversations a chat can take over. */
export type CliConversationRowAgent = keyof typeof CLI_CONVERSATION_ADOPTING_AGENTS
export function adoptsCliConversations(agent: unknown): agent is CliConversationRowAgent {
return typeof agent === 'string' && Object.hasOwn(CLI_CONVERSATION_ADOPTING_AGENTS, agent)
}
/** Whether chats of the two agents can hold one conversation: both take over one row's. */
export function chatAgentsShareConversations(left: string, right: string): boolean {
return (
left === right ||
Object.values(CLI_CONVERSATION_ADOPTING_AGENTS).some(
(agents: readonly string[]) => agents.includes(left) && agents.includes(right)
)
)
}
/** Whether two rows' conversations can be one: a chat that takes over either takes over both. */
export function cliConversationRowsShareAgent(
left: CliConversationRowAgent,
right: CliConversationRowAgent
): boolean {
const rightAgents: readonly string[] = CLI_CONVERSATION_ADOPTING_AGENTS[right]
return CLI_CONVERSATION_ADOPTING_AGENTS[left].some((agent) => rightAgents.includes(agent))
}