mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 10:08:13 +00:00
* feat(agent-launch): let a caller reserve the chat session and carry session picks to a terminal launch * fix(agent-launch): keep a caller-minted session id named for its agent, and mint the fallback the same way * test(mobile): model the older host from the launch fields, not the refined schema * docs(agent-launch): describe the reserved session id as conversation identity, not placement The caller mints the session id so it knows which conversation it started; tab placement is not keyed on it. Also puts the terminal surface's doc comment back on createTerminalSurface. * docs(agent-launch): say a terminal launch reads the session picks on the wire contract The `sessionOptions` field doc still said a terminal launch ignores them, which this branch changed. * fix(agent-launch): check a reserved session id's token after the agent name, not the whole id A hyphenated agent name failed the one-token check, so any session id for such an agent was refused at the wire, while every other agent without a chat has its id ignored on the terminal.
76 lines
2.8 KiB
TypeScript
76 lines
2.8 KiB
TypeScript
import type { AgentSessionHandleProvider } from './agent-session-provider-handle'
|
|
import type { AgentSessionMutationEnvelope } from './agent-session-wire'
|
|
import {
|
|
createStructuredAgentSessionOperationId,
|
|
structuredAgentSessionCreateFingerprint
|
|
} from './structured-agent-session-mutation'
|
|
|
|
/**
|
|
* The conversation a create adopts instead of starting a fresh one.
|
|
*
|
|
* Deliberately carries an identity and nothing else. The transcript file and the account home it
|
|
* lives under are derived by the executing host, never sent: `agentSession.create` is reachable by
|
|
* paired mobile clients, and a client-supplied path would let one choose which file the host reads
|
|
* into a journal and which credential directory the provider child launches against.
|
|
*/
|
|
export type StructuredAgentSessionResumeSource = {
|
|
/** claude: the session id. codex: the thread id. */
|
|
providerSessionId: string
|
|
}
|
|
|
|
export type StructuredAgentSessionCreateParams = {
|
|
envelope: AgentSessionMutationEnvelope
|
|
worktree: string
|
|
agent: AgentSessionHandleProvider
|
|
resumeFrom?: StructuredAgentSessionResumeSource
|
|
}
|
|
|
|
/** Provider-prefixed so a session id names its lane on sight, and underscore-only
|
|
* so the id stays a single token everywhere it is embedded (tab ids, log keys). */
|
|
export function createStructuredAgentSessionId(
|
|
agent: AgentSessionHandleProvider,
|
|
randomUuid: () => string
|
|
): string {
|
|
return `${agent}_${randomUuid().replaceAll('-', '_')}`
|
|
}
|
|
|
|
/** Whether a caller-minted id keeps the shape `createStructuredAgentSessionId` gives every id:
|
|
* named for its agent, then one token. The token alone is checked, so a hyphenated agent name
|
|
* is not refused at the wire. */
|
|
export function isStructuredAgentSessionIdFor(agent: string, sessionId: string): boolean {
|
|
const prefix = `${agent}_`
|
|
return sessionId.startsWith(prefix) && /^[A-Za-z0-9_]+$/.test(sessionId.slice(prefix.length))
|
|
}
|
|
|
|
/**
|
|
* The durable `agentSession.create` envelope every client replays on an ambiguous
|
|
* transport failure. The fingerprint must be computed over the same fields the host
|
|
* recomputes, so both clients build it here rather than each assembling their own.
|
|
*/
|
|
export function structuredAgentSessionCreateParams(args: {
|
|
sessionId: string
|
|
worktree: string
|
|
agent: AgentSessionHandleProvider
|
|
resumeFrom?: StructuredAgentSessionResumeSource
|
|
randomUuid: () => string
|
|
now?: number
|
|
}): StructuredAgentSessionCreateParams {
|
|
const fields = {
|
|
worktree: args.worktree,
|
|
agent: args.agent,
|
|
...(args.resumeFrom ? { resumeFrom: args.resumeFrom } : {})
|
|
}
|
|
return {
|
|
envelope: {
|
|
sessionId: args.sessionId,
|
|
clientOperationId: createStructuredAgentSessionOperationId(args.randomUuid, args.now),
|
|
expectedRuntimeFence: null,
|
|
payloadFingerprint: structuredAgentSessionCreateFingerprint({
|
|
sessionId: args.sessionId,
|
|
...fields
|
|
})
|
|
},
|
|
...fields
|
|
}
|
|
}
|