@pwrdrvr/agent-client 0.3.0 → 0.5.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/dist/index.d.ts CHANGED
@@ -458,6 +458,11 @@ type ChatThreadControllerDeps<TSettings = unknown> = {
458
458
  threadConfig?: Record<string, unknown>;
459
459
  /** Thread environments. `[]` disables exec-environment access. */
460
460
  threadEnvironments?: unknown[];
461
+ /** Opaque per-surface MCP server config forwarded to an ACP backend's
462
+ * `reopenThread` so a SHARED agent process can serve this surface's tools
463
+ * (different surfaces pass different servers). Ignored by backends without
464
+ * `reopenThread` (Codex). */
465
+ threadMcpServers?: readonly unknown[];
461
466
  /** Reasoning effort for turns. Defaults to "medium". */
462
467
  effort?: string;
463
468
  /** Default model id for thread/start (host's per-surface default). Omit for Codex default. */
package/dist/index.js CHANGED
@@ -1236,9 +1236,10 @@ var ChatThreadController = class {
1236
1236
  if (this.deps.threadEnvironments !== void 0) {
1237
1237
  startOptions.environments = this.deps.threadEnvironments;
1238
1238
  }
1239
+ const deferrable = this.deps.client;
1239
1240
  let started;
1240
1241
  try {
1241
- started = await this.deps.client.startThread(startOptions);
1242
+ started = typeof deferrable.createDeferredThread === "function" ? await deferrable.createDeferredThread(startOptions) : await this.deps.client.startThread(startOptions);
1242
1243
  } catch (cause) {
1243
1244
  await this.deps.store.discardPreparedThreadDir(preparedDir).catch(() => void 0);
1244
1245
  throw cause;
@@ -1383,7 +1384,8 @@ ${input.text}`;
1383
1384
  if (typeof reopenable.reopenThread === "function") {
1384
1385
  await reopenable.reopenThread({
1385
1386
  threadId,
1386
- buildInstructions: () => this.deps.buildSystemPrompt({ settings: settingsSnapshot, anchorId: anchorForTurn })
1387
+ buildInstructions: () => this.deps.buildSystemPrompt({ settings: settingsSnapshot, anchorId: anchorForTurn }),
1388
+ ...this.deps.threadMcpServers !== void 0 ? { mcpServers: this.deps.threadMcpServers } : {}
1387
1389
  });
1388
1390
  }
1389
1391
  const startTurnOptions = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/codex-thread-client.ts","../src/normalize.ts","../src/codex-error.ts","../src/codex-oneshot-client.ts","../src/codex-thread-config.ts","../src/chat/define-tool.ts","../src/chat/tool-catalog.ts","../src/chat/chat-thread-controller.ts"],"sourcesContent":["// Long-lived, multi-turn Codex App Server client.\n//\n// Keeps a single codex child process + JSON-RPC connection alive and lets the\n// caller open MULTIPLE threads on it, each carrying its own dynamic tools. It\n// is a thin transport client: it owns the connection lifecycle and routes\n// notifications / server-requests, but bakes in no chat or idle-timing logic.\n//\n// Ported from PwrSnap's CodexThreadClient with three seams broken:\n// • the logger is injected (agent-core `Logger`);\n// • `clientInfo.name` + the default `serviceName` are options (no hardcoded\n// \"pwrsnap\");\n// • every native notification is routed through `normalizeNotification`, so\n// subscribers receive agent-core `NormalizedThreadEvent` — never a raw\n// protocol shape.\n\nimport {\n noopLogger,\n type AgentBackend,\n type AgentBackendApprovalHandler,\n type AgentBackendStartThreadResult,\n type AgentBackendToolCall,\n type AgentBackendToolCallHandler,\n type AgentForkThreadOptions,\n type AgentStartThreadOptions,\n type AgentStartTurnOptions,\n type Logger,\n type NormalizedThreadEvent,\n type NormalizedApprovalDecision\n} from \"@pwrdrvr/agent-core\";\nimport {\n JsonRpcConnection,\n StdioJsonRpcTransport,\n type JsonRpcTransport\n} from \"@pwrdrvr/agent-transport\";\nimport { resolveCodexCommand } from \"@pwrdrvr/codex-discovery\";\nimport type {\n InitializeParams,\n InitializeResponse,\n Personality,\n ReasoningEffort\n} from \"@pwrdrvr/codex-app-server-protocol\";\nimport type {\n AskForApproval,\n DynamicToolCallResponse,\n DynamicToolSpec,\n SandboxMode,\n ThreadForkParams,\n ThreadForkResponse,\n ThreadResumeParams,\n ThreadResumeResponse,\n ThreadStartParams,\n ThreadStartResponse,\n TurnStartParams,\n TurnStartResponse,\n UserInput\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\nimport {\n CODEX_APPROVAL_METHODS,\n CODEX_TOOL_CALL_METHOD,\n normalizeNotification\n} from \"./normalize\";\n\nexport type CodexThreadClientTransportFactory = (command: string) => JsonRpcTransport;\n\nexport type CodexThreadClientOptions = {\n /** Configured command to resolve. `\"codex\"` (or empty) triggers discovery. */\n command?: string;\n /** Identity sent as `clientInfo.name` at `initialize`. Defaults to \"agent-kit\". */\n clientName?: string;\n /** Human title sent as `clientInfo.title`. Defaults to `clientName`. */\n clientTitle?: string;\n /** Version sent as `clientInfo.version`. Defaults to \"0.0.0\". */\n clientVersion?: string;\n /** Default `serviceName` applied at `thread/start` when the caller omits one. */\n serviceName?: string;\n requestTimeoutMs?: number;\n turnTimeoutMs?: number;\n /** Process env passed to the spawned codex. Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv;\n /** Override the transport (tests inject an in-memory fake). When supplied,\n * no discovery/spawn happens. */\n transportFactory?: CodexThreadClientTransportFactory;\n logger?: Logger;\n};\n\n/**\n * Codex-NATIVE thread/start options. **No longer the public `startThread`\n * surface** — `CodexThreadClient` now implements the non-generic `AgentBackend`\n * and its public `startThread` takes neutral `AgentStartThreadOptions`. This\n * type is retained as the internal mapping target (and is still exported for\n * hosts that want to construct the native shape directly via\n * `startThreadNative`). The neutral→native mapping lives in `startThread`.\n */\nexport type CodexStartThreadOptions = {\n approvalPolicy?: string;\n sandbox?: string;\n baseInstructions?: string;\n dynamicTools?: DynamicToolSpec[];\n cwd?: string;\n runtimeWorkspaceRoots?: string[];\n serviceName?: string;\n personality?: string;\n /** Model id to start the thread on (ThreadStartParams.model). Omit for the\n * Codex default. The host drives this from its settings (per-surface default). */\n model?: string;\n /** Model provider id (ThreadStartParams.modelProvider) — the \"provider\" a host\n * picks when more than one is configured. Omit for the Codex default. */\n modelProvider?: string;\n /** Service tier (ThreadStartParams.serviceTier), when the host pins one. */\n serviceTier?: string;\n /** Per-thread Codex config overlay (the `-c key=value` mechanism). Used to\n * disable Codex prompt/tool scaffolding that belongs to coding-agent threads. */\n config?: Record<string, unknown>;\n /** Thread environments. **Empty array disables exec-environment access**,\n * dropping Codex's built-in shell / unified_exec / apply_patch tools. Dynamic\n * tools are added before that gate, so they survive. */\n environments?: unknown[];\n};\n\n/** Codex-NATIVE turn/start options. Internal mapping target (see\n * `startThreadNative`'s sibling `startTurnNative`); the public `startTurn`\n * takes neutral `AgentStartTurnOptions`. */\nexport type CodexStartTurnOptions = {\n threadId: string;\n input: UserInput[];\n effort?: string;\n};\n\n/**\n * Handles a tool-call ServerRequest. Reconciled to the canonical\n * `AgentBackendToolCallHandler` shape so the controller drives Codex and ACP\n * identically: the handler receives a neutral `AgentBackendToolCall`\n * (`{ method, params }`) and returns an `unknown` payload the client forwards\n * back to Codex verbatim. For Codex the `params` is a `DynamicToolCallParams`\n * (cast at the dispatch site) and the returned payload is a\n * `DynamicToolCallResponse`.\n */\nexport type CodexToolCallHandler = AgentBackendToolCallHandler;\n\n/** Handles an approval ServerRequest; resolves to a neutral decision. Identical\n * to the canonical `AgentBackendApprovalHandler`. */\nexport type CodexApprovalHandler = AgentBackendApprovalHandler;\n\nexport type Unsubscribe = () => void;\n\nexport type StartThreadResult = {\n threadId: string;\n model: string;\n modelProvider: string;\n serviceTier: string | null;\n};\n\nconst DEFAULT_CLIENT_NAME = \"agent-kit\";\nconst DEFAULT_SERVICE_NAME = \"agent-kit\";\n\n/** Map a neutral approval decision onto the generic Codex approval response. */\nfunction approvalResponseFor(decision: NormalizedApprovalDecision): unknown {\n switch (decision) {\n case \"approved\":\n return { decision: \"approved\" };\n case \"abort\":\n return { decision: \"abort\" };\n case \"denied\":\n default:\n return { decision: \"denied\" };\n }\n}\n\nexport class CodexThreadClient implements AgentBackend {\n private readonly requestTimeoutMs: number;\n private readonly turnTimeoutMs: number;\n private readonly logger: Logger;\n private readonly transportFactory: CodexThreadClientTransportFactory | null;\n private resolvedCommand: string | null = null;\n private connection: JsonRpcConnection | null = null;\n private initializeResponse: InitializeResponse | null = null;\n\n private readonly eventListeners = new Set<(event: NormalizedThreadEvent) => void>();\n private toolCallHandler: CodexToolCallHandler | null = null;\n private approvalHandler: CodexApprovalHandler | null = null;\n private readonly loadedThreadIds = new Set<string>();\n\n constructor(private readonly options: CodexThreadClientOptions = {}) {\n this.requestTimeoutMs = options.requestTimeoutMs ?? 20_000;\n this.turnTimeoutMs = options.turnTimeoutMs ?? 120_000;\n this.logger = options.logger ?? noopLogger;\n this.transportFactory = options.transportFactory ?? null;\n }\n\n /** Subscribe to the normalized event stream. Every native notification is\n * routed through `normalizeNotification` before listeners see it. */\n onEvent(cb: (event: NormalizedThreadEvent) => void): Unsubscribe {\n this.eventListeners.add(cb);\n return () => {\n this.eventListeners.delete(cb);\n };\n }\n\n /** Register the dynamic-tool ServerRequest handler (one at a time). */\n onToolCall(handler: CodexToolCallHandler): Unsubscribe {\n this.toolCallHandler = handler;\n return () => {\n if (this.toolCallHandler === handler) this.toolCallHandler = null;\n };\n }\n\n /** Register the approval ServerRequest handler (one at a time). */\n onApprovalRequest(handler: CodexApprovalHandler): Unsubscribe {\n this.approvalHandler = handler;\n return () => {\n if (this.approvalHandler === handler) this.approvalHandler = null;\n };\n }\n\n /**\n * Public `AgentBackend.startThread`: accepts NEUTRAL `AgentStartThreadOptions`\n * and maps them onto Codex-native `CodexStartThreadOptions` before delegating\n * to `startThreadNative`. Mapping:\n * instructions→baseInstructions, cwd, workspaceRoots→runtimeWorkspaceRoots,\n * model/modelProvider, serviceTier (drop `null`), approvalPolicy, sandbox,\n * serviceName, config, environments, tools (cast to DynamicToolSpec[])→\n * dynamicTools.\n */\n async startThread(opts: AgentStartThreadOptions = {}): Promise<StartThreadResult> {\n const native: CodexStartThreadOptions = {};\n if (opts.instructions !== undefined) native.baseInstructions = opts.instructions;\n if (opts.cwd !== undefined) native.cwd = opts.cwd;\n if (opts.workspaceRoots !== undefined) {\n native.runtimeWorkspaceRoots = [...opts.workspaceRoots];\n }\n if (opts.model !== undefined) native.model = opts.model;\n if (opts.modelProvider !== undefined) native.modelProvider = opts.modelProvider;\n // Codex's serviceTier is a plain string; a neutral `null` means \"don't pin\".\n if (opts.serviceTier != null) native.serviceTier = opts.serviceTier;\n if (opts.approvalPolicy !== undefined) native.approvalPolicy = opts.approvalPolicy;\n if (opts.sandbox !== undefined) native.sandbox = opts.sandbox;\n if (opts.serviceName !== undefined) native.serviceName = opts.serviceName;\n if (opts.config !== undefined) native.config = opts.config;\n if (opts.environments !== undefined) native.environments = opts.environments;\n if (opts.tools !== undefined) native.dynamicTools = opts.tools as DynamicToolSpec[];\n return this.startThreadNative(native);\n }\n\n /** Fork an existing thread into a fresh one carrying its history (Codex\n * `thread/fork`). The new thread inherits the source's model/provider. */\n async forkThread(opts: AgentForkThreadOptions): Promise<AgentBackendStartThreadResult> {\n const connection = await this.getConnection();\n await this.initialize();\n\n const params: ThreadForkParams = {\n threadId: opts.sourceThreadId,\n persistExtendedHistory: false\n };\n if (opts.cwd !== undefined) params.cwd = opts.cwd;\n if (opts.workspaceRoots !== undefined) params.runtimeWorkspaceRoots = [...opts.workspaceRoots];\n if (opts.instructions !== undefined) params.baseInstructions = opts.instructions;\n if (opts.approvalPolicy !== undefined) params.approvalPolicy = opts.approvalPolicy as AskForApproval;\n if (opts.sandbox !== undefined) params.sandbox = opts.sandbox as SandboxMode;\n if (opts.config !== undefined) {\n params.config = opts.config as NonNullable<ThreadForkParams[\"config\"]>;\n }\n\n const response = (await connection.request(\n \"thread/fork\",\n params,\n this.requestTimeoutMs\n )) as ThreadForkResponse;\n const threadId = response.thread.id;\n this.loadedThreadIds.add(threadId);\n return {\n threadId,\n model: response.model,\n modelProvider: response.modelProvider,\n serviceTier: response.serviceTier\n };\n }\n\n /** Codex-native thread/start. Builds `ThreadStartParams` directly. Exposed for\n * hosts that want full Codex control; the neutral `startThread` delegates here. */\n async startThreadNative(opts: CodexStartThreadOptions = {}): Promise<StartThreadResult> {\n const connection = await this.getConnection();\n await this.initialize();\n\n // exactOptionalPropertyTypes: only attach a key when the caller supplied it.\n const params: ThreadStartParams = {\n experimentalRawEvents: false,\n persistExtendedHistory: false\n };\n if (opts.cwd !== undefined) params.cwd = opts.cwd;\n if (opts.model !== undefined) params.model = opts.model;\n if (opts.modelProvider !== undefined) params.modelProvider = opts.modelProvider;\n if (opts.serviceTier !== undefined) params.serviceTier = opts.serviceTier;\n if (opts.runtimeWorkspaceRoots !== undefined) {\n params.runtimeWorkspaceRoots = opts.runtimeWorkspaceRoots;\n }\n const serviceName = opts.serviceName ?? this.options.serviceName ?? DEFAULT_SERVICE_NAME;\n params.serviceName = serviceName;\n if (opts.approvalPolicy !== undefined) {\n params.approvalPolicy = opts.approvalPolicy as AskForApproval;\n }\n if (opts.sandbox !== undefined) params.sandbox = opts.sandbox as SandboxMode;\n if (opts.baseInstructions !== undefined) params.baseInstructions = opts.baseInstructions;\n if (opts.personality !== undefined) params.personality = opts.personality as Personality;\n if (opts.dynamicTools !== undefined) params.dynamicTools = opts.dynamicTools;\n if (opts.config !== undefined) {\n params.config = opts.config as NonNullable<ThreadStartParams[\"config\"]>;\n }\n if (opts.environments !== undefined) {\n params.environments = opts.environments as NonNullable<ThreadStartParams[\"environments\"]>;\n }\n\n const response = (await connection.request(\n \"thread/start\",\n params,\n this.requestTimeoutMs\n )) as ThreadStartResponse;\n const threadId = response.thread.id;\n this.loadedThreadIds.add(threadId);\n this.logger.debug(\"thread started\", { threadId });\n return {\n threadId,\n model: response.model,\n modelProvider: response.modelProvider,\n serviceTier: response.serviceTier\n };\n }\n\n async resumeThread(threadId: string): Promise<void> {\n if (this.loadedThreadIds.has(threadId)) return;\n const connection = await this.getConnection();\n await this.initialize();\n\n const params: ThreadResumeParams = {\n threadId,\n persistExtendedHistory: false\n };\n const response = (await connection.request(\n \"thread/resume\",\n params,\n this.requestTimeoutMs\n )) as ThreadResumeResponse;\n this.loadedThreadIds.add(response.thread.id);\n this.logger.debug(\"thread resumed\", { threadId: response.thread.id });\n }\n\n async clearThreadGitInfo(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await this.initialize();\n await connection.request(\n \"thread/metadata/update\",\n { threadId, gitInfo: { sha: null, branch: null, originUrl: null } },\n this.requestTimeoutMs\n );\n }\n\n /**\n * Public `AgentBackend.startTurn`: accepts NEUTRAL `AgentStartTurnOptions` and\n * maps them onto Codex-native `UserInput[]`. The neutral `input.text` becomes a\n * leading `{ type: \"text\" }` item; each `input.imagePaths` entry becomes a\n * `{ type: \"localImage\", path }` item appended after the text. `reasoning`\n * maps to Codex's `effort`.\n */\n async startTurn(opts: AgentStartTurnOptions): Promise<{ turnId: string }> {\n const input: UserInput[] = [{ type: \"text\", text: opts.input.text, text_elements: [] }];\n for (const path of opts.input.imagePaths ?? []) {\n input.push({ type: \"localImage\", path });\n }\n const native: CodexStartTurnOptions = { threadId: opts.threadId, input };\n if (opts.reasoning !== undefined) native.effort = opts.reasoning;\n return this.startTurnNative(native);\n }\n\n /** Codex-native turn/start. Takes pre-built `UserInput[]`. The neutral\n * `startTurn` delegates here after mapping text + image paths. */\n async startTurnNative(opts: CodexStartTurnOptions): Promise<{ turnId: string }> {\n await this.resumeThread(opts.threadId);\n const connection = await this.getConnection();\n await this.initialize();\n\n const params: TurnStartParams = {\n threadId: opts.threadId,\n input: opts.input\n };\n if (opts.effort !== undefined) params.effort = opts.effort as ReasoningEffort;\n\n const response = (await connection.request(\n \"turn/start\",\n params,\n this.turnTimeoutMs\n )) as TurnStartResponse;\n const turnId = response.turn.id;\n this.logger.debug(\"turn started\", { threadId: opts.threadId, turnId });\n return { turnId };\n }\n\n async interruptTurn(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await connection.request(\"turn/interrupt\", { threadId }, this.requestTimeoutMs);\n }\n\n async archiveThread(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await connection.request(\"thread/archive\", { threadId }, this.requestTimeoutMs);\n }\n\n async close(): Promise<void> {\n const connection = this.connection;\n this.connection = null;\n this.initializeResponse = null;\n this.loadedThreadIds.clear();\n if (connection) await connection.close();\n }\n\n // ---- internals ----\n\n private emit(event: NormalizedThreadEvent): void {\n for (const listener of this.eventListeners) listener(event);\n }\n\n private async resolveCommand(): Promise<string> {\n if (this.resolvedCommand !== null) return this.resolvedCommand;\n const resolved = await resolveCodexCommand({\n command: this.options.command ?? \"codex\",\n env: this.options.env ?? process.env\n });\n this.resolvedCommand = resolved.command;\n return resolved.command;\n }\n\n private async initialize(): Promise<InitializeResponse> {\n if (this.initializeResponse) return this.initializeResponse;\n const connection = await this.getConnection();\n const name = this.options.clientName ?? DEFAULT_CLIENT_NAME;\n const params: InitializeParams = {\n clientInfo: {\n name,\n title: this.options.clientTitle ?? name,\n version: this.options.clientVersion ?? \"0.0.0\"\n },\n capabilities: {\n experimentalApi: true,\n // We don't proxy through OpenAI's edge attestation flow, so opting in\n // would add per-turn latency for an unused round-trip.\n requestAttestation: false\n }\n };\n const response = (await connection.request(\n \"initialize\",\n params,\n this.requestTimeoutMs\n )) as InitializeResponse;\n this.initializeResponse = response;\n return response;\n }\n\n private async getConnection(): Promise<JsonRpcConnection> {\n if (this.connection) return this.connection;\n\n let transport: JsonRpcTransport;\n if (this.transportFactory !== null) {\n // Tests / hosts supplying a fake transport bypass discovery + spawn.\n transport = this.transportFactory(this.options.command ?? \"codex\");\n } else {\n const command = await this.resolveCommand();\n transport = new StdioJsonRpcTransport({\n command,\n args: [\"app-server\"],\n ...(this.options.env !== undefined ? { env: this.options.env } : {}),\n logger: this.logger\n });\n }\n\n const connection = new JsonRpcConnection(transport, this.requestTimeoutMs, undefined, {\n logger: this.logger,\n logContext: { owner: \"codex-thread-client\" }\n });\n connection.setNotificationHandler((method, params) => {\n this.handleNotification(method, params);\n });\n connection.setRequestHandler((method, params) => this.handleServerRequest(method, params));\n await connection.connect();\n this.connection = connection;\n return connection;\n }\n\n private handleNotification(method: string, params: unknown): void {\n const event = normalizeNotification(method, params);\n if (event !== null) this.emit(event);\n }\n\n private async handleServerRequest(method: string, params: unknown): Promise<unknown> {\n if (method === CODEX_TOOL_CALL_METHOD) {\n const handler = this.toolCallHandler;\n if (!handler) {\n this.logger.warn(\"tool call received with no handler registered\");\n return {\n contentItems: [\n { type: \"inputText\", text: \"No tool handler is registered for this thread.\" }\n ],\n success: false\n } satisfies DynamicToolCallResponse;\n }\n // Canonical `AgentBackendToolCall` shape: the host's handler reads\n // `call.params` (a `DynamicToolCallParams` for Codex) and returns the\n // `DynamicToolCallResponse` we forward back to Codex verbatim.\n const call: AgentBackendToolCall = { method, params };\n return await handler(call);\n }\n\n if (CODEX_APPROVAL_METHODS.has(method)) {\n const handler = this.approvalHandler;\n if (!handler) {\n this.logger.warn(\"approval request received with no handler registered\", { method });\n return approvalResponseFor(\"denied\");\n }\n const decision = await handler(method, params);\n return approvalResponseFor(decision);\n }\n\n this.logger.debug(\"unhandled codex server request\", { method });\n return {};\n }\n}\n","// Codex App Server v2 → agent-core neutral schema.\n//\n// Every native Codex notification / server-request a turn produces is mapped\n// here into one (or zero) `NormalizedThreadEvent`. Subscribers of the Codex\n// adapter only ever see normalized shapes — the raw protocol stops at this\n// boundary, so an ACP adapter emitting the same neutral events is a drop-in.\n//\n// The mapping is deliberately defensive: a notification we don't recognize, or\n// a malformed payload, yields `null` (no event) rather than throwing — a\n// streaming turn must never die on an unexpected wire shape.\n\nimport {\n inferToolKind,\n type NormalizedThreadEvent,\n type NormalizedToolCall,\n type NormalizedToolCallUpdate,\n type NormalizedToolKind,\n type NormalizedToolStatus,\n type NormalizedTokenUsage,\n type NormalizedTurnStatus,\n type NormalizedApprovalKind,\n type NormalizedApprovalRequest,\n type NormalizedThreadSettings,\n type NormalizedMessage\n} from \"@pwrdrvr/agent-core\";\nimport { formatCodexTurnError } from \"./codex-error\";\nimport type {\n AgentMessageDeltaNotification,\n DynamicToolCallParams,\n ItemCompletedNotification,\n ItemStartedNotification,\n ModelReroutedNotification,\n ReasoningTextDeltaNotification,\n ThreadItem,\n ThreadSettingsUpdatedNotification,\n ThreadTokenUsage,\n ThreadTokenUsageUpdatedNotification,\n TurnCompletedNotification,\n TurnError,\n TurnStartedNotification,\n TurnStatus\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\n\n// ---- wire method strings ----\n// These are the App Server JSON-RPC method names a turn emits. Kept as bare\n// strings (not protocol types — the wire carries strings) so the adapter routes\n// `(method, params)` straight through `normalizeNotification`.\n\nexport const CODEX_NOTIFICATION_METHODS = {\n agentMessageDelta: \"item/agentMessage/delta\",\n reasoningDelta: \"item/reasoning/delta\",\n reasoningTextDelta: \"item/reasoning/textDelta\",\n itemStarted: \"item/started\",\n itemCompleted: \"item/completed\",\n turnStarted: \"turn/started\",\n turnCompleted: \"turn/completed\",\n tokenUsage: \"thread/tokenUsage/updated\",\n threadSettings: \"thread/settings/updated\",\n modelRerouted: \"model/rerouted\",\n error: \"error\"\n} as const;\n\n/** Codex approval ServerRequest methods, normalized into `approval_request`. */\nexport const CODEX_APPROVAL_METHODS = new Set<string>([\n \"item/commandExecution/requestApproval\",\n \"item/fileChange/requestApproval\",\n \"item/permissions/requestApproval\",\n \"item/tool/requestUserInput\",\n // Legacy v1 method names — older Codex builds still emit these.\n \"applyPatchApproval\",\n \"execCommandApproval\"\n]);\n\n/** The dynamic-tool ServerRequest method Codex routes tool invocations on. */\nexport const CODEX_TOOL_CALL_METHOD = \"item/tool/call\";\n\n// ---- usage ----\n\n/** Map a Codex `ThreadTokenUsage` (its `last` breakdown) to the neutral shape. */\nexport function normalizeTokenUsage(usage: ThreadTokenUsage): NormalizedTokenUsage {\n const last = usage.last;\n return {\n inputTokens: last.inputTokens,\n cachedInputTokens: last.cachedInputTokens,\n outputTokens: last.outputTokens,\n reasoningOutputTokens: last.reasoningOutputTokens,\n totalTokens: last.totalTokens,\n // Top-level on ThreadTokenUsage (sibling to last/total), not on the breakdown.\n ...(usage.modelContextWindow != null ? { contextWindow: usage.modelContextWindow } : {})\n };\n}\n\n// ---- turn status ----\n\nfunction normalizeTurnStatus(status: TurnStatus | string): NormalizedTurnStatus {\n switch (status) {\n case \"completed\":\n return \"completed\";\n case \"failed\":\n return \"failed\";\n case \"interrupted\":\n return \"interrupted\";\n case \"inProgress\":\n return \"in_progress\";\n case \"aborted\":\n case \"cancelled\":\n case \"canceled\":\n return \"cancelled\";\n default:\n return \"failed\";\n }\n}\n\n// ---- tool call (from a ThreadItem) ----\n\nconst DYNAMIC_TOOL_STATUS: Record<string, NormalizedToolStatus> = {\n inProgress: \"in_progress\",\n completed: \"completed\",\n failed: \"failed\"\n};\n\nconst COMMAND_STATUS: Record<string, NormalizedToolStatus> = {\n inProgress: \"in_progress\",\n completed: \"completed\",\n failed: \"failed\",\n declined: \"cancelled\"\n};\n\n/** Render the content items a dynamic tool returned as a single string result. */\nfunction joinDynamicResult(\n contentItems: Extract<ThreadItem, { type: \"dynamicToolCall\" }>[\"contentItems\"]\n): string | undefined {\n if (contentItems === null) return undefined;\n const text = contentItems\n .map((item) => (item.type === \"inputText\" ? item.text : item.imageUrl))\n .join(\"\");\n return text.length > 0 ? text : undefined;\n}\n\n/**\n * Build a `NormalizedToolCall` from a tool-ish `ThreadItem`. Returns `null` for\n * non-tool items. `kind` defaults to `inferToolKind(name)` unless the item's\n * native shape already classifies it (a command execution is always \"command\").\n */\nexport function normalizeThreadItemToolCall(item: ThreadItem): NormalizedToolCall | null {\n if (item.type === \"dynamicToolCall\") {\n const kind: NormalizedToolKind = inferToolKind(item.tool);\n const status = DYNAMIC_TOOL_STATUS[item.status] ?? \"in_progress\";\n const call: NormalizedToolCall = {\n id: item.id,\n name: item.tool,\n kind,\n label: item.tool,\n status,\n args: item.arguments\n };\n const result = joinDynamicResult(item.contentItems);\n if (result !== undefined) call.result = result;\n return call;\n }\n\n if (item.type === \"commandExecution\") {\n const status = COMMAND_STATUS[item.status] ?? \"in_progress\";\n const call: NormalizedToolCall = {\n id: item.id,\n name: \"command\",\n kind: \"command\",\n label: item.command,\n status,\n command: {\n displayCommand: item.command,\n rawCommand: item.command,\n cwd: item.cwd,\n ...(item.aggregatedOutput !== null ? { output: item.aggregatedOutput } : {}),\n ...(item.exitCode !== null ? { exitCode: item.exitCode } : {}),\n ...(item.durationMs !== null ? { durationMs: item.durationMs } : {})\n }\n };\n return call;\n }\n\n if (item.type === \"webSearch\") {\n return {\n id: item.id,\n name: \"web_search\",\n kind: \"search\",\n label: item.query,\n status: \"completed\",\n args: { query: item.query }\n };\n }\n\n if (item.type === \"fileChange\") {\n return {\n id: item.id,\n name: \"file_change\",\n kind: \"write\",\n label: \"Edit files\",\n status: item.status === \"completed\" ? \"completed\" : \"in_progress\"\n };\n }\n\n return null;\n}\n\n/**\n * Build a `NormalizedToolCall` from a `DynamicToolCallParams` (the ServerRequest\n * the adapter must answer). `kind` defaults to `inferToolKind(name)`.\n */\nexport function normalizeDynamicToolCall(params: DynamicToolCallParams): NormalizedToolCall {\n return {\n id: params.callId,\n name: params.tool,\n kind: inferToolKind(params.tool),\n label: params.tool,\n status: \"in_progress\",\n args: params.arguments\n };\n}\n\n// ---- approvals ----\n\nfunction approvalKindForMethod(method: string): NormalizedApprovalKind {\n if (method.includes(\"commandExecution\") || method === \"execCommandApproval\") return \"exec\";\n if (method.includes(\"fileChange\") || method === \"applyPatchApproval\") return \"patch\";\n if (method.includes(\"tool\")) return \"tool\";\n return \"other\";\n}\n\n/** Normalize a Codex approval ServerRequest into a neutral approval request. */\nexport function normalizeApprovalRequest(\n method: string,\n params: unknown,\n approvalId: string\n): NormalizedApprovalRequest {\n const p = (params ?? {}) as Record<string, unknown>;\n const summary =\n typeof p.reason === \"string\"\n ? p.reason\n : typeof p.command === \"string\"\n ? p.command\n : undefined;\n const request: NormalizedApprovalRequest = {\n id: approvalId,\n method,\n kind: approvalKindForMethod(method),\n params\n };\n if (summary !== undefined) request.summary = summary;\n return request;\n}\n\n// ---- thread settings ----\n\nexport function normalizeThreadSettings(\n notification: ThreadSettingsUpdatedNotification\n): NormalizedThreadSettings {\n return {\n threadId: notification.threadId,\n model: notification.threadSettings.model,\n modelProvider: notification.threadSettings.modelProvider,\n serviceTier: notification.threadSettings.serviceTier\n };\n}\n\n// ---- top-level notification dispatch ----\n\nfunction isToolish(item: ThreadItem): boolean {\n return (\n item.type === \"dynamicToolCall\" ||\n item.type === \"commandExecution\" ||\n item.type === \"webSearch\" ||\n item.type === \"fileChange\"\n );\n}\n\nfunction toUpdate(call: NormalizedToolCall): NormalizedToolCallUpdate {\n return call;\n}\n\nfunction agentMessageFromItem(item: ThreadItem): NormalizedMessage | null {\n if (item.type !== \"agentMessage\") return null;\n return { id: item.id, role: \"assistant\", text: item.text };\n}\n\n/**\n * Normalize one native Codex notification into a `NormalizedThreadEvent`.\n * Returns `null` when the method/payload yields no neutral event (an unknown\n * method, or an `item/*` carrying a non-streamable item).\n *\n * `item/started` for a tool-ish item becomes a `tool_call`; the matching\n * `item/completed` becomes a `tool_call_update` (so the controller correlates\n * them by id and merges via `mergeToolCall`). An `agentMessage` `item/completed`\n * becomes a final `agent_message`.\n */\nexport function normalizeNotification(\n method: string,\n params: unknown\n): NormalizedThreadEvent | null {\n switch (method) {\n case CODEX_NOTIFICATION_METHODS.agentMessageDelta: {\n const n = params as AgentMessageDeltaNotification;\n return {\n kind: \"agent_message_delta\",\n threadId: n.threadId,\n turnId: n.turnId,\n itemId: n.itemId,\n delta: n.delta\n };\n }\n case CODEX_NOTIFICATION_METHODS.reasoningDelta:\n case CODEX_NOTIFICATION_METHODS.reasoningTextDelta: {\n const n = params as ReasoningTextDeltaNotification;\n return {\n kind: \"reasoning_delta\",\n threadId: n.threadId,\n turnId: n.turnId,\n itemId: n.itemId,\n delta: n.delta\n };\n }\n case CODEX_NOTIFICATION_METHODS.turnStarted: {\n const n = params as TurnStartedNotification;\n return { kind: \"turn_started\", threadId: n.threadId, turnId: n.turn.id };\n }\n case CODEX_NOTIFICATION_METHODS.turnCompleted: {\n const n = params as TurnCompletedNotification;\n return {\n kind: \"turn_completed\",\n threadId: n.threadId,\n turnId: n.turn.id,\n status: normalizeTurnStatus(n.turn.status)\n };\n }\n case CODEX_NOTIFICATION_METHODS.tokenUsage: {\n const n = params as ThreadTokenUsageUpdatedNotification;\n return {\n kind: \"token_usage\",\n threadId: n.threadId,\n turnId: n.turnId,\n usage: normalizeTokenUsage(n.tokenUsage)\n };\n }\n case CODEX_NOTIFICATION_METHODS.threadSettings: {\n const n = params as ThreadSettingsUpdatedNotification;\n return { kind: \"thread_settings\", settings: normalizeThreadSettings(n) };\n }\n case CODEX_NOTIFICATION_METHODS.modelRerouted: {\n const n = params as ModelReroutedNotification;\n return {\n kind: \"thread_settings\",\n settings: {\n threadId: n.threadId,\n model: n.toModel,\n modelProvider: \"openai\",\n serviceTier: null\n }\n };\n }\n case CODEX_NOTIFICATION_METHODS.itemStarted: {\n const n = params as ItemStartedNotification;\n if (isToolish(n.item)) {\n const call = normalizeThreadItemToolCall(n.item);\n if (call === null) return null;\n return { kind: \"tool_call\", threadId: n.threadId, turnId: n.turnId, toolCall: call };\n }\n return null;\n }\n case CODEX_NOTIFICATION_METHODS.itemCompleted: {\n const n = params as ItemCompletedNotification;\n const message = agentMessageFromItem(n.item);\n if (message !== null) {\n return {\n kind: \"agent_message\",\n threadId: n.threadId,\n turnId: n.turnId,\n message\n };\n }\n if (isToolish(n.item)) {\n const call = normalizeThreadItemToolCall(n.item);\n if (call === null) return null;\n return {\n kind: \"tool_call_update\",\n threadId: n.threadId,\n turnId: n.turnId,\n toolCall: toUpdate(call)\n };\n }\n return null;\n }\n case CODEX_NOTIFICATION_METHODS.error: {\n const p = (params ?? {}) as Record<string, unknown>;\n // ErrorNotification = { error: TurnError, willRetry, threadId, turnId }.\n // The authoritative reason rides `error` (a TurnError); format it. Fall\n // back to a bare `message` string for older/loose shapes.\n const message =\n \"error\" in p\n ? formatCodexTurnError(p.error as TurnError | null | undefined)\n : typeof p.message === \"string\"\n ? p.message\n : \"codex error\";\n const event: Extract<NormalizedThreadEvent, { kind: \"error\" }> = {\n kind: \"error\",\n message\n };\n if (typeof p.threadId === \"string\") event.threadId = p.threadId;\n if (typeof p.turnId === \"string\") event.turnId = p.turnId;\n if (typeof p.code === \"string\") event.code = p.code;\n if (typeof p.willRetry === \"boolean\") event.willRetry = p.willRetry;\n return event;\n }\n default:\n return null;\n }\n}\n","// Render a Codex `TurnError` into one human-readable transcript line. Ported\n// from PwrSnap (PR #194 \"surface Codex turn errors\") so the kit — which now owns\n// the controller — never drops a failed turn's cause. Never throws; always\n// returns a non-empty string usable directly as transcript text.\n\nimport type { TurnError } from \"@pwrdrvr/codex-app-server-protocol/v2\";\n\nconst FALLBACK = \"Codex returned an error\";\n\nexport function formatCodexTurnError(error: TurnError | null | undefined): string {\n if (!error) return FALLBACK;\n const base = extractMessage(error.message) || FALLBACK;\n const details = error.additionalDetails?.trim();\n if (details && details.length > 0 && !base.includes(details)) {\n return `${base} (${details})`;\n }\n return base;\n}\n\nfunction extractMessage(raw: string | null | undefined): string {\n if (typeof raw !== \"string\") return \"\";\n const trimmed = raw.trim();\n if (trimmed.length === 0) return \"\";\n // Best-effort: unwrap a nested provider-error JSON blob. Only attempt a parse\n // when the text actually looks like JSON — a plain message is the common case\n // and must pass through verbatim.\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n const nested = nestedErrorMessage(JSON.parse(trimmed));\n if (nested) return nested;\n } catch {\n // Not JSON after all — fall through to the raw text.\n }\n }\n return trimmed;\n}\n\nfunction nestedErrorMessage(value: unknown): string {\n if (typeof value !== \"object\" || value === null) return \"\";\n const obj = value as Record<string, unknown>;\n const err = obj.error;\n if (typeof err === \"object\" && err !== null) {\n const inner = (err as Record<string, unknown>).message;\n if (typeof inner === \"string\" && inner.trim().length > 0) {\n return inner.trim();\n }\n }\n const message = obj.message;\n return typeof message === \"string\" ? message.trim() : \"\";\n}\n","// One-shot Codex App Server client for structured-output enrichment turns.\n//\n// Drives a single short turn against a persistent worker thread: build a turn\n// with caller-supplied prompt + JSON Schema (`outputSchema`), feed optional\n// local images as file-path inputs, refuse any tool calls, await the assistant\n// message, then `thread/rollback` the turn so the worker thread stays clean for\n// the next request (a prompt-cache experiment from PwrSnap).\n//\n// Ported from PwrSnap's CodexAppServerClient with the product specifics removed:\n// • the prompt + JSON Schema + base instructions are CALLER-SUPPLIED per\n// request (no CAPTURE_ENRICHMENT_SCHEMA / capture prompt baked in);\n// • the logger is injected (agent-core `Logger`);\n// • identity (`clientInfo.name`, default `serviceName`) is parameterized;\n// • the binary is resolved via codex-discovery and spawned `[\"app-server\"]`.\n//\n// The result is the RAW assistant text plus token usage — parsing/validating\n// the JSON against the caller's schema is the caller's job.\n\nimport { mkdir } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n noopLogger,\n type Logger,\n type NormalizedTokenUsage\n} from \"@pwrdrvr/agent-core\";\nimport {\n JsonRpcConnection,\n StdioJsonRpcTransport,\n type JsonRpcTransport\n} from \"@pwrdrvr/agent-transport\";\nimport { resolveCodexCommand } from \"@pwrdrvr/codex-discovery\";\nimport type {\n InitializeParams,\n InitializeResponse,\n ResponseItem,\n ServerNotification\n} from \"@pwrdrvr/codex-app-server-protocol\";\nimport type {\n DynamicToolCallResponse,\n ItemCompletedNotification,\n Model,\n ModelListResponse,\n ThreadStartResponse,\n ThreadTokenUsage,\n ThreadTokenUsageUpdatedNotification,\n TurnCompletedNotification,\n TurnStartResponse,\n UserInput\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\nimport { normalizeTokenUsage } from \"./normalize\";\n\nexport type CodexOneShotTransportFactory = (command: string) => JsonRpcTransport;\n\nexport type CodexModelOption = {\n id: string;\n model: string;\n displayName: string;\n description: string;\n hidden: boolean;\n inputModalities: Model[\"inputModalities\"];\n defaultServiceTier: string | null;\n isDefault: boolean;\n};\n\nexport type CodexOneShotClientOptions = {\n command?: string;\n /** Identity sent as `clientInfo.name`. Defaults to \"agent-kit\". */\n clientName?: string;\n clientTitle?: string;\n clientVersion?: string;\n /** serviceName for the worker thread. Defaults to \"agent-kit\". */\n serviceName?: string;\n /** Working dir for the persistent worker thread (keeps it out of any repo). */\n workspaceDir?: string;\n /** Human-readable name set on the worker thread. */\n workerThreadName?: string;\n /** Per-thread Codex config overlay applied to the worker thread. */\n threadConfig?: Record<string, unknown>;\n requestTimeoutMs?: number;\n turnTimeoutMs?: number;\n env?: NodeJS.ProcessEnv;\n transportFactory?: CodexOneShotTransportFactory;\n logger?: Logger;\n};\n\nexport type CodexOneShotRequest = {\n /** The user-message text (the caller's prompt) for this turn. */\n prompt: string;\n /** Local image file paths fed as `localImage` inputs (not inlined as base64). */\n imagePaths?: readonly string[];\n /** JSON Schema constraining the final assistant message (`outputSchema`). */\n outputSchema?: unknown;\n /** Base instructions for the worker thread (set once; changing it re-creates\n * the worker thread). */\n baseInstructions?: string;\n /** Reasoning effort for the turn. Defaults to \"low\". */\n effort?: string;\n model?: string | null;\n /** Model provider (ThreadStartParams.modelProvider) for the worker thread.\n * Omit for the Codex default. Part of the worker-thread cache key. */\n modelProvider?: string | null;\n abortSignal?: AbortSignal;\n};\n\nexport type CodexOneShotResponse = {\n /** The raw assistant message text. Caller parses/validates against its schema. */\n rawText: string;\n threadId: string;\n turnId: string;\n userAgent: string;\n model: string;\n modelProvider: string;\n serviceTier: string | null;\n tokenUsage: NormalizedTokenUsage | null;\n};\n\ntype PendingTurn = {\n threadId: string;\n turnId: string;\n agentMessages: string[];\n tokenUsage: ThreadTokenUsage | null;\n resolve: (value: { rawText: string; tokenUsage: ThreadTokenUsage | null }) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\ntype WorkerThread = {\n threadId: string;\n modelKey: string;\n baseInstructions: string;\n model: string;\n modelProvider: string;\n serviceTier: string | null;\n};\n\nconst DEFAULT_CLIENT_NAME = \"agent-kit\";\nconst DEFAULT_SERVICE_NAME = \"agent-kit\";\n\nexport class CodexOneShotClient {\n private readonly requestTimeoutMs: number;\n private readonly turnTimeoutMs: number;\n private readonly logger: Logger;\n private readonly transportFactory: CodexOneShotTransportFactory | null;\n private resolvedCommand: string | null = null;\n private connection: JsonRpcConnection | null = null;\n private initializeResponse: InitializeResponse | null = null;\n private pendingTurn: PendingTurn | null = null;\n private workerThread: WorkerThread | null = null;\n private queue: Promise<void> = Promise.resolve();\n\n constructor(private readonly options: CodexOneShotClientOptions = {}) {\n this.requestTimeoutMs = options.requestTimeoutMs ?? 20_000;\n this.turnTimeoutMs = options.turnTimeoutMs ?? 120_000;\n this.logger = options.logger ?? noopLogger;\n this.transportFactory = options.transportFactory ?? null;\n }\n\n /** Run one structured-output turn. Calls are serialized — only one turn is in\n * flight at a time against the shared worker thread. */\n async run(request: CodexOneShotRequest): Promise<CodexOneShotResponse> {\n const run = this.queue.catch(() => undefined).then(() => this.runInner(request));\n this.queue = run.then(\n () => undefined,\n () => undefined\n );\n return run;\n }\n\n private async runInner(request: CodexOneShotRequest): Promise<CodexOneShotResponse> {\n const connection = await this.getConnection();\n const initialized = await this.initialize();\n let thread: WorkerThread | null = null;\n let turnId: string | null = null;\n let rolledBack = false;\n let aborted = false;\n\n const abortHandler = (): void => {\n aborted = true;\n if (thread && turnId) {\n void connection\n .request(\"turn/interrupt\", { threadId: thread.threadId, turnId }, this.requestTimeoutMs)\n .catch((error: unknown) => {\n this.logger.warn(\"turn interrupt failed\", {\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n };\n\n request.abortSignal?.addEventListener(\"abort\", abortHandler, { once: true });\n\n try {\n if (request.abortSignal?.aborted) {\n throw new DOMException(\"one-shot turn aborted\", \"AbortError\");\n }\n\n thread = await this.getWorkerThread(\n request.model ?? null,\n request.modelProvider ?? null,\n request.baseInstructions ?? \"\"\n );\n\n const input: UserInput[] = [\n { type: \"text\", text: request.prompt, text_elements: [] },\n ...imagePathsToLocalImageInputs(request.imagePaths ?? [])\n ];\n\n const turnResponse = (await connection.request(\n \"turn/start\",\n {\n threadId: thread.threadId,\n model: request.model ?? null,\n input,\n effort: request.effort ?? \"low\",\n ...(request.outputSchema !== undefined ? { outputSchema: request.outputSchema } : {})\n },\n this.requestTimeoutMs\n )) as TurnStartResponse;\n turnId = turnResponse.turn.id;\n\n if (request.abortSignal?.aborted || aborted) {\n throw new DOMException(\"one-shot turn aborted\", \"AbortError\");\n }\n\n const { rawText, tokenUsage } = await this.waitForTurn(thread.threadId, turnId);\n await this.rollbackWorkerThread(thread.threadId);\n rolledBack = true;\n return {\n rawText,\n threadId: thread.threadId,\n turnId,\n userAgent: initialized.userAgent,\n model: thread.model,\n modelProvider: thread.modelProvider,\n serviceTier: thread.serviceTier,\n tokenUsage: tokenUsage === null ? null : normalizeTokenUsage(tokenUsage)\n };\n } finally {\n request.abortSignal?.removeEventListener(\"abort\", abortHandler);\n if (thread && turnId && !rolledBack) {\n await this.rollbackWorkerThread(thread.threadId).catch((error: unknown) => {\n this.logger.warn(\"worker thread rollback failed\", {\n threadId: thread?.threadId,\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n }\n }\n\n async listModels(input: { includeHidden?: boolean } = {}): Promise<CodexModelOption[]> {\n const connection = await this.getConnection();\n await this.initialize();\n const models: CodexModelOption[] = [];\n let cursor: string | null = null;\n do {\n const response = (await connection.request(\n \"model/list\",\n { cursor, limit: 100, includeHidden: input.includeHidden ?? false },\n this.requestTimeoutMs\n )) as ModelListResponse;\n models.push(...response.data.map(modelToOption));\n cursor = response.nextCursor;\n } while (cursor !== null);\n return models;\n }\n\n async close(): Promise<void> {\n const connection = this.connection;\n const thread = this.workerThread;\n this.connection = null;\n this.initializeResponse = null;\n this.workerThread = null;\n this.queue = Promise.resolve();\n if (connection) {\n if (thread) {\n await connection\n .request(\"thread/archive\", { threadId: thread.threadId }, this.requestTimeoutMs)\n .catch((error: unknown) => {\n this.logger.warn(\"thread archive failed\", {\n threadId: thread.threadId,\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n await connection.close();\n }\n }\n\n // ---- worker-thread management ----\n\n private async getWorkerThread(\n model: string | null,\n modelProvider: string | null,\n baseInstructions: string\n ): Promise<WorkerThread> {\n const modelKey = `${model ?? \"__default__\"}@${modelProvider ?? \"__default__\"}::${baseInstructions}`;\n if (this.workerThread?.modelKey === modelKey) {\n return this.workerThread;\n }\n if (this.workerThread) {\n const stale = this.workerThread;\n this.workerThread = null;\n const connection = await this.getConnection();\n await connection\n .request(\"thread/archive\", { threadId: stale.threadId }, this.requestTimeoutMs)\n .catch((error: unknown) => {\n this.logger.warn(\"thread archive failed\", {\n threadId: stale.threadId,\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n\n const connection = await this.getConnection();\n const workspaceDir = await this.prepareWorkspace();\n const threadResponse = (await connection.request(\n \"thread/start\",\n {\n model,\n ...(modelProvider !== null ? { modelProvider } : {}),\n ephemeral: false,\n cwd: workspaceDir,\n runtimeWorkspaceRoots: [workspaceDir],\n serviceName: this.options.serviceName ?? DEFAULT_SERVICE_NAME,\n approvalPolicy: \"never\",\n sandbox: \"read-only\",\n ...(baseInstructions.length > 0 ? { baseInstructions } : {}),\n // Persistent worker thread for a prompt-cache experiment: keep the\n // thread id stable across requests, then roll back each turn. The\n // dedicated cwd keeps the worker out of any host repo/worktree.\n ...(this.options.threadConfig !== undefined ? { config: this.options.threadConfig } : {}),\n environments: [],\n experimentalRawEvents: false,\n persistExtendedHistory: false\n },\n this.requestTimeoutMs\n )) as ThreadStartResponse;\n await this.clearThreadGitInfo(threadResponse.thread.id);\n await this.setWorkerThreadName(threadResponse.thread.id);\n this.workerThread = {\n threadId: threadResponse.thread.id,\n modelKey,\n baseInstructions,\n model: threadResponse.model,\n modelProvider: threadResponse.modelProvider,\n serviceTier: threadResponse.serviceTier\n };\n return this.workerThread;\n }\n\n private async rollbackWorkerThread(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await connection.request(\"thread/rollback\", { threadId, numTurns: 1 }, this.requestTimeoutMs);\n }\n\n private async prepareWorkspace(): Promise<string> {\n const workspaceDir =\n this.options.workspaceDir ?? join(tmpdir(), \"agent-kit\", \"oneshot-worker\");\n await mkdir(workspaceDir, { recursive: true });\n return workspaceDir;\n }\n\n private async clearThreadGitInfo(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await connection\n .request(\n \"thread/metadata/update\",\n { threadId, gitInfo: { sha: null, branch: null, originUrl: null } },\n this.requestTimeoutMs\n )\n .catch((error: unknown) => {\n this.logger.warn(\"thread git metadata clear failed\", {\n threadId,\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n\n private async setWorkerThreadName(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await connection\n .request(\n \"thread/name/set\",\n { threadId, name: this.options.workerThreadName ?? \"agent-kit One-Shot Worker\" },\n this.requestTimeoutMs\n )\n .catch((error: unknown) => {\n this.logger.warn(\"worker thread name set failed\", {\n threadId,\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n\n // ---- connection / turn plumbing ----\n\n private async resolveCommand(): Promise<string> {\n if (this.resolvedCommand !== null) return this.resolvedCommand;\n const resolved = await resolveCodexCommand({\n command: this.options.command ?? \"codex\",\n env: this.options.env ?? process.env\n });\n this.resolvedCommand = resolved.command;\n return resolved.command;\n }\n\n private async initialize(): Promise<InitializeResponse> {\n if (this.initializeResponse) return this.initializeResponse;\n const connection = await this.getConnection();\n const name = this.options.clientName ?? DEFAULT_CLIENT_NAME;\n const params: InitializeParams = {\n clientInfo: {\n name,\n title: this.options.clientTitle ?? name,\n version: this.options.clientVersion ?? \"0.0.0\"\n },\n capabilities: {\n experimentalApi: true,\n requestAttestation: false\n }\n };\n const response = (await connection.request(\n \"initialize\",\n params,\n this.requestTimeoutMs\n )) as InitializeResponse;\n this.initializeResponse = response;\n return response;\n }\n\n private async getConnection(): Promise<JsonRpcConnection> {\n if (this.connection) return this.connection;\n\n let transport: JsonRpcTransport;\n if (this.transportFactory !== null) {\n transport = this.transportFactory(this.options.command ?? \"codex\");\n } else {\n const command = await this.resolveCommand();\n transport = new StdioJsonRpcTransport({\n command,\n args: [\"app-server\"],\n ...(this.options.env !== undefined ? { env: this.options.env } : {}),\n logger: this.logger\n });\n }\n\n const connection = new JsonRpcConnection(transport, this.requestTimeoutMs, undefined, {\n logger: this.logger,\n logContext: { owner: \"codex-oneshot-client\" }\n });\n connection.setNotificationHandler((method, params) => {\n this.handleNotification(method, params);\n });\n connection.setRequestHandler((method, params) => this.handleServerRequest(method, params));\n await connection.connect();\n this.connection = connection;\n return connection;\n }\n\n private waitForTurn(\n threadId: string,\n turnId: string\n ): Promise<{ rawText: string; tokenUsage: ThreadTokenUsage | null }> {\n if (this.pendingTurn) {\n throw new Error(\"codex one-shot client already has an active turn\");\n }\n\n return new Promise<{ rawText: string; tokenUsage: ThreadTokenUsage | null }>(\n (resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingTurn = null;\n reject(new Error(\"codex one-shot turn timed out\"));\n }, this.turnTimeoutMs);\n this.pendingTurn = {\n threadId,\n turnId,\n agentMessages: [],\n tokenUsage: null,\n resolve,\n reject,\n timer\n };\n }\n );\n }\n\n private handleNotification(method: string, params: unknown): void {\n if (method === \"item/completed\") {\n this.handleItemCompleted(params as ItemCompletedNotification);\n return;\n }\n if (method === \"rawResponseItem/completed\") {\n this.handleRawResponseItemCompleted(params as ServerNotification[\"params\"]);\n return;\n }\n if (method === \"thread/tokenUsage/updated\") {\n this.handleThreadTokenUsageUpdated(params as ThreadTokenUsageUpdatedNotification);\n return;\n }\n if (method === \"turn/completed\") {\n this.handleTurnCompleted(params as TurnCompletedNotification);\n }\n }\n\n private handleItemCompleted(params: ItemCompletedNotification): void {\n const pending = this.pendingTurn;\n if (!pending || params.threadId !== pending.threadId || params.turnId !== pending.turnId) {\n return;\n }\n if (params.item.type === \"agentMessage\") {\n pending.agentMessages.push(params.item.text);\n }\n }\n\n private handleRawResponseItemCompleted(params: ServerNotification[\"params\"]): void {\n const pending = this.pendingTurn;\n if (!pending || typeof params !== \"object\" || params === null) {\n return;\n }\n const maybe = params as { threadId?: unknown; turnId?: unknown; item?: ResponseItem };\n if (maybe.threadId !== pending.threadId || maybe.turnId !== pending.turnId) {\n return;\n }\n const item = maybe.item;\n if (item?.type !== \"message\" || item.role !== \"assistant\") {\n return;\n }\n const text = item.content\n .filter((content) => content.type === \"output_text\")\n .map((content) => content.text)\n .join(\"\");\n if (text) {\n pending.agentMessages.push(text);\n }\n }\n\n private handleTurnCompleted(params: TurnCompletedNotification): void {\n const pending = this.pendingTurn;\n if (!pending || params.threadId !== pending.threadId || params.turn.id !== pending.turnId) {\n return;\n }\n\n clearTimeout(pending.timer);\n this.pendingTurn = null;\n\n if (params.turn.status === \"failed\") {\n pending.reject(new Error(params.turn.error?.message ?? \"codex one-shot turn failed\"));\n return;\n }\n if (params.turn.status === \"interrupted\") {\n pending.reject(new DOMException(\"one-shot turn aborted\", \"AbortError\"));\n return;\n }\n\n const rawText = pending.agentMessages.at(-1)?.trim();\n if (!rawText) {\n pending.reject(new Error(\"codex one-shot turn returned no assistant message\"));\n return;\n }\n pending.resolve({ rawText, tokenUsage: pending.tokenUsage });\n }\n\n private handleThreadTokenUsageUpdated(params: ThreadTokenUsageUpdatedNotification): void {\n const pending = this.pendingTurn;\n if (!pending || params.threadId !== pending.threadId || params.turnId !== pending.turnId) {\n return;\n }\n pending.tokenUsage = params.tokenUsage;\n }\n\n private async handleServerRequest(method: string, _params: unknown): Promise<unknown> {\n if (method === \"item/tool/call\") {\n // One-shot enrichment exposes no tools — refuse any tool call.\n return {\n contentItems: [\n { type: \"inputText\", text: \"This one-shot run does not expose tools.\" }\n ],\n success: false\n } satisfies DynamicToolCallResponse;\n }\n this.logger.debug(\"unhandled codex server request\", { method });\n return {};\n }\n}\n\nfunction modelToOption(model: Model): CodexModelOption {\n return {\n id: model.id,\n model: model.model,\n displayName: model.displayName,\n description: model.description,\n hidden: model.hidden,\n inputModalities: model.inputModalities,\n defaultServiceTier: model.defaultServiceTier,\n isDefault: model.isDefault\n };\n}\n\nfunction imagePathsToLocalImageInputs(imagePaths: readonly string[]): UserInput[] {\n // `localImage` lets App Server read the file as an image input. Do NOT inline a\n // base64 data URL — the bridge can account that payload like fresh text.\n return imagePaths.map((path) => ({ type: \"localImage\", path }));\n}\n","// A per-thread Codex config overlay that disables Codex's coding-agent prompt\n// and hosted-tool scaffolding, so an App Server thread is scoped to the host's\n// own surfaces (chat, enrichment) instead of inheriting the full coding agent.\n//\n// Pass this as `config` at `thread/start` (the `-c key=value` mechanism). Empty\n// `environments: []` is still required separately at thread/start to drop the\n// env-gated shell / unified_exec / apply_patch builtins.\n\n/**\n * Generic \"disable coding-agent scaffolding\" config overlay. Hosts spread this\n * into `CodexStartThreadOptions.config` (optionally merging their own keys).\n */\nexport const DISABLE_CODING_AGENT_THREAD_CONFIG: Record<string, unknown> = {\n web_search: \"disabled\",\n include_permissions_instructions: false,\n include_apps_instructions: false,\n include_collaboration_mode_instructions: false,\n include_environment_context: false,\n skills: {\n include_instructions: false\n },\n features: {\n apps: false,\n plugins: false,\n tool_suggest: false,\n image_generation: false,\n multi_agent: false,\n goals: false\n }\n};\n","// Type-safe tool-definition primitive for a host's chat tool catalog.\n//\n// A host exposes its tool catalog to Codex as `DynamicToolSpec[]` (registered\n// at `thread/start`). Each `ToolSpec` pairs an agent-readable description + a\n// zod argument schema (the audit surface) with a single `dispatch` body the\n// host injects (it runs whatever the host wants — a command bus, an RPC, a\n// direct call). The kit never imports any concrete dispatch target.\n//\n// `defineTool` is an identity helper: it preserves each call site's `TArgs`\n// inference (the `argsSchema`'s inferred type flows into the `dispatch` body)\n// so the host never writes `any`. At the catalog boundary the type parameter is\n// erased to `AnyToolSpec` (see below): a catalog mixes tools with different\n// `TArgs`, and `ToolSpec<TArgs>` is contravariant in `TArgs` via `dispatch`, so\n// `ToolSpec<{a:number}>` is NOT assignable to `ToolSpec<unknown>`. Erasing to\n// `any` at the boundary is sound because `dispatchToolCall` zod-validates the\n// arguments at runtime before the typed `dispatch` body ever sees them.\n\nimport { z } from \"zod\";\nimport type {\n DynamicToolCallOutputContentItem,\n DynamicToolSpec\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\n\n/**\n * Result of a tool `dispatch`. The agent only ever sees text or image content,\n * so a structured host error is collapsed to a plain string at this boundary.\n */\nexport type ToolDispatchResult =\n | { ok: true; data: unknown }\n // For tools that return rich content the agent must SEE rather than read as\n // JSON (e.g. an `inputImage` data URL), pass content items through verbatim\n // instead of JSON-stringifying.\n | { ok: true; contentItems: DynamicToolCallOutputContentItem[] }\n | { ok: false; error: string };\n\n/**\n * One chat tool. The single audit unit: description (what the agent reads),\n * `argsSchema` (what the agent must satisfy — validated before dispatch), and\n * `dispatch` (the host-injected body it resolves to).\n */\nexport type ToolSpec<TArgs> = {\n /** Namespace this tool lives under; matched against `DynamicToolCallParams.namespace`. */\n namespace: string;\n /** snake_case agent-facing name, e.g. \"library_list\". */\n name: string;\n /** Agent-readable, terse. Shown verbatim to Codex. */\n description: string;\n /** zod schema for the tool arguments; also the source of `inputSchema`. */\n argsSchema: z.ZodType<TArgs>;\n /**\n * Behaviour hints surfaced to the agent / approval UI. Optional per tool;\n * omit (rather than set `undefined`) when not applicable —\n * `exactOptionalPropertyTypes` is on.\n */\n annotations?: {\n destructiveHint?: boolean;\n readOnlyHint?: boolean;\n idempotentHint?: boolean;\n };\n /**\n * The host-injected dispatch this tool resolves to. Receives the zod-validated\n * args (typed as `TArgs`) plus the calling thread id.\n */\n dispatch: (args: TArgs, ctx: { threadId: string }) => Promise<ToolDispatchResult>;\n};\n\n/**\n * Identity helper that preserves `TArgs` inference at each call site, so a\n * tool's `dispatch` body is fully type-checked against its own `argsSchema`\n * without any cast.\n */\nexport function defineTool<TArgs>(spec: ToolSpec<TArgs>): ToolSpec<TArgs> {\n return spec;\n}\n\n/**\n * A `ToolSpec` with its argument type erased — the shape a heterogeneous catalog\n * holds. `defineTool(...)`'s typed result is assignable to this, so a host writes\n * `[defineTool(a), defineTool(b)]` and passes it straight to `buildToolCatalog` /\n * `dispatchToolCall`. Args are validated at runtime, so the erasure is safe.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyToolSpec = ToolSpec<any>;\n\n/**\n * Convert a `ToolSpec` into the protocol `DynamicToolSpec` registered with Codex\n * at `thread/start`. The `inputSchema` is derived from the tool's zod\n * `argsSchema` via zod v4's `z.toJSONSchema()` (JSON Schema draft 2020-12).\n */\nexport function toDynamicToolSpec(spec: AnyToolSpec): DynamicToolSpec {\n return {\n namespace: spec.namespace,\n name: spec.name,\n description: spec.description,\n inputSchema: z.toJSONSchema(spec.argsSchema) as DynamicToolSpec[\"inputSchema\"]\n };\n}\n","// Generic catalog-builder + dispatcher derived from a host-supplied `ToolSpec[]`.\n//\n// • `buildToolCatalog()` — the `DynamicToolSpec[]` a host registers with Codex\n// at `thread/start`.\n// • `dispatchToolCall()` — routes an incoming `DynamicToolCallParams` back to\n// its matching tool: matches namespace + name, zod-validates the arguments,\n// runs the tool's injected dispatch, and wraps the outcome as a\n// `DynamicToolCallResponse`.\n//\n// Failure policy: NEVER throw across the tool-call boundary. Unknown tool,\n// namespace mismatch, bad arguments, and dispatch errors all return\n// `{ success: false }` with a text contentItem describing the problem, so the\n// agent can self-correct on its next turn.\n\nimport { z } from \"zod\";\nimport type {\n DynamicToolCallParams,\n DynamicToolCallResponse,\n DynamicToolSpec\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\nimport type { AnyToolSpec } from \"./define-tool\";\nimport { toDynamicToolSpec } from \"./define-tool\";\n\n/**\n * Build the `DynamicToolSpec[]` registered with Codex at `thread/start`. Pure\n * projection of the catalog — an empty catalog yields an empty spec list.\n */\nexport function buildToolCatalog(catalog: ReadonlyArray<AnyToolSpec>): DynamicToolSpec[] {\n return catalog.map(toDynamicToolSpec);\n}\n\n/**\n * Route an incoming `DynamicToolCallParams` to its catalog entry and run it.\n * Always resolves — never throws — so a malformed or unknown call comes back as\n * a `success: false` response the agent can recover from.\n */\nexport async function dispatchToolCall(\n params: DynamicToolCallParams,\n catalog: ReadonlyArray<AnyToolSpec>\n): Promise<DynamicToolCallResponse> {\n const entry = catalog.find((tool) => tool.name === params.tool);\n if (entry === undefined) {\n return errorResponse(`Unknown tool: ${params.tool}`);\n }\n\n // `namespace` is `string | null` on the wire. Accept a missing/null namespace\n // (Codex may omit it) but reject an explicit mismatch.\n if (params.namespace !== null && params.namespace !== entry.namespace) {\n return errorResponse(`Tool \"${params.tool}\" is not in namespace \"${params.namespace}\".`);\n }\n\n const parsed = entry.argsSchema.safeParse(params.arguments);\n if (!parsed.success) {\n return errorResponse(`Invalid arguments for \"${params.tool}\": ${formatZodError(parsed.error)}`);\n }\n\n let result: Awaited<ReturnType<AnyToolSpec[\"dispatch\"]>>;\n try {\n result = await entry.dispatch(parsed.data, { threadId: params.threadId });\n } catch (cause) {\n return errorResponse(\n `Tool \"${params.tool}\" failed: ${cause instanceof Error ? cause.message : String(cause)}`\n );\n }\n\n if (!result.ok) {\n return errorResponse(result.error);\n }\n\n // A tool that returns pre-built content items (e.g. an inputImage) passes them\n // through verbatim so the model SEES the content rather than a JSON blob.\n if (\"contentItems\" in result) {\n return { success: true, contentItems: result.contentItems };\n }\n\n return {\n success: true,\n contentItems: [{ type: \"inputText\", text: JSON.stringify(result.data) }]\n };\n}\n\nfunction errorResponse(message: string): DynamicToolCallResponse {\n return {\n success: false,\n contentItems: [{ type: \"inputText\", text: message }]\n };\n}\n\nfunction formatZodError(error: z.ZodError): string {\n return error.issues\n .map((issue) => {\n const path = issue.path.join(\".\");\n return path.length > 0 ? `${path}: ${issue.message}` : issue.message;\n })\n .join(\"; \");\n}\n","// The CANONICAL, backend-agnostic chat controller for agent-kit.\n//\n// Ties together a shared `AgentBackend` (one connection, many threads — Codex\n// App Server OR an ACP agent, driven identically), an injected agent-core\n// `ThreadStore` (thread index + per-turn journal + usage accounting), and a\n// host-supplied tool catalog + prompt builders. It owns orchestration + the\n// method surface (createThread / listThreads / rename / archive / sendMessage /\n// getHistory / interrupt / resolveApproval / wire); the host owns storage and\n// maps the controller's `ChatControllerEvent`s to its own IPC.\n//\n// Ported from PwrSnap's ChatThreadController with every product seam broken:\n// • persistence is the injected `ThreadStore` (no better-sqlite3, no\n// saveAiThreadUsage / estimateAiUsageCost import — the host computes cost in\n// its store impl via `recordUsage`);\n// • the backend is an `AgentBackend` (not a concrete CodexThreadClient), and\n// the controller subscribes via `backend.onEvent((e) => …)` switching on\n// `e.kind` instead of six granular per-event hooks;\n// • the catalog, `dispatchToolCall`, `buildSystemPrompt`, `buildTurnContext`,\n// and `broadcast` are all injected — no command bus, no PwrSnap tools or\n// typed event channels; `broadcast` takes a single neutral\n// `ChatControllerEvent`;\n// • `Settings` is generic (`TSettings`); the controller freezes a snapshot at\n// turn start and forwards it to the prompt builder, NEVER inspecting fields.\n//\n// Load-bearing design (preserved verbatim from PwrSnap):\n// • Per-thread TurnState in a Map, NEVER a singleton — two threads can stream\n// concurrently without cross-wiring.\n// • Settings are SNAPSHOTTED at turn start; a mid-turn change does not\n// retro-apply to the in-flight turn.\n// • Approvals carry (threadId, turnId, approvalId); a late / mismatched\n// resolution is rejected, never resolves the wrong turn.\n// • The host UI is a VIEW of this controller's state — all mutation flows out\n// via the `broadcast` seam.\n\nimport {\n noopLogger,\n type AgentBackend,\n type AgentBackendToolCall,\n type AgentForkThreadOptions,\n type AgentStartThreadOptions,\n type AgentStartTurnOptions,\n type AgentTurnInput,\n type Logger,\n type NormalizedApprovalDecision,\n type NormalizedApprovalRequest,\n type NormalizedMessage,\n type NormalizedThreadEvent,\n type NormalizedThreadRecord,\n type NormalizedThreadStatus,\n type NormalizedThreadView,\n type NormalizedTokenUsage,\n type NormalizedToolCall,\n type NormalizedToolCallUpdate,\n type NormalizedTurnStatus,\n type ThreadListOptions,\n type ThreadStore,\n mergeToolCall\n} from \"@pwrdrvr/agent-core\";\nimport type {\n DynamicToolCallParams,\n DynamicToolCallResponse,\n DynamicToolSpec\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\n\n/** The backend the controller drives. Codex (`CodexThreadClient`) and ACP\n * (`AcpAgentClient`) both implement the non-generic `AgentBackend`; the\n * controller builds NEUTRAL thread/turn options, so any backend drops in\n * identically with no per-backend branching. Retained as an alias to\n * `AgentBackend` so existing hosts that name `ChatBackend` keep compiling. */\nexport type ChatBackend = AgentBackend;\n\n/** Builds the per-thread system prompt (base + host guidance). Injected as\n * `baseInstructions` at thread/start. Receives the frozen settings snapshot and\n * the thread's anchor; the controller never inspects `TSettings`. */\nexport type ChatSystemPromptBuilder<TSettings = unknown> = (input: {\n settings: TSettings;\n anchorId: string | null;\n}) => string;\n\n/**\n * The neutral event union the controller broadcasts. The host maps these to its\n * own IPC. Surface-agnostic: a library-chat host and a sizzle-chat host map the\n * same union. Generalizes PwrSnap's six typed `events:*Chat:*` channels.\n */\nexport type ChatControllerEvent =\n | { type: \"thread_updated\"; thread: NormalizedThreadView }\n | { type: \"stream_delta\"; threadId: string; turnId: string; messageId: string; delta: string }\n | { type: \"tool_call\"; threadId: string; turnId: string; toolCall: NormalizedToolCall }\n | { type: \"message_committed\"; threadId: string; message: NormalizedMessage }\n | { type: \"turn_interrupted\"; threadId: string; turnId: string }\n | {\n type: \"approval_requested\";\n threadId: string;\n turnId: string;\n approval: NormalizedApprovalRequest;\n };\n\n/** Re-broadcasts the controller's neutral event stream to the host's UI. */\nexport type ChatBroadcast = (event: ChatControllerEvent) => void;\n\n/** Friendly present-tense labels for tool activity chips, keyed by tool name. */\nexport type ToolLabelMap = Record<string, string>;\n\nexport type ChatThreadControllerDeps<TSettings = unknown> = {\n /** The shared backend (Codex or ACP). */\n client: ChatBackend;\n /** Host persistence: thread index + per-turn journal + usage accounting. */\n store: ThreadStore;\n /** Reads the current host settings snapshot (frozen per turn). */\n readSettings: () => Promise<TSettings>;\n /** Re-broadcasts neutral controller events to the host UI. */\n broadcast: ChatBroadcast;\n /** Builds the per-thread system prompt. */\n buildSystemPrompt: ChatSystemPromptBuilder<TSettings>;\n /** Per-turn runtime context (L3), sent as a leading turn item framed as\n * system-generated — never folded into the user's message. Receives the\n * turn's anchor. Omit for no per-turn context. */\n buildTurnContext?: (anchor: string) => string;\n /** DynamicToolSpec[] registered on every thread/start. */\n catalog?: DynamicToolSpec[];\n /** Routes an incoming tool call to the host's tools. Defaults to a no-tools\n * responder when omitted. */\n dispatchToolCall?: (params: DynamicToolCallParams) => Promise<DynamicToolCallResponse>;\n /** Friendly chip labels for tool activity. */\n toolLabels?: ToolLabelMap;\n /** Default-Access policy applied to every chat thread. */\n approvalPolicy?: string;\n sandbox?: string;\n /** Default serviceName for thread/start. */\n serviceName?: string;\n /** Per-thread Codex config overlay applied on every thread/start. */\n threadConfig?: Record<string, unknown>;\n /** Thread environments. `[]` disables exec-environment access. */\n threadEnvironments?: unknown[];\n /** Reasoning effort for turns. Defaults to \"medium\". */\n effort?: string;\n /** Default model id for thread/start (host's per-surface default). Omit for Codex default. */\n model?: string;\n /** Default model provider for thread/start — the \"provider\" a host picks when\n * more than one is configured. Omit for Codex default. */\n modelProvider?: string;\n logger?: Logger;\n /** Injectable clock for tests. */\n now?: () => number;\n};\n\n/** Per-thread, in-flight turn state. */\ntype TurnState<TSettings> = {\n turnId: string;\n assistantMessageId: string;\n /** Accumulated streamed text for the in-flight assistant message. */\n buffer: string;\n /** Frozen at turn start — a mid-turn settings change can't retro-apply. */\n settingsSnapshot: TSettings;\n tokenUsage: NormalizedTokenUsage | null;\n /** Set when the backend emits an `error` for this turn. Surfaced in the\n * committed (failed) assistant message so the transcript shows WHY. */\n lastError: string | null;\n};\n\ntype ThreadModelState = {\n model: string | null;\n modelProvider: string | null;\n serviceTier: string | null;\n};\n\n/** A pending approval awaiting the host's decision. */\ntype PendingApproval = {\n threadId: string;\n turnId: string;\n approvalId: string;\n resolve: (decision: NormalizedApprovalDecision) => void;\n};\n\n/** One journal entry: a committed chat message. */\ntype JournalMessageEntry = { kind: \"message\"; message: NormalizedMessage };\n\nconst RATE_LIMIT_TURNS = 5;\nconst RATE_LIMIT_WINDOW_MS = 60_000;\n\n/** The committed assistant message text. The streamed buffer is always carried\n * (a turn can fault after streaming partial text). For a FAILED turn the\n * recorded error is appended so the transcript shows WHY it failed — folded\n * under the buffer when there's prose, else standing alone. */\nfunction buildFinalText(\n status: NormalizedTurnStatus,\n buffer: string,\n lastError: string | null\n): string {\n const errorText =\n status === \"failed\" && lastError !== null && lastError.trim().length > 0\n ? lastError.trim()\n : null;\n if (errorText === null) return buffer;\n return buffer.trim().length > 0 ? `${buffer.trimEnd()}\\n\\n${errorText}` : errorText;\n}\n\nexport class ChatThreadController<TSettings = unknown> {\n private readonly deps: ChatThreadControllerDeps<TSettings>;\n private readonly logger: Logger;\n private readonly turns = new Map<string, TurnState<TSettings>>();\n private readonly pendingApprovals = new Map<string, PendingApproval>();\n /** Per-thread recent turn timestamps for rate limiting. */\n private readonly turnTimestamps = new Map<string, number[]>();\n private readonly threadModels = new Map<string, ThreadModelState>();\n /** Accumulates streamed `tool_call`/`tool_call_update` events by id so the\n * full call can be surfaced once it reaches a terminal status (ACP backends\n * stream pending → in_progress → completed for tools they run themselves /\n * via MCP, unlike the Codex `onToolCall` request seam). Keyed by toolCall id. */\n private readonly streamedToolCalls = new Map<string, NormalizedToolCall>();\n private wired = false;\n\n constructor(deps: ChatThreadControllerDeps<TSettings>) {\n this.deps = deps;\n this.logger = deps.logger ?? noopLogger;\n }\n\n /** Wire the shared backend's subscription hooks ONCE. Idempotent. */\n wire(): void {\n if (this.wired) return;\n this.wired = true;\n const { client } = this.deps;\n client.onEvent((event) => this.onBackendEvent(event));\n client.onToolCall((call) => this.onToolCall(call));\n client.onApprovalRequest((method, params) => this.onApprovalRequest(method, params));\n }\n\n private now(): number {\n return this.deps.now ? this.deps.now() : Date.now();\n }\n\n // ---- thread lifecycle ----\n\n async createThread(\n opts: { name?: string; anchorId?: string | null } = {}\n ): Promise<NormalizedThreadView> {\n const anchorId = opts.anchorId ?? null;\n const settings = await this.deps.readSettings();\n const baseInstructions = this.deps.buildSystemPrompt({ settings, anchorId });\n const displayName =\n opts.name && opts.name.trim().length > 0 ? opts.name.trim() : this.defaultName();\n\n const preparedDir = await this.deps.store.prepareThreadDir(displayName);\n\n // NEUTRAL thread-open options. Every backend maps these onto its native\n // protocol internally — the controller never builds a Codex- or ACP-shaped\n // payload. `tools` is opaque (a Codex backend casts to DynamicToolSpec[];\n // ACP ignores it).\n const startOptions: AgentStartThreadOptions = {\n instructions: baseInstructions,\n cwd: preparedDir.path,\n workspaceRoots: [preparedDir.path]\n };\n if (this.deps.approvalPolicy !== undefined) startOptions.approvalPolicy = this.deps.approvalPolicy;\n if (this.deps.sandbox !== undefined) startOptions.sandbox = this.deps.sandbox;\n if (this.deps.model !== undefined) startOptions.model = this.deps.model;\n if (this.deps.modelProvider !== undefined) startOptions.modelProvider = this.deps.modelProvider;\n if (this.deps.serviceName !== undefined) startOptions.serviceName = this.deps.serviceName;\n if (this.deps.catalog !== undefined) startOptions.tools = this.deps.catalog;\n if (this.deps.threadConfig !== undefined) startOptions.config = this.deps.threadConfig;\n if (this.deps.threadEnvironments !== undefined) {\n startOptions.environments = this.deps.threadEnvironments;\n }\n\n let started: { threadId: string } & Partial<ThreadModelState>;\n try {\n started = await this.deps.client.startThread(startOptions);\n } catch (cause) {\n await this.deps.store.discardPreparedThreadDir(preparedDir).catch(() => undefined);\n throw cause;\n }\n\n await this.deps.client.clearThreadGitInfo?.(started.threadId).catch((cause) => {\n this.logger.warn(\"chat thread git metadata clear failed\", {\n threadId: started.threadId,\n message: cause instanceof Error ? cause.message : String(cause)\n });\n });\n\n this.threadModels.set(started.threadId, {\n model: started.model ?? null,\n modelProvider: started.modelProvider ?? null,\n serviceTier: started.serviceTier ?? null\n });\n\n // Glue the thread to the subject it was started from. Null anchor = an\n // unscoped thread. The anchor is written in the SAME insert as the rest of\n // the row — one write, not create-then-update.\n const record = await this.deps.store.create({\n threadId: started.threadId,\n name: displayName,\n anchorId,\n preparedDir\n });\n const view = this.toView(record);\n this.deps.broadcast({ type: \"thread_updated\", thread: view });\n return view;\n }\n\n async listThreads(\n opts: { includeArchived?: boolean; anchorId?: string | null } = {}\n ): Promise<NormalizedThreadView[]> {\n // Filtering (archived + anchor scoping) is pushed into the store's indexed\n // query — no full scan in the controller. When an anchor is supplied the list\n // is scoped to that subject's threads; when omitted, every anchor is listed.\n const listOpts: ThreadListOptions = {\n includeArchived: opts.includeArchived ?? false,\n ...(opts.anchorId !== undefined ? { anchorId: opts.anchorId } : {})\n };\n const records = await this.deps.store.list(listOpts);\n return records.map((r) => this.toView(r));\n }\n\n async rename(threadId: string, name: string): Promise<NormalizedThreadView> {\n const record = await this.deps.store.update(threadId, { name: name.trim() });\n const view = this.toView(record);\n this.deps.broadcast({ type: \"thread_updated\", thread: view });\n return view;\n }\n\n async archive(threadId: string, archived: boolean): Promise<NormalizedThreadView> {\n const record = await this.deps.store.update(threadId, { archived });\n if (archived) await this.deps.client.archiveThread?.(threadId).catch(() => undefined);\n const view = this.toView(record);\n this.deps.broadcast({ type: \"thread_updated\", thread: view });\n return view;\n }\n\n /** Fork every non-archived thread anchored to `sourceAnchorId` into fresh\n * threads anchored to `targetAnchorId`, carrying each source's journal — used\n * when a host duplicates a subject (e.g. a Sizzle reel) so its chats come\n * along. Requires a backend that supports forking (Codex `thread/fork`);\n * throws on a backend (ACP) that doesn't. */\n async forkThreadsForAnchor(input: {\n sourceAnchorId: string;\n targetAnchorId: string;\n }): Promise<NormalizedThreadView[]> {\n const client = this.deps.client;\n if (client.forkThread === undefined) {\n throw new Error(\"the active backend does not support forking threads\");\n }\n const forkThread = client.forkThread.bind(client);\n\n const sourceThreads = await this.deps.store.list({\n includeArchived: false,\n anchorId: input.sourceAnchorId\n });\n if (sourceThreads.length === 0) return [];\n\n const settings = await this.deps.readSettings();\n const baseInstructions = this.deps.buildSystemPrompt({\n settings,\n anchorId: input.targetAnchorId\n });\n const forkedViews: NormalizedThreadView[] = [];\n\n for (const source of sourceThreads) {\n const preparedDir = await this.deps.store.prepareThreadDir(source.name);\n const forkOptions: AgentForkThreadOptions = {\n sourceThreadId: source.threadId,\n instructions: baseInstructions,\n cwd: preparedDir.path,\n workspaceRoots: [preparedDir.path]\n };\n if (this.deps.approvalPolicy !== undefined) forkOptions.approvalPolicy = this.deps.approvalPolicy;\n if (this.deps.sandbox !== undefined) forkOptions.sandbox = this.deps.sandbox;\n if (this.deps.threadConfig !== undefined) forkOptions.config = this.deps.threadConfig;\n\n let forked: { threadId: string } & Partial<ThreadModelState>;\n try {\n forked = await forkThread(forkOptions);\n } catch (cause) {\n await this.deps.store.discardPreparedThreadDir(preparedDir).catch(() => undefined);\n throw cause;\n }\n\n await this.deps.client.clearThreadGitInfo?.(forked.threadId).catch((cause) => {\n this.logger.warn(\"forked chat thread git metadata clear failed\", {\n threadId: forked.threadId,\n message: cause instanceof Error ? cause.message : String(cause)\n });\n });\n this.threadModels.set(forked.threadId, {\n model: forked.model ?? null,\n modelProvider: forked.modelProvider ?? null,\n serviceTier: forked.serviceTier ?? null\n });\n\n const record = await this.deps.store.create({\n threadId: forked.threadId,\n name: source.name,\n anchorId: input.targetAnchorId,\n preparedDir\n });\n // Carry the source's per-turn journal so the forked thread shows history.\n const journal = await this.deps.store.readJournal(source.threadId);\n for (const entry of journal) {\n await this.deps.store.journalAppend(forked.threadId, entry);\n }\n const view = this.toView(record);\n this.deps.broadcast({ type: \"thread_updated\", thread: view });\n forkedViews.push(view);\n }\n return forkedViews;\n }\n\n // ---- turns ----\n\n async sendMessage(input: {\n threadId: string;\n text: string;\n anchorId?: string | null;\n /** Local image file paths to attach to this turn. Forwarded neutrally as\n * `AgentTurnInput.imagePaths`; the backend maps to its native attachment\n * (Codex `localImage`, ACP `image` blocks). */\n imagePaths?: readonly string[];\n }): Promise<{ turnId: string }> {\n const { threadId } = input;\n if (this.turns.has(threadId)) {\n throw new Error(\"a turn is already in progress for this thread\");\n }\n this.enforceRateLimit(threadId);\n\n if (input.anchorId !== undefined && input.anchorId !== null) {\n await this.deps.store.appendAnchor(threadId, input.anchorId);\n }\n\n // Persist + broadcast the user message BEFORE starting the turn so a dispatch\n // failure doesn't lose the typed prompt.\n const userMessage: NormalizedMessage = {\n id: this.randomId(),\n role: \"user\",\n text: input.text,\n createdAt: this.now()\n };\n await this.commitMessage(threadId, userMessage);\n\n const settingsSnapshot = await this.deps.readSettings();\n\n // Per-turn active-context is prepended to the turn text as a leading,\n // explicitly system-framed block — separated from the user's text by a blank\n // line, NOT silently merged into the prose. It's emitted only for the CURRENT\n // turn (never accumulated) so the thread carries no stale context blocks, and\n // the static instructions stay byte-identical across turns so the backend can\n // prompt-cache them. The neutral `AgentTurnInput` carries a single text field,\n // so the context rides as a labeled preamble rather than a separate protocol\n // item.\n const anchorForTurn = input.anchorId ?? (await this.currentAnchor(threadId));\n let turnText = input.text;\n if (anchorForTurn !== null && this.deps.buildTurnContext !== undefined) {\n turnText = `${this.deps.buildTurnContext(anchorForTurn)}\\n\\n${input.text}`;\n }\n const turnInput: AgentTurnInput = { text: turnText };\n if (input.imagePaths !== undefined) turnInput.imagePaths = input.imagePaths;\n\n // ACP-style backends keep their session IN-PROCESS, so a thread persisted\n // across an app restart has no live backend session (\"Unknown ACP thread\"\n // on the next turn). Re-establish one bound to the SAME thread id, with the\n // system prompt re-applied, before starting the turn. No-op for backends\n // that persist threads server-side (Codex) — they don't implement this seam.\n const reopenable = this.deps.client as {\n reopenThread?: (options: {\n threadId: string;\n buildInstructions?: () => string;\n }) => Promise<void>;\n };\n if (typeof reopenable.reopenThread === \"function\") {\n // Lazy: the backend only builds the prompt if it actually re-establishes\n // a session (skipped when the session is still live), so a normal turn\n // doesn't rebuild the system prompt.\n await reopenable.reopenThread({\n threadId,\n buildInstructions: () =>\n this.deps.buildSystemPrompt({ settings: settingsSnapshot, anchorId: anchorForTurn })\n });\n }\n\n const startTurnOptions: AgentStartTurnOptions = {\n threadId,\n input: turnInput,\n reasoning: this.deps.effort ?? \"medium\"\n };\n\n let turnId: string;\n try {\n const started = await this.deps.client.startTurn(startTurnOptions);\n turnId = started.turnId;\n } catch (cause) {\n // Mark a placeholder assistant message failed so the UI shows Retry.\n const failed: NormalizedMessage = {\n id: this.randomId(),\n role: \"assistant\",\n text: \"\",\n createdAt: this.now()\n };\n await this.commitMessage(threadId, failed);\n this.logger.warn(\"chat turn start failed\", {\n threadId,\n message: cause instanceof Error ? cause.message : String(cause)\n });\n throw cause;\n }\n\n const assistantMessageId = this.randomId();\n this.turns.set(threadId, {\n turnId,\n assistantMessageId,\n buffer: \"\",\n settingsSnapshot,\n tokenUsage: null,\n lastError: null\n });\n this.recordTurn(threadId);\n await this.broadcastThreadStatus(threadId, { kind: \"streaming\", turnId });\n return { turnId };\n }\n\n async getHistory(threadId: string): Promise<NormalizedMessage[]> {\n return this.readJournalMessages(threadId);\n }\n\n async interrupt(threadId: string): Promise<void> {\n const turn = this.turns.get(threadId);\n if (turn === undefined) return;\n await this.deps.client.interruptTurn(threadId).catch(() => undefined);\n await this.finalizeAssistant(threadId, \"interrupted\");\n this.deps.broadcast({ type: \"turn_interrupted\", threadId, turnId: turn.turnId });\n }\n\n // ---- approval flow ----\n\n async resolveApproval(input: {\n threadId: string;\n turnId: string;\n approvalId: string;\n decision: NormalizedApprovalDecision;\n }): Promise<void> {\n const key = approvalKey(input.threadId, input.turnId, input.approvalId);\n const pending = this.pendingApprovals.get(key);\n if (pending === undefined) {\n this.logger.warn(\"resolveApproval: no matching pending approval (stale?)\", { key });\n return;\n }\n this.pendingApprovals.delete(key);\n pending.resolve(input.decision);\n }\n\n // ---- backend subscription handlers ----\n\n private onBackendEvent(event: NormalizedThreadEvent): void {\n switch (event.kind) {\n case \"agent_message_delta\":\n this.onDelta(event.threadId, event.turnId, event.itemId, event.delta);\n return;\n case \"token_usage\":\n this.onTokenUsage(event.threadId, event.turnId, event.usage);\n return;\n case \"thread_settings\":\n this.threadModels.set(event.settings.threadId, {\n model: event.settings.model ?? null,\n modelProvider: event.settings.modelProvider ?? null,\n serviceTier: event.settings.serviceTier ?? null\n });\n return;\n case \"turn_completed\":\n void this.onTurnCompleted(event.threadId, event.turnId, event.status);\n return;\n case \"error\":\n void this.onTurnError(event.threadId, event.turnId, event.message, event.willRetry);\n return;\n case \"tool_call\":\n case \"tool_call_update\":\n // Backends that run their OWN tools (ACP agents — directly or via an\n // MCP server) report them as streamed tool_call events, NOT through the\n // `onToolCall` request seam (which only fires for host dynamic tools the\n // backend asks US to run, i.e. Codex). Surface those to the chat UI too,\n // so an ACP agent's tool usage shows the same activity chips as Codex.\n this.onStreamedToolCall(event);\n return;\n default:\n // reasoning_delta / agent_message / plan_update / turn_started /\n // approval_request are handled elsewhere or are informational.\n return;\n }\n }\n\n /** Accumulate a streamed tool_call / tool_call_update and broadcast it ONCE\n * it settles. The host UI dedups activity chips by id, so — like the\n * `onToolCall` seam — we surface only the terminal state with its final\n * status + label, rather than the intermediate pending/in-progress churn. */\n private onStreamedToolCall(\n event: Extract<NormalizedThreadEvent, { kind: \"tool_call\" | \"tool_call_update\" }>\n ): void {\n const id = event.toolCall.id;\n const merged: NormalizedToolCall =\n event.kind === \"tool_call\"\n ? event.toolCall\n : mergeToolCall(\n this.streamedToolCalls.get(id) ?? synthesizeToolCallBase(event.toolCall),\n event.toolCall\n );\n this.streamedToolCalls.set(id, merged);\n if (\n merged.status === \"completed\" ||\n merged.status === \"failed\" ||\n merged.status === \"cancelled\"\n ) {\n this.streamedToolCalls.delete(id);\n this.deps.broadcast({\n type: \"tool_call\",\n threadId: event.threadId,\n turnId: event.turnId,\n toolCall: merged\n });\n }\n }\n\n private onDelta(threadId: string, turnId: string, itemId: string, delta: string): void {\n const turn = this.turns.get(threadId);\n if (turn === undefined || turn.turnId !== turnId) return;\n turn.buffer += delta;\n this.deps.broadcast({\n type: \"stream_delta\",\n threadId,\n turnId,\n messageId: turn.assistantMessageId,\n delta\n });\n }\n\n private async onTurnCompleted(\n threadId: string,\n turnId: string,\n status: NormalizedTurnStatus\n ): Promise<void> {\n const turn = this.turns.get(threadId);\n if (turn === undefined || turn.turnId !== turnId) return;\n await this.finalizeAssistant(threadId, status);\n }\n\n /** The backend faulted a turn. Record the authoritative reason so it lands in\n * the committed (failed) assistant message; when terminal (`willRetry` not\n * true) end the turn now rather than waiting for a `turn_completed` that may\n * never arrive. When the backend says it WILL retry, keep the turn open and\n * let the eventual `turn_completed` decide its fate (carrying the reason if it\n * ends up failing). */\n private async onTurnError(\n threadId: string | undefined,\n turnId: string | undefined,\n message: string,\n willRetry: boolean | undefined\n ): Promise<void> {\n if (threadId === undefined || turnId === undefined) return;\n const turn = this.turns.get(threadId);\n if (turn === undefined || turn.turnId !== turnId) return;\n turn.lastError = message;\n if (willRetry !== true) {\n await this.finalizeAssistant(threadId, \"failed\");\n }\n }\n\n private onTokenUsage(threadId: string, turnId: string, usage: NormalizedTokenUsage): void {\n const turn = this.turns.get(threadId);\n if (turn === undefined || turn.turnId !== turnId) return;\n turn.tokenUsage = usage;\n }\n\n private async onToolCall(call: AgentBackendToolCall): Promise<unknown> {\n const params = call.params as DynamicToolCallParams;\n const response = this.deps.dispatchToolCall\n ? await this.deps.dispatchToolCall(params)\n : ({\n contentItems: [{ type: \"inputText\", text: \"No tools are enabled for this chat yet.\" }],\n success: false\n } satisfies DynamicToolCallResponse);\n // Surface the tool invocation to the chat UI as it happens (the activity chip\n // + working indicator). Re-broadcast as a neutral `tool_call` event carrying\n // the call's terminal status + a friendly label.\n this.deps.broadcast({\n type: \"tool_call\",\n threadId: params.threadId,\n turnId: params.turnId,\n toolCall: {\n id: params.callId,\n name: params.tool,\n kind: \"other\",\n label: humanizeToolCall(params.tool, response.success, this.deps.toolLabels),\n status: response.success ? \"completed\" : \"failed\",\n args: params.arguments,\n result: response\n }\n });\n return response;\n }\n\n private async onApprovalRequest(\n method: string,\n params: unknown\n ): Promise<NormalizedApprovalDecision> {\n // Best-effort extraction of (threadId, turnId); backend shapes vary by method.\n const p = (params ?? {}) as Record<string, unknown>;\n let threadId = typeof p.threadId === \"string\" ? p.threadId : \"\";\n let turnId = typeof p.turnId === \"string\" ? p.turnId : \"\";\n\n // The backend doesn't always tag an approval with its (threadId, turnId).\n // Without a threadId the host can't match the approval to a visible thread, so\n // the promise below would never resolve and the turn would hang. Recover the\n // only-possible thread when exactly one turn is in flight; otherwise auto-DENY\n // (Default Access never auto-APPROVES) with a warning rather than deadlocking.\n if (threadId.length === 0) {\n const onlyEntry = this.turns.size === 1 ? [...this.turns.entries()][0] : undefined;\n if (onlyEntry !== undefined) {\n const [onlyThreadId, onlyTurn] = onlyEntry;\n threadId = onlyThreadId;\n if (turnId.length === 0) turnId = onlyTurn.turnId;\n } else {\n this.logger.warn(\"approval request without a routable threadId — auto-denying\", {\n method,\n inFlightTurns: this.turns.size\n });\n return \"denied\";\n }\n }\n\n const approvalId = this.randomId();\n const request: NormalizedApprovalRequest = normalizeApprovalParams(method, params, approvalId);\n\n const decision = await new Promise<NormalizedApprovalDecision>((resolve) => {\n this.pendingApprovals.set(approvalKey(threadId, turnId, approvalId), {\n threadId,\n turnId,\n approvalId,\n resolve\n });\n this.deps.broadcast({ type: \"approval_requested\", threadId, turnId, approval: request });\n void this.broadcastThreadStatus(threadId, { kind: \"awaiting_approval\", approvalId });\n });\n\n const turn = this.turns.get(threadId);\n void this.broadcastThreadStatus(\n threadId,\n turn ? { kind: \"streaming\", turnId: turn.turnId } : { kind: \"idle\" }\n );\n return decision;\n }\n\n // ---- internals ----\n\n private async finalizeAssistant(\n threadId: string,\n status: NormalizedTurnStatus\n ): Promise<void> {\n const turn = this.turns.get(threadId);\n if (turn === undefined) return;\n this.turns.delete(threadId);\n\n const message: NormalizedMessage = {\n id: turn.assistantMessageId,\n role: \"assistant\",\n text: buildFinalText(status, turn.buffer, turn.lastError),\n createdAt: this.now()\n };\n\n this.recordUsage(threadId, turn).catch((cause) => {\n this.logger.warn(\"chat usage accounting failed\", {\n threadId,\n turnId: turn.turnId,\n message: cause instanceof Error ? cause.message : String(cause)\n });\n });\n\n await this.commitMessage(threadId, message);\n await this.broadcastThreadStatus(threadId, { kind: \"idle\" });\n }\n\n private async recordUsage(threadId: string, turn: TurnState<TSettings>): Promise<void> {\n if (turn.tokenUsage === null) return;\n const model = this.threadModels.get(threadId);\n const usage = turn.tokenUsage;\n await this.deps.store.recordUsage({\n threadId,\n turnId: turn.turnId,\n ...(model?.model != null ? { model: model.model } : {}),\n usage,\n ...(usage.contextWindow !== undefined ? { contextWindow: usage.contextWindow } : {}),\n at: this.now()\n });\n }\n\n private async commitMessage(threadId: string, message: NormalizedMessage): Promise<void> {\n const entry: JournalMessageEntry = { kind: \"message\", message };\n await this.deps.store.journalAppend(threadId, entry);\n this.deps.broadcast({ type: \"message_committed\", threadId, message });\n }\n\n private async readJournalMessages(threadId: string): Promise<NormalizedMessage[]> {\n const entries = await this.deps.store.readJournal(threadId).catch(() => [] as unknown[]);\n const messages: NormalizedMessage[] = [];\n for (const entry of entries) {\n if (\n entry !== null &&\n typeof entry === \"object\" &&\n (entry as { kind?: unknown }).kind === \"message\"\n ) {\n const m = (entry as { message?: unknown }).message;\n if (m !== undefined) messages.push(m as NormalizedMessage);\n }\n }\n return messages;\n }\n\n private async currentAnchor(threadId: string): Promise<string | null> {\n const record = await this.deps.store.get(threadId);\n return record?.anchorId ?? null;\n }\n\n private enforceRateLimit(threadId: string): void {\n const stamps = this.turnTimestamps.get(threadId) ?? [];\n const cutoff = this.now() - RATE_LIMIT_WINDOW_MS;\n const recent = stamps.filter((t) => t >= cutoff);\n if (recent.length >= RATE_LIMIT_TURNS) {\n throw new Error(`rate limit: max ${RATE_LIMIT_TURNS} turns per minute for this thread`);\n }\n }\n\n private recordTurn(threadId: string): void {\n const stamps = this.turnTimestamps.get(threadId) ?? [];\n const cutoff = this.now() - RATE_LIMIT_WINDOW_MS;\n const recent = stamps.filter((t) => t >= cutoff);\n recent.push(this.now());\n this.turnTimestamps.set(threadId, recent);\n }\n\n private async broadcastThreadStatus(\n threadId: string,\n status: NormalizedThreadStatus\n ): Promise<void> {\n const record = await this.deps.store.get(threadId);\n if (record === null) return;\n this.deps.broadcast({ type: \"thread_updated\", thread: this.toView(record, status) });\n }\n\n private toView(\n record: NormalizedThreadRecord,\n status?: NormalizedThreadStatus\n ): NormalizedThreadView {\n const turn = this.turns.get(record.threadId);\n const resolved: NormalizedThreadStatus =\n status ?? (turn !== undefined ? { kind: \"streaming\", turnId: turn.turnId } : { kind: \"idle\" });\n return {\n threadId: record.threadId,\n name: record.name,\n createdAt: record.createdAt,\n modifiedAt: record.modifiedAt,\n anchorId: record.anchorId,\n archived: record.archived,\n pinned: record.pinned,\n lastMessagePreview: \"\",\n status: resolved\n };\n }\n\n private defaultName(): string {\n return `Chat ${localDateStamp(new Date(this.now()))}`;\n }\n\n private randomId(): string {\n return globalThis.crypto.randomUUID();\n }\n}\n\n/** Local-timezone `YYYY-MM-DD` stamp (NOT `toISOString()`, which is UTC). */\nexport function localDateStamp(d: Date): string {\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n\nfunction approvalKey(threadId: string, turnId: string, approvalId: string): string {\n return `${threadId}::${turnId}::${approvalId}`;\n}\n\n/** Friendly present-tense label for a tool invocation, shown as an activity chip.\n * The host supplies the label map; falls back to the raw tool name. The `ok` flag\n * lets a failed call read \"couldn't …\". */\n/** Build a minimal full tool call from a `tool_call_update` that arrived with\n * no prior `tool_call` to merge into (defensive — backends normally lead with\n * a full `tool_call`). */\nfunction synthesizeToolCallBase(update: NormalizedToolCallUpdate): NormalizedToolCall {\n return {\n id: update.id,\n name: update.name ?? \"tool\",\n kind: update.kind ?? \"other\",\n label: update.label ?? update.name ?? \"tool\",\n status: update.status ?? \"in_progress\"\n };\n}\n\nfunction humanizeToolCall(tool: string, ok: boolean, labels: ToolLabelMap = {}): string {\n const label = labels[tool] ?? tool;\n return ok ? label : `Couldn't: ${label.toLowerCase()}`;\n}\n\nfunction normalizeApprovalParams(\n method: string,\n params: unknown,\n approvalId: string\n): NormalizedApprovalRequest {\n const p = (params ?? {}) as Record<string, unknown>;\n const summary =\n typeof p.summary === \"string\"\n ? p.summary\n : typeof p.reason === \"string\"\n ? p.reason\n : typeof p.command === \"string\"\n ? p.command\n : undefined;\n const kind = method.includes(\"commandExecution\")\n ? \"exec\"\n : method.includes(\"fileChange\")\n ? \"patch\"\n : method.includes(\"tool\")\n ? \"tool\"\n : \"other\";\n const request: NormalizedApprovalRequest = { id: approvalId, method, kind, params };\n if (summary !== undefined) request.summary = summary;\n return request;\n}\n"],"mappings":"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","names":["noopLogger","JsonRpcConnection","StdioJsonRpcTransport","resolveCodexCommand","DEFAULT_CLIENT_NAME","DEFAULT_SERVICE_NAME","noopLogger","connection","resolveCodexCommand","StdioJsonRpcTransport","JsonRpcConnection","noopLogger"]}
1
+ {"version":3,"sources":["../src/codex-thread-client.ts","../src/normalize.ts","../src/codex-error.ts","../src/codex-oneshot-client.ts","../src/codex-thread-config.ts","../src/chat/define-tool.ts","../src/chat/tool-catalog.ts","../src/chat/chat-thread-controller.ts"],"sourcesContent":["// Long-lived, multi-turn Codex App Server client.\n//\n// Keeps a single codex child process + JSON-RPC connection alive and lets the\n// caller open MULTIPLE threads on it, each carrying its own dynamic tools. It\n// is a thin transport client: it owns the connection lifecycle and routes\n// notifications / server-requests, but bakes in no chat or idle-timing logic.\n//\n// Ported from PwrSnap's CodexThreadClient with three seams broken:\n// • the logger is injected (agent-core `Logger`);\n// • `clientInfo.name` + the default `serviceName` are options (no hardcoded\n// \"pwrsnap\");\n// • every native notification is routed through `normalizeNotification`, so\n// subscribers receive agent-core `NormalizedThreadEvent` — never a raw\n// protocol shape.\n\nimport {\n noopLogger,\n type AgentBackend,\n type AgentBackendApprovalHandler,\n type AgentBackendStartThreadResult,\n type AgentBackendToolCall,\n type AgentBackendToolCallHandler,\n type AgentForkThreadOptions,\n type AgentStartThreadOptions,\n type AgentStartTurnOptions,\n type Logger,\n type NormalizedThreadEvent,\n type NormalizedApprovalDecision\n} from \"@pwrdrvr/agent-core\";\nimport {\n JsonRpcConnection,\n StdioJsonRpcTransport,\n type JsonRpcTransport\n} from \"@pwrdrvr/agent-transport\";\nimport { resolveCodexCommand } from \"@pwrdrvr/codex-discovery\";\nimport type {\n InitializeParams,\n InitializeResponse,\n Personality,\n ReasoningEffort\n} from \"@pwrdrvr/codex-app-server-protocol\";\nimport type {\n AskForApproval,\n DynamicToolCallResponse,\n DynamicToolSpec,\n SandboxMode,\n ThreadForkParams,\n ThreadForkResponse,\n ThreadResumeParams,\n ThreadResumeResponse,\n ThreadStartParams,\n ThreadStartResponse,\n TurnStartParams,\n TurnStartResponse,\n UserInput\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\nimport {\n CODEX_APPROVAL_METHODS,\n CODEX_TOOL_CALL_METHOD,\n normalizeNotification\n} from \"./normalize\";\n\nexport type CodexThreadClientTransportFactory = (command: string) => JsonRpcTransport;\n\nexport type CodexThreadClientOptions = {\n /** Configured command to resolve. `\"codex\"` (or empty) triggers discovery. */\n command?: string;\n /** Identity sent as `clientInfo.name` at `initialize`. Defaults to \"agent-kit\". */\n clientName?: string;\n /** Human title sent as `clientInfo.title`. Defaults to `clientName`. */\n clientTitle?: string;\n /** Version sent as `clientInfo.version`. Defaults to \"0.0.0\". */\n clientVersion?: string;\n /** Default `serviceName` applied at `thread/start` when the caller omits one. */\n serviceName?: string;\n requestTimeoutMs?: number;\n turnTimeoutMs?: number;\n /** Process env passed to the spawned codex. Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv;\n /** Override the transport (tests inject an in-memory fake). When supplied,\n * no discovery/spawn happens. */\n transportFactory?: CodexThreadClientTransportFactory;\n logger?: Logger;\n};\n\n/**\n * Codex-NATIVE thread/start options. **No longer the public `startThread`\n * surface** — `CodexThreadClient` now implements the non-generic `AgentBackend`\n * and its public `startThread` takes neutral `AgentStartThreadOptions`. This\n * type is retained as the internal mapping target (and is still exported for\n * hosts that want to construct the native shape directly via\n * `startThreadNative`). The neutral→native mapping lives in `startThread`.\n */\nexport type CodexStartThreadOptions = {\n approvalPolicy?: string;\n sandbox?: string;\n baseInstructions?: string;\n dynamicTools?: DynamicToolSpec[];\n cwd?: string;\n runtimeWorkspaceRoots?: string[];\n serviceName?: string;\n personality?: string;\n /** Model id to start the thread on (ThreadStartParams.model). Omit for the\n * Codex default. The host drives this from its settings (per-surface default). */\n model?: string;\n /** Model provider id (ThreadStartParams.modelProvider) — the \"provider\" a host\n * picks when more than one is configured. Omit for the Codex default. */\n modelProvider?: string;\n /** Service tier (ThreadStartParams.serviceTier), when the host pins one. */\n serviceTier?: string;\n /** Per-thread Codex config overlay (the `-c key=value` mechanism). Used to\n * disable Codex prompt/tool scaffolding that belongs to coding-agent threads. */\n config?: Record<string, unknown>;\n /** Thread environments. **Empty array disables exec-environment access**,\n * dropping Codex's built-in shell / unified_exec / apply_patch tools. Dynamic\n * tools are added before that gate, so they survive. */\n environments?: unknown[];\n};\n\n/** Codex-NATIVE turn/start options. Internal mapping target (see\n * `startThreadNative`'s sibling `startTurnNative`); the public `startTurn`\n * takes neutral `AgentStartTurnOptions`. */\nexport type CodexStartTurnOptions = {\n threadId: string;\n input: UserInput[];\n effort?: string;\n};\n\n/**\n * Handles a tool-call ServerRequest. Reconciled to the canonical\n * `AgentBackendToolCallHandler` shape so the controller drives Codex and ACP\n * identically: the handler receives a neutral `AgentBackendToolCall`\n * (`{ method, params }`) and returns an `unknown` payload the client forwards\n * back to Codex verbatim. For Codex the `params` is a `DynamicToolCallParams`\n * (cast at the dispatch site) and the returned payload is a\n * `DynamicToolCallResponse`.\n */\nexport type CodexToolCallHandler = AgentBackendToolCallHandler;\n\n/** Handles an approval ServerRequest; resolves to a neutral decision. Identical\n * to the canonical `AgentBackendApprovalHandler`. */\nexport type CodexApprovalHandler = AgentBackendApprovalHandler;\n\nexport type Unsubscribe = () => void;\n\nexport type StartThreadResult = {\n threadId: string;\n model: string;\n modelProvider: string;\n serviceTier: string | null;\n};\n\nconst DEFAULT_CLIENT_NAME = \"agent-kit\";\nconst DEFAULT_SERVICE_NAME = \"agent-kit\";\n\n/** Map a neutral approval decision onto the generic Codex approval response. */\nfunction approvalResponseFor(decision: NormalizedApprovalDecision): unknown {\n switch (decision) {\n case \"approved\":\n return { decision: \"approved\" };\n case \"abort\":\n return { decision: \"abort\" };\n case \"denied\":\n default:\n return { decision: \"denied\" };\n }\n}\n\nexport class CodexThreadClient implements AgentBackend {\n private readonly requestTimeoutMs: number;\n private readonly turnTimeoutMs: number;\n private readonly logger: Logger;\n private readonly transportFactory: CodexThreadClientTransportFactory | null;\n private resolvedCommand: string | null = null;\n private connection: JsonRpcConnection | null = null;\n private initializeResponse: InitializeResponse | null = null;\n\n private readonly eventListeners = new Set<(event: NormalizedThreadEvent) => void>();\n private toolCallHandler: CodexToolCallHandler | null = null;\n private approvalHandler: CodexApprovalHandler | null = null;\n private readonly loadedThreadIds = new Set<string>();\n\n constructor(private readonly options: CodexThreadClientOptions = {}) {\n this.requestTimeoutMs = options.requestTimeoutMs ?? 20_000;\n this.turnTimeoutMs = options.turnTimeoutMs ?? 120_000;\n this.logger = options.logger ?? noopLogger;\n this.transportFactory = options.transportFactory ?? null;\n }\n\n /** Subscribe to the normalized event stream. Every native notification is\n * routed through `normalizeNotification` before listeners see it. */\n onEvent(cb: (event: NormalizedThreadEvent) => void): Unsubscribe {\n this.eventListeners.add(cb);\n return () => {\n this.eventListeners.delete(cb);\n };\n }\n\n /** Register the dynamic-tool ServerRequest handler (one at a time). */\n onToolCall(handler: CodexToolCallHandler): Unsubscribe {\n this.toolCallHandler = handler;\n return () => {\n if (this.toolCallHandler === handler) this.toolCallHandler = null;\n };\n }\n\n /** Register the approval ServerRequest handler (one at a time). */\n onApprovalRequest(handler: CodexApprovalHandler): Unsubscribe {\n this.approvalHandler = handler;\n return () => {\n if (this.approvalHandler === handler) this.approvalHandler = null;\n };\n }\n\n /**\n * Public `AgentBackend.startThread`: accepts NEUTRAL `AgentStartThreadOptions`\n * and maps them onto Codex-native `CodexStartThreadOptions` before delegating\n * to `startThreadNative`. Mapping:\n * instructions→baseInstructions, cwd, workspaceRoots→runtimeWorkspaceRoots,\n * model/modelProvider, serviceTier (drop `null`), approvalPolicy, sandbox,\n * serviceName, config, environments, tools (cast to DynamicToolSpec[])→\n * dynamicTools.\n */\n async startThread(opts: AgentStartThreadOptions = {}): Promise<StartThreadResult> {\n const native: CodexStartThreadOptions = {};\n if (opts.instructions !== undefined) native.baseInstructions = opts.instructions;\n if (opts.cwd !== undefined) native.cwd = opts.cwd;\n if (opts.workspaceRoots !== undefined) {\n native.runtimeWorkspaceRoots = [...opts.workspaceRoots];\n }\n if (opts.model !== undefined) native.model = opts.model;\n if (opts.modelProvider !== undefined) native.modelProvider = opts.modelProvider;\n // Codex's serviceTier is a plain string; a neutral `null` means \"don't pin\".\n if (opts.serviceTier != null) native.serviceTier = opts.serviceTier;\n if (opts.approvalPolicy !== undefined) native.approvalPolicy = opts.approvalPolicy;\n if (opts.sandbox !== undefined) native.sandbox = opts.sandbox;\n if (opts.serviceName !== undefined) native.serviceName = opts.serviceName;\n if (opts.config !== undefined) native.config = opts.config;\n if (opts.environments !== undefined) native.environments = opts.environments;\n if (opts.tools !== undefined) native.dynamicTools = opts.tools as DynamicToolSpec[];\n return this.startThreadNative(native);\n }\n\n /** Fork an existing thread into a fresh one carrying its history (Codex\n * `thread/fork`). The new thread inherits the source's model/provider. */\n async forkThread(opts: AgentForkThreadOptions): Promise<AgentBackendStartThreadResult> {\n const connection = await this.getConnection();\n await this.initialize();\n\n const params: ThreadForkParams = {\n threadId: opts.sourceThreadId,\n persistExtendedHistory: false\n };\n if (opts.cwd !== undefined) params.cwd = opts.cwd;\n if (opts.workspaceRoots !== undefined) params.runtimeWorkspaceRoots = [...opts.workspaceRoots];\n if (opts.instructions !== undefined) params.baseInstructions = opts.instructions;\n if (opts.approvalPolicy !== undefined) params.approvalPolicy = opts.approvalPolicy as AskForApproval;\n if (opts.sandbox !== undefined) params.sandbox = opts.sandbox as SandboxMode;\n if (opts.config !== undefined) {\n params.config = opts.config as NonNullable<ThreadForkParams[\"config\"]>;\n }\n\n const response = (await connection.request(\n \"thread/fork\",\n params,\n this.requestTimeoutMs\n )) as ThreadForkResponse;\n const threadId = response.thread.id;\n this.loadedThreadIds.add(threadId);\n return {\n threadId,\n model: response.model,\n modelProvider: response.modelProvider,\n serviceTier: response.serviceTier\n };\n }\n\n /** Codex-native thread/start. Builds `ThreadStartParams` directly. Exposed for\n * hosts that want full Codex control; the neutral `startThread` delegates here. */\n async startThreadNative(opts: CodexStartThreadOptions = {}): Promise<StartThreadResult> {\n const connection = await this.getConnection();\n await this.initialize();\n\n // exactOptionalPropertyTypes: only attach a key when the caller supplied it.\n const params: ThreadStartParams = {\n experimentalRawEvents: false,\n persistExtendedHistory: false\n };\n if (opts.cwd !== undefined) params.cwd = opts.cwd;\n if (opts.model !== undefined) params.model = opts.model;\n if (opts.modelProvider !== undefined) params.modelProvider = opts.modelProvider;\n if (opts.serviceTier !== undefined) params.serviceTier = opts.serviceTier;\n if (opts.runtimeWorkspaceRoots !== undefined) {\n params.runtimeWorkspaceRoots = opts.runtimeWorkspaceRoots;\n }\n const serviceName = opts.serviceName ?? this.options.serviceName ?? DEFAULT_SERVICE_NAME;\n params.serviceName = serviceName;\n if (opts.approvalPolicy !== undefined) {\n params.approvalPolicy = opts.approvalPolicy as AskForApproval;\n }\n if (opts.sandbox !== undefined) params.sandbox = opts.sandbox as SandboxMode;\n if (opts.baseInstructions !== undefined) params.baseInstructions = opts.baseInstructions;\n if (opts.personality !== undefined) params.personality = opts.personality as Personality;\n if (opts.dynamicTools !== undefined) params.dynamicTools = opts.dynamicTools;\n if (opts.config !== undefined) {\n params.config = opts.config as NonNullable<ThreadStartParams[\"config\"]>;\n }\n if (opts.environments !== undefined) {\n params.environments = opts.environments as NonNullable<ThreadStartParams[\"environments\"]>;\n }\n\n const response = (await connection.request(\n \"thread/start\",\n params,\n this.requestTimeoutMs\n )) as ThreadStartResponse;\n const threadId = response.thread.id;\n this.loadedThreadIds.add(threadId);\n this.logger.debug(\"thread started\", { threadId });\n return {\n threadId,\n model: response.model,\n modelProvider: response.modelProvider,\n serviceTier: response.serviceTier\n };\n }\n\n async resumeThread(threadId: string): Promise<void> {\n if (this.loadedThreadIds.has(threadId)) return;\n const connection = await this.getConnection();\n await this.initialize();\n\n const params: ThreadResumeParams = {\n threadId,\n persistExtendedHistory: false\n };\n const response = (await connection.request(\n \"thread/resume\",\n params,\n this.requestTimeoutMs\n )) as ThreadResumeResponse;\n this.loadedThreadIds.add(response.thread.id);\n this.logger.debug(\"thread resumed\", { threadId: response.thread.id });\n }\n\n async clearThreadGitInfo(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await this.initialize();\n await connection.request(\n \"thread/metadata/update\",\n { threadId, gitInfo: { sha: null, branch: null, originUrl: null } },\n this.requestTimeoutMs\n );\n }\n\n /**\n * Public `AgentBackend.startTurn`: accepts NEUTRAL `AgentStartTurnOptions` and\n * maps them onto Codex-native `UserInput[]`. The neutral `input.text` becomes a\n * leading `{ type: \"text\" }` item; each `input.imagePaths` entry becomes a\n * `{ type: \"localImage\", path }` item appended after the text. `reasoning`\n * maps to Codex's `effort`.\n */\n async startTurn(opts: AgentStartTurnOptions): Promise<{ turnId: string }> {\n const input: UserInput[] = [{ type: \"text\", text: opts.input.text, text_elements: [] }];\n for (const path of opts.input.imagePaths ?? []) {\n input.push({ type: \"localImage\", path });\n }\n const native: CodexStartTurnOptions = { threadId: opts.threadId, input };\n if (opts.reasoning !== undefined) native.effort = opts.reasoning;\n return this.startTurnNative(native);\n }\n\n /** Codex-native turn/start. Takes pre-built `UserInput[]`. The neutral\n * `startTurn` delegates here after mapping text + image paths. */\n async startTurnNative(opts: CodexStartTurnOptions): Promise<{ turnId: string }> {\n await this.resumeThread(opts.threadId);\n const connection = await this.getConnection();\n await this.initialize();\n\n const params: TurnStartParams = {\n threadId: opts.threadId,\n input: opts.input\n };\n if (opts.effort !== undefined) params.effort = opts.effort as ReasoningEffort;\n\n const response = (await connection.request(\n \"turn/start\",\n params,\n this.turnTimeoutMs\n )) as TurnStartResponse;\n const turnId = response.turn.id;\n this.logger.debug(\"turn started\", { threadId: opts.threadId, turnId });\n return { turnId };\n }\n\n async interruptTurn(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await connection.request(\"turn/interrupt\", { threadId }, this.requestTimeoutMs);\n }\n\n async archiveThread(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await connection.request(\"thread/archive\", { threadId }, this.requestTimeoutMs);\n }\n\n async close(): Promise<void> {\n const connection = this.connection;\n this.connection = null;\n this.initializeResponse = null;\n this.loadedThreadIds.clear();\n if (connection) await connection.close();\n }\n\n // ---- internals ----\n\n private emit(event: NormalizedThreadEvent): void {\n for (const listener of this.eventListeners) listener(event);\n }\n\n private async resolveCommand(): Promise<string> {\n if (this.resolvedCommand !== null) return this.resolvedCommand;\n const resolved = await resolveCodexCommand({\n command: this.options.command ?? \"codex\",\n env: this.options.env ?? process.env\n });\n this.resolvedCommand = resolved.command;\n return resolved.command;\n }\n\n private async initialize(): Promise<InitializeResponse> {\n if (this.initializeResponse) return this.initializeResponse;\n const connection = await this.getConnection();\n const name = this.options.clientName ?? DEFAULT_CLIENT_NAME;\n const params: InitializeParams = {\n clientInfo: {\n name,\n title: this.options.clientTitle ?? name,\n version: this.options.clientVersion ?? \"0.0.0\"\n },\n capabilities: {\n experimentalApi: true,\n // We don't proxy through OpenAI's edge attestation flow, so opting in\n // would add per-turn latency for an unused round-trip.\n requestAttestation: false\n }\n };\n const response = (await connection.request(\n \"initialize\",\n params,\n this.requestTimeoutMs\n )) as InitializeResponse;\n this.initializeResponse = response;\n return response;\n }\n\n private async getConnection(): Promise<JsonRpcConnection> {\n if (this.connection) return this.connection;\n\n let transport: JsonRpcTransport;\n if (this.transportFactory !== null) {\n // Tests / hosts supplying a fake transport bypass discovery + spawn.\n transport = this.transportFactory(this.options.command ?? \"codex\");\n } else {\n const command = await this.resolveCommand();\n transport = new StdioJsonRpcTransport({\n command,\n args: [\"app-server\"],\n ...(this.options.env !== undefined ? { env: this.options.env } : {}),\n logger: this.logger\n });\n }\n\n const connection = new JsonRpcConnection(transport, this.requestTimeoutMs, undefined, {\n logger: this.logger,\n logContext: { owner: \"codex-thread-client\" }\n });\n connection.setNotificationHandler((method, params) => {\n this.handleNotification(method, params);\n });\n connection.setRequestHandler((method, params) => this.handleServerRequest(method, params));\n await connection.connect();\n this.connection = connection;\n return connection;\n }\n\n private handleNotification(method: string, params: unknown): void {\n const event = normalizeNotification(method, params);\n if (event !== null) this.emit(event);\n }\n\n private async handleServerRequest(method: string, params: unknown): Promise<unknown> {\n if (method === CODEX_TOOL_CALL_METHOD) {\n const handler = this.toolCallHandler;\n if (!handler) {\n this.logger.warn(\"tool call received with no handler registered\");\n return {\n contentItems: [\n { type: \"inputText\", text: \"No tool handler is registered for this thread.\" }\n ],\n success: false\n } satisfies DynamicToolCallResponse;\n }\n // Canonical `AgentBackendToolCall` shape: the host's handler reads\n // `call.params` (a `DynamicToolCallParams` for Codex) and returns the\n // `DynamicToolCallResponse` we forward back to Codex verbatim.\n const call: AgentBackendToolCall = { method, params };\n return await handler(call);\n }\n\n if (CODEX_APPROVAL_METHODS.has(method)) {\n const handler = this.approvalHandler;\n if (!handler) {\n this.logger.warn(\"approval request received with no handler registered\", { method });\n return approvalResponseFor(\"denied\");\n }\n const decision = await handler(method, params);\n return approvalResponseFor(decision);\n }\n\n this.logger.debug(\"unhandled codex server request\", { method });\n return {};\n }\n}\n","// Codex App Server v2 → agent-core neutral schema.\n//\n// Every native Codex notification / server-request a turn produces is mapped\n// here into one (or zero) `NormalizedThreadEvent`. Subscribers of the Codex\n// adapter only ever see normalized shapes — the raw protocol stops at this\n// boundary, so an ACP adapter emitting the same neutral events is a drop-in.\n//\n// The mapping is deliberately defensive: a notification we don't recognize, or\n// a malformed payload, yields `null` (no event) rather than throwing — a\n// streaming turn must never die on an unexpected wire shape.\n\nimport {\n inferToolKind,\n type NormalizedThreadEvent,\n type NormalizedToolCall,\n type NormalizedToolCallUpdate,\n type NormalizedToolKind,\n type NormalizedToolStatus,\n type NormalizedTokenUsage,\n type NormalizedTurnStatus,\n type NormalizedApprovalKind,\n type NormalizedApprovalRequest,\n type NormalizedThreadSettings,\n type NormalizedMessage\n} from \"@pwrdrvr/agent-core\";\nimport { formatCodexTurnError } from \"./codex-error\";\nimport type {\n AgentMessageDeltaNotification,\n DynamicToolCallParams,\n ItemCompletedNotification,\n ItemStartedNotification,\n ModelReroutedNotification,\n ReasoningTextDeltaNotification,\n ThreadItem,\n ThreadSettingsUpdatedNotification,\n ThreadTokenUsage,\n ThreadTokenUsageUpdatedNotification,\n TurnCompletedNotification,\n TurnError,\n TurnStartedNotification,\n TurnStatus\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\n\n// ---- wire method strings ----\n// These are the App Server JSON-RPC method names a turn emits. Kept as bare\n// strings (not protocol types — the wire carries strings) so the adapter routes\n// `(method, params)` straight through `normalizeNotification`.\n\nexport const CODEX_NOTIFICATION_METHODS = {\n agentMessageDelta: \"item/agentMessage/delta\",\n reasoningDelta: \"item/reasoning/delta\",\n reasoningTextDelta: \"item/reasoning/textDelta\",\n itemStarted: \"item/started\",\n itemCompleted: \"item/completed\",\n turnStarted: \"turn/started\",\n turnCompleted: \"turn/completed\",\n tokenUsage: \"thread/tokenUsage/updated\",\n threadSettings: \"thread/settings/updated\",\n modelRerouted: \"model/rerouted\",\n error: \"error\"\n} as const;\n\n/** Codex approval ServerRequest methods, normalized into `approval_request`. */\nexport const CODEX_APPROVAL_METHODS = new Set<string>([\n \"item/commandExecution/requestApproval\",\n \"item/fileChange/requestApproval\",\n \"item/permissions/requestApproval\",\n \"item/tool/requestUserInput\",\n // Legacy v1 method names — older Codex builds still emit these.\n \"applyPatchApproval\",\n \"execCommandApproval\"\n]);\n\n/** The dynamic-tool ServerRequest method Codex routes tool invocations on. */\nexport const CODEX_TOOL_CALL_METHOD = \"item/tool/call\";\n\n// ---- usage ----\n\n/** Map a Codex `ThreadTokenUsage` (its `last` breakdown) to the neutral shape. */\nexport function normalizeTokenUsage(usage: ThreadTokenUsage): NormalizedTokenUsage {\n const last = usage.last;\n return {\n inputTokens: last.inputTokens,\n cachedInputTokens: last.cachedInputTokens,\n outputTokens: last.outputTokens,\n reasoningOutputTokens: last.reasoningOutputTokens,\n totalTokens: last.totalTokens,\n // Top-level on ThreadTokenUsage (sibling to last/total), not on the breakdown.\n ...(usage.modelContextWindow != null ? { contextWindow: usage.modelContextWindow } : {})\n };\n}\n\n// ---- turn status ----\n\nfunction normalizeTurnStatus(status: TurnStatus | string): NormalizedTurnStatus {\n switch (status) {\n case \"completed\":\n return \"completed\";\n case \"failed\":\n return \"failed\";\n case \"interrupted\":\n return \"interrupted\";\n case \"inProgress\":\n return \"in_progress\";\n case \"aborted\":\n case \"cancelled\":\n case \"canceled\":\n return \"cancelled\";\n default:\n return \"failed\";\n }\n}\n\n// ---- tool call (from a ThreadItem) ----\n\nconst DYNAMIC_TOOL_STATUS: Record<string, NormalizedToolStatus> = {\n inProgress: \"in_progress\",\n completed: \"completed\",\n failed: \"failed\"\n};\n\nconst COMMAND_STATUS: Record<string, NormalizedToolStatus> = {\n inProgress: \"in_progress\",\n completed: \"completed\",\n failed: \"failed\",\n declined: \"cancelled\"\n};\n\n/** Render the content items a dynamic tool returned as a single string result. */\nfunction joinDynamicResult(\n contentItems: Extract<ThreadItem, { type: \"dynamicToolCall\" }>[\"contentItems\"]\n): string | undefined {\n if (contentItems === null) return undefined;\n const text = contentItems\n .map((item) => (item.type === \"inputText\" ? item.text : item.imageUrl))\n .join(\"\");\n return text.length > 0 ? text : undefined;\n}\n\n/**\n * Build a `NormalizedToolCall` from a tool-ish `ThreadItem`. Returns `null` for\n * non-tool items. `kind` defaults to `inferToolKind(name)` unless the item's\n * native shape already classifies it (a command execution is always \"command\").\n */\nexport function normalizeThreadItemToolCall(item: ThreadItem): NormalizedToolCall | null {\n if (item.type === \"dynamicToolCall\") {\n const kind: NormalizedToolKind = inferToolKind(item.tool);\n const status = DYNAMIC_TOOL_STATUS[item.status] ?? \"in_progress\";\n const call: NormalizedToolCall = {\n id: item.id,\n name: item.tool,\n kind,\n label: item.tool,\n status,\n args: item.arguments\n };\n const result = joinDynamicResult(item.contentItems);\n if (result !== undefined) call.result = result;\n return call;\n }\n\n if (item.type === \"commandExecution\") {\n const status = COMMAND_STATUS[item.status] ?? \"in_progress\";\n const call: NormalizedToolCall = {\n id: item.id,\n name: \"command\",\n kind: \"command\",\n label: item.command,\n status,\n command: {\n displayCommand: item.command,\n rawCommand: item.command,\n cwd: item.cwd,\n ...(item.aggregatedOutput !== null ? { output: item.aggregatedOutput } : {}),\n ...(item.exitCode !== null ? { exitCode: item.exitCode } : {}),\n ...(item.durationMs !== null ? { durationMs: item.durationMs } : {})\n }\n };\n return call;\n }\n\n if (item.type === \"webSearch\") {\n return {\n id: item.id,\n name: \"web_search\",\n kind: \"search\",\n label: item.query,\n status: \"completed\",\n args: { query: item.query }\n };\n }\n\n if (item.type === \"fileChange\") {\n return {\n id: item.id,\n name: \"file_change\",\n kind: \"write\",\n label: \"Edit files\",\n status: item.status === \"completed\" ? \"completed\" : \"in_progress\"\n };\n }\n\n return null;\n}\n\n/**\n * Build a `NormalizedToolCall` from a `DynamicToolCallParams` (the ServerRequest\n * the adapter must answer). `kind` defaults to `inferToolKind(name)`.\n */\nexport function normalizeDynamicToolCall(params: DynamicToolCallParams): NormalizedToolCall {\n return {\n id: params.callId,\n name: params.tool,\n kind: inferToolKind(params.tool),\n label: params.tool,\n status: \"in_progress\",\n args: params.arguments\n };\n}\n\n// ---- approvals ----\n\nfunction approvalKindForMethod(method: string): NormalizedApprovalKind {\n if (method.includes(\"commandExecution\") || method === \"execCommandApproval\") return \"exec\";\n if (method.includes(\"fileChange\") || method === \"applyPatchApproval\") return \"patch\";\n if (method.includes(\"tool\")) return \"tool\";\n return \"other\";\n}\n\n/** Normalize a Codex approval ServerRequest into a neutral approval request. */\nexport function normalizeApprovalRequest(\n method: string,\n params: unknown,\n approvalId: string\n): NormalizedApprovalRequest {\n const p = (params ?? {}) as Record<string, unknown>;\n const summary =\n typeof p.reason === \"string\"\n ? p.reason\n : typeof p.command === \"string\"\n ? p.command\n : undefined;\n const request: NormalizedApprovalRequest = {\n id: approvalId,\n method,\n kind: approvalKindForMethod(method),\n params\n };\n if (summary !== undefined) request.summary = summary;\n return request;\n}\n\n// ---- thread settings ----\n\nexport function normalizeThreadSettings(\n notification: ThreadSettingsUpdatedNotification\n): NormalizedThreadSettings {\n return {\n threadId: notification.threadId,\n model: notification.threadSettings.model,\n modelProvider: notification.threadSettings.modelProvider,\n serviceTier: notification.threadSettings.serviceTier\n };\n}\n\n// ---- top-level notification dispatch ----\n\nfunction isToolish(item: ThreadItem): boolean {\n return (\n item.type === \"dynamicToolCall\" ||\n item.type === \"commandExecution\" ||\n item.type === \"webSearch\" ||\n item.type === \"fileChange\"\n );\n}\n\nfunction toUpdate(call: NormalizedToolCall): NormalizedToolCallUpdate {\n return call;\n}\n\nfunction agentMessageFromItem(item: ThreadItem): NormalizedMessage | null {\n if (item.type !== \"agentMessage\") return null;\n return { id: item.id, role: \"assistant\", text: item.text };\n}\n\n/**\n * Normalize one native Codex notification into a `NormalizedThreadEvent`.\n * Returns `null` when the method/payload yields no neutral event (an unknown\n * method, or an `item/*` carrying a non-streamable item).\n *\n * `item/started` for a tool-ish item becomes a `tool_call`; the matching\n * `item/completed` becomes a `tool_call_update` (so the controller correlates\n * them by id and merges via `mergeToolCall`). An `agentMessage` `item/completed`\n * becomes a final `agent_message`.\n */\nexport function normalizeNotification(\n method: string,\n params: unknown\n): NormalizedThreadEvent | null {\n switch (method) {\n case CODEX_NOTIFICATION_METHODS.agentMessageDelta: {\n const n = params as AgentMessageDeltaNotification;\n return {\n kind: \"agent_message_delta\",\n threadId: n.threadId,\n turnId: n.turnId,\n itemId: n.itemId,\n delta: n.delta\n };\n }\n case CODEX_NOTIFICATION_METHODS.reasoningDelta:\n case CODEX_NOTIFICATION_METHODS.reasoningTextDelta: {\n const n = params as ReasoningTextDeltaNotification;\n return {\n kind: \"reasoning_delta\",\n threadId: n.threadId,\n turnId: n.turnId,\n itemId: n.itemId,\n delta: n.delta\n };\n }\n case CODEX_NOTIFICATION_METHODS.turnStarted: {\n const n = params as TurnStartedNotification;\n return { kind: \"turn_started\", threadId: n.threadId, turnId: n.turn.id };\n }\n case CODEX_NOTIFICATION_METHODS.turnCompleted: {\n const n = params as TurnCompletedNotification;\n return {\n kind: \"turn_completed\",\n threadId: n.threadId,\n turnId: n.turn.id,\n status: normalizeTurnStatus(n.turn.status)\n };\n }\n case CODEX_NOTIFICATION_METHODS.tokenUsage: {\n const n = params as ThreadTokenUsageUpdatedNotification;\n return {\n kind: \"token_usage\",\n threadId: n.threadId,\n turnId: n.turnId,\n usage: normalizeTokenUsage(n.tokenUsage)\n };\n }\n case CODEX_NOTIFICATION_METHODS.threadSettings: {\n const n = params as ThreadSettingsUpdatedNotification;\n return { kind: \"thread_settings\", settings: normalizeThreadSettings(n) };\n }\n case CODEX_NOTIFICATION_METHODS.modelRerouted: {\n const n = params as ModelReroutedNotification;\n return {\n kind: \"thread_settings\",\n settings: {\n threadId: n.threadId,\n model: n.toModel,\n modelProvider: \"openai\",\n serviceTier: null\n }\n };\n }\n case CODEX_NOTIFICATION_METHODS.itemStarted: {\n const n = params as ItemStartedNotification;\n if (isToolish(n.item)) {\n const call = normalizeThreadItemToolCall(n.item);\n if (call === null) return null;\n return { kind: \"tool_call\", threadId: n.threadId, turnId: n.turnId, toolCall: call };\n }\n return null;\n }\n case CODEX_NOTIFICATION_METHODS.itemCompleted: {\n const n = params as ItemCompletedNotification;\n const message = agentMessageFromItem(n.item);\n if (message !== null) {\n return {\n kind: \"agent_message\",\n threadId: n.threadId,\n turnId: n.turnId,\n message\n };\n }\n if (isToolish(n.item)) {\n const call = normalizeThreadItemToolCall(n.item);\n if (call === null) return null;\n return {\n kind: \"tool_call_update\",\n threadId: n.threadId,\n turnId: n.turnId,\n toolCall: toUpdate(call)\n };\n }\n return null;\n }\n case CODEX_NOTIFICATION_METHODS.error: {\n const p = (params ?? {}) as Record<string, unknown>;\n // ErrorNotification = { error: TurnError, willRetry, threadId, turnId }.\n // The authoritative reason rides `error` (a TurnError); format it. Fall\n // back to a bare `message` string for older/loose shapes.\n const message =\n \"error\" in p\n ? formatCodexTurnError(p.error as TurnError | null | undefined)\n : typeof p.message === \"string\"\n ? p.message\n : \"codex error\";\n const event: Extract<NormalizedThreadEvent, { kind: \"error\" }> = {\n kind: \"error\",\n message\n };\n if (typeof p.threadId === \"string\") event.threadId = p.threadId;\n if (typeof p.turnId === \"string\") event.turnId = p.turnId;\n if (typeof p.code === \"string\") event.code = p.code;\n if (typeof p.willRetry === \"boolean\") event.willRetry = p.willRetry;\n return event;\n }\n default:\n return null;\n }\n}\n","// Render a Codex `TurnError` into one human-readable transcript line. Ported\n// from PwrSnap (PR #194 \"surface Codex turn errors\") so the kit — which now owns\n// the controller — never drops a failed turn's cause. Never throws; always\n// returns a non-empty string usable directly as transcript text.\n\nimport type { TurnError } from \"@pwrdrvr/codex-app-server-protocol/v2\";\n\nconst FALLBACK = \"Codex returned an error\";\n\nexport function formatCodexTurnError(error: TurnError | null | undefined): string {\n if (!error) return FALLBACK;\n const base = extractMessage(error.message) || FALLBACK;\n const details = error.additionalDetails?.trim();\n if (details && details.length > 0 && !base.includes(details)) {\n return `${base} (${details})`;\n }\n return base;\n}\n\nfunction extractMessage(raw: string | null | undefined): string {\n if (typeof raw !== \"string\") return \"\";\n const trimmed = raw.trim();\n if (trimmed.length === 0) return \"\";\n // Best-effort: unwrap a nested provider-error JSON blob. Only attempt a parse\n // when the text actually looks like JSON — a plain message is the common case\n // and must pass through verbatim.\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n const nested = nestedErrorMessage(JSON.parse(trimmed));\n if (nested) return nested;\n } catch {\n // Not JSON after all — fall through to the raw text.\n }\n }\n return trimmed;\n}\n\nfunction nestedErrorMessage(value: unknown): string {\n if (typeof value !== \"object\" || value === null) return \"\";\n const obj = value as Record<string, unknown>;\n const err = obj.error;\n if (typeof err === \"object\" && err !== null) {\n const inner = (err as Record<string, unknown>).message;\n if (typeof inner === \"string\" && inner.trim().length > 0) {\n return inner.trim();\n }\n }\n const message = obj.message;\n return typeof message === \"string\" ? message.trim() : \"\";\n}\n","// One-shot Codex App Server client for structured-output enrichment turns.\n//\n// Drives a single short turn against a persistent worker thread: build a turn\n// with caller-supplied prompt + JSON Schema (`outputSchema`), feed optional\n// local images as file-path inputs, refuse any tool calls, await the assistant\n// message, then `thread/rollback` the turn so the worker thread stays clean for\n// the next request (a prompt-cache experiment from PwrSnap).\n//\n// Ported from PwrSnap's CodexAppServerClient with the product specifics removed:\n// • the prompt + JSON Schema + base instructions are CALLER-SUPPLIED per\n// request (no CAPTURE_ENRICHMENT_SCHEMA / capture prompt baked in);\n// • the logger is injected (agent-core `Logger`);\n// • identity (`clientInfo.name`, default `serviceName`) is parameterized;\n// • the binary is resolved via codex-discovery and spawned `[\"app-server\"]`.\n//\n// The result is the RAW assistant text plus token usage — parsing/validating\n// the JSON against the caller's schema is the caller's job.\n\nimport { mkdir } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n noopLogger,\n type Logger,\n type NormalizedTokenUsage\n} from \"@pwrdrvr/agent-core\";\nimport {\n JsonRpcConnection,\n StdioJsonRpcTransport,\n type JsonRpcTransport\n} from \"@pwrdrvr/agent-transport\";\nimport { resolveCodexCommand } from \"@pwrdrvr/codex-discovery\";\nimport type {\n InitializeParams,\n InitializeResponse,\n ResponseItem,\n ServerNotification\n} from \"@pwrdrvr/codex-app-server-protocol\";\nimport type {\n DynamicToolCallResponse,\n ItemCompletedNotification,\n Model,\n ModelListResponse,\n ThreadStartResponse,\n ThreadTokenUsage,\n ThreadTokenUsageUpdatedNotification,\n TurnCompletedNotification,\n TurnStartResponse,\n UserInput\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\nimport { normalizeTokenUsage } from \"./normalize\";\n\nexport type CodexOneShotTransportFactory = (command: string) => JsonRpcTransport;\n\nexport type CodexModelOption = {\n id: string;\n model: string;\n displayName: string;\n description: string;\n hidden: boolean;\n inputModalities: Model[\"inputModalities\"];\n defaultServiceTier: string | null;\n isDefault: boolean;\n};\n\nexport type CodexOneShotClientOptions = {\n command?: string;\n /** Identity sent as `clientInfo.name`. Defaults to \"agent-kit\". */\n clientName?: string;\n clientTitle?: string;\n clientVersion?: string;\n /** serviceName for the worker thread. Defaults to \"agent-kit\". */\n serviceName?: string;\n /** Working dir for the persistent worker thread (keeps it out of any repo). */\n workspaceDir?: string;\n /** Human-readable name set on the worker thread. */\n workerThreadName?: string;\n /** Per-thread Codex config overlay applied to the worker thread. */\n threadConfig?: Record<string, unknown>;\n requestTimeoutMs?: number;\n turnTimeoutMs?: number;\n env?: NodeJS.ProcessEnv;\n transportFactory?: CodexOneShotTransportFactory;\n logger?: Logger;\n};\n\nexport type CodexOneShotRequest = {\n /** The user-message text (the caller's prompt) for this turn. */\n prompt: string;\n /** Local image file paths fed as `localImage` inputs (not inlined as base64). */\n imagePaths?: readonly string[];\n /** JSON Schema constraining the final assistant message (`outputSchema`). */\n outputSchema?: unknown;\n /** Base instructions for the worker thread (set once; changing it re-creates\n * the worker thread). */\n baseInstructions?: string;\n /** Reasoning effort for the turn. Defaults to \"low\". */\n effort?: string;\n model?: string | null;\n /** Model provider (ThreadStartParams.modelProvider) for the worker thread.\n * Omit for the Codex default. Part of the worker-thread cache key. */\n modelProvider?: string | null;\n abortSignal?: AbortSignal;\n};\n\nexport type CodexOneShotResponse = {\n /** The raw assistant message text. Caller parses/validates against its schema. */\n rawText: string;\n threadId: string;\n turnId: string;\n userAgent: string;\n model: string;\n modelProvider: string;\n serviceTier: string | null;\n tokenUsage: NormalizedTokenUsage | null;\n};\n\ntype PendingTurn = {\n threadId: string;\n turnId: string;\n agentMessages: string[];\n tokenUsage: ThreadTokenUsage | null;\n resolve: (value: { rawText: string; tokenUsage: ThreadTokenUsage | null }) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\ntype WorkerThread = {\n threadId: string;\n modelKey: string;\n baseInstructions: string;\n model: string;\n modelProvider: string;\n serviceTier: string | null;\n};\n\nconst DEFAULT_CLIENT_NAME = \"agent-kit\";\nconst DEFAULT_SERVICE_NAME = \"agent-kit\";\n\nexport class CodexOneShotClient {\n private readonly requestTimeoutMs: number;\n private readonly turnTimeoutMs: number;\n private readonly logger: Logger;\n private readonly transportFactory: CodexOneShotTransportFactory | null;\n private resolvedCommand: string | null = null;\n private connection: JsonRpcConnection | null = null;\n private initializeResponse: InitializeResponse | null = null;\n private pendingTurn: PendingTurn | null = null;\n private workerThread: WorkerThread | null = null;\n private queue: Promise<void> = Promise.resolve();\n\n constructor(private readonly options: CodexOneShotClientOptions = {}) {\n this.requestTimeoutMs = options.requestTimeoutMs ?? 20_000;\n this.turnTimeoutMs = options.turnTimeoutMs ?? 120_000;\n this.logger = options.logger ?? noopLogger;\n this.transportFactory = options.transportFactory ?? null;\n }\n\n /** Run one structured-output turn. Calls are serialized — only one turn is in\n * flight at a time against the shared worker thread. */\n async run(request: CodexOneShotRequest): Promise<CodexOneShotResponse> {\n const run = this.queue.catch(() => undefined).then(() => this.runInner(request));\n this.queue = run.then(\n () => undefined,\n () => undefined\n );\n return run;\n }\n\n private async runInner(request: CodexOneShotRequest): Promise<CodexOneShotResponse> {\n const connection = await this.getConnection();\n const initialized = await this.initialize();\n let thread: WorkerThread | null = null;\n let turnId: string | null = null;\n let rolledBack = false;\n let aborted = false;\n\n const abortHandler = (): void => {\n aborted = true;\n if (thread && turnId) {\n void connection\n .request(\"turn/interrupt\", { threadId: thread.threadId, turnId }, this.requestTimeoutMs)\n .catch((error: unknown) => {\n this.logger.warn(\"turn interrupt failed\", {\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n };\n\n request.abortSignal?.addEventListener(\"abort\", abortHandler, { once: true });\n\n try {\n if (request.abortSignal?.aborted) {\n throw new DOMException(\"one-shot turn aborted\", \"AbortError\");\n }\n\n thread = await this.getWorkerThread(\n request.model ?? null,\n request.modelProvider ?? null,\n request.baseInstructions ?? \"\"\n );\n\n const input: UserInput[] = [\n { type: \"text\", text: request.prompt, text_elements: [] },\n ...imagePathsToLocalImageInputs(request.imagePaths ?? [])\n ];\n\n const turnResponse = (await connection.request(\n \"turn/start\",\n {\n threadId: thread.threadId,\n model: request.model ?? null,\n input,\n effort: request.effort ?? \"low\",\n ...(request.outputSchema !== undefined ? { outputSchema: request.outputSchema } : {})\n },\n this.requestTimeoutMs\n )) as TurnStartResponse;\n turnId = turnResponse.turn.id;\n\n if (request.abortSignal?.aborted || aborted) {\n throw new DOMException(\"one-shot turn aborted\", \"AbortError\");\n }\n\n const { rawText, tokenUsage } = await this.waitForTurn(thread.threadId, turnId);\n await this.rollbackWorkerThread(thread.threadId);\n rolledBack = true;\n return {\n rawText,\n threadId: thread.threadId,\n turnId,\n userAgent: initialized.userAgent,\n model: thread.model,\n modelProvider: thread.modelProvider,\n serviceTier: thread.serviceTier,\n tokenUsage: tokenUsage === null ? null : normalizeTokenUsage(tokenUsage)\n };\n } finally {\n request.abortSignal?.removeEventListener(\"abort\", abortHandler);\n if (thread && turnId && !rolledBack) {\n await this.rollbackWorkerThread(thread.threadId).catch((error: unknown) => {\n this.logger.warn(\"worker thread rollback failed\", {\n threadId: thread?.threadId,\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n }\n }\n\n async listModels(input: { includeHidden?: boolean } = {}): Promise<CodexModelOption[]> {\n const connection = await this.getConnection();\n await this.initialize();\n const models: CodexModelOption[] = [];\n let cursor: string | null = null;\n do {\n const response = (await connection.request(\n \"model/list\",\n { cursor, limit: 100, includeHidden: input.includeHidden ?? false },\n this.requestTimeoutMs\n )) as ModelListResponse;\n models.push(...response.data.map(modelToOption));\n cursor = response.nextCursor;\n } while (cursor !== null);\n return models;\n }\n\n async close(): Promise<void> {\n const connection = this.connection;\n const thread = this.workerThread;\n this.connection = null;\n this.initializeResponse = null;\n this.workerThread = null;\n this.queue = Promise.resolve();\n if (connection) {\n if (thread) {\n await connection\n .request(\"thread/archive\", { threadId: thread.threadId }, this.requestTimeoutMs)\n .catch((error: unknown) => {\n this.logger.warn(\"thread archive failed\", {\n threadId: thread.threadId,\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n await connection.close();\n }\n }\n\n // ---- worker-thread management ----\n\n private async getWorkerThread(\n model: string | null,\n modelProvider: string | null,\n baseInstructions: string\n ): Promise<WorkerThread> {\n const modelKey = `${model ?? \"__default__\"}@${modelProvider ?? \"__default__\"}::${baseInstructions}`;\n if (this.workerThread?.modelKey === modelKey) {\n return this.workerThread;\n }\n if (this.workerThread) {\n const stale = this.workerThread;\n this.workerThread = null;\n const connection = await this.getConnection();\n await connection\n .request(\"thread/archive\", { threadId: stale.threadId }, this.requestTimeoutMs)\n .catch((error: unknown) => {\n this.logger.warn(\"thread archive failed\", {\n threadId: stale.threadId,\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n\n const connection = await this.getConnection();\n const workspaceDir = await this.prepareWorkspace();\n const threadResponse = (await connection.request(\n \"thread/start\",\n {\n model,\n ...(modelProvider !== null ? { modelProvider } : {}),\n ephemeral: false,\n cwd: workspaceDir,\n runtimeWorkspaceRoots: [workspaceDir],\n serviceName: this.options.serviceName ?? DEFAULT_SERVICE_NAME,\n approvalPolicy: \"never\",\n sandbox: \"read-only\",\n ...(baseInstructions.length > 0 ? { baseInstructions } : {}),\n // Persistent worker thread for a prompt-cache experiment: keep the\n // thread id stable across requests, then roll back each turn. The\n // dedicated cwd keeps the worker out of any host repo/worktree.\n ...(this.options.threadConfig !== undefined ? { config: this.options.threadConfig } : {}),\n environments: [],\n experimentalRawEvents: false,\n persistExtendedHistory: false\n },\n this.requestTimeoutMs\n )) as ThreadStartResponse;\n await this.clearThreadGitInfo(threadResponse.thread.id);\n await this.setWorkerThreadName(threadResponse.thread.id);\n this.workerThread = {\n threadId: threadResponse.thread.id,\n modelKey,\n baseInstructions,\n model: threadResponse.model,\n modelProvider: threadResponse.modelProvider,\n serviceTier: threadResponse.serviceTier\n };\n return this.workerThread;\n }\n\n private async rollbackWorkerThread(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await connection.request(\"thread/rollback\", { threadId, numTurns: 1 }, this.requestTimeoutMs);\n }\n\n private async prepareWorkspace(): Promise<string> {\n const workspaceDir =\n this.options.workspaceDir ?? join(tmpdir(), \"agent-kit\", \"oneshot-worker\");\n await mkdir(workspaceDir, { recursive: true });\n return workspaceDir;\n }\n\n private async clearThreadGitInfo(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await connection\n .request(\n \"thread/metadata/update\",\n { threadId, gitInfo: { sha: null, branch: null, originUrl: null } },\n this.requestTimeoutMs\n )\n .catch((error: unknown) => {\n this.logger.warn(\"thread git metadata clear failed\", {\n threadId,\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n\n private async setWorkerThreadName(threadId: string): Promise<void> {\n const connection = await this.getConnection();\n await connection\n .request(\n \"thread/name/set\",\n { threadId, name: this.options.workerThreadName ?? \"agent-kit One-Shot Worker\" },\n this.requestTimeoutMs\n )\n .catch((error: unknown) => {\n this.logger.warn(\"worker thread name set failed\", {\n threadId,\n error: error instanceof Error ? error.message : String(error)\n });\n });\n }\n\n // ---- connection / turn plumbing ----\n\n private async resolveCommand(): Promise<string> {\n if (this.resolvedCommand !== null) return this.resolvedCommand;\n const resolved = await resolveCodexCommand({\n command: this.options.command ?? \"codex\",\n env: this.options.env ?? process.env\n });\n this.resolvedCommand = resolved.command;\n return resolved.command;\n }\n\n private async initialize(): Promise<InitializeResponse> {\n if (this.initializeResponse) return this.initializeResponse;\n const connection = await this.getConnection();\n const name = this.options.clientName ?? DEFAULT_CLIENT_NAME;\n const params: InitializeParams = {\n clientInfo: {\n name,\n title: this.options.clientTitle ?? name,\n version: this.options.clientVersion ?? \"0.0.0\"\n },\n capabilities: {\n experimentalApi: true,\n requestAttestation: false\n }\n };\n const response = (await connection.request(\n \"initialize\",\n params,\n this.requestTimeoutMs\n )) as InitializeResponse;\n this.initializeResponse = response;\n return response;\n }\n\n private async getConnection(): Promise<JsonRpcConnection> {\n if (this.connection) return this.connection;\n\n let transport: JsonRpcTransport;\n if (this.transportFactory !== null) {\n transport = this.transportFactory(this.options.command ?? \"codex\");\n } else {\n const command = await this.resolveCommand();\n transport = new StdioJsonRpcTransport({\n command,\n args: [\"app-server\"],\n ...(this.options.env !== undefined ? { env: this.options.env } : {}),\n logger: this.logger\n });\n }\n\n const connection = new JsonRpcConnection(transport, this.requestTimeoutMs, undefined, {\n logger: this.logger,\n logContext: { owner: \"codex-oneshot-client\" }\n });\n connection.setNotificationHandler((method, params) => {\n this.handleNotification(method, params);\n });\n connection.setRequestHandler((method, params) => this.handleServerRequest(method, params));\n await connection.connect();\n this.connection = connection;\n return connection;\n }\n\n private waitForTurn(\n threadId: string,\n turnId: string\n ): Promise<{ rawText: string; tokenUsage: ThreadTokenUsage | null }> {\n if (this.pendingTurn) {\n throw new Error(\"codex one-shot client already has an active turn\");\n }\n\n return new Promise<{ rawText: string; tokenUsage: ThreadTokenUsage | null }>(\n (resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingTurn = null;\n reject(new Error(\"codex one-shot turn timed out\"));\n }, this.turnTimeoutMs);\n this.pendingTurn = {\n threadId,\n turnId,\n agentMessages: [],\n tokenUsage: null,\n resolve,\n reject,\n timer\n };\n }\n );\n }\n\n private handleNotification(method: string, params: unknown): void {\n if (method === \"item/completed\") {\n this.handleItemCompleted(params as ItemCompletedNotification);\n return;\n }\n if (method === \"rawResponseItem/completed\") {\n this.handleRawResponseItemCompleted(params as ServerNotification[\"params\"]);\n return;\n }\n if (method === \"thread/tokenUsage/updated\") {\n this.handleThreadTokenUsageUpdated(params as ThreadTokenUsageUpdatedNotification);\n return;\n }\n if (method === \"turn/completed\") {\n this.handleTurnCompleted(params as TurnCompletedNotification);\n }\n }\n\n private handleItemCompleted(params: ItemCompletedNotification): void {\n const pending = this.pendingTurn;\n if (!pending || params.threadId !== pending.threadId || params.turnId !== pending.turnId) {\n return;\n }\n if (params.item.type === \"agentMessage\") {\n pending.agentMessages.push(params.item.text);\n }\n }\n\n private handleRawResponseItemCompleted(params: ServerNotification[\"params\"]): void {\n const pending = this.pendingTurn;\n if (!pending || typeof params !== \"object\" || params === null) {\n return;\n }\n const maybe = params as { threadId?: unknown; turnId?: unknown; item?: ResponseItem };\n if (maybe.threadId !== pending.threadId || maybe.turnId !== pending.turnId) {\n return;\n }\n const item = maybe.item;\n if (item?.type !== \"message\" || item.role !== \"assistant\") {\n return;\n }\n const text = item.content\n .filter((content) => content.type === \"output_text\")\n .map((content) => content.text)\n .join(\"\");\n if (text) {\n pending.agentMessages.push(text);\n }\n }\n\n private handleTurnCompleted(params: TurnCompletedNotification): void {\n const pending = this.pendingTurn;\n if (!pending || params.threadId !== pending.threadId || params.turn.id !== pending.turnId) {\n return;\n }\n\n clearTimeout(pending.timer);\n this.pendingTurn = null;\n\n if (params.turn.status === \"failed\") {\n pending.reject(new Error(params.turn.error?.message ?? \"codex one-shot turn failed\"));\n return;\n }\n if (params.turn.status === \"interrupted\") {\n pending.reject(new DOMException(\"one-shot turn aborted\", \"AbortError\"));\n return;\n }\n\n const rawText = pending.agentMessages.at(-1)?.trim();\n if (!rawText) {\n pending.reject(new Error(\"codex one-shot turn returned no assistant message\"));\n return;\n }\n pending.resolve({ rawText, tokenUsage: pending.tokenUsage });\n }\n\n private handleThreadTokenUsageUpdated(params: ThreadTokenUsageUpdatedNotification): void {\n const pending = this.pendingTurn;\n if (!pending || params.threadId !== pending.threadId || params.turnId !== pending.turnId) {\n return;\n }\n pending.tokenUsage = params.tokenUsage;\n }\n\n private async handleServerRequest(method: string, _params: unknown): Promise<unknown> {\n if (method === \"item/tool/call\") {\n // One-shot enrichment exposes no tools — refuse any tool call.\n return {\n contentItems: [\n { type: \"inputText\", text: \"This one-shot run does not expose tools.\" }\n ],\n success: false\n } satisfies DynamicToolCallResponse;\n }\n this.logger.debug(\"unhandled codex server request\", { method });\n return {};\n }\n}\n\nfunction modelToOption(model: Model): CodexModelOption {\n return {\n id: model.id,\n model: model.model,\n displayName: model.displayName,\n description: model.description,\n hidden: model.hidden,\n inputModalities: model.inputModalities,\n defaultServiceTier: model.defaultServiceTier,\n isDefault: model.isDefault\n };\n}\n\nfunction imagePathsToLocalImageInputs(imagePaths: readonly string[]): UserInput[] {\n // `localImage` lets App Server read the file as an image input. Do NOT inline a\n // base64 data URL — the bridge can account that payload like fresh text.\n return imagePaths.map((path) => ({ type: \"localImage\", path }));\n}\n","// A per-thread Codex config overlay that disables Codex's coding-agent prompt\n// and hosted-tool scaffolding, so an App Server thread is scoped to the host's\n// own surfaces (chat, enrichment) instead of inheriting the full coding agent.\n//\n// Pass this as `config` at `thread/start` (the `-c key=value` mechanism). Empty\n// `environments: []` is still required separately at thread/start to drop the\n// env-gated shell / unified_exec / apply_patch builtins.\n\n/**\n * Generic \"disable coding-agent scaffolding\" config overlay. Hosts spread this\n * into `CodexStartThreadOptions.config` (optionally merging their own keys).\n */\nexport const DISABLE_CODING_AGENT_THREAD_CONFIG: Record<string, unknown> = {\n web_search: \"disabled\",\n include_permissions_instructions: false,\n include_apps_instructions: false,\n include_collaboration_mode_instructions: false,\n include_environment_context: false,\n skills: {\n include_instructions: false\n },\n features: {\n apps: false,\n plugins: false,\n tool_suggest: false,\n image_generation: false,\n multi_agent: false,\n goals: false\n }\n};\n","// Type-safe tool-definition primitive for a host's chat tool catalog.\n//\n// A host exposes its tool catalog to Codex as `DynamicToolSpec[]` (registered\n// at `thread/start`). Each `ToolSpec` pairs an agent-readable description + a\n// zod argument schema (the audit surface) with a single `dispatch` body the\n// host injects (it runs whatever the host wants — a command bus, an RPC, a\n// direct call). The kit never imports any concrete dispatch target.\n//\n// `defineTool` is an identity helper: it preserves each call site's `TArgs`\n// inference (the `argsSchema`'s inferred type flows into the `dispatch` body)\n// so the host never writes `any`. At the catalog boundary the type parameter is\n// erased to `AnyToolSpec` (see below): a catalog mixes tools with different\n// `TArgs`, and `ToolSpec<TArgs>` is contravariant in `TArgs` via `dispatch`, so\n// `ToolSpec<{a:number}>` is NOT assignable to `ToolSpec<unknown>`. Erasing to\n// `any` at the boundary is sound because `dispatchToolCall` zod-validates the\n// arguments at runtime before the typed `dispatch` body ever sees them.\n\nimport { z } from \"zod\";\nimport type {\n DynamicToolCallOutputContentItem,\n DynamicToolSpec\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\n\n/**\n * Result of a tool `dispatch`. The agent only ever sees text or image content,\n * so a structured host error is collapsed to a plain string at this boundary.\n */\nexport type ToolDispatchResult =\n | { ok: true; data: unknown }\n // For tools that return rich content the agent must SEE rather than read as\n // JSON (e.g. an `inputImage` data URL), pass content items through verbatim\n // instead of JSON-stringifying.\n | { ok: true; contentItems: DynamicToolCallOutputContentItem[] }\n | { ok: false; error: string };\n\n/**\n * One chat tool. The single audit unit: description (what the agent reads),\n * `argsSchema` (what the agent must satisfy — validated before dispatch), and\n * `dispatch` (the host-injected body it resolves to).\n */\nexport type ToolSpec<TArgs> = {\n /** Namespace this tool lives under; matched against `DynamicToolCallParams.namespace`. */\n namespace: string;\n /** snake_case agent-facing name, e.g. \"library_list\". */\n name: string;\n /** Agent-readable, terse. Shown verbatim to Codex. */\n description: string;\n /** zod schema for the tool arguments; also the source of `inputSchema`. */\n argsSchema: z.ZodType<TArgs>;\n /**\n * Behaviour hints surfaced to the agent / approval UI. Optional per tool;\n * omit (rather than set `undefined`) when not applicable —\n * `exactOptionalPropertyTypes` is on.\n */\n annotations?: {\n destructiveHint?: boolean;\n readOnlyHint?: boolean;\n idempotentHint?: boolean;\n };\n /**\n * The host-injected dispatch this tool resolves to. Receives the zod-validated\n * args (typed as `TArgs`) plus the calling thread id.\n */\n dispatch: (args: TArgs, ctx: { threadId: string }) => Promise<ToolDispatchResult>;\n};\n\n/**\n * Identity helper that preserves `TArgs` inference at each call site, so a\n * tool's `dispatch` body is fully type-checked against its own `argsSchema`\n * without any cast.\n */\nexport function defineTool<TArgs>(spec: ToolSpec<TArgs>): ToolSpec<TArgs> {\n return spec;\n}\n\n/**\n * A `ToolSpec` with its argument type erased — the shape a heterogeneous catalog\n * holds. `defineTool(...)`'s typed result is assignable to this, so a host writes\n * `[defineTool(a), defineTool(b)]` and passes it straight to `buildToolCatalog` /\n * `dispatchToolCall`. Args are validated at runtime, so the erasure is safe.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyToolSpec = ToolSpec<any>;\n\n/**\n * Convert a `ToolSpec` into the protocol `DynamicToolSpec` registered with Codex\n * at `thread/start`. The `inputSchema` is derived from the tool's zod\n * `argsSchema` via zod v4's `z.toJSONSchema()` (JSON Schema draft 2020-12).\n */\nexport function toDynamicToolSpec(spec: AnyToolSpec): DynamicToolSpec {\n return {\n namespace: spec.namespace,\n name: spec.name,\n description: spec.description,\n inputSchema: z.toJSONSchema(spec.argsSchema) as DynamicToolSpec[\"inputSchema\"]\n };\n}\n","// Generic catalog-builder + dispatcher derived from a host-supplied `ToolSpec[]`.\n//\n// • `buildToolCatalog()` — the `DynamicToolSpec[]` a host registers with Codex\n// at `thread/start`.\n// • `dispatchToolCall()` — routes an incoming `DynamicToolCallParams` back to\n// its matching tool: matches namespace + name, zod-validates the arguments,\n// runs the tool's injected dispatch, and wraps the outcome as a\n// `DynamicToolCallResponse`.\n//\n// Failure policy: NEVER throw across the tool-call boundary. Unknown tool,\n// namespace mismatch, bad arguments, and dispatch errors all return\n// `{ success: false }` with a text contentItem describing the problem, so the\n// agent can self-correct on its next turn.\n\nimport { z } from \"zod\";\nimport type {\n DynamicToolCallParams,\n DynamicToolCallResponse,\n DynamicToolSpec\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\nimport type { AnyToolSpec } from \"./define-tool\";\nimport { toDynamicToolSpec } from \"./define-tool\";\n\n/**\n * Build the `DynamicToolSpec[]` registered with Codex at `thread/start`. Pure\n * projection of the catalog — an empty catalog yields an empty spec list.\n */\nexport function buildToolCatalog(catalog: ReadonlyArray<AnyToolSpec>): DynamicToolSpec[] {\n return catalog.map(toDynamicToolSpec);\n}\n\n/**\n * Route an incoming `DynamicToolCallParams` to its catalog entry and run it.\n * Always resolves — never throws — so a malformed or unknown call comes back as\n * a `success: false` response the agent can recover from.\n */\nexport async function dispatchToolCall(\n params: DynamicToolCallParams,\n catalog: ReadonlyArray<AnyToolSpec>\n): Promise<DynamicToolCallResponse> {\n const entry = catalog.find((tool) => tool.name === params.tool);\n if (entry === undefined) {\n return errorResponse(`Unknown tool: ${params.tool}`);\n }\n\n // `namespace` is `string | null` on the wire. Accept a missing/null namespace\n // (Codex may omit it) but reject an explicit mismatch.\n if (params.namespace !== null && params.namespace !== entry.namespace) {\n return errorResponse(`Tool \"${params.tool}\" is not in namespace \"${params.namespace}\".`);\n }\n\n const parsed = entry.argsSchema.safeParse(params.arguments);\n if (!parsed.success) {\n return errorResponse(`Invalid arguments for \"${params.tool}\": ${formatZodError(parsed.error)}`);\n }\n\n let result: Awaited<ReturnType<AnyToolSpec[\"dispatch\"]>>;\n try {\n result = await entry.dispatch(parsed.data, { threadId: params.threadId });\n } catch (cause) {\n return errorResponse(\n `Tool \"${params.tool}\" failed: ${cause instanceof Error ? cause.message : String(cause)}`\n );\n }\n\n if (!result.ok) {\n return errorResponse(result.error);\n }\n\n // A tool that returns pre-built content items (e.g. an inputImage) passes them\n // through verbatim so the model SEES the content rather than a JSON blob.\n if (\"contentItems\" in result) {\n return { success: true, contentItems: result.contentItems };\n }\n\n return {\n success: true,\n contentItems: [{ type: \"inputText\", text: JSON.stringify(result.data) }]\n };\n}\n\nfunction errorResponse(message: string): DynamicToolCallResponse {\n return {\n success: false,\n contentItems: [{ type: \"inputText\", text: message }]\n };\n}\n\nfunction formatZodError(error: z.ZodError): string {\n return error.issues\n .map((issue) => {\n const path = issue.path.join(\".\");\n return path.length > 0 ? `${path}: ${issue.message}` : issue.message;\n })\n .join(\"; \");\n}\n","// The CANONICAL, backend-agnostic chat controller for agent-kit.\n//\n// Ties together a shared `AgentBackend` (one connection, many threads — Codex\n// App Server OR an ACP agent, driven identically), an injected agent-core\n// `ThreadStore` (thread index + per-turn journal + usage accounting), and a\n// host-supplied tool catalog + prompt builders. It owns orchestration + the\n// method surface (createThread / listThreads / rename / archive / sendMessage /\n// getHistory / interrupt / resolveApproval / wire); the host owns storage and\n// maps the controller's `ChatControllerEvent`s to its own IPC.\n//\n// Ported from PwrSnap's ChatThreadController with every product seam broken:\n// • persistence is the injected `ThreadStore` (no better-sqlite3, no\n// saveAiThreadUsage / estimateAiUsageCost import — the host computes cost in\n// its store impl via `recordUsage`);\n// • the backend is an `AgentBackend` (not a concrete CodexThreadClient), and\n// the controller subscribes via `backend.onEvent((e) => …)` switching on\n// `e.kind` instead of six granular per-event hooks;\n// • the catalog, `dispatchToolCall`, `buildSystemPrompt`, `buildTurnContext`,\n// and `broadcast` are all injected — no command bus, no PwrSnap tools or\n// typed event channels; `broadcast` takes a single neutral\n// `ChatControllerEvent`;\n// • `Settings` is generic (`TSettings`); the controller freezes a snapshot at\n// turn start and forwards it to the prompt builder, NEVER inspecting fields.\n//\n// Load-bearing design (preserved verbatim from PwrSnap):\n// • Per-thread TurnState in a Map, NEVER a singleton — two threads can stream\n// concurrently without cross-wiring.\n// • Settings are SNAPSHOTTED at turn start; a mid-turn change does not\n// retro-apply to the in-flight turn.\n// • Approvals carry (threadId, turnId, approvalId); a late / mismatched\n// resolution is rejected, never resolves the wrong turn.\n// • The host UI is a VIEW of this controller's state — all mutation flows out\n// via the `broadcast` seam.\n\nimport {\n noopLogger,\n type AgentBackend,\n type AgentBackendToolCall,\n type AgentForkThreadOptions,\n type AgentStartThreadOptions,\n type AgentStartTurnOptions,\n type AgentTurnInput,\n type Logger,\n type NormalizedApprovalDecision,\n type NormalizedApprovalRequest,\n type NormalizedMessage,\n type NormalizedThreadEvent,\n type NormalizedThreadRecord,\n type NormalizedThreadStatus,\n type NormalizedThreadView,\n type NormalizedTokenUsage,\n type NormalizedToolCall,\n type NormalizedToolCallUpdate,\n type NormalizedTurnStatus,\n type ThreadListOptions,\n type ThreadStore,\n mergeToolCall\n} from \"@pwrdrvr/agent-core\";\nimport type {\n DynamicToolCallParams,\n DynamicToolCallResponse,\n DynamicToolSpec\n} from \"@pwrdrvr/codex-app-server-protocol/v2\";\n\n/** The backend the controller drives. Codex (`CodexThreadClient`) and ACP\n * (`AcpAgentClient`) both implement the non-generic `AgentBackend`; the\n * controller builds NEUTRAL thread/turn options, so any backend drops in\n * identically with no per-backend branching. Retained as an alias to\n * `AgentBackend` so existing hosts that name `ChatBackend` keep compiling. */\nexport type ChatBackend = AgentBackend;\n\n/** Builds the per-thread system prompt (base + host guidance). Injected as\n * `baseInstructions` at thread/start. Receives the frozen settings snapshot and\n * the thread's anchor; the controller never inspects `TSettings`. */\nexport type ChatSystemPromptBuilder<TSettings = unknown> = (input: {\n settings: TSettings;\n anchorId: string | null;\n}) => string;\n\n/**\n * The neutral event union the controller broadcasts. The host maps these to its\n * own IPC. Surface-agnostic: a library-chat host and a sizzle-chat host map the\n * same union. Generalizes PwrSnap's six typed `events:*Chat:*` channels.\n */\nexport type ChatControllerEvent =\n | { type: \"thread_updated\"; thread: NormalizedThreadView }\n | { type: \"stream_delta\"; threadId: string; turnId: string; messageId: string; delta: string }\n | { type: \"tool_call\"; threadId: string; turnId: string; toolCall: NormalizedToolCall }\n | { type: \"message_committed\"; threadId: string; message: NormalizedMessage }\n | { type: \"turn_interrupted\"; threadId: string; turnId: string }\n | {\n type: \"approval_requested\";\n threadId: string;\n turnId: string;\n approval: NormalizedApprovalRequest;\n };\n\n/** Re-broadcasts the controller's neutral event stream to the host's UI. */\nexport type ChatBroadcast = (event: ChatControllerEvent) => void;\n\n/** Friendly present-tense labels for tool activity chips, keyed by tool name. */\nexport type ToolLabelMap = Record<string, string>;\n\nexport type ChatThreadControllerDeps<TSettings = unknown> = {\n /** The shared backend (Codex or ACP). */\n client: ChatBackend;\n /** Host persistence: thread index + per-turn journal + usage accounting. */\n store: ThreadStore;\n /** Reads the current host settings snapshot (frozen per turn). */\n readSettings: () => Promise<TSettings>;\n /** Re-broadcasts neutral controller events to the host UI. */\n broadcast: ChatBroadcast;\n /** Builds the per-thread system prompt. */\n buildSystemPrompt: ChatSystemPromptBuilder<TSettings>;\n /** Per-turn runtime context (L3), sent as a leading turn item framed as\n * system-generated — never folded into the user's message. Receives the\n * turn's anchor. Omit for no per-turn context. */\n buildTurnContext?: (anchor: string) => string;\n /** DynamicToolSpec[] registered on every thread/start. */\n catalog?: DynamicToolSpec[];\n /** Routes an incoming tool call to the host's tools. Defaults to a no-tools\n * responder when omitted. */\n dispatchToolCall?: (params: DynamicToolCallParams) => Promise<DynamicToolCallResponse>;\n /** Friendly chip labels for tool activity. */\n toolLabels?: ToolLabelMap;\n /** Default-Access policy applied to every chat thread. */\n approvalPolicy?: string;\n sandbox?: string;\n /** Default serviceName for thread/start. */\n serviceName?: string;\n /** Per-thread Codex config overlay applied on every thread/start. */\n threadConfig?: Record<string, unknown>;\n /** Thread environments. `[]` disables exec-environment access. */\n threadEnvironments?: unknown[];\n /** Opaque per-surface MCP server config forwarded to an ACP backend's\n * `reopenThread` so a SHARED agent process can serve this surface's tools\n * (different surfaces pass different servers). Ignored by backends without\n * `reopenThread` (Codex). */\n threadMcpServers?: readonly unknown[];\n /** Reasoning effort for turns. Defaults to \"medium\". */\n effort?: string;\n /** Default model id for thread/start (host's per-surface default). Omit for Codex default. */\n model?: string;\n /** Default model provider for thread/start — the \"provider\" a host picks when\n * more than one is configured. Omit for Codex default. */\n modelProvider?: string;\n logger?: Logger;\n /** Injectable clock for tests. */\n now?: () => number;\n};\n\n/** Per-thread, in-flight turn state. */\ntype TurnState<TSettings> = {\n turnId: string;\n assistantMessageId: string;\n /** Accumulated streamed text for the in-flight assistant message. */\n buffer: string;\n /** Frozen at turn start — a mid-turn settings change can't retro-apply. */\n settingsSnapshot: TSettings;\n tokenUsage: NormalizedTokenUsage | null;\n /** Set when the backend emits an `error` for this turn. Surfaced in the\n * committed (failed) assistant message so the transcript shows WHY. */\n lastError: string | null;\n};\n\ntype ThreadModelState = {\n model: string | null;\n modelProvider: string | null;\n serviceTier: string | null;\n};\n\n/** A pending approval awaiting the host's decision. */\ntype PendingApproval = {\n threadId: string;\n turnId: string;\n approvalId: string;\n resolve: (decision: NormalizedApprovalDecision) => void;\n};\n\n/** One journal entry: a committed chat message. */\ntype JournalMessageEntry = { kind: \"message\"; message: NormalizedMessage };\n\nconst RATE_LIMIT_TURNS = 5;\nconst RATE_LIMIT_WINDOW_MS = 60_000;\n\n/** The committed assistant message text. The streamed buffer is always carried\n * (a turn can fault after streaming partial text). For a FAILED turn the\n * recorded error is appended so the transcript shows WHY it failed — folded\n * under the buffer when there's prose, else standing alone. */\nfunction buildFinalText(\n status: NormalizedTurnStatus,\n buffer: string,\n lastError: string | null\n): string {\n const errorText =\n status === \"failed\" && lastError !== null && lastError.trim().length > 0\n ? lastError.trim()\n : null;\n if (errorText === null) return buffer;\n return buffer.trim().length > 0 ? `${buffer.trimEnd()}\\n\\n${errorText}` : errorText;\n}\n\nexport class ChatThreadController<TSettings = unknown> {\n private readonly deps: ChatThreadControllerDeps<TSettings>;\n private readonly logger: Logger;\n private readonly turns = new Map<string, TurnState<TSettings>>();\n private readonly pendingApprovals = new Map<string, PendingApproval>();\n /** Per-thread recent turn timestamps for rate limiting. */\n private readonly turnTimestamps = new Map<string, number[]>();\n private readonly threadModels = new Map<string, ThreadModelState>();\n /** Accumulates streamed `tool_call`/`tool_call_update` events by id so the\n * full call can be surfaced once it reaches a terminal status (ACP backends\n * stream pending → in_progress → completed for tools they run themselves /\n * via MCP, unlike the Codex `onToolCall` request seam). Keyed by toolCall id. */\n private readonly streamedToolCalls = new Map<string, NormalizedToolCall>();\n private wired = false;\n\n constructor(deps: ChatThreadControllerDeps<TSettings>) {\n this.deps = deps;\n this.logger = deps.logger ?? noopLogger;\n }\n\n /** Wire the shared backend's subscription hooks ONCE. Idempotent. */\n wire(): void {\n if (this.wired) return;\n this.wired = true;\n const { client } = this.deps;\n client.onEvent((event) => this.onBackendEvent(event));\n client.onToolCall((call) => this.onToolCall(call));\n client.onApprovalRequest((method, params) => this.onApprovalRequest(method, params));\n }\n\n private now(): number {\n return this.deps.now ? this.deps.now() : Date.now();\n }\n\n // ---- thread lifecycle ----\n\n async createThread(\n opts: { name?: string; anchorId?: string | null } = {}\n ): Promise<NormalizedThreadView> {\n const anchorId = opts.anchorId ?? null;\n const settings = await this.deps.readSettings();\n const baseInstructions = this.deps.buildSystemPrompt({ settings, anchorId });\n const displayName =\n opts.name && opts.name.trim().length > 0 ? opts.name.trim() : this.defaultName();\n\n const preparedDir = await this.deps.store.prepareThreadDir(displayName);\n\n // NEUTRAL thread-open options. Every backend maps these onto its native\n // protocol internally — the controller never builds a Codex- or ACP-shaped\n // payload. `tools` is opaque (a Codex backend casts to DynamicToolSpec[];\n // ACP ignores it).\n const startOptions: AgentStartThreadOptions = {\n instructions: baseInstructions,\n cwd: preparedDir.path,\n workspaceRoots: [preparedDir.path]\n };\n if (this.deps.approvalPolicy !== undefined) startOptions.approvalPolicy = this.deps.approvalPolicy;\n if (this.deps.sandbox !== undefined) startOptions.sandbox = this.deps.sandbox;\n if (this.deps.model !== undefined) startOptions.model = this.deps.model;\n if (this.deps.modelProvider !== undefined) startOptions.modelProvider = this.deps.modelProvider;\n if (this.deps.serviceName !== undefined) startOptions.serviceName = this.deps.serviceName;\n if (this.deps.catalog !== undefined) startOptions.tools = this.deps.catalog;\n if (this.deps.threadConfig !== undefined) startOptions.config = this.deps.threadConfig;\n if (this.deps.threadEnvironments !== undefined) {\n startOptions.environments = this.deps.threadEnvironments;\n }\n\n // Backends that establish their session lazily (ACP — the agent process is\n // spawned on the first turn via reopenThread) expose `createDeferredThread`\n // to mint a thread id WITHOUT the multi-second spawn, so \"New chat\" is\n // instant. Backends without it (Codex) open the thread eagerly as before.\n const deferrable = this.deps.client as {\n createDeferredThread?: (\n options: AgentStartThreadOptions\n ) => Promise<{ threadId: string } & Partial<ThreadModelState>>;\n };\n let started: { threadId: string } & Partial<ThreadModelState>;\n try {\n started =\n typeof deferrable.createDeferredThread === \"function\"\n ? await deferrable.createDeferredThread(startOptions)\n : await this.deps.client.startThread(startOptions);\n } catch (cause) {\n await this.deps.store.discardPreparedThreadDir(preparedDir).catch(() => undefined);\n throw cause;\n }\n\n await this.deps.client.clearThreadGitInfo?.(started.threadId).catch((cause) => {\n this.logger.warn(\"chat thread git metadata clear failed\", {\n threadId: started.threadId,\n message: cause instanceof Error ? cause.message : String(cause)\n });\n });\n\n this.threadModels.set(started.threadId, {\n model: started.model ?? null,\n modelProvider: started.modelProvider ?? null,\n serviceTier: started.serviceTier ?? null\n });\n\n // Glue the thread to the subject it was started from. Null anchor = an\n // unscoped thread. The anchor is written in the SAME insert as the rest of\n // the row — one write, not create-then-update.\n const record = await this.deps.store.create({\n threadId: started.threadId,\n name: displayName,\n anchorId,\n preparedDir\n });\n const view = this.toView(record);\n this.deps.broadcast({ type: \"thread_updated\", thread: view });\n return view;\n }\n\n async listThreads(\n opts: { includeArchived?: boolean; anchorId?: string | null } = {}\n ): Promise<NormalizedThreadView[]> {\n // Filtering (archived + anchor scoping) is pushed into the store's indexed\n // query — no full scan in the controller. When an anchor is supplied the list\n // is scoped to that subject's threads; when omitted, every anchor is listed.\n const listOpts: ThreadListOptions = {\n includeArchived: opts.includeArchived ?? false,\n ...(opts.anchorId !== undefined ? { anchorId: opts.anchorId } : {})\n };\n const records = await this.deps.store.list(listOpts);\n return records.map((r) => this.toView(r));\n }\n\n async rename(threadId: string, name: string): Promise<NormalizedThreadView> {\n const record = await this.deps.store.update(threadId, { name: name.trim() });\n const view = this.toView(record);\n this.deps.broadcast({ type: \"thread_updated\", thread: view });\n return view;\n }\n\n async archive(threadId: string, archived: boolean): Promise<NormalizedThreadView> {\n const record = await this.deps.store.update(threadId, { archived });\n if (archived) await this.deps.client.archiveThread?.(threadId).catch(() => undefined);\n const view = this.toView(record);\n this.deps.broadcast({ type: \"thread_updated\", thread: view });\n return view;\n }\n\n /** Fork every non-archived thread anchored to `sourceAnchorId` into fresh\n * threads anchored to `targetAnchorId`, carrying each source's journal — used\n * when a host duplicates a subject (e.g. a Sizzle reel) so its chats come\n * along. Requires a backend that supports forking (Codex `thread/fork`);\n * throws on a backend (ACP) that doesn't. */\n async forkThreadsForAnchor(input: {\n sourceAnchorId: string;\n targetAnchorId: string;\n }): Promise<NormalizedThreadView[]> {\n const client = this.deps.client;\n if (client.forkThread === undefined) {\n throw new Error(\"the active backend does not support forking threads\");\n }\n const forkThread = client.forkThread.bind(client);\n\n const sourceThreads = await this.deps.store.list({\n includeArchived: false,\n anchorId: input.sourceAnchorId\n });\n if (sourceThreads.length === 0) return [];\n\n const settings = await this.deps.readSettings();\n const baseInstructions = this.deps.buildSystemPrompt({\n settings,\n anchorId: input.targetAnchorId\n });\n const forkedViews: NormalizedThreadView[] = [];\n\n for (const source of sourceThreads) {\n const preparedDir = await this.deps.store.prepareThreadDir(source.name);\n const forkOptions: AgentForkThreadOptions = {\n sourceThreadId: source.threadId,\n instructions: baseInstructions,\n cwd: preparedDir.path,\n workspaceRoots: [preparedDir.path]\n };\n if (this.deps.approvalPolicy !== undefined) forkOptions.approvalPolicy = this.deps.approvalPolicy;\n if (this.deps.sandbox !== undefined) forkOptions.sandbox = this.deps.sandbox;\n if (this.deps.threadConfig !== undefined) forkOptions.config = this.deps.threadConfig;\n\n let forked: { threadId: string } & Partial<ThreadModelState>;\n try {\n forked = await forkThread(forkOptions);\n } catch (cause) {\n await this.deps.store.discardPreparedThreadDir(preparedDir).catch(() => undefined);\n throw cause;\n }\n\n await this.deps.client.clearThreadGitInfo?.(forked.threadId).catch((cause) => {\n this.logger.warn(\"forked chat thread git metadata clear failed\", {\n threadId: forked.threadId,\n message: cause instanceof Error ? cause.message : String(cause)\n });\n });\n this.threadModels.set(forked.threadId, {\n model: forked.model ?? null,\n modelProvider: forked.modelProvider ?? null,\n serviceTier: forked.serviceTier ?? null\n });\n\n const record = await this.deps.store.create({\n threadId: forked.threadId,\n name: source.name,\n anchorId: input.targetAnchorId,\n preparedDir\n });\n // Carry the source's per-turn journal so the forked thread shows history.\n const journal = await this.deps.store.readJournal(source.threadId);\n for (const entry of journal) {\n await this.deps.store.journalAppend(forked.threadId, entry);\n }\n const view = this.toView(record);\n this.deps.broadcast({ type: \"thread_updated\", thread: view });\n forkedViews.push(view);\n }\n return forkedViews;\n }\n\n // ---- turns ----\n\n async sendMessage(input: {\n threadId: string;\n text: string;\n anchorId?: string | null;\n /** Local image file paths to attach to this turn. Forwarded neutrally as\n * `AgentTurnInput.imagePaths`; the backend maps to its native attachment\n * (Codex `localImage`, ACP `image` blocks). */\n imagePaths?: readonly string[];\n }): Promise<{ turnId: string }> {\n const { threadId } = input;\n if (this.turns.has(threadId)) {\n throw new Error(\"a turn is already in progress for this thread\");\n }\n this.enforceRateLimit(threadId);\n\n if (input.anchorId !== undefined && input.anchorId !== null) {\n await this.deps.store.appendAnchor(threadId, input.anchorId);\n }\n\n // Persist + broadcast the user message BEFORE starting the turn so a dispatch\n // failure doesn't lose the typed prompt.\n const userMessage: NormalizedMessage = {\n id: this.randomId(),\n role: \"user\",\n text: input.text,\n createdAt: this.now()\n };\n await this.commitMessage(threadId, userMessage);\n\n const settingsSnapshot = await this.deps.readSettings();\n\n // Per-turn active-context is prepended to the turn text as a leading,\n // explicitly system-framed block — separated from the user's text by a blank\n // line, NOT silently merged into the prose. It's emitted only for the CURRENT\n // turn (never accumulated) so the thread carries no stale context blocks, and\n // the static instructions stay byte-identical across turns so the backend can\n // prompt-cache them. The neutral `AgentTurnInput` carries a single text field,\n // so the context rides as a labeled preamble rather than a separate protocol\n // item.\n const anchorForTurn = input.anchorId ?? (await this.currentAnchor(threadId));\n let turnText = input.text;\n if (anchorForTurn !== null && this.deps.buildTurnContext !== undefined) {\n turnText = `${this.deps.buildTurnContext(anchorForTurn)}\\n\\n${input.text}`;\n }\n const turnInput: AgentTurnInput = { text: turnText };\n if (input.imagePaths !== undefined) turnInput.imagePaths = input.imagePaths;\n\n // ACP-style backends keep their session IN-PROCESS, so a thread persisted\n // across an app restart has no live backend session (\"Unknown ACP thread\"\n // on the next turn). Re-establish one bound to the SAME thread id, with the\n // system prompt re-applied, before starting the turn. No-op for backends\n // that persist threads server-side (Codex) — they don't implement this seam.\n const reopenable = this.deps.client as {\n reopenThread?: (options: {\n threadId: string;\n buildInstructions?: () => string;\n mcpServers?: readonly unknown[];\n }) => Promise<void>;\n };\n if (typeof reopenable.reopenThread === \"function\") {\n // Lazy: the backend only builds the prompt if it actually re-establishes\n // a session (skipped when the session is still live), so a normal turn\n // doesn't rebuild the system prompt. The per-surface MCP servers ride\n // along so a SHARED agent process spawns THIS surface's tools.\n await reopenable.reopenThread({\n threadId,\n buildInstructions: () =>\n this.deps.buildSystemPrompt({ settings: settingsSnapshot, anchorId: anchorForTurn }),\n ...(this.deps.threadMcpServers !== undefined\n ? { mcpServers: this.deps.threadMcpServers }\n : {})\n });\n }\n\n const startTurnOptions: AgentStartTurnOptions = {\n threadId,\n input: turnInput,\n reasoning: this.deps.effort ?? \"medium\"\n };\n\n let turnId: string;\n try {\n const started = await this.deps.client.startTurn(startTurnOptions);\n turnId = started.turnId;\n } catch (cause) {\n // Mark a placeholder assistant message failed so the UI shows Retry.\n const failed: NormalizedMessage = {\n id: this.randomId(),\n role: \"assistant\",\n text: \"\",\n createdAt: this.now()\n };\n await this.commitMessage(threadId, failed);\n this.logger.warn(\"chat turn start failed\", {\n threadId,\n message: cause instanceof Error ? cause.message : String(cause)\n });\n throw cause;\n }\n\n const assistantMessageId = this.randomId();\n this.turns.set(threadId, {\n turnId,\n assistantMessageId,\n buffer: \"\",\n settingsSnapshot,\n tokenUsage: null,\n lastError: null\n });\n this.recordTurn(threadId);\n await this.broadcastThreadStatus(threadId, { kind: \"streaming\", turnId });\n return { turnId };\n }\n\n async getHistory(threadId: string): Promise<NormalizedMessage[]> {\n return this.readJournalMessages(threadId);\n }\n\n async interrupt(threadId: string): Promise<void> {\n const turn = this.turns.get(threadId);\n if (turn === undefined) return;\n await this.deps.client.interruptTurn(threadId).catch(() => undefined);\n await this.finalizeAssistant(threadId, \"interrupted\");\n this.deps.broadcast({ type: \"turn_interrupted\", threadId, turnId: turn.turnId });\n }\n\n // ---- approval flow ----\n\n async resolveApproval(input: {\n threadId: string;\n turnId: string;\n approvalId: string;\n decision: NormalizedApprovalDecision;\n }): Promise<void> {\n const key = approvalKey(input.threadId, input.turnId, input.approvalId);\n const pending = this.pendingApprovals.get(key);\n if (pending === undefined) {\n this.logger.warn(\"resolveApproval: no matching pending approval (stale?)\", { key });\n return;\n }\n this.pendingApprovals.delete(key);\n pending.resolve(input.decision);\n }\n\n // ---- backend subscription handlers ----\n\n private onBackendEvent(event: NormalizedThreadEvent): void {\n switch (event.kind) {\n case \"agent_message_delta\":\n this.onDelta(event.threadId, event.turnId, event.itemId, event.delta);\n return;\n case \"token_usage\":\n this.onTokenUsage(event.threadId, event.turnId, event.usage);\n return;\n case \"thread_settings\":\n this.threadModels.set(event.settings.threadId, {\n model: event.settings.model ?? null,\n modelProvider: event.settings.modelProvider ?? null,\n serviceTier: event.settings.serviceTier ?? null\n });\n return;\n case \"turn_completed\":\n void this.onTurnCompleted(event.threadId, event.turnId, event.status);\n return;\n case \"error\":\n void this.onTurnError(event.threadId, event.turnId, event.message, event.willRetry);\n return;\n case \"tool_call\":\n case \"tool_call_update\":\n // Backends that run their OWN tools (ACP agents — directly or via an\n // MCP server) report them as streamed tool_call events, NOT through the\n // `onToolCall` request seam (which only fires for host dynamic tools the\n // backend asks US to run, i.e. Codex). Surface those to the chat UI too,\n // so an ACP agent's tool usage shows the same activity chips as Codex.\n this.onStreamedToolCall(event);\n return;\n default:\n // reasoning_delta / agent_message / plan_update / turn_started /\n // approval_request are handled elsewhere or are informational.\n return;\n }\n }\n\n /** Accumulate a streamed tool_call / tool_call_update and broadcast it ONCE\n * it settles. The host UI dedups activity chips by id, so — like the\n * `onToolCall` seam — we surface only the terminal state with its final\n * status + label, rather than the intermediate pending/in-progress churn. */\n private onStreamedToolCall(\n event: Extract<NormalizedThreadEvent, { kind: \"tool_call\" | \"tool_call_update\" }>\n ): void {\n const id = event.toolCall.id;\n const merged: NormalizedToolCall =\n event.kind === \"tool_call\"\n ? event.toolCall\n : mergeToolCall(\n this.streamedToolCalls.get(id) ?? synthesizeToolCallBase(event.toolCall),\n event.toolCall\n );\n this.streamedToolCalls.set(id, merged);\n if (\n merged.status === \"completed\" ||\n merged.status === \"failed\" ||\n merged.status === \"cancelled\"\n ) {\n this.streamedToolCalls.delete(id);\n this.deps.broadcast({\n type: \"tool_call\",\n threadId: event.threadId,\n turnId: event.turnId,\n toolCall: merged\n });\n }\n }\n\n private onDelta(threadId: string, turnId: string, itemId: string, delta: string): void {\n const turn = this.turns.get(threadId);\n if (turn === undefined || turn.turnId !== turnId) return;\n turn.buffer += delta;\n this.deps.broadcast({\n type: \"stream_delta\",\n threadId,\n turnId,\n messageId: turn.assistantMessageId,\n delta\n });\n }\n\n private async onTurnCompleted(\n threadId: string,\n turnId: string,\n status: NormalizedTurnStatus\n ): Promise<void> {\n const turn = this.turns.get(threadId);\n if (turn === undefined || turn.turnId !== turnId) return;\n await this.finalizeAssistant(threadId, status);\n }\n\n /** The backend faulted a turn. Record the authoritative reason so it lands in\n * the committed (failed) assistant message; when terminal (`willRetry` not\n * true) end the turn now rather than waiting for a `turn_completed` that may\n * never arrive. When the backend says it WILL retry, keep the turn open and\n * let the eventual `turn_completed` decide its fate (carrying the reason if it\n * ends up failing). */\n private async onTurnError(\n threadId: string | undefined,\n turnId: string | undefined,\n message: string,\n willRetry: boolean | undefined\n ): Promise<void> {\n if (threadId === undefined || turnId === undefined) return;\n const turn = this.turns.get(threadId);\n if (turn === undefined || turn.turnId !== turnId) return;\n turn.lastError = message;\n if (willRetry !== true) {\n await this.finalizeAssistant(threadId, \"failed\");\n }\n }\n\n private onTokenUsage(threadId: string, turnId: string, usage: NormalizedTokenUsage): void {\n const turn = this.turns.get(threadId);\n if (turn === undefined || turn.turnId !== turnId) return;\n turn.tokenUsage = usage;\n }\n\n private async onToolCall(call: AgentBackendToolCall): Promise<unknown> {\n const params = call.params as DynamicToolCallParams;\n const response = this.deps.dispatchToolCall\n ? await this.deps.dispatchToolCall(params)\n : ({\n contentItems: [{ type: \"inputText\", text: \"No tools are enabled for this chat yet.\" }],\n success: false\n } satisfies DynamicToolCallResponse);\n // Surface the tool invocation to the chat UI as it happens (the activity chip\n // + working indicator). Re-broadcast as a neutral `tool_call` event carrying\n // the call's terminal status + a friendly label.\n this.deps.broadcast({\n type: \"tool_call\",\n threadId: params.threadId,\n turnId: params.turnId,\n toolCall: {\n id: params.callId,\n name: params.tool,\n kind: \"other\",\n label: humanizeToolCall(params.tool, response.success, this.deps.toolLabels),\n status: response.success ? \"completed\" : \"failed\",\n args: params.arguments,\n result: response\n }\n });\n return response;\n }\n\n private async onApprovalRequest(\n method: string,\n params: unknown\n ): Promise<NormalizedApprovalDecision> {\n // Best-effort extraction of (threadId, turnId); backend shapes vary by method.\n const p = (params ?? {}) as Record<string, unknown>;\n let threadId = typeof p.threadId === \"string\" ? p.threadId : \"\";\n let turnId = typeof p.turnId === \"string\" ? p.turnId : \"\";\n\n // The backend doesn't always tag an approval with its (threadId, turnId).\n // Without a threadId the host can't match the approval to a visible thread, so\n // the promise below would never resolve and the turn would hang. Recover the\n // only-possible thread when exactly one turn is in flight; otherwise auto-DENY\n // (Default Access never auto-APPROVES) with a warning rather than deadlocking.\n if (threadId.length === 0) {\n const onlyEntry = this.turns.size === 1 ? [...this.turns.entries()][0] : undefined;\n if (onlyEntry !== undefined) {\n const [onlyThreadId, onlyTurn] = onlyEntry;\n threadId = onlyThreadId;\n if (turnId.length === 0) turnId = onlyTurn.turnId;\n } else {\n this.logger.warn(\"approval request without a routable threadId — auto-denying\", {\n method,\n inFlightTurns: this.turns.size\n });\n return \"denied\";\n }\n }\n\n const approvalId = this.randomId();\n const request: NormalizedApprovalRequest = normalizeApprovalParams(method, params, approvalId);\n\n const decision = await new Promise<NormalizedApprovalDecision>((resolve) => {\n this.pendingApprovals.set(approvalKey(threadId, turnId, approvalId), {\n threadId,\n turnId,\n approvalId,\n resolve\n });\n this.deps.broadcast({ type: \"approval_requested\", threadId, turnId, approval: request });\n void this.broadcastThreadStatus(threadId, { kind: \"awaiting_approval\", approvalId });\n });\n\n const turn = this.turns.get(threadId);\n void this.broadcastThreadStatus(\n threadId,\n turn ? { kind: \"streaming\", turnId: turn.turnId } : { kind: \"idle\" }\n );\n return decision;\n }\n\n // ---- internals ----\n\n private async finalizeAssistant(\n threadId: string,\n status: NormalizedTurnStatus\n ): Promise<void> {\n const turn = this.turns.get(threadId);\n if (turn === undefined) return;\n this.turns.delete(threadId);\n\n const message: NormalizedMessage = {\n id: turn.assistantMessageId,\n role: \"assistant\",\n text: buildFinalText(status, turn.buffer, turn.lastError),\n createdAt: this.now()\n };\n\n this.recordUsage(threadId, turn).catch((cause) => {\n this.logger.warn(\"chat usage accounting failed\", {\n threadId,\n turnId: turn.turnId,\n message: cause instanceof Error ? cause.message : String(cause)\n });\n });\n\n await this.commitMessage(threadId, message);\n await this.broadcastThreadStatus(threadId, { kind: \"idle\" });\n }\n\n private async recordUsage(threadId: string, turn: TurnState<TSettings>): Promise<void> {\n if (turn.tokenUsage === null) return;\n const model = this.threadModels.get(threadId);\n const usage = turn.tokenUsage;\n await this.deps.store.recordUsage({\n threadId,\n turnId: turn.turnId,\n ...(model?.model != null ? { model: model.model } : {}),\n usage,\n ...(usage.contextWindow !== undefined ? { contextWindow: usage.contextWindow } : {}),\n at: this.now()\n });\n }\n\n private async commitMessage(threadId: string, message: NormalizedMessage): Promise<void> {\n const entry: JournalMessageEntry = { kind: \"message\", message };\n await this.deps.store.journalAppend(threadId, entry);\n this.deps.broadcast({ type: \"message_committed\", threadId, message });\n }\n\n private async readJournalMessages(threadId: string): Promise<NormalizedMessage[]> {\n const entries = await this.deps.store.readJournal(threadId).catch(() => [] as unknown[]);\n const messages: NormalizedMessage[] = [];\n for (const entry of entries) {\n if (\n entry !== null &&\n typeof entry === \"object\" &&\n (entry as { kind?: unknown }).kind === \"message\"\n ) {\n const m = (entry as { message?: unknown }).message;\n if (m !== undefined) messages.push(m as NormalizedMessage);\n }\n }\n return messages;\n }\n\n private async currentAnchor(threadId: string): Promise<string | null> {\n const record = await this.deps.store.get(threadId);\n return record?.anchorId ?? null;\n }\n\n private enforceRateLimit(threadId: string): void {\n const stamps = this.turnTimestamps.get(threadId) ?? [];\n const cutoff = this.now() - RATE_LIMIT_WINDOW_MS;\n const recent = stamps.filter((t) => t >= cutoff);\n if (recent.length >= RATE_LIMIT_TURNS) {\n throw new Error(`rate limit: max ${RATE_LIMIT_TURNS} turns per minute for this thread`);\n }\n }\n\n private recordTurn(threadId: string): void {\n const stamps = this.turnTimestamps.get(threadId) ?? [];\n const cutoff = this.now() - RATE_LIMIT_WINDOW_MS;\n const recent = stamps.filter((t) => t >= cutoff);\n recent.push(this.now());\n this.turnTimestamps.set(threadId, recent);\n }\n\n private async broadcastThreadStatus(\n threadId: string,\n status: NormalizedThreadStatus\n ): Promise<void> {\n const record = await this.deps.store.get(threadId);\n if (record === null) return;\n this.deps.broadcast({ type: \"thread_updated\", thread: this.toView(record, status) });\n }\n\n private toView(\n record: NormalizedThreadRecord,\n status?: NormalizedThreadStatus\n ): NormalizedThreadView {\n const turn = this.turns.get(record.threadId);\n const resolved: NormalizedThreadStatus =\n status ?? (turn !== undefined ? { kind: \"streaming\", turnId: turn.turnId } : { kind: \"idle\" });\n return {\n threadId: record.threadId,\n name: record.name,\n createdAt: record.createdAt,\n modifiedAt: record.modifiedAt,\n anchorId: record.anchorId,\n archived: record.archived,\n pinned: record.pinned,\n lastMessagePreview: \"\",\n status: resolved\n };\n }\n\n private defaultName(): string {\n return `Chat ${localDateStamp(new Date(this.now()))}`;\n }\n\n private randomId(): string {\n return globalThis.crypto.randomUUID();\n }\n}\n\n/** Local-timezone `YYYY-MM-DD` stamp (NOT `toISOString()`, which is UTC). */\nexport function localDateStamp(d: Date): string {\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n\nfunction approvalKey(threadId: string, turnId: string, approvalId: string): string {\n return `${threadId}::${turnId}::${approvalId}`;\n}\n\n/** Friendly present-tense label for a tool invocation, shown as an activity chip.\n * The host supplies the label map; falls back to the raw tool name. The `ok` flag\n * lets a failed call read \"couldn't …\". */\n/** Build a minimal full tool call from a `tool_call_update` that arrived with\n * no prior `tool_call` to merge into (defensive — backends normally lead with\n * a full `tool_call`). */\nfunction synthesizeToolCallBase(update: NormalizedToolCallUpdate): NormalizedToolCall {\n return {\n id: update.id,\n name: update.name ?? \"tool\",\n kind: update.kind ?? \"other\",\n label: update.label ?? update.name ?? \"tool\",\n status: update.status ?? \"in_progress\"\n };\n}\n\nfunction humanizeToolCall(tool: string, ok: boolean, labels: ToolLabelMap = {}): string {\n const label = labels[tool] ?? tool;\n return ok ? label : `Couldn't: ${label.toLowerCase()}`;\n}\n\nfunction normalizeApprovalParams(\n method: string,\n params: unknown,\n approvalId: string\n): NormalizedApprovalRequest {\n const p = (params ?? {}) as Record<string, unknown>;\n const summary =\n typeof p.summary === \"string\"\n ? p.summary\n : typeof p.reason === \"string\"\n ? p.reason\n : typeof p.command === \"string\"\n ? p.command\n : undefined;\n const kind = method.includes(\"commandExecution\")\n ? \"exec\"\n : method.includes(\"fileChange\")\n ? \"patch\"\n : method.includes(\"tool\")\n ? \"tool\"\n : \"other\";\n const request: NormalizedApprovalRequest = { id: approvalId, method, kind, params };\n if (summary !== undefined) request.summary = summary;\n return request;\n}\n"],"mappings":"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","names":["noopLogger","JsonRpcConnection","StdioJsonRpcTransport","resolveCodexCommand","DEFAULT_CLIENT_NAME","DEFAULT_SERVICE_NAME","noopLogger","connection","resolveCodexCommand","StdioJsonRpcTransport","JsonRpcConnection","noopLogger"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pwrdrvr/agent-client",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Codex App Server adapter for agent-kit: long-lived multi-turn thread client, one-shot structured-output client, and a surface-agnostic chat controller, all normalizing into the agent-core neutral schema.",
5
5
  "license": "MIT",
6
6
  "author": "PwrDrvr LLC",
@@ -20,9 +20,9 @@
20
20
  "dependencies": {
21
21
  "@pwrdrvr/codex-app-server-protocol": "^0.133.0",
22
22
  "zod": "^4.0.0",
23
+ "@pwrdrvr/agent-core": "^0.1.2",
23
24
  "@pwrdrvr/agent-transport": "^0.1.5",
24
- "@pwrdrvr/codex-discovery": "^0.1.2",
25
- "@pwrdrvr/agent-core": "^0.1.2"
25
+ "@pwrdrvr/codex-discovery": "^0.1.2"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^24.0.0"