@ai-sdk/harness-codex 1.0.101 → 1.0.103

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/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @ai-sdk/harness-codex
2
2
 
3
+ ## 1.0.103
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [951c54d]
8
+ - @ai-sdk/harness@1.0.101
9
+
10
+ ## 1.0.102
11
+
12
+ ### Patch Changes
13
+
14
+ - 0c37bf0: fix(harness): avoid warning about lack of credential brokering support when `credentialForwarding` callback is used to replace all credentials with ephemeral fake secrets
15
+ - Updated dependencies [0c37bf0]
16
+ - @ai-sdk/harness@1.0.100
17
+
3
18
  ## 1.0.101
4
19
 
5
20
  ### Patch Changes
@@ -214,6 +214,7 @@ async function runBridge(options) {
214
214
  }
215
215
  }
216
216
  const pendingToolResults = /* @__PURE__ */ new Map();
217
+ const bufferedToolResults = [];
217
218
  const pendingToolApprovals = /* @__PURE__ */ new Map();
218
219
  const writeBridgeMeta = async (state) => {
219
220
  try {
@@ -393,9 +394,23 @@ async function runBridge(options) {
393
394
  const userMessages = createBridgeUserMessageQueue({ respond: emit });
394
395
  const turn = {
395
396
  emit,
396
- requestToolResult: (toolCallId) => new Promise((resolve) => {
397
- pendingToolResults.set(toolCallId, resolve);
398
- }),
397
+ requestToolResult: (requestInput) => {
398
+ const request = typeof requestInput === "string" ? { toolCallId: requestInput } : requestInput;
399
+ const bufferedIndex = bufferedToolResults.findIndex(
400
+ (buffered) => buffered.toolCallId === request.toolCallId || request.matches?.(buffered.result) === true
401
+ );
402
+ if (bufferedIndex >= 0) {
403
+ return Promise.resolve(
404
+ bufferedToolResults.splice(bufferedIndex, 1)[0].result
405
+ );
406
+ }
407
+ return new Promise((resolve) => {
408
+ pendingToolResults.set(request.toolCallId, {
409
+ resolve,
410
+ matches: request.matches
411
+ });
412
+ });
413
+ },
399
414
  requestToolApproval: (approvalId) => new Promise((resolve) => {
400
415
  pendingToolApprovals.set(approvalId, resolve);
401
416
  }),
@@ -437,10 +452,25 @@ async function runBridge(options) {
437
452
  return;
438
453
  }
439
454
  case "tool-result": {
440
- const resolver = pendingToolResults.get(msg.toolCallId);
441
- if (resolver) {
442
- pendingToolResults.delete(msg.toolCallId);
443
- resolver({ output: msg.output, isError: msg.isError });
455
+ const result = {
456
+ output: msg.output,
457
+ isError: msg.isError,
458
+ toolResult: msg.toolResult
459
+ };
460
+ const exactPending = pendingToolResults.get(msg.toolCallId);
461
+ const matchingPending = exactPending == null ? Array.from(pendingToolResults.entries()).find(
462
+ ([, pending2]) => pending2.matches?.(result) === true
463
+ ) : void 0;
464
+ const pending = exactPending ?? matchingPending?.[1];
465
+ const pendingId = exactPending != null ? msg.toolCallId : matchingPending?.[0];
466
+ if (pending != null && pendingId != null) {
467
+ pendingToolResults.delete(pendingId);
468
+ pending.resolve(result);
469
+ } else {
470
+ bufferedToolResults.push({
471
+ toolCallId: msg.toolCallId,
472
+ result
473
+ });
444
474
  }
445
475
  return;
446
476
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../harness/src/bridge/index.ts","../../../harness/src/bridge/harness-bridge-capability-unsupported-error.ts","../../src/bridge/index.ts","../../src/bridge/cli-relay.ts","../../src/bridge/codex-step-tracker.ts","../../src/bridge/create-emit-stream-event.ts","../../src/bridge/tool-relay.ts","../../src/bridge/tool-relay-auth.ts"],"sourcesContent":["// Shared in-sandbox bridge runtime. Adapter `bridge.mjs` bundles re-bundle\n// this module (tsup inlines it; `ws` stays external and resolves from the\n// sandbox-installed node_modules). It owns everything generic to the bridge\n// transport — the WebSocket server, token auth, the in-memory event log +\n// monotonic `seq`, resume replay, and the lifecycle/meta files. Any number of\n// hosts may be connected; exactly one of them owns the event stream, and\n// `start`/`resume` transfer that ownership. The adapter supplies only `onStart`\n// (drive its CLI/SDK and translate to wire events) and lifecycle cleanup hooks.\n\nimport { appendFile, mkdir, writeFile } from 'node:fs/promises';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { env as procEnv, pid, stdout } from 'node:process';\nimport { WebSocketServer, type WebSocket } from 'ws';\n\nexport { HarnessBridgeCapabilityUnsupportedError } from './harness-bridge-capability-unsupported-error';\n\nexport type BridgeState = 'init' | 'waiting' | 'running' | 'draining' | 'done';\n\n/** Outbound turn event the adapter emits. `seq` is added by the runtime. */\nexport type BridgeEvent = Record<string, unknown> & { type: string };\n\nexport type BridgeDebugLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nexport interface Experimental_BridgeUserMessage {\n readonly messageId: string;\n readonly text: string;\n accept(): void;\n reject(error: unknown): void;\n}\n\nexport interface Experimental_BridgeUserMessageQueue extends AsyncIterable<Experimental_BridgeUserMessage> {\n readonly pendingCount: number;\n close(error?: unknown): void;\n}\n\ntype InternalBridgeUserMessageQueue = Experimental_BridgeUserMessageQueue & {\n enqueue(input: { messageId: string; text: string }): void;\n};\n\ntype BridgeUserMessageResponse = {\n type: 'user-message-response';\n messageId: string;\n accepted: boolean;\n error?: { message: string };\n};\n\n/**\n * Per-session diagnostics config. The host resolves it from settings +\n * env and sends it on `start.debug`; the bridge gates console capture and\n * structured `debug-event`s on it. When disabled, nothing is captured or\n * emitted and no `seq` is consumed.\n */\nexport interface BridgeDebugConfig {\n enabled?: boolean;\n level?: BridgeDebugLevel;\n subsystems?: string[];\n}\n\nconst DEBUG_LEVEL_WEIGHT: Record<BridgeDebugLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n};\n\n/** Exact-or-dotted-prefix subsystem match (`'bridge'` matches `'bridge.turn'`). */\nfunction subsystemMatches(\n filters: string[] | undefined,\n subsystem: string,\n): boolean {\n if (!filters || filters.length === 0) return true;\n return filters.some(\n filter => subsystem === filter || subsystem.startsWith(`${filter}.`),\n );\n}\n\nfunction formatBridgeError(err: unknown): {\n name?: string;\n message: string;\n stack?: string;\n} {\n if (err instanceof Error) {\n return { name: err.name, message: err.message, stack: err.stack };\n }\n if (typeof err === 'string') {\n return { message: err };\n }\n if (err !== null && typeof err === 'object') {\n try {\n return { message: JSON.stringify(err) };\n } catch {}\n }\n return { message: String(err) };\n}\n\nfunction createBridgeUserMessageQueue(options: {\n respond(response: BridgeUserMessageResponse): void;\n}): InternalBridgeUserMessageQueue {\n const messages: Experimental_BridgeUserMessage[] = [];\n const waiters: Array<\n (result: IteratorResult<Experimental_BridgeUserMessage>) => void\n > = [];\n const entries = new Map<\n string,\n {\n response?: BridgeUserMessageResponse;\n reject(error: unknown): void;\n }\n >();\n let closed = false;\n let pendingCount = 0;\n\n const enqueue = (input: { messageId: string; text: string }): void => {\n const existing = entries.get(input.messageId);\n if (existing != null) {\n if (existing.response != null) {\n options.respond(existing.response);\n }\n return;\n }\n\n let settled = false;\n const settle = (response: BridgeUserMessageResponse): void => {\n if (settled) return;\n settled = true;\n pendingCount--;\n const entry = entries.get(input.messageId);\n if (entry != null) entry.response = response;\n options.respond(response);\n };\n const message: Experimental_BridgeUserMessage = {\n messageId: input.messageId,\n text: input.text,\n accept: () => {\n settle({\n type: 'user-message-response',\n messageId: input.messageId,\n accepted: true,\n });\n },\n reject: error => {\n settle({\n type: 'user-message-response',\n messageId: input.messageId,\n accepted: false,\n error: { message: formatBridgeError(error).message },\n });\n },\n };\n entries.set(input.messageId, {\n reject: message.reject,\n });\n pendingCount++;\n\n if (closed) {\n message.reject(\n new Error('The bridge turn is no longer accepting user messages.'),\n );\n return;\n }\n\n const waiter = waiters.shift();\n if (waiter != null) {\n waiter({ done: false, value: message });\n } else {\n messages.push(message);\n }\n };\n\n const close = (error?: unknown): void => {\n if (closed) return;\n closed = true;\n const reason =\n error ??\n new Error('The bridge turn ended before accepting the user message.');\n for (const entry of entries.values()) {\n if (entry.response == null) entry.reject(reason);\n }\n messages.length = 0;\n while (waiters.length > 0) {\n waiters.shift()!({ done: true, value: undefined });\n }\n };\n\n return {\n get pendingCount() {\n return pendingCount;\n },\n enqueue,\n close,\n [Symbol.asyncIterator]() {\n return {\n next: () => {\n const message = messages.shift();\n if (message != null) {\n return Promise.resolve({ done: false as const, value: message });\n }\n if (closed) {\n return Promise.resolve({\n done: true as const,\n value: undefined,\n });\n }\n return new Promise<IteratorResult<Experimental_BridgeUserMessage>>(\n resolve => {\n waiters.push(resolve);\n },\n );\n },\n };\n },\n };\n}\n\nfunction parseEnvList(value: string | undefined): string[] | undefined {\n if (!value) return undefined;\n const items = value\n .split(',')\n .map(item => item.trim())\n .filter(Boolean);\n return items.length > 0 ? items : undefined;\n}\n\nconst ENV_TRUTHY = new Set(['1', 'true', 'yes', 'on']);\n\n/**\n * Per-turn surface handed to {@link RunBridgeOptions.onStart}. The adapter\n * drives its runtime against these primitives; the runtime owns the transport.\n */\nexport interface BridgeTurn {\n /**\n * Emit a turn event to the host. Stamps a monotonic `seq`, appends to the\n * in-memory replay log, and sends to the live socket (best-effort — if the\n * host is mid-reconnect the event waits in the log and is replayed on\n * resume).\n */\n emit(event: BridgeEvent): void;\n\n /**\n * Register interest in a host-executed tool result and resolve when the\n * matching `tool-result` arrives. The adapter emits the `tool-call` event\n * itself (via {@link emit}) using the same `toolCallId`.\n */\n requestToolResult(\n toolCallId: string,\n ): Promise<{ output: unknown; isError?: boolean }>;\n\n /**\n * Register interest in a host approval decision and resolve when the matching\n * `tool-approval-response` arrives. The adapter emits the\n * `tool-approval-request` event itself using the same `approvalId`.\n */\n requestToolApproval(\n approvalId: string,\n ): Promise<{ approved: boolean; reason?: string }>;\n\n readonly experimental_userMessages: Experimental_BridgeUserMessageQueue;\n\n /** Aborts when the host sends `abort`. */\n readonly abortSignal: AbortSignal;\n\n /** True for the first turn since this bridge process started. */\n readonly firstTurn: boolean;\n\n /**\n * Emit a structured diagnostic. Gated by the session's debug level +\n * subsystem filter; a no-op when diagnostics are disabled. Adapters use this\n * for runtime-level instrumentation; raw `console.*` output is captured and\n * forwarded automatically.\n */\n bridgeLog(input: {\n level?: BridgeDebugLevel;\n subsystem: string;\n message: string;\n attrs?: Record<string, unknown>;\n error?: unknown;\n }): void;\n\n /**\n * Emit a non-fatal bridge warning to stderr using the runtime's harness\n * prefix. This is diagnostic-only: it does not emit a stream event, does not\n * consume a `seq`, and does not fail the turn.\n */\n emitWarning(input: { message: string }): void;\n\n emitError(input: { error: unknown; message?: string }): void;\n}\n\nexport interface RunBridgeOptions<TStart extends { type: 'start' }> {\n /** Identifier written into `bridge-meta.json` (`'claude-code'` / `'codex'`). */\n bridgeType: string;\n /** Directory for `bridge-meta.json` / `start-config.json`. Created if absent. */\n bridgeStateDir: string;\n /**\n * Drive one prompt turn. Rejections surface to the host as an `error`\n * event.\n *\n * Contract: once `turn.abortSignal` fires, wind down promptly — turns are\n * serialized, and a replacement `start` waits up to\n * {@link turnTeardownGraceMs} for this promise to settle before it\n * proceeds anyway.\n */\n onStart(start: TStart, turn: BridgeTurn): Promise<void>;\n /**\n * How long a replacement `start` waits for the previous turn's teardown\n * after aborting it, in milliseconds. Turns are serialized so an aborted\n * turn cannot emit into its replacement's event log or overlap its runtime\n * process — but only within this bound: an adapter that does not settle\n * `onStart` after its abort signal fires forfeits the protection for that\n * boundary, and the new turn proceeds anyway rather than blocking forever.\n * The default of ten seconds exceeds the Claude bridge's five-second\n * hard-abort fallback.\n */\n turnTeardownGraceMs?: number;\n /**\n * Produce the adapter-defined runtime resume data for `stop`. Defaults to\n * `{}`.\n */\n onStop?(): unknown | Promise<unknown>;\n /**\n * Perform adapter-defined destruction before the bridge exits.\n */\n onDestroy?(): void | Promise<void>;\n /** WS port. Defaults to `BRIDGE_WS_PORT` env (0 = OS-assigned). */\n port?: number;\n /** Auth token. Defaults to `BRIDGE_CHANNEL_TOKEN` env. */\n token?: string;\n /** Called with the bound port once the server is listening. */\n onListening?(port: number): void;\n /**\n * Tear the process down after `stop` / `destroy`. Defaults to closing\n * the server and calling `process.exit(0)`. Overridable for tests.\n */\n onExit?(): void;\n}\n\ntype InboundControl =\n | {\n type: 'tool-result';\n toolCallId: string;\n output: unknown;\n isError?: boolean;\n }\n | {\n type: 'tool-approval-response';\n approvalId: string;\n approved: boolean;\n reason?: string;\n }\n | { type: 'user-message'; messageId?: string; text: string }\n | { type: 'abort' }\n | { type: 'stop' }\n | { type: 'destroy' }\n | { type: 'resume'; lastSeenEventId: number };\n\nconst WS_OPEN = 1;\n\n/**\n * Boot the bridge: bind the WebSocket server, announce `bridge-ready`, and\n * service host connections for the lifetime of the process. Resolves once the\n * server is listening; the process then stays alive on the server until a\n * `stop` / `destroy` exits it.\n */\nexport interface BridgeHandle {\n /** The port the WebSocket server bound to. */\n readonly port: number;\n /** Close the WebSocket server. Does not call `process.exit`. */\n close(): Promise<void>;\n}\n\nexport async function runBridge<TStart extends { type: 'start' }>(\n options: RunBridgeOptions<TStart>,\n): Promise<BridgeHandle> {\n const { bridgeType, bridgeStateDir, onStart, onStop, onDestroy } = options;\n const teardownGraceMs = options.turnTeardownGraceMs ?? 10_000;\n const expectedToken = options.token ?? procEnv.BRIDGE_CHANNEL_TOKEN ?? '';\n const bridgeWsPort =\n options.port ?? parseInt(procEnv.BRIDGE_WS_PORT ?? '0', 10);\n\n const bridgeMetaPath = `${bridgeStateDir}/bridge-meta.json`;\n const startConfigPath = `${bridgeStateDir}/start-config.json`;\n const rerunStartConfigPath = `${bridgeStateDir}/rerun-start-config.json`;\n const eventLogPath = `${bridgeStateDir}/event-log.ndjson`;\n\n try {\n await mkdir(bridgeStateDir, { recursive: true });\n } catch {\n // Best-effort; the bridge still runs without its state files.\n }\n\n // ─── mutable runtime state ──────────────────────────────────────────\n let currentBoundPort = 0;\n let currentTurnState: BridgeState = 'init';\n /*\n * The one connection turn events stream to. A socket claims it by asking for\n * work — `start` (a turn) or `resume` (a catch-up) — never by connecting:\n * every event goes here alone, so claiming on connect would silence a turn\n * already streaming to someone else. Any number of sockets may be connected;\n * the others still exchange control frames, they just get no events.\n */\n let activeSocket: WebSocket | undefined;\n let isFirstTurn = true;\n let turnAbort: AbortController | undefined;\n let currentUserMessages: InternalBridgeUserMessageQueue | undefined;\n /**\n * Settles when the in-flight turn has fully wound down — `onStart`\n * returned or threw AND its completion state was recorded. `undefined`\n * between turns. A new `start` fences on this so turns never overlap.\n */\n let activeTurn: Promise<void> | undefined;\n\n // Diagnostics. Resolved per turn from `start.debug` with a sandbox-side\n // env fallback; gates console capture + structured `debug-event`s.\n let debugConfig: BridgeDebugConfig | undefined;\n let consoleCaptureInstalled = false;\n const envDebugEnabled = ENV_TRUTHY.has(\n (procEnv.HARNESS_DEBUG ?? '').toLowerCase(),\n );\n\n // Replay log. `seq` is monotonic across the whole process — never reset —\n // because the host's `SandboxChannel` cursor (`lastSeenEventId`) lives across\n // turns. The log *contents* are cleared at the start of each turn to bound\n // memory; the just-finished turn stays replayable until the next `start`.\n let seqCounter = 0;\n let eventLog: Array<{ seq: number; line: string }> = [];\n\n /*\n * Disk mirror of the in-memory replay log. The in-memory log is lost when the\n * bridge process dies; the on-disk `event-log.ndjson` survives in the sandbox\n * filesystem so a respawned bridge (started with `BRIDGE_REPLAY_FROM_DISK=1`)\n * can reload the in-flight turn and serve a host's resume cursor —\n * `replay` recovery. Writes are batched on `setImmediate` (single-flight via\n * `flushPromise`) to keep `emit` off the disk hot path.\n */\n let diskBuffer = '';\n let flushPromise: Promise<void> | null = null;\n\n const flushEventsToDisk = async (): Promise<void> => {\n while (diskBuffer.length > 0) {\n const buf = diskBuffer;\n diskBuffer = '';\n await appendFile(eventLogPath, buf).catch(() => {\n // Best-effort crash-recovery mirror; the in-memory log is the source of\n // truth for the live connection.\n });\n }\n };\n\n const scheduleEventFlush = (): void => {\n if (flushPromise) return;\n flushPromise = new Promise<void>(resolve => {\n setImmediate(() => {\n void flushEventsToDisk().finally(resolve);\n });\n }).finally(() => {\n flushPromise = null;\n if (diskBuffer.length > 0) {\n scheduleEventFlush();\n }\n });\n };\n\n const flushPendingEventsToDisk = async (): Promise<void> => {\n if (diskBuffer.length > 0 && !flushPromise) {\n scheduleEventFlush();\n }\n // Await each in-flight flush, re-reading `flushPromise` after every await\n // since a fresh flush may have been scheduled for buffer that arrived while\n // we waited.\n let inFlight = flushPromise;\n while (inFlight) {\n await inFlight;\n inFlight = flushPromise;\n }\n };\n\n /*\n * When respawned for `replay`, reload the previous turn's log from disk before\n * accepting any connection so the very first `resume{lastSeenEventId}` can be\n * served the tail (including the terminal `finish`). The seq counter is\n * restored to the last persisted seq so it stays aligned with the host's\n * long-lived cursor. The file is NOT truncated in this mode — only a fresh\n * `start` (next turn) clears it.\n */\n const replayFromDisk = procEnv.BRIDGE_REPLAY_FROM_DISK === '1';\n if (replayFromDisk && existsSync(eventLogPath)) {\n try {\n const lines = readFileSync(eventLogPath, 'utf8')\n .split('\\n')\n .map(line => line.trim())\n .filter(Boolean);\n eventLog = lines.map(line => ({\n seq: (JSON.parse(line) as { seq: number }).seq,\n line,\n }));\n seqCounter = eventLog.at(-1)?.seq ?? 0;\n } catch {\n // Corrupt/partial log: fall back to an empty log; the host then degrades\n // to `rerun` instead of replaying a malformed tail.\n eventLog = [];\n seqCounter = 0;\n }\n }\n\n const pendingToolResults = new Map<\n string,\n (output: { output: unknown; isError?: boolean }) => void\n >();\n const pendingToolApprovals = new Map<\n string,\n (response: { approved: boolean; reason?: string }) => void\n >();\n\n // ─── persistence (best-effort meta + start config) ──────────────────\n const writeBridgeMeta = async (state: BridgeState): Promise<void> => {\n try {\n await writeFile(\n bridgeMetaPath,\n JSON.stringify({\n type: bridgeType,\n port: currentBoundPort,\n state,\n pid,\n }),\n );\n } catch {\n // Best-effort resilience metadata; not load-bearing for the active turn.\n }\n };\n\n const writeStartConfig = async (start: unknown): Promise<void> => {\n try {\n const serialized = JSON.stringify(start);\n await writeFile(startConfigPath, serialized);\n // Frozen copy: written once, restored over start-config.json by future\n // rerun-mode recovery to re-run the original turn from scratch.\n if (!existsSync(rerunStartConfigPath)) {\n await writeFile(rerunStartConfigPath, serialized);\n }\n } catch {\n // Best-effort.\n }\n };\n\n // ─── wire send + replay ─────────────────────────────────────────────\n const emit = (event: BridgeEvent): void => {\n const seq = ++seqCounter;\n const line = JSON.stringify({ ...event, seq });\n eventLog.push({ seq, line });\n diskBuffer += `${line}\\n`;\n scheduleEventFlush();\n if (activeSocket?.readyState === WS_OPEN) {\n try {\n activeSocket.send(line);\n } catch {\n // Send is best-effort: a dropped socket leaves the event in the log,\n // replayed once the host reconnects and sends `resume`.\n }\n }\n };\n\n const replay = (ws: WebSocket, afterSeq: number): void => {\n for (const entry of eventLog) {\n if (entry.seq > afterSeq && ws.readyState === WS_OPEN) {\n ws.send(entry.line);\n }\n }\n };\n\n // ─── diagnostics ──────────────────────────────────────────────\n const shouldEmitDebugEvent = (\n level: BridgeDebugLevel,\n subsystem: string,\n ): boolean => {\n if (!debugConfig?.enabled) return false;\n const threshold = debugConfig.level ?? 'debug';\n if (DEBUG_LEVEL_WEIGHT[level] > DEBUG_LEVEL_WEIGHT[threshold]) return false;\n return subsystemMatches(debugConfig.subsystems, subsystem);\n };\n\n /*\n * Forward sandbox console output. We line-buffer the original writers (kept so\n * output still reaches the real fds) and emit one `sandbox-log` per complete\n * line. `emit` never writes to stdout/stderr, so there is no recursion.\n * Installed lazily the first time a turn enables diagnostics; once installed,\n * capture is gated per-write on `debugConfig.enabled` so a later turn can\n * disable it. Console capture is independent of the subsystem/level filter.\n */\n const rawStdoutWrite = process.stdout.write.bind(process.stdout);\n const rawStderrWrite = process.stderr.write.bind(process.stderr);\n\n const writeErrorToStderr = (input: {\n message: string;\n error: unknown;\n }): void => {\n try {\n const formatted = formatBridgeError(input.error);\n rawStderrWrite(\n `[harness:${bridgeType}:error] ${input.message}: ${formatted.message}\\n`,\n );\n if (formatted.stack) {\n rawStderrWrite(`${formatted.stack}\\n`);\n }\n } catch {}\n };\n\n const emitWarning = (input: { message: string }): void => {\n try {\n for (const line of input.message.split('\\n')) {\n if (line.trim().length > 0) {\n rawStderrWrite(`[harness:${bridgeType}:warn] ${line}\\n`);\n }\n }\n } catch {}\n };\n\n const emitError = (input: { error: unknown; message?: string }): void => {\n writeErrorToStderr({\n message: input.message ?? 'bridge error',\n error: input.error,\n });\n emit({ type: 'error', error: serialiseError(input.error) });\n };\n\n const installConsoleCapture = (): void => {\n if (consoleCaptureInstalled) return;\n consoleCaptureInstalled = true;\n const buffers: { stdout: string; stderr: string } = {\n stdout: '',\n stderr: '',\n };\n const patch =\n (stream: 'stdout' | 'stderr', raw: typeof process.stdout.write) =>\n (chunk: unknown, encoding?: unknown, cb?: unknown): boolean => {\n if (debugConfig?.enabled) {\n try {\n const enc = typeof encoding === 'string' ? encoding : 'utf8';\n const text =\n typeof chunk === 'string'\n ? chunk\n : Buffer.from(chunk as Uint8Array).toString(\n enc as BufferEncoding,\n );\n const combined = buffers[stream] + text.replace(/\\r\\n/g, '\\n');\n const parts = combined.split('\\n');\n buffers[stream] = parts.pop() ?? '';\n for (const line of parts) {\n const trimmed = line.replace(/\\s+$/, '');\n if (trimmed) {\n emit({\n type: 'sandbox-log',\n source: bridgeType,\n stream,\n line: trimmed,\n });\n }\n }\n } catch {\n // Never let capture break real output.\n }\n }\n return (raw as (c: unknown, e?: unknown, cb?: unknown) => boolean)(\n chunk,\n encoding,\n cb,\n );\n };\n process.stdout.write = patch(\n 'stdout',\n rawStdoutWrite,\n ) as typeof process.stdout.write;\n process.stderr.write = patch(\n 'stderr',\n rawStderrWrite,\n ) as typeof process.stderr.write;\n };\n\n // ─── inbound routing ────────────────────────────────────────────────\n const handleInbound = async (\n msg: TStart | InboundControl,\n ws: WebSocket,\n ): Promise<void> => {\n switch (msg.type) {\n case 'start': {\n /*\n * A new turn replaces the active one — but only after the active one\n * has fully wound down. Inbound frames are dispatched concurrently,\n * and the host settles a caller abort immediately, so a retry's\n * `start` can arrive while the aborted turn is still tearing down\n * (e.g. a graceful interrupt). Without this fence the old turn would\n * keep emitting into the new turn's cleared event log, two runtime\n * processes would run side by side, and the old turn's completion\n * would mark the bridge `waiting` underneath the new turn. Abort the\n * old turn to hasten its teardown; adapters are expected to bound\n * that teardown themselves (e.g. a hard-abort fallback), but the\n * runtime does not rely on it: the wait is capped by the teardown\n * grace period, after which the new turn proceeds anyway — the\n * pre-fence overlapping behavior — rather than hanging behind a\n * teardown that never settles.\n */\n for (;;) {\n const pendingTurn = activeTurn;\n if (pendingTurn == null) break;\n turnAbort?.abort();\n currentUserMessages?.close(\n new Error('A new bridge turn replaced the active turn.'),\n );\n let graceTimer: ReturnType<typeof setTimeout> | undefined;\n const settled = await Promise.race([\n pendingTurn.then(() => true as const),\n new Promise<false>(resolve => {\n graceTimer = setTimeout(() => resolve(false), teardownGraceMs);\n graceTimer.unref?.();\n }),\n ]);\n clearTimeout(graceTimer);\n if (!settled) break;\n }\n let turnFinished!: () => void;\n const thisTurn = new Promise<void>(resolve => (turnFinished = resolve));\n activeTurn = thisTurn;\n activeSocket = ws; // asking for a turn claims the event stream\n const firstTurn = isFirstTurn;\n isFirstTurn = false;\n eventLog = []; // clear previous turn; keep seqCounter monotonic\n // Mirror the in-memory clear to disk: the log tracks only the current\n // turn. Discard any unflushed tail from the prior turn first.\n diskBuffer = '';\n void writeFile(eventLogPath, '').catch(() => {});\n turnAbort = new AbortController();\n currentTurnState = 'running';\n void writeStartConfig(msg);\n void writeBridgeMeta('running');\n const startDebug = (msg as { debug?: BridgeDebugConfig }).debug;\n debugConfig = {\n enabled: startDebug?.enabled ?? envDebugEnabled,\n level:\n startDebug?.level ??\n (procEnv.HARNESS_DEBUG_LEVEL as BridgeDebugLevel | undefined),\n subsystems:\n startDebug?.subsystems ??\n parseEnvList(procEnv.HARNESS_DEBUG_SUBSYSTEMS),\n };\n if (debugConfig.enabled) {\n installConsoleCapture();\n }\n const userMessages = createBridgeUserMessageQueue({ respond: emit });\n const turn: BridgeTurn = {\n emit,\n requestToolResult: toolCallId =>\n new Promise(resolve => {\n pendingToolResults.set(toolCallId, resolve);\n }),\n requestToolApproval: approvalId =>\n new Promise(resolve => {\n pendingToolApprovals.set(approvalId, resolve);\n }),\n experimental_userMessages: userMessages,\n abortSignal: turnAbort.signal,\n firstTurn,\n bridgeLog: input => {\n const level = input.level ?? 'debug';\n if (!shouldEmitDebugEvent(level, input.subsystem)) return;\n emit({\n type: 'debug-event',\n level,\n subsystem: input.subsystem,\n message: input.message,\n ...(input.attrs ? { attrs: input.attrs } : {}),\n ...(input.error !== undefined\n ? { error: formatBridgeError(input.error) }\n : {}),\n });\n },\n emitWarning,\n emitError,\n };\n currentUserMessages = userMessages;\n try {\n await onStart(msg as TStart, turn);\n } catch (err) {\n emitError({ error: err, message: 'bridge turn failed' });\n } finally {\n userMessages.close();\n if (currentUserMessages === userMessages) {\n currentUserMessages = undefined;\n }\n // Only the still-active turn records completion: after a fence\n // timeout a replacement turn is already running, and this stale\n // completion must not mark the bridge waiting underneath it.\n if (activeTurn === thisTurn) {\n activeTurn = undefined;\n currentTurnState = 'waiting';\n void writeBridgeMeta('waiting');\n }\n turnFinished();\n }\n return;\n }\n case 'tool-result': {\n const resolver = pendingToolResults.get(msg.toolCallId);\n if (resolver) {\n pendingToolResults.delete(msg.toolCallId);\n resolver({ output: msg.output, isError: msg.isError });\n }\n return;\n }\n case 'tool-approval-response': {\n const resolver = pendingToolApprovals.get(msg.approvalId);\n if (resolver) {\n pendingToolApprovals.delete(msg.approvalId);\n resolver({ approved: msg.approved, reason: msg.reason });\n }\n return;\n }\n case 'user-message': {\n const messageId = msg.messageId ?? randomUUID();\n if (currentUserMessages == null) {\n sendControl(ws, {\n type: 'user-message-response',\n messageId,\n accepted: false,\n error: { message: 'The bridge has no active turn to steer.' },\n });\n return;\n }\n if (ws !== activeSocket) {\n sendControl(ws, {\n type: 'user-message-response',\n messageId,\n accepted: false,\n error: {\n message: 'The connection does not own the active bridge turn.',\n },\n });\n return;\n }\n currentUserMessages.enqueue({\n messageId,\n text: msg.text,\n });\n return;\n }\n case 'abort':\n turnAbort?.abort();\n return;\n case 'resume':\n activeSocket = ws; // asking for a catch-up claims it too\n // Synchronous, so no event can slip out live ahead of the replayed tail.\n replay(ws, msg.lastSeenEventId);\n return;\n case 'destroy':\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n await onDestroy?.();\n drainThenExit(ws, 1000, 'destroy');\n return;\n case 'stop': {\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n const data = (await onStop?.()) ?? {};\n sendControl(ws, { type: 'bridge-stop', data });\n drainThenExit(ws, 1000, 'stop');\n return;\n }\n }\n };\n\n // ─── server ─────────────────────────────────────────────────────────\n void writeBridgeMeta('init');\n\n const wss = new WebSocketServer({ port: bridgeWsPort, host: '0.0.0.0' });\n\n const exit = (): void => {\n if (options.onExit) {\n options.onExit();\n return;\n }\n wss.close(() => process.exit(0));\n setTimeout(() => process.exit(0), 1000).unref();\n };\n\n const drainThenExit = (ws: WebSocket, code: number, reason: string): void => {\n const start = Date.now();\n const tick = (): void => {\n const drained = ws.bufferedAmount === 0 || ws.readyState !== WS_OPEN;\n if (drained || Date.now() - start >= 5_000) {\n // Flush the on-disk log so a clean stop/destroy leaves a complete\n // event-log.ndjson for any later replay recovery.\n void flushPendingEventsToDisk().finally(() => {\n try {\n ws.close(code, reason);\n } finally {\n exit();\n }\n });\n return;\n }\n setTimeout(tick, 10).unref();\n };\n tick();\n };\n\n wss.on('listening', () => {\n const addr = wss.address();\n currentBoundPort = typeof addr === 'object' && addr ? addr.port : 0;\n currentTurnState = 'waiting';\n void writeBridgeMeta('waiting');\n stdout.write(\n JSON.stringify({\n type: 'bridge-ready',\n port: currentBoundPort,\n }) + '\\n',\n );\n options.onListening?.(currentBoundPort);\n });\n\n wss.on('connection', (ws: WebSocket, req: { url?: string }) => {\n const url = new URL(req.url ?? '/', 'http://localhost');\n if (url.searchParams.get('agent_bridge_token') !== expectedToken) {\n ws.close(1008, 'unauthorized');\n return;\n }\n\n // Announce liveness the instant we accept. Some sandbox runtimes complete\n // the host-side WS handshake before the connection is forwarded here; the\n // host waits for this frame before sending `start`/`resume`.\n sendControl(ws, {\n type: 'bridge-hello',\n state: currentTurnState,\n lastSeq: seqCounter,\n capabilities: { experimental_userMessageResponses: true },\n });\n\n ws.on('message', (raw: ArrayBufferLike | string) => {\n let parsed: TStart | InboundControl;\n try {\n const text =\n typeof raw === 'string' ? raw : Buffer.from(raw).toString('utf8');\n parsed = JSON.parse(text) as TStart | InboundControl;\n } catch (err) {\n sendControl(ws, {\n type: 'error',\n error: `protocol parse error: ${(err as Error).message}`,\n });\n return;\n }\n void handleInbound(parsed, ws);\n });\n\n ws.on('close', () => {\n // Only the stream owner's close matters; a socket that never claimed it,\n // or that a later `start`/`resume` displaced, closes as a no-op.\n // Crucially we do NOT abort the in-flight turn: it keeps running and its\n // events accumulate in the log for replay on reconnect.\n if (activeSocket === ws) {\n activeSocket = undefined;\n }\n });\n\n ws.on('error', () => {\n // 'close' follows; nothing to do beyond keeping the process alive.\n });\n });\n\n // Surface bridge-internal crashes to the host instead of dying silently.\n process.on('uncaughtException', err => {\n emitError({ error: err, message: 'uncaught exception' });\n });\n process.on('unhandledRejection', err => {\n emitError({ error: err, message: 'unhandled rejection' });\n });\n\n await new Promise<void>((resolve, reject) => {\n if (wss.address() != null) {\n resolve();\n return;\n }\n\n wss.once('listening', resolve);\n wss.once('error', reject);\n });\n\n return {\n port: currentBoundPort,\n close: () =>\n new Promise<void>(resolve => {\n wss.close(() => resolve());\n }),\n };\n}\n\n/*\n * Control frames answer the socket that sent the frame they reply to, so the\n * target is always explicit. Event streaming is the separate, stateful path\n * (`emit` → `activeSocket`); this one carries no state at all.\n */\nfunction sendControl(\n socket: WebSocket | undefined,\n message: Record<string, unknown>,\n): void {\n if (socket?.readyState === WS_OPEN) {\n try {\n socket.send(JSON.stringify(message));\n } catch {\n // best-effort\n }\n }\n}\n\nfunction serialiseError(err: unknown): unknown {\n if (err instanceof Error) {\n return { name: err.name, message: err.message, stack: err.stack };\n }\n return err;\n}\n","const name = 'AI_HarnessBridgeCapabilityUnsupportedError';\n\n/**\n * Signals an unsupported capability discovered inside a sandbox bridge.\n * `isInstance` also recognizes the serialized error shape received by the\n * host, where it can be translated to `HarnessCapabilityUnsupportedError`.\n */\nexport class HarnessBridgeCapabilityUnsupportedError extends Error {\n readonly harnessId?: string;\n readonly cause?: unknown;\n\n constructor({\n message,\n harnessId,\n cause,\n }: {\n message: string;\n harnessId?: string;\n cause?: unknown;\n }) {\n super(message);\n Object.defineProperty(this, 'name', { value: name });\n this.harnessId = harnessId;\n this.cause = cause;\n }\n\n static isInstance(\n error: unknown,\n ): error is HarnessBridgeCapabilityUnsupportedError {\n return (\n error != null &&\n typeof error === 'object' &&\n 'name' in error &&\n error.name === name &&\n 'message' in error &&\n typeof error.message === 'string'\n );\n }\n}\n","// Long-running process that runs alongside the `codex` CLI in the sandbox.\n// The generic transport — WebSocket server, token auth, single-flight\n// reconnect, the in-memory event log + `seq`, resume replay, and the\n// lifecycle/meta files — lives in the shared `@ai-sdk/harness/bridge` runtime.\n// This file supplies only the Codex-specific turn driver.\n//\n// Host-defined tools are routed through an HTTP relay bound to\n// `127.0.0.1:0`. The bridge writes a CLI shim into the per-session runtime\n// directory; the shim POSTs each tool call to the relay, which emits\n// `tool-call` to the host and waits for the matching `tool-result`.\n\nimport {\n runBridge,\n type BridgeEvent,\n type BridgeTurn,\n} from '@ai-sdk/harness/bridge';\nimport type { StartMessage } from '../codex-bridge-protocol';\nimport { mkdir, writeFile } from 'node:fs/promises';\n// Temporary workaround for upstream codex MCP-tool bug — see ./cli-relay.ts\nimport {\n CLI_SHIM_FILENAME,\n buildCliShimScript,\n parseToolRelayCommands,\n} from './cli-relay';\nimport { createCodexStepTracker, defaultUsage } from './codex-step-tracker';\nimport {\n createEmitStreamEvent,\n type CodexEvent,\n} from './create-emit-stream-event';\nimport { startAuthorizedToolRelay, type ToolRelay } from './tool-relay';\nimport { argv, env as procEnv, stdout } from 'node:process';\n\n/*\n * CONSTRAINT — the third-party imports below are NEVER bundled into the\n * compiled `bridge/index.mjs`. They are declared `external` in\n * tsup.config.ts and resolved at runtime from the node_modules that this\n * bridge installs *inside the sandbox* from `src/bridge/package.json` (and\n * its pinned `pnpm-lock.yaml`). That bridge package.json — NOT this host\n * package — is the single source of truth for these packages and their\n * versions; the published `@ai-sdk/harness-codex` package does not provide\n * them at runtime.\n *\n * When adding or changing a third-party import here you MUST keep all three\n * in sync, or the bridge will either get the dependency bundled in or fail\n * to resolve it in the sandbox:\n * 1. the import statement below,\n * 2. the `external` array in tsup.config.ts, and\n * 3. the dependency entry in `src/bridge/package.json`.\n */\nimport * as codexSdkModule from '@openai/codex-sdk';\n\nconst args = parseArgs(argv.slice(2));\nconst workdir = requireArg({ value: args.workdir, name: '--workdir' });\nconst bridgeStateDir = requireArg({\n value: args.bridgeStateDir,\n name: '--bridge-state-dir',\n});\nconst cliShimDir = requireArg({\n value: args.cliShimDir,\n name: '--cli-shim-dir',\n});\nconst HARNESS_CLIENT_APP = procEnv.AI_SDK_HARNESS_CLIENT_APP;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst codexSdk = codexSdkModule as any;\n\n// Codex thread id — survives across turns within this bridge process and is\n// returned to the host on `stop` so a future process can resume the thread.\nconst threadState: { id: string | undefined } = { id: undefined };\n\nawait runBridge<StartMessage>({\n bridgeType: 'codex',\n bridgeStateDir,\n onStart: runTurn,\n onStop: () => (threadState.id ? { threadId: threadState.id } : {}),\n});\n\ntype Emit = (msg: Record<string, unknown>) => void;\n\nasync function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {\n const emit: Emit = msg => turn.emit(msg as BridgeEvent);\n\n // Cross-process resume: the host carries the threadId we returned on stop.\n // Seed `threadState.id` so the codex SDK call below takes the `resumeThread`\n // branch.\n if (start.restartThread) {\n threadState.id = undefined;\n } else if (\n typeof start.resumeThreadId === 'string' &&\n start.resumeThreadId.length > 0\n ) {\n threadState.id = start.resumeThreadId;\n }\n\n /*\n * Known limitation: codex CLI does not reliably surface MCP tools to the\n * model in `codex exec --experimental-json` mode (the path the\n * `@openai/codex-sdk` uses). Some versions do not register MCP tools at all;\n * others expose the tool names but pass empty arguments.\n *\n * Until that's fixed, host tools are made available to the model via a\n * separate CLI-relay workaround (see `./cli-relay.ts`). Writing the shim\n * here, adding matching prompt guidance in the host adapter, and filtering\n * the shim command below implement the workaround and can be removed once the\n * upstream bug is fixed.\n */\n let relay: ToolRelay | undefined;\n let cliShimPath: string | undefined;\n if (start.tools && start.tools.length > 0) {\n cliShimPath = `${cliShimDir}/${CLI_SHIM_FILENAME}`;\n relay = await startToolRelay({\n tools: start.tools,\n emit,\n requestToolResult: turn.requestToolResult,\n });\n // Temporary workaround for upstream codex MCP-tool bug — see ./cli-relay.ts\n await mkdir(cliShimDir, { recursive: true });\n await writeFile(\n cliShimPath,\n buildCliShimScript({ relayPort: relay.port }),\n 'utf8',\n );\n }\n\n const codexConfig: Record<string, unknown> = {\n ...start.codexConfig,\n developer_instructions: [\n start.instructions,\n 'Only respond with your `final` message once you have fully addressed the user request.',\n ]\n .filter((instruction): instruction is string => Boolean(instruction))\n .join('\\n\\n'),\n model_reasoning_summary: 'detailed',\n };\n\n const gatewayBaseUrl = procEnv.AI_GATEWAY_BASE_URL;\n const hasGatewayAuth = Boolean(procEnv.AI_GATEWAY_API_KEY || gatewayBaseUrl);\n if (hasGatewayAuth && !gatewayBaseUrl) {\n throw new Error(\n 'AI Gateway auth was selected but AI_GATEWAY_BASE_URL is missing from the Codex bridge environment.',\n );\n }\n const apiBaseUrl = hasGatewayAuth ? gatewayBaseUrl : procEnv.OPENAI_BASE_URL;\n const codexModel =\n start.model && hasGatewayAuth && !start.model.includes('/')\n ? `openai/${start.model}`\n : start.model;\n /*\n * AI Gateway only returns populated reasoning summaries for its\n * creator-qualified model IDs. Codex treats qualified IDs as custom model\n * metadata, so its reasoning-summary capability must also be forced on for\n * the OpenAI Gateway route.\n */\n if (hasGatewayAuth && codexModel?.startsWith('openai/')) {\n codexConfig.model_supports_reasoning_summaries = true;\n }\n if (apiBaseUrl) {\n codexConfig.preferred_auth_method = 'apikey';\n codexConfig.model_provider = 'agent_bridge_openai';\n codexConfig.model_providers = {\n agent_bridge_openai: {\n name: procEnv.CODEX_MODEL_PROVIDER_NAME || 'Agent Bridge OpenAI',\n base_url: apiBaseUrl,\n env_key: 'CODEX_API_KEY',\n wire_api: 'responses',\n supports_websockets: false,\n ...(hasGatewayAuth && HARNESS_CLIENT_APP\n ? {\n http_headers: {\n 'User-Agent': HARNESS_CLIENT_APP,\n 'x-client-app': HARNESS_CLIENT_APP,\n },\n }\n : {}),\n },\n };\n }\n if (start.mcpServers != null) {\n codexConfig.mcp_servers = start.mcpServers;\n }\n const usesConfiguredModelProvider =\n typeof codexConfig.model_provider === 'string';\n\n const codex = new codexSdk.Codex({\n ...(procEnv.CODEX_API_KEY ? { apiKey: procEnv.CODEX_API_KEY } : {}),\n ...(!usesConfiguredModelProvider && apiBaseUrl\n ? { baseUrl: apiBaseUrl }\n : {}),\n env: Object.fromEntries(\n Object.entries(procEnv).filter(\n (entry): entry is [string, string] => typeof entry[1] === 'string',\n ),\n ),\n ...(Object.keys(codexConfig).length > 0 ? { config: codexConfig } : {}),\n });\n\n const threadOptions = {\n ...(codexModel ? { model: codexModel } : {}),\n sandboxMode: 'danger-full-access',\n approvalPolicy: 'never',\n workingDirectory: workdir,\n skipGitRepoCheck: true,\n ...(start.reasoningEffort\n ? { modelReasoningEffort: start.reasoningEffort }\n : {}),\n webSearchMode: start.webSearch ? 'live' : 'disabled',\n };\n const thread = threadState.id\n ? codex.resumeThread(threadState.id, threadOptions)\n : codex.startThread(threadOptions);\n\n emit({ type: 'stream-start' });\n\n const userMessage = start.prompt;\n let turnUsage: Record<string, unknown> | undefined;\n const stepTracker = createCodexStepTracker({ send: emit });\n const emitStreamEvent = createEmitStreamEvent({\n send: emit,\n stepTracker,\n setTurnUsage: usage => (turnUsage = usage),\n setThreadId: threadId => (threadState.id = threadId),\n emitWarning: turn.emitWarning,\n emitError: turn.emitError,\n });\n\n try {\n const { events } = await thread.runStreamed(userMessage, {\n signal: turn.abortSignal,\n ...(start.responseFormat?.type === 'json' &&\n start.responseFormat.schema != null\n ? { outputSchema: start.responseFormat.schema }\n : {}),\n });\n for await (const event of events as AsyncIterable<CodexEvent>) {\n if (turn.abortSignal.aborted) break;\n // Temporary workaround for upstream codex MCP-tool bug — see ./cli-relay.ts\n if (cliShimPath && event.item?.type === 'command_execution') {\n const relayCalls =\n typeof event.item.command === 'string'\n ? parseToolRelayCommands({\n command: event.item.command,\n cliShimPath,\n })\n : undefined;\n if (event.type === 'item.started' && relay && relayCalls) {\n for (const relayCall of relayCalls) {\n relay.authorizeToolCall(relayCall);\n }\n }\n if (relayCalls) {\n stepTracker.observeEvent({ event, itemId: event.item.id });\n continue;\n }\n }\n emitStreamEvent(event);\n }\n } catch (err) {\n turn.emitError({ error: err, message: 'codex turn failed' });\n return;\n } finally {\n relay?.close();\n }\n\n emit({\n type: 'finish',\n finishReason: { unified: 'stop', raw: 'stop' },\n totalUsage: turnUsage ?? defaultUsage(),\n });\n}\n\n/**\n * Tool relay — HTTP server on 127.0.0.1:0. The CLI shim invoked by Codex POSTs\n * each tool invocation here; the relay forwards the call to the host (via the\n * shared runtime's `emit`), awaits the matching `tool-result` (via\n * `requestToolResult`), and responds with `{ result }`.\n */\nasync function startToolRelay({\n tools,\n emit,\n requestToolResult,\n}: {\n tools: ReadonlyArray<{ name: string }>;\n emit: Emit;\n requestToolResult: (\n toolCallId: string,\n ) => Promise<{ output: unknown; isError?: boolean }>;\n}): Promise<ToolRelay> {\n return startAuthorizedToolRelay({ tools, emit, requestToolResult });\n}\n\nfunction parseArgs(args: string[]): {\n workdir?: string;\n bridgeStateDir?: string;\n cliShimDir?: string;\n} {\n const out: {\n workdir?: string;\n bridgeStateDir?: string;\n cliShimDir?: string;\n } = {};\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--workdir' && i + 1 < args.length) {\n out.workdir = args[++i];\n } else if (args[i] === '--bridge-state-dir' && i + 1 < args.length) {\n out.bridgeStateDir = args[++i];\n } else if (args[i] === '--cli-shim-dir' && i + 1 < args.length) {\n out.cliShimDir = args[++i];\n }\n }\n return out;\n}\n\nfunction emitFatal(message: string): never {\n stdout.write(JSON.stringify({ type: 'bridge-fatal', message }) + '\\n');\n process.exit(1);\n}\n\nfunction requireArg({\n value,\n name,\n}: {\n value: string | undefined;\n name: string;\n}): string {\n if (!value) {\n emitFatal(`Missing ${name} argument.`);\n }\n return value;\n}\n","/*\n * Temporary workaround for upstream codex CLI bug\n * https://github.com/openai/codex/issues/19425 — MCP tools registered via\n * `mcp_servers.*` are not exposed to the model in `codex exec --experimental-json`\n * mode (which is what `@openai/codex-sdk` uses). The MCP handshake completes\n * and `tools/list` succeeds, but codex never registers the tools as\n * model-callable functions.\n *\n * Until that's fixed upstream, this file implements a CLI-based relay:\n *\n * 1. A small Node script is written into harness-owned session state at turn\n * start (`buildCliShimScript`). It accepts `<toolName> <jsonInput>` as\n * argv, POSTs to the same HTTP relay the MCP shim uses, and prints the\n * result to stdout.\n *\n * 2. Tool descriptions and invocation instructions are injected into the\n * initial user prompt by the host adapter, telling the model to call host\n * tools by running `node <shim-path> <toolName> '<jsonInput>'` via its\n * built-in `bash` tool.\n *\n * 3. The bridge's event loop suppresses the matching `command_execution`\n * events (`isToolRelayCommand`) so callers receive clean `tool-call` /\n * `tool-result` events from the HTTP relay rather than seeing the\n * relay invocations as raw bash commands.\n *\n * Once #19425 is fixed and MCP tools are properly exposed in exec mode, the\n * three hookpoints in `bridge/index.ts` can be removed along with this file.\n */\nexport const CLI_SHIM_FILENAME = 'harness-tool.mjs';\n\nexport function buildCliShimScript({\n relayPort,\n}: {\n relayPort: number;\n}): string {\n return `#!/usr/bin/env node\nconst [toolName, inputJson = '{}'] = process.argv.slice(2);\nif (!toolName) {\n console.error('Usage: harness-tool <tool_name> <json_input>');\n process.exit(64);\n}\nlet input;\ntry {\n input = JSON.parse(inputJson);\n} catch (error) {\n console.error('Invalid JSON input: ' + (error instanceof Error ? error.message : String(error)));\n process.exit(64);\n}\nconst requestId = 'cli-' + Date.now() + '-' + Math.random().toString(16).slice(2);\nconst response = await fetch('http://127.0.0.1:${relayPort}', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ requestId, toolName, input }),\n});\nconst text = await response.text();\nlet payload;\ntry {\n payload = text ? JSON.parse(text) : {};\n} catch {\n payload = { error: text };\n}\nif (!response.ok || payload.error) {\n console.error(String(payload.error ?? ('tool relay failed with HTTP ' + response.status)));\n process.exit(1);\n}\nconsole.log(JSON.stringify(payload.result ?? payload, null, 2));\n`;\n}\n\nexport function isToolRelayCommand({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): boolean {\n return parseToolRelayCommands({ command, cliShimPath }) !== undefined;\n}\n\nexport function parseToolRelayCommand({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): { toolName: string; input: unknown } | undefined {\n const calls = parseToolRelayCommands({ command, cliShimPath });\n return calls?.length === 1 ? calls[0] : undefined;\n}\n\nexport function parseToolRelayCommands({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): Array<{ toolName: string; input: unknown }> | undefined {\n return parseToolRelayCommandsInternal({ command, cliShimPath, depth: 0 });\n}\n\nfunction parseToolRelayCommandsInternal({\n command,\n cliShimPath,\n depth,\n}: {\n command: string;\n cliShimPath: string;\n depth: number;\n}): Array<{ toolName: string; input: unknown }> | undefined {\n const commands = splitShellAndCommands(command);\n if (!commands) return undefined;\n if (commands.length > 1) {\n const relayCalls: Array<{ toolName: string; input: unknown }> = [];\n for (const nestedCommand of commands) {\n const nestedCalls = parseToolRelayCommandsInternal({\n command: nestedCommand,\n cliShimPath,\n depth,\n });\n if (!nestedCalls) return undefined;\n relayCalls.push(...nestedCalls);\n }\n return relayCalls;\n }\n\n const argv = parseShellWords(command);\n if (!argv) return undefined;\n\n const relayCall = parseDirectToolRelayArgv({ argv, cliShimPath });\n if (relayCall) return [relayCall];\n\n const innerCommand = extractShellEvalCommand(argv);\n if (!innerCommand || depth >= 2) return undefined;\n return parseToolRelayCommandsInternal({\n command: innerCommand,\n cliShimPath,\n depth: depth + 1,\n });\n}\n\nfunction parseDirectToolRelayArgv({\n argv,\n cliShimPath,\n}: {\n argv: string[];\n cliShimPath: string;\n}): { toolName: string; input: unknown } | undefined {\n if (argv.length < 3 || argv.length > 4) return undefined;\n if (argv[0] !== 'node' || argv[1] !== cliShimPath) return undefined;\n const toolName = argv[2];\n if (!toolName) return undefined;\n try {\n return { toolName, input: JSON.parse(argv[3] ?? '{}') };\n } catch {\n return undefined;\n }\n}\n\nfunction extractShellEvalCommand(argv: string[]): string | undefined {\n if (argv.length !== 3) return undefined;\n const shellName = argv[0].split('/').at(-1);\n if (shellName !== 'bash' && shellName !== 'sh' && shellName !== 'zsh') {\n return undefined;\n }\n if (argv[1] !== '-c' && argv[1] !== '-lc') return undefined;\n return argv[2];\n}\n\nfunction splitShellAndCommands(command: string): string[] | undefined {\n const commands: string[] = [];\n let start = 0;\n let quote: '\"' | \"'\" | undefined;\n\n for (let i = 0; i < command.length; i++) {\n const char = command[i];\n if (quote === \"'\") {\n if (char === \"'\") quote = undefined;\n continue;\n }\n if (quote === '\"') {\n if (char === '\"') {\n quote = undefined;\n } else if (char === '\\\\') {\n i++;\n }\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n continue;\n }\n if (char === '\\\\') {\n i++;\n continue;\n }\n if (char === '&' && command[i + 1] === '&') {\n const nestedCommand = command.slice(start, i).trim();\n if (!nestedCommand) return undefined;\n commands.push(nestedCommand);\n start = i + 2;\n i++;\n }\n }\n\n if (quote) return undefined;\n const nestedCommand = command.slice(start).trim();\n if (!nestedCommand) return undefined;\n commands.push(nestedCommand);\n return commands;\n}\n\nfunction parseShellWords(command: string): string[] | undefined {\n const words: string[] = [];\n let current = '';\n let quote: '\"' | \"'\" | undefined;\n let hasCurrent = false;\n\n const pushCurrent = () => {\n if (!hasCurrent) return;\n words.push(current);\n current = '';\n hasCurrent = false;\n };\n\n for (let i = 0; i < command.length; i++) {\n const char = command[i];\n if (quote === \"'\") {\n if (char === \"'\") {\n quote = undefined;\n } else {\n current += char;\n }\n hasCurrent = true;\n continue;\n }\n if (quote === '\"') {\n if (char === '\"') {\n quote = undefined;\n } else if (char === '\\\\' && i + 1 < command.length) {\n current += command[++i];\n } else {\n current += char;\n }\n hasCurrent = true;\n continue;\n }\n if (/\\s/.test(char)) {\n pushCurrent();\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n hasCurrent = true;\n continue;\n }\n if (char === '\\\\' && i + 1 < command.length) {\n current += command[++i];\n hasCurrent = true;\n continue;\n }\n if (/[;&|<>()`$]/.test(char)) return undefined;\n current += char;\n hasCurrent = true;\n }\n if (quote) return undefined;\n pushCurrent();\n return words;\n}\n","import type { BridgeEvent } from '@ai-sdk/harness/bridge';\n\ntype Emit = (msg: BridgeEvent) => void;\n\nexport type CodexStepTrackerItem = {\n type: string;\n};\n\nexport type CodexStepTrackerEvent = {\n type: string;\n item?: CodexStepTrackerItem;\n};\n\nexport type CodexStepTracker = {\n observeEvent(input: {\n event: CodexStepTrackerEvent;\n itemId: string | undefined;\n }): void;\n finishTurn(): void;\n};\n\nexport function createCodexStepTracker(input: {\n send: Emit;\n}): CodexStepTracker {\n let stepOpen = false;\n const pendingToolItemIds = new Set<string>();\n\n const finishStep = (): void => {\n if (!stepOpen || pendingToolItemIds.size > 0) return;\n input.send({\n type: 'finish-step',\n finishReason: { unified: 'stop', raw: 'stop' },\n usage: defaultUsage(),\n harnessMetadata: { codex: { inferredStep: true } },\n });\n stepOpen = false;\n };\n\n return {\n observeEvent({ event, itemId }) {\n const item = event.item;\n if (!item || !isStepItem(item)) return;\n\n stepOpen = true;\n\n if (isToolStepItem(item)) {\n if (event.type === 'item.started' && itemId) {\n pendingToolItemIds.add(itemId);\n } else if (event.type === 'item.completed') {\n if (itemId) pendingToolItemIds.delete(itemId);\n finishStep();\n }\n return;\n }\n },\n finishTurn() {\n pendingToolItemIds.clear();\n finishStep();\n },\n };\n}\n\nfunction isStepItem(item: CodexStepTrackerItem): boolean {\n return isModelStepItem(item) || isToolStepItem(item);\n}\n\nfunction isModelStepItem(item: CodexStepTrackerItem): boolean {\n return item.type === 'reasoning' || item.type === 'agent_message';\n}\n\nfunction isToolStepItem(item: CodexStepTrackerItem): boolean {\n return (\n item.type === 'command_execution' ||\n item.type === 'mcp_tool_call' ||\n item.type === 'web_search' ||\n item.type === 'file_change' ||\n item.type === 'todo_list'\n );\n}\n\nexport function defaultUsage(): Record<string, unknown> {\n return {\n inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },\n outputTokens: { total: 0, text: 0 },\n };\n}\n","import type { HarnessV1BuiltinToolName } from '@ai-sdk/harness';\nimport type { BridgeTurn } from '@ai-sdk/harness/bridge';\nimport { randomUUID } from 'node:crypto';\nimport type { CodexStepTracker } from './codex-step-tracker';\n\ntype Emit = (message: Record<string, unknown>) => void;\n\nexport type CodexItem = {\n type: string;\n id?: string;\n text?: string;\n command?: string;\n exit_code?: number;\n aggregated_output?: string;\n status?: 'in_progress' | 'completed' | 'failed';\n server?: string;\n tool?: string;\n arguments?: unknown;\n result?: { content?: unknown; structured_content?: unknown } | unknown;\n error?: { message?: string };\n query?: string;\n message?: string;\n changes?: ReadonlyArray<{\n path: string;\n kind: 'add' | 'delete' | 'update';\n }>;\n};\n\nexport type CodexEvent = {\n type:\n | 'thread.started'\n | 'turn.completed'\n | 'turn.failed'\n | 'error'\n | 'item.started'\n | 'item.updated'\n | 'item.completed';\n item?: CodexItem;\n usage?: Record<string, number>;\n error?: { message: string };\n message?: string;\n thread_id?: string;\n};\n\n/*\n * Native Codex tool name → cross-harness common name. Tools outside this map\n * (e.g. MCP tools the model invokes by name) have no common equivalent; their\n * native name is forwarded as-is on `tool-call` events.\n */\nconst NATIVE_TO_COMMON: Readonly<Record<string, HarnessV1BuiltinToolName>> = {\n shell: 'bash',\n web_search: 'webSearch',\n};\n\nfunction toCommonName(nativeName: string): HarnessV1BuiltinToolName | string {\n return NATIVE_TO_COMMON[nativeName] ?? nativeName;\n}\n\nexport function createEmitStreamEvent({\n send,\n stepTracker,\n setTurnUsage,\n setThreadId,\n emitWarning,\n emitError,\n}: {\n send: Emit;\n stepTracker: CodexStepTracker;\n setTurnUsage: (usage: Record<string, unknown>) => void;\n setThreadId: (threadId: string) => void;\n emitWarning: BridgeTurn['emitWarning'];\n emitError: BridgeTurn['emitError'];\n}): (event: CodexEvent) => void {\n const textByItem = new Map<string, string>();\n const reasoningByItem = new Map<string, string>();\n\n return event => {\n if (\n event.type === 'thread.started' &&\n typeof event.thread_id === 'string'\n ) {\n setThreadId(event.thread_id);\n // Announce to the host so it can include the id in resume state.\n send({ type: 'bridge-thread', threadId: event.thread_id });\n }\n if (event.type === 'turn.completed') {\n if (event.usage) setTurnUsage(mapUsage(event.usage));\n stepTracker.finishTurn();\n return;\n }\n if (event.type === 'turn.failed') {\n emitError({\n error: event.error?.message ?? 'codex turn failed',\n message: 'codex turn failed',\n });\n return;\n }\n if (event.type === 'error') {\n emitError({\n error: event.message ?? 'codex error',\n message: 'codex stream error',\n });\n return;\n }\n if (!event.item) return;\n const item = event.item;\n const id = item.id ?? randomUUID();\n const observeStep = (): void => {\n stepTracker.observeEvent({ event, itemId: id });\n };\n\n if (item.type === 'agent_message' && typeof item.text === 'string') {\n /*\n * The presence of `id` in `textByItem` — not the `item.started` event —\n * marks the text part as opened. Codex does not guarantee an\n * `item.started` event carrying text precedes the first `item.updated`\n * with text, so keying the `text-start` off the event type can emit a\n * `text-delta` for a part that was never opened. Opening lazily on the\n * first event with text keeps `text-start` before any `text-delta`.\n */\n if (!textByItem.has(id)) {\n send({ type: 'text-start', id });\n textByItem.set(id, '');\n }\n const last = textByItem.get(id) ?? '';\n const next = item.text;\n if (next.length > last.length) {\n send({ type: 'text-delta', id, delta: next.slice(last.length) });\n textByItem.set(id, next);\n }\n if (event.type === 'item.completed') send({ type: 'text-end', id });\n observeStep();\n return;\n }\n\n if (item.type === 'reasoning' && typeof item.text === 'string') {\n if (!reasoningByItem.has(id)) {\n send({ type: 'reasoning-start', id });\n reasoningByItem.set(id, '');\n }\n const last = reasoningByItem.get(id) ?? '';\n const next = item.text;\n if (next.length > last.length) {\n send({ type: 'reasoning-delta', id, delta: next.slice(last.length) });\n reasoningByItem.set(id, next);\n }\n if (event.type === 'item.completed') send({ type: 'reasoning-end', id });\n observeStep();\n return;\n }\n\n if (item.type === 'command_execution') {\n const nativeName = 'shell';\n if (event.type === 'item.started') {\n send({\n type: 'tool-call',\n toolCallId: id,\n toolName: toCommonName(nativeName),\n nativeName,\n input: JSON.stringify({ command: item.command ?? '' }),\n providerExecuted: true,\n });\n } else if (event.type === 'item.completed') {\n send({\n type: 'tool-result',\n toolCallId: id,\n toolName: toCommonName(nativeName),\n result: {\n exitCode: item.exit_code ?? null,\n output: item.aggregated_output ?? '',\n status: item.status ?? 'completed',\n },\n });\n }\n observeStep();\n return;\n }\n\n if (item.type === 'mcp_tool_call') {\n if (event.type === 'item.started') {\n send({\n type: 'tool-call',\n toolCallId: id,\n toolName: item.tool ?? 'unknown',\n nativeName: item.tool ?? 'unknown',\n input: JSON.stringify(item.arguments ?? {}),\n providerExecuted: true,\n dynamic: true,\n });\n } else if (event.type === 'item.completed') {\n send({\n type: 'tool-result',\n toolCallId: id,\n toolName: item.tool ?? 'unknown',\n result: extractMcpToolCallResult(item),\n dynamic: true,\n });\n }\n observeStep();\n return;\n }\n\n if (item.type === 'web_search') {\n const nativeName = 'web_search';\n if (event.type === 'item.started') {\n send({\n type: 'tool-call',\n toolCallId: id,\n toolName: toCommonName(nativeName),\n nativeName,\n input: JSON.stringify({ query: item.query ?? '' }),\n providerExecuted: true,\n });\n } else if (event.type === 'item.completed') {\n send({\n type: 'tool-result',\n toolCallId: id,\n toolName: toCommonName(nativeName),\n result: item.result ?? null,\n });\n }\n observeStep();\n return;\n }\n\n if (item.type === 'file_change' && event.type === 'item.completed') {\n for (const change of item.changes ?? []) {\n send({\n type: 'file-change',\n event:\n change.kind === 'add'\n ? 'create'\n : change.kind === 'delete'\n ? 'delete'\n : 'modify',\n path: change.path,\n });\n }\n observeStep();\n return;\n }\n\n if (item.type === 'error' && event.type === 'item.completed') {\n const message =\n typeof item.message === 'string' && item.message.trim()\n ? item.message\n : 'codex reported a non-fatal error item';\n emitWarning({ message });\n }\n };\n}\n\nfunction extractMcpToolCallResult(item: CodexItem): unknown {\n if (\n item.result === undefined ||\n item.result === null ||\n typeof item.result !== 'object'\n ) {\n return item.error?.message ? { error: item.error.message } : null;\n }\n const result = item.result as {\n content?: unknown;\n structured_content?: unknown;\n };\n if (\n result.structured_content !== undefined &&\n result.structured_content !== null\n ) {\n return result.structured_content;\n }\n return result.content ?? null;\n}\n\nfunction mapUsage(usage: Record<string, number>): Record<string, unknown> {\n const input = usage.input_tokens ?? 0;\n const cacheRead = usage.cached_input_tokens ?? 0;\n return {\n inputTokens: {\n total: input,\n noCache: Math.max(0, input - cacheRead),\n cacheRead,\n cacheWrite: 0,\n },\n outputTokens: {\n total: usage.output_tokens ?? 0,\n text: usage.output_tokens ?? 0,\n },\n };\n}\n","import { createServer, type Server } from 'node:http';\nimport {\n ToolRelayAuthorizer,\n ToolRelayPendingCalls,\n type ToolRelayCall,\n} from './tool-relay-auth';\n\nexport type ToolRelay = {\n port: number;\n close(): void;\n authorizeToolCall(call: ToolRelayCall): void;\n};\n\nexport async function startAuthorizedToolRelay({\n tools,\n emit,\n requestToolResult,\n authorizer = new ToolRelayAuthorizer(),\n}: {\n tools: ReadonlyArray<{ name: string }>;\n emit: (message: Record<string, unknown>) => void;\n requestToolResult: (\n toolCallId: string,\n ) => Promise<{ output: unknown; isError?: boolean }>;\n authorizer?: ToolRelayAuthorizer;\n}): Promise<ToolRelay> {\n const toolNames = new Set(tools.map(tool => tool.name));\n const pendingCalls = new ToolRelayPendingCalls();\n\n const server = createServer(async (req, res) => {\n try {\n if (req.method !== 'POST' || req.url !== '/') {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'unauthorized tool relay request' }));\n return;\n }\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n const body = Buffer.concat(chunks).toString('utf8');\n const { requestId, toolName, input } = JSON.parse(body) as {\n requestId: string;\n toolName: string;\n input: unknown;\n };\n\n if (!toolNames.has(toolName)) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: `Tool \"${toolName}\" is not available` }),\n );\n return;\n }\n const relayCall = { toolName, input };\n if (!(await authorizer.waitForToolCallAuthorization(relayCall))) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'unauthorized tool relay request' }));\n return;\n }\n\n const { result } = pendingCalls.begin({\n call: relayCall,\n run: async () => {\n emit({\n type: 'tool-call',\n toolCallId: requestId,\n toolName,\n input: JSON.stringify(input ?? {}),\n providerExecuted: false,\n });\n\n const toolResult = await requestToolResult(requestId);\n emit({\n type: 'tool-result',\n toolCallId: requestId,\n toolName,\n result: toolResult.output ?? null,\n isError: !!toolResult.isError,\n });\n return toolResult;\n },\n });\n const { output } = await result;\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ result: output }));\n } catch (error) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n });\n\n await new Promise<void>(resolve =>\n server.listen(0, '127.0.0.1', () => resolve()),\n );\n const address = server.address();\n if (!address || typeof address === 'string') {\n throw new Error('tool relay did not expose a numeric port');\n }\n return {\n port: address.port,\n close: () => {\n authorizer.close();\n closeServer(server);\n },\n authorizeToolCall: call => authorizer.authorizeToolCall(call),\n };\n}\n\nfunction closeServer(server: Server): void {\n try {\n server.close();\n } catch {}\n}\n","export type ToolRelayCall = {\n toolName: string;\n input: unknown;\n};\n\nexport type ToolRelayResult = {\n output: unknown;\n isError?: boolean;\n};\n\nexport class ToolRelayAuthorizer {\n private readonly ttlMs: number;\n private readonly now: () => number;\n private readonly authorizations: Array<{ key: string; expiresAt: number }> =\n [];\n private readonly pendingRequests: Array<{\n key: string;\n expiresAt: number;\n timeout: ReturnType<typeof setTimeout>;\n resolve: (authorized: boolean) => void;\n }> = [];\n\n constructor({\n ttlMs = 10_000,\n now = Date.now,\n }: {\n ttlMs?: number;\n now?: () => number;\n } = {}) {\n this.ttlMs = ttlMs;\n this.now = now;\n }\n\n authorizeToolCall(call: ToolRelayCall): void {\n this.pruneExpired();\n const key = toolRelayCallKey(call);\n const pendingRequestIndex = this.pendingRequests.findIndex(\n request => request.key === key,\n );\n if (pendingRequestIndex !== -1) {\n const [pendingRequest] = this.pendingRequests.splice(\n pendingRequestIndex,\n 1,\n );\n clearTimeout(pendingRequest.timeout);\n pendingRequest.resolve(true);\n return;\n }\n this.authorizations.push({\n key,\n expiresAt: this.now() + this.ttlMs,\n });\n }\n\n waitForToolCallAuthorization(call: ToolRelayCall): Promise<boolean> {\n this.pruneExpired();\n const key = toolRelayCallKey(call);\n const authorizationIndex = this.authorizations.findIndex(\n authorization => authorization.key === key,\n );\n if (authorizationIndex !== -1) {\n this.authorizations.splice(authorizationIndex, 1);\n return Promise.resolve(true);\n }\n\n const expiresAt = this.now() + this.ttlMs;\n return new Promise(resolve => {\n const pendingRequest = {\n key,\n expiresAt,\n timeout: setTimeout(() => {\n const index = this.pendingRequests.indexOf(pendingRequest);\n if (index !== -1) this.pendingRequests.splice(index, 1);\n resolve(false);\n }, this.ttlMs),\n resolve,\n };\n this.pendingRequests.push(pendingRequest);\n });\n }\n\n close(): void {\n this.authorizations.length = 0;\n for (const pendingRequest of this.pendingRequests.splice(0)) {\n clearTimeout(pendingRequest.timeout);\n pendingRequest.resolve(false);\n }\n }\n\n private pruneExpired(): void {\n const now = this.now();\n for (let i = this.authorizations.length - 1; i >= 0; i--) {\n if (this.authorizations[i].expiresAt <= now) {\n this.authorizations.splice(i, 1);\n }\n }\n for (let i = this.pendingRequests.length - 1; i >= 0; i--) {\n const pendingRequest = this.pendingRequests[i];\n if (pendingRequest.expiresAt <= now) {\n this.pendingRequests.splice(i, 1);\n clearTimeout(pendingRequest.timeout);\n pendingRequest.resolve(false);\n }\n }\n }\n}\n\nexport class ToolRelayPendingCalls {\n private readonly calls = new Map<string, Promise<ToolRelayResult>>();\n\n begin({\n call,\n run,\n }: {\n call: ToolRelayCall;\n run: () => Promise<ToolRelayResult>;\n }): { result: Promise<ToolRelayResult>; isNew: boolean } {\n const key = toolRelayCallKey(call);\n const existing = this.calls.get(key);\n if (existing) return { result: existing, isNew: false };\n\n const result = run();\n this.calls.set(key, result);\n void result\n .finally(() => {\n if (this.calls.get(key) === result) {\n this.calls.delete(key);\n }\n })\n .catch(() => {});\n return { result, isNew: true };\n }\n}\n\nfunction toolRelayCallKey({ toolName, input }: ToolRelayCall): string {\n return `${toolName}\\0${canonicalJson(input ?? {})}`;\n}\n\nfunction canonicalJson(value: unknown): string {\n return JSON.stringify(normalizeJsonValue(value));\n}\n\nfunction normalizeJsonValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(normalizeJsonValue);\n }\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .filter(([, entryValue]) => entryValue !== undefined)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entryValue]) => [key, normalizeJsonValue(entryValue)]),\n );\n }\n return value;\n}\n"],"mappings":"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","names":["bridgeStateDir","mkdir","writeFile","argv","nestedCommand","randomUUID","procEnv","stdout","mkdir","writeFile","args"]}
1
+ {"version":3,"sources":["../../../harness/src/bridge/index.ts","../../../harness/src/bridge/harness-bridge-capability-unsupported-error.ts","../../src/bridge/index.ts","../../src/bridge/cli-relay.ts","../../src/bridge/codex-step-tracker.ts","../../src/bridge/create-emit-stream-event.ts","../../src/bridge/tool-relay.ts","../../src/bridge/tool-relay-auth.ts"],"sourcesContent":["// Shared in-sandbox bridge runtime. Adapter `bridge.mjs` bundles re-bundle\n// this module (tsup inlines it; `ws` stays external and resolves from the\n// sandbox-installed node_modules). It owns everything generic to the bridge\n// transport — the WebSocket server, token auth, the in-memory event log +\n// monotonic `seq`, resume replay, and the lifecycle/meta files. Any number of\n// hosts may be connected; exactly one of them owns the event stream, and\n// `start`/`resume` transfer that ownership. The adapter supplies only `onStart`\n// (drive its CLI/SDK and translate to wire events) and lifecycle cleanup hooks.\n\nimport { appendFile, mkdir, writeFile } from 'node:fs/promises';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { env as procEnv, pid, stdout } from 'node:process';\nimport type { ToolResultPart } from '@ai-sdk/provider-utils';\nimport { WebSocketServer, type WebSocket } from 'ws';\n\nexport { HarnessBridgeCapabilityUnsupportedError } from './harness-bridge-capability-unsupported-error';\n\nexport type BridgeState = 'init' | 'waiting' | 'running' | 'draining' | 'done';\n\n/** Outbound turn event the adapter emits. `seq` is added by the runtime. */\nexport type BridgeEvent = Record<string, unknown> & { type: string };\n\nexport type BridgeDebugLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nexport interface Experimental_BridgeUserMessage {\n readonly messageId: string;\n readonly text: string;\n accept(): void;\n reject(error: unknown): void;\n}\n\nexport interface Experimental_BridgeUserMessageQueue extends AsyncIterable<Experimental_BridgeUserMessage> {\n readonly pendingCount: number;\n close(error?: unknown): void;\n}\n\ntype InternalBridgeUserMessageQueue = Experimental_BridgeUserMessageQueue & {\n enqueue(input: { messageId: string; text: string }): void;\n};\n\ntype BridgeUserMessageResponse = {\n type: 'user-message-response';\n messageId: string;\n accepted: boolean;\n error?: { message: string };\n};\n\n/**\n * Per-session diagnostics config. The host resolves it from settings +\n * env and sends it on `start.debug`; the bridge gates console capture and\n * structured `debug-event`s on it. When disabled, nothing is captured or\n * emitted and no `seq` is consumed.\n */\nexport interface BridgeDebugConfig {\n enabled?: boolean;\n level?: BridgeDebugLevel;\n subsystems?: string[];\n}\n\nconst DEBUG_LEVEL_WEIGHT: Record<BridgeDebugLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n};\n\n/** Exact-or-dotted-prefix subsystem match (`'bridge'` matches `'bridge.turn'`). */\nfunction subsystemMatches(\n filters: string[] | undefined,\n subsystem: string,\n): boolean {\n if (!filters || filters.length === 0) return true;\n return filters.some(\n filter => subsystem === filter || subsystem.startsWith(`${filter}.`),\n );\n}\n\nfunction formatBridgeError(err: unknown): {\n name?: string;\n message: string;\n stack?: string;\n} {\n if (err instanceof Error) {\n return { name: err.name, message: err.message, stack: err.stack };\n }\n if (typeof err === 'string') {\n return { message: err };\n }\n if (err !== null && typeof err === 'object') {\n try {\n return { message: JSON.stringify(err) };\n } catch {}\n }\n return { message: String(err) };\n}\n\nfunction createBridgeUserMessageQueue(options: {\n respond(response: BridgeUserMessageResponse): void;\n}): InternalBridgeUserMessageQueue {\n const messages: Experimental_BridgeUserMessage[] = [];\n const waiters: Array<\n (result: IteratorResult<Experimental_BridgeUserMessage>) => void\n > = [];\n const entries = new Map<\n string,\n {\n response?: BridgeUserMessageResponse;\n reject(error: unknown): void;\n }\n >();\n let closed = false;\n let pendingCount = 0;\n\n const enqueue = (input: { messageId: string; text: string }): void => {\n const existing = entries.get(input.messageId);\n if (existing != null) {\n if (existing.response != null) {\n options.respond(existing.response);\n }\n return;\n }\n\n let settled = false;\n const settle = (response: BridgeUserMessageResponse): void => {\n if (settled) return;\n settled = true;\n pendingCount--;\n const entry = entries.get(input.messageId);\n if (entry != null) entry.response = response;\n options.respond(response);\n };\n const message: Experimental_BridgeUserMessage = {\n messageId: input.messageId,\n text: input.text,\n accept: () => {\n settle({\n type: 'user-message-response',\n messageId: input.messageId,\n accepted: true,\n });\n },\n reject: error => {\n settle({\n type: 'user-message-response',\n messageId: input.messageId,\n accepted: false,\n error: { message: formatBridgeError(error).message },\n });\n },\n };\n entries.set(input.messageId, {\n reject: message.reject,\n });\n pendingCount++;\n\n if (closed) {\n message.reject(\n new Error('The bridge turn is no longer accepting user messages.'),\n );\n return;\n }\n\n const waiter = waiters.shift();\n if (waiter != null) {\n waiter({ done: false, value: message });\n } else {\n messages.push(message);\n }\n };\n\n const close = (error?: unknown): void => {\n if (closed) return;\n closed = true;\n const reason =\n error ??\n new Error('The bridge turn ended before accepting the user message.');\n for (const entry of entries.values()) {\n if (entry.response == null) entry.reject(reason);\n }\n messages.length = 0;\n while (waiters.length > 0) {\n waiters.shift()!({ done: true, value: undefined });\n }\n };\n\n return {\n get pendingCount() {\n return pendingCount;\n },\n enqueue,\n close,\n [Symbol.asyncIterator]() {\n return {\n next: () => {\n const message = messages.shift();\n if (message != null) {\n return Promise.resolve({ done: false as const, value: message });\n }\n if (closed) {\n return Promise.resolve({\n done: true as const,\n value: undefined,\n });\n }\n return new Promise<IteratorResult<Experimental_BridgeUserMessage>>(\n resolve => {\n waiters.push(resolve);\n },\n );\n },\n };\n },\n };\n}\n\nfunction parseEnvList(value: string | undefined): string[] | undefined {\n if (!value) return undefined;\n const items = value\n .split(',')\n .map(item => item.trim())\n .filter(Boolean);\n return items.length > 0 ? items : undefined;\n}\n\nconst ENV_TRUTHY = new Set(['1', 'true', 'yes', 'on']);\n\n/**\n * Per-turn surface handed to {@link RunBridgeOptions.onStart}. The adapter\n * drives its runtime against these primitives; the runtime owns the transport.\n */\nexport interface BridgeTurn {\n /**\n * Emit a turn event to the host. Stamps a monotonic `seq`, appends to the\n * in-memory replay log, and sends to the live socket (best-effort — if the\n * host is mid-reconnect the event waits in the log and is replayed on\n * resume).\n */\n emit(event: BridgeEvent): void;\n\n /**\n * Register interest in a host-executed tool result and resolve when the\n * matching `tool-result` arrives. The adapter emits the `tool-call` event\n * itself (via {@link emit}) using the same `toolCallId`.\n */\n requestToolResult(\n input:\n | string\n | {\n toolCallId: string;\n matches?: (result: {\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n }) => boolean;\n },\n ): Promise<{\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n }>;\n\n /**\n * Register interest in a host approval decision and resolve when the matching\n * `tool-approval-response` arrives. The adapter emits the\n * `tool-approval-request` event itself using the same `approvalId`.\n */\n requestToolApproval(\n approvalId: string,\n ): Promise<{ approved: boolean; reason?: string }>;\n\n readonly experimental_userMessages: Experimental_BridgeUserMessageQueue;\n\n /** Aborts when the host sends `abort`. */\n readonly abortSignal: AbortSignal;\n\n /** True for the first turn since this bridge process started. */\n readonly firstTurn: boolean;\n\n /**\n * Emit a structured diagnostic. Gated by the session's debug level +\n * subsystem filter; a no-op when diagnostics are disabled. Adapters use this\n * for runtime-level instrumentation; raw `console.*` output is captured and\n * forwarded automatically.\n */\n bridgeLog(input: {\n level?: BridgeDebugLevel;\n subsystem: string;\n message: string;\n attrs?: Record<string, unknown>;\n error?: unknown;\n }): void;\n\n /**\n * Emit a non-fatal bridge warning to stderr using the runtime's harness\n * prefix. This is diagnostic-only: it does not emit a stream event, does not\n * consume a `seq`, and does not fail the turn.\n */\n emitWarning(input: { message: string }): void;\n\n emitError(input: { error: unknown; message?: string }): void;\n}\n\nexport interface RunBridgeOptions<TStart extends { type: 'start' }> {\n /** Identifier written into `bridge-meta.json` (`'claude-code'` / `'codex'`). */\n bridgeType: string;\n /** Directory for `bridge-meta.json` / `start-config.json`. Created if absent. */\n bridgeStateDir: string;\n /**\n * Drive one prompt turn. Rejections surface to the host as an `error`\n * event.\n *\n * Contract: once `turn.abortSignal` fires, wind down promptly — turns are\n * serialized, and a replacement `start` waits up to\n * {@link turnTeardownGraceMs} for this promise to settle before it\n * proceeds anyway.\n */\n onStart(start: TStart, turn: BridgeTurn): Promise<void>;\n /**\n * How long a replacement `start` waits for the previous turn's teardown\n * after aborting it, in milliseconds. Turns are serialized so an aborted\n * turn cannot emit into its replacement's event log or overlap its runtime\n * process — but only within this bound: an adapter that does not settle\n * `onStart` after its abort signal fires forfeits the protection for that\n * boundary, and the new turn proceeds anyway rather than blocking forever.\n * The default of ten seconds exceeds the Claude bridge's five-second\n * hard-abort fallback.\n */\n turnTeardownGraceMs?: number;\n /**\n * Produce the adapter-defined runtime resume data for `stop`. Defaults to\n * `{}`.\n */\n onStop?(): unknown | Promise<unknown>;\n /**\n * Perform adapter-defined destruction before the bridge exits.\n */\n onDestroy?(): void | Promise<void>;\n /** WS port. Defaults to `BRIDGE_WS_PORT` env (0 = OS-assigned). */\n port?: number;\n /** Auth token. Defaults to `BRIDGE_CHANNEL_TOKEN` env. */\n token?: string;\n /** Called with the bound port once the server is listening. */\n onListening?(port: number): void;\n /**\n * Tear the process down after `stop` / `destroy`. Defaults to closing\n * the server and calling `process.exit(0)`. Overridable for tests.\n */\n onExit?(): void;\n}\n\ntype InboundControl =\n | {\n type: 'tool-result';\n toolCallId: string;\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n }\n | {\n type: 'tool-approval-response';\n approvalId: string;\n approved: boolean;\n reason?: string;\n }\n | { type: 'user-message'; messageId?: string; text: string }\n | { type: 'abort' }\n | { type: 'stop' }\n | { type: 'destroy' }\n | { type: 'resume'; lastSeenEventId: number };\n\nconst WS_OPEN = 1;\n\n/**\n * Boot the bridge: bind the WebSocket server, announce `bridge-ready`, and\n * service host connections for the lifetime of the process. Resolves once the\n * server is listening; the process then stays alive on the server until a\n * `stop` / `destroy` exits it.\n */\nexport interface BridgeHandle {\n /** The port the WebSocket server bound to. */\n readonly port: number;\n /** Close the WebSocket server. Does not call `process.exit`. */\n close(): Promise<void>;\n}\n\nexport async function runBridge<TStart extends { type: 'start' }>(\n options: RunBridgeOptions<TStart>,\n): Promise<BridgeHandle> {\n const { bridgeType, bridgeStateDir, onStart, onStop, onDestroy } = options;\n const teardownGraceMs = options.turnTeardownGraceMs ?? 10_000;\n const expectedToken = options.token ?? procEnv.BRIDGE_CHANNEL_TOKEN ?? '';\n const bridgeWsPort =\n options.port ?? parseInt(procEnv.BRIDGE_WS_PORT ?? '0', 10);\n\n const bridgeMetaPath = `${bridgeStateDir}/bridge-meta.json`;\n const startConfigPath = `${bridgeStateDir}/start-config.json`;\n const rerunStartConfigPath = `${bridgeStateDir}/rerun-start-config.json`;\n const eventLogPath = `${bridgeStateDir}/event-log.ndjson`;\n\n try {\n await mkdir(bridgeStateDir, { recursive: true });\n } catch {\n // Best-effort; the bridge still runs without its state files.\n }\n\n // ─── mutable runtime state ──────────────────────────────────────────\n let currentBoundPort = 0;\n let currentTurnState: BridgeState = 'init';\n /*\n * The one connection turn events stream to. A socket claims it by asking for\n * work — `start` (a turn) or `resume` (a catch-up) — never by connecting:\n * every event goes here alone, so claiming on connect would silence a turn\n * already streaming to someone else. Any number of sockets may be connected;\n * the others still exchange control frames, they just get no events.\n */\n let activeSocket: WebSocket | undefined;\n let isFirstTurn = true;\n let turnAbort: AbortController | undefined;\n let currentUserMessages: InternalBridgeUserMessageQueue | undefined;\n /**\n * Settles when the in-flight turn has fully wound down — `onStart`\n * returned or threw AND its completion state was recorded. `undefined`\n * between turns. A new `start` fences on this so turns never overlap.\n */\n let activeTurn: Promise<void> | undefined;\n\n // Diagnostics. Resolved per turn from `start.debug` with a sandbox-side\n // env fallback; gates console capture + structured `debug-event`s.\n let debugConfig: BridgeDebugConfig | undefined;\n let consoleCaptureInstalled = false;\n const envDebugEnabled = ENV_TRUTHY.has(\n (procEnv.HARNESS_DEBUG ?? '').toLowerCase(),\n );\n\n // Replay log. `seq` is monotonic across the whole process — never reset —\n // because the host's `SandboxChannel` cursor (`lastSeenEventId`) lives across\n // turns. The log *contents* are cleared at the start of each turn to bound\n // memory; the just-finished turn stays replayable until the next `start`.\n let seqCounter = 0;\n let eventLog: Array<{ seq: number; line: string }> = [];\n\n /*\n * Disk mirror of the in-memory replay log. The in-memory log is lost when the\n * bridge process dies; the on-disk `event-log.ndjson` survives in the sandbox\n * filesystem so a respawned bridge (started with `BRIDGE_REPLAY_FROM_DISK=1`)\n * can reload the in-flight turn and serve a host's resume cursor —\n * `replay` recovery. Writes are batched on `setImmediate` (single-flight via\n * `flushPromise`) to keep `emit` off the disk hot path.\n */\n let diskBuffer = '';\n let flushPromise: Promise<void> | null = null;\n\n const flushEventsToDisk = async (): Promise<void> => {\n while (diskBuffer.length > 0) {\n const buf = diskBuffer;\n diskBuffer = '';\n await appendFile(eventLogPath, buf).catch(() => {\n // Best-effort crash-recovery mirror; the in-memory log is the source of\n // truth for the live connection.\n });\n }\n };\n\n const scheduleEventFlush = (): void => {\n if (flushPromise) return;\n flushPromise = new Promise<void>(resolve => {\n setImmediate(() => {\n void flushEventsToDisk().finally(resolve);\n });\n }).finally(() => {\n flushPromise = null;\n if (diskBuffer.length > 0) {\n scheduleEventFlush();\n }\n });\n };\n\n const flushPendingEventsToDisk = async (): Promise<void> => {\n if (diskBuffer.length > 0 && !flushPromise) {\n scheduleEventFlush();\n }\n // Await each in-flight flush, re-reading `flushPromise` after every await\n // since a fresh flush may have been scheduled for buffer that arrived while\n // we waited.\n let inFlight = flushPromise;\n while (inFlight) {\n await inFlight;\n inFlight = flushPromise;\n }\n };\n\n /*\n * When respawned for `replay`, reload the previous turn's log from disk before\n * accepting any connection so the very first `resume{lastSeenEventId}` can be\n * served the tail (including the terminal `finish`). The seq counter is\n * restored to the last persisted seq so it stays aligned with the host's\n * long-lived cursor. The file is NOT truncated in this mode — only a fresh\n * `start` (next turn) clears it.\n */\n const replayFromDisk = procEnv.BRIDGE_REPLAY_FROM_DISK === '1';\n if (replayFromDisk && existsSync(eventLogPath)) {\n try {\n const lines = readFileSync(eventLogPath, 'utf8')\n .split('\\n')\n .map(line => line.trim())\n .filter(Boolean);\n eventLog = lines.map(line => ({\n seq: (JSON.parse(line) as { seq: number }).seq,\n line,\n }));\n seqCounter = eventLog.at(-1)?.seq ?? 0;\n } catch {\n // Corrupt/partial log: fall back to an empty log; the host then degrades\n // to `rerun` instead of replaying a malformed tail.\n eventLog = [];\n seqCounter = 0;\n }\n }\n\n const pendingToolResults = new Map<\n string,\n {\n resolve: (output: {\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n }) => void;\n matches?: (output: {\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n }) => boolean;\n }\n >();\n const bufferedToolResults: Array<{\n toolCallId: string;\n result: {\n output: unknown;\n isError?: boolean;\n toolResult?: ToolResultPart;\n };\n }> = [];\n const pendingToolApprovals = new Map<\n string,\n (response: { approved: boolean; reason?: string }) => void\n >();\n\n // ─── persistence (best-effort meta + start config) ──────────────────\n const writeBridgeMeta = async (state: BridgeState): Promise<void> => {\n try {\n await writeFile(\n bridgeMetaPath,\n JSON.stringify({\n type: bridgeType,\n port: currentBoundPort,\n state,\n pid,\n }),\n );\n } catch {\n // Best-effort resilience metadata; not load-bearing for the active turn.\n }\n };\n\n const writeStartConfig = async (start: unknown): Promise<void> => {\n try {\n const serialized = JSON.stringify(start);\n await writeFile(startConfigPath, serialized);\n // Frozen copy: written once, restored over start-config.json by future\n // rerun-mode recovery to re-run the original turn from scratch.\n if (!existsSync(rerunStartConfigPath)) {\n await writeFile(rerunStartConfigPath, serialized);\n }\n } catch {\n // Best-effort.\n }\n };\n\n // ─── wire send + replay ─────────────────────────────────────────────\n const emit = (event: BridgeEvent): void => {\n const seq = ++seqCounter;\n const line = JSON.stringify({ ...event, seq });\n eventLog.push({ seq, line });\n diskBuffer += `${line}\\n`;\n scheduleEventFlush();\n if (activeSocket?.readyState === WS_OPEN) {\n try {\n activeSocket.send(line);\n } catch {\n // Send is best-effort: a dropped socket leaves the event in the log,\n // replayed once the host reconnects and sends `resume`.\n }\n }\n };\n\n const replay = (ws: WebSocket, afterSeq: number): void => {\n for (const entry of eventLog) {\n if (entry.seq > afterSeq && ws.readyState === WS_OPEN) {\n ws.send(entry.line);\n }\n }\n };\n\n // ─── diagnostics ──────────────────────────────────────────────\n const shouldEmitDebugEvent = (\n level: BridgeDebugLevel,\n subsystem: string,\n ): boolean => {\n if (!debugConfig?.enabled) return false;\n const threshold = debugConfig.level ?? 'debug';\n if (DEBUG_LEVEL_WEIGHT[level] > DEBUG_LEVEL_WEIGHT[threshold]) return false;\n return subsystemMatches(debugConfig.subsystems, subsystem);\n };\n\n /*\n * Forward sandbox console output. We line-buffer the original writers (kept so\n * output still reaches the real fds) and emit one `sandbox-log` per complete\n * line. `emit` never writes to stdout/stderr, so there is no recursion.\n * Installed lazily the first time a turn enables diagnostics; once installed,\n * capture is gated per-write on `debugConfig.enabled` so a later turn can\n * disable it. Console capture is independent of the subsystem/level filter.\n */\n const rawStdoutWrite = process.stdout.write.bind(process.stdout);\n const rawStderrWrite = process.stderr.write.bind(process.stderr);\n\n const writeErrorToStderr = (input: {\n message: string;\n error: unknown;\n }): void => {\n try {\n const formatted = formatBridgeError(input.error);\n rawStderrWrite(\n `[harness:${bridgeType}:error] ${input.message}: ${formatted.message}\\n`,\n );\n if (formatted.stack) {\n rawStderrWrite(`${formatted.stack}\\n`);\n }\n } catch {}\n };\n\n const emitWarning = (input: { message: string }): void => {\n try {\n for (const line of input.message.split('\\n')) {\n if (line.trim().length > 0) {\n rawStderrWrite(`[harness:${bridgeType}:warn] ${line}\\n`);\n }\n }\n } catch {}\n };\n\n const emitError = (input: { error: unknown; message?: string }): void => {\n writeErrorToStderr({\n message: input.message ?? 'bridge error',\n error: input.error,\n });\n emit({ type: 'error', error: serialiseError(input.error) });\n };\n\n const installConsoleCapture = (): void => {\n if (consoleCaptureInstalled) return;\n consoleCaptureInstalled = true;\n const buffers: { stdout: string; stderr: string } = {\n stdout: '',\n stderr: '',\n };\n const patch =\n (stream: 'stdout' | 'stderr', raw: typeof process.stdout.write) =>\n (chunk: unknown, encoding?: unknown, cb?: unknown): boolean => {\n if (debugConfig?.enabled) {\n try {\n const enc = typeof encoding === 'string' ? encoding : 'utf8';\n const text =\n typeof chunk === 'string'\n ? chunk\n : Buffer.from(chunk as Uint8Array).toString(\n enc as BufferEncoding,\n );\n const combined = buffers[stream] + text.replace(/\\r\\n/g, '\\n');\n const parts = combined.split('\\n');\n buffers[stream] = parts.pop() ?? '';\n for (const line of parts) {\n const trimmed = line.replace(/\\s+$/, '');\n if (trimmed) {\n emit({\n type: 'sandbox-log',\n source: bridgeType,\n stream,\n line: trimmed,\n });\n }\n }\n } catch {\n // Never let capture break real output.\n }\n }\n return (raw as (c: unknown, e?: unknown, cb?: unknown) => boolean)(\n chunk,\n encoding,\n cb,\n );\n };\n process.stdout.write = patch(\n 'stdout',\n rawStdoutWrite,\n ) as typeof process.stdout.write;\n process.stderr.write = patch(\n 'stderr',\n rawStderrWrite,\n ) as typeof process.stderr.write;\n };\n\n // ─── inbound routing ────────────────────────────────────────────────\n const handleInbound = async (\n msg: TStart | InboundControl,\n ws: WebSocket,\n ): Promise<void> => {\n switch (msg.type) {\n case 'start': {\n /*\n * A new turn replaces the active one — but only after the active one\n * has fully wound down. Inbound frames are dispatched concurrently,\n * and the host settles a caller abort immediately, so a retry's\n * `start` can arrive while the aborted turn is still tearing down\n * (e.g. a graceful interrupt). Without this fence the old turn would\n * keep emitting into the new turn's cleared event log, two runtime\n * processes would run side by side, and the old turn's completion\n * would mark the bridge `waiting` underneath the new turn. Abort the\n * old turn to hasten its teardown; adapters are expected to bound\n * that teardown themselves (e.g. a hard-abort fallback), but the\n * runtime does not rely on it: the wait is capped by the teardown\n * grace period, after which the new turn proceeds anyway — the\n * pre-fence overlapping behavior — rather than hanging behind a\n * teardown that never settles.\n */\n for (;;) {\n const pendingTurn = activeTurn;\n if (pendingTurn == null) break;\n turnAbort?.abort();\n currentUserMessages?.close(\n new Error('A new bridge turn replaced the active turn.'),\n );\n let graceTimer: ReturnType<typeof setTimeout> | undefined;\n const settled = await Promise.race([\n pendingTurn.then(() => true as const),\n new Promise<false>(resolve => {\n graceTimer = setTimeout(() => resolve(false), teardownGraceMs);\n graceTimer.unref?.();\n }),\n ]);\n clearTimeout(graceTimer);\n if (!settled) break;\n }\n let turnFinished!: () => void;\n const thisTurn = new Promise<void>(resolve => (turnFinished = resolve));\n activeTurn = thisTurn;\n activeSocket = ws; // asking for a turn claims the event stream\n const firstTurn = isFirstTurn;\n isFirstTurn = false;\n eventLog = []; // clear previous turn; keep seqCounter monotonic\n // Mirror the in-memory clear to disk: the log tracks only the current\n // turn. Discard any unflushed tail from the prior turn first.\n diskBuffer = '';\n void writeFile(eventLogPath, '').catch(() => {});\n turnAbort = new AbortController();\n currentTurnState = 'running';\n void writeStartConfig(msg);\n void writeBridgeMeta('running');\n const startDebug = (msg as { debug?: BridgeDebugConfig }).debug;\n debugConfig = {\n enabled: startDebug?.enabled ?? envDebugEnabled,\n level:\n startDebug?.level ??\n (procEnv.HARNESS_DEBUG_LEVEL as BridgeDebugLevel | undefined),\n subsystems:\n startDebug?.subsystems ??\n parseEnvList(procEnv.HARNESS_DEBUG_SUBSYSTEMS),\n };\n if (debugConfig.enabled) {\n installConsoleCapture();\n }\n const userMessages = createBridgeUserMessageQueue({ respond: emit });\n const turn: BridgeTurn = {\n emit,\n requestToolResult: requestInput => {\n const request =\n typeof requestInput === 'string'\n ? { toolCallId: requestInput }\n : requestInput;\n const bufferedIndex = bufferedToolResults.findIndex(\n buffered =>\n buffered.toolCallId === request.toolCallId ||\n request.matches?.(buffered.result) === true,\n );\n if (bufferedIndex >= 0) {\n return Promise.resolve(\n bufferedToolResults.splice(bufferedIndex, 1)[0].result,\n );\n }\n return new Promise(resolve => {\n pendingToolResults.set(request.toolCallId, {\n resolve,\n matches: request.matches,\n });\n });\n },\n requestToolApproval: approvalId =>\n new Promise(resolve => {\n pendingToolApprovals.set(approvalId, resolve);\n }),\n experimental_userMessages: userMessages,\n abortSignal: turnAbort.signal,\n firstTurn,\n bridgeLog: input => {\n const level = input.level ?? 'debug';\n if (!shouldEmitDebugEvent(level, input.subsystem)) return;\n emit({\n type: 'debug-event',\n level,\n subsystem: input.subsystem,\n message: input.message,\n ...(input.attrs ? { attrs: input.attrs } : {}),\n ...(input.error !== undefined\n ? { error: formatBridgeError(input.error) }\n : {}),\n });\n },\n emitWarning,\n emitError,\n };\n currentUserMessages = userMessages;\n try {\n await onStart(msg as TStart, turn);\n } catch (err) {\n emitError({ error: err, message: 'bridge turn failed' });\n } finally {\n userMessages.close();\n if (currentUserMessages === userMessages) {\n currentUserMessages = undefined;\n }\n // Only the still-active turn records completion: after a fence\n // timeout a replacement turn is already running, and this stale\n // completion must not mark the bridge waiting underneath it.\n if (activeTurn === thisTurn) {\n activeTurn = undefined;\n currentTurnState = 'waiting';\n void writeBridgeMeta('waiting');\n }\n turnFinished();\n }\n return;\n }\n case 'tool-result': {\n const result = {\n output: msg.output,\n isError: msg.isError,\n toolResult: msg.toolResult,\n };\n const exactPending = pendingToolResults.get(msg.toolCallId);\n const matchingPending =\n exactPending == null\n ? Array.from(pendingToolResults.entries()).find(\n ([, pending]) => pending.matches?.(result) === true,\n )\n : undefined;\n const pending = exactPending ?? matchingPending?.[1];\n const pendingId =\n exactPending != null ? msg.toolCallId : matchingPending?.[0];\n if (pending != null && pendingId != null) {\n pendingToolResults.delete(pendingId);\n pending.resolve(result);\n } else {\n bufferedToolResults.push({\n toolCallId: msg.toolCallId,\n result,\n });\n }\n return;\n }\n case 'tool-approval-response': {\n const resolver = pendingToolApprovals.get(msg.approvalId);\n if (resolver) {\n pendingToolApprovals.delete(msg.approvalId);\n resolver({ approved: msg.approved, reason: msg.reason });\n }\n return;\n }\n case 'user-message': {\n const messageId = msg.messageId ?? randomUUID();\n if (currentUserMessages == null) {\n sendControl(ws, {\n type: 'user-message-response',\n messageId,\n accepted: false,\n error: { message: 'The bridge has no active turn to steer.' },\n });\n return;\n }\n if (ws !== activeSocket) {\n sendControl(ws, {\n type: 'user-message-response',\n messageId,\n accepted: false,\n error: {\n message: 'The connection does not own the active bridge turn.',\n },\n });\n return;\n }\n currentUserMessages.enqueue({\n messageId,\n text: msg.text,\n });\n return;\n }\n case 'abort':\n turnAbort?.abort();\n return;\n case 'resume':\n activeSocket = ws; // asking for a catch-up claims it too\n // Synchronous, so no event can slip out live ahead of the replayed tail.\n replay(ws, msg.lastSeenEventId);\n return;\n case 'destroy':\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n await onDestroy?.();\n drainThenExit(ws, 1000, 'destroy');\n return;\n case 'stop': {\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n const data = (await onStop?.()) ?? {};\n sendControl(ws, { type: 'bridge-stop', data });\n drainThenExit(ws, 1000, 'stop');\n return;\n }\n }\n };\n\n // ─── server ─────────────────────────────────────────────────────────\n void writeBridgeMeta('init');\n\n const wss = new WebSocketServer({ port: bridgeWsPort, host: '0.0.0.0' });\n\n const exit = (): void => {\n if (options.onExit) {\n options.onExit();\n return;\n }\n wss.close(() => process.exit(0));\n setTimeout(() => process.exit(0), 1000).unref();\n };\n\n const drainThenExit = (ws: WebSocket, code: number, reason: string): void => {\n const start = Date.now();\n const tick = (): void => {\n const drained = ws.bufferedAmount === 0 || ws.readyState !== WS_OPEN;\n if (drained || Date.now() - start >= 5_000) {\n // Flush the on-disk log so a clean stop/destroy leaves a complete\n // event-log.ndjson for any later replay recovery.\n void flushPendingEventsToDisk().finally(() => {\n try {\n ws.close(code, reason);\n } finally {\n exit();\n }\n });\n return;\n }\n setTimeout(tick, 10).unref();\n };\n tick();\n };\n\n wss.on('listening', () => {\n const addr = wss.address();\n currentBoundPort = typeof addr === 'object' && addr ? addr.port : 0;\n currentTurnState = 'waiting';\n void writeBridgeMeta('waiting');\n stdout.write(\n JSON.stringify({\n type: 'bridge-ready',\n port: currentBoundPort,\n }) + '\\n',\n );\n options.onListening?.(currentBoundPort);\n });\n\n wss.on('connection', (ws: WebSocket, req: { url?: string }) => {\n const url = new URL(req.url ?? '/', 'http://localhost');\n if (url.searchParams.get('agent_bridge_token') !== expectedToken) {\n ws.close(1008, 'unauthorized');\n return;\n }\n\n // Announce liveness the instant we accept. Some sandbox runtimes complete\n // the host-side WS handshake before the connection is forwarded here; the\n // host waits for this frame before sending `start`/`resume`.\n sendControl(ws, {\n type: 'bridge-hello',\n state: currentTurnState,\n lastSeq: seqCounter,\n capabilities: { experimental_userMessageResponses: true },\n });\n\n ws.on('message', (raw: ArrayBufferLike | string) => {\n let parsed: TStart | InboundControl;\n try {\n const text =\n typeof raw === 'string' ? raw : Buffer.from(raw).toString('utf8');\n parsed = JSON.parse(text) as TStart | InboundControl;\n } catch (err) {\n sendControl(ws, {\n type: 'error',\n error: `protocol parse error: ${(err as Error).message}`,\n });\n return;\n }\n void handleInbound(parsed, ws);\n });\n\n ws.on('close', () => {\n // Only the stream owner's close matters; a socket that never claimed it,\n // or that a later `start`/`resume` displaced, closes as a no-op.\n // Crucially we do NOT abort the in-flight turn: it keeps running and its\n // events accumulate in the log for replay on reconnect.\n if (activeSocket === ws) {\n activeSocket = undefined;\n }\n });\n\n ws.on('error', () => {\n // 'close' follows; nothing to do beyond keeping the process alive.\n });\n });\n\n // Surface bridge-internal crashes to the host instead of dying silently.\n process.on('uncaughtException', err => {\n emitError({ error: err, message: 'uncaught exception' });\n });\n process.on('unhandledRejection', err => {\n emitError({ error: err, message: 'unhandled rejection' });\n });\n\n await new Promise<void>((resolve, reject) => {\n if (wss.address() != null) {\n resolve();\n return;\n }\n\n wss.once('listening', resolve);\n wss.once('error', reject);\n });\n\n return {\n port: currentBoundPort,\n close: () =>\n new Promise<void>(resolve => {\n wss.close(() => resolve());\n }),\n };\n}\n\n/*\n * Control frames answer the socket that sent the frame they reply to, so the\n * target is always explicit. Event streaming is the separate, stateful path\n * (`emit` → `activeSocket`); this one carries no state at all.\n */\nfunction sendControl(\n socket: WebSocket | undefined,\n message: Record<string, unknown>,\n): void {\n if (socket?.readyState === WS_OPEN) {\n try {\n socket.send(JSON.stringify(message));\n } catch {\n // best-effort\n }\n }\n}\n\nfunction serialiseError(err: unknown): unknown {\n if (err instanceof Error) {\n return { name: err.name, message: err.message, stack: err.stack };\n }\n return err;\n}\n","const name = 'AI_HarnessBridgeCapabilityUnsupportedError';\n\n/**\n * Signals an unsupported capability discovered inside a sandbox bridge.\n * `isInstance` also recognizes the serialized error shape received by the\n * host, where it can be translated to `HarnessCapabilityUnsupportedError`.\n */\nexport class HarnessBridgeCapabilityUnsupportedError extends Error {\n readonly harnessId?: string;\n readonly cause?: unknown;\n\n constructor({\n message,\n harnessId,\n cause,\n }: {\n message: string;\n harnessId?: string;\n cause?: unknown;\n }) {\n super(message);\n Object.defineProperty(this, 'name', { value: name });\n this.harnessId = harnessId;\n this.cause = cause;\n }\n\n static isInstance(\n error: unknown,\n ): error is HarnessBridgeCapabilityUnsupportedError {\n return (\n error != null &&\n typeof error === 'object' &&\n 'name' in error &&\n error.name === name &&\n 'message' in error &&\n typeof error.message === 'string'\n );\n }\n}\n","// Long-running process that runs alongside the `codex` CLI in the sandbox.\n// The generic transport — WebSocket server, token auth, single-flight\n// reconnect, the in-memory event log + `seq`, resume replay, and the\n// lifecycle/meta files — lives in the shared `@ai-sdk/harness/bridge` runtime.\n// This file supplies only the Codex-specific turn driver.\n//\n// Host-defined tools are routed through an HTTP relay bound to\n// `127.0.0.1:0`. The bridge writes a CLI shim into the per-session runtime\n// directory; the shim POSTs each tool call to the relay, which emits\n// `tool-call` to the host and waits for the matching `tool-result`.\n\nimport {\n runBridge,\n type BridgeEvent,\n type BridgeTurn,\n} from '@ai-sdk/harness/bridge';\nimport type { StartMessage } from '../codex-bridge-protocol';\nimport { mkdir, writeFile } from 'node:fs/promises';\n// Temporary workaround for upstream codex MCP-tool bug — see ./cli-relay.ts\nimport {\n CLI_SHIM_FILENAME,\n buildCliShimScript,\n parseToolRelayCommands,\n} from './cli-relay';\nimport { createCodexStepTracker, defaultUsage } from './codex-step-tracker';\nimport {\n createEmitStreamEvent,\n type CodexEvent,\n} from './create-emit-stream-event';\nimport { startAuthorizedToolRelay, type ToolRelay } from './tool-relay';\nimport { argv, env as procEnv, stdout } from 'node:process';\n\n/*\n * CONSTRAINT — the third-party imports below are NEVER bundled into the\n * compiled `bridge/index.mjs`. They are declared `external` in\n * tsup.config.ts and resolved at runtime from the node_modules that this\n * bridge installs *inside the sandbox* from `src/bridge/package.json` (and\n * its pinned `pnpm-lock.yaml`). That bridge package.json — NOT this host\n * package — is the single source of truth for these packages and their\n * versions; the published `@ai-sdk/harness-codex` package does not provide\n * them at runtime.\n *\n * When adding or changing a third-party import here you MUST keep all three\n * in sync, or the bridge will either get the dependency bundled in or fail\n * to resolve it in the sandbox:\n * 1. the import statement below,\n * 2. the `external` array in tsup.config.ts, and\n * 3. the dependency entry in `src/bridge/package.json`.\n */\nimport * as codexSdkModule from '@openai/codex-sdk';\n\nconst args = parseArgs(argv.slice(2));\nconst workdir = requireArg({ value: args.workdir, name: '--workdir' });\nconst bridgeStateDir = requireArg({\n value: args.bridgeStateDir,\n name: '--bridge-state-dir',\n});\nconst cliShimDir = requireArg({\n value: args.cliShimDir,\n name: '--cli-shim-dir',\n});\nconst HARNESS_CLIENT_APP = procEnv.AI_SDK_HARNESS_CLIENT_APP;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst codexSdk = codexSdkModule as any;\n\n// Codex thread id — survives across turns within this bridge process and is\n// returned to the host on `stop` so a future process can resume the thread.\nconst threadState: { id: string | undefined } = { id: undefined };\n\nawait runBridge<StartMessage>({\n bridgeType: 'codex',\n bridgeStateDir,\n onStart: runTurn,\n onStop: () => (threadState.id ? { threadId: threadState.id } : {}),\n});\n\ntype Emit = (msg: Record<string, unknown>) => void;\n\nasync function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {\n const emit: Emit = msg => turn.emit(msg as BridgeEvent);\n\n // Cross-process resume: the host carries the threadId we returned on stop.\n // Seed `threadState.id` so the codex SDK call below takes the `resumeThread`\n // branch.\n if (start.restartThread) {\n threadState.id = undefined;\n } else if (\n typeof start.resumeThreadId === 'string' &&\n start.resumeThreadId.length > 0\n ) {\n threadState.id = start.resumeThreadId;\n }\n\n /*\n * Known limitation: codex CLI does not reliably surface MCP tools to the\n * model in `codex exec --experimental-json` mode (the path the\n * `@openai/codex-sdk` uses). Some versions do not register MCP tools at all;\n * others expose the tool names but pass empty arguments.\n *\n * Until that's fixed, host tools are made available to the model via a\n * separate CLI-relay workaround (see `./cli-relay.ts`). Writing the shim\n * here, adding matching prompt guidance in the host adapter, and filtering\n * the shim command below implement the workaround and can be removed once the\n * upstream bug is fixed.\n */\n let relay: ToolRelay | undefined;\n let cliShimPath: string | undefined;\n if (start.tools && start.tools.length > 0) {\n cliShimPath = `${cliShimDir}/${CLI_SHIM_FILENAME}`;\n relay = await startToolRelay({\n tools: start.tools,\n emit,\n requestToolResult: turn.requestToolResult,\n });\n // Temporary workaround for upstream codex MCP-tool bug — see ./cli-relay.ts\n await mkdir(cliShimDir, { recursive: true });\n await writeFile(\n cliShimPath,\n buildCliShimScript({ relayPort: relay.port }),\n 'utf8',\n );\n }\n\n const codexConfig: Record<string, unknown> = {\n ...start.codexConfig,\n developer_instructions: [\n start.instructions,\n 'Only respond with your `final` message once you have fully addressed the user request.',\n ]\n .filter((instruction): instruction is string => Boolean(instruction))\n .join('\\n\\n'),\n model_reasoning_summary: 'detailed',\n };\n\n const gatewayBaseUrl = procEnv.AI_GATEWAY_BASE_URL;\n const hasGatewayAuth = Boolean(procEnv.AI_GATEWAY_API_KEY || gatewayBaseUrl);\n if (hasGatewayAuth && !gatewayBaseUrl) {\n throw new Error(\n 'AI Gateway auth was selected but AI_GATEWAY_BASE_URL is missing from the Codex bridge environment.',\n );\n }\n const apiBaseUrl = hasGatewayAuth ? gatewayBaseUrl : procEnv.OPENAI_BASE_URL;\n const codexModel =\n start.model && hasGatewayAuth && !start.model.includes('/')\n ? `openai/${start.model}`\n : start.model;\n /*\n * AI Gateway only returns populated reasoning summaries for its\n * creator-qualified model IDs. Codex treats qualified IDs as custom model\n * metadata, so its reasoning-summary capability must also be forced on for\n * the OpenAI Gateway route.\n */\n if (hasGatewayAuth && codexModel?.startsWith('openai/')) {\n codexConfig.model_supports_reasoning_summaries = true;\n }\n if (apiBaseUrl) {\n codexConfig.preferred_auth_method = 'apikey';\n codexConfig.model_provider = 'agent_bridge_openai';\n codexConfig.model_providers = {\n agent_bridge_openai: {\n name: procEnv.CODEX_MODEL_PROVIDER_NAME || 'Agent Bridge OpenAI',\n base_url: apiBaseUrl,\n env_key: 'CODEX_API_KEY',\n wire_api: 'responses',\n supports_websockets: false,\n ...(hasGatewayAuth && HARNESS_CLIENT_APP\n ? {\n http_headers: {\n 'User-Agent': HARNESS_CLIENT_APP,\n 'x-client-app': HARNESS_CLIENT_APP,\n },\n }\n : {}),\n },\n };\n }\n if (start.mcpServers != null) {\n codexConfig.mcp_servers = start.mcpServers;\n }\n const usesConfiguredModelProvider =\n typeof codexConfig.model_provider === 'string';\n\n const codex = new codexSdk.Codex({\n ...(procEnv.CODEX_API_KEY ? { apiKey: procEnv.CODEX_API_KEY } : {}),\n ...(!usesConfiguredModelProvider && apiBaseUrl\n ? { baseUrl: apiBaseUrl }\n : {}),\n env: Object.fromEntries(\n Object.entries(procEnv).filter(\n (entry): entry is [string, string] => typeof entry[1] === 'string',\n ),\n ),\n ...(Object.keys(codexConfig).length > 0 ? { config: codexConfig } : {}),\n });\n\n const threadOptions = {\n ...(codexModel ? { model: codexModel } : {}),\n sandboxMode: 'danger-full-access',\n approvalPolicy: 'never',\n workingDirectory: workdir,\n skipGitRepoCheck: true,\n ...(start.reasoningEffort\n ? { modelReasoningEffort: start.reasoningEffort }\n : {}),\n webSearchMode: start.webSearch ? 'live' : 'disabled',\n };\n const thread = threadState.id\n ? codex.resumeThread(threadState.id, threadOptions)\n : codex.startThread(threadOptions);\n\n emit({ type: 'stream-start' });\n\n const userMessage = start.prompt;\n let turnUsage: Record<string, unknown> | undefined;\n const stepTracker = createCodexStepTracker({ send: emit });\n const emitStreamEvent = createEmitStreamEvent({\n send: emit,\n stepTracker,\n setTurnUsage: usage => (turnUsage = usage),\n setThreadId: threadId => (threadState.id = threadId),\n emitWarning: turn.emitWarning,\n emitError: turn.emitError,\n });\n\n try {\n const { events } = await thread.runStreamed(userMessage, {\n signal: turn.abortSignal,\n ...(start.responseFormat?.type === 'json' &&\n start.responseFormat.schema != null\n ? { outputSchema: start.responseFormat.schema }\n : {}),\n });\n for await (const event of events as AsyncIterable<CodexEvent>) {\n if (turn.abortSignal.aborted) break;\n // Temporary workaround for upstream codex MCP-tool bug — see ./cli-relay.ts\n if (cliShimPath && event.item?.type === 'command_execution') {\n const relayCalls =\n typeof event.item.command === 'string'\n ? parseToolRelayCommands({\n command: event.item.command,\n cliShimPath,\n })\n : undefined;\n if (event.type === 'item.started' && relay && relayCalls) {\n for (const relayCall of relayCalls) {\n relay.authorizeToolCall(relayCall);\n }\n }\n if (relayCalls) {\n stepTracker.observeEvent({ event, itemId: event.item.id });\n continue;\n }\n }\n emitStreamEvent(event);\n }\n } catch (err) {\n turn.emitError({ error: err, message: 'codex turn failed' });\n return;\n } finally {\n relay?.close();\n }\n\n emit({\n type: 'finish',\n finishReason: { unified: 'stop', raw: 'stop' },\n totalUsage: turnUsage ?? defaultUsage(),\n });\n}\n\n/**\n * Tool relay — HTTP server on 127.0.0.1:0. The CLI shim invoked by Codex POSTs\n * each tool invocation here; the relay forwards the call to the host (via the\n * shared runtime's `emit`), awaits the matching `tool-result` (via\n * `requestToolResult`), and responds with `{ result }`.\n */\nasync function startToolRelay({\n tools,\n emit,\n requestToolResult,\n}: {\n tools: ReadonlyArray<{ name: string }>;\n emit: Emit;\n requestToolResult: (\n toolCallId: string,\n ) => Promise<{ output: unknown; isError?: boolean }>;\n}): Promise<ToolRelay> {\n return startAuthorizedToolRelay({ tools, emit, requestToolResult });\n}\n\nfunction parseArgs(args: string[]): {\n workdir?: string;\n bridgeStateDir?: string;\n cliShimDir?: string;\n} {\n const out: {\n workdir?: string;\n bridgeStateDir?: string;\n cliShimDir?: string;\n } = {};\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--workdir' && i + 1 < args.length) {\n out.workdir = args[++i];\n } else if (args[i] === '--bridge-state-dir' && i + 1 < args.length) {\n out.bridgeStateDir = args[++i];\n } else if (args[i] === '--cli-shim-dir' && i + 1 < args.length) {\n out.cliShimDir = args[++i];\n }\n }\n return out;\n}\n\nfunction emitFatal(message: string): never {\n stdout.write(JSON.stringify({ type: 'bridge-fatal', message }) + '\\n');\n process.exit(1);\n}\n\nfunction requireArg({\n value,\n name,\n}: {\n value: string | undefined;\n name: string;\n}): string {\n if (!value) {\n emitFatal(`Missing ${name} argument.`);\n }\n return value;\n}\n","/*\n * Temporary workaround for upstream codex CLI bug\n * https://github.com/openai/codex/issues/19425 — MCP tools registered via\n * `mcp_servers.*` are not exposed to the model in `codex exec --experimental-json`\n * mode (which is what `@openai/codex-sdk` uses). The MCP handshake completes\n * and `tools/list` succeeds, but codex never registers the tools as\n * model-callable functions.\n *\n * Until that's fixed upstream, this file implements a CLI-based relay:\n *\n * 1. A small Node script is written into harness-owned session state at turn\n * start (`buildCliShimScript`). It accepts `<toolName> <jsonInput>` as\n * argv, POSTs to the same HTTP relay the MCP shim uses, and prints the\n * result to stdout.\n *\n * 2. Tool descriptions and invocation instructions are injected into the\n * initial user prompt by the host adapter, telling the model to call host\n * tools by running `node <shim-path> <toolName> '<jsonInput>'` via its\n * built-in `bash` tool.\n *\n * 3. The bridge's event loop suppresses the matching `command_execution`\n * events (`isToolRelayCommand`) so callers receive clean `tool-call` /\n * `tool-result` events from the HTTP relay rather than seeing the\n * relay invocations as raw bash commands.\n *\n * Once #19425 is fixed and MCP tools are properly exposed in exec mode, the\n * three hookpoints in `bridge/index.ts` can be removed along with this file.\n */\nexport const CLI_SHIM_FILENAME = 'harness-tool.mjs';\n\nexport function buildCliShimScript({\n relayPort,\n}: {\n relayPort: number;\n}): string {\n return `#!/usr/bin/env node\nconst [toolName, inputJson = '{}'] = process.argv.slice(2);\nif (!toolName) {\n console.error('Usage: harness-tool <tool_name> <json_input>');\n process.exit(64);\n}\nlet input;\ntry {\n input = JSON.parse(inputJson);\n} catch (error) {\n console.error('Invalid JSON input: ' + (error instanceof Error ? error.message : String(error)));\n process.exit(64);\n}\nconst requestId = 'cli-' + Date.now() + '-' + Math.random().toString(16).slice(2);\nconst response = await fetch('http://127.0.0.1:${relayPort}', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ requestId, toolName, input }),\n});\nconst text = await response.text();\nlet payload;\ntry {\n payload = text ? JSON.parse(text) : {};\n} catch {\n payload = { error: text };\n}\nif (!response.ok || payload.error) {\n console.error(String(payload.error ?? ('tool relay failed with HTTP ' + response.status)));\n process.exit(1);\n}\nconsole.log(JSON.stringify(payload.result ?? payload, null, 2));\n`;\n}\n\nexport function isToolRelayCommand({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): boolean {\n return parseToolRelayCommands({ command, cliShimPath }) !== undefined;\n}\n\nexport function parseToolRelayCommand({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): { toolName: string; input: unknown } | undefined {\n const calls = parseToolRelayCommands({ command, cliShimPath });\n return calls?.length === 1 ? calls[0] : undefined;\n}\n\nexport function parseToolRelayCommands({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): Array<{ toolName: string; input: unknown }> | undefined {\n return parseToolRelayCommandsInternal({ command, cliShimPath, depth: 0 });\n}\n\nfunction parseToolRelayCommandsInternal({\n command,\n cliShimPath,\n depth,\n}: {\n command: string;\n cliShimPath: string;\n depth: number;\n}): Array<{ toolName: string; input: unknown }> | undefined {\n const commands = splitShellAndCommands(command);\n if (!commands) return undefined;\n if (commands.length > 1) {\n const relayCalls: Array<{ toolName: string; input: unknown }> = [];\n for (const nestedCommand of commands) {\n const nestedCalls = parseToolRelayCommandsInternal({\n command: nestedCommand,\n cliShimPath,\n depth,\n });\n if (!nestedCalls) return undefined;\n relayCalls.push(...nestedCalls);\n }\n return relayCalls;\n }\n\n const argv = parseShellWords(command);\n if (!argv) return undefined;\n\n const relayCall = parseDirectToolRelayArgv({ argv, cliShimPath });\n if (relayCall) return [relayCall];\n\n const innerCommand = extractShellEvalCommand(argv);\n if (!innerCommand || depth >= 2) return undefined;\n return parseToolRelayCommandsInternal({\n command: innerCommand,\n cliShimPath,\n depth: depth + 1,\n });\n}\n\nfunction parseDirectToolRelayArgv({\n argv,\n cliShimPath,\n}: {\n argv: string[];\n cliShimPath: string;\n}): { toolName: string; input: unknown } | undefined {\n if (argv.length < 3 || argv.length > 4) return undefined;\n if (argv[0] !== 'node' || argv[1] !== cliShimPath) return undefined;\n const toolName = argv[2];\n if (!toolName) return undefined;\n try {\n return { toolName, input: JSON.parse(argv[3] ?? '{}') };\n } catch {\n return undefined;\n }\n}\n\nfunction extractShellEvalCommand(argv: string[]): string | undefined {\n if (argv.length !== 3) return undefined;\n const shellName = argv[0].split('/').at(-1);\n if (shellName !== 'bash' && shellName !== 'sh' && shellName !== 'zsh') {\n return undefined;\n }\n if (argv[1] !== '-c' && argv[1] !== '-lc') return undefined;\n return argv[2];\n}\n\nfunction splitShellAndCommands(command: string): string[] | undefined {\n const commands: string[] = [];\n let start = 0;\n let quote: '\"' | \"'\" | undefined;\n\n for (let i = 0; i < command.length; i++) {\n const char = command[i];\n if (quote === \"'\") {\n if (char === \"'\") quote = undefined;\n continue;\n }\n if (quote === '\"') {\n if (char === '\"') {\n quote = undefined;\n } else if (char === '\\\\') {\n i++;\n }\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n continue;\n }\n if (char === '\\\\') {\n i++;\n continue;\n }\n if (char === '&' && command[i + 1] === '&') {\n const nestedCommand = command.slice(start, i).trim();\n if (!nestedCommand) return undefined;\n commands.push(nestedCommand);\n start = i + 2;\n i++;\n }\n }\n\n if (quote) return undefined;\n const nestedCommand = command.slice(start).trim();\n if (!nestedCommand) return undefined;\n commands.push(nestedCommand);\n return commands;\n}\n\nfunction parseShellWords(command: string): string[] | undefined {\n const words: string[] = [];\n let current = '';\n let quote: '\"' | \"'\" | undefined;\n let hasCurrent = false;\n\n const pushCurrent = () => {\n if (!hasCurrent) return;\n words.push(current);\n current = '';\n hasCurrent = false;\n };\n\n for (let i = 0; i < command.length; i++) {\n const char = command[i];\n if (quote === \"'\") {\n if (char === \"'\") {\n quote = undefined;\n } else {\n current += char;\n }\n hasCurrent = true;\n continue;\n }\n if (quote === '\"') {\n if (char === '\"') {\n quote = undefined;\n } else if (char === '\\\\' && i + 1 < command.length) {\n current += command[++i];\n } else {\n current += char;\n }\n hasCurrent = true;\n continue;\n }\n if (/\\s/.test(char)) {\n pushCurrent();\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n hasCurrent = true;\n continue;\n }\n if (char === '\\\\' && i + 1 < command.length) {\n current += command[++i];\n hasCurrent = true;\n continue;\n }\n if (/[;&|<>()`$]/.test(char)) return undefined;\n current += char;\n hasCurrent = true;\n }\n if (quote) return undefined;\n pushCurrent();\n return words;\n}\n","import type { BridgeEvent } from '@ai-sdk/harness/bridge';\n\ntype Emit = (msg: BridgeEvent) => void;\n\nexport type CodexStepTrackerItem = {\n type: string;\n};\n\nexport type CodexStepTrackerEvent = {\n type: string;\n item?: CodexStepTrackerItem;\n};\n\nexport type CodexStepTracker = {\n observeEvent(input: {\n event: CodexStepTrackerEvent;\n itemId: string | undefined;\n }): void;\n finishTurn(): void;\n};\n\nexport function createCodexStepTracker(input: {\n send: Emit;\n}): CodexStepTracker {\n let stepOpen = false;\n const pendingToolItemIds = new Set<string>();\n\n const finishStep = (): void => {\n if (!stepOpen || pendingToolItemIds.size > 0) return;\n input.send({\n type: 'finish-step',\n finishReason: { unified: 'stop', raw: 'stop' },\n usage: defaultUsage(),\n harnessMetadata: { codex: { inferredStep: true } },\n });\n stepOpen = false;\n };\n\n return {\n observeEvent({ event, itemId }) {\n const item = event.item;\n if (!item || !isStepItem(item)) return;\n\n stepOpen = true;\n\n if (isToolStepItem(item)) {\n if (event.type === 'item.started' && itemId) {\n pendingToolItemIds.add(itemId);\n } else if (event.type === 'item.completed') {\n if (itemId) pendingToolItemIds.delete(itemId);\n finishStep();\n }\n return;\n }\n },\n finishTurn() {\n pendingToolItemIds.clear();\n finishStep();\n },\n };\n}\n\nfunction isStepItem(item: CodexStepTrackerItem): boolean {\n return isModelStepItem(item) || isToolStepItem(item);\n}\n\nfunction isModelStepItem(item: CodexStepTrackerItem): boolean {\n return item.type === 'reasoning' || item.type === 'agent_message';\n}\n\nfunction isToolStepItem(item: CodexStepTrackerItem): boolean {\n return (\n item.type === 'command_execution' ||\n item.type === 'mcp_tool_call' ||\n item.type === 'web_search' ||\n item.type === 'file_change' ||\n item.type === 'todo_list'\n );\n}\n\nexport function defaultUsage(): Record<string, unknown> {\n return {\n inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },\n outputTokens: { total: 0, text: 0 },\n };\n}\n","import type { HarnessV1BuiltinToolName } from '@ai-sdk/harness';\nimport type { BridgeTurn } from '@ai-sdk/harness/bridge';\nimport { randomUUID } from 'node:crypto';\nimport type { CodexStepTracker } from './codex-step-tracker';\n\ntype Emit = (message: Record<string, unknown>) => void;\n\nexport type CodexItem = {\n type: string;\n id?: string;\n text?: string;\n command?: string;\n exit_code?: number;\n aggregated_output?: string;\n status?: 'in_progress' | 'completed' | 'failed';\n server?: string;\n tool?: string;\n arguments?: unknown;\n result?: { content?: unknown; structured_content?: unknown } | unknown;\n error?: { message?: string };\n query?: string;\n message?: string;\n changes?: ReadonlyArray<{\n path: string;\n kind: 'add' | 'delete' | 'update';\n }>;\n};\n\nexport type CodexEvent = {\n type:\n | 'thread.started'\n | 'turn.completed'\n | 'turn.failed'\n | 'error'\n | 'item.started'\n | 'item.updated'\n | 'item.completed';\n item?: CodexItem;\n usage?: Record<string, number>;\n error?: { message: string };\n message?: string;\n thread_id?: string;\n};\n\n/*\n * Native Codex tool name → cross-harness common name. Tools outside this map\n * (e.g. MCP tools the model invokes by name) have no common equivalent; their\n * native name is forwarded as-is on `tool-call` events.\n */\nconst NATIVE_TO_COMMON: Readonly<Record<string, HarnessV1BuiltinToolName>> = {\n shell: 'bash',\n web_search: 'webSearch',\n};\n\nfunction toCommonName(nativeName: string): HarnessV1BuiltinToolName | string {\n return NATIVE_TO_COMMON[nativeName] ?? nativeName;\n}\n\nexport function createEmitStreamEvent({\n send,\n stepTracker,\n setTurnUsage,\n setThreadId,\n emitWarning,\n emitError,\n}: {\n send: Emit;\n stepTracker: CodexStepTracker;\n setTurnUsage: (usage: Record<string, unknown>) => void;\n setThreadId: (threadId: string) => void;\n emitWarning: BridgeTurn['emitWarning'];\n emitError: BridgeTurn['emitError'];\n}): (event: CodexEvent) => void {\n const textByItem = new Map<string, string>();\n const reasoningByItem = new Map<string, string>();\n\n return event => {\n if (\n event.type === 'thread.started' &&\n typeof event.thread_id === 'string'\n ) {\n setThreadId(event.thread_id);\n // Announce to the host so it can include the id in resume state.\n send({ type: 'bridge-thread', threadId: event.thread_id });\n }\n if (event.type === 'turn.completed') {\n if (event.usage) setTurnUsage(mapUsage(event.usage));\n stepTracker.finishTurn();\n return;\n }\n if (event.type === 'turn.failed') {\n emitError({\n error: event.error?.message ?? 'codex turn failed',\n message: 'codex turn failed',\n });\n return;\n }\n if (event.type === 'error') {\n emitError({\n error: event.message ?? 'codex error',\n message: 'codex stream error',\n });\n return;\n }\n if (!event.item) return;\n const item = event.item;\n const id = item.id ?? randomUUID();\n const observeStep = (): void => {\n stepTracker.observeEvent({ event, itemId: id });\n };\n\n if (item.type === 'agent_message' && typeof item.text === 'string') {\n /*\n * The presence of `id` in `textByItem` — not the `item.started` event —\n * marks the text part as opened. Codex does not guarantee an\n * `item.started` event carrying text precedes the first `item.updated`\n * with text, so keying the `text-start` off the event type can emit a\n * `text-delta` for a part that was never opened. Opening lazily on the\n * first event with text keeps `text-start` before any `text-delta`.\n */\n if (!textByItem.has(id)) {\n send({ type: 'text-start', id });\n textByItem.set(id, '');\n }\n const last = textByItem.get(id) ?? '';\n const next = item.text;\n if (next.length > last.length) {\n send({ type: 'text-delta', id, delta: next.slice(last.length) });\n textByItem.set(id, next);\n }\n if (event.type === 'item.completed') send({ type: 'text-end', id });\n observeStep();\n return;\n }\n\n if (item.type === 'reasoning' && typeof item.text === 'string') {\n if (!reasoningByItem.has(id)) {\n send({ type: 'reasoning-start', id });\n reasoningByItem.set(id, '');\n }\n const last = reasoningByItem.get(id) ?? '';\n const next = item.text;\n if (next.length > last.length) {\n send({ type: 'reasoning-delta', id, delta: next.slice(last.length) });\n reasoningByItem.set(id, next);\n }\n if (event.type === 'item.completed') send({ type: 'reasoning-end', id });\n observeStep();\n return;\n }\n\n if (item.type === 'command_execution') {\n const nativeName = 'shell';\n if (event.type === 'item.started') {\n send({\n type: 'tool-call',\n toolCallId: id,\n toolName: toCommonName(nativeName),\n nativeName,\n input: JSON.stringify({ command: item.command ?? '' }),\n providerExecuted: true,\n });\n } else if (event.type === 'item.completed') {\n send({\n type: 'tool-result',\n toolCallId: id,\n toolName: toCommonName(nativeName),\n result: {\n exitCode: item.exit_code ?? null,\n output: item.aggregated_output ?? '',\n status: item.status ?? 'completed',\n },\n });\n }\n observeStep();\n return;\n }\n\n if (item.type === 'mcp_tool_call') {\n if (event.type === 'item.started') {\n send({\n type: 'tool-call',\n toolCallId: id,\n toolName: item.tool ?? 'unknown',\n nativeName: item.tool ?? 'unknown',\n input: JSON.stringify(item.arguments ?? {}),\n providerExecuted: true,\n dynamic: true,\n });\n } else if (event.type === 'item.completed') {\n send({\n type: 'tool-result',\n toolCallId: id,\n toolName: item.tool ?? 'unknown',\n result: extractMcpToolCallResult(item),\n dynamic: true,\n });\n }\n observeStep();\n return;\n }\n\n if (item.type === 'web_search') {\n const nativeName = 'web_search';\n if (event.type === 'item.started') {\n send({\n type: 'tool-call',\n toolCallId: id,\n toolName: toCommonName(nativeName),\n nativeName,\n input: JSON.stringify({ query: item.query ?? '' }),\n providerExecuted: true,\n });\n } else if (event.type === 'item.completed') {\n send({\n type: 'tool-result',\n toolCallId: id,\n toolName: toCommonName(nativeName),\n result: item.result ?? null,\n });\n }\n observeStep();\n return;\n }\n\n if (item.type === 'file_change' && event.type === 'item.completed') {\n for (const change of item.changes ?? []) {\n send({\n type: 'file-change',\n event:\n change.kind === 'add'\n ? 'create'\n : change.kind === 'delete'\n ? 'delete'\n : 'modify',\n path: change.path,\n });\n }\n observeStep();\n return;\n }\n\n if (item.type === 'error' && event.type === 'item.completed') {\n const message =\n typeof item.message === 'string' && item.message.trim()\n ? item.message\n : 'codex reported a non-fatal error item';\n emitWarning({ message });\n }\n };\n}\n\nfunction extractMcpToolCallResult(item: CodexItem): unknown {\n if (\n item.result === undefined ||\n item.result === null ||\n typeof item.result !== 'object'\n ) {\n return item.error?.message ? { error: item.error.message } : null;\n }\n const result = item.result as {\n content?: unknown;\n structured_content?: unknown;\n };\n if (\n result.structured_content !== undefined &&\n result.structured_content !== null\n ) {\n return result.structured_content;\n }\n return result.content ?? null;\n}\n\nfunction mapUsage(usage: Record<string, number>): Record<string, unknown> {\n const input = usage.input_tokens ?? 0;\n const cacheRead = usage.cached_input_tokens ?? 0;\n return {\n inputTokens: {\n total: input,\n noCache: Math.max(0, input - cacheRead),\n cacheRead,\n cacheWrite: 0,\n },\n outputTokens: {\n total: usage.output_tokens ?? 0,\n text: usage.output_tokens ?? 0,\n },\n };\n}\n","import { createServer, type Server } from 'node:http';\nimport {\n ToolRelayAuthorizer,\n ToolRelayPendingCalls,\n type ToolRelayCall,\n} from './tool-relay-auth';\n\nexport type ToolRelay = {\n port: number;\n close(): void;\n authorizeToolCall(call: ToolRelayCall): void;\n};\n\nexport async function startAuthorizedToolRelay({\n tools,\n emit,\n requestToolResult,\n authorizer = new ToolRelayAuthorizer(),\n}: {\n tools: ReadonlyArray<{ name: string }>;\n emit: (message: Record<string, unknown>) => void;\n requestToolResult: (\n toolCallId: string,\n ) => Promise<{ output: unknown; isError?: boolean }>;\n authorizer?: ToolRelayAuthorizer;\n}): Promise<ToolRelay> {\n const toolNames = new Set(tools.map(tool => tool.name));\n const pendingCalls = new ToolRelayPendingCalls();\n\n const server = createServer(async (req, res) => {\n try {\n if (req.method !== 'POST' || req.url !== '/') {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'unauthorized tool relay request' }));\n return;\n }\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(chunk as Buffer);\n }\n const body = Buffer.concat(chunks).toString('utf8');\n const { requestId, toolName, input } = JSON.parse(body) as {\n requestId: string;\n toolName: string;\n input: unknown;\n };\n\n if (!toolNames.has(toolName)) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: `Tool \"${toolName}\" is not available` }),\n );\n return;\n }\n const relayCall = { toolName, input };\n if (!(await authorizer.waitForToolCallAuthorization(relayCall))) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'unauthorized tool relay request' }));\n return;\n }\n\n const { result } = pendingCalls.begin({\n call: relayCall,\n run: async () => {\n emit({\n type: 'tool-call',\n toolCallId: requestId,\n toolName,\n input: JSON.stringify(input ?? {}),\n providerExecuted: false,\n });\n\n const toolResult = await requestToolResult(requestId);\n emit({\n type: 'tool-result',\n toolCallId: requestId,\n toolName,\n result: toolResult.output ?? null,\n isError: !!toolResult.isError,\n });\n return toolResult;\n },\n });\n const { output } = await result;\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ result: output }));\n } catch (error) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n });\n\n await new Promise<void>(resolve =>\n server.listen(0, '127.0.0.1', () => resolve()),\n );\n const address = server.address();\n if (!address || typeof address === 'string') {\n throw new Error('tool relay did not expose a numeric port');\n }\n return {\n port: address.port,\n close: () => {\n authorizer.close();\n closeServer(server);\n },\n authorizeToolCall: call => authorizer.authorizeToolCall(call),\n };\n}\n\nfunction closeServer(server: Server): void {\n try {\n server.close();\n } catch {}\n}\n","export type ToolRelayCall = {\n toolName: string;\n input: unknown;\n};\n\nexport type ToolRelayResult = {\n output: unknown;\n isError?: boolean;\n};\n\nexport class ToolRelayAuthorizer {\n private readonly ttlMs: number;\n private readonly now: () => number;\n private readonly authorizations: Array<{ key: string; expiresAt: number }> =\n [];\n private readonly pendingRequests: Array<{\n key: string;\n expiresAt: number;\n timeout: ReturnType<typeof setTimeout>;\n resolve: (authorized: boolean) => void;\n }> = [];\n\n constructor({\n ttlMs = 10_000,\n now = Date.now,\n }: {\n ttlMs?: number;\n now?: () => number;\n } = {}) {\n this.ttlMs = ttlMs;\n this.now = now;\n }\n\n authorizeToolCall(call: ToolRelayCall): void {\n this.pruneExpired();\n const key = toolRelayCallKey(call);\n const pendingRequestIndex = this.pendingRequests.findIndex(\n request => request.key === key,\n );\n if (pendingRequestIndex !== -1) {\n const [pendingRequest] = this.pendingRequests.splice(\n pendingRequestIndex,\n 1,\n );\n clearTimeout(pendingRequest.timeout);\n pendingRequest.resolve(true);\n return;\n }\n this.authorizations.push({\n key,\n expiresAt: this.now() + this.ttlMs,\n });\n }\n\n waitForToolCallAuthorization(call: ToolRelayCall): Promise<boolean> {\n this.pruneExpired();\n const key = toolRelayCallKey(call);\n const authorizationIndex = this.authorizations.findIndex(\n authorization => authorization.key === key,\n );\n if (authorizationIndex !== -1) {\n this.authorizations.splice(authorizationIndex, 1);\n return Promise.resolve(true);\n }\n\n const expiresAt = this.now() + this.ttlMs;\n return new Promise(resolve => {\n const pendingRequest = {\n key,\n expiresAt,\n timeout: setTimeout(() => {\n const index = this.pendingRequests.indexOf(pendingRequest);\n if (index !== -1) this.pendingRequests.splice(index, 1);\n resolve(false);\n }, this.ttlMs),\n resolve,\n };\n this.pendingRequests.push(pendingRequest);\n });\n }\n\n close(): void {\n this.authorizations.length = 0;\n for (const pendingRequest of this.pendingRequests.splice(0)) {\n clearTimeout(pendingRequest.timeout);\n pendingRequest.resolve(false);\n }\n }\n\n private pruneExpired(): void {\n const now = this.now();\n for (let i = this.authorizations.length - 1; i >= 0; i--) {\n if (this.authorizations[i].expiresAt <= now) {\n this.authorizations.splice(i, 1);\n }\n }\n for (let i = this.pendingRequests.length - 1; i >= 0; i--) {\n const pendingRequest = this.pendingRequests[i];\n if (pendingRequest.expiresAt <= now) {\n this.pendingRequests.splice(i, 1);\n clearTimeout(pendingRequest.timeout);\n pendingRequest.resolve(false);\n }\n }\n }\n}\n\nexport class ToolRelayPendingCalls {\n private readonly calls = new Map<string, Promise<ToolRelayResult>>();\n\n begin({\n call,\n run,\n }: {\n call: ToolRelayCall;\n run: () => Promise<ToolRelayResult>;\n }): { result: Promise<ToolRelayResult>; isNew: boolean } {\n const key = toolRelayCallKey(call);\n const existing = this.calls.get(key);\n if (existing) return { result: existing, isNew: false };\n\n const result = run();\n this.calls.set(key, result);\n void result\n .finally(() => {\n if (this.calls.get(key) === result) {\n this.calls.delete(key);\n }\n })\n .catch(() => {});\n return { result, isNew: true };\n }\n}\n\nfunction toolRelayCallKey({ toolName, input }: ToolRelayCall): string {\n return `${toolName}\\0${canonicalJson(input ?? {})}`;\n}\n\nfunction canonicalJson(value: unknown): string {\n return JSON.stringify(normalizeJsonValue(value));\n}\n\nfunction normalizeJsonValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(normalizeJsonValue);\n }\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .filter(([, entryValue]) => entryValue !== undefined)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entryValue]) => [key, normalizeJsonValue(entryValue)]),\n );\n }\n return value;\n}\n"],"mappings":"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","names":["bridgeStateDir","pending","mkdir","writeFile","argv","nestedCommand","randomUUID","procEnv","stdout","mkdir","writeFile","args"]}
package/dist/index.js CHANGED
@@ -182,7 +182,7 @@ var inboundMessageSchema = z.discriminatedUnion("type", [
182
182
  var CLI_SHIM_FILENAME = "harness-tool.mjs";
183
183
 
184
184
  // src/version.ts
185
- var VERSION = true ? "1.0.101" : "0.0.0-test";
185
+ var VERSION = true ? "1.0.103" : "0.0.0-test";
186
186
 
187
187
  // src/codex-harness.ts
188
188
  var DEFAULT_CODEX_MODEL = "gpt-5.5";
@@ -290,8 +290,6 @@ function createCodex(settings = {}) {
290
290
  if (requestTransformations.length > 0 && authenticationMode === "direct" && resolvedAuthEnvironment.OPENAI_BASE_URL == null) {
291
291
  sandboxAuthEnvironment.OPENAI_BASE_URL = DEFAULT_OPENAI_BASE_URL;
292
292
  }
293
- } else {
294
- warnCredentialBrokeringUnavailable();
295
293
  }
296
294
  const bootstrapDir = path.posix.resolve(
297
295
  defaultWorkingDirectory,
@@ -387,6 +385,13 @@ function createCodex(settings = {}) {
387
385
  credentialEnvironmentVariables: CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES,
388
386
  credentialForwarding: settings.credentialForwarding
389
387
  });
388
+ if (!credentialsBrokered) {
389
+ warnCredentialBrokeringUnavailable({
390
+ environment: resolvedAuthEnvironment,
391
+ forwardedEnvironment: forwardedAuthEnvironment,
392
+ credentialEnvironmentVariables: CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES
393
+ });
394
+ }
390
395
  const env = {
391
396
  ...forwardedAuthEnvironment,
392
397
  AI_SDK_HARNESS_CLIENT_APP: CODEX_CLIENT_APP,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/codex-harness.ts","../src/codex-bootstrap.ts","../src/codex-auth.ts","../src/codex-bridge-protocol.ts","../src/bridge/cli-relay.ts","../src/version.ts","../src/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport path from 'node:path';\nimport {\n commonTool,\n HarnessCapabilityUnsupportedError,\n harnessV1DiagnosticFromBridgeFrame,\n type HarnessV1,\n type HarnessV1DebugConfig,\n type HarnessV1BuiltinTool,\n type HarnessV1ContinueTurnState,\n type HarnessV1CredentialForwarding,\n type HarnessV1Prompt,\n type HarnessV1PromptControl,\n type HarnessV1PortEndpoint,\n type HarnessV1ResumeSessionState,\n type HarnessV1NetworkSandboxSession,\n type HarnessV1PermissionMode,\n type HarnessV1Session,\n type HarnessV1Skill,\n type HarnessV1StreamPart,\n} from '@ai-sdk/harness';\nimport {\n applyCredentialForwarding,\n classifyDiskLog,\n createBridgeToken,\n createSandboxCredentialEnvironment,\n createBridgeErrorHandler,\n createBridgeStartupError,\n drainBridgeProcessStream,\n forwardBridgeProcessStream,\n getRestrictedSandboxSession,\n markBridgeStarting,\n resolveSandboxDefaultWorkingDirectory,\n resolveSandboxHomeDir,\n SandboxChannel,\n shellQuote,\n warnCredentialBrokeringUnavailable,\n waitForBridgeReady,\n withBridgeToken,\n writeSkills as writeHarnessSkills,\n type WriteSkillsResult,\n} from '@ai-sdk/harness/utils';\nimport {\n type Experimental_SandboxProcess,\n type Experimental_SandboxSession as SandboxSession,\n} from '@ai-sdk/provider-utils';\nimport { WebSocket } from 'ws';\nimport { z } from 'zod/v4';\nimport {\n CODEX_BOOTSTRAP_DIR as BOOTSTRAP_DIR,\n getCodexBootstrap,\n} from './codex-bootstrap';\nimport {\n CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES,\n createCodexRequestTransformations,\n DEFAULT_OPENAI_BASE_URL,\n resolveCodexAuthenticationMode,\n resolveCodexEnv,\n type CodexAuthenticationMode,\n} from './codex-auth';\nimport {\n outboundMessageSchema,\n type InboundMessage,\n type OutboundMessage,\n} from './codex-bridge-protocol';\nimport { CLI_SHIM_FILENAME } from './bridge/cli-relay';\nimport { VERSION } from './version';\n\ntype CodexChannel = SandboxChannel<OutboundMessage, InboundMessage>;\ntype CodexRespawnStrategy = 'replay' | 'rerun';\n\n/*\n * This intentionally is not the latest Codex model. Newer GPT-5.6 models use\n * Responses Lite, which does not expose their code-mode tools as callable\n * through the custom model provider used by the harness. Keep GPT-5.5 as the\n * default until the upstream bug is resolved:\n * https://github.com/openai/codex/issues/31894\n *\n * Passing the model explicitly keeps the runtime behavior deterministic and\n * the telemetry (`gen_ai.request.model`) accurate.\n */\nconst DEFAULT_CODEX_MODEL = 'gpt-5.5';\n\n/**\n * Value to use in User-Agent and `x-client-app` headers.\n */\nconst CODEX_CLIENT_APP = `ai-sdk/harness-codex/${VERSION}`;\n\nexport type CodexHarnessSettings = {\n readonly auth?: CodexAuthenticationMode;\n /**\n * Customizes each credential value before it is forwarded into a sandbox\n * process. This does not restrict which credentials the harness adapter can\n * discover, read, or otherwise access in the host process.\n */\n readonly credentialForwarding?: HarnessV1CredentialForwarding;\n /**\n * Additional configuration passed through to Codex as-is. Codex config keys\n * typically use snake_case and must be provided in that form. Values managed\n * by this adapter take precedence over conflicting entries.\n */\n readonly codexConfig?: Record<string, unknown>;\n /**\n * MCP server definitions keyed by server name. Each definition uses the\n * underlying runtime's native MCP server configuration format.\n */\n readonly mcpServers?: Record<string, unknown>;\n /**\n * OpenAI model id the underlying `codex` CLI should use. Leaving this unset\n * pins the adapter default (`DEFAULT_CODEX_MODEL`).\n *\n * @deprecated Use `model` on `HarnessAgent` instead.\n */\n readonly model?: string;\n /**\n * Reasoning effort for reasoning-capable models. Leaving this unset\n * defers to the CLI's default.\n */\n readonly reasoningEffort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n /**\n * When `true`, allow the underlying runtime to use live web search.\n */\n readonly webSearch?: boolean;\n /**\n * Override the port the bridge binds inside the sandbox. By default the\n * adapter uses the first port the sandbox declares via `sandbox.ports`.\n * Only set this if the sandbox declares multiple ports and the first one\n * is reserved for something else.\n */\n readonly port?: number;\n /**\n * Override the host endpoint used to connect to the sandbox bridge. Required\n * together with `port` when using a basic sandbox session.\n */\n readonly portEndpoint?: HarnessV1PortEndpoint;\n /** Maximum milliseconds to wait for the bridge to advertise its port. Defaults to 120000. */\n readonly startupTimeoutMs?: number;\n /**\n * Creates the authentication token used by the sandbox bridge. Defaults to\n * a random 32-byte hexadecimal token.\n */\n readonly mintBridgeToken?: (sandboxId: string) => string;\n};\n\n/*\n * Every native tool the Codex CLI can invoke as a model-callable tool,\n * declared as a `ToolSet` keyed by what the bridge emits as `toolName` on\n * the wire (`commonName ?? nativeName`). Schemas reflect the `ThreadItem`\n * union in `@openai/codex-sdk`'s `dist/index.d.ts`.\n *\n * Codex's other native operations (`apply_patch`, todo planning) surface\n * only as side-effect events (`file_change`, `todo_list`) and are not\n * model-callable tools — they don't appear here.\n */\nconst CODEX_BUILTIN_TOOLS = {\n bash: commonTool('bash', {\n nativeName: 'shell',\n toolUseKind: 'bash',\n description: 'Execute a shell command',\n inputSchema: z.object({ command: z.string() }),\n }),\n webSearch: commonTool('webSearch', {\n nativeName: 'web_search',\n toolUseKind: 'readonly',\n description: 'Search the web',\n inputSchema: z.object({ query: z.string() }),\n }),\n} as const satisfies Record<string, HarnessV1BuiltinTool<any, any>>;\n\n/**\n * Live bridge coordinates returned by `doDetach()` and `doSuspendTurn()`. A\n * future process uses them to reopen a socket to the still-running bridge\n * (`attach`) instead of re-spawning it. Absent on a `doStop()` payload.\n */\nconst codexBridgeCoordsSchema = z.object({\n port: z.number(),\n token: z.string(),\n lastSeenEventId: z.number(),\n sandboxId: z.string().optional(),\n});\n\n/**\n * Schema for the adapter-specific lifecycle `data` payload Codex produces.\n * `threadId` is what `codex.resumeThread(...)` requires for the replay/rerun\n * rungs; the sandbox lookup is handled separately via\n * `provider.resumeSession({ sessionId })`. `bridge` carries live coordinates\n * for cross-process `attach` (present on `doDetach()` and `doSuspendTurn()`\n * payloads).\n */\nconst codexResumeStateSchema = z.object({\n threadId: z.string().optional(),\n turnConfigurationFingerprint: z.string().optional(),\n bridge: codexBridgeCoordsSchema.optional(),\n sandboxCredentialEnvironment: z.record(z.string(), z.string()).optional(),\n});\n\ntype CodexBridgeCoords = z.infer<typeof codexBridgeCoordsSchema>;\n\nexport function createCodex(\n settings: CodexHarnessSettings = {},\n): HarnessV1<typeof CODEX_BUILTIN_TOOLS> {\n return {\n specificationVersion: 'harness-v1',\n harnessId: 'codex',\n builtinTools: CODEX_BUILTIN_TOOLS,\n supportsBuiltinToolApprovals: false,\n lifecycleStateSchema: codexResumeStateSchema,\n getBootstrap: getCodexBootstrap,\n doStart: async startOpts => {\n const model = settings.model ?? DEFAULT_CODEX_MODEL;\n if (startOpts.builtinToolFiltering != null) {\n throw new HarnessCapabilityUnsupportedError({\n message:\n \"Harness 'codex' does not support built-in tool filtering controls.\",\n harnessId: 'codex',\n });\n }\n if (\n startOpts.permissionMode != null &&\n startOpts.permissionMode !== 'allow-all'\n ) {\n throw new HarnessCapabilityUnsupportedError({\n message:\n \"Harness 'codex' does not support built-in tool approval requests; use permissionMode: 'allow-all'.\",\n harnessId: 'codex',\n });\n }\n const sandboxSession = startOpts.sandboxSession;\n const toolSafeSandboxSession =\n getRestrictedSandboxSession(sandboxSession);\n const sandboxId = 'id' in sandboxSession ? sandboxSession.id : undefined;\n validateBasicSandboxSettings({\n sandboxSession,\n port: settings.port,\n portEndpoint: settings.portEndpoint,\n });\n if (settings.mintBridgeToken != null && sandboxId == null) {\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message:\n 'The codex harness cannot use `mintBridgeToken` with a sandbox session that does not expose an id.',\n });\n }\n const defaultWorkingDirectory =\n await resolveSandboxDefaultWorkingDirectory({\n sandboxSession,\n abortSignal: startOpts.abortSignal,\n });\n const lifecycleState = startOpts.continueFrom ?? startOpts.resumeFrom;\n const isResume = lifecycleState != null;\n const isContinue = startOpts.continueFrom != null;\n const resumeData =\n isResume && typeof lifecycleState?.data === 'object'\n ? (lifecycleState.data as {\n threadId?: unknown;\n turnConfigurationFingerprint?: unknown;\n bridge?: CodexBridgeCoords;\n sandboxCredentialEnvironment?: Record<string, string>;\n })\n : undefined;\n const resumeThreadId = resumeData?.threadId;\n const resumeThreadIdString =\n typeof resumeThreadId === 'string' && resumeThreadId.length > 0\n ? resumeThreadId\n : undefined;\n const turnConfigurationFingerprint =\n typeof resumeData?.turnConfigurationFingerprint === 'string'\n ? resumeData.turnConfigurationFingerprint\n : undefined;\n const coords = resumeData?.bridge;\n const authenticationMode = resolveCodexAuthenticationMode(settings.auth);\n const resolvedAuthEnvironment = resolveCodexEnv(settings.auth);\n let sandboxAuthEnvironment = resolvedAuthEnvironment;\n let sandboxCredentialEnvironment: Record<string, string> | undefined;\n let credentialsBrokered = false;\n if (\n 'addRequestTransformations' in sandboxSession &&\n sandboxSession.addRequestTransformations != null\n ) {\n sandboxCredentialEnvironment =\n resumeData?.sandboxCredentialEnvironment ??\n (await createSandboxCredentialEnvironment({\n environment: resolvedAuthEnvironment,\n credentialEnvironmentVariables:\n CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES,\n credentialForwarding: settings.credentialForwarding,\n }));\n sandboxAuthEnvironment = {\n ...resolvedAuthEnvironment,\n ...sandboxCredentialEnvironment,\n };\n const requestTransformations = createCodexRequestTransformations({\n env: resolvedAuthEnvironment,\n sandboxEnv: sandboxAuthEnvironment,\n auth: authenticationMode,\n });\n if (requestTransformations.length > 0) {\n await sandboxSession.addRequestTransformations(\n requestTransformations,\n );\n }\n credentialsBrokered = true;\n if (\n requestTransformations.length > 0 &&\n authenticationMode === 'direct' &&\n resolvedAuthEnvironment.OPENAI_BASE_URL == null\n ) {\n /*\n * Vercel Sandbox request transformations apply only to HTTP traffic.\n * Materializing Codex's standard OpenAI URL makes the bridge select\n * its custom provider, where WebSockets are disabled, while keeping\n * the non-brokered path on Codex's built-in OpenAI provider.\n */\n sandboxAuthEnvironment.OPENAI_BASE_URL = DEFAULT_OPENAI_BASE_URL;\n }\n } else {\n warnCredentialBrokeringUnavailable();\n }\n const bootstrapDir = path.posix.resolve(\n defaultWorkingDirectory,\n BOOTSTRAP_DIR,\n );\n\n const workDir = startOpts.sessionWorkDir;\n const sandboxHomeDir = await resolveSandboxHomeDir({\n sandbox: toolSafeSandboxSession,\n abortSignal: startOpts.abortSignal,\n });\n const sessionDataDir = `${defaultWorkingDirectory}/.agent-runs/${startOpts.sessionId}`;\n const bridgeStateDir = `${sessionDataDir}/bridge`;\n const cliShimDir = `${sessionDataDir}/codex`;\n const cliShimPath = `${cliShimDir}/${CLI_SHIM_FILENAME}`;\n const timeoutMs = settings.startupTimeoutMs ?? 120_000;\n\n // Normalize each forwarded bridge diagnostics frame into the general\n // `HarnessV1Diagnostic` and report it. The adapter does no telemetry work\n // beyond this transport→emission mapping.\n const report = startOpts.observability?.report;\n const onDiagnostic = report\n ? (frame: Parameters<typeof harnessV1DiagnosticFromBridgeFrame>[0]) =>\n report(\n harnessV1DiagnosticFromBridgeFrame(frame, {\n sessionId: startOpts.sessionId,\n timestamp: Date.now(),\n }),\n )\n : undefined;\n const onBridgeError = createBridgeErrorHandler({\n harnessId: 'codex',\n sessionId: startOpts.sessionId,\n });\n\n /*\n * Rung 1 — ATTACH. With live coordinates, reopen a socket to the\n * still-running bridge. Parked between-turn sessions just attach and wait\n * for the next `start`; suspended in-flight turns request replay of\n * everything past the persisted cursor. No spawn, no fresh token. If the\n * bridge is gone the open throws and we fall through to a spawn-based\n * recovery.\n */\n if (coords) {\n try {\n const endpoint = await resolveBridgeEndpoint({\n sandboxSession,\n override: settings.portEndpoint,\n port: coords.port,\n });\n const attachEndpoint = withBridgeToken({\n endpoint,\n token: coords.token,\n });\n const attachChannel: CodexChannel = new SandboxChannel({\n connect: () => openWebSocket(attachEndpoint),\n outboundSchema: outboundMessageSchema,\n initialLastSeenEventId: coords.lastSeenEventId,\n onDiagnostic,\n onBridgeError,\n });\n await attachChannel.open(isContinue ? { resume: true } : undefined);\n return createSession({\n sessionId: startOpts.sessionId,\n channel: attachChannel,\n cliShimPath,\n // The live bridge was spawned by another process; no process handle.\n proc: undefined,\n model,\n reasoningEffort: settings.reasoningEffort,\n webSearch: settings.webSearch,\n codexConfig: settings.codexConfig,\n mcpServers: settings.mcpServers,\n resumeThreadId: resumeThreadIdString,\n isResume: true,\n seedResumeThreadOnFirstPrompt: false,\n rerunContinue: false,\n bridgePort: coords.port,\n bridgeToken: coords.token,\n sandboxId,\n sandboxCredentialEnvironment,\n debug: startOpts.observability?.debug,\n permissionMode: startOpts.permissionMode,\n sandbox: toolSafeSandboxSession,\n sandboxHomeDir,\n turnConfigurationFingerprint,\n });\n } catch {\n // Bridge no longer reachable — recover by respawning below.\n }\n }\n\n /*\n * Rungs 2/3 — REPLAY vs RERUN. Respawn the bridge. `replay` is only sound\n * for `continueFrom`: those coordinates include the cursor the on-disk\n * log is replayed *from*. `resumeFrom` is a between-turn resume; even when\n * it carries bridge coordinates, replaying the previous turn would\n * re-deliver stale events into the next turn. Those resumes always `rerun`\n * via `codex.resumeThread(threadId)` when attach is unavailable.\n */\n let respawnStrategy: CodexRespawnStrategy | undefined = isResume\n ? 'rerun'\n : undefined;\n if (coords && isContinue) {\n const logRaw = await Promise.resolve(\n toolSafeSandboxSession.readTextFile({\n path: `${bridgeStateDir}/event-log.ndjson`,\n abortSignal: startOpts.abortSignal,\n }),\n ).catch(() => null);\n if ((await classifyDiskLog(logRaw)) === 'replay') {\n respawnStrategy = 'replay';\n }\n }\n\n const port = resolveBridgePort({\n sandboxSession,\n override: settings.port,\n });\n const token =\n settings.mintBridgeToken == null\n ? createBridgeToken()\n : settings.mintBridgeToken(sandboxId!);\n const forwardedAuthEnvironment = credentialsBrokered\n ? sandboxAuthEnvironment\n : await applyCredentialForwarding({\n environment: sandboxAuthEnvironment,\n credentialEnvironmentVariables:\n CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES,\n credentialForwarding: settings.credentialForwarding,\n });\n const env = {\n ...forwardedAuthEnvironment,\n AI_SDK_HARNESS_CLIENT_APP: CODEX_CLIENT_APP,\n BRIDGE_CHANNEL_TOKEN: token,\n BRIDGE_WS_PORT: String(port),\n ...(respawnStrategy === 'replay'\n ? { BRIDGE_REPLAY_FROM_DISK: '1' }\n : {}),\n };\n\n if (respawnStrategy === undefined) {\n await toolSafeSandboxSession.run({\n command: `mkdir -p ${shellQuote(workDir)} ${shellQuote(bridgeStateDir)}`,\n abortSignal: startOpts.abortSignal,\n });\n }\n\n await markBridgeStarting({\n sandbox: toolSafeSandboxSession,\n bridgeStateDir,\n bridgeType: 'codex',\n abortSignal: startOpts.abortSignal,\n });\n\n const proc = await toolSafeSandboxSession.spawn({\n command: `node ${shellQuote(`${bootstrapDir}/bridge.mjs`)} --workdir ${shellQuote(workDir)} --bridge-state-dir ${shellQuote(bridgeStateDir)} --cli-shim-dir ${shellQuote(cliShimDir)}`,\n env,\n abortSignal: startOpts.abortSignal,\n });\n const stderrTail: string[] = [];\n const bridgeStderrDone = forwardBridgeProcessStream({\n stream: proc.stderr,\n streamName: 'stderr',\n source: 'codex',\n collectTail: stderrTail,\n });\n\n const { port: boundPort } = await waitForBridgeReady({\n proc,\n sandbox: toolSafeSandboxSession,\n bridgeStateDir,\n bridgeType: 'codex',\n timeoutMs,\n abortSignal: startOpts.abortSignal,\n createTimeoutError: ({ proc, stdoutTail }) =>\n createBridgeStartupError({\n message: 'codex bridge did not become ready in time.',\n proc,\n stdoutTail,\n stderrTail,\n stderrDone: bridgeStderrDone,\n }),\n createExitError: ({ proc, stdoutTail }) =>\n createBridgeStartupError({\n message: 'codex bridge exited before becoming ready.',\n proc,\n stdoutTail,\n stderrTail,\n stderrDone: bridgeStderrDone,\n }),\n });\n void drainBridgeProcessStream(proc.stdout);\n\n const endpoint = await resolveBridgeEndpoint({\n sandboxSession,\n override: settings.portEndpoint,\n port: boundPort,\n });\n const bridgeEndpoint = withBridgeToken({ endpoint, token });\n\n const channel: CodexChannel = new SandboxChannel({\n connect: () => openWebSocket(bridgeEndpoint),\n outboundSchema: outboundMessageSchema,\n onDiagnostic,\n onBridgeError,\n // In replay mode the respawned bridge reloaded the finished turn from\n // disk; seed the cursor and resume so it streams the tail (incl.\n // `finish`).\n ...(respawnStrategy === 'replay'\n ? { initialLastSeenEventId: coords?.lastSeenEventId ?? 0 }\n : {}),\n });\n await channel.open(\n respawnStrategy === 'replay' ? { resume: true } : undefined,\n );\n\n return createSession({\n sessionId: startOpts.sessionId,\n channel,\n cliShimPath,\n proc,\n model,\n reasoningEffort: settings.reasoningEffort,\n webSearch: settings.webSearch,\n codexConfig: settings.codexConfig,\n mcpServers: settings.mcpServers,\n resumeThreadId: resumeThreadIdString,\n isResume: respawnStrategy !== undefined,\n seedResumeThreadOnFirstPrompt: respawnStrategy !== undefined,\n rerunContinue: respawnStrategy === 'rerun',\n bridgePort: boundPort,\n bridgeToken: token,\n sandboxId,\n sandboxCredentialEnvironment,\n debug: startOpts.observability?.debug,\n permissionMode: startOpts.permissionMode,\n sandbox: toolSafeSandboxSession,\n sandboxHomeDir,\n turnConfigurationFingerprint,\n });\n },\n };\n}\n\nfunction resolveBridgePort({\n sandboxSession,\n override,\n}: {\n sandboxSession: HarnessV1NetworkSandboxSession | SandboxSession;\n override: number | undefined;\n}): number {\n if (override !== undefined) return override;\n if ('ports' in sandboxSession && sandboxSession.ports.length > 0) {\n return sandboxSession.ports[0];\n }\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message:\n 'The codex harness needs a TCP port exposed by the sandbox. ' +\n 'Create the sandbox with `ports: [<port>]` or pass `createCodex({ port })`.',\n });\n}\n\nfunction validateBasicSandboxSettings({\n sandboxSession,\n port,\n portEndpoint,\n}: {\n sandboxSession: HarnessV1NetworkSandboxSession | SandboxSession;\n port: number | undefined;\n portEndpoint: HarnessV1PortEndpoint | undefined;\n}): void {\n if ('getPortEndpoint' in sandboxSession) return;\n if (port == null) {\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message:\n 'The codex harness requires an explicit `port` when using a basic sandbox session.',\n });\n }\n if (portEndpoint == null) {\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message:\n 'The codex harness requires an explicit `portEndpoint` when using a basic sandbox session.',\n });\n }\n}\n\nasync function resolveBridgeEndpoint({\n sandboxSession,\n override,\n port,\n}: {\n sandboxSession: HarnessV1NetworkSandboxSession | SandboxSession;\n override: HarnessV1PortEndpoint | undefined;\n port: number;\n}): Promise<HarnessV1PortEndpoint> {\n if (override != null) return override;\n if ('getPortEndpoint' in sandboxSession) {\n return sandboxSession.getPortEndpoint({ port, protocol: 'ws' });\n }\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message:\n 'The codex harness requires an explicit `portEndpoint` when using a basic sandbox session.',\n });\n}\n\nasync function writeCodexSkills({\n sandbox,\n sandboxHomeDir,\n skills,\n abortSignal,\n}: {\n sandbox: SandboxSession;\n sandboxHomeDir: string;\n skills: ReadonlyArray<HarnessV1Skill>;\n abortSignal?: AbortSignal;\n}): Promise<WriteSkillsResult> {\n const rootDir = path.posix.join(sandboxHomeDir, '.agents', 'skills');\n return writeHarnessSkills({\n sandbox,\n rootDir,\n skills,\n abortSignal,\n invalidSkillNameMessage: ({ name }) => `Invalid Codex skill name: ${name}`,\n invalidSkillFilePathMessage: ({ skillName, filePath }) =>\n `Invalid Codex skill file path for ${skillName}: ${filePath}`,\n });\n}\n\nfunction openWebSocket({\n url,\n headers,\n}: HarnessV1PortEndpoint): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(url, {\n headers: headers == null ? undefined : { ...headers },\n });\n const onOpen = () => {\n ws.off('error', onError);\n resolve(ws);\n };\n const onError = (err: Error) => {\n ws.off('open', onOpen);\n reject(err);\n };\n ws.once('open', onOpen);\n ws.once('error', onError);\n });\n}\n\nfunction createSession({\n sessionId,\n channel,\n cliShimPath,\n proc,\n model,\n reasoningEffort,\n webSearch,\n codexConfig,\n mcpServers,\n resumeThreadId,\n isResume,\n seedResumeThreadOnFirstPrompt,\n rerunContinue,\n bridgePort,\n bridgeToken,\n sandboxId,\n sandboxCredentialEnvironment,\n debug,\n permissionMode,\n sandbox,\n sandboxHomeDir,\n turnConfigurationFingerprint,\n}: {\n sessionId: string;\n channel: CodexChannel;\n cliShimPath: string;\n /** Undefined on `attach` — the live bridge was spawned by another process. */\n proc: Experimental_SandboxProcess | undefined;\n model: string | undefined;\n reasoningEffort: 'low' | 'medium' | 'high' | 'xhigh' | 'max' | undefined;\n webSearch: boolean | undefined;\n codexConfig: Record<string, unknown> | undefined;\n mcpServers: Record<string, unknown> | undefined;\n resumeThreadId: string | undefined;\n isResume: boolean;\n seedResumeThreadOnFirstPrompt: boolean;\n rerunContinue: boolean;\n bridgePort: number;\n bridgeToken: string;\n sandboxId: string | undefined;\n sandboxCredentialEnvironment: Record<string, string> | undefined;\n debug: HarnessV1DebugConfig | undefined;\n permissionMode: HarnessV1PermissionMode | undefined;\n sandbox: SandboxSession;\n sandboxHomeDir: string;\n turnConfigurationFingerprint: string | undefined;\n}): HarnessV1Session {\n let stopped = false;\n let stopPromise: Promise<void> | undefined;\n /*\n * Send the persisted threadId on the first prompt only when the bridge was\n * respawned (rerun/replay) so it takes the `codex.resumeThread(...)` branch.\n * An `attach`ed bridge already holds its threadState in memory and continues\n * on its own, so it needs no seed.\n */\n let pendingResumeThreadId = seedResumeThreadOnFirstPrompt\n ? resumeThreadId\n : undefined;\n /*\n * Host-tool relay guidance is prepended to the first user message of a fresh\n * session only. A resumed session (attach/replay/rerun) already carried it in\n * its original first message (preserved in the persisted thread), so it\n * starts \"applied\".\n */\n let initialPromptGuidanceApplied = isResume;\n\n /*\n * Latest codex thread id, cached from the bridge's `bridge-thread`\n * announcements. Seeded from lifecycle state so `doDetach()` and `doStop()`\n * can include a thread id even before this process has run a turn.\n */\n let latestThreadId = resumeThreadId;\n let latestTurnConfigurationFingerprint = turnConfigurationFingerprint;\n channel.on('bridge-thread', msg => {\n latestThreadId = msg.threadId;\n });\n\n const synchronizeTurnConfiguration = async ({\n skills,\n instructions,\n tools,\n abortSignal,\n }: {\n skills: ReadonlyArray<HarnessV1Skill>;\n instructions: string | undefined;\n tools: ReadonlyArray<{\n name: string;\n description?: string;\n inputSchema: unknown;\n }>;\n abortSignal?: AbortSignal;\n }): Promise<{ restartThread: boolean }> => {\n const skillsResult = await writeCodexSkills({\n sandbox,\n sandboxHomeDir,\n skills,\n abortSignal,\n });\n const nextFingerprint = fingerprintCodexTurnConfiguration({\n instructions,\n tools,\n });\n const restartThread =\n latestThreadId != null &&\n (skillsResult.changed ||\n (latestTurnConfigurationFingerprint != null &&\n latestTurnConfigurationFingerprint !== nextFingerprint));\n latestTurnConfigurationFingerprint = nextFingerprint;\n if (restartThread) {\n /*\n * `codex exec resume` retains the native thread's original developer\n * instructions and skill catalog. A fresh native thread is therefore\n * required for replacement semantics. Host-tool guidance is framed\n * again because that guidance also belongs to the new native thread.\n */\n initialPromptGuidanceApplied = false;\n pendingResumeThreadId = undefined;\n }\n return { restartThread };\n };\n\n /*\n * Wire the channel into one turn's worth of events and return the control\n * surface. Shared by `doPromptTurn` (which sends a `start` afterwards) and\n * `doContinueTurn` (which attaches to an already-running/replayed turn, or sends\n * a rerun `start`). The only difference between the two entry points is the\n * `start` message, not the listener/abort/settle plumbing.\n */\n const wireTurn = (turnOpts: {\n emit: (event: HarnessV1StreamPart) => void;\n abortSignal?: AbortSignal;\n }): {\n control: HarnessV1PromptControl;\n sendStart: (send: () => void) => void;\n } => {\n let pendingResolve: (() => void) | undefined;\n let pendingReject: ((err: unknown) => void) | undefined;\n const done = new Promise<void>((resolve, reject) => {\n pendingResolve = resolve;\n pendingReject = reject;\n });\n\n const unsubs: Array<() => void> = [];\n const forward = (event: HarnessV1StreamPart) => {\n try {\n turnOpts.emit(event);\n } catch {}\n };\n\n const eventTypes = [\n 'stream-start',\n 'text-start',\n 'text-delta',\n 'text-end',\n 'reasoning-start',\n 'reasoning-delta',\n 'reasoning-end',\n 'tool-call',\n 'tool-approval-request',\n 'tool-result',\n 'file-change',\n 'finish-step',\n 'raw',\n ] as const;\n let isSettled = false;\n const settleSuccess = () => {\n if (isSettled) return;\n isSettled = true;\n for (const u of unsubs) u();\n pendingResolve!();\n };\n const settleError = (err: unknown) => {\n if (isSettled) return;\n isSettled = true;\n for (const u of unsubs) u();\n pendingReject!(err);\n };\n\n for (const type of eventTypes) {\n unsubs.push(\n channel.on(type, msg => {\n forward(msg);\n }),\n );\n }\n unsubs.push(\n channel.on('finish', msg => {\n forward(msg);\n settleSuccess();\n }),\n );\n unsubs.push(\n channel.on('error', msg => {\n forward(msg);\n settleError(msg.error);\n }),\n );\n\n /*\n * A `'suspended'` close is a graceful slice-boundary freeze the host\n * initiated (`doSuspendTurn`): the turn keeps running in the bridge and its\n * tail is replayed to the next process, so wind this turn down cleanly\n * rather than failing it. Any other close mid-turn is an unexpected drop.\n */\n const onClose = (_code?: number, reason?: string) => {\n if (isSettled) return;\n if (reason === 'suspended') {\n settleSuccess();\n return;\n }\n settleError(new Error('codex bridge closed before the turn finished.'));\n };\n channel.onClose(onClose);\n\n const onAbort = () => {\n if (isSettled) return;\n try {\n channel.send({ type: 'abort' });\n } catch {}\n settleError(\n turnOpts.abortSignal?.reason ??\n new DOMException('Aborted', 'AbortError'),\n );\n };\n if (turnOpts.abortSignal) {\n if (turnOpts.abortSignal.aborted) {\n onAbort();\n } else {\n turnOpts.abortSignal.addEventListener('abort', onAbort, {\n once: true,\n });\n }\n }\n\n const control: HarnessV1PromptControl = {\n submitToolResult: async input => {\n channel.send({\n type: 'tool-result',\n toolCallId: input.toolCallId,\n output: input.output,\n isError: input.isError,\n });\n },\n submitToolApproval: async input => {\n channel.send({\n type: 'tool-approval-response',\n approvalId: input.approvalId,\n approved: input.approved,\n reason: input.reason,\n });\n },\n done,\n };\n\n return {\n control,\n sendStart: send => {\n /*\n * Codex can complete short turns without using tools. Deferring the\n * start frame gives the harness runner one event-loop turn to finish\n * wiring the prompt control and stream output before Codex can settle.\n */\n const timer = setTimeout(() => {\n if (isSettled) return;\n try {\n send();\n } catch (err) {\n settleError(err);\n }\n }, 0);\n timer.unref?.();\n },\n };\n };\n\n return {\n sessionId,\n isResume,\n doPromptTurn: async promptOpts => {\n if (\n promptOpts.responseFormat?.type === 'json' &&\n promptOpts.responseFormat.schema == null\n ) {\n throw new HarnessCapabilityUnsupportedError({\n message:\n \"Harness 'codex' requires a JSON schema for structured output.\",\n harnessId: 'codex',\n });\n }\n const tools = (promptOpts.tools ?? []).map(t => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n }));\n const { restartThread } = await synchronizeTurnConfiguration({\n skills: promptOpts.skills,\n instructions: promptOpts.instructions,\n tools,\n abortSignal: promptOpts.abortSignal,\n });\n const turn = wireTurn({\n emit: promptOpts.emit,\n abortSignal: promptOpts.abortSignal,\n });\n\n let promptText = extractUserText(promptOpts.prompt);\n if (!initialPromptGuidanceApplied) {\n promptText = frameInitialPromptGuidance({\n toolUsageBlock:\n tools.length > 0\n ? composeToolUsageInstructions({\n tools,\n cliShimPath,\n })\n : undefined,\n userText: promptText,\n });\n }\n initialPromptGuidanceApplied = true;\n\n const startMessage = {\n type: 'start' as const,\n prompt: promptText,\n tools,\n ...(promptOpts.responseFormat == null\n ? {}\n : { responseFormat: promptOpts.responseFormat }),\n ...(promptOpts.instructions\n ? { instructions: promptOpts.instructions }\n : {}),\n model: promptOpts.model ?? model,\n reasoningEffort,\n webSearch,\n ...(codexConfig == null ? {} : { codexConfig }),\n ...(mcpServers == null ? {} : { mcpServers }),\n ...(permissionMode ? { permissionMode } : {}),\n ...(pendingResumeThreadId\n ? { resumeThreadId: pendingResumeThreadId }\n : {}),\n ...(restartThread ? { restartThread: true } : {}),\n ...(debug ? { debug } : {}),\n };\n pendingResumeThreadId = undefined;\n turn.sendStart(() => channel.send(startMessage));\n\n return turn.control;\n },\n doContinueTurn: async continueOpts => {\n if (\n continueOpts.responseFormat?.type === 'json' &&\n continueOpts.responseFormat.schema == null\n ) {\n throw new HarnessCapabilityUnsupportedError({\n message:\n \"Harness 'codex' requires a JSON schema for structured output.\",\n harnessId: 'codex',\n });\n }\n const tools = (continueOpts.tools ?? []).map(t => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n }));\n const { restartThread } = await synchronizeTurnConfiguration({\n skills: continueOpts.skills,\n instructions: continueOpts.instructions,\n tools,\n abortSignal: continueOpts.abortSignal,\n });\n const turn = wireTurn({\n emit: continueOpts.emit,\n abortSignal: continueOpts.abortSignal,\n });\n\n /*\n * attach / replay: the still-running (or disk-replayed) turn streams into\n * the wired listeners — `doStart` opened the channel with `{ resume: true }`\n * so the bridge replays everything past the persisted cursor (including a\n * `finish` if the turn ended during the gap). No `start` is sent: issuing\n * one would clear the bridge's replay log and begin a new turn. Lossless.\n *\n * rerun: the bridge was respawned with no in-flight turn to attach to, so\n * re-drive codex's own thread via `resumeThreadId`. Lossy — work in flight\n * at the suspension is recomputed. This is the rare bridge-died\n * fallback; the common slice path is `attach`.\n */\n if (rerunContinue) {\n const threadId = pendingResumeThreadId ?? latestThreadId;\n pendingResumeThreadId = undefined;\n turn.sendStart(() =>\n channel.send({\n type: 'start' as const,\n /*\n * A continuation nudge rather than an empty prompt: `resumeThreadId`\n * rehydrates the prior thread, and this is the new user turn that\n * drives it forward. Keeping it non-empty avoids handing the runtime\n * an empty user message (and mirrors the claude-code adapter, where an\n * empty text block trips the Anthropic API's `cache_control` rule).\n */\n prompt: 'Continue.',\n tools,\n ...(continueOpts.responseFormat == null\n ? {}\n : { responseFormat: continueOpts.responseFormat }),\n ...(continueOpts.instructions\n ? { instructions: continueOpts.instructions }\n : {}),\n model: continueOpts.model ?? model,\n reasoningEffort,\n webSearch,\n ...(codexConfig == null ? {} : { codexConfig }),\n ...(mcpServers == null ? {} : { mcpServers }),\n ...(permissionMode ? { permissionMode } : {}),\n ...(threadId ? { resumeThreadId: threadId } : {}),\n ...(restartThread ? { restartThread: true } : {}),\n ...(debug ? { debug } : {}),\n }),\n );\n }\n\n return turn.control;\n },\n doCompact: async () => {\n /*\n * Codex compacts its context automatically inside the core turn loop\n * (~90% of the model context window), but the `codex exec` transport this\n * adapter drives exposes no manual compaction trigger and emits no\n * compaction event. Manual `compact()` is therefore unsupported; Codex's\n * own auto-compaction continues to run regardless.\n */\n throw new HarnessCapabilityUnsupportedError({\n message:\n \"Harness 'codex' does not support manual compaction; Codex auto-compacts its context internally.\",\n harnessId: 'codex',\n });\n },\n doDetach: async () => {\n if (stopped) {\n throw new Error(\n `codex session ${sessionId} is already stopped; cannot detach.`,\n );\n }\n stopped = true;\n const lastSeenEventId = await channel.suspend();\n const payload: HarnessV1ResumeSessionState = {\n type: 'resume-session',\n harnessId: 'codex',\n specificationVersion: 'harness-v1',\n data: {\n ...(latestThreadId ? { threadId: latestThreadId } : {}),\n ...(latestTurnConfigurationFingerprint\n ? {\n turnConfigurationFingerprint:\n latestTurnConfigurationFingerprint,\n }\n : {}),\n ...(sandboxCredentialEnvironment == null\n ? {}\n : { sandboxCredentialEnvironment }),\n bridge: {\n port: bridgePort,\n token: bridgeToken,\n lastSeenEventId,\n ...(sandboxId == null ? {} : { sandboxId }),\n },\n },\n };\n return payload;\n },\n doDestroy: async () => {\n if (stopped) return stopPromise;\n stopped = true;\n stopPromise = (async () => {\n // Tell the channel we are tearing down so the bridge's post-shutdown\n // socket close finalises instead of triggering a reconnect.\n channel.beginClose();\n try {\n if (!channel.isClosed()) {\n channel.send({ type: 'destroy' });\n }\n } catch {}\n let stopTimer: ReturnType<typeof setTimeout> | undefined;\n try {\n if (proc) {\n await Promise.race([\n proc.wait(),\n new Promise<void>(resolve => {\n stopTimer = setTimeout(resolve, 5000);\n stopTimer.unref?.();\n }),\n ]);\n }\n } finally {\n if (stopTimer) clearTimeout(stopTimer);\n try {\n await proc?.kill();\n } catch {}\n channel.close();\n }\n })();\n return stopPromise;\n },\n doStop: async () => {\n if (stopped) {\n throw new Error(\n `codex session ${sessionId} is already stopped; cannot stop.`,\n );\n }\n stopped = true;\n /*\n * If the bridge's channel already closed (e.g. mid-turn WS drop)\n * there is no one to acknowledge a `stop` message. Synthesize an empty\n * payload — the workdir is still captured by the sandbox snapshot\n * during the subsequent `sandboxSession.stop()`, so the next turn can\n * resume the filesystem state. The trade-off: we lose\n * `threadId`, so the codex CLI starts a fresh thread on the\n * preserved workdir rather than resuming the prior conversation\n * inside Codex's runtime. Ability to continue beats throwing.\n */\n // Tell the channel we are tearing down so the bridge's post-stop\n // socket close finalises instead of triggering a reconnect.\n channel.beginClose();\n const data: unknown = channel.isClosed()\n ? {}\n : await new Promise<unknown>((resolve, reject) => {\n const timer = setTimeout(() => {\n unsub();\n reject(\n new Error(\n `codex session ${sessionId} did not reply to stop within 5s.`,\n ),\n );\n }, 5000);\n timer.unref?.();\n const unsub = channel.on('bridge-stop', msg => {\n clearTimeout(timer);\n unsub();\n resolve(msg.data);\n });\n try {\n channel.send({ type: 'stop' });\n } catch (err) {\n clearTimeout(timer);\n unsub();\n reject(err);\n }\n });\n\n let stopTimer: ReturnType<typeof setTimeout> | undefined;\n try {\n if (proc) {\n await Promise.race([\n proc.wait(),\n new Promise<void>(resolve => {\n stopTimer = setTimeout(resolve, 5000);\n stopTimer.unref?.();\n }),\n ]);\n }\n } finally {\n if (stopTimer) clearTimeout(stopTimer);\n try {\n await proc?.kill();\n } catch {}\n channel.close();\n }\n\n const lifecycleData =\n data != null && typeof data === 'object' && !Array.isArray(data)\n ? { ...(data as Record<string, unknown>) }\n : {};\n const payload: HarnessV1ResumeSessionState = {\n type: 'resume-session',\n harnessId: 'codex',\n specificationVersion: 'harness-v1',\n data: {\n ...lifecycleData,\n ...(latestTurnConfigurationFingerprint\n ? {\n turnConfigurationFingerprint:\n latestTurnConfigurationFingerprint,\n }\n : {}),\n ...(sandboxCredentialEnvironment == null\n ? {}\n : { sandboxCredentialEnvironment }),\n } as HarnessV1ResumeSessionState['data'],\n };\n return payload;\n },\n doSuspendTurn: async () => {\n if (stopped) {\n throw new Error(\n `codex session ${sessionId} is stopped; cannot suspend.`,\n );\n }\n stopped = true;\n /*\n * Freeze the host at a precise cursor without stopping the active model\n * turn. `channel.suspend` stops processing inbound frames, drains what\n * was already dispatched, then closes the host socket with reason\n * `'suspended'`. The bridge keeps the turn running and accumulates events\n * past the cursor for the next slice to replay. The sandbox process is\n * deliberately left alive.\n */\n const lastSeenEventId = await channel.suspend();\n const payload: HarnessV1ContinueTurnState = {\n type: 'continue-turn',\n harnessId: 'codex',\n specificationVersion: 'harness-v1',\n data: {\n ...(latestThreadId ? { threadId: latestThreadId } : {}),\n ...(latestTurnConfigurationFingerprint\n ? {\n turnConfigurationFingerprint:\n latestTurnConfigurationFingerprint,\n }\n : {}),\n ...(sandboxCredentialEnvironment == null\n ? {}\n : { sandboxCredentialEnvironment }),\n bridge: {\n port: bridgePort,\n token: bridgeToken,\n lastSeenEventId,\n ...(sandboxId == null ? {} : { sandboxId }),\n },\n },\n };\n return payload;\n },\n };\n}\n\nfunction fingerprintCodexTurnConfiguration({\n instructions,\n tools,\n}: {\n instructions: string | undefined;\n tools: ReadonlyArray<{\n name: string;\n description?: string;\n inputSchema: unknown;\n }>;\n}): string {\n return createHash('sha256')\n .update(JSON.stringify({ instructions: instructions ?? null, tools }))\n .digest('hex');\n}\n\n/*\n * Frame host-tool relay guidance and the user's text so Codex treats the\n * prepended block as operating guidance rather than user prose. Applied only\n * to the first user message of a fresh session.\n */\nfunction frameInitialPromptGuidance({\n toolUsageBlock,\n userText,\n}: {\n toolUsageBlock: string | undefined;\n userText: string;\n}): string {\n const blocks: string[] = [];\n if (toolUsageBlock) blocks.push(toolUsageBlock);\n if (blocks.length === 0) return userText;\n return `${blocks.join('\\n\\n')}\\n\\n<user-message>\\n${userText}\\n</user-message>`;\n}\n\nfunction composeToolUsageInstructions({\n tools,\n cliShimPath,\n}: {\n tools: ReadonlyArray<{\n name: string;\n description?: string;\n inputSchema?: unknown;\n }>;\n cliShimPath: string;\n}): string {\n const lines: string[] = [\n '<host-tool-instructions>',\n 'You have access to the following host-provided tools. To use one, run the following command via your built-in `bash` tool:',\n '',\n ` node ${cliShimPath} <toolName> '<jsonInput>'`,\n '',\n 'The script prints the JSON result to stdout. Do not invent another way to call these tools — only this CLI invocation will work. Pass the JSON input as a single-quoted argument.',\n 'For every user request that depends on a host-provided tool, run a separate CLI invocation for each needed tool call in the current turn before answering. Do not reuse previous tool results, and do not say you used a host tool unless the command has completed in the current turn.',\n '',\n ];\n for (const toolSpec of tools) {\n lines.push(\n `- **${toolSpec.name}**${toolSpec.description ? ': ' + toolSpec.description : ''}`,\n );\n lines.push(\n ` - Input schema: \\`${JSON.stringify(toolSpec.inputSchema ?? {})}\\``,\n );\n }\n lines.push('</host-tool-instructions>');\n return lines.join('\\n');\n}\n\n/*\n * Reduce a `HarnessV1Prompt` to the plain user text the bridge forwards\n * to the Codex SDK. File and image parts on the message are not yet\n * supported by the underlying runtime — throw rather than silently drop\n * them so callers learn about the gap instead of seeing mysteriously\n * truncated prompts.\n */\nfunction extractUserText(prompt: HarnessV1Prompt): string {\n if (typeof prompt === 'string') return prompt;\n const { content } = prompt;\n if (typeof content === 'string') return content;\n const parts: string[] = [];\n for (const part of content) {\n if (part.type !== 'text') {\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message: `The codex harness does not yet support user message parts of type '${part.type}'. Pass a string or a user message whose content contains only text parts.`,\n });\n }\n parts.push(part.text);\n }\n return parts.join('\\n\\n');\n}\n","import type { HarnessV1Bootstrap } from '@ai-sdk/harness';\nimport { createReadBridgeAsset } from '@ai-sdk/harness/utils';\n\nconst readBridgeAsset = createReadBridgeAsset({\n resolveAssetUrl: name => new URL(`./bridge/${name}`, import.meta.url),\n});\n\n/*\n * Bootstrap is derived state stored under the sandbox's default working\n * directory so snapshot-capable providers can preserve the installed CLI,\n * bridge, and recipe marker without requiring root filesystem access.\n *\n * The session work dir (`startOpts.sessionWorkDir`) lives under the sandbox's\n * default working directory — the provider's persistent mount — so any files\n * the agent edits survive both detach -> attach and stop -> snapshot -> resume\n * cycles. Harness infra derived from `sandboxSession.defaultWorkingDirectory`\n * lives under `.agent-runs`, outside the agent workdir.\n */\nexport const CODEX_BOOTSTRAP_DIR = '.harness-bootstrap/codex';\n\nlet cachedBootstrap: HarnessV1Bootstrap | undefined;\n\nexport async function getCodexBootstrap(): Promise<HarnessV1Bootstrap> {\n if (cachedBootstrap != null) return cachedBootstrap;\n const [pkg, lock, bridge] = await Promise.all([\n readBridgeAsset('package.json'),\n readBridgeAsset('pnpm-lock.yaml'),\n readBridgeAsset('index.mjs'),\n ]);\n cachedBootstrap = {\n harnessId: 'codex',\n bootstrapDir: CODEX_BOOTSTRAP_DIR,\n files: [\n { path: `${CODEX_BOOTSTRAP_DIR}/package.json`, content: pkg },\n { path: `${CODEX_BOOTSTRAP_DIR}/pnpm-lock.yaml`, content: lock },\n { path: `${CODEX_BOOTSTRAP_DIR}/bridge.mjs`, content: bridge },\n ],\n commands: [\n {\n command: 'pnpm install --frozen-lockfile --store-dir .pnpm-store',\n },\n ],\n };\n return cachedBootstrap;\n}\n","import type {\n HarnessV1Authentication,\n HarnessV1RequestTransformation,\n HarnessV1RequestTransformationSources,\n} from '@ai-sdk/harness';\nimport {\n createCredentialRequestTransformation,\n getAiGatewayAuthFromEnv,\n isHarnessAuthenticationEnvironment,\n} from '@ai-sdk/harness/utils';\n\nconst DEFAULT_AI_GATEWAY_BASE_URL = 'https://ai-gateway.vercel.sh/v1';\nexport const DEFAULT_OPENAI_BASE_URL = 'https://api.openai.com/v1';\n\nexport const CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES = [\n 'AI_GATEWAY_API_KEY',\n 'CODEX_API_KEY',\n] as const;\n\nexport function createCodexRequestTransformations({\n env: environment,\n sandboxEnv: sandboxEnvironment,\n auth: authenticationMode,\n}: HarnessV1RequestTransformationSources<CodexResolvedAuthenticationMode>): HarnessV1RequestTransformation[] {\n if (!environment.CODEX_API_KEY || !sandboxEnvironment.CODEX_API_KEY) {\n return [];\n }\n return [\n createCredentialRequestTransformation({\n matchUrl:\n environment.OPENAI_BASE_URL ??\n (authenticationMode === 'ai-gateway'\n ? DEFAULT_AI_GATEWAY_BASE_URL\n : DEFAULT_OPENAI_BASE_URL),\n matchHeaders: {\n Authorization: `Bearer ${sandboxEnvironment.CODEX_API_KEY}`,\n },\n transformHeaders: {\n Authorization: `Bearer ${environment.CODEX_API_KEY}`,\n },\n }),\n ];\n}\n\nexport type CodexResolvedAuthenticationMode = 'direct' | 'ai-gateway';\n\nexport type CodexAuthenticationMode = HarnessV1Authentication;\n\n/**\n * Resolve the environment-variable blob the codex bridge needs. Precedence:\n *\n * 1. An explicit authentication mode pins the selected route.\n * 2. Auto-detect from the host process env: gateway first\n * (`AI_GATEWAY_API_KEY` / `VERCEL_OIDC_TOKEN`), then `CODEX_API_KEY` /\n * `OPENAI_API_KEY`.\n */\nexport function resolveCodexEnv(\n auth: CodexAuthenticationMode | undefined,\n processEnv: Record<string, string | undefined> = process.env,\n): Record<string, string> {\n const suppliedEnvironment = isHarnessAuthenticationEnvironment(auth);\n const authenticationEnvironment = suppliedEnvironment ? auth : processEnv;\n if (auth === 'direct') {\n return pickOpenAI({ processEnv: authenticationEnvironment });\n }\n\n const gatewayAuthFromEnv = getAiGatewayAuthFromEnv({\n env: authenticationEnvironment,\n });\n if (auth === 'ai-gateway' || gatewayAuthFromEnv.apiKey) {\n return pickGateway({ gatewayAuthFromEnv });\n }\n return pickOpenAI({ processEnv: authenticationEnvironment });\n}\n\nexport function resolveCodexAuthenticationMode(\n auth: CodexAuthenticationMode | undefined,\n processEnv: Record<string, string | undefined> = process.env,\n): CodexResolvedAuthenticationMode {\n if (isHarnessAuthenticationEnvironment(auth)) {\n return getAiGatewayAuthFromEnv({ env: auth }).apiKey\n ? 'ai-gateway'\n : 'direct';\n }\n if (auth === 'direct') {\n return 'direct';\n }\n if (auth === 'ai-gateway') {\n return 'ai-gateway';\n }\n return getAiGatewayAuthFromEnv({ env: processEnv }).apiKey\n ? 'ai-gateway'\n : 'direct';\n}\n\nfunction pickOpenAI({\n processEnv,\n}: {\n processEnv: Record<string, string | undefined>;\n}): Record<string, string> {\n const env: Record<string, string> = {};\n const apiKey = processEnv.OPENAI_API_KEY ?? processEnv.CODEX_API_KEY;\n if (apiKey) env.CODEX_API_KEY = apiKey;\n const baseUrl = processEnv.OPENAI_BASE_URL;\n if (baseUrl) env.OPENAI_BASE_URL = baseUrl;\n const organization = processEnv.OPENAI_ORGANIZATION;\n if (organization) env.OPENAI_ORGANIZATION = organization;\n const project = processEnv.OPENAI_PROJECT;\n if (project) env.OPENAI_PROJECT = project;\n return env;\n}\n\nfunction pickGateway({\n gatewayAuthFromEnv,\n}: {\n gatewayAuthFromEnv: ReturnType<typeof getAiGatewayAuthFromEnv>;\n}): Record<string, string> {\n const apiKey = gatewayAuthFromEnv.apiKey;\n const baseUrl = toCodexGatewayBaseUrl(gatewayAuthFromEnv.baseUrl);\n const env: Record<string, string> = {};\n if (apiKey) {\n env.AI_GATEWAY_API_KEY = apiKey;\n env.CODEX_API_KEY = apiKey;\n }\n env.AI_GATEWAY_BASE_URL = baseUrl;\n env.OPENAI_BASE_URL = baseUrl;\n return env;\n}\n\nfunction toCodexGatewayBaseUrl(baseUrl: string): string {\n const trimmed = baseUrl.replace(/\\/+$/, '');\n return trimmed.endsWith('/v1') ? trimmed : `${trimmed}/v1`;\n}\n","import {\n harnessV1BridgeInboundCommandSchemas,\n harnessV1BridgeOutboundMessageSchema,\n harnessV1BridgeReadySchema,\n harnessV1BridgeStartBaseSchema,\n} from '@ai-sdk/harness';\nimport { z } from 'zod/v4';\n\n/*\n * Codex's bridge wire protocol. The outbound events (including `file-change`\n * and the `bridge-thread` resume coordinate), transport frames, shared inbound\n * commands, and `bridge-ready` line all come from the shared `@ai-sdk/harness`\n * protocol — the only Codex-specific piece is the `start` payload.\n */\n\nexport const outboundMessageSchema = harnessV1BridgeOutboundMessageSchema;\nexport type OutboundMessage = z.infer<typeof outboundMessageSchema>;\n\nexport const startMessageSchema = harnessV1BridgeStartBaseSchema.extend({\n instructions: z.string().optional(),\n reasoningEffort: z.enum(['low', 'medium', 'high', 'xhigh', 'max']).optional(),\n webSearch: z.boolean().optional(),\n codexConfig: z.record(z.string(), z.unknown()).optional(),\n mcpServers: z.record(z.string(), z.unknown()).optional(),\n // Resume signal. When supplied, the bridge calls\n // `codex.resumeThread(resumeThreadId, …)` instead of starting a fresh thread.\n // The host sources the id from lifecycle state `data` cached from a prior\n // `agent.detach`.\n resumeThreadId: z.string().optional(),\n restartThread: z.boolean().optional(),\n});\n\nexport type StartMessage = z.infer<typeof startMessageSchema>;\n\nexport const inboundMessageSchema = z.discriminatedUnion('type', [\n startMessageSchema,\n ...harnessV1BridgeInboundCommandSchemas,\n]);\nexport type InboundMessage = z.infer<typeof inboundMessageSchema>;\n\nexport const bridgeReadySchema = harnessV1BridgeReadySchema;\nexport type BridgeReady = z.infer<typeof bridgeReadySchema>;\n","/*\n * Temporary workaround for upstream codex CLI bug\n * https://github.com/openai/codex/issues/19425 — MCP tools registered via\n * `mcp_servers.*` are not exposed to the model in `codex exec --experimental-json`\n * mode (which is what `@openai/codex-sdk` uses). The MCP handshake completes\n * and `tools/list` succeeds, but codex never registers the tools as\n * model-callable functions.\n *\n * Until that's fixed upstream, this file implements a CLI-based relay:\n *\n * 1. A small Node script is written into harness-owned session state at turn\n * start (`buildCliShimScript`). It accepts `<toolName> <jsonInput>` as\n * argv, POSTs to the same HTTP relay the MCP shim uses, and prints the\n * result to stdout.\n *\n * 2. Tool descriptions and invocation instructions are injected into the\n * initial user prompt by the host adapter, telling the model to call host\n * tools by running `node <shim-path> <toolName> '<jsonInput>'` via its\n * built-in `bash` tool.\n *\n * 3. The bridge's event loop suppresses the matching `command_execution`\n * events (`isToolRelayCommand`) so callers receive clean `tool-call` /\n * `tool-result` events from the HTTP relay rather than seeing the\n * relay invocations as raw bash commands.\n *\n * Once #19425 is fixed and MCP tools are properly exposed in exec mode, the\n * three hookpoints in `bridge/index.ts` can be removed along with this file.\n */\nexport const CLI_SHIM_FILENAME = 'harness-tool.mjs';\n\nexport function buildCliShimScript({\n relayPort,\n}: {\n relayPort: number;\n}): string {\n return `#!/usr/bin/env node\nconst [toolName, inputJson = '{}'] = process.argv.slice(2);\nif (!toolName) {\n console.error('Usage: harness-tool <tool_name> <json_input>');\n process.exit(64);\n}\nlet input;\ntry {\n input = JSON.parse(inputJson);\n} catch (error) {\n console.error('Invalid JSON input: ' + (error instanceof Error ? error.message : String(error)));\n process.exit(64);\n}\nconst requestId = 'cli-' + Date.now() + '-' + Math.random().toString(16).slice(2);\nconst response = await fetch('http://127.0.0.1:${relayPort}', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ requestId, toolName, input }),\n});\nconst text = await response.text();\nlet payload;\ntry {\n payload = text ? JSON.parse(text) : {};\n} catch {\n payload = { error: text };\n}\nif (!response.ok || payload.error) {\n console.error(String(payload.error ?? ('tool relay failed with HTTP ' + response.status)));\n process.exit(1);\n}\nconsole.log(JSON.stringify(payload.result ?? payload, null, 2));\n`;\n}\n\nexport function isToolRelayCommand({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): boolean {\n return parseToolRelayCommands({ command, cliShimPath }) !== undefined;\n}\n\nexport function parseToolRelayCommand({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): { toolName: string; input: unknown } | undefined {\n const calls = parseToolRelayCommands({ command, cliShimPath });\n return calls?.length === 1 ? calls[0] : undefined;\n}\n\nexport function parseToolRelayCommands({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): Array<{ toolName: string; input: unknown }> | undefined {\n return parseToolRelayCommandsInternal({ command, cliShimPath, depth: 0 });\n}\n\nfunction parseToolRelayCommandsInternal({\n command,\n cliShimPath,\n depth,\n}: {\n command: string;\n cliShimPath: string;\n depth: number;\n}): Array<{ toolName: string; input: unknown }> | undefined {\n const commands = splitShellAndCommands(command);\n if (!commands) return undefined;\n if (commands.length > 1) {\n const relayCalls: Array<{ toolName: string; input: unknown }> = [];\n for (const nestedCommand of commands) {\n const nestedCalls = parseToolRelayCommandsInternal({\n command: nestedCommand,\n cliShimPath,\n depth,\n });\n if (!nestedCalls) return undefined;\n relayCalls.push(...nestedCalls);\n }\n return relayCalls;\n }\n\n const argv = parseShellWords(command);\n if (!argv) return undefined;\n\n const relayCall = parseDirectToolRelayArgv({ argv, cliShimPath });\n if (relayCall) return [relayCall];\n\n const innerCommand = extractShellEvalCommand(argv);\n if (!innerCommand || depth >= 2) return undefined;\n return parseToolRelayCommandsInternal({\n command: innerCommand,\n cliShimPath,\n depth: depth + 1,\n });\n}\n\nfunction parseDirectToolRelayArgv({\n argv,\n cliShimPath,\n}: {\n argv: string[];\n cliShimPath: string;\n}): { toolName: string; input: unknown } | undefined {\n if (argv.length < 3 || argv.length > 4) return undefined;\n if (argv[0] !== 'node' || argv[1] !== cliShimPath) return undefined;\n const toolName = argv[2];\n if (!toolName) return undefined;\n try {\n return { toolName, input: JSON.parse(argv[3] ?? '{}') };\n } catch {\n return undefined;\n }\n}\n\nfunction extractShellEvalCommand(argv: string[]): string | undefined {\n if (argv.length !== 3) return undefined;\n const shellName = argv[0].split('/').at(-1);\n if (shellName !== 'bash' && shellName !== 'sh' && shellName !== 'zsh') {\n return undefined;\n }\n if (argv[1] !== '-c' && argv[1] !== '-lc') return undefined;\n return argv[2];\n}\n\nfunction splitShellAndCommands(command: string): string[] | undefined {\n const commands: string[] = [];\n let start = 0;\n let quote: '\"' | \"'\" | undefined;\n\n for (let i = 0; i < command.length; i++) {\n const char = command[i];\n if (quote === \"'\") {\n if (char === \"'\") quote = undefined;\n continue;\n }\n if (quote === '\"') {\n if (char === '\"') {\n quote = undefined;\n } else if (char === '\\\\') {\n i++;\n }\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n continue;\n }\n if (char === '\\\\') {\n i++;\n continue;\n }\n if (char === '&' && command[i + 1] === '&') {\n const nestedCommand = command.slice(start, i).trim();\n if (!nestedCommand) return undefined;\n commands.push(nestedCommand);\n start = i + 2;\n i++;\n }\n }\n\n if (quote) return undefined;\n const nestedCommand = command.slice(start).trim();\n if (!nestedCommand) return undefined;\n commands.push(nestedCommand);\n return commands;\n}\n\nfunction parseShellWords(command: string): string[] | undefined {\n const words: string[] = [];\n let current = '';\n let quote: '\"' | \"'\" | undefined;\n let hasCurrent = false;\n\n const pushCurrent = () => {\n if (!hasCurrent) return;\n words.push(current);\n current = '';\n hasCurrent = false;\n };\n\n for (let i = 0; i < command.length; i++) {\n const char = command[i];\n if (quote === \"'\") {\n if (char === \"'\") {\n quote = undefined;\n } else {\n current += char;\n }\n hasCurrent = true;\n continue;\n }\n if (quote === '\"') {\n if (char === '\"') {\n quote = undefined;\n } else if (char === '\\\\' && i + 1 < command.length) {\n current += command[++i];\n } else {\n current += char;\n }\n hasCurrent = true;\n continue;\n }\n if (/\\s/.test(char)) {\n pushCurrent();\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n hasCurrent = true;\n continue;\n }\n if (char === '\\\\' && i + 1 < command.length) {\n current += command[++i];\n hasCurrent = true;\n continue;\n }\n if (/[;&|<>()`$]/.test(char)) return undefined;\n current += char;\n hasCurrent = true;\n }\n if (quote) return undefined;\n pushCurrent();\n return words;\n}\n","// Version string of this package injected at build time.\ndeclare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n","import { createCodex } from './codex-harness';\n\n/**\n * Default `codex` harness instance with no overrides — suitable for the\n * common case where the underlying `codex` CLI's defaults are fine.\n * Equivalent to `createCodex()`.\n */\nexport const codex = createCodex();\n\nexport { createCodex } from './codex-harness';\nexport { VERSION } from './version';\nexport type { CodexHarnessSettings } from './codex-harness';\nexport type { CodexAuthenticationMode } from './codex-auth';\n"],"mappings":"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","names":["z","z","endpoint","proc"]}
1
+ {"version":3,"sources":["../src/codex-harness.ts","../src/codex-bootstrap.ts","../src/codex-auth.ts","../src/codex-bridge-protocol.ts","../src/bridge/cli-relay.ts","../src/version.ts","../src/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport path from 'node:path';\nimport {\n commonTool,\n HarnessCapabilityUnsupportedError,\n harnessV1DiagnosticFromBridgeFrame,\n type HarnessV1,\n type HarnessV1DebugConfig,\n type HarnessV1BuiltinTool,\n type HarnessV1ContinueTurnState,\n type HarnessV1CredentialForwarding,\n type HarnessV1Prompt,\n type HarnessV1PromptControl,\n type HarnessV1PortEndpoint,\n type HarnessV1ResumeSessionState,\n type HarnessV1NetworkSandboxSession,\n type HarnessV1PermissionMode,\n type HarnessV1Session,\n type HarnessV1Skill,\n type HarnessV1StreamPart,\n} from '@ai-sdk/harness';\nimport {\n applyCredentialForwarding,\n classifyDiskLog,\n createBridgeToken,\n createSandboxCredentialEnvironment,\n createBridgeErrorHandler,\n createBridgeStartupError,\n drainBridgeProcessStream,\n forwardBridgeProcessStream,\n getRestrictedSandboxSession,\n markBridgeStarting,\n resolveSandboxDefaultWorkingDirectory,\n resolveSandboxHomeDir,\n SandboxChannel,\n shellQuote,\n warnCredentialBrokeringUnavailable,\n waitForBridgeReady,\n withBridgeToken,\n writeSkills as writeHarnessSkills,\n type WriteSkillsResult,\n} from '@ai-sdk/harness/utils';\nimport {\n type Experimental_SandboxProcess,\n type Experimental_SandboxSession as SandboxSession,\n} from '@ai-sdk/provider-utils';\nimport { WebSocket } from 'ws';\nimport { z } from 'zod/v4';\nimport {\n CODEX_BOOTSTRAP_DIR as BOOTSTRAP_DIR,\n getCodexBootstrap,\n} from './codex-bootstrap';\nimport {\n CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES,\n createCodexRequestTransformations,\n DEFAULT_OPENAI_BASE_URL,\n resolveCodexAuthenticationMode,\n resolveCodexEnv,\n type CodexAuthenticationMode,\n} from './codex-auth';\nimport {\n outboundMessageSchema,\n type InboundMessage,\n type OutboundMessage,\n} from './codex-bridge-protocol';\nimport { CLI_SHIM_FILENAME } from './bridge/cli-relay';\nimport { VERSION } from './version';\n\ntype CodexChannel = SandboxChannel<OutboundMessage, InboundMessage>;\ntype CodexRespawnStrategy = 'replay' | 'rerun';\n\n/*\n * This intentionally is not the latest Codex model. Newer GPT-5.6 models use\n * Responses Lite, which does not expose their code-mode tools as callable\n * through the custom model provider used by the harness. Keep GPT-5.5 as the\n * default until the upstream bug is resolved:\n * https://github.com/openai/codex/issues/31894\n *\n * Passing the model explicitly keeps the runtime behavior deterministic and\n * the telemetry (`gen_ai.request.model`) accurate.\n */\nconst DEFAULT_CODEX_MODEL = 'gpt-5.5';\n\n/**\n * Value to use in User-Agent and `x-client-app` headers.\n */\nconst CODEX_CLIENT_APP = `ai-sdk/harness-codex/${VERSION}`;\n\nexport type CodexHarnessSettings = {\n readonly auth?: CodexAuthenticationMode;\n /**\n * Customizes each credential value before it is forwarded into a sandbox\n * process. This does not restrict which credentials the harness adapter can\n * discover, read, or otherwise access in the host process.\n */\n readonly credentialForwarding?: HarnessV1CredentialForwarding;\n /**\n * Additional configuration passed through to Codex as-is. Codex config keys\n * typically use snake_case and must be provided in that form. Values managed\n * by this adapter take precedence over conflicting entries.\n */\n readonly codexConfig?: Record<string, unknown>;\n /**\n * MCP server definitions keyed by server name. Each definition uses the\n * underlying runtime's native MCP server configuration format.\n */\n readonly mcpServers?: Record<string, unknown>;\n /**\n * OpenAI model id the underlying `codex` CLI should use. Leaving this unset\n * pins the adapter default (`DEFAULT_CODEX_MODEL`).\n *\n * @deprecated Use `model` on `HarnessAgent` instead.\n */\n readonly model?: string;\n /**\n * Reasoning effort for reasoning-capable models. Leaving this unset\n * defers to the CLI's default.\n */\n readonly reasoningEffort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n /**\n * When `true`, allow the underlying runtime to use live web search.\n */\n readonly webSearch?: boolean;\n /**\n * Override the port the bridge binds inside the sandbox. By default the\n * adapter uses the first port the sandbox declares via `sandbox.ports`.\n * Only set this if the sandbox declares multiple ports and the first one\n * is reserved for something else.\n */\n readonly port?: number;\n /**\n * Override the host endpoint used to connect to the sandbox bridge. Required\n * together with `port` when using a basic sandbox session.\n */\n readonly portEndpoint?: HarnessV1PortEndpoint;\n /** Maximum milliseconds to wait for the bridge to advertise its port. Defaults to 120000. */\n readonly startupTimeoutMs?: number;\n /**\n * Creates the authentication token used by the sandbox bridge. Defaults to\n * a random 32-byte hexadecimal token.\n */\n readonly mintBridgeToken?: (sandboxId: string) => string;\n};\n\n/*\n * Every native tool the Codex CLI can invoke as a model-callable tool,\n * declared as a `ToolSet` keyed by what the bridge emits as `toolName` on\n * the wire (`commonName ?? nativeName`). Schemas reflect the `ThreadItem`\n * union in `@openai/codex-sdk`'s `dist/index.d.ts`.\n *\n * Codex's other native operations (`apply_patch`, todo planning) surface\n * only as side-effect events (`file_change`, `todo_list`) and are not\n * model-callable tools — they don't appear here.\n */\nconst CODEX_BUILTIN_TOOLS = {\n bash: commonTool('bash', {\n nativeName: 'shell',\n toolUseKind: 'bash',\n description: 'Execute a shell command',\n inputSchema: z.object({ command: z.string() }),\n }),\n webSearch: commonTool('webSearch', {\n nativeName: 'web_search',\n toolUseKind: 'readonly',\n description: 'Search the web',\n inputSchema: z.object({ query: z.string() }),\n }),\n} as const satisfies Record<string, HarnessV1BuiltinTool<any, any>>;\n\n/**\n * Live bridge coordinates returned by `doDetach()` and `doSuspendTurn()`. A\n * future process uses them to reopen a socket to the still-running bridge\n * (`attach`) instead of re-spawning it. Absent on a `doStop()` payload.\n */\nconst codexBridgeCoordsSchema = z.object({\n port: z.number(),\n token: z.string(),\n lastSeenEventId: z.number(),\n sandboxId: z.string().optional(),\n});\n\n/**\n * Schema for the adapter-specific lifecycle `data` payload Codex produces.\n * `threadId` is what `codex.resumeThread(...)` requires for the replay/rerun\n * rungs; the sandbox lookup is handled separately via\n * `provider.resumeSession({ sessionId })`. `bridge` carries live coordinates\n * for cross-process `attach` (present on `doDetach()` and `doSuspendTurn()`\n * payloads).\n */\nconst codexResumeStateSchema = z.object({\n threadId: z.string().optional(),\n turnConfigurationFingerprint: z.string().optional(),\n bridge: codexBridgeCoordsSchema.optional(),\n sandboxCredentialEnvironment: z.record(z.string(), z.string()).optional(),\n});\n\ntype CodexBridgeCoords = z.infer<typeof codexBridgeCoordsSchema>;\n\nexport function createCodex(\n settings: CodexHarnessSettings = {},\n): HarnessV1<typeof CODEX_BUILTIN_TOOLS> {\n return {\n specificationVersion: 'harness-v1',\n harnessId: 'codex',\n builtinTools: CODEX_BUILTIN_TOOLS,\n supportsBuiltinToolApprovals: false,\n lifecycleStateSchema: codexResumeStateSchema,\n getBootstrap: getCodexBootstrap,\n doStart: async startOpts => {\n const model = settings.model ?? DEFAULT_CODEX_MODEL;\n if (startOpts.builtinToolFiltering != null) {\n throw new HarnessCapabilityUnsupportedError({\n message:\n \"Harness 'codex' does not support built-in tool filtering controls.\",\n harnessId: 'codex',\n });\n }\n if (\n startOpts.permissionMode != null &&\n startOpts.permissionMode !== 'allow-all'\n ) {\n throw new HarnessCapabilityUnsupportedError({\n message:\n \"Harness 'codex' does not support built-in tool approval requests; use permissionMode: 'allow-all'.\",\n harnessId: 'codex',\n });\n }\n const sandboxSession = startOpts.sandboxSession;\n const toolSafeSandboxSession =\n getRestrictedSandboxSession(sandboxSession);\n const sandboxId = 'id' in sandboxSession ? sandboxSession.id : undefined;\n validateBasicSandboxSettings({\n sandboxSession,\n port: settings.port,\n portEndpoint: settings.portEndpoint,\n });\n if (settings.mintBridgeToken != null && sandboxId == null) {\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message:\n 'The codex harness cannot use `mintBridgeToken` with a sandbox session that does not expose an id.',\n });\n }\n const defaultWorkingDirectory =\n await resolveSandboxDefaultWorkingDirectory({\n sandboxSession,\n abortSignal: startOpts.abortSignal,\n });\n const lifecycleState = startOpts.continueFrom ?? startOpts.resumeFrom;\n const isResume = lifecycleState != null;\n const isContinue = startOpts.continueFrom != null;\n const resumeData =\n isResume && typeof lifecycleState?.data === 'object'\n ? (lifecycleState.data as {\n threadId?: unknown;\n turnConfigurationFingerprint?: unknown;\n bridge?: CodexBridgeCoords;\n sandboxCredentialEnvironment?: Record<string, string>;\n })\n : undefined;\n const resumeThreadId = resumeData?.threadId;\n const resumeThreadIdString =\n typeof resumeThreadId === 'string' && resumeThreadId.length > 0\n ? resumeThreadId\n : undefined;\n const turnConfigurationFingerprint =\n typeof resumeData?.turnConfigurationFingerprint === 'string'\n ? resumeData.turnConfigurationFingerprint\n : undefined;\n const coords = resumeData?.bridge;\n const authenticationMode = resolveCodexAuthenticationMode(settings.auth);\n const resolvedAuthEnvironment = resolveCodexEnv(settings.auth);\n let sandboxAuthEnvironment = resolvedAuthEnvironment;\n let sandboxCredentialEnvironment: Record<string, string> | undefined;\n let credentialsBrokered = false;\n if (\n 'addRequestTransformations' in sandboxSession &&\n sandboxSession.addRequestTransformations != null\n ) {\n sandboxCredentialEnvironment =\n resumeData?.sandboxCredentialEnvironment ??\n (await createSandboxCredentialEnvironment({\n environment: resolvedAuthEnvironment,\n credentialEnvironmentVariables:\n CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES,\n credentialForwarding: settings.credentialForwarding,\n }));\n sandboxAuthEnvironment = {\n ...resolvedAuthEnvironment,\n ...sandboxCredentialEnvironment,\n };\n const requestTransformations = createCodexRequestTransformations({\n env: resolvedAuthEnvironment,\n sandboxEnv: sandboxAuthEnvironment,\n auth: authenticationMode,\n });\n if (requestTransformations.length > 0) {\n await sandboxSession.addRequestTransformations(\n requestTransformations,\n );\n }\n credentialsBrokered = true;\n if (\n requestTransformations.length > 0 &&\n authenticationMode === 'direct' &&\n resolvedAuthEnvironment.OPENAI_BASE_URL == null\n ) {\n /*\n * Vercel Sandbox request transformations apply only to HTTP traffic.\n * Materializing Codex's standard OpenAI URL makes the bridge select\n * its custom provider, where WebSockets are disabled, while keeping\n * the non-brokered path on Codex's built-in OpenAI provider.\n */\n sandboxAuthEnvironment.OPENAI_BASE_URL = DEFAULT_OPENAI_BASE_URL;\n }\n }\n const bootstrapDir = path.posix.resolve(\n defaultWorkingDirectory,\n BOOTSTRAP_DIR,\n );\n\n const workDir = startOpts.sessionWorkDir;\n const sandboxHomeDir = await resolveSandboxHomeDir({\n sandbox: toolSafeSandboxSession,\n abortSignal: startOpts.abortSignal,\n });\n const sessionDataDir = `${defaultWorkingDirectory}/.agent-runs/${startOpts.sessionId}`;\n const bridgeStateDir = `${sessionDataDir}/bridge`;\n const cliShimDir = `${sessionDataDir}/codex`;\n const cliShimPath = `${cliShimDir}/${CLI_SHIM_FILENAME}`;\n const timeoutMs = settings.startupTimeoutMs ?? 120_000;\n\n // Normalize each forwarded bridge diagnostics frame into the general\n // `HarnessV1Diagnostic` and report it. The adapter does no telemetry work\n // beyond this transport→emission mapping.\n const report = startOpts.observability?.report;\n const onDiagnostic = report\n ? (frame: Parameters<typeof harnessV1DiagnosticFromBridgeFrame>[0]) =>\n report(\n harnessV1DiagnosticFromBridgeFrame(frame, {\n sessionId: startOpts.sessionId,\n timestamp: Date.now(),\n }),\n )\n : undefined;\n const onBridgeError = createBridgeErrorHandler({\n harnessId: 'codex',\n sessionId: startOpts.sessionId,\n });\n\n /*\n * Rung 1 — ATTACH. With live coordinates, reopen a socket to the\n * still-running bridge. Parked between-turn sessions just attach and wait\n * for the next `start`; suspended in-flight turns request replay of\n * everything past the persisted cursor. No spawn, no fresh token. If the\n * bridge is gone the open throws and we fall through to a spawn-based\n * recovery.\n */\n if (coords) {\n try {\n const endpoint = await resolveBridgeEndpoint({\n sandboxSession,\n override: settings.portEndpoint,\n port: coords.port,\n });\n const attachEndpoint = withBridgeToken({\n endpoint,\n token: coords.token,\n });\n const attachChannel: CodexChannel = new SandboxChannel({\n connect: () => openWebSocket(attachEndpoint),\n outboundSchema: outboundMessageSchema,\n initialLastSeenEventId: coords.lastSeenEventId,\n onDiagnostic,\n onBridgeError,\n });\n await attachChannel.open(isContinue ? { resume: true } : undefined);\n return createSession({\n sessionId: startOpts.sessionId,\n channel: attachChannel,\n cliShimPath,\n // The live bridge was spawned by another process; no process handle.\n proc: undefined,\n model,\n reasoningEffort: settings.reasoningEffort,\n webSearch: settings.webSearch,\n codexConfig: settings.codexConfig,\n mcpServers: settings.mcpServers,\n resumeThreadId: resumeThreadIdString,\n isResume: true,\n seedResumeThreadOnFirstPrompt: false,\n rerunContinue: false,\n bridgePort: coords.port,\n bridgeToken: coords.token,\n sandboxId,\n sandboxCredentialEnvironment,\n debug: startOpts.observability?.debug,\n permissionMode: startOpts.permissionMode,\n sandbox: toolSafeSandboxSession,\n sandboxHomeDir,\n turnConfigurationFingerprint,\n });\n } catch {\n // Bridge no longer reachable — recover by respawning below.\n }\n }\n\n /*\n * Rungs 2/3 — REPLAY vs RERUN. Respawn the bridge. `replay` is only sound\n * for `continueFrom`: those coordinates include the cursor the on-disk\n * log is replayed *from*. `resumeFrom` is a between-turn resume; even when\n * it carries bridge coordinates, replaying the previous turn would\n * re-deliver stale events into the next turn. Those resumes always `rerun`\n * via `codex.resumeThread(threadId)` when attach is unavailable.\n */\n let respawnStrategy: CodexRespawnStrategy | undefined = isResume\n ? 'rerun'\n : undefined;\n if (coords && isContinue) {\n const logRaw = await Promise.resolve(\n toolSafeSandboxSession.readTextFile({\n path: `${bridgeStateDir}/event-log.ndjson`,\n abortSignal: startOpts.abortSignal,\n }),\n ).catch(() => null);\n if ((await classifyDiskLog(logRaw)) === 'replay') {\n respawnStrategy = 'replay';\n }\n }\n\n const port = resolveBridgePort({\n sandboxSession,\n override: settings.port,\n });\n const token =\n settings.mintBridgeToken == null\n ? createBridgeToken()\n : settings.mintBridgeToken(sandboxId!);\n const forwardedAuthEnvironment = credentialsBrokered\n ? sandboxAuthEnvironment\n : await applyCredentialForwarding({\n environment: sandboxAuthEnvironment,\n credentialEnvironmentVariables:\n CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES,\n credentialForwarding: settings.credentialForwarding,\n });\n if (!credentialsBrokered) {\n warnCredentialBrokeringUnavailable({\n environment: resolvedAuthEnvironment,\n forwardedEnvironment: forwardedAuthEnvironment,\n credentialEnvironmentVariables:\n CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES,\n });\n }\n const env = {\n ...forwardedAuthEnvironment,\n AI_SDK_HARNESS_CLIENT_APP: CODEX_CLIENT_APP,\n BRIDGE_CHANNEL_TOKEN: token,\n BRIDGE_WS_PORT: String(port),\n ...(respawnStrategy === 'replay'\n ? { BRIDGE_REPLAY_FROM_DISK: '1' }\n : {}),\n };\n\n if (respawnStrategy === undefined) {\n await toolSafeSandboxSession.run({\n command: `mkdir -p ${shellQuote(workDir)} ${shellQuote(bridgeStateDir)}`,\n abortSignal: startOpts.abortSignal,\n });\n }\n\n await markBridgeStarting({\n sandbox: toolSafeSandboxSession,\n bridgeStateDir,\n bridgeType: 'codex',\n abortSignal: startOpts.abortSignal,\n });\n\n const proc = await toolSafeSandboxSession.spawn({\n command: `node ${shellQuote(`${bootstrapDir}/bridge.mjs`)} --workdir ${shellQuote(workDir)} --bridge-state-dir ${shellQuote(bridgeStateDir)} --cli-shim-dir ${shellQuote(cliShimDir)}`,\n env,\n abortSignal: startOpts.abortSignal,\n });\n const stderrTail: string[] = [];\n const bridgeStderrDone = forwardBridgeProcessStream({\n stream: proc.stderr,\n streamName: 'stderr',\n source: 'codex',\n collectTail: stderrTail,\n });\n\n const { port: boundPort } = await waitForBridgeReady({\n proc,\n sandbox: toolSafeSandboxSession,\n bridgeStateDir,\n bridgeType: 'codex',\n timeoutMs,\n abortSignal: startOpts.abortSignal,\n createTimeoutError: ({ proc, stdoutTail }) =>\n createBridgeStartupError({\n message: 'codex bridge did not become ready in time.',\n proc,\n stdoutTail,\n stderrTail,\n stderrDone: bridgeStderrDone,\n }),\n createExitError: ({ proc, stdoutTail }) =>\n createBridgeStartupError({\n message: 'codex bridge exited before becoming ready.',\n proc,\n stdoutTail,\n stderrTail,\n stderrDone: bridgeStderrDone,\n }),\n });\n void drainBridgeProcessStream(proc.stdout);\n\n const endpoint = await resolveBridgeEndpoint({\n sandboxSession,\n override: settings.portEndpoint,\n port: boundPort,\n });\n const bridgeEndpoint = withBridgeToken({ endpoint, token });\n\n const channel: CodexChannel = new SandboxChannel({\n connect: () => openWebSocket(bridgeEndpoint),\n outboundSchema: outboundMessageSchema,\n onDiagnostic,\n onBridgeError,\n // In replay mode the respawned bridge reloaded the finished turn from\n // disk; seed the cursor and resume so it streams the tail (incl.\n // `finish`).\n ...(respawnStrategy === 'replay'\n ? { initialLastSeenEventId: coords?.lastSeenEventId ?? 0 }\n : {}),\n });\n await channel.open(\n respawnStrategy === 'replay' ? { resume: true } : undefined,\n );\n\n return createSession({\n sessionId: startOpts.sessionId,\n channel,\n cliShimPath,\n proc,\n model,\n reasoningEffort: settings.reasoningEffort,\n webSearch: settings.webSearch,\n codexConfig: settings.codexConfig,\n mcpServers: settings.mcpServers,\n resumeThreadId: resumeThreadIdString,\n isResume: respawnStrategy !== undefined,\n seedResumeThreadOnFirstPrompt: respawnStrategy !== undefined,\n rerunContinue: respawnStrategy === 'rerun',\n bridgePort: boundPort,\n bridgeToken: token,\n sandboxId,\n sandboxCredentialEnvironment,\n debug: startOpts.observability?.debug,\n permissionMode: startOpts.permissionMode,\n sandbox: toolSafeSandboxSession,\n sandboxHomeDir,\n turnConfigurationFingerprint,\n });\n },\n };\n}\n\nfunction resolveBridgePort({\n sandboxSession,\n override,\n}: {\n sandboxSession: HarnessV1NetworkSandboxSession | SandboxSession;\n override: number | undefined;\n}): number {\n if (override !== undefined) return override;\n if ('ports' in sandboxSession && sandboxSession.ports.length > 0) {\n return sandboxSession.ports[0];\n }\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message:\n 'The codex harness needs a TCP port exposed by the sandbox. ' +\n 'Create the sandbox with `ports: [<port>]` or pass `createCodex({ port })`.',\n });\n}\n\nfunction validateBasicSandboxSettings({\n sandboxSession,\n port,\n portEndpoint,\n}: {\n sandboxSession: HarnessV1NetworkSandboxSession | SandboxSession;\n port: number | undefined;\n portEndpoint: HarnessV1PortEndpoint | undefined;\n}): void {\n if ('getPortEndpoint' in sandboxSession) return;\n if (port == null) {\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message:\n 'The codex harness requires an explicit `port` when using a basic sandbox session.',\n });\n }\n if (portEndpoint == null) {\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message:\n 'The codex harness requires an explicit `portEndpoint` when using a basic sandbox session.',\n });\n }\n}\n\nasync function resolveBridgeEndpoint({\n sandboxSession,\n override,\n port,\n}: {\n sandboxSession: HarnessV1NetworkSandboxSession | SandboxSession;\n override: HarnessV1PortEndpoint | undefined;\n port: number;\n}): Promise<HarnessV1PortEndpoint> {\n if (override != null) return override;\n if ('getPortEndpoint' in sandboxSession) {\n return sandboxSession.getPortEndpoint({ port, protocol: 'ws' });\n }\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message:\n 'The codex harness requires an explicit `portEndpoint` when using a basic sandbox session.',\n });\n}\n\nasync function writeCodexSkills({\n sandbox,\n sandboxHomeDir,\n skills,\n abortSignal,\n}: {\n sandbox: SandboxSession;\n sandboxHomeDir: string;\n skills: ReadonlyArray<HarnessV1Skill>;\n abortSignal?: AbortSignal;\n}): Promise<WriteSkillsResult> {\n const rootDir = path.posix.join(sandboxHomeDir, '.agents', 'skills');\n return writeHarnessSkills({\n sandbox,\n rootDir,\n skills,\n abortSignal,\n invalidSkillNameMessage: ({ name }) => `Invalid Codex skill name: ${name}`,\n invalidSkillFilePathMessage: ({ skillName, filePath }) =>\n `Invalid Codex skill file path for ${skillName}: ${filePath}`,\n });\n}\n\nfunction openWebSocket({\n url,\n headers,\n}: HarnessV1PortEndpoint): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(url, {\n headers: headers == null ? undefined : { ...headers },\n });\n const onOpen = () => {\n ws.off('error', onError);\n resolve(ws);\n };\n const onError = (err: Error) => {\n ws.off('open', onOpen);\n reject(err);\n };\n ws.once('open', onOpen);\n ws.once('error', onError);\n });\n}\n\nfunction createSession({\n sessionId,\n channel,\n cliShimPath,\n proc,\n model,\n reasoningEffort,\n webSearch,\n codexConfig,\n mcpServers,\n resumeThreadId,\n isResume,\n seedResumeThreadOnFirstPrompt,\n rerunContinue,\n bridgePort,\n bridgeToken,\n sandboxId,\n sandboxCredentialEnvironment,\n debug,\n permissionMode,\n sandbox,\n sandboxHomeDir,\n turnConfigurationFingerprint,\n}: {\n sessionId: string;\n channel: CodexChannel;\n cliShimPath: string;\n /** Undefined on `attach` — the live bridge was spawned by another process. */\n proc: Experimental_SandboxProcess | undefined;\n model: string | undefined;\n reasoningEffort: 'low' | 'medium' | 'high' | 'xhigh' | 'max' | undefined;\n webSearch: boolean | undefined;\n codexConfig: Record<string, unknown> | undefined;\n mcpServers: Record<string, unknown> | undefined;\n resumeThreadId: string | undefined;\n isResume: boolean;\n seedResumeThreadOnFirstPrompt: boolean;\n rerunContinue: boolean;\n bridgePort: number;\n bridgeToken: string;\n sandboxId: string | undefined;\n sandboxCredentialEnvironment: Record<string, string> | undefined;\n debug: HarnessV1DebugConfig | undefined;\n permissionMode: HarnessV1PermissionMode | undefined;\n sandbox: SandboxSession;\n sandboxHomeDir: string;\n turnConfigurationFingerprint: string | undefined;\n}): HarnessV1Session {\n let stopped = false;\n let stopPromise: Promise<void> | undefined;\n /*\n * Send the persisted threadId on the first prompt only when the bridge was\n * respawned (rerun/replay) so it takes the `codex.resumeThread(...)` branch.\n * An `attach`ed bridge already holds its threadState in memory and continues\n * on its own, so it needs no seed.\n */\n let pendingResumeThreadId = seedResumeThreadOnFirstPrompt\n ? resumeThreadId\n : undefined;\n /*\n * Host-tool relay guidance is prepended to the first user message of a fresh\n * session only. A resumed session (attach/replay/rerun) already carried it in\n * its original first message (preserved in the persisted thread), so it\n * starts \"applied\".\n */\n let initialPromptGuidanceApplied = isResume;\n\n /*\n * Latest codex thread id, cached from the bridge's `bridge-thread`\n * announcements. Seeded from lifecycle state so `doDetach()` and `doStop()`\n * can include a thread id even before this process has run a turn.\n */\n let latestThreadId = resumeThreadId;\n let latestTurnConfigurationFingerprint = turnConfigurationFingerprint;\n channel.on('bridge-thread', msg => {\n latestThreadId = msg.threadId;\n });\n\n const synchronizeTurnConfiguration = async ({\n skills,\n instructions,\n tools,\n abortSignal,\n }: {\n skills: ReadonlyArray<HarnessV1Skill>;\n instructions: string | undefined;\n tools: ReadonlyArray<{\n name: string;\n description?: string;\n inputSchema: unknown;\n }>;\n abortSignal?: AbortSignal;\n }): Promise<{ restartThread: boolean }> => {\n const skillsResult = await writeCodexSkills({\n sandbox,\n sandboxHomeDir,\n skills,\n abortSignal,\n });\n const nextFingerprint = fingerprintCodexTurnConfiguration({\n instructions,\n tools,\n });\n const restartThread =\n latestThreadId != null &&\n (skillsResult.changed ||\n (latestTurnConfigurationFingerprint != null &&\n latestTurnConfigurationFingerprint !== nextFingerprint));\n latestTurnConfigurationFingerprint = nextFingerprint;\n if (restartThread) {\n /*\n * `codex exec resume` retains the native thread's original developer\n * instructions and skill catalog. A fresh native thread is therefore\n * required for replacement semantics. Host-tool guidance is framed\n * again because that guidance also belongs to the new native thread.\n */\n initialPromptGuidanceApplied = false;\n pendingResumeThreadId = undefined;\n }\n return { restartThread };\n };\n\n /*\n * Wire the channel into one turn's worth of events and return the control\n * surface. Shared by `doPromptTurn` (which sends a `start` afterwards) and\n * `doContinueTurn` (which attaches to an already-running/replayed turn, or sends\n * a rerun `start`). The only difference between the two entry points is the\n * `start` message, not the listener/abort/settle plumbing.\n */\n const wireTurn = (turnOpts: {\n emit: (event: HarnessV1StreamPart) => void;\n abortSignal?: AbortSignal;\n }): {\n control: HarnessV1PromptControl;\n sendStart: (send: () => void) => void;\n } => {\n let pendingResolve: (() => void) | undefined;\n let pendingReject: ((err: unknown) => void) | undefined;\n const done = new Promise<void>((resolve, reject) => {\n pendingResolve = resolve;\n pendingReject = reject;\n });\n\n const unsubs: Array<() => void> = [];\n const forward = (event: HarnessV1StreamPart) => {\n try {\n turnOpts.emit(event);\n } catch {}\n };\n\n const eventTypes = [\n 'stream-start',\n 'text-start',\n 'text-delta',\n 'text-end',\n 'reasoning-start',\n 'reasoning-delta',\n 'reasoning-end',\n 'tool-call',\n 'tool-approval-request',\n 'tool-result',\n 'file-change',\n 'finish-step',\n 'raw',\n ] as const;\n let isSettled = false;\n const settleSuccess = () => {\n if (isSettled) return;\n isSettled = true;\n for (const u of unsubs) u();\n pendingResolve!();\n };\n const settleError = (err: unknown) => {\n if (isSettled) return;\n isSettled = true;\n for (const u of unsubs) u();\n pendingReject!(err);\n };\n\n for (const type of eventTypes) {\n unsubs.push(\n channel.on(type, msg => {\n forward(msg);\n }),\n );\n }\n unsubs.push(\n channel.on('finish', msg => {\n forward(msg);\n settleSuccess();\n }),\n );\n unsubs.push(\n channel.on('error', msg => {\n forward(msg);\n settleError(msg.error);\n }),\n );\n\n /*\n * A `'suspended'` close is a graceful slice-boundary freeze the host\n * initiated (`doSuspendTurn`): the turn keeps running in the bridge and its\n * tail is replayed to the next process, so wind this turn down cleanly\n * rather than failing it. Any other close mid-turn is an unexpected drop.\n */\n const onClose = (_code?: number, reason?: string) => {\n if (isSettled) return;\n if (reason === 'suspended') {\n settleSuccess();\n return;\n }\n settleError(new Error('codex bridge closed before the turn finished.'));\n };\n channel.onClose(onClose);\n\n const onAbort = () => {\n if (isSettled) return;\n try {\n channel.send({ type: 'abort' });\n } catch {}\n settleError(\n turnOpts.abortSignal?.reason ??\n new DOMException('Aborted', 'AbortError'),\n );\n };\n if (turnOpts.abortSignal) {\n if (turnOpts.abortSignal.aborted) {\n onAbort();\n } else {\n turnOpts.abortSignal.addEventListener('abort', onAbort, {\n once: true,\n });\n }\n }\n\n const control: HarnessV1PromptControl = {\n submitToolResult: async input => {\n channel.send({\n type: 'tool-result',\n toolCallId: input.toolCallId,\n output: input.output,\n isError: input.isError,\n });\n },\n submitToolApproval: async input => {\n channel.send({\n type: 'tool-approval-response',\n approvalId: input.approvalId,\n approved: input.approved,\n reason: input.reason,\n });\n },\n done,\n };\n\n return {\n control,\n sendStart: send => {\n /*\n * Codex can complete short turns without using tools. Deferring the\n * start frame gives the harness runner one event-loop turn to finish\n * wiring the prompt control and stream output before Codex can settle.\n */\n const timer = setTimeout(() => {\n if (isSettled) return;\n try {\n send();\n } catch (err) {\n settleError(err);\n }\n }, 0);\n timer.unref?.();\n },\n };\n };\n\n return {\n sessionId,\n isResume,\n doPromptTurn: async promptOpts => {\n if (\n promptOpts.responseFormat?.type === 'json' &&\n promptOpts.responseFormat.schema == null\n ) {\n throw new HarnessCapabilityUnsupportedError({\n message:\n \"Harness 'codex' requires a JSON schema for structured output.\",\n harnessId: 'codex',\n });\n }\n const tools = (promptOpts.tools ?? []).map(t => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n }));\n const { restartThread } = await synchronizeTurnConfiguration({\n skills: promptOpts.skills,\n instructions: promptOpts.instructions,\n tools,\n abortSignal: promptOpts.abortSignal,\n });\n const turn = wireTurn({\n emit: promptOpts.emit,\n abortSignal: promptOpts.abortSignal,\n });\n\n let promptText = extractUserText(promptOpts.prompt);\n if (!initialPromptGuidanceApplied) {\n promptText = frameInitialPromptGuidance({\n toolUsageBlock:\n tools.length > 0\n ? composeToolUsageInstructions({\n tools,\n cliShimPath,\n })\n : undefined,\n userText: promptText,\n });\n }\n initialPromptGuidanceApplied = true;\n\n const startMessage = {\n type: 'start' as const,\n prompt: promptText,\n tools,\n ...(promptOpts.responseFormat == null\n ? {}\n : { responseFormat: promptOpts.responseFormat }),\n ...(promptOpts.instructions\n ? { instructions: promptOpts.instructions }\n : {}),\n model: promptOpts.model ?? model,\n reasoningEffort,\n webSearch,\n ...(codexConfig == null ? {} : { codexConfig }),\n ...(mcpServers == null ? {} : { mcpServers }),\n ...(permissionMode ? { permissionMode } : {}),\n ...(pendingResumeThreadId\n ? { resumeThreadId: pendingResumeThreadId }\n : {}),\n ...(restartThread ? { restartThread: true } : {}),\n ...(debug ? { debug } : {}),\n };\n pendingResumeThreadId = undefined;\n turn.sendStart(() => channel.send(startMessage));\n\n return turn.control;\n },\n doContinueTurn: async continueOpts => {\n if (\n continueOpts.responseFormat?.type === 'json' &&\n continueOpts.responseFormat.schema == null\n ) {\n throw new HarnessCapabilityUnsupportedError({\n message:\n \"Harness 'codex' requires a JSON schema for structured output.\",\n harnessId: 'codex',\n });\n }\n const tools = (continueOpts.tools ?? []).map(t => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n }));\n const { restartThread } = await synchronizeTurnConfiguration({\n skills: continueOpts.skills,\n instructions: continueOpts.instructions,\n tools,\n abortSignal: continueOpts.abortSignal,\n });\n const turn = wireTurn({\n emit: continueOpts.emit,\n abortSignal: continueOpts.abortSignal,\n });\n\n /*\n * attach / replay: the still-running (or disk-replayed) turn streams into\n * the wired listeners — `doStart` opened the channel with `{ resume: true }`\n * so the bridge replays everything past the persisted cursor (including a\n * `finish` if the turn ended during the gap). No `start` is sent: issuing\n * one would clear the bridge's replay log and begin a new turn. Lossless.\n *\n * rerun: the bridge was respawned with no in-flight turn to attach to, so\n * re-drive codex's own thread via `resumeThreadId`. Lossy — work in flight\n * at the suspension is recomputed. This is the rare bridge-died\n * fallback; the common slice path is `attach`.\n */\n if (rerunContinue) {\n const threadId = pendingResumeThreadId ?? latestThreadId;\n pendingResumeThreadId = undefined;\n turn.sendStart(() =>\n channel.send({\n type: 'start' as const,\n /*\n * A continuation nudge rather than an empty prompt: `resumeThreadId`\n * rehydrates the prior thread, and this is the new user turn that\n * drives it forward. Keeping it non-empty avoids handing the runtime\n * an empty user message (and mirrors the claude-code adapter, where an\n * empty text block trips the Anthropic API's `cache_control` rule).\n */\n prompt: 'Continue.',\n tools,\n ...(continueOpts.responseFormat == null\n ? {}\n : { responseFormat: continueOpts.responseFormat }),\n ...(continueOpts.instructions\n ? { instructions: continueOpts.instructions }\n : {}),\n model: continueOpts.model ?? model,\n reasoningEffort,\n webSearch,\n ...(codexConfig == null ? {} : { codexConfig }),\n ...(mcpServers == null ? {} : { mcpServers }),\n ...(permissionMode ? { permissionMode } : {}),\n ...(threadId ? { resumeThreadId: threadId } : {}),\n ...(restartThread ? { restartThread: true } : {}),\n ...(debug ? { debug } : {}),\n }),\n );\n }\n\n return turn.control;\n },\n doCompact: async () => {\n /*\n * Codex compacts its context automatically inside the core turn loop\n * (~90% of the model context window), but the `codex exec` transport this\n * adapter drives exposes no manual compaction trigger and emits no\n * compaction event. Manual `compact()` is therefore unsupported; Codex's\n * own auto-compaction continues to run regardless.\n */\n throw new HarnessCapabilityUnsupportedError({\n message:\n \"Harness 'codex' does not support manual compaction; Codex auto-compacts its context internally.\",\n harnessId: 'codex',\n });\n },\n doDetach: async () => {\n if (stopped) {\n throw new Error(\n `codex session ${sessionId} is already stopped; cannot detach.`,\n );\n }\n stopped = true;\n const lastSeenEventId = await channel.suspend();\n const payload: HarnessV1ResumeSessionState = {\n type: 'resume-session',\n harnessId: 'codex',\n specificationVersion: 'harness-v1',\n data: {\n ...(latestThreadId ? { threadId: latestThreadId } : {}),\n ...(latestTurnConfigurationFingerprint\n ? {\n turnConfigurationFingerprint:\n latestTurnConfigurationFingerprint,\n }\n : {}),\n ...(sandboxCredentialEnvironment == null\n ? {}\n : { sandboxCredentialEnvironment }),\n bridge: {\n port: bridgePort,\n token: bridgeToken,\n lastSeenEventId,\n ...(sandboxId == null ? {} : { sandboxId }),\n },\n },\n };\n return payload;\n },\n doDestroy: async () => {\n if (stopped) return stopPromise;\n stopped = true;\n stopPromise = (async () => {\n // Tell the channel we are tearing down so the bridge's post-shutdown\n // socket close finalises instead of triggering a reconnect.\n channel.beginClose();\n try {\n if (!channel.isClosed()) {\n channel.send({ type: 'destroy' });\n }\n } catch {}\n let stopTimer: ReturnType<typeof setTimeout> | undefined;\n try {\n if (proc) {\n await Promise.race([\n proc.wait(),\n new Promise<void>(resolve => {\n stopTimer = setTimeout(resolve, 5000);\n stopTimer.unref?.();\n }),\n ]);\n }\n } finally {\n if (stopTimer) clearTimeout(stopTimer);\n try {\n await proc?.kill();\n } catch {}\n channel.close();\n }\n })();\n return stopPromise;\n },\n doStop: async () => {\n if (stopped) {\n throw new Error(\n `codex session ${sessionId} is already stopped; cannot stop.`,\n );\n }\n stopped = true;\n /*\n * If the bridge's channel already closed (e.g. mid-turn WS drop)\n * there is no one to acknowledge a `stop` message. Synthesize an empty\n * payload — the workdir is still captured by the sandbox snapshot\n * during the subsequent `sandboxSession.stop()`, so the next turn can\n * resume the filesystem state. The trade-off: we lose\n * `threadId`, so the codex CLI starts a fresh thread on the\n * preserved workdir rather than resuming the prior conversation\n * inside Codex's runtime. Ability to continue beats throwing.\n */\n // Tell the channel we are tearing down so the bridge's post-stop\n // socket close finalises instead of triggering a reconnect.\n channel.beginClose();\n const data: unknown = channel.isClosed()\n ? {}\n : await new Promise<unknown>((resolve, reject) => {\n const timer = setTimeout(() => {\n unsub();\n reject(\n new Error(\n `codex session ${sessionId} did not reply to stop within 5s.`,\n ),\n );\n }, 5000);\n timer.unref?.();\n const unsub = channel.on('bridge-stop', msg => {\n clearTimeout(timer);\n unsub();\n resolve(msg.data);\n });\n try {\n channel.send({ type: 'stop' });\n } catch (err) {\n clearTimeout(timer);\n unsub();\n reject(err);\n }\n });\n\n let stopTimer: ReturnType<typeof setTimeout> | undefined;\n try {\n if (proc) {\n await Promise.race([\n proc.wait(),\n new Promise<void>(resolve => {\n stopTimer = setTimeout(resolve, 5000);\n stopTimer.unref?.();\n }),\n ]);\n }\n } finally {\n if (stopTimer) clearTimeout(stopTimer);\n try {\n await proc?.kill();\n } catch {}\n channel.close();\n }\n\n const lifecycleData =\n data != null && typeof data === 'object' && !Array.isArray(data)\n ? { ...(data as Record<string, unknown>) }\n : {};\n const payload: HarnessV1ResumeSessionState = {\n type: 'resume-session',\n harnessId: 'codex',\n specificationVersion: 'harness-v1',\n data: {\n ...lifecycleData,\n ...(latestTurnConfigurationFingerprint\n ? {\n turnConfigurationFingerprint:\n latestTurnConfigurationFingerprint,\n }\n : {}),\n ...(sandboxCredentialEnvironment == null\n ? {}\n : { sandboxCredentialEnvironment }),\n } as HarnessV1ResumeSessionState['data'],\n };\n return payload;\n },\n doSuspendTurn: async () => {\n if (stopped) {\n throw new Error(\n `codex session ${sessionId} is stopped; cannot suspend.`,\n );\n }\n stopped = true;\n /*\n * Freeze the host at a precise cursor without stopping the active model\n * turn. `channel.suspend` stops processing inbound frames, drains what\n * was already dispatched, then closes the host socket with reason\n * `'suspended'`. The bridge keeps the turn running and accumulates events\n * past the cursor for the next slice to replay. The sandbox process is\n * deliberately left alive.\n */\n const lastSeenEventId = await channel.suspend();\n const payload: HarnessV1ContinueTurnState = {\n type: 'continue-turn',\n harnessId: 'codex',\n specificationVersion: 'harness-v1',\n data: {\n ...(latestThreadId ? { threadId: latestThreadId } : {}),\n ...(latestTurnConfigurationFingerprint\n ? {\n turnConfigurationFingerprint:\n latestTurnConfigurationFingerprint,\n }\n : {}),\n ...(sandboxCredentialEnvironment == null\n ? {}\n : { sandboxCredentialEnvironment }),\n bridge: {\n port: bridgePort,\n token: bridgeToken,\n lastSeenEventId,\n ...(sandboxId == null ? {} : { sandboxId }),\n },\n },\n };\n return payload;\n },\n };\n}\n\nfunction fingerprintCodexTurnConfiguration({\n instructions,\n tools,\n}: {\n instructions: string | undefined;\n tools: ReadonlyArray<{\n name: string;\n description?: string;\n inputSchema: unknown;\n }>;\n}): string {\n return createHash('sha256')\n .update(JSON.stringify({ instructions: instructions ?? null, tools }))\n .digest('hex');\n}\n\n/*\n * Frame host-tool relay guidance and the user's text so Codex treats the\n * prepended block as operating guidance rather than user prose. Applied only\n * to the first user message of a fresh session.\n */\nfunction frameInitialPromptGuidance({\n toolUsageBlock,\n userText,\n}: {\n toolUsageBlock: string | undefined;\n userText: string;\n}): string {\n const blocks: string[] = [];\n if (toolUsageBlock) blocks.push(toolUsageBlock);\n if (blocks.length === 0) return userText;\n return `${blocks.join('\\n\\n')}\\n\\n<user-message>\\n${userText}\\n</user-message>`;\n}\n\nfunction composeToolUsageInstructions({\n tools,\n cliShimPath,\n}: {\n tools: ReadonlyArray<{\n name: string;\n description?: string;\n inputSchema?: unknown;\n }>;\n cliShimPath: string;\n}): string {\n const lines: string[] = [\n '<host-tool-instructions>',\n 'You have access to the following host-provided tools. To use one, run the following command via your built-in `bash` tool:',\n '',\n ` node ${cliShimPath} <toolName> '<jsonInput>'`,\n '',\n 'The script prints the JSON result to stdout. Do not invent another way to call these tools — only this CLI invocation will work. Pass the JSON input as a single-quoted argument.',\n 'For every user request that depends on a host-provided tool, run a separate CLI invocation for each needed tool call in the current turn before answering. Do not reuse previous tool results, and do not say you used a host tool unless the command has completed in the current turn.',\n '',\n ];\n for (const toolSpec of tools) {\n lines.push(\n `- **${toolSpec.name}**${toolSpec.description ? ': ' + toolSpec.description : ''}`,\n );\n lines.push(\n ` - Input schema: \\`${JSON.stringify(toolSpec.inputSchema ?? {})}\\``,\n );\n }\n lines.push('</host-tool-instructions>');\n return lines.join('\\n');\n}\n\n/*\n * Reduce a `HarnessV1Prompt` to the plain user text the bridge forwards\n * to the Codex SDK. File and image parts on the message are not yet\n * supported by the underlying runtime — throw rather than silently drop\n * them so callers learn about the gap instead of seeing mysteriously\n * truncated prompts.\n */\nfunction extractUserText(prompt: HarnessV1Prompt): string {\n if (typeof prompt === 'string') return prompt;\n const { content } = prompt;\n if (typeof content === 'string') return content;\n const parts: string[] = [];\n for (const part of content) {\n if (part.type !== 'text') {\n throw new HarnessCapabilityUnsupportedError({\n harnessId: 'codex',\n message: `The codex harness does not yet support user message parts of type '${part.type}'. Pass a string or a user message whose content contains only text parts.`,\n });\n }\n parts.push(part.text);\n }\n return parts.join('\\n\\n');\n}\n","import type { HarnessV1Bootstrap } from '@ai-sdk/harness';\nimport { createReadBridgeAsset } from '@ai-sdk/harness/utils';\n\nconst readBridgeAsset = createReadBridgeAsset({\n resolveAssetUrl: name => new URL(`./bridge/${name}`, import.meta.url),\n});\n\n/*\n * Bootstrap is derived state stored under the sandbox's default working\n * directory so snapshot-capable providers can preserve the installed CLI,\n * bridge, and recipe marker without requiring root filesystem access.\n *\n * The session work dir (`startOpts.sessionWorkDir`) lives under the sandbox's\n * default working directory — the provider's persistent mount — so any files\n * the agent edits survive both detach -> attach and stop -> snapshot -> resume\n * cycles. Harness infra derived from `sandboxSession.defaultWorkingDirectory`\n * lives under `.agent-runs`, outside the agent workdir.\n */\nexport const CODEX_BOOTSTRAP_DIR = '.harness-bootstrap/codex';\n\nlet cachedBootstrap: HarnessV1Bootstrap | undefined;\n\nexport async function getCodexBootstrap(): Promise<HarnessV1Bootstrap> {\n if (cachedBootstrap != null) return cachedBootstrap;\n const [pkg, lock, bridge] = await Promise.all([\n readBridgeAsset('package.json'),\n readBridgeAsset('pnpm-lock.yaml'),\n readBridgeAsset('index.mjs'),\n ]);\n cachedBootstrap = {\n harnessId: 'codex',\n bootstrapDir: CODEX_BOOTSTRAP_DIR,\n files: [\n { path: `${CODEX_BOOTSTRAP_DIR}/package.json`, content: pkg },\n { path: `${CODEX_BOOTSTRAP_DIR}/pnpm-lock.yaml`, content: lock },\n { path: `${CODEX_BOOTSTRAP_DIR}/bridge.mjs`, content: bridge },\n ],\n commands: [\n {\n command: 'pnpm install --frozen-lockfile --store-dir .pnpm-store',\n },\n ],\n };\n return cachedBootstrap;\n}\n","import type {\n HarnessV1Authentication,\n HarnessV1RequestTransformation,\n HarnessV1RequestTransformationSources,\n} from '@ai-sdk/harness';\nimport {\n createCredentialRequestTransformation,\n getAiGatewayAuthFromEnv,\n isHarnessAuthenticationEnvironment,\n} from '@ai-sdk/harness/utils';\n\nconst DEFAULT_AI_GATEWAY_BASE_URL = 'https://ai-gateway.vercel.sh/v1';\nexport const DEFAULT_OPENAI_BASE_URL = 'https://api.openai.com/v1';\n\nexport const CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES = [\n 'AI_GATEWAY_API_KEY',\n 'CODEX_API_KEY',\n] as const;\n\nexport function createCodexRequestTransformations({\n env: environment,\n sandboxEnv: sandboxEnvironment,\n auth: authenticationMode,\n}: HarnessV1RequestTransformationSources<CodexResolvedAuthenticationMode>): HarnessV1RequestTransformation[] {\n if (!environment.CODEX_API_KEY || !sandboxEnvironment.CODEX_API_KEY) {\n return [];\n }\n return [\n createCredentialRequestTransformation({\n matchUrl:\n environment.OPENAI_BASE_URL ??\n (authenticationMode === 'ai-gateway'\n ? DEFAULT_AI_GATEWAY_BASE_URL\n : DEFAULT_OPENAI_BASE_URL),\n matchHeaders: {\n Authorization: `Bearer ${sandboxEnvironment.CODEX_API_KEY}`,\n },\n transformHeaders: {\n Authorization: `Bearer ${environment.CODEX_API_KEY}`,\n },\n }),\n ];\n}\n\nexport type CodexResolvedAuthenticationMode = 'direct' | 'ai-gateway';\n\nexport type CodexAuthenticationMode = HarnessV1Authentication;\n\n/**\n * Resolve the environment-variable blob the codex bridge needs. Precedence:\n *\n * 1. An explicit authentication mode pins the selected route.\n * 2. Auto-detect from the host process env: gateway first\n * (`AI_GATEWAY_API_KEY` / `VERCEL_OIDC_TOKEN`), then `CODEX_API_KEY` /\n * `OPENAI_API_KEY`.\n */\nexport function resolveCodexEnv(\n auth: CodexAuthenticationMode | undefined,\n processEnv: Record<string, string | undefined> = process.env,\n): Record<string, string> {\n const suppliedEnvironment = isHarnessAuthenticationEnvironment(auth);\n const authenticationEnvironment = suppliedEnvironment ? auth : processEnv;\n if (auth === 'direct') {\n return pickOpenAI({ processEnv: authenticationEnvironment });\n }\n\n const gatewayAuthFromEnv = getAiGatewayAuthFromEnv({\n env: authenticationEnvironment,\n });\n if (auth === 'ai-gateway' || gatewayAuthFromEnv.apiKey) {\n return pickGateway({ gatewayAuthFromEnv });\n }\n return pickOpenAI({ processEnv: authenticationEnvironment });\n}\n\nexport function resolveCodexAuthenticationMode(\n auth: CodexAuthenticationMode | undefined,\n processEnv: Record<string, string | undefined> = process.env,\n): CodexResolvedAuthenticationMode {\n if (isHarnessAuthenticationEnvironment(auth)) {\n return getAiGatewayAuthFromEnv({ env: auth }).apiKey\n ? 'ai-gateway'\n : 'direct';\n }\n if (auth === 'direct') {\n return 'direct';\n }\n if (auth === 'ai-gateway') {\n return 'ai-gateway';\n }\n return getAiGatewayAuthFromEnv({ env: processEnv }).apiKey\n ? 'ai-gateway'\n : 'direct';\n}\n\nfunction pickOpenAI({\n processEnv,\n}: {\n processEnv: Record<string, string | undefined>;\n}): Record<string, string> {\n const env: Record<string, string> = {};\n const apiKey = processEnv.OPENAI_API_KEY ?? processEnv.CODEX_API_KEY;\n if (apiKey) env.CODEX_API_KEY = apiKey;\n const baseUrl = processEnv.OPENAI_BASE_URL;\n if (baseUrl) env.OPENAI_BASE_URL = baseUrl;\n const organization = processEnv.OPENAI_ORGANIZATION;\n if (organization) env.OPENAI_ORGANIZATION = organization;\n const project = processEnv.OPENAI_PROJECT;\n if (project) env.OPENAI_PROJECT = project;\n return env;\n}\n\nfunction pickGateway({\n gatewayAuthFromEnv,\n}: {\n gatewayAuthFromEnv: ReturnType<typeof getAiGatewayAuthFromEnv>;\n}): Record<string, string> {\n const apiKey = gatewayAuthFromEnv.apiKey;\n const baseUrl = toCodexGatewayBaseUrl(gatewayAuthFromEnv.baseUrl);\n const env: Record<string, string> = {};\n if (apiKey) {\n env.AI_GATEWAY_API_KEY = apiKey;\n env.CODEX_API_KEY = apiKey;\n }\n env.AI_GATEWAY_BASE_URL = baseUrl;\n env.OPENAI_BASE_URL = baseUrl;\n return env;\n}\n\nfunction toCodexGatewayBaseUrl(baseUrl: string): string {\n const trimmed = baseUrl.replace(/\\/+$/, '');\n return trimmed.endsWith('/v1') ? trimmed : `${trimmed}/v1`;\n}\n","import {\n harnessV1BridgeInboundCommandSchemas,\n harnessV1BridgeOutboundMessageSchema,\n harnessV1BridgeReadySchema,\n harnessV1BridgeStartBaseSchema,\n} from '@ai-sdk/harness';\nimport { z } from 'zod/v4';\n\n/*\n * Codex's bridge wire protocol. The outbound events (including `file-change`\n * and the `bridge-thread` resume coordinate), transport frames, shared inbound\n * commands, and `bridge-ready` line all come from the shared `@ai-sdk/harness`\n * protocol — the only Codex-specific piece is the `start` payload.\n */\n\nexport const outboundMessageSchema = harnessV1BridgeOutboundMessageSchema;\nexport type OutboundMessage = z.infer<typeof outboundMessageSchema>;\n\nexport const startMessageSchema = harnessV1BridgeStartBaseSchema.extend({\n instructions: z.string().optional(),\n reasoningEffort: z.enum(['low', 'medium', 'high', 'xhigh', 'max']).optional(),\n webSearch: z.boolean().optional(),\n codexConfig: z.record(z.string(), z.unknown()).optional(),\n mcpServers: z.record(z.string(), z.unknown()).optional(),\n // Resume signal. When supplied, the bridge calls\n // `codex.resumeThread(resumeThreadId, …)` instead of starting a fresh thread.\n // The host sources the id from lifecycle state `data` cached from a prior\n // `agent.detach`.\n resumeThreadId: z.string().optional(),\n restartThread: z.boolean().optional(),\n});\n\nexport type StartMessage = z.infer<typeof startMessageSchema>;\n\nexport const inboundMessageSchema = z.discriminatedUnion('type', [\n startMessageSchema,\n ...harnessV1BridgeInboundCommandSchemas,\n]);\nexport type InboundMessage = z.infer<typeof inboundMessageSchema>;\n\nexport const bridgeReadySchema = harnessV1BridgeReadySchema;\nexport type BridgeReady = z.infer<typeof bridgeReadySchema>;\n","/*\n * Temporary workaround for upstream codex CLI bug\n * https://github.com/openai/codex/issues/19425 — MCP tools registered via\n * `mcp_servers.*` are not exposed to the model in `codex exec --experimental-json`\n * mode (which is what `@openai/codex-sdk` uses). The MCP handshake completes\n * and `tools/list` succeeds, but codex never registers the tools as\n * model-callable functions.\n *\n * Until that's fixed upstream, this file implements a CLI-based relay:\n *\n * 1. A small Node script is written into harness-owned session state at turn\n * start (`buildCliShimScript`). It accepts `<toolName> <jsonInput>` as\n * argv, POSTs to the same HTTP relay the MCP shim uses, and prints the\n * result to stdout.\n *\n * 2. Tool descriptions and invocation instructions are injected into the\n * initial user prompt by the host adapter, telling the model to call host\n * tools by running `node <shim-path> <toolName> '<jsonInput>'` via its\n * built-in `bash` tool.\n *\n * 3. The bridge's event loop suppresses the matching `command_execution`\n * events (`isToolRelayCommand`) so callers receive clean `tool-call` /\n * `tool-result` events from the HTTP relay rather than seeing the\n * relay invocations as raw bash commands.\n *\n * Once #19425 is fixed and MCP tools are properly exposed in exec mode, the\n * three hookpoints in `bridge/index.ts` can be removed along with this file.\n */\nexport const CLI_SHIM_FILENAME = 'harness-tool.mjs';\n\nexport function buildCliShimScript({\n relayPort,\n}: {\n relayPort: number;\n}): string {\n return `#!/usr/bin/env node\nconst [toolName, inputJson = '{}'] = process.argv.slice(2);\nif (!toolName) {\n console.error('Usage: harness-tool <tool_name> <json_input>');\n process.exit(64);\n}\nlet input;\ntry {\n input = JSON.parse(inputJson);\n} catch (error) {\n console.error('Invalid JSON input: ' + (error instanceof Error ? error.message : String(error)));\n process.exit(64);\n}\nconst requestId = 'cli-' + Date.now() + '-' + Math.random().toString(16).slice(2);\nconst response = await fetch('http://127.0.0.1:${relayPort}', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ requestId, toolName, input }),\n});\nconst text = await response.text();\nlet payload;\ntry {\n payload = text ? JSON.parse(text) : {};\n} catch {\n payload = { error: text };\n}\nif (!response.ok || payload.error) {\n console.error(String(payload.error ?? ('tool relay failed with HTTP ' + response.status)));\n process.exit(1);\n}\nconsole.log(JSON.stringify(payload.result ?? payload, null, 2));\n`;\n}\n\nexport function isToolRelayCommand({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): boolean {\n return parseToolRelayCommands({ command, cliShimPath }) !== undefined;\n}\n\nexport function parseToolRelayCommand({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): { toolName: string; input: unknown } | undefined {\n const calls = parseToolRelayCommands({ command, cliShimPath });\n return calls?.length === 1 ? calls[0] : undefined;\n}\n\nexport function parseToolRelayCommands({\n command,\n cliShimPath,\n}: {\n command: string;\n cliShimPath: string;\n}): Array<{ toolName: string; input: unknown }> | undefined {\n return parseToolRelayCommandsInternal({ command, cliShimPath, depth: 0 });\n}\n\nfunction parseToolRelayCommandsInternal({\n command,\n cliShimPath,\n depth,\n}: {\n command: string;\n cliShimPath: string;\n depth: number;\n}): Array<{ toolName: string; input: unknown }> | undefined {\n const commands = splitShellAndCommands(command);\n if (!commands) return undefined;\n if (commands.length > 1) {\n const relayCalls: Array<{ toolName: string; input: unknown }> = [];\n for (const nestedCommand of commands) {\n const nestedCalls = parseToolRelayCommandsInternal({\n command: nestedCommand,\n cliShimPath,\n depth,\n });\n if (!nestedCalls) return undefined;\n relayCalls.push(...nestedCalls);\n }\n return relayCalls;\n }\n\n const argv = parseShellWords(command);\n if (!argv) return undefined;\n\n const relayCall = parseDirectToolRelayArgv({ argv, cliShimPath });\n if (relayCall) return [relayCall];\n\n const innerCommand = extractShellEvalCommand(argv);\n if (!innerCommand || depth >= 2) return undefined;\n return parseToolRelayCommandsInternal({\n command: innerCommand,\n cliShimPath,\n depth: depth + 1,\n });\n}\n\nfunction parseDirectToolRelayArgv({\n argv,\n cliShimPath,\n}: {\n argv: string[];\n cliShimPath: string;\n}): { toolName: string; input: unknown } | undefined {\n if (argv.length < 3 || argv.length > 4) return undefined;\n if (argv[0] !== 'node' || argv[1] !== cliShimPath) return undefined;\n const toolName = argv[2];\n if (!toolName) return undefined;\n try {\n return { toolName, input: JSON.parse(argv[3] ?? '{}') };\n } catch {\n return undefined;\n }\n}\n\nfunction extractShellEvalCommand(argv: string[]): string | undefined {\n if (argv.length !== 3) return undefined;\n const shellName = argv[0].split('/').at(-1);\n if (shellName !== 'bash' && shellName !== 'sh' && shellName !== 'zsh') {\n return undefined;\n }\n if (argv[1] !== '-c' && argv[1] !== '-lc') return undefined;\n return argv[2];\n}\n\nfunction splitShellAndCommands(command: string): string[] | undefined {\n const commands: string[] = [];\n let start = 0;\n let quote: '\"' | \"'\" | undefined;\n\n for (let i = 0; i < command.length; i++) {\n const char = command[i];\n if (quote === \"'\") {\n if (char === \"'\") quote = undefined;\n continue;\n }\n if (quote === '\"') {\n if (char === '\"') {\n quote = undefined;\n } else if (char === '\\\\') {\n i++;\n }\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n continue;\n }\n if (char === '\\\\') {\n i++;\n continue;\n }\n if (char === '&' && command[i + 1] === '&') {\n const nestedCommand = command.slice(start, i).trim();\n if (!nestedCommand) return undefined;\n commands.push(nestedCommand);\n start = i + 2;\n i++;\n }\n }\n\n if (quote) return undefined;\n const nestedCommand = command.slice(start).trim();\n if (!nestedCommand) return undefined;\n commands.push(nestedCommand);\n return commands;\n}\n\nfunction parseShellWords(command: string): string[] | undefined {\n const words: string[] = [];\n let current = '';\n let quote: '\"' | \"'\" | undefined;\n let hasCurrent = false;\n\n const pushCurrent = () => {\n if (!hasCurrent) return;\n words.push(current);\n current = '';\n hasCurrent = false;\n };\n\n for (let i = 0; i < command.length; i++) {\n const char = command[i];\n if (quote === \"'\") {\n if (char === \"'\") {\n quote = undefined;\n } else {\n current += char;\n }\n hasCurrent = true;\n continue;\n }\n if (quote === '\"') {\n if (char === '\"') {\n quote = undefined;\n } else if (char === '\\\\' && i + 1 < command.length) {\n current += command[++i];\n } else {\n current += char;\n }\n hasCurrent = true;\n continue;\n }\n if (/\\s/.test(char)) {\n pushCurrent();\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n hasCurrent = true;\n continue;\n }\n if (char === '\\\\' && i + 1 < command.length) {\n current += command[++i];\n hasCurrent = true;\n continue;\n }\n if (/[;&|<>()`$]/.test(char)) return undefined;\n current += char;\n hasCurrent = true;\n }\n if (quote) return undefined;\n pushCurrent();\n return words;\n}\n","// Version string of this package injected at build time.\ndeclare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n","import { createCodex } from './codex-harness';\n\n/**\n * Default `codex` harness instance with no overrides — suitable for the\n * common case where the underlying `codex` CLI's defaults are fine.\n * Equivalent to `createCodex()`.\n */\nexport const codex = createCodex();\n\nexport { createCodex } from './codex-harness';\nexport { VERSION } from './version';\nexport type { CodexHarnessSettings } from './codex-harness';\nexport type { CodexAuthenticationMode } from './codex-auth';\n"],"mappings":"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","names":["z","z","endpoint","proc"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/harness-codex",
3
- "version": "1.0.101",
3
+ "version": "1.0.103",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -26,7 +26,7 @@
26
26
  }
27
27
  },
28
28
  "dependencies": {
29
- "@ai-sdk/harness": "1.0.99",
29
+ "@ai-sdk/harness": "1.0.101",
30
30
  "@ai-sdk/provider-utils": "5.0.36",
31
31
  "ws": "^8.21.0"
32
32
  },
@@ -313,8 +313,6 @@ export function createCodex(
313
313
  */
314
314
  sandboxAuthEnvironment.OPENAI_BASE_URL = DEFAULT_OPENAI_BASE_URL;
315
315
  }
316
- } else {
317
- warnCredentialBrokeringUnavailable();
318
316
  }
319
317
  const bootstrapDir = path.posix.resolve(
320
318
  defaultWorkingDirectory,
@@ -446,6 +444,14 @@ export function createCodex(
446
444
  CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES,
447
445
  credentialForwarding: settings.credentialForwarding,
448
446
  });
447
+ if (!credentialsBrokered) {
448
+ warnCredentialBrokeringUnavailable({
449
+ environment: resolvedAuthEnvironment,
450
+ forwardedEnvironment: forwardedAuthEnvironment,
451
+ credentialEnvironmentVariables:
452
+ CODEX_CREDENTIAL_ENVIRONMENT_VARIABLES,
453
+ });
454
+ }
449
455
  const env = {
450
456
  ...forwardedAuthEnvironment,
451
457
  AI_SDK_HARNESS_CLIENT_APP: CODEX_CLIENT_APP,