@threahq/remote-session 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +219 -0
- package/attachments.d.ts +107 -0
- package/client.d.ts +146 -0
- package/config-file.d.ts +12 -0
- package/delegation-client.d.ts +98 -0
- package/delegation-runner.d.ts +57 -0
- package/examples/echo-connector.ts +73 -0
- package/examples/mention-bot.ts +120 -0
- package/identity.d.ts +157 -0
- package/index.d.ts +10 -0
- package/index.js +3683 -0
- package/index.js.map +19 -0
- package/lifecycle.d.ts +41 -0
- package/package.json +44 -0
- package/session.d.ts +729 -0
- package/session.test-support.d.ts +6 -0
- package/tool-trace.d.ts +14 -0
- package/turn-route.d.ts +149 -0
package/index.js.map
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/session.ts", "../src/attachments.ts", "../src/identity.ts", "../src/client.ts", "../src/turn-route.ts", "../src/config-file.ts", "../src/lifecycle.ts", "../src/delegation-client.ts", "../src/delegation-runner.ts", "../src/tool-trace.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { createHash } from \"node:crypto\"\nimport { homedir, hostname } from \"node:os\"\nimport { join } from \"node:path\"\nimport {\n ArchiveGraceController,\n BotKeyring,\n E2eKeyring,\n e2eKeyAccount,\n mintE2eKeyRecord,\n readLegacyBikFile,\n resolveKeyStore,\n FileKeyStore,\n WS_BACKSTOP_POLL_MS,\n BotRuntimeTransport,\n mintStreamKeyWraps,\n openSealedAck,\n openSealedDecisionNote,\n openSealedTurnContext,\n parseSealedAckContext,\n parseSealedTurnContext,\n scrubSealedError,\n sealDecision,\n sealReply,\n sealStep,\n type BotDecisionPayload,\n type BotRuntimeHello,\n type CreateDecisionRequestBody,\n type DecisionOption,\n type DecisionRequest,\n type DelegationAvailableNudge,\n type SealingState,\n type InvocationInputUpdate,\n type ObservedClaimHandle,\n type SealedReplyBody,\n type StepFrame,\n} from \"@threahq/bot-runtime-client\"\nimport {\n downloadInboundAttachments,\n downloadSealedInboundAttachments,\n formatInboundAttachmentManifest,\n selectSealedInboundRefs,\n uploadReplyAttachments,\n uploadSealedReplyAttachments,\n} from \"./attachments\"\nimport { sanitizeId, type RemoteSessionConfig } from \"./identity\"\nimport {\n ThreaApiError,\n ThreaClient,\n type ClaimedInvocation,\n type ExternalHistoryMessage,\n type RuntimeSessionLink,\n} from \"./client\"\nimport { RouteRevokedError, TurnRoute, type CloseRequest, type PostIntent, type PreparedClose } from \"./turn-route\"\n\nexport const SUPPORTED_CAPABILITIES = [\"active-scratchpad\", \"mentionable\"] as const\nexport const SESSION_CONTROL_CAPABILITY = \"session-control\"\n// Mirror Pi's STEER_DRAIN_LIMIT: how many queued messages a single /steer folds\n// into one combined turn before stopping (a backstop, not an expected count).\nconst STEER_DRAIN_LIMIT = 10\n/** Milliseconds to wait after an interrupt before delivering the steer turn, so the runtime has returned to idle. */\nexport const STEER_SETTLE_MS = 250\n\nconst CLAIM_TTL_SECONDS = 120\n// With NO socket, the poll is the only delivery path, but a fast fixed cadence\n// is how a single wedged session burned ~29k billed edge requests/day. Back off\n// empty ticks exponentially from config.pollMs to this cap; a claimed turn or a\n// socket reconnect resets to the fast cadence. Worst-case degraded latency for\n// a socketless session is one cap interval.\nconst NO_SOCKET_POLL_CAP_MS = 2 * 60 * 1000\nconst CLAIM_RETRY_CAP_MS = 2 * 60 * 1000\n// Harness preflight can take 10s and replacement verification up to 15s.\nexport const RECONNECT_HANDOFF_FALLBACK_MS = 30_000\nconst MAX_CLAIMS_PER_DRAIN = 20\n// Server-side cap on `excludeResponseStreamIds` (`claimInvocationSchema` in\n// apps/backend/src/features/public-api/schemas.ts). A drain excludes every\n// in-flight stream plus each stream it stopped, so the turn cap leaves room\n// for a full drain of stops.\nconst MAX_EXCLUDED_RESPONSE_STREAMS = 32\nconst MAX_CONCURRENT_TURNS = MAX_EXCLUDED_RESPONSE_STREAMS - MAX_CLAIMS_PER_DRAIN\n// Server-side cap on frames per bot:invocation:steps call (`stepsFrameSchema`\n// in apps/backend/src/features/bot-runtimes/socket-handler.ts).\nconst MAX_STEP_FRAMES_PER_CALL = 50\nconst MAX_CONTEXT_MESSAGES = 12\nconst MAX_MESSAGE_CHARS = 2_000\n// Recent messages to scan for inbound attachments. The trigger message is always\n// the newest, so this comfortably covers it plus the history the agent is shown.\nconst ATTACHMENT_SCAN_LIMIT = 30\n// Bounds retained stream keys and callback tokens while covering several hours of typical channel use.\nexport const COMPLETED_TURN_MEMORY = 64\n// These 4xx responses can clear on retry; other 4xx responses permanently revoke the route.\nconst RETRYABLE_POST_STATUSES = new Set([408, 425, 429])\n\nexport interface ModelSuggestionInfo {\n value: string\n label?: string\n description?: string\n}\n\n/** A runtime this session can hand a `/spawn` off to; `description` is the resolved binary path. */\nexport interface SpawnRuntimeInfo {\n value: string\n label: string\n /** What `--thinking` accepts for THIS runtime, so a Claude desk can offer Pi's levels and back. */\n thinkingLevels: readonly string[]\n /** What `--model` accepts for THIS runtime, read from its own config on this machine. */\n models: readonly ModelSuggestionInfo[]\n description?: string\n}\n\n/** A turn handed to the connector for execution by its runtime. */\nexport interface DeliveredTurn {\n invocationId: string\n streamId: string\n /** The stream tree the turn belongs to: the session's scratchpad, or a channel or DM root when the bot was mentioned there. */\n rootStreamId: string\n sourceMessageId: string\n content: string\n /**\n * The turn arrived sealed (E2EE): everything the connector records for it is\n * ciphertext to the server, so a transcript tracer may run in full-detail\n * mode — the point of sealed steps is more for the owner, nothing for the server.\n */\n sealed: boolean\n}\n\n/**\n * How a connector drives its runtime for session control. `stop` and `steer`\n * are actuated by the SDK itself (they manipulate SDK-owned turn state) using\n * `interrupt()`/`steer()`; every other advertised command is routed to\n * `runCommand`, which returns the user-facing ack markdown.\n */\nexport interface SessionControlInvocationContext {\n rootStreamId: string\n /** The message the user typed the command into — what a command anchors its thread on. */\n sourceMessageId: string\n}\n\nexport interface SessionControlActuator {\n /** Command names to advertise (must be Threa catalog names, e.g. \"model\", \"thinking\", \"compact\", \"run\", \"reload\", \"steer\", \"stop\"). */\n commands: readonly string[]\n /** Model options for the composer's arg picker. */\n modelSuggestions?: readonly ModelSuggestionInfo[]\n /** Levels for the canonical /thinking command's arg picker. */\n thinkingLevels?: readonly string[]\n /** Runtimes for the canonical /spawn command's arg picker. */\n spawnRuntimes?: readonly SpawnRuntimeInfo[]\n /** Which of them a `/spawn` naming no runtime lands on, so the picker offers its models first. */\n spawnDefaultRuntime?: string\n /**\n * Interrupt the runtime's current turn. False = control lost (e.g. pane gone).\n * The SDK always passes the stream the turn answers into; a serial runtime may\n * ignore it, but a runtime declaring `maxConcurrentTurns > 1` must interrupt\n * only that stream's turn.\n */\n interrupt(streamId?: string): boolean\n /**\n * Fold text into the RUNNING turn without interrupting it — the runtime's\n * native mid-turn steering (typing into Claude Code while it works). When\n * present and a turn is in flight, /steer steers in place: the running\n * invocation keeps its trace and its reply. Absent, /steer falls back to\n * interrupt + redeliver. False = control lost. The SDK always passes the\n * target stream; a serial runtime may ignore it, but a runtime declaring\n * `maxConcurrentTurns > 1` must steer only that stream's turn.\n */\n steer?(text: string, streamId?: string): Promise<boolean> | boolean\n runCommand(\n name: string,\n args: string,\n context: SessionControlInvocationContext\n ): Promise<{\n /** False rejects the command: it closes as failed with `message` as the reason and nothing is posted. */\n ok: boolean\n /** What the command did (\"Set the model to opus\"). It lands on the command's own entry, not in the stream. */\n summary?: string\n /** Reply markdown, for a command whose result is content the user asked for (`/status`'s report) rather than an account of it. */\n message?: string\n afterAck?: () => unknown | Promise<unknown>\n /**\n * Hand the still-open command to another process, which drives its steps\n * and closes it with this claim. Nothing is posted and the SDK stops\n * observing the command once the handoff returns; a throw fails it here.\n */\n handoff?: (claim: HandedOffCommandClaim) => unknown | Promise<unknown>\n /**\n * Set by a handoff this session outlives (`/spawn` launches a second agent).\n * The default assumes the handoff is winding this session down, so presence\n * parks busy and claiming pauses until the process is gone; a session that\n * keeps running must answer the next message instead of sitting out the\n * fallback window. `onHandoffReset` belongs to the parked path only.\n */\n handoffKeepsSessionRunning?: boolean\n onHandoffReset?: () => unknown | Promise<unknown>\n }>\n}\n\n/** What another process needs to report on, renew and close a claimed command. */\nexport interface HandedOffCommandClaim {\n workspaceId: string\n invocationId: string\n instanceId: string\n claimToken: string\n}\n\n/**\n * What a connector implements. The SDK owns the whole session lifecycle —\n * linking, claiming, steer/stop semantics, presence, idle timeouts, claim\n * renewal, attachments — and calls the delegate at the two points a runtime\n * differs: delivering a turn into it, and (optionally) driving it.\n */\nexport interface RemoteSessionDelegate {\n /** Push a turn into the runtime. Resolve when handed off (not when answered). */\n deliverTurn(turn: DeliveredTurn): Promise<void>\n /**\n * The scratchpad link was created or resumed (also after an unarchive\n * reattach). Runs before the link is committed locally and before presence\n * is synced, so a connector can record what this process now owns. A throw\n * leaves the session unlinked for this tick (the next poll links again); it\n * does not stop the session from connecting or claiming meanwhile.\n */\n onLinked?(link: RuntimeSessionLink): Promise<void> | void\n /** Present iff the connector can drive the runtime. Gates advertising session control (fail-safe). */\n sessionControl?: SessionControlActuator\n /**\n * The linked scratchpad was archived (the server already ended the session\n * link) and stayed archived through the restore grace window. Called after\n * the SDK has gone offline and failed its in-flight turns; the connector\n * finishes the wind-down — the Claude channel pushes its branch and kills\n * its own tmux window, so this hook may never return. An unarchive within\n * the grace window reattaches the session instead and this never fires.\n */\n onArchived?: (payload: { rootStreamId: string }) => Promise<void> | void\n}\n\nexport interface ShutdownOptions {\n /**\n * The host runtime died under us — stdin closed and the parent process is\n * gone: an OOM kill, a crash, a supervisor that took the pane down. A host\n * that quit and closed us on the way out does not set this.\n */\n hostGone?: boolean\n}\n\n/** The connector's runtime identity and user-facing wording. */\nexport interface RuntimeDescriptor {\n /** Threa runtime kind, e.g. \"claude-code-channel\". */\n kind: string\n /** `bot:hello` output manifest. */\n manifest?: BotRuntimeHello[\"manifest\"]\n /** Presence status text while a turn is executing, e.g. \"Working in Claude Code…\". */\n busyStatusText: string\n /** Trace note recorded when a turn is handed to the runtime. */\n forwardedNote?: string\n /** Error recorded on in-flight turns when the session shuts down. */\n shutdownErrorMessage: string\n /**\n * Streams that may run a turn at the same time. Absent = 1 = serial: one turn\n * at a time across the whole session. Above 1, at most one turn per response\n * stream runs, and the actuator must honour the `streamId` passed to\n * `interrupt`/`steer`. At most 12.\n */\n maxConcurrentTurns?: number\n}\n\nexport interface SendResult {\n ok: boolean\n message: string\n /** Set when the failure leaves the request open so the caller may retry. */\n retryable?: boolean\n closedTurn?: true\n}\n\nexport interface RemoteSessionStatusSnapshot {\n stopped: boolean\n linkGeneration: number\n linkState: \"unlinked\" | \"linked\" | \"detached\"\n rootStreamId?: string\n activeStreamId?: string\n socketConnected: boolean\n inflightCount: number\n activeTurnStreamId?: string\n /** Distinct response streams with an in-flight turn. */\n inflightStreamIds: string[]\n /** Decisions opened on the stream and still awaiting an answer. */\n pendingDecisionCount: number\n}\n\ntype SessionControlCommand = { name: string; args: string }\n\n/**\n * Extract the session-control command (name + args) from a claimed invocation.\n * Prefers the structured `metadata.command` the dispatch endpoint stamps; falls\n * back to parsing the `/name args` prompt for a session-control invocation.\n */\nexport function parseSessionControlCommand(invocation: ClaimedInvocation): SessionControlCommand | null {\n const meta = invocation.metadata?.command\n if (meta && typeof meta === \"object\") {\n const value = meta as Record<string, unknown>\n if (value.executionKind === \"bot-runtime\" && typeof value.name === \"string\") {\n return { name: value.name.toLowerCase(), args: typeof value.args === \"string\" ? value.args.trim() : \"\" }\n }\n }\n if (invocation.trigger !== SESSION_CONTROL_CAPABILITY) return null\n const match = invocation.promptMarkdown.trim().match(/^\\/([\\w-]+)(?:\\s+([\\s\\S]*))?$/)\n if (!match) return null\n return { name: match[1]!.toLowerCase(), args: (match[2] ?? \"\").trim() }\n}\n\nexport function isSessionControlInvocation(invocation: ClaimedInvocation): boolean {\n return invocation.trigger === SESSION_CONTROL_CAPABILITY && parseSessionControlCommand(invocation) !== null\n}\n\n/**\n * Turn a claimed invocation into the body the runtime reads. The source message\n * is the request; any hydrated history follows as compact context.\n */\nexport function formatInvocationContent(invocation: ClaimedInvocation): string {\n const prompt = invocation.promptMarkdown.trim() || \"(empty message)\"\n const history = (invocation.context?.messages ?? [])\n .filter((message) => message.messageId !== invocation.sourceMessageId)\n .slice(-MAX_CONTEXT_MESSAGES)\n .map((message) => {\n const author = message.authorDisplayName?.trim() || message.role\n const content = message.contentMarkdown.trim().slice(0, MAX_MESSAGE_CHARS)\n return `- ${author}: ${content}`\n })\n\n if (history.length === 0) return prompt\n return [prompt, \"\", \"Earlier in this scratchpad (oldest first, for context):\", ...history].join(\"\\n\")\n}\n\nexport function withInboundAttachments(content: string, manifest: string): string {\n return manifest ? `${content}\\n\\n${manifest}` : content\n}\n\n/** Fold the steer text + any swept queued messages into one prompt (most recent last). */\nexport function buildSteerContent(parts: string[]): string {\n if (parts.length === 1) return parts[0]!\n return [\"Handle all of the following together (most recent last):\", \"\", parts.join(\"\\n\\n---\\n\\n\")].join(\"\\n\")\n}\n\n/** Capabilities advertised in hello + presence. Session control only when the connector can drive the runtime. */\nexport function supportedCapabilitiesFor(sessionControlEnabled: boolean): string[] {\n return sessionControlEnabled ? [...SUPPORTED_CAPABILITIES, SESSION_CONTROL_CAPABILITY] : [...SUPPORTED_CAPABILITIES]\n}\n\nexport function effectiveRuntimeManifest(\n manifest: BotRuntimeHello[\"manifest\"] | undefined,\n actuator: SessionControlActuator | undefined\n): NonNullable<BotRuntimeHello[\"manifest\"]> {\n return {\n output: { ...(manifest?.output ?? {}) },\n input: { updates: actuator?.steer ? \"live\" : \"restart\" },\n }\n}\n\n/**\n * Capabilities to claim with. Idle: everything we support. Busy (a turn in\n * flight): session-control ONLY, so /stop and /steer jump the queue while a\n * normal active-scratchpad follow-up waits. Empty when busy without runtime\n * control (callers must not claim in that state).\n */\nexport function claimCapabilitiesFor(busy: boolean, sessionControlEnabled: boolean): string[] {\n if (!busy) return supportedCapabilitiesFor(sessionControlEnabled)\n return sessionControlEnabled ? [SESSION_CONTROL_CAPABILITY] : []\n}\n\nexport function runtimeCapabilitiesFor(\n runtimeSessionId: string,\n actuator: SessionControlActuator | undefined\n): Record<string, unknown> {\n return {\n runtimeSessionId,\n supportsActiveScratchpad: true,\n supportsPersistentSessions: true,\n ...(actuator\n ? {\n supportsSessionControlCommands: true,\n sessionControlCommands: [...actuator.commands],\n ...(actuator.modelSuggestions ? { modelSuggestions: [...actuator.modelSuggestions] } : {}),\n ...(actuator.thinkingLevels ? { thinkingLevels: [...actuator.thinkingLevels] } : {}),\n ...(actuator.spawnRuntimes ? { spawnRuntimes: [...actuator.spawnRuntimes] } : {}),\n ...(actuator.spawnDefaultRuntime ? { spawnDefaultRuntime: actuator.spawnDefaultRuntime } : {}),\n }\n : {}),\n }\n}\n\ntype ObservedClaimPhase = \"unstarted\" | \"processing\" | \"running\" | \"terminal\"\n\ninterface ObservedClaim {\n invocation: ClaimedInvocation\n handle: ObservedClaimHandle\n phase: ObservedClaimPhase\n updateInProgress: boolean\n restartPending: boolean\n lifecycle: AbortController\n /** Running turn whose input incorporated this folded/swept claim. */\n runningOwnerInvocationId?: string\n}\n\n/** The turn's source moved on between preparing a post and putting it on the wire. */\nclass StaleInputError extends Error {}\n\n/**\n * The descriptive half of a presence body, handed to {@link RemoteSessionOptions.onPresence}\n * after it has been published. Status is included so a supervisor can tell a\n * session that is running from one that shut down; the BIK is not, because it\n * belongs to the running process alone.\n */\nexport interface RuntimePresenceReport {\n runtimeKind: string\n instanceId: string\n runtimeSessionId: string\n displayName: string\n status: \"available\" | \"busy\" | \"offline\"\n capabilities: Record<string, unknown>\n manifest: Record<string, unknown>\n}\n\n/** A presence body on the wire: the report's fields plus the status text and BIK the server needs. */\ntype PresenceBody = RuntimePresenceReport & Record<string, unknown>\n\nexport interface RemoteSessionOptions {\n config: RemoteSessionConfig\n client: ThreaClient\n delegate: RemoteSessionDelegate\n runtime: RuntimeDescriptor\n /** Injectable for tests. */\n transport?: BotRuntimeTransport\n /**\n * Tap for the workspace-wide `delegation:available` socket nudge (roadmap\n * 5.4) — wire it to a `DelegationRunner.notifyAvailable()`. The nudge payload\n * carries the delegation id so a runner lacking the stream grant can claim it\n * by id (and, on 404, request access, F3). Only fires on the SDK-constructed\n * transport; an injected transport owns its callbacks.\n */\n onDelegationAvailable?: (payload?: DelegationAvailableNudge) => void\n /**\n * Called with every presence this session publishes, hello included, once the\n * write has gone through. A supervising connector records it so presence can\n * be held while the session's process is not running; a public connector has\n * no use for it and leaves it unset.\n */\n onPresence?: (presence: RuntimePresenceReport) => void\n log?: (message: string) => void\n /** Override the archive→restore grace window (tests). */\n archiveGraceMs?: number\n}\n\n/**\n * A linked Threa scratchpad session for one runtime instance. Owns the whole\n * loop: link creation, claim drain + busy semantics, steer/stop, presence,\n * idle timeouts, claim renewal, and attachment plumbing. Connectors implement\n * `RemoteSessionDelegate` and call `sendInterim`/`reply` from their runtime.\n */\n/** What a connector asks its human when it cannot make the call itself. */\nexport interface DecisionRequestInput {\n title: string\n /** Markdown body shown under the title on the card. */\n body?: string\n options: DecisionOption[]\n allowNote?: boolean\n externalRef?: string\n expiresInMs?: number\n /** Defaults to the active turn's stream, then the root stream. */\n streamId?: string\n /** Defaults to the in-flight invocation on that stream when one is running. */\n invocationId?: string\n}\n\nexport type DecisionOutcome =\n | { status: \"resolved\"; optionId: string; note: string | null; decision: DecisionRequest }\n | { status: \"cancelled\" | \"expired\"; decision: DecisionRequest }\n\n/** Thrown into every awaiting `requestDecision` when the session tears down. */\nexport class DecisionAbandonedError extends Error {\n constructor(readonly decisionId: string) {\n super(`Decision ${decisionId} was abandoned: the remote session is shutting down.`)\n this.name = \"DecisionAbandonedError\"\n }\n}\n\ninterface PendingDecision {\n decision: DecisionRequest\n /** The turn's sealing state, kept so the answer's sealed note can be opened. */\n sealing?: SealingState\n resolve: (outcome: DecisionOutcome) => void\n reject: (error: Error) => void\n}\n\nfunction decisionAbortError(decisionId: string): Error {\n const error = new Error(`Decision ${decisionId} was aborted by its caller.`)\n error.name = \"AbortError\"\n return error\n}\n\nexport class RemoteSession {\n private readonly config: RemoteSessionConfig\n private readonly client: ThreaClient\n private readonly delegate: RemoteSessionDelegate\n private readonly runtime: RuntimeDescriptor\n private readonly transport: BotRuntimeTransport\n private readonly log: (message: string) => void\n private readonly onPresence: ((presence: RuntimePresenceReport) => void) | undefined\n private readonly bik: BotKeyring\n /** The keyring as last advertised to the server, so a grant only writes presence when it added a key. */\n private advertisedKeyIds = \"\"\n private readonly hello: BotRuntimeHello\n /** This bot's own id, learned from the `bot:hello` ack — a sealed card's AAD names its requester. */\n private botId: string | undefined\n private link: RuntimeSessionLink | undefined\n private linkGeneration = 0\n private claiming = false\n /** Claim HTTP mutates server presence outside presenceTail, so teardown waits for its drain. */\n private claimDrainTask: Promise<boolean> | undefined\n private claimRetryTimer: ReturnType<typeof setTimeout> | undefined\n private claimFailures = 0\n private reconnectHandoff = false\n private onHandoffReset: (() => unknown | Promise<unknown>) | undefined\n private reconnectResetTimer: ReturnType<typeof setTimeout> | undefined\n private reconnectFallbackTask: Promise<unknown> | undefined\n private stopped = false\n private readonly archive: ArchiveGraceController\n private pollTimer: ReturnType<typeof setTimeout> | undefined\n /** Consecutive empty poll ticks while the socket is down; drives the poll backoff. */\n private emptyNoSocketPolls = 0\n private readonly inflight = new Map<string, TurnRoute>()\n private readonly completed = new Map<string, TurnRoute>()\n private readonly terminalReplies = new Map<string, { replyDigest?: string }>()\n private nextRouteOrder = 0\n /** Teardown generation fences stale routes from writes, reinsertion, and presence changes. */\n private lifecycle = 0\n private presenceTail: Promise<void> = Promise.resolve()\n private readonly observedClaims = new Map<string, ObservedClaim>()\n // Weak ownership avoids retaining every unique cancelled invocation id for\n // the lifetime of a long-running connector while still fencing references\n // held by an interceptor/fold/command that outlive map removal.\n private readonly cancelledInvocations = new WeakSet<ClaimedInvocation>()\n private claimDrainRequested = false\n private claimDrainScheduled = false\n // The invocation whose turn is executing — the stream a relayed permission\n // prompt belongs in. Set when a non-intercepted invocation is pushed to the\n // runtime. Tracking it beats guessing from the in-flight map, where a\n // follow-up claimed during an open-permission window would otherwise be\n // picked as the (wrong) target.\n private activeTurnStream: string | undefined\n /** Decisions this session opened and is still awaiting an answer for, keyed by decision id. */\n private readonly pendingDecisions = new Map<string, PendingDecision>()\n private decisionPollTimer: ReturnType<typeof setTimeout> | undefined\n private readonly maxConcurrentTurns: number\n\n constructor(options: RemoteSessionOptions) {\n const maxConcurrentTurns = options.runtime.maxConcurrentTurns ?? 1\n if (!Number.isInteger(maxConcurrentTurns) || maxConcurrentTurns < 1) {\n throw new Error(`maxConcurrentTurns must be a positive integer, got ${maxConcurrentTurns}`)\n }\n if (maxConcurrentTurns > MAX_CONCURRENT_TURNS) {\n throw new Error(`maxConcurrentTurns must be at most ${MAX_CONCURRENT_TURNS}, got ${maxConcurrentTurns}`)\n }\n this.maxConcurrentTurns = maxConcurrentTurns\n this.config = options.config\n this.client = options.client\n this.delegate = options.delegate\n this.runtime = options.runtime\n this.log = options.log ?? (() => undefined)\n this.onPresence = options.onPresence\n this.archive = new ArchiveGraceController(\n {\n isArchived: async (rootStreamId) => Boolean(await this.client.getStreamArchivedAt(rootStreamId)),\n reattach: () => this.relinkAfterRestore(),\n onDetached: (rootStreamId) => this.detachForArchive(rootStreamId),\n onReattached: async () => {\n await this.syncPresence()\n await this.claimDrain()\n },\n onWindDown: (rootStreamId) => this.windDownForArchive(rootStreamId),\n log: this.log,\n },\n options.archiveGraceMs === undefined ? {} : { graceMs: options.archiveGraceMs }\n )\n this.bik = new BotKeyring({ keyring: () => this.buildKeyring(), log: this.log })\n // The transport re-sends this exact object on every reconnect hello, so the\n // key fields assigned into it at start() (after ensure()) ride every one.\n this.hello = {\n ...this.presenceBody(\"available\"),\n supportedCapabilities: supportedCapabilitiesFor(this.sessionControlEnabled),\n }\n this.transport =\n options.transport ??\n new BotRuntimeTransport({\n baseUrl: this.config.baseUrl,\n workspaceId: this.config.workspaceId,\n apiKey: this.config.apiKey,\n hello: this.hello,\n beforeHello: () => this.refreshHelloCapabilities(),\n callbacks: {\n onInvocationAvailable: () => void this.claimDrain(),\n ...(options.onDelegationAvailable\n ? { onDelegationAvailable: (payload: DelegationAvailableNudge) => options.onDelegationAvailable?.(payload) }\n : {}),\n onE2eGrant: (payload) => void this.keyGrantedStreams([payload.streamId]),\n onE2eRevoke: (payload) => void this.keyRevokedStream(payload.streamId),\n onBootstrap: (bootstrap) => {\n if (bootstrap.botId) this.botId = bootstrap.botId\n // A reconnect is exactly when an archive push went missing, so\n // re-derive before trusting the link the bootstrap arrived on.\n void this.probeArchiveBackstop()\n // Catch-up for the grants that landed while this instance was down.\n if (bootstrap.e2eGrantedStreamIds.length > 0) void this.keyGrantedStreams(bootstrap.e2eGrantedStreamIds)\n if (bootstrap.availableInvocations.length > 0 || bootstrap.ownedClaims.length > 0) void this.claimDrain()\n if (this.pendingDecisions.size > 0) this.scheduleDecisionPoll(0)\n },\n onDisconnected: () => this.handleTransportDisconnected(),\n onSessionArchived: (payload) => void this.handleSessionArchived(payload),\n onSessionRestored: (payload) => void this.handleSessionRestored(payload),\n onDecisionResolved: (payload) => this.handleDecisionPush(payload),\n onDecisionCancelled: (payload) => this.handleDecisionPush(payload),\n },\n log: this.log,\n })\n }\n\n private get sessionControlEnabled(): boolean {\n return Boolean(this.delegate.sessionControl)\n }\n\n private get parallel(): boolean {\n return this.maxConcurrentTurns > 1\n }\n\n /** Distinct response streams of the in-flight routes. */\n private inflightStreams(): Set<string> {\n return new Set([...this.inflight.values()].map((route) => route.invocation.responseStreamId))\n }\n\n /** With the serial default this is exactly `inflight.size > 0`. */\n private get atCapacity(): boolean {\n return this.inflightStreams().size >= this.maxConcurrentTurns\n }\n\n private refreshHelloCapabilities(): void {\n let status: \"available\" | \"busy\" | \"offline\" = \"available\"\n if (this.stopped || this.archive.detached || !this.link) status = \"offline\"\n else if (this.reconnectHandoff || this.atCapacity) status = \"busy\"\n const body = this.presenceBody(status)\n Object.assign(this.hello, body)\n this.hello.supportedCapabilities = supportedCapabilitiesFor(this.sessionControlEnabled)\n this.reportPresence(body)\n }\n\n /** The stream of the turn the runtime is executing right now, if any. */\n get activeTurnStreamId(): string | undefined {\n return this.activeTurnStream\n }\n\n /** The scratchpad root stream, once linked. */\n get rootStreamId(): string | undefined {\n return this.link?.rootStreamId\n }\n\n get statusSnapshot(): RemoteSessionStatusSnapshot {\n const linkState = this.archive.detached ? \"detached\" : this.link ? \"linked\" : \"unlinked\"\n return {\n stopped: this.stopped,\n linkGeneration: this.linkGeneration,\n linkState,\n rootStreamId: this.link?.rootStreamId ?? this.archive.pendingRootStreamId,\n activeStreamId: this.link?.activeStreamId,\n socketConnected: this.transport.socketConnected,\n inflightCount: this.inflight.size,\n activeTurnStreamId: this.activeTurnStream,\n inflightStreamIds: [...this.inflightStreams()],\n pendingDecisionCount: this.pendingDecisions.size,\n }\n }\n\n /**\n * Where this install's E2E keys live and which one it holds. Built lazily so\n * an operator who never enables encryption is not asked to pick a key store.\n */\n private buildKeyring(): E2eKeyring {\n const dir = this.config.keyDir ?? join(homedir(), \".threa\", \"e2e-keys\")\n const account = e2eKeyAccount({\n scope: this.config.keyScope,\n hostname: hostname(),\n instanceId: this.config.instanceId,\n identitySeed: this.config.apiKey,\n })\n const files = new FileKeyStore({ dir })\n const legacyPath = this.config.bikPath ?? join(homedir(), \".threa\", `bik-${sanitizeId(this.runtime.kind)}.json`)\n return new E2eKeyring({\n store: resolveKeyStore({\n requested: this.config.keyStore,\n platform: process.platform,\n dir,\n hasExistingFileKey: account === null ? files.hasAny() : files.read(account) !== undefined,\n }),\n account,\n mint: mintE2eKeyRecord,\n legacy: () => readLegacyBikFile(legacyPath),\n log: this.log,\n })\n }\n\n // --- Lifecycle ------------------------------------------------------------\n\n async start(): Promise<void> {\n // Keys before the first hello/presence write: the server reads an\n // advertised keyring as the instance's complete set, so a write without\n // these fields unregisters every key and breaks sealed-claim wrap coverage.\n await this.bik.ensure()\n this.advertisedKeyIds = this.bik.identities.map((identity) => identity.publicKeyId).join(\",\")\n Object.assign(this.hello, this.bik.presenceFields())\n await this.verifyPrincipal()\n await this.ensureLink()\n await this.transport.connect()\n this.startPoll()\n await this.claimDrain()\n }\n\n /** Create (or recover) the scratchpad link. Best-effort so a transient Threa outage self-heals on the next poll tick. */\n private async ensureLink(): Promise<void> {\n // While detached the controller's reattach is the ONLY path allowed to\n // relink: a link created here would cancel a wind-down against a\n // scratchpad that is still archived server-side.\n if (this.link || this.stopped || this.archive.detached) return\n try {\n await this.createLink()\n } catch (error) {\n this.log(`could not link to Threa (will retry): ${this.summarize(error)}${this.linkErrorHint(error)}`)\n }\n }\n\n /** The reattach hook: a confirmed link is what cancels the grace, so failure must read as \"still archived\". */\n private async relinkAfterRestore(): Promise<boolean> {\n try {\n return await this.createLink()\n } catch (error) {\n this.log(`reattach link failed: ${this.summarize(error)}${this.linkErrorHint(error)}`)\n return false\n }\n }\n\n private async createLink(): Promise<boolean> {\n const generation = this.archive.generation\n const link = await this.createSession()\n // A pre-archive session-create can resolve AFTER the archive lands;\n // committing it would resurrect a link to a scratchpad that is archived\n // server-side and hide the detach from the next probe.\n if (this.stopped) return false\n if (this.archive.generation !== generation) {\n this.log(\"link response raced an archive state change — dropped; the next probe decides\")\n return false\n }\n await this.delegate.onLinked?.(link)\n // The callback can take real time (it may write files); a shutdown or\n // archive that landed meanwhile must win, same as above.\n if (this.stopped) return false\n if (this.archive.generation !== generation) {\n this.log(\"link response raced an archive state change — dropped; the next probe decides\")\n return false\n }\n this.link = link\n this.linkGeneration += 1\n this.log(`linked to scratchpad ${this.config.baseUrl}${this.link.streamUrlPath}`)\n if (!this.archive.detached) await this.syncPresence()\n return true\n }\n\n /** Actionable next step for the link failures a retry alone will never fix. */\n private linkErrorHint(error: unknown): string {\n if (!(error instanceof ThreaApiError)) return \"\"\n if (error.status === 401 || error.status === 403) {\n return \" — check THREA_API_KEY (must be a bot key, threa_bk_…) and THREA_WORKSPACE_ID\"\n }\n if (error.code === \"SCRATCHPAD_ARCHIVED\" && !this.archive.detached) {\n return \" — the server does not support ifArchived replace yet; unarchive the scratchpad in Threa to link\"\n }\n return \"\"\n }\n\n async shutdown(options: ShutdownOptions = {}): Promise<void> {\n if (this.stopped) return\n this.stopped = true\n if (this.pollTimer) clearTimeout(this.pollTimer)\n if (this.claimRetryTimer) clearTimeout(this.claimRetryTimer)\n this.claimRetryTimer = undefined\n this.archive.stop()\n const withdrawals = this.abandonPendingDecisions()\n this.resetReconnectHandoff()\n await this.reconnectFallbackTask\n // Fast, idempotent teardown first so SIGTERM cleanup isn't held hostage by\n // slow writes when Threa is the thing that's unreachable. Dropping the socket\n // before the offline push means updatePresence falls straight to HTTP rather\n // than waiting on an ack from a connection that's already going away.\n this.transport.disconnect()\n // Fence before awaits so an in-flight completion cannot resurrect the route or presence.\n const routes = this.revokeAllRoutes()\n await this.waitForClaimDrain()\n await Promise.all([this.enqueueOfflinePresence(() => this.stopped), withdrawals])\n if (options.hostGone && routes.length > 0) {\n // Renewal stopped above, so the claims expire on the server and the\n // next runtime on this scratchpad — the revival — claims the same\n // messages again and answers them as its own turns. Failing them here\n // would close those turns for good with nobody left to read the error.\n this.log(`host gone: leaving ${routes.length} in-flight claim(s) to lapse for the revived session`)\n return\n }\n await this.failUnansweredRoutes(routes)\n }\n\n private revokeAllRoutes(): TurnRoute[] {\n this.lifecycle += 1\n const inflight = [...this.inflight.values()]\n for (const route of inflight) route.revoke()\n for (const route of this.completed.values()) route.revoke()\n for (const context of this.observedClaims.values()) this.fenceObservedClaim(context.invocation)\n this.inflight.clear()\n this.completed.clear()\n this.terminalReplies.clear()\n return inflight\n }\n\n private async failUnansweredRoutes(routes: TurnRoute[]): Promise<void> {\n await Promise.allSettled(\n routes.map((route) =>\n // Let /complete settle before /fail so an acknowledged answer cannot be overwritten.\n Promise.resolve(route.closing)\n .catch(() => undefined)\n .then(() => {\n if (route.state === \"closed\") return undefined\n return Promise.allSettled(\n [route.invocation, ...route.contributors].map((invocation) =>\n this.client.fail(invocation.id, {\n instanceId: this.config.instanceId,\n claimToken: invocation.claimToken,\n // The shutdown message is a fixed string (never turn content), so it\n // is safe on sealed turns too.\n errorMessage: this.runtime.shutdownErrorMessage,\n })\n )\n )\n })\n )\n )\n }\n\n private async verifyPrincipal(): Promise<void> {\n try {\n const me = await this.client.getMe()\n if (me.kind !== \"bot\") {\n this.log(\"WARNING: the configured API key is not a bot key (threa_bk_…). Bot-runtime endpoints will reject it.\")\n }\n } catch (error) {\n this.log(`could not verify principal (continuing): ${this.summarize(error)}`)\n }\n }\n\n private async createSession(): Promise<RuntimeSessionLink> {\n const e2e = this.config.e2e ? await this.resolveE2eCreateBlock() : undefined\n const link = await this.client.createSession({\n runtimeKind: this.runtime.kind,\n instanceId: this.config.instanceId,\n runtimeSessionId: this.config.runtimeSessionId,\n displayName: this.config.displayName,\n ...(this.config.localCwd ? { localCwd: this.config.localCwd } : {}),\n // Detached-pending-restore probes always wait. Cold starts replace by\n // default, but supervisors reviving a known stream can force wait so an\n // archive between their preflight and process launch cannot mint another\n // scratchpad.\n ifArchived: this.archive.detached ? \"wait\" : (this.config.coldStartIfArchived ?? \"replace\"),\n ifMissing: this.config.expectedRootStreamId ? \"error\" : (this.config.coldStartIfMissing ?? \"create\"),\n ...(this.config.defaultLabel && { labelName: this.config.defaultLabel }),\n ...(e2e ? { e2e: { ownerKeyId: e2e.ownerKeyId } } : {}),\n })\n if (this.config.expectedRootStreamId && link.rootStreamId !== this.config.expectedRootStreamId) {\n throw new Error(\n `Session link root mismatch: expected ${this.config.expectedRootStreamId}, got ${link.rootStreamId}`\n )\n }\n if (this.config.e2e && link.e2eEnabled !== true) {\n // A resume of a pre-existing PLAINTEXT scratchpad — nothing to provision,\n // but the user asked for encryption, so say why they aren't getting it.\n this.log(\n `WARNING: e2e is enabled but the resumed scratchpad ${link.rootStreamId} is plaintext ` +\n \"(it predates the setting). Archive it to get a fresh encrypted scratchpad on the next start.\"\n )\n return link\n }\n if (e2e && link.e2eEnabled === true) {\n await this.provisionE2eStreamKey(link, e2e)\n }\n return link\n }\n\n /**\n * Resolve the owner-key half of an E2E create. Throws with an actionable\n * message when the owner has no encryption key — ensureLink logs it and\n * retries each poll tick, so the session self-heals the moment the owner\n * sets up encryption. This install's own key is phase two's to mint: under\n * the per-stream policy it is keyed to a scratchpad that does not exist yet.\n */\n private async resolveE2eCreateBlock(): Promise<{ ownerKeyId: string; ownerPublicKey: string }> {\n let ownerKey: { keyId: string; publicKey: string }\n try {\n ownerKey = await this.client.getOwnerE2eKey()\n } catch (error) {\n if (error instanceof ThreaApiError && error.status === 404) {\n throw new Error(\n \"e2e is enabled but the bot owner has not set up encryption in Threa yet — \" +\n \"set an encryption passphrase in the app, then this session will link encrypted.\"\n )\n }\n throw error\n }\n return { ownerKeyId: ownerKey.keyId, ownerPublicKey: ownerKey.publicKey }\n }\n\n /**\n * Phase two of the encrypted create: mint the generation-0 stream key, wrap\n * it to the owner's UIK + this install's BIK, and store the wraps. Until this\n * lands nobody can seal into the scratchpad (INV-E1 keeps plaintext out), so\n * a failure retries in place; a 409 means an earlier attempt landed.\n */\n private async provisionE2eStreamKey(\n link: RuntimeSessionLink,\n e2e: { ownerKeyId: string; ownerPublicKey: string }\n ): Promise<void> {\n const bik = await this.bik.identityForStream(link.rootStreamId)\n if (!bik) {\n throw new Error(\"e2e is enabled but this install could not create a bot identity key (see earlier log)\")\n }\n await this.advertiseKeyring()\n const { wraps } = await mintStreamKeyWraps({\n streamId: link.rootStreamId,\n keyGeneration: 0,\n recipients: [\n { recipientKind: \"user\", recipientKeyId: e2e.ownerKeyId, publicKeyBase64: e2e.ownerPublicKey },\n { recipientKind: \"bot\", recipientKeyId: bik.publicKeyId, publicKeyBase64: bik.publicKeyBase64 },\n ],\n })\n for (let attempt = 1; ; attempt++) {\n try {\n await this.client.provisionStreamKeyWraps(link.rootStreamId, { keyGeneration: 0, wraps })\n this.log(`provisioned encrypted scratchpad ${link.rootStreamId} (gen 0, owner + BIK wraps)`)\n return\n } catch (error) {\n // 409: a previous attempt (this process or a crashed predecessor) landed.\n if (error instanceof ThreaApiError && error.status === 409) return\n if (attempt >= 3) throw error\n await new Promise((resolve) => setTimeout(resolve, attempt * 1_000))\n }\n }\n }\n\n // --- Claiming -------------------------------------------------------------\n\n /** Returns whether at least one invocation was claimed (feeds the poll backoff reset). */\n private claimDrain(): Promise<boolean> {\n // No claims while detached-pending-restore: the scratchpad is archived, so\n // any claimable work predates the archive and would reply into a closed\n // stream. Restore re-runs the drain.\n if (this.stopped || this.claimRetryTimer || this.archive.detached || this.reconnectHandoff) {\n return Promise.resolve(false)\n }\n if (this.claiming || this.claimDrainTask) {\n this.claimDrainRequested = true\n return Promise.resolve(false)\n }\n this.claiming = true\n const task = this.runClaimDrain()\n this.claimDrainTask = task\n const clear = () => {\n if (this.claimDrainTask === task) this.claimDrainTask = undefined\n this.scheduleRequestedClaimDrain()\n }\n void task.then(clear, clear)\n return task\n }\n\n private async runClaimDrain(): Promise<boolean> {\n let claimedAny = false\n // Parallel mode only: streams a /stop in this drain asked to keep quiet.\n const stoppedStreams = new Set<string>()\n try {\n for (let i = 0; i < MAX_CLAIMS_PER_DRAIN; i++) {\n // One normal turn at a time: once a turn is in flight we claim with\n // session-control caps ONLY (claimBody(busy)), so /stop and /steer still\n // reach us mid-turn while a normal active-scratchpad follow-up stays\n // queued. Without runtime control there's nothing to claim while busy:\n // strict one-at-a-time. With `maxConcurrentTurns > 1` \"busy\" means at\n // capacity; under it we claim everything except streams already running.\n if (this.reconnectHandoff || this.stopped || this.archive.detached) break\n const busy = this.atCapacity\n if (busy && !this.sessionControlEnabled) break\n const exclude = busy ? [] : [...new Set([...this.inflightStreams(), ...stoppedStreams])]\n const invocation = await this.claimNext(busy, undefined, exclude)\n if (!invocation) break\n claimedAny = true\n this.markClaimProcessing(invocation)\n if (this.isClaimCancelled(invocation)) continue\n if (isSessionControlInvocation(invocation)) {\n const isStop = parseSessionControlCommand(invocation)?.name === \"stop\"\n await this.handleSessionControl(invocation)\n // After a stop, don't immediately pull the next queued turn — the user\n // asked for quiet (mirrors Pi's runStopCommand). In parallel mode the\n // quiet is that stream's only; other streams keep draining.\n if (isStop) {\n if (this.parallel) {\n stoppedStreams.add(invocation.responseStreamId)\n continue\n }\n this.claimDrainRequested = false\n break\n }\n continue\n }\n if (this.routeForStream(invocation.responseStreamId)) {\n this.log(\n `claimed ${invocation.id} for busy stream ${invocation.responseStreamId}: server ignored excludeResponseStreamIds`\n )\n await this.failInvocation(invocation, \"Threa server ignored excludeResponseStreamIds; resend the message\")\n continue\n }\n const deferred = await this.startFoldedTurn(invocation)\n // Session control queued behind the folded messages still runs, and\n // still runs against the turn the fold just started — a queued /stop\n // must stop it, not the turn after it.\n for (const control of deferred) {\n if (parseSessionControlCommand(control)?.name === \"stop\") {\n await this.handleSessionControl(control)\n if (this.parallel) {\n stoppedStreams.add(control.responseStreamId)\n continue\n }\n this.claimDrainRequested = false\n return claimedAny\n }\n await this.handleSessionControl(control)\n }\n }\n } catch (error) {\n this.log(`claim failed: ${this.summarize(error)}`)\n } finally {\n this.claiming = false\n }\n return claimedAny\n }\n\n private async waitForClaimDrain(): Promise<void> {\n await this.claimDrainTask\n }\n\n /**\n * Claim one invocation and, when it arrives sealed, hydrate it in place: open\n * the SSK wraps with this install's BIK, decrypt the trigger + history, and\n * stash the {@link SealingState} every reply/step seals with. From here on the\n * invocation looks like a plaintext one to the rest of the loop — only the\n * write paths branch on `sealing`. A hydration failure fails the invocation\n * loudly (scrubbed reason) and reports \"nothing claimed\" rather than throwing\n * the drain into a TTL-recycle loop.\n */\n private async claimAndHydrate(\n busy: boolean,\n responseStreamId?: string,\n excludeResponseStreamIds: string[] = []\n ): Promise<ClaimedInvocation | null> {\n if (this.claimRetryTimer) return null\n let invocation: ClaimedInvocation | null\n try {\n invocation = await this.client.claim({\n ...this.claimBody(busy, excludeResponseStreamIds),\n ...(responseStreamId ? { responseStreamId } : {}),\n })\n this.claimFailures = 0\n } catch (error) {\n this.scheduleClaimRetry(error)\n throw error\n }\n if (!invocation || invocation.sealedContext === undefined) return invocation\n const fail = async (reason: string): Promise<null> => {\n this.log(`sealed claim ${invocation.id} unusable: ${reason}`)\n await this.client\n .fail(invocation.id, {\n instanceId: this.config.instanceId,\n claimToken: invocation.claimToken,\n errorMessage: `Sealed turn failed: ${reason}`.slice(0, 200),\n })\n .catch(() => undefined)\n return null\n }\n const sealed = parseSealedTurnContext(invocation.sealedContext)\n if (!sealed) return fail(\"malformed sealedContext\")\n const identities = await this.bik.ensureForStream(invocation.rootStreamId)\n if (identities.length === 0) return fail(\"no bot identity key\")\n try {\n // Wraps and the message AAD bind to the ROOT stream that owns the E2E key.\n const opened = await openSealedTurnContext({ sealed, identities, streamId: invocation.rootStreamId })\n const messages: ExternalHistoryMessage[] = opened.history.map((item) => ({\n messageId: `sealed-${item.sequence}`,\n role: item.role,\n authorId: \"\",\n authorType: item.role === \"assistant\" ? \"bot\" : \"user\",\n contentMarkdown: item.contentMarkdown,\n createdAt: \"\",\n }))\n const historyRefs = opened.history.flatMap((item) => item.attachmentRefs)\n return {\n ...invocation,\n sealedContext: undefined,\n promptMarkdown: opened.promptMarkdown,\n sealing: opened.sealing,\n ...(opened.promptAttachmentRefs.length > 0 || historyRefs.length > 0\n ? { sealedAttachments: { prompt: opened.promptAttachmentRefs, history: historyRefs } }\n : {}),\n ...(messages.length > 0 ? { context: { kind: \"inline\" as const, messages } } : {}),\n }\n } catch (error) {\n return fail(scrubSealedError(error))\n }\n }\n\n private scheduleClaimRetry(error: unknown): void {\n if (this.stopped || this.archive.detached || this.claimRetryTimer) return\n if (error instanceof ThreaApiError && error.status < 500 && !RETRYABLE_POST_STATUSES.has(error.status)) return\n const backoff = Math.min(CLAIM_RETRY_CAP_MS, this.config.pollMs * 2 ** this.claimFailures)\n this.claimFailures++\n const retryAfter = error instanceof ThreaApiError ? (error.retryAfterMs ?? 0) : 0\n const delay = Math.min(2_147_483_647, Math.max(backoff, retryAfter))\n this.log(`claim failed; retrying in ${delay}ms: ${this.summarize(error)}`)\n // A connected socket's next poll can be 15 minutes away. Retry the failed\n // claim independently, and don't let new pushes bypass the cooldown.\n this.claimRetryTimer = setTimeout(() => {\n this.claimRetryTimer = undefined\n this.claimDrainRequested = true\n this.scheduleRequestedClaimDrain()\n }, delay)\n }\n\n private async claimNext(\n busy: boolean,\n responseStreamId?: string,\n excludeResponseStreamIds: string[] = []\n ): Promise<ClaimedInvocation | null> {\n const lifecycle = this.lifecycle\n const invocation = await this.claimAndHydrate(busy, responseStreamId, excludeResponseStreamIds)\n if (!invocation || this.stopped || this.archive.detached || lifecycle !== this.lifecycle) return null\n const identities = invocation.sealing ? this.bik.identities : []\n const handle = this.transport.observeClaim({\n invocationId: invocation.id,\n claimToken: invocation.claimToken,\n sourceRevision: invocation.sourceRevision,\n claimTtlSeconds: CLAIM_TTL_SECONDS,\n instanceId: this.config.instanceId,\n callbacks: {\n onInputUpdated: (update, signal) => this.applyInputUpdate(invocation.id, update, signal),\n onCancelled: () =>\n this.terminalizeObservedClaim(invocation.id, \"Folded input was cancelled while the turn was running.\"),\n onClaimLost: () =>\n this.terminalizeObservedClaim(invocation.id, \"Folded claim ownership was lost while the turn was running.\"),\n },\n ...(invocation.sealing && identities.length > 0\n ? {\n sealed: {\n identities,\n streamId: invocation.rootStreamId,\n callbackToken: invocation.sealing.callbackToken,\n },\n }\n : {}),\n })\n this.observedClaims.set(invocation.id, {\n invocation,\n handle,\n phase: \"unstarted\",\n updateInProgress: false,\n restartPending: false,\n lifecycle: new AbortController(),\n })\n await handle.sync()\n return this.isClaimCancelled(invocation) ? null : invocation\n }\n\n private markClaimProcessing(invocation: ClaimedInvocation): void {\n const context = this.observedClaims.get(invocation.id)\n if (context && context.invocation === invocation && context.phase === \"unstarted\") context.phase = \"processing\"\n }\n\n private installInputUpdate(context: ObservedClaim, update: InvocationInputUpdate): void {\n Object.assign(context.invocation, {\n promptMarkdown: update.promptMarkdown,\n sourceRevision: update.sourceRevision,\n ...(update.delivery === \"sealed\"\n ? {\n sealing: update.sealing,\n sealedAttachments: {\n prompt: update.attachmentRefs,\n history: context.invocation.sealedAttachments?.history ?? [],\n },\n }\n : { sealing: undefined, sealedAttachments: undefined }),\n })\n // Never reuse output prepared under the previous source revision/key.\n this.inflight.get(context.invocation.id)?.discardPrepared()\n }\n\n private abortForInputRestart(context: ObservedClaim): void {\n context.restartPending = true\n context.updateInProgress = false\n this.cancelledInvocations.add(context.invocation)\n this.abortRunningTurnForContext(context, \"Folded input changed while the turn was running.\")\n }\n\n private abortRunningTurnForContext(context: ObservedClaim, ownerFailure: string): void {\n const ownerId = context.runningOwnerInvocationId\n const running = this.inflight.get(context.invocation.id) ?? (ownerId ? this.inflight.get(ownerId) : undefined)\n if (!running) return\n try {\n this.delegate.sessionControl?.interrupt(running.invocation.responseStreamId)\n } catch {\n // Backend authority still fences output when native control is gone.\n }\n running.execution.abort()\n this.clearInflight(running.invocation.id)\n if (this.activeTurnStream === running.invocation.responseStreamId) this.activeTurnStream = undefined\n\n const affected = [running.invocation, ...running.contributors].filter(\n (invocation) => invocation !== context.invocation\n )\n for (const invocation of affected) this.fenceObservedClaim(invocation)\n void Promise.all(affected.map((invocation) => this.failFencedInvocation(invocation, ownerFailure))).finally(() => {\n void this.syncPresence()\n })\n }\n\n private async applyInputUpdate(\n invocationId: string,\n update: InvocationInputUpdate,\n signal: AbortSignal\n ): Promise<\"applied\" | \"restart-required\"> {\n const context = this.observedClaims.get(invocationId)\n if (\n signal.aborted ||\n !context ||\n context.phase === \"terminal\" ||\n (update.delivery === \"sealed\" && !update.sealing)\n ) {\n return \"restart-required\"\n }\n if (context.phase === \"unstarted\") {\n this.installInputUpdate(context, update)\n return signal.aborted ? \"restart-required\" : \"applied\"\n }\n if (context.phase !== \"running\" || context.restartPending) {\n this.abortForInputRestart(context)\n return \"restart-required\"\n }\n\n const steer = this.delegate.sessionControl?.steer\n // reply() removes the entry before its first await. If renewal wins during\n // reply preparation, do not steer a turn that is already closing; fence its\n // pending output and let the backend perform the restart instead.\n const route = this.inflight.get(invocationId)\n if (!steer || !route || route.state !== \"open\" || route.revoked) {\n this.abortForInputRestart(context)\n return \"restart-required\"\n }\n\n // Renewal has already rotated the backend's accepted reply generation.\n // Install the matching revision/sealing state before any awaited attachment\n // rebuild or steering so concurrent trace/reply code can never use the old\n // cryptographic fence. Output methods pause while updateInProgress is true.\n context.updateInProgress = true\n this.installInputUpdate(context, update)\n try {\n if (signal.aborted) throw signal.reason\n const content = await this.buildTurnContent(context.invocation, { strictAttachments: true, signal })\n if (signal.aborted || this.isClaimCancelled(context.invocation)) throw signal.reason\n const interruptOnAbort = () => this.abortForInputRestart(context)\n signal.addEventListener(\"abort\", interruptOnAbort, { once: true })\n let steered: boolean\n try {\n if (signal.aborted) throw signal.reason\n steered = await steer.call(this.delegate.sessionControl, content, context.invocation.responseStreamId)\n } finally {\n signal.removeEventListener(\"abort\", interruptOnAbort)\n }\n if (signal.aborted || this.isClaimCancelled(context.invocation) || !steered) {\n this.abortForInputRestart(context)\n return \"restart-required\"\n }\n context.updateInProgress = false\n route.touchIdleTimeout()\n return \"applied\"\n } catch {\n this.abortForInputRestart(context)\n return \"restart-required\"\n }\n }\n\n private terminalizeObservedClaim(invocationId: string, ownerFailure: string): void {\n const context = this.observedClaims.get(invocationId)\n if (!context || context.phase === \"terminal\") return\n this.fenceObservedClaim(context.invocation)\n this.abortRunningTurnForContext(context, ownerFailure)\n if (!this.stopped && !this.archive.detached) void this.syncPresence()\n this.claimDrainRequested = true\n this.scheduleRequestedClaimDrain()\n }\n\n private scheduleRequestedClaimDrain(): void {\n if (!this.claimDrainRequested || this.claimDrainScheduled || this.claiming || this.stopped || this.archive.detached)\n return\n this.claimDrainScheduled = true\n // A task (not an awaited/microtask re-entry) lets the currently executing\n // cancellation callback leave its global adapter queue before a replacement\n // observation calls handle.sync().\n setTimeout(() => {\n this.claimDrainScheduled = false\n if (!this.claimDrainRequested || this.stopped || this.archive.detached) return\n this.claimDrainRequested = false\n void this.claimDrain().finally(() => this.scheduleRequestedClaimDrain())\n }, 0)\n }\n\n private isClaimCancelled(invocation: ClaimedInvocation): boolean {\n return this.cancelledInvocations.has(invocation)\n }\n\n private isOutputCurrent(invocation: ClaimedInvocation, sourceRevision = invocation.sourceRevision): boolean {\n const context = this.observedClaims.get(invocation.id)\n return (\n !this.isClaimCancelled(invocation) &&\n invocation.sourceRevision === sourceRevision &&\n context?.phase !== \"terminal\" &&\n context?.restartPending !== true &&\n context?.updateInProgress !== true\n )\n }\n\n private releaseObservation(invocationId: string): void {\n const context = this.observedClaims.get(invocationId)\n if (!context) return\n context.phase = \"terminal\"\n context.handle.unregister()\n this.observedClaims.delete(invocationId)\n }\n\n private fenceObservedClaim(invocation: ClaimedInvocation): void {\n this.cancelledInvocations.add(invocation)\n const context = this.observedClaims.get(invocation.id)\n if (!context) return\n context.lifecycle.abort()\n context.handle.dispose()\n this.observedClaims.delete(invocation.id)\n }\n\n private async failFencedInvocation(invocation: ClaimedInvocation, errorMessage: string): Promise<void> {\n // A sealed turn's error text could echo decrypted content — scrub to a\n // generic reason (the /fail wire itself is shared, model A).\n const scrubbed = invocation.sealing ? \"Sealed turn failed\" : errorMessage.slice(0, 1000)\n await this.client\n .fail(invocation.id, {\n instanceId: this.config.instanceId,\n claimToken: invocation.claimToken,\n errorMessage: scrubbed,\n })\n .catch((error) => this.log(`invocation fail write failed: ${this.summarize(error)}`))\n }\n\n /**\n * Start one turn that sees every ordinary message already queued behind this\n * one, and return any session-control commands the sweep pulled up with them.\n *\n * Without this, N messages sent while the session was busy became N\n * sequential turns, each answering a question the user had already moved\n * past — the reply to message 1 arriving after they had sent 4 more. `/steer`\n * has always folded the backlog (`sweepQueuedForSteer`); an ordinary message\n * got no such treatment, and that asymmetry is the whole of the lag.\n *\n * The primary invocation keeps the reply; the folded ones close without a\n * response of their own, exactly as the steer sweep closes what it folds.\n * Session control is never folded as text — a queued `/stop` has to stop the\n * turn, not become a line in its prompt — so it is handed back to the caller.\n */\n private async startFoldedTurn(invocation: ClaimedInvocation): Promise<ClaimedInvocation[]> {\n const primary = await this.buildTurnContent(invocation)\n if (this.isClaimCancelled(invocation)) return []\n const folded: ClaimedInvocation[] = []\n const control: ClaimedInvocation[] = []\n try {\n for (let i = 1; i < STEER_DRAIN_LIMIT; i++) {\n // Scoped to the primary's response stream, server-side. Folding across\n // streams would answer one stream's question in another and close the\n // rest unanswered, and a claim taken by mistake cannot be released —\n // so the filter has to keep it from being claimed at all. Sealing rides\n // along: a stream is uniformly sealed or uniformly plaintext.\n const extra = await this.claimNext(false, invocation.responseStreamId).catch(() => null)\n if (!extra) break\n this.markClaimProcessing(extra)\n if (this.isClaimCancelled(extra)) continue\n if (isSessionControlInvocation(extra)) {\n control.push(extra)\n // Stop folding at a control command: everything after it belongs to\n // whatever that command decides.\n break\n }\n folded.push(extra)\n }\n // A folded source can change while a later scoped claim or download is\n // awaited. Its callback requests a restart for that claim; omit its stale\n // snapshot from this turn and leave it for backend replacement rather\n // than executing content that is no longer canonical.\n const foldedParts = await this.foldedTurnParts(folded)\n // An archive can land while the sweep awaits; delivering into a detached\n // link publishes busy for a turn whose reply cannot arrive.\n if (this.stopped || this.archive.detached) {\n // Leave the folded messages claimed, exactly as the primary is left:\n // closing them here would discard their content for good, while the\n // primary comes back on the next drain. The drain's own guard says the\n // restore re-runs the pass — that has to mean all of it.\n return control\n }\n if (this.isClaimCancelled(invocation)) return control\n const liveFolded = foldedParts.map(({ invocation: item }) => item)\n const content = buildSteerContent([primary, ...foldedParts.map((part) => part.content)])\n this.bindRunningOwner(invocation.id, liveFolded)\n await this.deliverTurn(invocation, content, liveFolded)\n } catch (error) {\n // Never throw past here. Control claimed by the sweep has to run even when\n // delivery failed — otherwise a swept /stop is claimed, never handled, and\n // interrupts an unrelated turn once its claim expires. The messages fail\n // loudly instead of vanishing into a silent close.\n const reason = `Could not start the turn: ${this.summarize(error)}`\n // The primary was registered in `inflight` before the delegate ran, so a\n // throw would otherwise leave the session reporting busy — claiming\n // session-control only — until the idle timeout fired on an invocation\n // that is already terminal.\n this.clearInflight(invocation.id)\n await this.failInvocation(invocation, reason).catch(() => undefined)\n await Promise.all(folded.map((item) => this.failInvocation(item, reason).catch(() => undefined)))\n }\n return control\n }\n\n /**\n * The content each folded message contributes, attachments included, for the\n * ones still live once every download has landed. Every claim here is under\n * `observeClaim`, which renews it on its own timer, so a slow download cannot\n * expire the claims the sweep is holding.\n */\n private async foldedTurnParts(\n folded: ClaimedInvocation[]\n ): Promise<Array<{ invocation: ClaimedInvocation; content: string }>> {\n const parts: Array<{ invocation: ClaimedInvocation; content: string }> = []\n for (const item of folded) {\n if (this.isClaimCancelled(item)) continue\n parts.push({ invocation: item, content: await this.buildTurnContent(item) })\n }\n return parts.filter((part) => !this.isClaimCancelled(part.invocation))\n }\n\n private bindRunningOwner(ownerInvocationId: string, dependencies: ClaimedInvocation[]): void {\n const running = this.inflight.get(ownerInvocationId)\n for (const dependency of dependencies) {\n const context = this.observedClaims.get(dependency.id)\n if (context && context.invocation === dependency) {\n context.runningOwnerInvocationId = ownerInvocationId\n if (context.phase === \"processing\") context.phase = \"running\"\n }\n if (running && !running.contributors.some((item) => item.id === dependency.id)) {\n running.contributors.push(dependency)\n }\n }\n }\n\n private unbindRunningOwner(ownerInvocationId: string, dependencies: ClaimedInvocation[]): void {\n const ids = new Set(dependencies.map((item) => item.id))\n const running = this.inflight.get(ownerInvocationId)\n if (running) running.contributors = running.contributors.filter((item) => !ids.has(item.id))\n for (const dependency of dependencies) {\n const context = this.observedClaims.get(dependency.id)\n if (context?.runningOwnerInvocationId === ownerInvocationId) context.runningOwnerInvocationId = undefined\n }\n }\n\n private async completeContributors(route: TurnRoute): Promise<void> {\n await Promise.all(route.contributors.map((invocation) => this.completeNoResponse(invocation)))\n }\n\n private async failContributors(route: TurnRoute, reason: string): Promise<void> {\n await Promise.all(route.contributors.map((invocation) => this.failInvocation(invocation, reason)))\n }\n\n /** Register an invocation as the in-flight turn and push its content to the runtime. */\n private async deliverTurn(\n invocation: ClaimedInvocation,\n content: string,\n inputDependencies: ClaimedInvocation[] = []\n ): Promise<void> {\n if (this.isClaimCancelled(invocation)) throw new Error(\"invocation request is closed\")\n this.registerTurn(invocation, inputDependencies)\n // This is the turn the runtime is now executing; a permission prompt it\n // triggers belongs in this invocation's stream.\n this.activeTurnStream = invocation.responseStreamId\n await this.syncPresence()\n await this.recordForwardedStep(invocation).catch(() => undefined)\n // `syncPresence` yields, and an archive landing in that window fails this\n // invocation and clears it from `inflight`. Handing it to the runtime\n // anyway would execute a turn whose reply the server has already closed.\n if (\n this.stopped ||\n this.archive.detached ||\n !this.inflight.has(invocation.id) ||\n this.isClaimCancelled(invocation) ||\n inputDependencies.some((item) => this.isClaimCancelled(item))\n ) {\n throw new Error(\"session went offline or its input changed before the turn could be delivered\")\n }\n await this.delegate.deliverTurn({\n invocationId: invocation.id,\n streamId: invocation.responseStreamId,\n rootStreamId: invocation.rootStreamId,\n sourceMessageId: invocation.sourceMessageId,\n content,\n sealed: invocation.sealing !== undefined,\n })\n const dependencyChanged = inputDependencies.some((item) => this.isClaimCancelled(item))\n if (!this.inflight.has(invocation.id) || this.isClaimCancelled(invocation) || dependencyChanged) {\n if (dependencyChanged) {\n try {\n this.delegate.sessionControl?.interrupt(invocation.responseStreamId)\n } catch {}\n }\n throw new Error(\"invocation input changed while the runtime was accepting the turn\")\n }\n const observed = this.observedClaims.get(invocation.id)\n if (observed && observed.phase === \"processing\") observed.phase = \"running\"\n }\n\n /** The turn-handed-to-runtime trace note — sealed under the stream key on an E2E turn. */\n private async recordForwardedStep(invocation: ClaimedInvocation): Promise<void> {\n const forwardedNote = this.runtime.forwardedNote\n if (forwardedNote === undefined) return\n const sourceRevision = invocation.sourceRevision\n if (invocation.sealing) {\n const sealing = invocation.sealing\n const frame = await sealStep(sealing, \"thinking\", forwardedNote)\n if (!this.isOutputCurrent(invocation, sourceRevision)) return\n await this.transport.recordSealedSteps(invocation.id, sealing.callbackToken, [frame])\n return\n }\n if (!this.isOutputCurrent(invocation, sourceRevision)) return\n await this.transport.recordSteps(\n invocation.id,\n invocation.claimToken,\n [{ stepType: \"thinking\", content: forwardedNote }],\n this.runtime.busyStatusText\n )\n }\n\n /**\n * Close a control invocation with session-authored text or no response. Final\n * replies and idle timeouts use the prepared-close path so ambiguous retries\n * retain their exact wire body.\n */\n private async completeTurn(\n invocation: ClaimedInvocation,\n body: { markdown?: string; noResponse?: true; metadata?: Record<string, unknown>; signal?: AbortSignal }\n ): Promise<void> {\n const signal = body.signal ?? this.observedClaims.get(invocation.id)?.lifecycle.signal\n if (signal?.aborted || this.isClaimCancelled(invocation)) throw new Error(\"invocation request is closed\")\n const sourceRevision = invocation.sourceRevision\n const assertCurrent = (): void => {\n if (signal?.aborted || !this.isOutputCurrent(invocation, sourceRevision)) {\n throw new Error(\"invocation request is closed\")\n }\n }\n if (invocation.sealing) {\n const sealing = invocation.sealing\n const payload = body.markdown\n ? { sourceRevision, reply: await sealReply(sealing, body.markdown) }\n : { noResponse: true as const, sourceRevision }\n assertCurrent()\n await this.client.completeSealed(invocation.id, sealing.callbackToken, payload, signal)\n assertCurrent()\n this.releaseObservation(invocation.id)\n return\n }\n assertCurrent()\n await this.client.complete(\n invocation.id,\n {\n instanceId: this.config.instanceId,\n claimToken: invocation.claimToken,\n sourceRevision,\n ...(body.markdown ? { finalMessageMarkdown: body.markdown } : { noResponse: true }),\n ...(body.metadata ? { metadata: body.metadata } : {}),\n },\n signal\n )\n assertCurrent()\n this.releaseObservation(invocation.id)\n }\n\n // --- Session control (steer / stop / delegated commands) -------------------\n\n private async handleSessionControl(invocation: ClaimedInvocation): Promise<void> {\n if (this.isClaimCancelled(invocation)) return\n const command = parseSessionControlCommand(invocation)\n if (!command) {\n await this.failInvocation(invocation, \"Missing session-control command metadata\")\n return\n }\n const actuator = this.delegate.sessionControl\n if (!actuator) {\n await this.failInvocation(invocation, \"Session control is not available for this runtime\")\n return\n }\n try {\n if (this.isClaimCancelled(invocation)) return\n switch (command.name) {\n case \"stop\":\n return await this.runStop(invocation, actuator)\n case \"steer\":\n return await this.runSteer(invocation, actuator, command.args)\n default: {\n if (!actuator.commands.includes(command.name)) {\n await this.failInvocation(invocation, `Unsupported session-control command: ${command.name}`)\n return\n }\n const outcome = await actuator.runCommand(command.name, command.args, {\n rootStreamId: invocation.rootStreamId,\n sourceMessageId: invocation.sourceMessageId,\n })\n if (this.isClaimCancelled(invocation)) return\n if (!outcome.ok) {\n await this.failInvocation(invocation, outcome.message ?? \"Command rejected.\")\n return\n }\n const ackOutcome = (): Promise<boolean> => {\n if (outcome.message !== undefined) return this.completeReply(invocation, outcome.message)\n if (outcome.summary !== undefined) return this.completeAck(invocation, outcome.summary)\n return this.completeSilentAck(invocation)\n }\n if (outcome.handoff) {\n const parks = !outcome.handoffKeepsSessionRunning\n if (parks) {\n this.reconnectHandoff = true\n this.onHandoffReset = outcome.onHandoffReset\n await this.syncPresence()\n }\n if (this.stopped || !this.link || this.archive.detached || this.isClaimCancelled(invocation)) {\n if (parks) this.resetReconnectHandoff()\n await this.failInvocation(invocation, \"Remote session changed before the command was handed off.\")\n return\n }\n try {\n await outcome.handoff({\n workspaceId: invocation.workspaceId,\n invocationId: invocation.id,\n instanceId: this.config.instanceId,\n claimToken: invocation.claimToken,\n })\n } catch (error) {\n if (parks) this.resetReconnectHandoff()\n throw error\n }\n this.releaseObservation(invocation.id)\n if (parks) {\n this.reconnectResetTimer = setTimeout(() => this.resetReconnectHandoff(), RECONNECT_HANDOFF_FALLBACK_MS)\n }\n return\n }\n if (!outcome.afterAck) {\n await ackOutcome()\n return\n }\n this.reconnectHandoff = true\n this.onHandoffReset = outcome.onHandoffReset\n await this.syncPresence()\n const completed = await ackOutcome()\n if (!completed || this.stopped || !this.link || this.archive.detached) {\n this.resetReconnectHandoff()\n return\n }\n try {\n await outcome.afterAck()\n this.reconnectResetTimer = setTimeout(() => this.resetReconnectHandoff(), RECONNECT_HANDOFF_FALLBACK_MS)\n } catch (error) {\n this.log(`session-control post-ack action failed: ${this.summarize(error)}`)\n this.resetReconnectHandoff()\n }\n }\n }\n } catch (error) {\n await this.failInvocation(invocation, this.summarize(error))\n }\n }\n\n private async runStop(invocation: ClaimedInvocation, actuator: SessionControlActuator): Promise<void> {\n // If the interrupt can't be sent (runtime control lost), the runtime is\n // still running — don't close its in-flight turns as if we stopped them.\n const streamId = invocation.responseStreamId\n if (this.parallel && !this.routeForStream(streamId)) {\n if (streamId === this.link?.rootStreamId) return await this.stopTurnsOutsideScratchpad(invocation, actuator)\n await this.completeAck(invocation, \"No turn is running in this stream.\")\n return\n }\n if (!actuator.interrupt(streamId)) {\n await this.completeAck(invocation, \"Could not send the interrupt (runtime control unavailable).\")\n return\n }\n const hadTurn = this.inflight.size > 0\n await this.completeInterruptedTurns(this.controlStream(streamId))\n await this.completeAck(invocation, hadTurn ? \"Stopped the current turn.\" : \"Sent an interrupt to the session.\")\n await this.syncPresence()\n }\n\n // Commands can't be typed in a channel or DM, so a turn a mention started\n // there is stopped from the scratchpad root.\n private async stopTurnsOutsideScratchpad(\n invocation: ClaimedInvocation,\n actuator: SessionControlActuator\n ): Promise<void> {\n const root = this.link?.rootStreamId\n const streams = new Set(\n [...this.inflight.values()]\n .filter((route) => route.invocation.rootStreamId !== root)\n .map((route) => route.invocation.responseStreamId)\n )\n if (streams.size === 0) {\n await this.completeAck(invocation, \"No turn is running in this stream.\")\n return\n }\n const interrupted = [...streams].filter((streamId) => actuator.interrupt(streamId))\n for (const streamId of interrupted) await this.completeInterruptedTurns(streamId)\n if (interrupted.length === 0) {\n await this.completeAck(invocation, \"Could not send the interrupt (runtime control unavailable).\")\n return\n }\n await this.completeAck(\n invocation,\n interrupted.length === 1\n ? \"Stopped the turn running outside this scratchpad.\"\n : `Stopped ${interrupted.length} turns running outside this scratchpad.`\n )\n await this.syncPresence()\n }\n\n /**\n * Route /steer. With a turn in flight and a steer-capable actuator, fold the\n * text into the RUNNING turn (the running invocation keeps its trace and its\n * reply). Otherwise fall back to interrupt + redeliver — the only option for\n * an idle session (there is no turn to fold into) or a runtime without\n * native mid-turn steering.\n */\n private async runSteer(invocation: ClaimedInvocation, actuator: SessionControlActuator, text: string): Promise<void> {\n const steer = actuator.steer?.bind(actuator)\n const running = this.parallel\n ? this.routeForStream(invocation.responseStreamId) !== undefined\n : this.inflight.size > 0\n if (running && steer) {\n return await this.steerRunningTurn(invocation, steer, text)\n }\n // Redelivering would start a turn past the cap.\n if (this.parallel && !running && this.atCapacity) {\n await this.completeAck(invocation, \"Every turn slot is busy; resend the steer when a turn finishes.\")\n return\n }\n return await this.steerByInterrupt(invocation, actuator, text)\n }\n\n /**\n * Steer in place: sweep any messages queued while busy, record a `steer`\n * step on the running turn's trace (the visible record of what was folded\n * in), and inject the combined text via the runtime's native mid-turn\n * steering. The running invocation stays the primary — its eventual reply\n * answers the steer — so the /steer command itself closes immediately\n * (command_completed resolves the card) instead of spinning until the turn\n * ends.\n */\n private async steerRunningTurn(\n invocation: ClaimedInvocation,\n steer: (text: string, streamId?: string) => Promise<boolean> | boolean,\n text: string\n ): Promise<void> {\n const streamId = invocation.responseStreamId\n const { parts, swept, contents } = await this.sweepQueuedForSteer(text, streamId)\n if (this.isClaimCancelled(invocation)) return\n if (parts.length === 0) {\n // The sweep can still have claimed foldless invocations (a queued control\n // command in the double-command race) — close them or they hang to TTL.\n await Promise.all(swept.map((item) => this.completeNoResponse(item)))\n if (invocation.metadata?.steeredMessage === true) {\n // An embedded-steer pair carries its text on the normal message. If\n // that companion is already running, the empty control half is only a\n // barrier — do not post a false \"nothing to steer\" acknowledgement.\n await this.completeTurn(invocation, {\n noResponse: true,\n metadata: {\n \"remote.invocationId\": invocation.id,\n \"remote.sessionControl\": \"true\",\n \"remote.steered\": \"true\",\n },\n })\n return\n }\n await this.completeAck(invocation, \"Nothing to steer with (no text, no queued messages); the turn continues.\")\n return\n }\n let combined = buildSteerContent(parts)\n // Step before actuation so it sits ahead of the continuation's frames in\n // the trace; a steer is also a sign of life for the turn it redirects.\n for (const route of this.controlRoutes(streamId)) {\n await this.recordSteps(route.invocation.id, [{ stepType: \"steer\", content: combined }])\n route.touchIdleTimeout()\n }\n if (this.isClaimCancelled(invocation)) return\n const liveSwept = swept.filter((item) => !this.isClaimCancelled(item))\n const currentParts = this.steerParts(liveSwept, text, contents)\n if (currentParts.length === 0) {\n await Promise.all(liveSwept.map((item) => this.completeNoResponse(item)))\n await this.completeAck(invocation, \"Nothing to steer with; the turn continues.\")\n return\n }\n combined = buildSteerContent(currentParts)\n const owner = [...this.inflight.values()].find(\n (entry) => entry.invocation.responseStreamId === invocation.responseStreamId\n )?.invocation\n if (owner) this.bindRunningOwner(owner.id, [invocation, ...liveSwept])\n if (!(await steer(combined, streamId))) {\n // Nothing was injected: the swept messages were claimed but not\n // delivered — fail them loudly so they don't vanish into a silent close.\n if (owner) this.unbindRunningOwner(owner.id, [invocation, ...liveSwept])\n await Promise.all(\n liveSwept.map((item) => this.failInvocation(item, \"Steer not delivered (runtime control unavailable); resend.\"))\n )\n await this.completeAck(invocation, \"Could not steer the session (runtime control unavailable).\")\n return\n }\n if (this.isClaimCancelled(invocation) || (owner && !this.inflight.has(owner.id))) return\n if (owner) this.unbindRunningOwner(owner.id, [invocation])\n await this.completeTurn(invocation, {\n noResponse: true,\n metadata: {\n \"remote.invocationId\": invocation.id,\n \"remote.sessionControl\": \"true\",\n \"remote.steered\": \"true\",\n },\n }).catch((error) => this.failAfterTerminalWrite(invocation, error, \"steer completion\"))\n }\n\n /**\n * Interrupt the running turn, then fold the steer text + any messages queued\n * while the runtime was busy into ONE combined turn (mirrors Pi: N messages →\n * 1 response). The interrupt is the only actuation; the combined content\n * round-trips through the normal delivery path so the runtime replies to it.\n */\n private async steerByInterrupt(\n invocation: ClaimedInvocation,\n actuator: SessionControlActuator,\n text: string\n ): Promise<void> {\n // If the interrupt can't be sent, bail before any destructive side-effect —\n // don't close the running turn or deliver the steer as a second concurrent\n // turn against a runtime we couldn't actually interrupt.\n const streamId = invocation.responseStreamId\n if (!actuator.interrupt(streamId)) {\n await this.completeAck(\n invocation,\n \"Could not interrupt the session (runtime control unavailable); steer not delivered.\"\n )\n return\n }\n await new Promise((resolve) => setTimeout(resolve, STEER_SETTLE_MS))\n if (this.isClaimCancelled(invocation)) return\n await this.completeInterruptedTurns(this.controlStream(streamId))\n\n const { parts, swept } = await this.sweepQueuedForSteer(text, streamId)\n if (this.isClaimCancelled(invocation)) return\n\n if (parts.length === 0) {\n await this.completeAck(invocation, \"Interrupted the session; nothing pending to steer with.\")\n await this.syncPresence()\n return\n }\n\n this.bindRunningOwner(invocation.id, swept)\n await this.deliverTurn(invocation, buildSteerContent(parts), swept)\n }\n\n /**\n * Claim messages queued while the runtime was busy and fold their text in\n * (steer text last).\n *\n * Scoped to the stream the steered turn answers into, for the same reason the\n * fold's sweep is: a message belonging to another stream would be folded\n * here, closed unanswered where it was asked, and answered somewhere else.\n * Unscoped when nothing is in flight — there is no turn whose stream to\n * inherit, and the steer itself is then the only thing being folded into.\n */\n private async sweepQueuedForSteer(\n text: string,\n streamId: string\n ): Promise<{\n parts: string[]\n swept: ClaimedInvocation[]\n contents: Map<string, string>\n }> {\n const swept: ClaimedInvocation[] = []\n const running = this.parallel ? streamId : [...this.inflight.values()][0]?.invocation.responseStreamId\n for (let i = 0; i < STEER_DRAIN_LIMIT; i++) {\n const extra = await this.claimNext(false, running).catch(() => null)\n if (!extra) break\n this.markClaimProcessing(extra)\n if (this.isClaimCancelled(extra)) continue\n // The canonical text is derived after the sweep so a claim cancelled by an\n // update while a later claim awaited is omitted rather than injected stale.\n swept.push(extra)\n }\n const contents = new Map<string, string>()\n for (const item of swept) {\n if (this.isClaimCancelled(item)) continue\n contents.set(item.id, await this.foldedSteerContent(item))\n }\n const liveSwept = swept.filter((item) => !this.isClaimCancelled(item))\n return { parts: this.steerParts(liveSwept, text, contents), swept: liveSwept, contents }\n }\n\n /** Fold the swept messages' prepared content (steer text last); a claim cancelled since its download contributes nothing. */\n private steerParts(liveSwept: ClaimedInvocation[], text: string, contents: Map<string, string>): string[] {\n const parts = liveSwept.map((item) => contents.get(item.id) ?? \"\")\n if (text) parts.push(text)\n return parts.filter(Boolean)\n }\n\n /**\n * Seal a session-control command ack under the stream key, when the claim\n * carried the SSK wraps (an E2E scratchpad). Returns undefined on a plaintext\n * claim or a key race — the caller then takes the plaintext path, which\n * closes silently on E2E rather than showing the command as failed.\n */\n private async sealSessionControlAck(\n invocation: ClaimedInvocation,\n markdown: string\n ): Promise<SealedReplyBody | undefined> {\n const ack = parseSealedAckContext(invocation.sealedAck)\n if (!ack) return undefined\n const identities = await this.bik.ensureForStream(invocation.rootStreamId)\n if (identities.length === 0) return undefined\n try {\n const sealing = await openSealedAck({ ack, identities, streamId: invocation.rootStreamId })\n return await sealReply(sealing, markdown)\n } catch {\n return undefined\n }\n }\n\n /**\n * Close a session-control command with an account of what it did. The summary\n * lands on the command's own entry, so nothing is posted in the stream and\n * there is nothing to seal — it states what happened and never quotes stream\n * content, the same way the dispatched entry already carries the command args.\n */\n private async completeAck(invocation: ClaimedInvocation, summary: string): Promise<boolean> {\n if (this.isClaimCancelled(invocation)) return false\n const signal = this.observedClaims.get(invocation.id)?.lifecycle.signal\n try {\n await this.client.complete(\n invocation.id,\n {\n instanceId: this.config.instanceId,\n claimToken: invocation.claimToken,\n sourceRevision: invocation.sourceRevision,\n summary,\n metadata: {\n \"remote.invocationId\": invocation.id,\n \"remote.sessionControl\": \"true\",\n },\n },\n signal\n )\n if (signal?.aborted || this.isClaimCancelled(invocation)) return false\n } catch (error) {\n await this.failAfterTerminalWrite(invocation, error, \"session-control acknowledgement\")\n return false\n }\n this.releaseObservation(invocation.id)\n return true\n }\n\n /** Close a session-control command by posting its answer — content the user asked for, not an account of the command. */\n private async completeReply(invocation: ClaimedInvocation, markdown: string): Promise<boolean> {\n if (this.isClaimCancelled(invocation)) return false\n const signal = this.observedClaims.get(invocation.id)?.lifecycle.signal\n // Sealed session-control reply on E2E: seal it under the stream key and post\n // it as `sealedReply`. Falls through to the plaintext path when the bot can't\n // seal (no wrap / key race), which silently closes on E2E.\n const sealedReply = await this.sealSessionControlAck(invocation, markdown)\n if (signal?.aborted || this.isClaimCancelled(invocation)) return false\n try {\n await this.client.complete(\n invocation.id,\n {\n instanceId: this.config.instanceId,\n claimToken: invocation.claimToken,\n sourceRevision: invocation.sourceRevision,\n ...(sealedReply ? { sealedReply } : { finalMessageMarkdown: markdown }),\n metadata: {\n \"remote.invocationId\": invocation.id,\n \"remote.sessionControl\": \"true\",\n },\n },\n signal\n )\n if (signal?.aborted || this.isClaimCancelled(invocation)) return false\n } catch (error) {\n // Reached only when the reply couldn't be sealed (no BIK / wrap race, so\n // `sealSessionControlAck` returned undefined). On an E2E scratchpad the\n // plaintext reply is rejected with E2E_STREAM_PLAINTEXT_UNSUPPORTED; close\n // silently — the command still ran and command:completed carries the\n // feedback. Narrow to that exact code so a capability/validation 400 isn't\n // masked as a successful close (INV-11, fail loud).\n if (!sealedReply && error instanceof ThreaApiError && error.code === \"E2E_STREAM_PLAINTEXT_UNSUPPORTED\") {\n try {\n await this.completeTurn(invocation, { noResponse: true })\n return false\n } catch (inner) {\n await this.failAfterTerminalWrite(invocation, inner, \"session-control silent acknowledgement\")\n return false\n }\n }\n await this.failAfterTerminalWrite(\n invocation,\n error,\n sealedReply ? \"sealed session-control reply\" : \"session-control reply\"\n )\n return false\n }\n this.releaseObservation(invocation.id)\n return true\n }\n\n private async completeSilentAck(invocation: ClaimedInvocation): Promise<boolean> {\n if (this.isClaimCancelled(invocation)) return false\n try {\n await this.completeTurn(invocation, {\n noResponse: true,\n metadata: { \"remote.invocationId\": invocation.id, \"remote.sessionControl\": \"true\" },\n })\n } catch (error) {\n await this.failAfterTerminalWrite(invocation, error, \"silent session-control acknowledgement\")\n return false\n }\n return true\n }\n\n private async completeNoResponse(invocation: ClaimedInvocation): Promise<void> {\n try {\n await this.completeTurn(invocation, {\n noResponse: true,\n metadata: {\n \"remote.invocationId\": invocation.id,\n \"remote.steered\": \"true\",\n },\n })\n } catch (error) {\n await this.failAfterTerminalWrite(invocation, error, \"no-response completion\")\n }\n }\n\n private async failAfterTerminalWrite(\n invocation: ClaimedInvocation,\n error: unknown,\n operation: string\n ): Promise<void> {\n this.log(`${operation} failed: ${this.summarize(error)}`)\n if (this.isClaimCancelled(invocation)) return\n if (error instanceof ThreaApiError && error.status === 409 && error.code === \"INVOCATION_INPUT_STALE\") {\n this.releaseObservation(invocation.id)\n return\n }\n await this.failInvocation(invocation, `Could not persist ${operation}.`)\n }\n\n private async failInvocation(invocation: ClaimedInvocation, errorMessage: string): Promise<void> {\n if (this.isClaimCancelled(invocation)) return\n await this.failFencedInvocation(invocation, errorMessage)\n this.releaseObservation(invocation.id)\n }\n\n /**\n * Close every in-flight turn that an interrupt just aborted, so none\n * idle-hangs for an hour. Nothing is posted: the /stop or /steer that caused\n * the interrupt closes with its own account of it, on its own entry.\n */\n private async completeInterruptedTurns(streamId?: string): Promise<void> {\n const routes = this.controlRoutes(streamId)\n const interrupted = new Set(routes.map((route) => route.invocation.id))\n const withdrawals = this.abandonPendingDecisions(\n (decision) => !!decision.requesterInvocationId && interrupted.has(decision.requesterInvocationId)\n )\n const closes = routes.map((route) => {\n route.revoke()\n if (route.state === \"open\") route.beginClosing()\n if (this.activeTurnStream === route.invocation.responseStreamId) this.activeTurnStream = undefined\n const generation = route.generation\n const task = route.enqueue(async () => {\n if (this.stopped || generation !== this.lifecycle || route.state === \"closed\") return\n try {\n await this.completeTurn(route.invocation, {\n noResponse: true,\n metadata: { \"remote.invocationId\": route.invocation.id, \"remote.interrupted\": \"true\" },\n signal: route.execution.signal,\n })\n route.markClosed()\n await this.completeContributors(route)\n } catch (error) {\n await this.failAfterTerminalWrite(route.invocation, error, \"interrupted-turn completion\")\n await this.failContributors(route, \"The owning turn could not be closed after interruption.\")\n } finally {\n if (generation === this.lifecycle && this.inflight.get(route.invocation.id) === route) {\n this.inflight.delete(route.invocation.id)\n }\n }\n })\n return route.trackClosing(task)\n })\n await Promise.all([...closes, withdrawals])\n }\n\n /** The prompt + history the runtime reads, with any downloaded attachments appended as a manifest. */\n private async buildTurnContent(\n invocation: ClaimedInvocation,\n options: { strictAttachments?: boolean; signal?: AbortSignal } = {}\n ): Promise<string> {\n return withInboundAttachments(\n formatInvocationContent(invocation),\n await this.inboundAttachmentManifest(invocation, options)\n )\n }\n\n /**\n * The text a message folded into a running turn contributes: its prompt and\n * the manifest of its own attachments — no history and no history\n * attachments, the running turn already has them. A control command\n * contributes its /steer args, or nothing.\n */\n private async foldedSteerContent(invocation: ClaimedInvocation): Promise<string> {\n if (isSessionControlInvocation(invocation)) {\n const queued = parseSessionControlCommand(invocation)\n return queued?.name === \"steer\" ? queued.args : \"\"\n }\n const prompt = invocation.promptMarkdown.trim() || \"(empty message)\"\n return withInboundAttachments(prompt, await this.inboundAttachmentManifest(invocation, { sourceOnly: true }))\n }\n\n /**\n * Download the turn's inbound attachments and return the manifest listing\n * where they landed (\"\" when none). `sourceOnly` skips the history messages'\n * attachments and takes the source message's alone.\n */\n private async inboundAttachmentManifest(\n invocation: ClaimedInvocation,\n options: { strictAttachments?: boolean; signal?: AbortSignal; sourceOnly?: boolean } = {}\n ): Promise<string> {\n if (options.signal?.aborted) throw options.signal.reason\n // A sealed turn's attachments come from the refs hydration opened out of the\n // sealed payloads — the plaintext message list only holds ciphertext\n // placeholders, so there is nothing to scan there. The S3 object is opaque\n // ciphertext; the ref's key decrypts it locally.\n if (invocation.sealing) {\n const refs = invocation.sealedAttachments\n if (!refs) return \"\"\n try {\n const downloaded = await downloadSealedInboundAttachments(this.client, {\n refs: selectSealedInboundRefs(refs.prompt, options.sourceOnly ? [] : refs.history),\n invocationId: invocation.id,\n cwd: process.cwd(),\n log: this.log,\n strict: options.strictAttachments,\n signal: options.signal,\n })\n if (options.signal?.aborted) throw options.signal.reason\n return formatInboundAttachmentManifest(downloaded)\n } catch (error) {\n if (options.strictAttachments || options.signal?.aborted) throw error\n this.log(`sealed inbound attachment fetch failed: ${this.summarize(error)}`)\n return \"\"\n }\n }\n // Best-effort: a discovery/download failure (e.g. a key without\n // attachments:read) must never block the prompt from reaching the runtime.\n try {\n const downloaded = await downloadInboundAttachments(this.client, {\n streamId: invocation.activeStreamId,\n sourceMessageId: invocation.sourceMessageId,\n contextMessageIds: options.sourceOnly\n ? []\n : (invocation.context?.messages ?? []).map((message) => message.messageId),\n invocationId: invocation.id,\n cwd: process.cwd(),\n scanLimit: ATTACHMENT_SCAN_LIMIT,\n log: this.log,\n strict: options.strictAttachments,\n signal: options.signal,\n })\n if (options.signal?.aborted) throw options.signal.reason\n return formatInboundAttachmentManifest(downloaded)\n } catch (error) {\n if (options.strictAttachments || options.signal?.aborted) throw error\n this.log(`inbound attachment scan failed: ${this.summarize(error)}`)\n return \"\"\n }\n }\n\n // --- Interim + final output ------------------------------------------------\n\n private route(invocationId: string): TurnRoute | undefined {\n return this.inflight.get(invocationId) ?? this.completed.get(invocationId)\n }\n\n private registerTurn(invocation: ClaimedInvocation, contributors: ClaimedInvocation[] = []): TurnRoute {\n const route = new TurnRoute({\n invocation,\n contributors,\n order: (this.nextRouteOrder += 1),\n generation: this.lifecycle,\n idleTimeoutMs: this.config.idleTimeoutMs,\n onIdleDeadline: (target, generation) => void this.onReplyTimeout(target, generation),\n })\n route.armIdleTimeout()\n this.inflight.set(invocation.id, route)\n return route\n }\n\n private revokedResult(route: TurnRoute): SendResult {\n return {\n ok: false,\n retryable: false,\n message: `Request ${route.invocation.id} is no longer routable — this session stopped speaking for its stream.`,\n }\n }\n\n private async postTurnMessage(\n route: TurnRoute,\n intent: PostIntent,\n metadata: Record<string, unknown>\n ): Promise<void> {\n const seq = route.claimSeq(intent.retry)\n const sealing = route.invocation.sealing\n const sourceRevision = route.invocation.sourceRevision\n let prepared = intent.retry\n if (!prepared) {\n if (sealing) {\n const uploaded = await uploadSealedReplyAttachments(this.client, intent.text, process.cwd())\n const body = await sealReply(\n sealing,\n uploaded.markdown.trim(),\n uploaded.refs.length > 0 ? { attachmentRefs: uploaded.refs } : undefined\n )\n prepared = {\n kind: \"sealed\",\n seq,\n text: intent.text,\n ...(intent.retryKey === undefined ? {} : { retryKey: intent.retryKey }),\n body,\n attachmentIds: uploaded.attachmentIds,\n }\n } else {\n const { markdown } = await uploadReplyAttachments(this.client, intent.text, process.cwd())\n prepared = {\n kind: \"plaintext\",\n seq,\n text: intent.text,\n ...(intent.retryKey === undefined ? {} : { retryKey: intent.retryKey }),\n body: {\n instanceId: this.config.instanceId,\n claimToken: route.invocation.claimToken,\n content: markdown,\n clientMessageId: intent.retryKey ?? `remote-send-${route.invocation.id}-${seq}`,\n metadata,\n },\n }\n }\n }\n if (!prepared) throw new Error(\"post preparation produced no body\")\n if (route.isFenced(this.lifecycle)) {\n throw new RouteRevokedError(this.revokedResult(route).message)\n }\n if (!this.isOutputCurrent(route.invocation, sourceRevision)) {\n throw new StaleInputError(\"invocation input changed while the post was being prepared\")\n }\n try {\n if (prepared.kind === \"sealed\") {\n await this.client.sendSealedMessage(route.invocation.id, sealing!.callbackToken, {\n ...prepared.body,\n ...(prepared.attachmentIds.length > 0 && { attachmentIds: prepared.attachmentIds }),\n })\n } else {\n await this.client.sendInvocationMessage(route.invocation.id, prepared.body)\n }\n } catch (error) {\n route.rememberFailedPost(seq, prepared, this.lifecycle)\n throw error\n }\n route.recordLandedPost(seq, prepared)\n }\n\n private async writeRouteMessage(\n route: TurnRoute,\n intent: PostIntent,\n metadata: Record<string, unknown>\n ): Promise<void> {\n try {\n await this.postTurnMessage(route, intent, metadata)\n } catch (error) {\n await this.terminalizeRouteWrite(route, error)\n throw error\n }\n }\n\n /**\n * A reply that carries no words and no attachments closes as `noResponse` —\n * the wire's own word for a turn that said nothing — instead of standing in a\n * message the session never wrote.\n */\n private async prepareReply(route: TurnRoute, text: string): Promise<PreparedClose> {\n const sealing = route.invocation.sealing\n const sourceRevision = route.invocation.sourceRevision\n if (sealing) {\n const { markdown, refs, attachmentIds } = await uploadSealedReplyAttachments(this.client, text, process.cwd())\n const spoken = markdown.trim()\n const reply =\n spoken.length > 0 || refs.length > 0\n ? await sealReply(sealing, spoken, refs.length > 0 ? { attachmentRefs: refs } : undefined)\n : undefined\n return {\n reason: \"reply\",\n sourceText: text,\n wire: {\n kind: \"sealed\",\n callbackToken: sealing.callbackToken,\n body:\n reply === undefined\n ? { noResponse: true, sourceRevision }\n : { sourceRevision, reply: { ...reply, ...(attachmentIds.length > 0 && { attachmentIds }) } },\n },\n }\n }\n const { markdown, uploaded } = await uploadReplyAttachments(this.client, text, process.cwd())\n const attachmentIds = uploaded.map((attachment) => attachment.id)\n return {\n reason: \"reply\",\n sourceText: text,\n wire: {\n kind: \"plaintext\",\n body: {\n instanceId: this.config.instanceId,\n claimToken: route.invocation.claimToken,\n sourceRevision,\n ...(markdown.trim().length > 0 ? { finalMessageMarkdown: markdown } : { noResponse: true as const }),\n metadata: {\n \"remote.invocationId\": route.invocation.id,\n \"remote.instanceId\": this.config.instanceId,\n ...(attachmentIds.length > 0 && { \"remote.attachmentIds\": attachmentIds.join(\",\") }),\n },\n },\n },\n }\n }\n\n private async prepareTimeout(route: TurnRoute): Promise<PreparedClose> {\n const note = \"_The session ended the turn without sending a reply._\"\n const noResponse = route.sentCount > 0\n const sealing = route.invocation.sealing\n const sourceRevision = route.invocation.sourceRevision\n if (sealing) {\n return {\n reason: \"timeout\",\n wire: {\n kind: \"sealed\",\n callbackToken: sealing.callbackToken,\n body: noResponse\n ? { noResponse: true, sourceRevision }\n : { sourceRevision, reply: await sealReply(sealing, note) },\n },\n }\n }\n return {\n reason: \"timeout\",\n wire: {\n kind: \"plaintext\",\n body: {\n instanceId: this.config.instanceId,\n claimToken: route.invocation.claimToken,\n sourceRevision,\n ...(noResponse ? { noResponse: true as const } : { finalMessageMarkdown: note }),\n metadata: { \"remote.invocationId\": route.invocation.id, \"remote.timedOut\": \"true\" },\n },\n },\n }\n }\n\n private async postPreparedClose(route: TurnRoute, prepared: PreparedClose): Promise<void> {\n if (route.isFenced(this.lifecycle)) throw new RouteRevokedError(\"route revoked\")\n if (prepared.wire.kind === \"sealed\") {\n await this.client.completeSealed(\n route.invocation.id,\n prepared.wire.callbackToken,\n prepared.wire.body,\n route.execution.signal\n )\n return\n }\n await this.client.complete(route.invocation.id, prepared.wire.body, route.execution.signal)\n }\n\n private async settleClosed(route: TurnRoute, replyText?: string): Promise<void> {\n const invocationId = route.invocation.id\n route.settleClosed(replyText)\n this.inflight.delete(invocationId)\n // Teardown owns reinsertion and presence if it advanced the route generation.\n if (route.isFenced(this.lifecycle)) return\n // Keep the same object so ids reserved by posts queued behind this close remain visible.\n this.completed.delete(invocationId)\n this.completed.set(invocationId, route)\n for (const oldest of this.completed.keys()) {\n if (this.completed.size <= COMPLETED_TURN_MEMORY) break\n this.completed.delete(oldest)\n }\n if (this.activeTurnStream === route.invocation.responseStreamId) this.activeTurnStream = undefined\n await this.syncPresence()\n this.claimDrainRequested = true\n this.scheduleRequestedClaimDrain()\n }\n\n private async reopenAfterFailedCompletion(route: TurnRoute, prepared: PreparedClose | undefined): Promise<void> {\n if (route.isFenced(this.lifecycle)) {\n route.reopen(undefined)\n return\n }\n route.reopen(prepared)\n route.armIdleTimeout()\n this.inflight.set(route.invocation.id, route)\n await this.syncPresence()\n }\n\n private touchCompleted(invocationId: string, record: TurnRoute): void {\n if (!this.completed.delete(invocationId)) return\n this.completed.set(invocationId, record)\n }\n\n private isTerminalPostError(error: unknown): boolean {\n return (\n error instanceof ThreaApiError &&\n error.status >= 400 &&\n error.status < 500 &&\n !RETRYABLE_POST_STATUSES.has(error.status)\n )\n }\n\n private async terminalizeRouteWrite(route: TurnRoute, error: unknown): Promise<boolean> {\n if (!this.isTerminalPostError(error)) return false\n if (!route.terminal) await this.evictTerminalRoute(route)\n return true\n }\n\n private terminalWriteResult(invocationId: string, kind: \"message\" | \"reply\", error: unknown): SendResult {\n return {\n ok: false,\n retryable: false,\n message: `Threa rejected the ${kind} for request ${invocationId}: ${this.summarize(error)}.`,\n }\n }\n\n private terminalResult(invocationId: string, kind: \"send\" | \"reply\", text: string): SendResult {\n const tombstone = this.terminalReplies.get(invocationId)\n if (kind === \"reply\" && tombstone?.replyDigest === this.replyDigest(text)) return { ok: true, message: \"sent\" }\n return {\n ok: false,\n retryable: false,\n message: `Threa refused further messages for request ${invocationId} — it is closed and no longer accepts follow-ups.`,\n }\n }\n\n /** Drop write credentials but retain a digest for exact final-reply idempotency. */\n private async evictTerminalRoute(route: TurnRoute): Promise<void> {\n const invocationId = route.invocation.id\n route.markTerminal()\n this.releaseObservation(invocationId)\n this.inflight.delete(invocationId)\n this.completed.delete(invocationId)\n const newerRouteOwnsStream = [...this.inflight.values()].some(\n (candidate) =>\n candidate.order > route.order &&\n !candidate.revoked &&\n candidate.invocation.responseStreamId === route.invocation.responseStreamId\n )\n if (this.activeTurnStream === route.invocation.responseStreamId && !newerRouteOwnsStream) {\n this.activeTurnStream = undefined\n }\n this.terminalReplies.delete(invocationId)\n this.terminalReplies.set(invocationId, {\n ...(route.replyText === undefined ? {} : { replyDigest: this.replyDigest(route.replyText) }),\n })\n for (const oldest of this.terminalReplies.keys()) {\n if (this.terminalReplies.size <= COMPLETED_TURN_MEMORY) break\n this.terminalReplies.delete(oldest)\n }\n await this.syncPresence()\n }\n\n private async postThroughClosed(route: TurnRoute, kind: \"send\" | \"reply\", intent: PostIntent): Promise<SendResult> {\n const invocationId = route.invocation.id\n if (kind === \"reply\" && route.replyText === intent.text) {\n this.touchCompleted(invocationId, route)\n return { ok: true, message: \"sent\" }\n }\n if (route.terminal) return this.terminalResult(invocationId, kind, intent.text)\n if (intent.text.trim().length === 0) {\n return {\n ok: false,\n retryable: false,\n message: `Request ${invocationId} had already closed, and an empty ${kind} has nothing to post as a follow-up.`,\n }\n }\n try {\n await this.writeRouteMessage(route, intent, {\n \"remote.invocationId\": invocationId,\n \"remote.followUp\": \"true\",\n })\n } catch (error) {\n if (error instanceof RouteRevokedError) return this.revokedResult(route)\n if (this.isTerminalPostError(error)) return this.terminalWriteResult(invocationId, \"message\", error)\n return { ok: false, message: `Failed to post message to Threa: ${this.summarize(error)}`, retryable: true }\n }\n if (kind === \"reply\") route.replyText = intent.text\n this.touchCompleted(invocationId, route)\n return {\n ok: true,\n message: `Posted as a follow-up message — request ${invocationId} had already closed, and stays closed.`,\n }\n }\n\n async sendInterim(invocationId: string, text: string): Promise<SendResult> {\n const route = this.route(invocationId)\n if (!route) {\n if (this.terminalReplies.has(invocationId)) return this.terminalResult(invocationId, \"send\", text)\n return {\n ok: false,\n retryable: false,\n message: `No open request with invocation_id ${invocationId} — interim messages need an open request (it may have been answered or closed).`,\n }\n }\n if (text.trim().length === 0) {\n return { ok: false, retryable: false, message: \"An interim message needs content — nothing was posted.\" }\n }\n const intent = route.snapshotIntent(text)\n return route.enqueue(() => this.runSend(route, intent))\n }\n\n private async runSend(route: TurnRoute, intent: PostIntent): Promise<SendResult> {\n if (route.terminal) return this.terminalResult(route.invocation.id, \"send\", intent.text)\n if (route.revoked) return this.revokedResult(route)\n if (route.state === \"closed\") return this.postThroughClosed(route, \"send\", intent)\n if (this.observedClaims.get(route.invocation.id)?.updateInProgress) {\n return { ok: false, message: \"Input update is still in progress; retry this send.\", retryable: true }\n }\n const sourceRevision = route.invocation.sourceRevision\n try {\n await this.writeRouteMessage(route, intent, {\n \"remote.invocationId\": route.invocation.id,\n \"remote.interim\": \"true\",\n })\n } catch (error) {\n if (error instanceof RouteRevokedError) return this.revokedResult(route)\n if (error instanceof StaleInputError) {\n return {\n ok: false,\n message: \"Input changed while preparing this send; retry on the current turn.\",\n retryable: true,\n }\n }\n if (this.isTerminalPostError(error)) return this.terminalWriteResult(route.invocation.id, \"message\", error)\n return { ok: false, message: `Failed to post message to Threa: ${this.summarize(error)}`, retryable: true }\n }\n if (!this.isOutputCurrent(route.invocation, sourceRevision)) {\n return {\n ok: false,\n message: `Message post raced a source update for ${route.invocation.id}; do not treat it as current-turn output.`,\n }\n }\n // A send is a sign of life: push the idle timeout out so a turn that keeps\n // posting progress is never force-closed.\n route.touchIdleTimeout()\n return { ok: true, message: \"sent\" }\n }\n\n async reply(invocationId: string, text: string): Promise<SendResult> {\n const route = this.route(invocationId)\n if (!route) {\n if (this.terminalReplies.has(invocationId)) return this.terminalResult(invocationId, \"reply\", text)\n return {\n ok: false,\n retryable: false,\n message: `No open request with invocation_id ${invocationId} (already answered, expired, or unknown).`,\n }\n }\n const intent = route.snapshotIntent(text)\n return route.enqueue(() => this.runReply(route, intent))\n }\n\n private async runReply(route: TurnRoute, intent: PostIntent): Promise<SendResult> {\n if (route.state === \"closed\" && route.replyText === intent.text) return { ok: true, message: \"sent\" }\n if (route.terminal) return this.terminalResult(route.invocation.id, \"reply\", intent.text)\n if (route.revoked) return this.revokedResult(route)\n if (route.state === \"closed\") return this.postThroughClosed(route, \"reply\", intent)\n if (this.observedClaims.get(route.invocation.id)?.updateInProgress) {\n return { ok: false, message: \"Input update is still in progress; retry this reply.\", retryable: true }\n }\n // Resolve an ambiguous earlier close before posting changed text under a new id.\n if (route.prepared && (route.prepared.reason === \"timeout\" || route.prepared.sourceText !== intent.text)) {\n const resolved = await this.closeWith(route, route.prepared)\n if (!resolved.ok) {\n return {\n ok: false,\n retryable: resolved.retryable ?? false,\n message: `The earlier close for request ${route.invocation.id} has not landed yet, so it still owns the close: ${resolved.message}`,\n }\n }\n const followUp = await this.postThroughClosed(route, \"reply\", intent)\n return resolved.closedTurn ? { ...followUp, closedTurn: true } : followUp\n }\n return this.closeWith(route, route.prepared ?? { kind: \"reply\", text: intent.text })\n }\n\n private closeWith(route: TurnRoute, source: PreparedClose | CloseRequest): Promise<SendResult> {\n route.beginClosing()\n return route.trackClosing(this.runCompletion(route, source))\n }\n\n private async runCompletion(route: TurnRoute, source: PreparedClose | CloseRequest): Promise<SendResult> {\n const sourceRevision = route.invocation.sourceRevision\n let prepared: PreparedClose\n if (\"wire\" in source) {\n prepared = source\n } else {\n try {\n prepared =\n source.kind === \"reply\" ? await this.prepareReply(route, source.text) : await this.prepareTimeout(route)\n } catch (error) {\n await this.reopenAfterFailedCompletion(route, undefined)\n if (route.revoked) return this.revokedResult(route)\n return {\n ok: false,\n message: `Failed to post reply to Threa (will stay open for retry): ${this.summarize(error)}`,\n retryable: true,\n }\n }\n }\n if (!this.isOutputCurrent(route.invocation, sourceRevision)) return this.closeStaleReply(route)\n route.prepared = prepared\n try {\n await this.postPreparedClose(route, prepared)\n } catch (error) {\n if (this.isClaimCancelled(route.invocation)) return this.closeStaleReply(route)\n if (error instanceof ThreaApiError && error.status === 409 && error.code === \"INVOCATION_INPUT_STALE\") {\n this.releaseObservation(route.invocation.id)\n await this.failContributors(route, \"The owning turn input became stale during completion.\")\n return this.closeStaleReply(route)\n }\n if (await this.terminalizeRouteWrite(route, error)) {\n return this.terminalWriteResult(route.invocation.id, \"reply\", error)\n }\n await this.reopenAfterFailedCompletion(route, prepared)\n if (error instanceof RouteRevokedError || route.revoked) return this.revokedResult(route)\n return {\n ok: false,\n message: `Failed to post reply to Threa (will stay open for retry): ${this.summarize(error)}`,\n retryable: true,\n }\n }\n this.releaseObservation(route.invocation.id)\n await this.completeContributors(route)\n await this.settleClosed(route, prepared.reason === \"reply\" ? prepared.sourceText : undefined)\n return { ok: true, message: \"sent\", closedTurn: true }\n }\n\n private async closeStaleReply(route: TurnRoute): Promise<SendResult> {\n route.revoke()\n if (this.inflight.get(route.invocation.id) === route) this.inflight.delete(route.invocation.id)\n if (this.activeTurnStream === route.invocation.responseStreamId) this.activeTurnStream = undefined\n await this.syncPresence()\n return { ok: false, message: `Request ${route.invocation.id} is closed; its source changed.` }\n }\n\n /**\n * Close an in-flight turn as failed: the runtime reported the work itself\n * failed, so nothing is posted and the invocation carries the reason. Mirrors\n * what the delivery catch path does after `registerTurn` — the route dies,\n * presence frees up, and the next claim drain runs. Tracked as the route's\n * closing task so a shutdown mid-fail awaits it instead of failing the turn\n * a second time. Returns false when this session holds no route for the id or\n * the turn already closed, so nothing was failed.\n */\n async failTurn(invocationId: string, errorMessage: string): Promise<boolean> {\n const route = this.route(invocationId)\n if (!route) return false\n return route.enqueue(() =>\n route.trackClosing(\n (async () => {\n if (route.state === \"closed\" || route.terminal) return false\n route.beginClosing()\n await this.failContributors(route, errorMessage)\n await this.failInvocation(route.invocation, errorMessage)\n route.markClosed()\n this.clearInflight(invocationId)\n if (this.activeTurnStream === route.invocation.responseStreamId) this.activeTurnStream = undefined\n await this.syncPresence()\n this.claimDrainRequested = true\n this.scheduleRequestedClaimDrain()\n return true\n })()\n )\n )\n }\n\n /**\n * Record trace steps against an in-flight turn. Fire-and-forget: a failed\n * frame is logged and dropped, not retried — steps are ephemeral progress,\n * not state. Returns false when the invocation is no longer taking work\n * (answered, expired, superseded, or its completion is already on the wire),\n * which a transcript tailer uses as its stop signal. Frames must arrive\n * already redacted (or full, on a sealed turn — the tailer decides); this\n * method ships them verbatim, sealing each one under the stream key when the\n * turn is sealed so plaintext step content never leaves the machine on an E2E\n * scratchpad.\n */\n async recordSteps(invocationId: string, frames: StepFrame[], statusText?: string): Promise<boolean> {\n const entry = this.openRoute(invocationId)\n if (!entry) return false\n // Keep the tracer alive but do not emit old-turn frames while the runtime is\n // being steered onto a newer authoritative input.\n if (this.observedClaims.get(invocationId)?.updateInProgress) return true\n // The server rejects >50 frames per steps call (plaintext and sealed alike),\n // so a large batch (e.g. a transcript replay after late binding) ships in chunks.\n for (let start = 0; start < frames.length; start += MAX_STEP_FRAMES_PER_CALL) {\n const chunk = frames.slice(start, start + MAX_STEP_FRAMES_PER_CALL)\n const sourceRevision = entry.invocation.sourceRevision\n if (entry.invocation.sealing) {\n // Sealed turn: seal each frame under the stream key and ship on the\n // sealed wire. No statusText — the sealed wire deliberately carries\n // none (a plaintext status derived from sealed content would leak).\n const sealing = entry.invocation.sealing\n const finished = chunk.filter((frame) => frame.phase !== \"started\")\n if (finished.length === 0) continue\n try {\n const sealedFrames = await Promise.all(\n finished.map((frame) =>\n sealStep(\n sealing,\n frame.stepType,\n frame.content,\n frame.durationMs !== undefined ? { durationMs: frame.durationMs } : undefined\n )\n )\n )\n if (!this.isOutputCurrent(entry.invocation, sourceRevision)) return this.inflight.has(invocationId)\n await this.transport.recordSealedSteps(invocationId, sealing.callbackToken, sealedFrames)\n } catch (error) {\n this.log(`recordSteps (sealed) failed: ${this.summarize(error)}`)\n }\n } else {\n if (!this.isOutputCurrent(entry.invocation, sourceRevision)) return this.inflight.has(invocationId)\n await this.transport\n .recordSteps(invocationId, entry.invocation.claimToken, chunk, statusText ?? this.runtime.busyStatusText)\n .catch((error) => this.log(`recordSteps failed: ${this.summarize(error)}`))\n }\n // The turn can close during an awaited send (reply, /stop, idle timeout)\n // — exactly the long multi-chunk replays this loop exists for. Recheck so\n // the returned boolean stays an honest stop signal for the tailer.\n if (!this.openRoute(invocationId)) return false\n }\n return true\n }\n\n async postToInvocation(\n invocationId: string,\n body: { content: string; clientMessageId?: string; metadata?: Record<string, unknown> }\n ): Promise<void> {\n const route = this.route(invocationId)\n if (!route) throw this.routeUnavailableError(invocationId)\n await this.postRouteOwnedMessage(route, body)\n }\n\n async postToStream(\n streamId: string,\n body: { content: string; clientMessageId?: string; metadata?: Record<string, unknown> }\n ): Promise<void> {\n const route = this.routeForStream(streamId)\n if (route) {\n await this.postRouteOwnedMessage(route, body)\n return\n }\n await this.client.sendMessage(streamId, body)\n }\n\n private async postRouteOwnedMessage(\n route: TurnRoute,\n body: { content: string; clientMessageId?: string; metadata?: Record<string, unknown> }\n ): Promise<void> {\n const intent = route.snapshotIntent(body.content, body.clientMessageId)\n await route.enqueue(async () => {\n if (route.terminal) throw this.routeUnavailableError(route.invocation.id)\n if (route.revoked) throw new RouteRevokedError(this.revokedResult(route).message)\n await this.writeRouteMessage(route, intent, {\n \"remote.invocationId\": route.invocation.id,\n ...body.metadata,\n })\n if (route.state === \"closed\") this.touchCompleted(route.invocation.id, route)\n })\n }\n\n private routeUnavailableError(invocationId: string): Error {\n if (this.terminalReplies.has(invocationId)) {\n return new Error(`Threa refused further messages for request ${invocationId}; its route is terminal.`)\n }\n return new Error(`No routable request with invocation_id ${invocationId} exists in this session.`)\n }\n\n /**\n * The stream a control command acts on: its own in parallel mode, every stream\n * (undefined) in serial mode, where one turn runs whichever stream it answers.\n */\n private controlStream(streamId: string): string | undefined {\n return this.parallel ? streamId : undefined\n }\n\n private controlRoutes(streamId: string | undefined): TurnRoute[] {\n const routes = [...this.inflight.values()]\n const scope = streamId === undefined ? undefined : this.controlStream(streamId)\n return scope === undefined ? routes : routes.filter((route) => route.invocation.responseStreamId === scope)\n }\n\n private routeForStream(streamId: string): TurnRoute | undefined {\n let closing: TurnRoute | undefined\n for (const route of this.inflight.values()) {\n if (route.invocation.responseStreamId !== streamId) continue\n if (route.state === \"open\") return route\n closing ??= route\n }\n return closing\n }\n\n private openRoute(invocationId: string): TurnRoute | undefined {\n const route = this.inflight.get(invocationId)\n return route?.state === \"open\" && !route.revoked ? route : undefined\n }\n\n /** Whether this session still holds the invocation open (not yet replied, timed out, or superseded). */\n isInflight(invocationId: string): boolean {\n return this.openRoute(invocationId) !== undefined\n }\n\n /** Reset idle timeouts for every in-flight turn in a stream (a pending approval is a sign of life). */\n keepAlive(streamId: string): void {\n for (const entry of this.inflight.values()) {\n if (entry.state === \"open\" && entry.invocation.responseStreamId === streamId) entry.touchIdleTimeout()\n }\n }\n\n // --- Decisions ------------------------------------------------------------\n\n /**\n * Put a call the runtime cannot make to the human on the stream and block on\n * the answer. The card is opened over HTTP; the answer arrives on the bot\n * plane (`decision:resolved`/`decision:cancelled`) with a `getDecision` poll\n * on the socket backstop cadence as the missed-push insurance.\n */\n async requestDecision(input: DecisionRequestInput, opts: { signal?: AbortSignal } = {}): Promise<DecisionOutcome> {\n if (!input.streamId && this.parallel && this.inflightStreams().size > 1) {\n throw new Error(\"Cannot open a decision: turns are running in several streams; pass streamId.\")\n }\n const onlyStream = this.parallel ? [...this.inflightStreams()][0] : undefined\n const streamId = input.streamId ?? onlyStream ?? this.activeTurnStream ?? this.link?.rootStreamId\n if (!streamId) throw new Error(\"Cannot open a decision: this session has no active turn and no linked scratchpad.\")\n const route = this.routeForStream(streamId)\n const invocationId = input.invocationId ?? route?.invocation.id\n const sealing = route?.invocation.sealing\n const question = sealing\n ? await this.sealedDecisionQuestion(streamId, input, sealing)\n : {\n title: input.title,\n ...(input.body ? { bodyMarkdown: input.body } : {}),\n options: input.options,\n }\n const decision = await this.client.requestDecision(streamId, {\n ...question,\n ...(input.allowNote === undefined ? {} : { allowNote: input.allowNote }),\n ...(input.externalRef ? { externalRef: input.externalRef } : {}),\n ...(input.expiresInMs === undefined ? {} : { expiresInMs: input.expiresInMs }),\n runtimeSessionId: this.config.runtimeSessionId,\n ...(invocationId ? { invocationId } : {}),\n })\n // A decision that landed non-open already (an instant resolve, an expiry\n // race) never gets a push — settle from what the POST returned.\n if (decision.status !== \"open\") {\n return this.outcomeFor(decision, await this.decisionNote(decision, sealing))\n }\n // shutdown() during the POST already ran abandonPendingDecisions over an\n // empty map, so registering now would strand this caller forever.\n if (this.stopped) {\n void this.cancelDecision(decision.id).catch(() => {})\n throw new DecisionAbandonedError(decision.id)\n }\n const promise = new Promise<DecisionOutcome>((resolve, reject) => {\n this.pendingDecisions.set(decision.id, { decision, ...(sealing ? { sealing } : {}), resolve, reject })\n })\n const abort = () => {\n if (!this.pendingDecisions.has(decision.id)) return\n this.failDecision(decision.id, decisionAbortError(decision.id))\n void this.cancelDecision(decision.id).catch((error) =>\n this.log(`decision ${decision.id} cancel-on-abort failed: ${this.summarize(error)}`)\n )\n }\n if (opts.signal?.aborted) abort()\n else opts.signal?.addEventListener(\"abort\", abort, { once: true })\n this.keepTurnAliveForDecisions()\n this.scheduleDecisionPoll()\n try {\n return await promise\n } finally {\n opts.signal?.removeEventListener(\"abort\", abort)\n }\n }\n\n /** Withdraw a decision this session opened (also settles a local awaiter through the push/poll). */\n async cancelDecision(decisionId: string): Promise<void> {\n await this.client.cancelDecision(decisionId)\n }\n\n /**\n * The question half of a sealed create body: the title, body and option\n * labels travel inside the ciphertext, leaving only ids and tones for the\n * server to validate an answer against. The AAD binds the seal to the stream\n * the card is posted to, which on a thread is not the root the key hangs off,\n * and to an id minted here because the seal needs it before the row exists.\n */\n private async sealedDecisionQuestion(\n streamId: string,\n input: DecisionRequestInput,\n sealing: SealingState\n ): Promise<Pick<CreateDecisionRequestBody, \"options\" | \"decisionId\" | \"sealed\">> {\n if (!this.botId) {\n throw new Error(\"Cannot seal a decision: the bot plane never said which bot this session speaks as.\")\n }\n const sealed = await sealDecision(\n sealing,\n { streamId, requesterBotId: this.botId },\n {\n title: input.title,\n ...(input.body ? { bodyMarkdown: input.body } : {}),\n optionLabels: Object.fromEntries(input.options.map((option) => [option.id, option.label ?? option.id])),\n }\n )\n return {\n options: input.options.map((option) => ({ id: option.id, tone: option.tone })),\n decisionId: sealed.decisionId,\n sealed: { ciphertext: sealed.ciphertext, envelope: sealed.envelope },\n }\n }\n\n /**\n * The note the human attached, opened when it is sealed. A note that will not\n * open settles the decision without one: the answer itself is readable either\n * way, and losing the note beats stranding the turn on it.\n */\n private async decisionNote(decision: DecisionRequest, sealing: SealingState | undefined): Promise<string | null> {\n const resolution = decision.resolution\n if (!resolution?.noteCiphertext || !resolution.noteEnvelope) return resolution?.note ?? null\n if (!sealing || !resolution.decidedBy) {\n this.log(`decision ${decision.id} carries a sealed note this session has no way to open`)\n return null\n }\n const opened = await openSealedDecisionNote(sealing, {\n streamId: decision.streamId,\n decisionId: decision.id,\n decidedBy: resolution.decidedBy,\n ciphertext: resolution.noteCiphertext,\n envelope: resolution.noteEnvelope,\n })\n if (opened === null) this.log(`decision ${decision.id} sealed note did not open`)\n return opened\n }\n\n private outcomeFor(decision: DecisionRequest, note: string | null): DecisionOutcome {\n if (decision.status === \"resolved\") {\n const optionId = decision.resolution?.optionId\n if (!optionId) throw new Error(`Decision ${decision.id} resolved without an option id.`)\n return { status: \"resolved\", optionId, note, decision }\n }\n return { status: decision.status === \"expired\" ? \"expired\" : \"cancelled\", decision }\n }\n\n /** A `decision:resolved`/`decision:cancelled` push for a decision this session is awaiting. */\n private handleDecisionPush(payload: BotDecisionPayload): void {\n if (!payload || typeof payload !== \"object\") return\n const pending = this.pendingDecisions.get(payload.decisionId)\n if (!pending) return\n if (payload.runtimeSessionId !== this.config.runtimeSessionId) return\n void this.settleDecision({\n ...pending.decision,\n status: payload.status,\n version: payload.version,\n ...(payload.status === \"resolved\" && payload.optionId\n ? {\n resolution: {\n optionId: payload.optionId,\n ...(payload.note === null ? {} : { note: payload.note }),\n ...(payload.noteCiphertext && payload.noteEnvelope\n ? { noteCiphertext: payload.noteCiphertext, noteEnvelope: payload.noteEnvelope }\n : {}),\n ...(payload.decidedBy === null ? {} : { decidedBy: payload.decidedBy }),\n },\n }\n : {}),\n })\n }\n\n private async settleDecision(decision: DecisionRequest): Promise<void> {\n const pending = this.pendingDecisions.get(decision.id)\n if (!pending) return\n this.pendingDecisions.delete(decision.id)\n this.stopDecisionPollWhenIdle()\n try {\n pending.resolve(this.outcomeFor(decision, await this.decisionNote(decision, pending.sealing)))\n } catch (error) {\n pending.reject(error instanceof Error ? error : new Error(String(error)))\n }\n }\n\n private failDecision(decisionId: string, error: Error): void {\n const pending = this.pendingDecisions.get(decisionId)\n if (!pending) return\n this.pendingDecisions.delete(decisionId)\n this.stopDecisionPollWhenIdle()\n pending.reject(error)\n }\n\n /** A pending decision is a sign of life for the turn that is blocked on it. */\n private keepTurnAliveForDecisions(): void {\n for (const streamId of new Set([...this.pendingDecisions.values()].map((pending) => pending.decision.streamId))) {\n this.keepAlive(streamId)\n }\n }\n\n /**\n * (Re)arm the decision backstop, replacing any pending tick. The socket-up\n * cadence is bounded by half the turn's idle timeout because this poll is\n * also what keeps a turn blocked on an open card alive.\n */\n private scheduleDecisionPoll(delayMs?: number): void {\n if (this.decisionPollTimer) clearTimeout(this.decisionPollTimer)\n this.decisionPollTimer = undefined\n if (this.stopped || this.pendingDecisions.size === 0) return\n const delay =\n delayMs ??\n (this.transport.socketConnected\n ? Math.min(WS_BACKSTOP_POLL_MS, Math.floor(this.config.idleTimeoutMs / 2))\n : this.config.pollMs)\n this.decisionPollTimer = setTimeout(() => {\n this.decisionPollTimer = undefined\n void this.pollPendingDecisions()\n }, delay)\n }\n\n private stopDecisionPollWhenIdle(): void {\n if (this.pendingDecisions.size > 0) return\n if (this.decisionPollTimer) clearTimeout(this.decisionPollTimer)\n this.decisionPollTimer = undefined\n }\n\n /** Missed-push backstop: read every pending decision and settle the ones that moved. */\n private async pollPendingDecisions(): Promise<void> {\n if (this.stopped) return\n this.keepTurnAliveForDecisions()\n for (const decisionId of [...this.pendingDecisions.keys()]) {\n try {\n const decision = await this.client.getDecision(decisionId)\n if (decision.status !== \"open\") await this.settleDecision(decision)\n } catch (error) {\n // A decision the requester can no longer read is never coming back;\n // everything else is transient and retried on the next tick.\n if (error instanceof ThreaApiError && error.status === 404) {\n this.failDecision(decisionId, error)\n continue\n }\n this.log(`decision ${decisionId} backstop poll failed: ${this.summarize(error)}`)\n }\n }\n this.scheduleDecisionPoll()\n }\n\n /** Teardown: nobody is left to answer, so no connector may keep awaiting one. */\n /** Reject the matching awaiters and withdraw their cards, so no answerable card outlives its asker. */\n private async abandonPendingDecisions(matches: (decision: DecisionRequest) => boolean = () => true): Promise<void> {\n const abandoned = [...this.pendingDecisions.values()].map((pending) => pending.decision).filter(matches)\n for (const decision of abandoned) this.failDecision(decision.id, new DecisionAbandonedError(decision.id))\n this.stopDecisionPollWhenIdle()\n await Promise.all(\n abandoned.map((decision) =>\n this.cancelDecision(decision.id).catch((error) =>\n this.log(`decision ${decision.id} withdraw failed: ${this.summarize(error)}`)\n )\n )\n )\n }\n\n /** Queue timeout closure behind posts so in-flight output cannot be overtaken. */\n private async onReplyTimeout(route: TurnRoute, generation: number): Promise<void> {\n if (!route.isCurrentDeadline(generation) || route.state !== \"open\") return\n await route.enqueue(() => this.runIdleTimeout(route, generation))\n }\n\n private async runIdleTimeout(route: TurnRoute, generation: number): Promise<void> {\n if (!route.isCurrentDeadline(generation) || route.state !== \"open\" || route.revoked) return\n const result = await this.closeWith(route, route.prepared ?? { kind: \"timeout\" })\n if (!result.ok) this.log(`timeout close failed: ${result.message}`)\n }\n\n private clearInflight(invocationId: string): void {\n const entry = this.inflight.get(invocationId)\n if (!entry) return\n entry.revoke()\n this.inflight.delete(invocationId)\n }\n\n /**\n * A `bot:session_archived` push. Scoped to this session AND this root: a\n * runtime that re-registered under a new session id, or a cold start that\n * replaced an archived scratchpad with a fresh one, must not die to a stale\n * event for the retired root.\n */\n private async handleSessionArchived(payload: unknown): Promise<void> {\n const data = (payload ?? {}) as { runtimeSessionId?: unknown; rootStreamId?: unknown }\n if (typeof data.runtimeSessionId === \"string\" && data.runtimeSessionId !== this.config.runtimeSessionId) return\n const linked = this.link?.rootStreamId\n const rootStreamId = typeof data.rootStreamId === \"string\" ? data.rootStreamId : linked\n if (!rootStreamId || (linked && rootStreamId !== linked)) return\n await this.archive.archived(rootStreamId)\n }\n\n /** A `bot:session_restored` push: the server revived this session's link. */\n private async handleSessionRestored(payload: unknown): Promise<void> {\n const data = (payload ?? {}) as { runtimeSessionId?: unknown }\n if (typeof data.runtimeSessionId === \"string\" && data.runtimeSessionId !== this.config.runtimeSessionId) return\n await this.archive.restored()\n }\n\n /**\n * `bot:session_archived` is a one-shot push with no replay: a socket that was\n * down when the archive landed never learns of it, and the runtime then holds\n * a link to a dead scratchpad forever — taking its tmux window and worktree\n * with it. Re-derive from the server on every poll tick and socket bootstrap.\n */\n private async probeArchiveBackstop(): Promise<void> {\n await this.archive.probe(this.link?.rootStreamId)\n }\n\n /**\n * Detach effects. No more work can arrive, so fail any in-flight turn (its\n * reply could no longer land), drop the link, and go offline — but the\n * worktree survives until the grace expires.\n */\n private async detachForArchive(rootStreamId: string): Promise<void> {\n const inflight = this.revokeAllRoutes()\n this.activeTurnStream = undefined\n this.link = undefined\n this.linkGeneration += 1\n this.resetReconnectHandoff()\n await this.reconnectFallbackTask\n // Pull the next poll tick onto the probe cadence NOW — the pending tick was\n // scheduled with the slow socket-backstop delay (15 min), which would land\n // zero probes inside the grace window if the restore push is then missed.\n this.reschedulePoll(this.archive.probeDelayMs)\n await this.waitForClaimDrain()\n const offline = this.enqueueOfflinePresence(\n () => !this.stopped && this.archive.pendingRootStreamId === rootStreamId\n )\n await this.failUnansweredRoutes(inflight)\n await offline\n }\n\n /** The grace expired with the scratchpad still archived: hand the connector its terminal wind-down. */\n private async windDownForArchive(rootStreamId: string): Promise<void> {\n await this.shutdown()\n await this.delegate.onArchived?.({ rootStreamId })\n }\n\n // --- Timers ---------------------------------------------------------------\n\n private startPoll(): void {\n this.reschedulePoll(this.config.pollMs)\n }\n\n private handleTransportDisconnected(): void {\n this.emptyNoSocketPolls = 0\n this.reschedulePoll(this.config.pollMs)\n if (this.pendingDecisions.size > 0) this.scheduleDecisionPoll(this.config.pollMs)\n }\n\n /** (Re)arm the poll timer. Replaces any pending tick so a state change can pull the next tick closer. */\n private reschedulePoll(delayMs: number): void {\n if (this.stopped) return\n if (this.pollTimer) clearTimeout(this.pollTimer)\n this.pollTimer = setTimeout(() => void this.pollTick(), delayMs)\n }\n\n private async pollTick(): Promise<void> {\n if (this.stopped) return\n // Always first: while detached this is the reattach attempt (ensureLink\n // refuses to relink during the grace), and while linked it is the\n // missed-push backstop.\n await this.probeArchiveBackstop()\n if (!this.link) await this.ensureLink()\n if (!this.transport.socketConnected) await this.transport.connect()\n const claimed = await this.claimDrain()\n // shutdown() can land during the awaits above; re-arming then would leave\n // a live timer past teardown.\n if (!this.stopped) this.reschedulePoll(this.nextPollDelay(claimed))\n }\n\n /**\n * Socket up → slow backstop (pushes deliver work). Socket down → start at the\n * configured fast cadence and double per empty tick up to the cap, so an\n * active HTTP-only conversation stays snappy while an idle socketless session\n * can't burn the edge-request quota. Claimed work resets the backoff.\n */\n private nextPollDelay(claimed: boolean): number {\n // Detached-pending-restore: probe at a fixed cadence so a missed\n // bot:session_restored push still reattaches within the grace window. The\n // window bounds the total probes, so this cannot become a quota burn.\n if (this.archive.detached) return this.archive.probeDelayMs\n if (this.transport.socketConnected) {\n this.emptyNoSocketPolls = 0\n return WS_BACKSTOP_POLL_MS\n }\n if (claimed) {\n this.emptyNoSocketPolls = 0\n return this.config.pollMs\n }\n const delay = Math.min(NO_SOCKET_POLL_CAP_MS, this.config.pollMs * 2 ** this.emptyNoSocketPolls)\n this.emptyNoSocketPolls = Math.min(this.emptyNoSocketPolls + 1, 30)\n return delay\n }\n\n // --- Helpers --------------------------------------------------------------\n\n private resetReconnectHandoff(): void {\n if (this.reconnectResetTimer) clearTimeout(this.reconnectResetTimer)\n this.reconnectResetTimer = undefined\n const wasHandoff = this.reconnectHandoff\n this.reconnectHandoff = false\n const onHandoffReset = this.onHandoffReset\n this.onHandoffReset = undefined\n if (!wasHandoff && !onHandoffReset) return\n let callbackTask: Promise<unknown> | undefined\n if (onHandoffReset) {\n try {\n callbackTask = Promise.resolve(onHandoffReset()).catch((error) =>\n this.log(`session-control handoff reset failed: ${this.summarize(error)}`)\n )\n } catch (error) {\n this.log(`session-control handoff reset failed: ${this.summarize(error)}`)\n }\n }\n if (this.stopped || !this.link || this.archive.detached) {\n if (callbackTask) this.reconnectFallbackTask = callbackTask\n return\n }\n let task: Promise<unknown>\n const restoreIntake = () => this.syncPresence().then(() => this.claimDrain())\n task = (callbackTask ? callbackTask.then(restoreIntake) : restoreIntake()).finally(() => {\n if (this.reconnectFallbackTask === task) this.reconnectFallbackTask = undefined\n })\n this.reconnectFallbackTask = task\n }\n\n /**\n * Hold a key for each sealed scratchpad this bot was granted, then advertise\n * the keyring. Under the default policy the one key already covers them and\n * this changes nothing; under the per-stream policy the key is minted here,\n * and until presence carries it the owner has nothing to re-wrap to.\n */\n private async keyGrantedStreams(streamIds: string[]): Promise<void> {\n for (const streamId of streamIds) await this.bik.ensureForStream(streamId)\n await this.advertiseKeyring()\n }\n\n /**\n * Give up the key held for a scratchpad this bot was revoked from, then\n * re-advertise. The server has already deleted the wraps only that key could\n * open, so holding it buys nothing — under the default policy there is no\n * such key and the shared one stays, which is the point of one key per host.\n */\n private async keyRevokedStream(streamId: string): Promise<void> {\n await this.bik.dropStream(streamId)\n await this.advertiseKeyring()\n }\n\n /**\n * Push presence when the held keyring is no longer what the server was last\n * told, and update the hello body so a reconnect re-announces the same set.\n * A key the server has not registered is one no wrap can be addressed to, so\n * this runs before the wraps that name it.\n */\n private async advertiseKeyring(): Promise<void> {\n const advertised = this.bik.identities.map((identity) => identity.publicKeyId).join(\",\")\n if (advertised === this.advertisedKeyIds) return\n this.advertisedKeyIds = advertised\n Object.assign(this.hello, this.bik.presenceFields())\n await this.syncPresence()\n }\n\n private enqueuePresence(write: () => Promise<void>): Promise<void> {\n const queued = this.presenceTail.then(write)\n this.presenceTail = queued.catch(() => undefined)\n return this.presenceTail\n }\n\n /** Derive presence when this generation's queued write runs, not when queued. */\n private syncPresence(): Promise<void> {\n const lifecycle = this.lifecycle\n return this.enqueuePresence(async () => {\n if (lifecycle !== this.lifecycle || this.stopped || this.archive.detached) return\n const busy = this.reconnectHandoff || this.atCapacity\n await this.publishPresence(\n this.presenceBody(busy ? \"busy\" : \"available\", busy ? this.runtime.busyStatusText : undefined)\n )\n })\n }\n\n private enqueueOfflinePresence(isCurrent: () => boolean): Promise<void> {\n const lifecycle = this.lifecycle\n return this.enqueuePresence(async () => {\n if (lifecycle !== this.lifecycle || !isCurrent()) return\n await this.publishPresence(this.presenceBody(\"offline\"))\n })\n }\n\n private async publishPresence(body: PresenceBody): Promise<void> {\n await this.transport.updatePresence(body)\n this.reportPresence(body)\n }\n\n /** Never a reason to fail a presence write: the report is bookkeeping for a supervisor. */\n private reportPresence(body: PresenceBody): void {\n if (!this.onPresence) return\n try {\n this.onPresence({\n runtimeKind: body.runtimeKind,\n instanceId: body.instanceId,\n runtimeSessionId: body.runtimeSessionId,\n displayName: body.displayName,\n status: body.status,\n capabilities: body.capabilities,\n manifest: body.manifest,\n })\n } catch (error) {\n this.log(`presence report failed: ${this.summarize(error)}`)\n }\n }\n\n private presenceBody(status: \"available\" | \"busy\" | \"offline\", statusText?: string) {\n return {\n runtimeKind: this.runtime.kind,\n instanceId: this.config.instanceId,\n runtimeSessionId: this.config.runtimeSessionId,\n displayName: this.config.displayName,\n status,\n acceptingInvocations: status === \"available\",\n // Full capabilities on EVERY presence update: the server replaces stored\n // capabilities on a presence:update (it doesn't merge), so omitting the\n // session-control keys here would wipe what bot:hello advertised.\n capabilities: runtimeCapabilitiesFor(this.config.runtimeSessionId, this.delegate.sessionControl),\n manifest: effectiveRuntimeManifest(this.runtime.manifest, this.delegate.sessionControl),\n ...(statusText ? { statusText } : {}),\n // The keyring must ride every presence write too — an advertised set\n // replaces the stored one, so omitting it here clears what hello registered.\n ...this.bik.presenceFields(),\n }\n }\n\n private claimBody(busy: boolean, excludeResponseStreamIds: string[] = []): Record<string, unknown> {\n return {\n runtimeKind: this.runtime.kind,\n instanceId: this.config.instanceId,\n runtimeSessionId: this.config.runtimeSessionId,\n supportedCapabilities: claimCapabilitiesFor(busy, this.sessionControlEnabled),\n claimTtlSeconds: CLAIM_TTL_SECONDS,\n ...(!busy && excludeResponseStreamIds.length > 0 ? { excludeResponseStreamIds } : {}),\n }\n }\n\n private replyDigest(text: string): string {\n return createHash(\"sha256\").update(text).digest(\"hex\")\n }\n\n private summarize(error: unknown): string {\n return (error instanceof Error ? error.message : String(error)).slice(0, 200)\n }\n}\n",
|
|
6
|
+
"import { mkdirSync, readFileSync, statSync, writeFileSync } from \"node:fs\"\nimport { basename, dirname, join, resolve } from \"node:path\"\nimport {\n attachmentLocalPath,\n decryptAttachmentBytes,\n encryptAttachmentBytes,\n type AttachmentRef,\n} from \"@threahq/bot-runtime-client\"\nimport type { AttachmentSummary, StreamMessageSummary, ThreaClient } from \"./client\"\n\n/** A reply line `THREA_ATTACH: ./out.png` tells the channel to upload that file and attach it to the reply. */\nexport const ATTACH_DIRECTIVE_RE = /^THREA_ATTACH:\\s*(.+?)\\s*$/\n/** Inbound attachments land under `<cwd>/.threa-attachments/<invocationId>/<attachmentId>/`, fresh per turn. */\nexport const ATTACHMENT_DIR = \".threa-attachments\"\n\nexport interface SelectedAttachment {\n attachment: AttachmentSummary\n messageId: string\n /** True when the attachment is on the message that triggered this turn. */\n isSource: boolean\n}\n\nexport interface DownloadedAttachment extends SelectedAttachment {\n localPath: string\n}\n\n// --- Pure helpers ---------------------------------------------------------\n\n/** Strip `THREA_ATTACH:` directive lines out of a reply, returning the remaining text and the paths. */\nexport function extractAttachmentDirectives(markdown: string): { markdown: string; paths: string[] } {\n const paths: string[] = []\n const lines = markdown.split(\"\\n\").filter((line) => {\n const match = line.match(ATTACH_DIRECTIVE_RE)\n if (!match) return true\n paths.push(match[1]!)\n return false\n })\n return { markdown: lines.join(\"\\n\").trim(), paths }\n}\n\nexport function guessMimeType(path: string): string {\n const lower = path.toLowerCase()\n if (lower.endsWith(\".png\")) return \"image/png\"\n if (lower.endsWith(\".jpg\") || lower.endsWith(\".jpeg\")) return \"image/jpeg\"\n if (lower.endsWith(\".gif\")) return \"image/gif\"\n if (lower.endsWith(\".webp\")) return \"image/webp\"\n if (lower.endsWith(\".svg\")) return \"image/svg+xml\"\n if (lower.endsWith(\".html\")) return \"text/html\"\n if (lower.endsWith(\".md\")) return \"text/markdown\"\n if (lower.endsWith(\".txt\")) return \"text/plain\"\n if (lower.endsWith(\".csv\")) return \"text/csv\"\n if (lower.endsWith(\".json\")) return \"application/json\"\n if (lower.endsWith(\".pdf\")) return \"application/pdf\"\n return \"application/octet-stream\"\n}\n\n/**\n * Pick the attachments worth downloading: those on the source message (the\n * request) plus any on the history messages Claude is being shown. De-duplicated\n * by attachment id, source first so the manifest leads with the current request.\n */\nexport function selectInboundAttachments(\n messages: StreamMessageSummary[],\n sourceMessageId: string,\n contextMessageIds: readonly string[]\n): SelectedAttachment[] {\n const inScope = new Set<string>([sourceMessageId, ...contextMessageIds])\n // Process the source message first so it leads the manifest and so a file\n // shared with an older context message keeps its source marker regardless of\n // the order the stream listing returned.\n const ordered = [...messages].sort((a, b) => Number(b.id === sourceMessageId) - Number(a.id === sourceMessageId))\n const seen = new Set<string>()\n const selected: SelectedAttachment[] = []\n for (const message of ordered) {\n if (!inScope.has(message.id)) continue\n for (const attachment of message.attachments ?? []) {\n if (seen.has(attachment.id)) continue\n seen.add(attachment.id)\n selected.push({ attachment, messageId: message.id, isSource: message.id === sourceMessageId })\n }\n }\n return selected\n}\n\n/** The block appended to the channel event so Claude knows where the files landed. */\nexport function formatInboundAttachmentManifest(downloaded: DownloadedAttachment[]): string {\n if (downloaded.length === 0) return \"\"\n const lines = downloaded.map((entry) => {\n const marker = entry.isSource ? \" [attached to the message you just received]\" : \"\"\n const { filename, mimeType, sizeBytes } = entry.attachment\n return `- ${filename} (${mimeType}, ${sizeBytes} bytes) → ${entry.localPath}${marker}`\n })\n return [\"Attachments saved into this session's working directory — read them from these paths:\", ...lines].join(\"\\n\")\n}\n\n/** The attachment links / failure notes appended to an outbound reply. */\nexport function buildReplyAttachmentSection(uploaded: AttachmentSummary[], failed: string[]): string {\n const parts: string[] = []\n if (uploaded.length > 0) {\n parts.push([\"Attachments:\", ...uploaded.map((a) => `- [${a.filename}](attachment:${a.id})`)].join(\"\\n\"))\n }\n if (failed.length > 0) {\n parts.push([\"Attachment upload failed:\", ...failed.map((f) => `- ${f}`)].join(\"\\n\"))\n }\n return parts.join(\"\\n\\n\")\n}\n\n// --- IO orchestration -----------------------------------------------------\n\nconst DOWNLOAD_TIMEOUT_MS = 60_000\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) return\n throw signal.reason instanceof Error ? signal.reason : new Error(\"attachment hydration aborted\")\n}\n\nexport async function fetchAttachmentBytes(\n url: string,\n timeoutMs = DOWNLOAD_TIMEOUT_MS,\n signal?: AbortSignal\n): Promise<Uint8Array> {\n // The url is a short-lived pre-signed storage URL, so it carries its own auth\n // — a plain fetch, not the bearer-authenticated client request. The timeout\n // signal spans headers AND arrayBuffer(): a stalled download body must reject,\n // not hang the channel (same pathogen as the client request bound).\n const timeout = AbortSignal.timeout(timeoutMs)\n const response = await fetch(url, { signal: signal ? AbortSignal.any([timeout, signal]) : timeout })\n if (!response.ok) throw new Error(`download failed with ${response.status}`)\n const bytes = new Uint8Array(await response.arrayBuffer())\n throwIfAborted(signal)\n return bytes\n}\n\n/**\n * Discover the attachments on the messages Claude is being shown, download them\n * into `<cwd>/.threa-attachments/<invocationId>/<attachmentId>/`, and return\n * what landed. A per-attachment failure is logged and skipped rather than\n * aborting the turn.\n */\nexport async function downloadInboundAttachments(\n client: Pick<ThreaClient, \"listStreamMessages\" | \"getAttachmentDownloadUrl\">,\n params: {\n streamId: string\n sourceMessageId: string\n contextMessageIds: readonly string[]\n invocationId: string\n cwd: string\n scanLimit: number\n log: (message: string) => void\n /** Live canonical rebuilds fail instead of acknowledging a partial file set. */\n strict?: boolean\n signal?: AbortSignal\n }\n): Promise<DownloadedAttachment[]> {\n throwIfAborted(params.signal)\n const messages = await client.listStreamMessages(params.streamId, { limit: params.scanLimit })\n throwIfAborted(params.signal)\n const selected = selectInboundAttachments(messages, params.sourceMessageId, params.contextMessageIds)\n if (selected.length === 0) return []\n const dir = join(params.cwd, ATTACHMENT_DIR, params.invocationId)\n const downloaded: DownloadedAttachment[] = []\n for (const item of selected) {\n try {\n throwIfAborted(params.signal)\n const url = await client.getAttachmentDownloadUrl(item.attachment.id)\n const bytes = await fetchAttachmentBytes(url, DOWNLOAD_TIMEOUT_MS, params.signal)\n const localPath = attachmentLocalPath(dir, item.attachment.id, item.attachment.filename)\n mkdirSync(dirname(localPath), { recursive: true })\n writeFileSync(localPath, bytes)\n throwIfAborted(params.signal)\n downloaded.push({ ...item, localPath })\n } catch (error) {\n if (params.strict || params.signal?.aborted) throw error\n params.log(`attachment ${item.attachment.id} download failed: ${String(error)}`)\n }\n }\n return downloaded\n}\n\nasync function uploadFile(\n client: Pick<ThreaClient, \"uploadAttachment\">,\n path: string,\n cwd: string\n): Promise<AttachmentSummary> {\n const absolute = resolve(cwd, path)\n const stats = statSync(absolute)\n if (!stats.isFile()) throw new Error(`${path} is not a file`)\n const bytes = readFileSync(absolute)\n const form = new FormData()\n form.append(\"file\", new Blob([bytes], { type: guessMimeType(absolute) }), basename(absolute))\n return client.uploadAttachment(form)\n}\n\n/**\n * Resolve `THREA_ATTACH:` directives in a reply: upload each referenced file and\n * rewrite the reply to carry `attachment:<id>` links the backend associates with\n * the posted message. Upload failures surface as a note rather than throwing.\n */\nexport async function uploadReplyAttachments(\n client: Pick<ThreaClient, \"uploadAttachment\">,\n markdown: string,\n cwd: string\n): Promise<{ markdown: string; uploaded: AttachmentSummary[]; failed: string[] }> {\n const { markdown: stripped, paths } = extractAttachmentDirectives(markdown)\n const uploaded: AttachmentSummary[] = []\n const failed: string[] = []\n for (const path of paths) {\n try {\n uploaded.push(await uploadFile(client, path, cwd))\n } catch (error) {\n failed.push(`${path}: ${error instanceof Error ? error.message : String(error)}`)\n }\n }\n const section = buildReplyAttachmentSection(uploaded, failed)\n const finalMarkdown = [stripped, section].filter(Boolean).join(\"\\n\\n\")\n return { markdown: finalMarkdown, uploaded, failed }\n}\n\n// --- Sealed (E2E) attachments ----------------------------------------------\n\n/** Placeholder name/mime for the opaque ciphertext upload — the real values ride only in the sealed ref. */\nconst SEALED_UPLOAD_FILENAME = \"encrypted\"\nconst SEALED_UPLOAD_MIME = \"application/octet-stream\"\n/**\n * Server cap on `attachmentIds` per sealed message (`sealedAttachmentIdsSchema`\n * caps at 16). Clamp before uploading: sending more ids would 400 the whole\n * completion, and the retry loop would re-send the same over-limit body forever.\n */\nexport const MAX_SEALED_ATTACHMENTS_PER_MESSAGE = 16\n\nasync function uploadSealedFile(\n client: Pick<ThreaClient, \"uploadAttachment\">,\n path: string,\n cwd: string\n): Promise<AttachmentRef> {\n const absolute = resolve(cwd, path)\n const stats = statSync(absolute)\n if (!stats.isFile()) throw new Error(`${path} is not a file`)\n const bytes = readFileSync(absolute)\n const encrypted = await encryptAttachmentBytes(bytes)\n const form = new FormData()\n form.append(\"e2e\", \"true\")\n form.append(\"file\", new Blob([encrypted.ciphertext], { type: SEALED_UPLOAD_MIME }), SEALED_UPLOAD_FILENAME)\n const summary = await client.uploadAttachment(form)\n return {\n attachmentId: summary.id,\n key: encrypted.key,\n iv: encrypted.iv,\n filename: basename(absolute),\n mimeType: guessMimeType(absolute),\n sizeBytes: bytes.length,\n }\n}\n\n/**\n * Resolve `THREA_ATTACH:` directives in SEALED output: encrypt each file under a\n * fresh single-use key, upload only the ciphertext (`e2e=true`, placeholder\n * name/mime), and return the refs to seal into the message payload plus the ids\n * the wire body binds to the message row. No `attachment:<id>` links are added —\n * an E2E viewer renders attachments from the sealed refs, not the markdown.\n * Upload failures surface as a note (itself sealed) rather than throwing.\n */\nexport async function uploadSealedReplyAttachments(\n client: Pick<ThreaClient, \"uploadAttachment\">,\n markdown: string,\n cwd: string\n): Promise<{ markdown: string; refs: AttachmentRef[]; attachmentIds: string[] }> {\n const { markdown: stripped, paths } = extractAttachmentDirectives(markdown)\n const refs: AttachmentRef[] = []\n const failed: string[] = []\n for (const path of paths.slice(MAX_SEALED_ATTACHMENTS_PER_MESSAGE)) {\n failed.push(`${path}: over the ${MAX_SEALED_ATTACHMENTS_PER_MESSAGE}-attachment limit for one message`)\n }\n for (const path of paths.slice(0, MAX_SEALED_ATTACHMENTS_PER_MESSAGE)) {\n try {\n refs.push(await uploadSealedFile(client, path, cwd))\n } catch (error) {\n failed.push(`${path}: ${error instanceof Error ? error.message : String(error)}`)\n }\n }\n const failureNote = failed.length > 0 ? [\"Attachment upload failed:\", ...failed.map((f) => `- ${f}`)].join(\"\\n\") : \"\"\n return {\n markdown: [stripped, failureNote].filter(Boolean).join(\"\\n\\n\"),\n refs,\n attachmentIds: refs.map((ref) => ref.attachmentId),\n }\n}\n\n/** One inbound sealed attachment to fetch: the ref plus whether it rode the trigger message. */\nexport interface SealedInboundRef {\n ref: AttachmentRef\n isSource: boolean\n}\n\n/**\n * Dedupe the refs opened from a sealed claim (trigger payload + history\n * payloads) by attachment id, trigger first — the sealed sibling of\n * `selectInboundAttachments`, working from decrypted refs instead of the\n * plaintext message list (which only holds placeholders on an E2E stream).\n */\nexport function selectSealedInboundRefs(\n promptRefs: readonly AttachmentRef[],\n historyRefs: readonly AttachmentRef[]\n): SealedInboundRef[] {\n const seen = new Set<string>()\n const selected: SealedInboundRef[] = []\n for (const { refs, isSource } of [\n { refs: promptRefs, isSource: true },\n { refs: historyRefs, isSource: false },\n ]) {\n for (const ref of refs) {\n if (seen.has(ref.attachmentId)) continue\n seen.add(ref.attachmentId)\n selected.push({ ref, isSource })\n }\n }\n return selected\n}\n\n/**\n * Download + decrypt a sealed turn's inbound attachments into\n * `<cwd>/.threa-attachments/<invocationId>/<attachmentId>/`. The S3 object is opaque\n * ciphertext; the ref's key/iv (opened from the sealed message payload) decrypt\n * it locally, and the file lands under its REAL name — decrypted bytes never\n * transit the server. A per-attachment failure is logged and skipped.\n */\nexport async function downloadSealedInboundAttachments(\n client: Pick<ThreaClient, \"getAttachmentDownloadUrl\">,\n params: {\n refs: SealedInboundRef[]\n invocationId: string\n cwd: string\n log: (message: string) => void\n /** Live canonical rebuilds fail instead of acknowledging a partial file set. */\n strict?: boolean\n signal?: AbortSignal\n }\n): Promise<DownloadedAttachment[]> {\n throwIfAborted(params.signal)\n if (params.refs.length === 0) return []\n const dir = join(params.cwd, ATTACHMENT_DIR, params.invocationId)\n const downloaded: DownloadedAttachment[] = []\n for (const { ref, isSource } of params.refs) {\n try {\n throwIfAborted(params.signal)\n const url = await client.getAttachmentDownloadUrl(ref.attachmentId)\n const ciphertext = await fetchAttachmentBytes(url, DOWNLOAD_TIMEOUT_MS, params.signal)\n const plaintext = await decryptAttachmentBytes({ ciphertext, key: ref.key, iv: ref.iv })\n throwIfAborted(params.signal)\n const localPath = attachmentLocalPath(dir, ref.attachmentId, ref.filename)\n mkdirSync(dirname(localPath), { recursive: true })\n writeFileSync(localPath, plaintext)\n downloaded.push({\n attachment: { id: ref.attachmentId, filename: ref.filename, mimeType: ref.mimeType, sizeBytes: ref.sizeBytes },\n messageId: \"\",\n isSource,\n localPath,\n })\n } catch (error) {\n if (params.strict || params.signal?.aborted) throw error\n params.log(`sealed attachment ${ref.attachmentId} download failed: ${String(error)}`)\n }\n }\n return downloaded\n}\n",
|
|
7
|
+
"import { createHash } from \"node:crypto\"\nimport {\n E2E_KEY_SCOPES,\n E2E_KEY_STORE_KINDS,\n type E2eKeyScope,\n type E2eKeyStoreKind,\n} from \"@threahq/bot-runtime-client\"\n\nexport const TRACE_MODES = [\"headline\", \"commands\"] as const\nconst TRACE_MODE_SET: ReadonlySet<string> = new Set(TRACE_MODES)\nexport type TraceMode = (typeof TRACE_MODES)[number]\n\nexport interface RemoteSessionConfig {\n baseUrl: string\n workspaceId: string\n apiKey: string\n /** Scratchpad display name: the configured prefix with the project directory appended. */\n displayName: string\n /** Sent as `labelName` on session create; the backend applies it only to a newly created scratchpad. Unset = no label. */\n defaultLabel?: string\n /**\n * Recorded on the session link as the runtime's working directory, for a\n * supervisor (harnessd) that reaps worktrees. Unset = not sent; a public\n * connector has no reason to upload a local path.\n */\n localCwd?: string\n /** Cold-start behavior when this identity still points at an archived scratchpad. Default: replace. */\n coldStartIfArchived?: \"wait\" | \"replace\"\n /** Cold-start behavior when this identity has no session link. Default: create. */\n coldStartIfMissing?: \"create\" | \"error\"\n /** When set by a supervisor, refuse a session link to any other scratchpad root. */\n expectedRootStreamId?: string\n /** `^[A-Za-z0-9_-]+$`, ≤64 — must satisfy the `/bot` hello schema. */\n instanceId: string\n runtimeSessionId: string\n /** Relay the runtime's tool-approval prompts into the scratchpad for remote approval. */\n permissionRelay: boolean\n /** Backstop claim-poll cadence; the `/bot` socket pushes work faster than this. */\n pollMs: number\n /**\n * Safety net for a wedged turn: an in-flight invocation is force-closed after\n * this much *inactivity*. Every interim send (and tool-approval activity)\n * resets it, so an actively-working turn never trips it — only one that went\n * silent without a reply. Must exceed the longest single tool call the agent\n * makes, since it can't heartbeat while blocked on a tool.\n */\n idleTimeoutMs: number\n /**\n * The single-key BIK file this install used before keyrings. Still read: when\n * the configured key scope holds nothing yet, the old key is adopted under it\n * so the owner's existing wraps keep addressing a key this runtime holds.\n * Unset = a per-runtime-kind default under `~/.threa/`.\n */\n bikPath?: string\n /**\n * How widely this install's E2E identity key is shared. `host` (default) is\n * one key for every runtime on this machine, so a person running several\n * agents invites one recipient rather than one per agent. `identity` is one\n * key per bot (per API key) across machines, `instance` one per install.\n * Changing it points the runtime at a different key, so the owner must\n * re-invite it to streams wrapped under the old one.\n */\n keyScope: E2eKeyScope\n /**\n * Where E2E keys are kept. Unset lets a working OS keychain win and otherwise\n * asks rather than choosing disk on the operator's behalf; `file` keeps them\n * at mode 0600 under `keyDir`; `keychain` requires one and fails loudly\n * without it.\n */\n keyStore?: E2eKeyStoreKind\n /** Directory for the file key store. Default `~/.threa/e2e-keys`. */\n keyDir?: string\n /**\n * Emit FULL trace detail (real commands, file contents, outputs) on sealed\n * (E2EE) turns — safe because sealed step content is ciphertext the server\n * can't read. Default on; set false to use `traceMode` on sealed turns too.\n * Has no effect on plaintext turns, which never emit full detail.\n */\n sealedFullTrace: boolean\n /**\n * Base trace detail. `headline` keeps shell commands hidden; `commands`\n * includes only the Bash command while file bodies, patches, and every tool\n * result stay hidden. Used for plaintext turns and sealed turns when\n * `sealedFullTrace` is false. Defaults to `headline`.\n */\n traceMode: TraceMode\n /**\n * Create this connector's linked scratchpad end-to-end encrypted: the harness\n * mints the stream key and wraps it to the bot owner's UIK + its own BIK, so\n * the server only ever stores ciphertext. Requires the owner to have set up\n * encryption in Threa (their UIK is fetched at session create). Off by\n * default — an encrypted scratchpad opts out of GAM memory extraction.\n */\n e2e?: boolean\n /**\n * Run the workspace delegation queue on this connector (claim → execute →\n * complete, see delegation-runner.ts). Off by default: delegations are\n * workspace-wide and claimed first-come-first-served, so with several\n * connectors running only the one(s) the user explicitly opted in should\n * race for them.\n */\n delegations?: boolean\n}\n\n/**\n * Who this connector is: the stable-id prefixes that key its sessions and the\n * default display-name prefix. Every connector picks its own (Claude Code uses\n * cc/ccs), so two runtimes in the same directory never collide.\n */\nexport interface ConnectorIdentity {\n /** Prefix for the derived instance id (e.g. \"cc\"). */\n idPrefix: string\n /** Prefix for the derived runtime-session id (e.g. \"ccs\"). */\n sessionIdPrefix: string\n /** Human prefix for the scratchpad display name (e.g. \"Claude Code\"). */\n displayNamePrefix: string\n /** Where the connector reads file config from — used only in the missing-config error message. */\n configPathHint?: string\n}\n\nconst UNSAFE_ID_CHARS = /[^A-Za-z0-9_-]+/g\n\nexport function sanitizeId(raw: string): string {\n return raw.replace(UNSAFE_ID_CHARS, \"-\").replace(/^-+|-+$/g, \"\")\n}\n\n/**\n * Deterministic id from a seed (host + cwd), so the same project directory\n * always maps back to the same Threa scratchpad across runtime restarts —\n * no on-disk session state to keep in sync.\n */\nexport function deriveStableId(prefix: string, seed: string): string {\n const hash = createHash(\"sha256\").update(seed).digest(\"hex\").slice(0, 16)\n return `${prefix}-${hash}`.slice(0, 64)\n}\n\nexport function defaultDisplayName(cwd: string, prefix: string, override?: string): string {\n const effective = override?.trim() ? override.trim() : prefix\n const dir = cwd.split(\"/\").filter(Boolean).pop() ?? \"session\"\n const name = `${effective} - ${dir}`\n // upsertPresenceSchema caps displayName at 100 chars.\n return name.length > 100 ? name.slice(0, 100) : name\n}\n\nexport interface RawConfig {\n baseUrl?: unknown\n workspaceId?: unknown\n apiKey?: unknown\n displayName?: unknown\n defaultLabel?: unknown\n coldStartIfArchived?: unknown\n coldStartIfMissing?: unknown\n expectedRootStreamId?: unknown\n permissionRelay?: unknown\n pollMs?: unknown\n idleTimeoutMs?: unknown\n instanceId?: unknown\n runtimeSessionId?: unknown\n bikPath?: unknown\n keyScope?: unknown\n keyStore?: unknown\n keyDir?: unknown\n e2e?: unknown\n sealedFullTrace?: unknown\n traceMode?: unknown\n delegations?: unknown\n}\n\nexport function parseConfigFile(text: string): RawConfig {\n const parsed = JSON.parse(text) as unknown\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(\"config file must be a JSON object\")\n }\n return parsed as RawConfig\n}\n\nfunction str(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim().length > 0 ? value.trim() : undefined\n}\n\nfunction parseColdStartIfArchived(value: unknown): \"wait\" | \"replace\" {\n return str(value)?.toLowerCase() === \"wait\" ? \"wait\" : \"replace\"\n}\n\nfunction parseColdStartIfMissing(value: unknown): \"create\" | \"error\" {\n return str(value)?.toLowerCase() === \"error\" ? \"error\" : \"create\"\n}\n\nfunction parseBool(value: unknown, fallback: boolean): boolean {\n if (typeof value === \"boolean\") return value\n const s = str(value)?.toLowerCase()\n if (s === undefined) return fallback\n if ([\"0\", \"false\", \"no\", \"off\"].includes(s)) return false\n if ([\"1\", \"true\", \"yes\", \"on\"].includes(s)) return true\n return fallback\n}\n\nfunction parseNum(value: unknown, fallback: number, min: number): number {\n const n = typeof value === \"number\" ? value : Number(str(value))\n return Number.isFinite(n) ? Math.max(min, Math.floor(n)) : fallback\n}\n\nfunction parseTraceMode(value: unknown): TraceMode | undefined {\n const mode = str(value)?.toLowerCase()\n return mode && TRACE_MODE_SET.has(mode) ? (mode as TraceMode) : undefined\n}\n\nconst KEY_SCOPE_SET: ReadonlySet<string> = new Set(E2E_KEY_SCOPES)\nconst KEY_STORE_SET: ReadonlySet<string> = new Set(E2E_KEY_STORE_KINDS)\n\nexport interface LoadConfigInput {\n env: Record<string, string | undefined>\n cwd: string\n hostname: string\n file?: RawConfig\n}\n\nexport type LoadConfigResult = { config: RemoteSessionConfig } | { error: string }\n\n/**\n * Pure config resolver: file values are the base, environment variables win.\n * Kept side-effect-free so it can be unit-tested without touching disk/env.\n */\nexport function loadConfig(input: LoadConfigInput, identity: ConnectorIdentity): LoadConfigResult {\n const { env, cwd, hostname, file = {} } = input\n\n const baseUrl = str(env.THREA_BASE_URL) ?? str(file.baseUrl) ?? \"https://app.threa.io\"\n const workspaceId = str(env.THREA_WORKSPACE_ID) ?? str(file.workspaceId)\n const apiKey = str(env.THREA_API_KEY) ?? str(file.apiKey)\n\n const missing = [!workspaceId && \"THREA_WORKSPACE_ID\", !apiKey && \"THREA_API_KEY\"].filter(Boolean)\n if (missing.length > 0) {\n const hint = identity.configPathHint ? ` or ${identity.configPathHint}` : \"\"\n return { error: `Missing required config: ${missing.join(\", \")}. Set env vars${hint}.` }\n }\n\n const displayName = defaultDisplayName(\n cwd,\n identity.displayNamePrefix,\n str(env.THREA_DISPLAY_NAME) ?? str(file.displayName)\n )\n const defaultLabel = str(env.THREA_DEFAULT_LABEL) ?? str(file.defaultLabel)\n const configuredTraceMode = str(env.THREA_TRACE_MODE) ?? file.traceMode\n const traceMode = configuredTraceMode === undefined ? \"headline\" : parseTraceMode(configuredTraceMode)\n if (!traceMode) {\n return { error: \"Invalid traceMode: expected headline or commands.\" }\n }\n const seed = `${hostname}:${cwd}`\n const instanceId = sanitizeId(\n str(env.THREA_INSTANCE_ID) ?? str(file.instanceId) ?? deriveStableId(identity.idPrefix, seed)\n ).slice(0, 64)\n const runtimeSessionId = sanitizeId(\n str(env.THREA_RUNTIME_SESSION_ID) ?? str(file.runtimeSessionId) ?? deriveStableId(identity.sessionIdPrefix, seed)\n ).slice(0, 64)\n\n if (!instanceId || !runtimeSessionId) {\n return { error: \"Could not derive a valid instanceId/runtimeSessionId (empty after sanitization).\" }\n }\n\n const configuredKeyScope = str(env.THREA_E2E_KEY_SCOPE) ?? str(file.keyScope)\n if (configuredKeyScope !== undefined && !KEY_SCOPE_SET.has(configuredKeyScope.toLowerCase())) {\n return { error: `Invalid keyScope: expected one of ${E2E_KEY_SCOPES.join(\", \")}.` }\n }\n const keyScope = (configuredKeyScope?.toLowerCase() as E2eKeyScope | undefined) ?? \"host\"\n\n const configuredKeyStore = str(env.THREA_E2E_KEY_STORE) ?? str(file.keyStore)\n if (configuredKeyStore !== undefined && !KEY_STORE_SET.has(configuredKeyStore.toLowerCase())) {\n return { error: `Invalid keyStore: expected one of ${E2E_KEY_STORE_KINDS.join(\", \")}.` }\n }\n const keyStore = configuredKeyStore?.toLowerCase() as E2eKeyStoreKind | undefined\n\n return {\n config: {\n baseUrl: baseUrl.replace(/\\/$/, \"\"),\n workspaceId: workspaceId!,\n apiKey: apiKey!,\n displayName,\n defaultLabel,\n coldStartIfArchived: parseColdStartIfArchived(str(env.THREA_COLD_START_IF_ARCHIVED) ?? file.coldStartIfArchived),\n coldStartIfMissing: parseColdStartIfMissing(str(env.THREA_COLD_START_IF_MISSING) ?? file.coldStartIfMissing),\n expectedRootStreamId: str(env.THREA_EXPECTED_ROOT_STREAM_ID) ?? str(file.expectedRootStreamId),\n instanceId,\n runtimeSessionId,\n permissionRelay: parseBool(env.THREA_PERMISSION_RELAY ?? file.permissionRelay, true),\n pollMs: parseNum(env.THREA_POLL_MS ?? file.pollMs, 3000, 1000),\n idleTimeoutMs: parseNum(env.THREA_IDLE_TIMEOUT_MS ?? file.idleTimeoutMs, 3_600_000, 60_000),\n bikPath: str(env.THREA_BIK_PATH) ?? str(file.bikPath),\n keyScope,\n keyStore,\n keyDir: str(env.THREA_E2E_KEY_DIR) ?? str(file.keyDir),\n e2e: parseBool(env.THREA_E2E ?? file.e2e, false),\n sealedFullTrace: parseBool(env.THREA_SEALED_FULL_TRACE ?? file.sealedFullTrace, true),\n traceMode,\n delegations: parseBool(env.THREA_DELEGATIONS ?? file.delegations, false),\n },\n }\n}\n",
|
|
8
|
+
"import {\n THREA_CALLBACK_TOKEN_HEADER,\n type CreateDecisionRequestBody,\n type DecisionRequest,\n type AttachmentRef,\n type ProvisionedWrap,\n type SealedReplyBody,\n type SealingState,\n} from \"@threahq/bot-runtime-client\"\n\nconst FETCH_TIMEOUT_MS = 30_000\n\n/**\n * A sealed message body on the wire: the sealed ciphertext plus the E2E\n * attachment row ids the server binds to the message (the per-file keys ride\n * only inside the sealed payload's `attachmentRefs`).\n */\nexport type SealedWireReply = SealedReplyBody & { attachmentIds?: string[] }\n\nexport interface RuntimeSessionLink {\n linkId: string\n rootStreamId: string\n activeStreamId: string\n runtimeSessionId: string\n streamUrlPath: string\n /** The linked scratchpad's encryption state (create echoes the request; resume reports the actual state). */\n e2eEnabled?: boolean\n}\n\nexport interface ExternalHistoryMessage {\n messageId: string\n role: \"user\" | \"assistant\"\n authorId: string\n authorType: string\n authorDisplayName?: string\n contentMarkdown: string\n createdAt: string\n}\n\nexport interface AttachmentSummary {\n id: string\n filename: string\n mimeType: string\n sizeBytes: number\n}\n\n/** The slice of `GET /streams/:id/messages` we consume — id plus any attachments. */\nexport interface StreamMessageSummary {\n id: string\n attachments?: AttachmentSummary[]\n}\n\nexport interface ClaimedInvocation {\n id: string\n workspaceId: string\n rootStreamId: string\n activeStreamId: string\n sourceMessageId: string\n sourceRevision: number\n responseStreamId: string\n actor: { type: \"bot\"; id: string; slug: string }\n trigger: string\n requiredCapability: string\n promptMarkdown: string\n authorUserId: string\n mentionedActorSlugs: string[]\n claimToken: string\n claimExpiresAt: string\n runtimeSessionId: string | null\n metadata: Record<string, unknown>\n context?: { kind: \"inline\"; messages: ExternalHistoryMessage[] }\n /** Present on a sealed (E2E) claim as delivered by the server; consumed and cleared by hydration. */\n sealedContext?: unknown\n /** Present on a session-control claim on an E2E stream: SSK wraps to seal the command ack. */\n sealedAck?: unknown\n /** Derived from `sealedContext` at claim time; carries the stream key + binding for sealing replies/steps. */\n sealing?: SealingState\n /** Attachment refs opened from the sealed trigger/history payloads at claim time — download + decrypt is the turn's job. */\n sealedAttachments?: { prompt: AttachmentRef[]; history: AttachmentRef[] }\n}\n\nexport class ThreaApiError extends Error {\n constructor(\n message: string,\n readonly status: number,\n /** The server's structured error `code` (e.g. `E2E_STREAM_PLAINTEXT_UNSUPPORTED`), when the body was JSON. */\n readonly code?: string,\n readonly retryAfterMs?: number\n ) {\n super(message)\n this.name = \"ThreaApiError\"\n }\n}\n\nfunction retryDelayMs(headers: Headers): number | undefined {\n const retryAfter = headers.get(\"Retry-After\")?.trim()\n if (retryAfter) {\n const delay = /^\\d+$/.test(retryAfter) ? Number(retryAfter) * 1000 : Date.parse(retryAfter) - Date.now()\n if (Number.isFinite(delay)) return Math.max(0, delay)\n }\n const reset = headers.get(\"RateLimit-Reset\")?.trim()\n if (reset && /^\\d+$/.test(reset)) {\n const delay = Number(reset) * 1000\n if (Number.isFinite(delay)) return delay\n }\n return undefined\n}\n\nexport interface ThreaClientOptions {\n baseUrl: string\n workspaceId: string\n apiKey: string\n fetchTimeoutMs?: number\n}\n\nexport class ThreaClient {\n constructor(private readonly opts: ThreaClientOptions) {}\n\n private get base(): string {\n return this.opts.baseUrl.replace(/\\/$/, \"\")\n }\n\n private async request<T>(path: string, init?: RequestInit): Promise<T> {\n // One abort window over headers AND body. Clearing the timer once headers\n // arrived left every `response.text()`/`response.json()` below unbounded —\n // a stalled body hung the channel's request forever, the MCP server went\n // unresponsive, and Claude Code SIGINT-restarted it, failing the in-flight\n // invocation as \"channel shut down\" (observed live 2026-08-10; same\n // pathogen as pi-remote's #1841).\n const controller = new AbortController()\n const abortFromCaller = () => controller.abort(init?.signal?.reason)\n if (init?.signal?.aborted) abortFromCaller()\n else init?.signal?.addEventListener(\"abort\", abortFromCaller, { once: true })\n const timeout = setTimeout(() => controller.abort(), this.opts.fetchTimeoutMs ?? FETCH_TIMEOUT_MS)\n try {\n return await this.requestWithin<T>(path, init, controller.signal)\n } finally {\n clearTimeout(timeout)\n init?.signal?.removeEventListener(\"abort\", abortFromCaller)\n }\n }\n\n private async requestWithin<T>(path: string, init: RequestInit | undefined, signal: AbortSignal): Promise<T> {\n // A FormData body must keep its multipart boundary header, which fetch sets\n // only when Content-Type is left unset — so never force JSON on uploads.\n const isFormData = typeof FormData !== \"undefined\" && init?.body instanceof FormData\n const response = await fetch(`${this.base}${path}`, {\n ...init,\n signal,\n headers: {\n Authorization: `Bearer ${this.opts.apiKey}`,\n ...(isFormData ? {} : { \"Content-Type\": \"application/json\" }),\n ...init?.headers,\n },\n })\n if (!response.ok) {\n // Read the structured `code` so callers can branch on the specific error\n // (e.g. an E2E-plaintext rejection vs a capability/validation 400) instead\n // of swallowing every same-status error alike. Only parse a JSON body and\n // cap it — a proxy/server 5xx can return a large HTML page, which we must\n // not pull into memory.\n let code: string | undefined\n let serverMessage: string | undefined\n if (response.headers.get(\"content-type\")?.includes(\"application/json\")) {\n try {\n const body = (await response.text()).slice(0, 2000)\n const parsed = JSON.parse(body) as { code?: unknown; error?: unknown }\n if (typeof parsed.code === \"string\") code = parsed.code\n if (typeof parsed.error === \"string\") serverMessage = parsed.error\n } catch {\n code = undefined\n }\n }\n // Carry the structured code + server message in the text too — most call\n // sites log `error.message` only, and \"Threa API 409: Conflict\" gives the\n // user nothing to act on.\n const detail = [code, serverMessage].filter(Boolean).join(\" — \")\n throw new ThreaApiError(\n `Threa API ${response.status}${detail ? ` (${detail})` : `: ${response.statusText}`}`,\n response.status,\n code,\n retryDelayMs(response.headers)\n )\n }\n if (response.status === 204) return undefined as T\n return (await response.json()) as T\n }\n\n private workspacePath(suffix: string): string {\n return `/api/v1/workspaces/${this.opts.workspaceId}${suffix}`\n }\n\n /** Returns the authenticated principal; only `.kind` (`\"bot\"` vs `\"user\"`) is consumed today. */\n async getMe(): Promise<{ kind: string }> {\n const body = await this.request<{ data: { kind: string } }>(this.workspacePath(\"/me\"))\n return body.data\n }\n\n async createSession(body: Record<string, unknown>): Promise<RuntimeSessionLink> {\n const result = await this.request<{ data: RuntimeSessionLink }>(this.workspacePath(\"/bot-runtime/sessions\"), {\n method: \"POST\",\n body: JSON.stringify(body),\n })\n return result.data\n }\n\n async claim(body: Record<string, unknown>): Promise<ClaimedInvocation | null> {\n const result = await this.request<{ data: ClaimedInvocation | null }>(\n this.workspacePath(\"/bot-invocations/claim\"),\n { method: \"POST\", body: JSON.stringify(body) }\n )\n return result.data\n }\n\n async complete(invocationId: string, body: Record<string, unknown>, signal?: AbortSignal): Promise<void> {\n await this.request(this.workspacePath(`/bot-invocations/${invocationId}/complete`), {\n method: \"POST\",\n body: JSON.stringify(body),\n signal,\n })\n }\n\n async fail(invocationId: string, body: Record<string, unknown>): Promise<void> {\n await this.request(this.workspacePath(`/bot-invocations/${invocationId}/fail`), {\n method: \"POST\",\n body: JSON.stringify(body),\n })\n }\n\n async sendMessage(streamId: string, body: Record<string, unknown>): Promise<{ id: string }> {\n const result = await this.request<{ data?: { id?: string } }>(this.workspacePath(`/streams/${streamId}/messages`), {\n method: \"POST\",\n body: JSON.stringify(body),\n })\n const id = result?.data?.id\n if (typeof id !== \"string\" || !id) throw new Error(`Threa API returned no message id for stream ${streamId}`)\n return { id }\n }\n\n async sendInvocationMessage(invocationId: string, body: Record<string, unknown>): Promise<void> {\n await this.request(this.workspacePath(`/bot-invocations/${invocationId}/messages`), {\n method: \"POST\",\n body: JSON.stringify(body),\n })\n }\n\n async sendSealedMessage(invocationId: string, callbackToken: string, body: SealedWireReply): Promise<void> {\n await this.request(this.workspacePath(`/bot-invocations/${invocationId}/sealed-messages`), {\n method: \"POST\",\n headers: { [THREA_CALLBACK_TOKEN_HEADER]: callbackToken },\n body: JSON.stringify(body),\n })\n }\n\n /** The bot owner's active encryption key (public half). 404 = the owner has not set up encryption. */\n async getOwnerE2eKey(): Promise<{ keyId: string; publicKey: string }> {\n const body = await this.request<{ data: { keyId: string; publicKey: string } }>(\n this.workspacePath(\"/bot-runtime/owner-e2e-key\")\n )\n return body.data\n }\n\n /** Phase two of harness-created E2E scratchpads: store the generation-0 stream-key wraps. */\n async provisionStreamKeyWraps(\n streamId: string,\n body: { keyGeneration: number; wraps: ProvisionedWrap[] }\n ): Promise<void> {\n await this.request(this.workspacePath(`/streams/${streamId}/e2e/key-wraps`), {\n method: \"POST\",\n body: JSON.stringify(body),\n })\n }\n\n /** Complete a sealed turn with its final sealed reply — or silently (`noResponse`). Callback-token auth. */\n async completeSealed(\n invocationId: string,\n callbackToken: string,\n body: ({ reply: SealedWireReply } | { noResponse: true }) & { sourceRevision: number },\n signal?: AbortSignal\n ): Promise<void> {\n await this.request(this.workspacePath(`/bot-invocations/${invocationId}/sealed-complete`), {\n method: \"POST\",\n headers: { [THREA_CALLBACK_TOKEN_HEADER]: callbackToken },\n body: JSON.stringify(body),\n signal,\n })\n }\n\n /** Open a decision card on a stream and return the created request. Bot key only. */\n async requestDecision(streamId: string, body: CreateDecisionRequestBody): Promise<DecisionRequest> {\n const result = await this.request<{ data: DecisionRequest }>(this.workspacePath(`/streams/${streamId}/decisions`), {\n method: \"POST\",\n body: JSON.stringify(body),\n })\n return result.data\n }\n\n /** Read one decision this bot opened. 404 once it is out of the caller's scope. */\n async getDecision(decisionId: string): Promise<DecisionRequest> {\n const result = await this.request<{ data: DecisionRequest }>(this.workspacePath(`/decisions/${decisionId}`))\n return result.data\n }\n\n /** Withdraw a decision this bot opened. */\n async cancelDecision(decisionId: string): Promise<DecisionRequest> {\n const result = await this.request<{ data: DecisionRequest }>(\n this.workspacePath(`/decisions/${decisionId}/cancel`),\n { method: \"POST\" }\n )\n return result.data\n }\n\n /** Recent messages for a stream, newest-window first. Used to discover inbound attachments (the claim context omits them). Requires `messages:read` + `streams:read`. */\n async listStreamMessages(streamId: string, query: { limit?: number } = {}): Promise<StreamMessageSummary[]> {\n const suffix = query.limit ? `?limit=${query.limit}` : \"\"\n const body = await this.request<{ data: StreamMessageSummary[] }>(\n this.workspacePath(`/streams/${streamId}/messages${suffix}`)\n )\n return body.data\n }\n\n /** `archivedAt` for a stream, or null while it is live. Requires `streams:read`. */\n async getStreamArchivedAt(streamId: string): Promise<string | null> {\n const body = await this.request<{ data: { archivedAt?: string | null } }>(\n this.workspacePath(`/streams/${streamId}`)\n )\n return body.data?.archivedAt ?? null\n }\n\n /** Short-lived signed download URL for an attachment. Requires `attachments:read`. */\n async getAttachmentDownloadUrl(attachmentId: string): Promise<string> {\n const body = await this.request<{ data: { url: string } }>(this.workspacePath(`/attachments/${attachmentId}/url`))\n return body.data.url\n }\n\n /** Upload a file (multipart `file` field) and return its summary. Requires `attachments:write`. */\n async uploadAttachment(form: FormData): Promise<AttachmentSummary> {\n const body = await this.request<{ data: AttachmentSummary }>(this.workspacePath(\"/attachments\"), {\n method: \"POST\",\n body: form,\n })\n return body.data\n }\n}\n",
|
|
9
|
+
"import type { SealedReplyBody } from \"@threahq/bot-runtime-client\"\nimport type { ClaimedInvocation } from \"./client\"\n\n/** Exact failed POST bytes and id, retained because an ambiguous failure may have committed. */\nexport type PreparedPost =\n | {\n kind: \"plaintext\"\n seq: number\n text: string\n retryKey?: string\n body: {\n instanceId: string\n claimToken: string\n content: string\n clientMessageId: string\n metadata: Record<string, unknown>\n }\n }\n | {\n kind: \"sealed\"\n seq: number\n text: string\n retryKey?: string\n body: SealedReplyBody\n attachmentIds: string[]\n }\n\nexport interface PostIntent {\n text: string\n retryKey?: string\n retry?: PreparedPost\n}\n\nexport type PlaintextCompletionBody = {\n instanceId: string\n claimToken: string\n sourceRevision: number\n metadata: Record<string, unknown>\n} & ({ finalMessageMarkdown: string } | { noResponse: true })\n\nexport type SealedCompletionBody = (\n | { reply: SealedReplyBody & { attachmentIds?: string[] } }\n | { noResponse: true }\n) & {\n sourceRevision: number\n}\n\nexport type PreparedCompletionWire =\n | { kind: \"plaintext\"; body: PlaintextCompletionBody }\n | { kind: \"sealed\"; callbackToken: string; body: SealedCompletionBody }\n\nexport type PreparedClose =\n | { reason: \"reply\"; sourceText: string; wire: PreparedCompletionWire }\n | { reason: \"timeout\"; wire: PreparedCompletionWire }\n\nexport type CloseRequest = { kind: \"reply\"; text: string } | { kind: \"timeout\" }\n\nexport type RouteState = \"open\" | \"closing\" | \"closed\"\n\nexport class RouteRevokedError extends Error {}\n\n/**\n * One claimed invocation's delivery route. The session's maps and queued posts\n * share this object so reserved ids survive state transitions. Route death has\n * three private signals with distinct meanings — `state` (turn protocol\n * progress), `revoked` (this session stopped speaking for the stream), and\n * `terminal` (the server refused the route for good) — mutated only through\n * the named transitions below; `generation` fences a route created before a\n * session teardown (`isFenced`).\n */\nexport class TurnRoute {\n readonly invocation: ClaimedInvocation\n /** Registration order distinguishes an older route from a newer owner of the same stream. */\n readonly order: number\n /** The session lifecycle this route belongs to; a bump fences it out for good. */\n readonly generation: number\n sentCount = 0\n /** The accepted final reply's exact text, for idempotent reply retries. */\n replyText?: string\n /** Exact close body retained after an ambiguous completion. */\n prepared?: PreparedClose\n /** The completion currently on the wire, so shutdown can settle it instead of racing it. */\n closing?: Promise<unknown>\n deadline?: ReturnType<typeof setTimeout>\n readonly pending = new Map<number, PreparedPost>()\n /** Source-backed inputs folded into this turn; they close with it and fail with it. */\n contributors: ClaimedInvocation[]\n /** Aborts the completion on the wire when any folded source changes underneath it. */\n readonly execution = new AbortController()\n /** FIFO tail: every post on this route runs behind it, in call order. */\n private tail: Promise<unknown> = Promise.resolve()\n /** Highest sequence handed out. Reserved before the write, so a failure spends it. */\n private reservedSeq = 0\n /** Bumped on every (re-)arm, so a fired timeout queued behind a post can tell it is stale. */\n private deadlineGeneration = 0\n private stateValue: RouteState = \"open\"\n private revokedFlag = false\n private terminalFlag = false\n private readonly idleTimeoutMs: number\n private readonly onIdleDeadline: (route: TurnRoute, deadlineGeneration: number) => void\n\n constructor(options: {\n invocation: ClaimedInvocation\n order: number\n generation: number\n idleTimeoutMs: number\n onIdleDeadline: (route: TurnRoute, deadlineGeneration: number) => void\n contributors?: ClaimedInvocation[]\n }) {\n this.invocation = options.invocation\n this.contributors = [...(options.contributors ?? [])]\n this.order = options.order\n this.generation = options.generation\n this.idleTimeoutMs = options.idleTimeoutMs\n this.onIdleDeadline = options.onIdleDeadline\n }\n\n get state(): RouteState {\n return this.stateValue\n }\n\n get revoked(): boolean {\n return this.revokedFlag\n }\n\n get terminal(): boolean {\n return this.terminalFlag\n }\n\n isFenced(lifecycle: number): boolean {\n return this.revokedFlag || this.generation !== lifecycle\n }\n\n /** FIFO allocation keeps concurrent posts on distinct ids and orders them against completion. */\n enqueue<T>(task: () => Promise<T>): Promise<T> {\n // `.then(task, task)` so one rejected post never wedges the queue behind it.\n const run = this.tail.then(task, task)\n this.tail = run.then(\n () => undefined,\n () => undefined\n )\n return run\n }\n\n /** Snapshot retry intent before queueing so concurrent callers cannot adopt each other's failure. */\n snapshotIntent(text: string, retryKey?: string): PostIntent {\n let retry: PreparedPost | undefined\n for (const pending of this.pending.values()) {\n if (pending.text === text && pending.retryKey === retryKey && (!retry || pending.seq < retry.seq)) {\n retry = pending\n }\n }\n return {\n text,\n ...(retryKey === undefined ? {} : { retryKey }),\n ...(retry ? { retry } : {}),\n }\n }\n\n /** An ambiguous failure reserves its id and exact bytes; changed text takes the next id. */\n claimSeq(retry: PreparedPost | undefined): number {\n return retry?.seq ?? (this.reservedSeq += 1)\n }\n\n rememberFailedPost(seq: number, prepared: PreparedPost, lifecycle: number): void {\n if (!this.isFenced(lifecycle)) this.pending.set(seq, prepared)\n }\n\n recordLandedPost(seq: number, prepared: PreparedPost): void {\n if (this.pending.get(seq) === prepared) this.pending.delete(seq)\n this.sentCount += 1\n }\n\n /** The source changed under a prepared body: never replay bytes sealed or revisioned against the old input. */\n discardPrepared(): void {\n this.pending.clear()\n this.prepared = undefined\n }\n\n /** This session stopped speaking for the route's stream; pending retries and the deadline die with it. */\n revoke(): void {\n this.revokedFlag = true\n this.pending.clear()\n this.prepared = undefined\n this.clearDeadline()\n }\n\n /** The server refused the route for good: drop write credentials and every pending payload. */\n markTerminal(): void {\n this.stateValue = \"closed\"\n this.terminalFlag = true\n this.revokedFlag = true\n this.clearDeadline()\n this.deadlineGeneration += 1\n this.closing = undefined\n this.pending.clear()\n this.prepared = undefined\n this.invocation.claimToken = \"\"\n this.invocation.sealing = undefined\n this.invocation.sealedAttachments = undefined\n this.invocation.sealedAck = undefined\n }\n\n beginClosing(): void {\n this.stateValue = \"closing\"\n this.clearDeadline()\n }\n\n markClosed(): void {\n this.stateValue = \"closed\"\n }\n\n settleClosed(replyText: string | undefined): void {\n this.stateValue = \"closed\"\n this.prepared = undefined\n if (replyText === undefined) delete this.replyText\n else this.replyText = replyText\n }\n\n reopen(prepared: PreparedClose | undefined): void {\n this.stateValue = \"open\"\n this.prepared = prepared\n }\n\n /** Track the completion on the wire so shutdown can settle it instead of racing it. */\n trackClosing<T>(task: Promise<T>): Promise<T> {\n this.closing = task\n return task.finally(() => {\n if (this.closing === task) this.closing = undefined\n })\n }\n\n armIdleTimeout(): void {\n const generation = (this.deadlineGeneration += 1)\n this.deadline = setTimeout(() => this.onIdleDeadline(this, generation), this.idleTimeoutMs)\n }\n\n /** Reset the idle timeout after a sign of life. */\n touchIdleTimeout(): void {\n if (this.stateValue !== \"open\" || this.revokedFlag) return\n this.clearDeadline()\n this.armIdleTimeout()\n }\n\n isCurrentDeadline(deadlineGeneration: number): boolean {\n return this.deadlineGeneration === deadlineGeneration\n }\n\n private clearDeadline(): void {\n clearTimeout(this.deadline)\n this.deadline = undefined\n }\n}\n",
|
|
10
|
+
"import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\"\nimport { dirname } from \"node:path\"\nimport { parseConfigFile, type RawConfig } from \"./identity\"\n\n/**\n * A connector's optional JSON config file. Absent is undefined; a damaged file\n * is logged and ignored so env vars can still carry the config.\n */\nexport function readConfigFile(path: string, log: (message: string) => void): RawConfig | undefined {\n if (!existsSync(path)) return undefined\n try {\n return parseConfigFile(readFileSync(path, \"utf8\"))\n } catch (error) {\n log(`ignoring ${path}: ${error instanceof Error ? error.message : String(error)}`)\n return undefined\n }\n}\n\n/**\n * Owner-only from the first byte, then swapped in whole: an existing file's\n * looser mode never applies to the new content, and a reader or a crash never\n * sees a half-written file.\n */\nexport function writeFileAtomic(path: string, content: string, mode = 0o600): void {\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 })\n const temp = `${path}.${process.pid}.tmp`\n writeFileSync(temp, content, { mode, flag: \"wx\" })\n chmodSync(temp, mode)\n renameSync(temp, path)\n}\n",
|
|
11
|
+
"import type { ShutdownOptions } from \"./session\"\n\nfunction describeError(value: unknown): string {\n if (value instanceof Error) return value.stack ?? value.message\n return String(value)\n}\n\n/** The slice of `process` the lifecycle wiring touches, narrowed so it can be unit-tested with a fake. */\nexport interface LifecycleProcess {\n /** The host's pid, read once at wiring: after the host dies, `process.ppid` names whoever adopted us. */\n ppid: number\n on(event: string, listener: (arg?: unknown) => void): unknown\n stdin: { on(event: string, listener: (arg?: unknown) => void): unknown }\n stderr: { write(chunk: string): unknown }\n exit(code: number): never\n}\n\nexport interface LifecycleOptions {\n /** Prefix for shutdown log lines, e.g. \"[threa-channel]\". */\n logPrefix?: string\n /** Bound on teardown so a hung Threa request can't hold the process past its host's kill grace window. */\n exitGuardMs?: number\n /** Is the process with this pid still running? Decides whether a closed stdin is the host's death or its choice. */\n parentAlive?: (pid: number) => boolean\n /** Wait before probing the parent: a host that was just killed may not be reaped yet. */\n parentProbeDelayMs?: number\n}\n\nfunction defaultParentAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Route every way the process can die through one graceful teardown, so the\n * session marks presence offline + fails its in-flight claim instead of just\n * vanishing. A host runtime typically never respawns a dead stdio child\n * mid-session, so a silent drop strands the scratchpad as \"busy\" with nobody to\n * answer until a human restarts. The paths covered:\n * - SIGINT/SIGTERM — the host's normal stop, and a 2nd Ctrl-C.\n * - SIGHUP — terminal/SSH/tmux disconnect (previously an unhandled hard kill).\n * - stdin end/close — the parent's write end closed: the host exited, was\n * killed, or was swapped out by an auto-update. The session we serve is gone,\n * so exit rather than linger as an orphan that keeps renewing the claim.\n * - uncaughtException/unhandledRejection — a steady-state throw would otherwise\n * vanish the process with no log and no cleanup; log it and exit non-zero.\n */\nexport function wireLifecycle(\n server: { shutdown(options?: ShutdownOptions): Promise<void> },\n host: LifecycleProcess,\n options: LifecycleOptions = {}\n): void {\n const logPrefix = options.logPrefix ?? \"[threa-remote]\"\n const exitGuardMs = options.exitGuardMs ?? 4000\n const parentAlive = options.parentAlive ?? defaultParentAlive\n const parentProbeDelayMs = options.parentProbeDelayMs ?? 250\n const hostPid = host.ppid\n let shuttingDown = false\n const shutdownAndExit = async (code: number, reason: string, shutdown: ShutdownOptions = {}): Promise<void> => {\n if (shuttingDown) return\n shuttingDown = true\n host.stderr.write(`${logPrefix} shutting down (${reason})\\n`)\n // Bound teardown so a hung Threa request can't hold us past the host's\n // SIGTERM→SIGKILL grace window — exit even if presence/fail never lands.\n const guard = setTimeout(() => host.exit(code), exitGuardMs)\n if (guard && typeof guard === \"object\" && \"unref\" in guard) (guard as { unref(): void }).unref()\n await server.shutdown(shutdown).catch(() => undefined)\n clearTimeout(guard)\n host.exit(code)\n }\n\n host.on(\"SIGINT\", () => void shutdownAndExit(0, \"SIGINT\"))\n host.on(\"SIGTERM\", () => void shutdownAndExit(0, \"SIGTERM\"))\n host.on(\"SIGHUP\", () => void shutdownAndExit(0, \"SIGHUP\"))\n // A closed stdin looks the same whether the host died or quit and closed\n // us on the way out, so the host's absence decides: only a dead host leaves\n // claims to lapse. A signal is somebody stopping this runtime on purpose,\n // and its turns fail loudly.\n const stdinClosed = () => {\n if (shuttingDown) return\n setTimeout(\n () => void shutdownAndExit(0, \"stdin closed by parent\", { hostGone: !parentAlive(hostPid) }),\n parentProbeDelayMs\n )\n }\n host.stdin.on(\"end\", stdinClosed)\n host.stdin.on(\"close\", stdinClosed)\n host.on(\"uncaughtException\", (error) => {\n host.stderr.write(`${logPrefix} uncaughtException: ${describeError(error)}\\n`)\n void shutdownAndExit(1, \"uncaughtException\")\n })\n host.on(\"unhandledRejection\", (reason) => {\n host.stderr.write(`${logPrefix} unhandledRejection: ${describeError(reason)}\\n`)\n void shutdownAndExit(1, \"unhandledRejection\")\n })\n}\n",
|
|
12
|
+
"import { ThreaApiError } from \"./client\"\n\nconst FETCH_TIMEOUT_MS = 30_000\nconst CALLBACK_TOKEN_HEADER = \"X-Threa-Callback-Token\"\n\n/** Wire shape of a delegation on the public API (list + lifecycle responses). */\nexport interface DelegationSummary {\n id: string\n streamId: string\n title: string\n status: string\n claimedByLabel?: string\n statusNote?: string\n resultMessageId?: string\n sourceConversationId?: string\n createdAt: string\n statusChangedAt: string\n}\n\n/** Inspect response: the full working set without claim credentials. */\nexport interface InspectedDelegation extends DelegationSummary {\n brief: string\n contextRefs: string[]\n claimExpiresAt?: string\n}\n\n/** The claim response: the executor's full working set plus the one-time token. */\nexport interface ClaimedDelegation extends InspectedDelegation {\n /** Cleartext, returned exactly once — send it back as X-Threa-Callback-Token. */\n claimToken: string\n claimExpiresAt: string\n}\n\nexport interface DelegationClientOptions {\n baseUrl: string\n workspaceId: string\n apiKey: string\n fetchTimeoutMs?: number\n}\n\n/**\n * HTTP client for the delegation lifecycle (roadmap 5.3/5.4) — a deliberate\n * sibling of `ThreaClient`, not an extension of it: the bot-runtime surface is\n * bot-key-only with body-carried claim tokens, while delegations accept either\n * key kind and authenticate transitions with the `X-Threa-Callback-Token`\n * header. Keeping the clients separate keeps the two credential/transport\n * models from cross-contaminating (the recorded 5.3 ruling).\n */\nexport class DelegationClient {\n constructor(private readonly opts: DelegationClientOptions) {}\n\n private get base(): string {\n return this.opts.baseUrl.replace(/\\/$/, \"\")\n }\n\n private path(suffix: string): string {\n return `${this.base}/api/v1/workspaces/${this.opts.workspaceId}/delegations${suffix}`\n }\n\n private async request<T>(url: string, init?: RequestInit & { claimToken?: string }): Promise<T> {\n // One abort window over headers AND body, matching ThreaClient.request: a\n // stalled body after headers must reject at FETCH_TIMEOUT_MS, not hang the\n // channel forever.\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), this.opts.fetchTimeoutMs ?? FETCH_TIMEOUT_MS)\n try {\n return await this.requestWithin<T>(url, init, controller.signal)\n } finally {\n clearTimeout(timeout)\n }\n }\n\n private async requestWithin<T>(\n url: string,\n init: (RequestInit & { claimToken?: string }) | undefined,\n signal: AbortSignal\n ): Promise<T> {\n const { claimToken, ...request } = init ?? {}\n const response = await fetch(url, {\n ...request,\n signal,\n headers: {\n Authorization: `Bearer ${this.opts.apiKey}`,\n \"Content-Type\": \"application/json\",\n ...(claimToken ? { [CALLBACK_TOKEN_HEADER]: claimToken } : {}),\n ...request.headers,\n },\n })\n if (!response.ok) {\n let code: string | undefined\n if (response.headers.get(\"content-type\")?.includes(\"application/json\")) {\n try {\n const parsed = JSON.parse((await response.text()).slice(0, 2000)) as { code?: unknown }\n if (typeof parsed.code === \"string\") code = parsed.code\n } catch {\n code = undefined\n }\n }\n throw new ThreaApiError(`Threa API ${response.status}: ${response.statusText}`, response.status, code)\n }\n const { data } = (await response.json()) as { data: T }\n return data\n }\n\n /** Inspect a delegation without claiming it. The response never contains claim credentials. */\n async get(id: string): Promise<InspectedDelegation> {\n return this.request(this.path(`/${encodeURIComponent(id)}`))\n }\n\n /** Open delegations the key can access, oldest first. `since` narrows to a delta. */\n async listOpen(opts?: { since?: string }): Promise<DelegationSummary[]> {\n const query = opts?.since ? `?since=${encodeURIComponent(opts.since)}` : \"\"\n return this.request<DelegationSummary[]>(this.path(query))\n }\n\n /**\n * CAS-claim one delegation. Persist `idempotencyKey` BEFORE calling: a retry\n * bearing the live claim's key re-keys it (fresh token + lease) instead of\n * 409ing — the crash-between-response-and-persist recovery path.\n * Throws `ThreaApiError` 409 (`DELEGATION_NOT_OPEN`) on a lost race.\n */\n async claim(id: string, body: { claimedByLabel: string; idempotencyKey?: string }): Promise<ClaimedDelegation> {\n return this.request<ClaimedDelegation>(this.path(`/${id}/claim`), {\n method: \"POST\",\n body: JSON.stringify(body),\n })\n }\n\n /** Release a live claim back to the open queue. */\n async release(id: string, claimToken: string): Promise<DelegationSummary> {\n return this.request(this.path(`/${encodeURIComponent(id)}/release`), {\n method: \"POST\",\n body: \"{}\",\n claimToken,\n })\n }\n\n /** Renew the 15-minute lease. Liveness only — nothing changes on the card. */\n async heartbeat(id: string, claimToken: string): Promise<{ claimExpiresAt: string }> {\n return this.request(this.path(`/${id}/heartbeat`), { method: \"POST\", body: \"{}\", claimToken })\n }\n\n /** Progress note on the card (`claimed|running → running`); also renews the lease. */\n async reportStatus(id: string, claimToken: string, statusNote: string): Promise<DelegationSummary> {\n return this.request(this.path(`/${id}/status`), {\n method: \"POST\",\n body: JSON.stringify({ statusNote }),\n claimToken,\n })\n }\n\n /**\n * Terminal success. `resultMarkdown` posts into the delegation card's thread\n * as the key's identity in the same transaction as the flip; retries with the\n * same token are idempotent (the committed outcome comes back, nothing double-posts).\n */\n async complete(\n id: string,\n claimToken: string,\n body: { resultMarkdown?: string; metadata?: Record<string, string> }\n ): Promise<DelegationSummary & { resultMessageId?: string; resultThreadId?: string }> {\n return this.request(this.path(`/${id}/complete`), {\n method: \"POST\",\n body: JSON.stringify(body),\n claimToken,\n })\n }\n\n /** Terminal failure: the reason lands on the card. Idempotent like complete. */\n async fail(id: string, claimToken: string, errorMessage: string): Promise<DelegationSummary> {\n return this.request(this.path(`/${id}/fail`), {\n method: \"POST\",\n body: JSON.stringify({ errorMessage }),\n claimToken,\n })\n }\n\n /**\n * Ask a stream member to grant this bot access to the delegation's stream\n * (F3). Called when a claim 404s for lack of a channel grant — files a card a\n * member approves or denies. No claim token: the bot has no claim yet. Returns\n * `{ status: \"already_granted\" }` (no `requestId`) when the bot already had\n * access, else `{ requestId, status: \"open\" }`; idempotent per (bot, stream).\n */\n async requestAccess(\n delegationId: string,\n opts?: { requestedByLabel?: string }\n ): Promise<{ requestId?: string; status: string }> {\n return this.request(this.path(`/${delegationId}/request-access`), {\n method: \"POST\",\n body: JSON.stringify(opts?.requestedByLabel ? { requestedByLabel: opts.requestedByLabel } : {}),\n })\n }\n}\n",
|
|
13
|
+
"import { ThreaApiError } from \"./client\"\nimport type { ClaimedDelegation, DelegationClient, DelegationSummary } from \"./delegation-client\"\n\nconst DEFAULT_POLL_MS = 60_000\nconst DEFAULT_HEARTBEAT_MS = 5 * 60 * 1000\nconst FAIL_MESSAGE_MAX = 1_000\nconst STATUS_NOTE_MAX = 2_000\nconst SHUTDOWN_WAIT_MS = 2_000\nexport const DELEGATION_STOP_REASON = \"runner_shutdown\"\n\nexport interface DelegationExecutorContext {\n signal: AbortSignal\n reportStatus(note: string): Promise<void>\n}\n\nexport type DelegationExecutor = (\n task: ClaimedDelegation,\n ctx: DelegationExecutorContext\n) => Promise<{ resultMarkdown?: string; metadata?: Record<string, string> } | void>\n\nexport interface DelegationRunnerOptions {\n client: DelegationClient\n executor: DelegationExecutor\n claimedByLabel: string\n persistIdempotencyKey?: (delegationId: string, key: string) => void | Promise<void>\n pollMs?: number\n heartbeatMs?: number\n /** Maximum controlled-stop wait. Primarily useful to bound host reconnects. */\n shutdownWaitMs?: number\n log?: (message: string) => void\n}\n\ntype ActiveClaim = {\n task: ClaimedDelegation\n generation: number\n controller: AbortController\n lost: boolean\n settleLost: () => void\n lostPromise: Promise<void>\n release?: Promise<void>\n cleanupHeartbeat?: () => void\n}\n\ntype Drain = { generation: number; promise: Promise<void> }\n\nexport class DelegationRunner {\n private readonly client: DelegationClient\n private readonly executor: DelegationExecutor\n private readonly claimedByLabel: string\n private readonly persistIdempotencyKey?: DelegationRunnerOptions[\"persistIdempotencyKey\"]\n private readonly pollMs: number\n private readonly heartbeatMs: number\n private readonly shutdownWaitMs: number\n private readonly log: (message: string) => void\n\n private stopped = true\n private generation = 0\n private current: Drain | undefined\n private stopOperation: Drain | undefined\n private pollTimer: ReturnType<typeof setInterval> | undefined\n private active: ActiveClaim | undefined\n private readonly pendingNudged = new Set<string>()\n private readonly accessRequested = new Set<string>()\n\n constructor(opts: DelegationRunnerOptions) {\n this.client = opts.client\n this.executor = opts.executor\n this.claimedByLabel = opts.claimedByLabel\n this.persistIdempotencyKey = opts.persistIdempotencyKey\n this.pollMs = opts.pollMs ?? DEFAULT_POLL_MS\n this.heartbeatMs = opts.heartbeatMs ?? DEFAULT_HEARTBEAT_MS\n this.shutdownWaitMs = opts.shutdownWaitMs ?? SHUTDOWN_WAIT_MS\n this.log = opts.log ?? (() => {})\n }\n\n start(): void {\n if (!this.stopped) return\n this.stopped = false\n this.generation += 1\n const generation = this.generation\n this.pollTimer = setInterval(() => this.drain(generation), this.pollMs)\n this.drain(generation)\n }\n\n async stop(_reason = DELEGATION_STOP_REASON, options?: { strict?: boolean }): Promise<void> {\n if (!this.stopped) this.stopped = true\n const generation = this.generation\n if (this.pollTimer) clearInterval(this.pollTimer)\n this.pollTimer = undefined\n\n const active = this.active?.generation === generation ? this.active : undefined\n active?.cleanupHeartbeat?.()\n active?.controller.abort()\n let pending = this.stopOperation?.generation === generation ? this.stopOperation.promise : undefined\n if (!pending) {\n const release = active && !active.lost ? this.releaseActive(active) : undefined\n pending = release ?? (this.current?.generation === generation ? this.current.promise : Promise.resolve())\n this.stopOperation = { generation, promise: pending }\n }\n\n if (this.current?.generation === generation) this.current = undefined\n if (this.active === active) this.active = undefined\n\n const timeoutError = new Error(`delegation runner stop timed out after ${this.shutdownWaitMs}ms`)\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(timeoutError), this.shutdownWaitMs)\n })\n try {\n if (options?.strict) await Promise.race([pending, timeout])\n else await Promise.race([pending.catch(() => undefined), timeout.catch(() => undefined)])\n } finally {\n if (timer) clearTimeout(timer)\n }\n }\n\n notifyAvailable(nudge?: { delegationId?: string }): void {\n if (nudge?.delegationId) this.pendingNudged.add(nudge.delegationId)\n this.drain(this.generation)\n }\n\n private isCurrent(generation: number): boolean {\n return !this.stopped && this.generation === generation\n }\n\n private drain(generation: number): void {\n if (!this.isCurrent(generation) || this.current?.generation === generation) return\n const promise = this.runDrain(generation).finally(() => {\n if (this.current?.promise === promise) this.current = undefined\n })\n this.current = { generation, promise }\n void promise.catch((error) => {\n this.log(`delegation drain failed: ${error instanceof Error ? error.message : String(error)}`)\n })\n }\n\n private async runDrain(generation: number): Promise<void> {\n let executed = true\n while (executed && this.isCurrent(generation)) {\n executed = false\n const open = await this.client.listOpen()\n if (!this.isCurrent(generation)) return\n for (const summary of open) this.pendingNudged.delete(summary.id)\n for (const summary of open) {\n if (!this.isCurrent(generation)) return\n const claimed = await this.tryClaim(summary)\n if (!claimed) continue\n if (!this.isCurrent(generation)) {\n await this.releaseStoppedClaim(claimed, generation)\n return\n }\n await this.execute(claimed, generation)\n executed = true\n break\n }\n if (executed) continue\n for (const id of [...this.pendingNudged]) {\n if (!this.isCurrent(generation)) return\n const claimed = await this.tryClaimNudged(id)\n if (!claimed) continue\n if (!this.isCurrent(generation)) {\n await this.releaseStoppedClaim(claimed, generation)\n return\n }\n await this.execute(claimed, generation)\n executed = true\n break\n }\n }\n }\n\n private async tryClaim(summary: DelegationSummary): Promise<ClaimedDelegation | null> {\n const idempotencyKey = crypto.randomUUID()\n await this.persistIdempotencyKey?.(summary.id, idempotencyKey)\n try {\n return await this.client.claim(summary.id, { claimedByLabel: this.claimedByLabel, idempotencyKey })\n } catch (error) {\n if (error instanceof ThreaApiError && (error.status === 409 || error.status === 404)) return null\n throw error\n }\n }\n\n private async tryClaimNudged(id: string): Promise<ClaimedDelegation | null> {\n const idempotencyKey = crypto.randomUUID()\n await this.persistIdempotencyKey?.(id, idempotencyKey)\n try {\n const claimed = await this.client.claim(id, { claimedByLabel: this.claimedByLabel, idempotencyKey })\n this.pendingNudged.delete(id)\n return claimed\n } catch (error) {\n if (error instanceof ThreaApiError && error.status === 409) {\n this.pendingNudged.delete(id)\n return null\n }\n if (error instanceof ThreaApiError && error.status === 404) {\n await this.requestAccessOnce(id)\n this.pendingNudged.delete(id)\n return null\n }\n throw error\n }\n }\n\n private async requestAccessOnce(id: string): Promise<void> {\n if (this.accessRequested.has(id)) return\n try {\n await this.client.requestAccess(id, { requestedByLabel: this.claimedByLabel })\n this.accessRequested.add(id)\n this.log(`delegation ${id} not claimable (no access) — filed an access request`)\n } catch (error) {\n this.log(`delegation ${id} access request failed: ${error instanceof Error ? error.message : String(error)}`)\n }\n }\n\n private async releaseStoppedClaim(task: ClaimedDelegation, generation: number): Promise<void> {\n const active = this.createActiveClaim(task, generation)\n await this.releaseActive(active)\n }\n\n private createActiveClaim(task: ClaimedDelegation, generation: number): ActiveClaim {\n let settleLost!: () => void\n const lostPromise = new Promise<void>((resolve) => (settleLost = resolve))\n return { task, generation, controller: new AbortController(), lost: false, settleLost, lostPromise }\n }\n\n private releaseActive(active: ActiveClaim): Promise<void> {\n if (active.release) return active.release\n const release = this.client.release(active.task.id, active.task.claimToken).then(() => undefined)\n active.release = release\n void release.catch((error) => {\n this.log(`delegation ${active.task.id} release failed: ${error instanceof Error ? error.message : String(error)}`)\n })\n return release\n }\n\n private async execute(task: ClaimedDelegation, generation: number): Promise<void> {\n const { id, claimToken } = task\n const active = this.createActiveClaim(task, generation)\n this.active = active\n let heartbeatBusy = false\n const cleanupHeartbeat = () => {\n if (!active.cleanupHeartbeat) return\n active.cleanupHeartbeat = undefined\n clearInterval(heartbeat)\n }\n const loseClaim = () => {\n if (active.lost) return\n active.lost = true\n cleanupHeartbeat()\n active.controller.abort()\n active.settleLost()\n }\n const handleLifecycleError = (kind: string, error: unknown) => {\n if (error instanceof ThreaApiError && error.status === 404) loseClaim()\n this.log(`delegation ${id} ${kind} failed: ${error instanceof Error ? error.message : String(error)}`)\n }\n const heartbeat = setInterval(async () => {\n if (heartbeatBusy || active.lost || active.controller.signal.aborted) return\n heartbeatBusy = true\n try {\n await this.client.heartbeat(id, claimToken)\n } catch (error) {\n handleLifecycleError(\"heartbeat\", error)\n } finally {\n heartbeatBusy = false\n }\n }, this.heartbeatMs)\n active.cleanupHeartbeat = cleanupHeartbeat\n\n const ctx: DelegationExecutorContext = {\n signal: active.controller.signal,\n reportStatus: async (note: string) => {\n if (active.lost || active.controller.signal.aborted) return\n try {\n await this.client.reportStatus(id, claimToken, note.slice(0, STATUS_NOTE_MAX))\n } catch (error) {\n handleLifecycleError(\"status report\", error)\n }\n },\n }\n\n const execution = Promise.resolve()\n .then(() => this.executor(task, ctx))\n .then(\n (result) => ({ kind: \"result\" as const, result }),\n (error: unknown) => ({ kind: \"error\" as const, error })\n )\n try {\n const outcome = await Promise.race([execution, active.lostPromise.then(() => ({ kind: \"lost\" as const }))])\n if (outcome.kind === \"lost\") return\n if (active.lost || active.controller.signal.aborted || !this.isCurrent(generation) || this.active !== active)\n return\n if (outcome.kind === \"error\") throw outcome.error\n await this.client.complete(id, claimToken, {\n resultMarkdown: outcome.result?.resultMarkdown,\n metadata: outcome.result?.metadata,\n })\n this.log(`delegation ${id} completed`)\n } catch (error) {\n if (active.lost || active.controller.signal.aborted || !this.isCurrent(generation) || this.active !== active)\n return\n const message = (error instanceof Error ? error.message : String(error)).slice(0, FAIL_MESSAGE_MAX)\n try {\n await this.client.fail(id, claimToken, message || \"Delegation runner failed without a message\")\n } catch (failError) {\n this.log(\n `delegation ${id} failed AND the fail report failed: ${failError instanceof Error ? failError.message : String(failError)}`\n )\n }\n } finally {\n cleanupHeartbeat()\n if (this.active === active) this.active = undefined\n }\n }\n}\n",
|
|
14
|
+
"// Wire format parsed by `apps/frontend/src/components/trace/trace-step.tsx`; duplicated because this package installs standalone.\nconst TOOL_TRACE_FORMAT = \"pi_tool_trace\"\nconst TOOL_TRACE_MAX_CHARS = 9_500\nconst HEADLINE_MAX_CHARS = 500\nconst TRUNCATION_MARKER = \"\\n\\n…[section truncated;\"\n\nexport type ToolTraceSectionLabel = \"Arguments\" | \"Output\" | \"Error output\" | \"Details\"\n\nexport interface ToolTraceSection {\n label: ToolTraceSectionLabel\n body: string\n lang: string | null\n}\n\n/**\n * Serialize a structured tool trace under the step content limit, trimming the\n * largest section first (the same algorithm as pi-remote and claude-code-remote).\n */\nexport function toolTraceContent(params: { headline: string; sections: ToolTraceSection[] }): string {\n const headline =\n params.headline.length <= HEADLINE_MAX_CHARS ? params.headline : `${params.headline.slice(0, HEADLINE_MAX_CHARS)}…`\n const sections = params.sections.map((section) => ({ ...section, originalBody: section.body }))\n\n for (let attempt = 0; attempt < 24; attempt++) {\n const payload = JSON.stringify({\n format: TOOL_TRACE_FORMAT,\n headline,\n sections: sections.map(({ originalBody: _originalBody, ...section }) => section),\n })\n if (payload.length <= TOOL_TRACE_MAX_CHARS) return payload\n\n const largestIndex = sections.reduce(\n (largest, section, index) => (section.body.length > sections[largest]!.body.length ? index : largest),\n 0\n )\n const largest = sections[largestIndex]\n if (!largest || largest.originalBody.length === 0) break\n\n const overflow = payload.length - TOOL_TRACE_MAX_CHARS\n const currentVisibleLength = largest.body.includes(TRUNCATION_MARKER)\n ? largest.body.indexOf(TRUNCATION_MARKER)\n : largest.body.length\n const nextVisibleLength = Math.max(0, currentVisibleLength - Math.max(overflow + 256, 512))\n const omitted = largest.originalBody.length - nextVisibleLength\n largest.body = `${largest.originalBody.slice(0, nextVisibleLength).trimEnd()}${TRUNCATION_MARKER} ${omitted} more characters]`\n }\n\n return JSON.stringify({\n format: TOOL_TRACE_FORMAT,\n headline,\n sections: [{ label: \"Details\", body: \"Trace content was too large to serialize safely.\", lang: null }],\n })\n}\n"
|
|
15
|
+
],
|
|
16
|
+
"mappings": "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",
|
|
17
|
+
"debugId": "EE71C0ED22C7B43264756E2164756E21",
|
|
18
|
+
"names": []
|
|
19
|
+
}
|