@ai-sdk/harness 1.0.21 → 1.0.23
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 +20 -0
- package/README.md +59 -49
- package/dist/agent/index.js +63 -0
- package/dist/agent/index.js.map +1 -1
- package/dist/bridge/index.d.ts +18 -0
- package/dist/bridge/index.js +69 -4
- package/dist/bridge/index.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +40 -1
- package/dist/utils/index.js +240 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +4 -4
- package/src/agent/internal/run-prompt.ts +19 -0
- package/src/bridge/index.ts +86 -3
- package/src/utils/bridge-diagnostics.ts +213 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/sandbox-channel.ts +72 -0
- package/src/v1/harness-v1-bridge-protocol.ts +17 -0
package/dist/bridge/index.d.ts
CHANGED
|
@@ -53,6 +53,12 @@ interface BridgeTurn {
|
|
|
53
53
|
readonly pendingUserMessages: string[];
|
|
54
54
|
/** Aborts when the host sends `abort`. */
|
|
55
55
|
readonly abortSignal: AbortSignal;
|
|
56
|
+
/**
|
|
57
|
+
* Register the runtime-specific interrupt hook for this active turn. The
|
|
58
|
+
* shared bridge invokes it when the host sends `interrupt`, then acknowledges
|
|
59
|
+
* only after the hook settles.
|
|
60
|
+
*/
|
|
61
|
+
onInterrupt(handler: () => void | Promise<void>): void;
|
|
56
62
|
/** True for the first turn since this bridge process started. */
|
|
57
63
|
readonly firstTurn: boolean;
|
|
58
64
|
/**
|
|
@@ -68,6 +74,18 @@ interface BridgeTurn {
|
|
|
68
74
|
attrs?: Record<string, unknown>;
|
|
69
75
|
error?: unknown;
|
|
70
76
|
}): void;
|
|
77
|
+
/**
|
|
78
|
+
* Emit a non-fatal bridge warning to stderr using the runtime's harness
|
|
79
|
+
* prefix. This is diagnostic-only: it does not emit a stream event, does not
|
|
80
|
+
* consume a `seq`, and does not fail the turn.
|
|
81
|
+
*/
|
|
82
|
+
emitWarning(input: {
|
|
83
|
+
message: string;
|
|
84
|
+
}): void;
|
|
85
|
+
emitError(input: {
|
|
86
|
+
error: unknown;
|
|
87
|
+
message?: string;
|
|
88
|
+
}): void;
|
|
71
89
|
}
|
|
72
90
|
interface RunBridgeOptions<TStart extends {
|
|
73
91
|
type: 'start';
|
package/dist/bridge/index.js
CHANGED
|
@@ -20,6 +20,15 @@ function formatBridgeError(err) {
|
|
|
20
20
|
if (err instanceof Error) {
|
|
21
21
|
return { name: err.name, message: err.message, stack: err.stack };
|
|
22
22
|
}
|
|
23
|
+
if (typeof err === "string") {
|
|
24
|
+
return { message: err };
|
|
25
|
+
}
|
|
26
|
+
if (err !== null && typeof err === "object") {
|
|
27
|
+
try {
|
|
28
|
+
return { message: JSON.stringify(err) };
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
}
|
|
23
32
|
return { message: String(err) };
|
|
24
33
|
}
|
|
25
34
|
function parseEnvList(value) {
|
|
@@ -47,6 +56,7 @@ async function runBridge(options) {
|
|
|
47
56
|
let isFirstTurn = true;
|
|
48
57
|
let turnAbort;
|
|
49
58
|
let currentUserMessages;
|
|
59
|
+
let currentInterruptHandler;
|
|
50
60
|
let debugConfig;
|
|
51
61
|
let consoleCaptureInstalled = false;
|
|
52
62
|
const envDebugEnabled = ENV_TRUTHY.has(
|
|
@@ -164,6 +174,38 @@ async function runBridge(options) {
|
|
|
164
174
|
};
|
|
165
175
|
const rawStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
166
176
|
const rawStderrWrite = process.stderr.write.bind(process.stderr);
|
|
177
|
+
const writeErrorToStderr = (input) => {
|
|
178
|
+
try {
|
|
179
|
+
const formatted = formatBridgeError(input.error);
|
|
180
|
+
rawStderrWrite(
|
|
181
|
+
`[harness:${bridgeType}:error] ${input.message}: ${formatted.message}
|
|
182
|
+
`
|
|
183
|
+
);
|
|
184
|
+
if (formatted.stack) {
|
|
185
|
+
rawStderrWrite(`${formatted.stack}
|
|
186
|
+
`);
|
|
187
|
+
}
|
|
188
|
+
} catch {
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
const emitWarning = (input) => {
|
|
192
|
+
try {
|
|
193
|
+
for (const line of input.message.split("\n")) {
|
|
194
|
+
if (line.trim().length > 0) {
|
|
195
|
+
rawStderrWrite(`[harness:${bridgeType}:warn] ${line}
|
|
196
|
+
`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} catch {
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
const emitError = (input) => {
|
|
203
|
+
writeErrorToStderr({
|
|
204
|
+
message: input.message ?? "bridge error",
|
|
205
|
+
error: input.error
|
|
206
|
+
});
|
|
207
|
+
emit({ type: "error", error: serialiseError(input.error) });
|
|
208
|
+
};
|
|
167
209
|
const installConsoleCapture = () => {
|
|
168
210
|
if (consoleCaptureInstalled) return;
|
|
169
211
|
consoleCaptureInstalled = true;
|
|
@@ -221,6 +263,7 @@ async function runBridge(options) {
|
|
|
221
263
|
});
|
|
222
264
|
turnAbort = new AbortController();
|
|
223
265
|
currentTurnState = "running";
|
|
266
|
+
currentInterruptHandler = void 0;
|
|
224
267
|
void writeStartConfig(msg);
|
|
225
268
|
void writeBridgeMeta("running");
|
|
226
269
|
const startDebug = msg.debug;
|
|
@@ -242,6 +285,9 @@ async function runBridge(options) {
|
|
|
242
285
|
}),
|
|
243
286
|
pendingUserMessages: [],
|
|
244
287
|
abortSignal: turnAbort.signal,
|
|
288
|
+
onInterrupt: (handler) => {
|
|
289
|
+
currentInterruptHandler = handler;
|
|
290
|
+
},
|
|
245
291
|
firstTurn,
|
|
246
292
|
bridgeLog: (input) => {
|
|
247
293
|
const level = input.level ?? "debug";
|
|
@@ -254,14 +300,17 @@ async function runBridge(options) {
|
|
|
254
300
|
...input.attrs ? { attrs: input.attrs } : {},
|
|
255
301
|
...input.error !== void 0 ? { error: formatBridgeError(input.error) } : {}
|
|
256
302
|
});
|
|
257
|
-
}
|
|
303
|
+
},
|
|
304
|
+
emitWarning,
|
|
305
|
+
emitError
|
|
258
306
|
};
|
|
259
307
|
currentUserMessages = turn.pendingUserMessages;
|
|
260
308
|
try {
|
|
261
309
|
await onStart(msg, turn);
|
|
262
310
|
} catch (err) {
|
|
263
|
-
|
|
311
|
+
emitError({ error: err, message: "bridge turn failed" });
|
|
264
312
|
} finally {
|
|
313
|
+
currentInterruptHandler = void 0;
|
|
265
314
|
currentTurnState = "waiting";
|
|
266
315
|
void writeBridgeMeta("waiting");
|
|
267
316
|
}
|
|
@@ -289,6 +338,22 @@ async function runBridge(options) {
|
|
|
289
338
|
case "abort":
|
|
290
339
|
turnAbort?.abort();
|
|
291
340
|
return;
|
|
341
|
+
case "interrupt":
|
|
342
|
+
try {
|
|
343
|
+
if (currentInterruptHandler) {
|
|
344
|
+
await currentInterruptHandler();
|
|
345
|
+
} else {
|
|
346
|
+
turnAbort?.abort();
|
|
347
|
+
}
|
|
348
|
+
sendControl({ type: "bridge-interrupted", ok: true });
|
|
349
|
+
} catch (err) {
|
|
350
|
+
sendControl({
|
|
351
|
+
type: "bridge-interrupted",
|
|
352
|
+
ok: false,
|
|
353
|
+
error: serialiseError(err)
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
return;
|
|
292
357
|
case "resume":
|
|
293
358
|
replay(ws, msg.lastSeenEventId);
|
|
294
359
|
return;
|
|
@@ -383,10 +448,10 @@ async function runBridge(options) {
|
|
|
383
448
|
});
|
|
384
449
|
});
|
|
385
450
|
process.on("uncaughtException", (err) => {
|
|
386
|
-
|
|
451
|
+
emitError({ error: err, message: "uncaught exception" });
|
|
387
452
|
});
|
|
388
453
|
process.on("unhandledRejection", (err) => {
|
|
389
|
-
|
|
454
|
+
emitError({ error: err, message: "unhandled rejection" });
|
|
390
455
|
});
|
|
391
456
|
await new Promise((resolve, reject) => {
|
|
392
457
|
if (wss.address() != null) {
|
package/dist/bridge/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bridge/index.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, single-flight connection\n// replacement, the in-memory event log + monotonic `seq`, resume replay, and\n// the lifecycle/meta files. The adapter supplies only `onStart` (drive its\n// CLI/SDK and translate to wire events) and `onDetach` (its resume payload).\n\nimport { appendFile, mkdir, writeFile } from 'node:fs/promises';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { env as procEnv, pid, stdout } from 'node:process';\nimport { WebSocketServer, type WebSocket } from 'ws';\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\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 return { message: String(err) };\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 /**\n * Live queue of mid-turn user messages. The runtime pushes inbound\n * `user-message` text here; the adapter drains it as its runtime accepts\n * interactive input.\n */\n readonly pendingUserMessages: string[];\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\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 /** Drive one prompt turn. Rejections surface to the host as an `error` event. */\n onStart(start: TStart, turn: BridgeTurn): Promise<void>;\n /** Produce the adapter-defined resume payload for a `detach`. Defaults to `{}`. */\n onDetach?(): unknown | Promise<unknown>;\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 a `shutdown` / `detach`. 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'; text: string }\n | { type: 'abort' }\n | { type: 'shutdown' }\n | { type: 'detach' }\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 * `shutdown` / `detach` 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, onDetach } = options;\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 let activeSocket: WebSocket | undefined;\n let isFirstTurn = true;\n let turnAbort: AbortController | undefined;\n let currentUserMessages: string[] | 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 just-interrupted 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 sendControl = (msg: Record<string, unknown>): void => {\n if (activeSocket?.readyState === WS_OPEN) {\n try {\n activeSocket.send(JSON.stringify(msg));\n } catch {\n // best-effort\n }\n }\n };\n\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 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 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 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 pendingUserMessages: [],\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 };\n currentUserMessages = turn.pendingUserMessages;\n try {\n await onStart(msg as TStart, turn);\n } catch (err) {\n emit({ type: 'error', error: serialiseError(err) });\n } finally {\n currentTurnState = 'waiting';\n void writeBridgeMeta('waiting');\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 currentUserMessages?.push(msg.text);\n return;\n case 'abort':\n turnAbort?.abort();\n return;\n case 'resume':\n replay(ws, msg.lastSeenEventId);\n return;\n case 'shutdown':\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n drainThenExit(ws, 1000, 'shutdown');\n return;\n case 'detach': {\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n const data = (await onDetach?.()) ?? {};\n sendControl({ type: 'bridge-detach', data });\n drainThenExit(ws, 1000, 'detach');\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 shutdown/detach 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 // Single-flight: a fresh authorized connection *replaces* the active one\n // (the host reconnecting after a drop). The previous socket's close is a\n // no-op below because it is no longer `activeSocket`.\n activeSocket = ws;\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({\n type: 'bridge-hello',\n state: currentTurnState,\n lastSeq: seqCounter,\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({\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 *current* socket's close matters. A stale socket (already\n // replaced by a reconnect) closing is a no-op. Crucially we do NOT abort\n // the in-flight turn — it keeps running and its events accumulate in the\n // log for replay when the host reconnects.\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 emit({ type: 'error', error: serialiseError(err) });\n });\n process.on('unhandledRejection', err => {\n emit({ type: 'error', error: serialiseError(err) });\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\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"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/bridge/index.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, single-flight connection\n// replacement, the in-memory event log + monotonic `seq`, resume replay, and\n// the lifecycle/meta files. The adapter supplies only `onStart` (drive its\n// CLI/SDK and translate to wire events) and `onDetach` (its resume payload).\n\nimport { appendFile, mkdir, writeFile } from 'node:fs/promises';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { env as procEnv, pid, stdout } from 'node:process';\nimport { WebSocketServer, type WebSocket } from 'ws';\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\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 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 /**\n * Live queue of mid-turn user messages. The runtime pushes inbound\n * `user-message` text here; the adapter drains it as its runtime accepts\n * interactive input.\n */\n readonly pendingUserMessages: string[];\n\n /** Aborts when the host sends `abort`. */\n readonly abortSignal: AbortSignal;\n\n /**\n * Register the runtime-specific interrupt hook for this active turn. The\n * shared bridge invokes it when the host sends `interrupt`, then acknowledges\n * only after the hook settles.\n */\n onInterrupt(handler: () => void | Promise<void>): void;\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 /** Drive one prompt turn. Rejections surface to the host as an `error` event. */\n onStart(start: TStart, turn: BridgeTurn): Promise<void>;\n /** Produce the adapter-defined resume payload for a `detach`. Defaults to `{}`. */\n onDetach?(): unknown | Promise<unknown>;\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 a `shutdown` / `detach`. 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'; text: string }\n | { type: 'abort' }\n | { type: 'interrupt' }\n | { type: 'shutdown' }\n | { type: 'detach' }\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 * `shutdown` / `detach` 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, onDetach } = options;\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 let activeSocket: WebSocket | undefined;\n let isFirstTurn = true;\n let turnAbort: AbortController | undefined;\n let currentUserMessages: string[] | undefined;\n let currentInterruptHandler: (() => void | 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 just-interrupted 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 sendControl = (msg: Record<string, unknown>): void => {\n if (activeSocket?.readyState === WS_OPEN) {\n try {\n activeSocket.send(JSON.stringify(msg));\n } catch {\n // best-effort\n }\n }\n };\n\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 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 currentInterruptHandler = undefined;\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 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 pendingUserMessages: [],\n abortSignal: turnAbort.signal,\n onInterrupt: handler => {\n currentInterruptHandler = handler;\n },\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 = turn.pendingUserMessages;\n try {\n await onStart(msg as TStart, turn);\n } catch (err) {\n emitError({ error: err, message: 'bridge turn failed' });\n } finally {\n currentInterruptHandler = undefined;\n currentTurnState = 'waiting';\n void writeBridgeMeta('waiting');\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 currentUserMessages?.push(msg.text);\n return;\n case 'abort':\n turnAbort?.abort();\n return;\n case 'interrupt':\n try {\n if (currentInterruptHandler) {\n await currentInterruptHandler();\n } else {\n turnAbort?.abort();\n }\n sendControl({ type: 'bridge-interrupted', ok: true });\n } catch (err) {\n sendControl({\n type: 'bridge-interrupted',\n ok: false,\n error: serialiseError(err),\n });\n }\n return;\n case 'resume':\n replay(ws, msg.lastSeenEventId);\n return;\n case 'shutdown':\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n drainThenExit(ws, 1000, 'shutdown');\n return;\n case 'detach': {\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n const data = (await onDetach?.()) ?? {};\n sendControl({ type: 'bridge-detach', data });\n drainThenExit(ws, 1000, 'detach');\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 shutdown/detach 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 // Single-flight: a fresh authorized connection *replaces* the active one\n // (the host reconnecting after a drop). The previous socket's close is a\n // no-op below because it is no longer `activeSocket`.\n activeSocket = ws;\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({\n type: 'bridge-hello',\n state: currentTurnState,\n lastSeq: seqCounter,\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({\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 *current* socket's close matters. A stale socket (already\n // replaced by a reconnect) closing is a no-op. Crucially we do NOT abort\n // the in-flight turn — it keeps running and its events accumulate in the\n // log for replay when the host reconnects.\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\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"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1427,6 +1427,10 @@ declare const harnessV1BridgeOutboundMessageSchema: z.ZodDiscriminatedUnion<[z.Z
|
|
|
1427
1427
|
}, z.core.$strip>, z.ZodObject<{
|
|
1428
1428
|
type: z.ZodLiteral<"bridge-thread">;
|
|
1429
1429
|
threadId: z.ZodString;
|
|
1430
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1431
|
+
type: z.ZodLiteral<"bridge-interrupted">;
|
|
1432
|
+
ok: z.ZodBoolean;
|
|
1433
|
+
error: z.ZodOptional<z.ZodUnknown>;
|
|
1430
1434
|
}, z.core.$strip>, z.ZodObject<{
|
|
1431
1435
|
type: z.ZodLiteral<"sandbox-log">;
|
|
1432
1436
|
source: z.ZodString;
|
|
@@ -1524,6 +1528,8 @@ declare const harnessV1BridgeInboundCommandSchemas: readonly [z.ZodObject<{
|
|
|
1524
1528
|
text: z.ZodString;
|
|
1525
1529
|
}, z.core.$strip>, z.ZodObject<{
|
|
1526
1530
|
type: z.ZodLiteral<"abort">;
|
|
1531
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1532
|
+
type: z.ZodLiteral<"interrupt">;
|
|
1527
1533
|
}, z.core.$strip>, z.ZodObject<{
|
|
1528
1534
|
type: z.ZodLiteral<"shutdown">;
|
|
1529
1535
|
}, z.core.$strip>, z.ZodObject<{
|
package/dist/index.js
CHANGED
|
@@ -300,6 +300,11 @@ var harnessV1BridgeThreadSchema = z4.object({
|
|
|
300
300
|
type: z4.literal("bridge-thread"),
|
|
301
301
|
threadId: z4.string()
|
|
302
302
|
});
|
|
303
|
+
var harnessV1BridgeInterruptedSchema = z4.object({
|
|
304
|
+
type: z4.literal("bridge-interrupted"),
|
|
305
|
+
ok: z4.boolean(),
|
|
306
|
+
error: z4.unknown().optional()
|
|
307
|
+
});
|
|
303
308
|
var harnessV1BridgeSandboxLogSchema = z4.object({
|
|
304
309
|
type: z4.literal("sandbox-log"),
|
|
305
310
|
source: z4.string(),
|
|
@@ -340,6 +345,7 @@ var harnessV1BridgeOutboundMessageSchema = z4.discriminatedUnion(
|
|
|
340
345
|
harnessV1BridgeHelloSchema,
|
|
341
346
|
harnessV1BridgeDetachSchema,
|
|
342
347
|
harnessV1BridgeThreadSchema,
|
|
348
|
+
harnessV1BridgeInterruptedSchema,
|
|
343
349
|
harnessV1BridgeSandboxLogSchema,
|
|
344
350
|
harnessV1BridgeDebugEventSchema
|
|
345
351
|
]
|
|
@@ -387,6 +393,9 @@ var harnessV1BridgeUserMessageInboundSchema = z4.object({
|
|
|
387
393
|
var harnessV1BridgeAbortInboundSchema = z4.object({
|
|
388
394
|
type: z4.literal("abort")
|
|
389
395
|
});
|
|
396
|
+
var harnessV1BridgeInterruptInboundSchema = z4.object({
|
|
397
|
+
type: z4.literal("interrupt")
|
|
398
|
+
});
|
|
390
399
|
var harnessV1BridgeShutdownInboundSchema = z4.object({
|
|
391
400
|
type: z4.literal("shutdown")
|
|
392
401
|
});
|
|
@@ -402,6 +411,7 @@ var harnessV1BridgeInboundCommandSchemas = [
|
|
|
402
411
|
harnessV1BridgeToolApprovalResponseInboundSchema,
|
|
403
412
|
harnessV1BridgeUserMessageInboundSchema,
|
|
404
413
|
harnessV1BridgeAbortInboundSchema,
|
|
414
|
+
harnessV1BridgeInterruptInboundSchema,
|
|
405
415
|
harnessV1BridgeShutdownInboundSchema,
|
|
406
416
|
harnessV1BridgeResumeInboundSchema,
|
|
407
417
|
harnessV1BridgeDetachInboundSchema
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/v1/harness-v1-builtin-tool.ts","../src/v1/harness-v1-stream-part.ts","../src/v1/harness-v1-bridge-protocol.ts","../src/v1/harness-v1-diagnostic.ts","../src/v1/harness-v1-tool-filtering.ts","../src/errors/harness-error.ts","../src/errors/harness-capability-unsupported-error.ts"],"sourcesContent":["import { tool, type FlexibleSchema, type Tool } from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\n\n/**\n * Cross-harness vocabulary of common built-in tool names with their baseline\n * input schemas. Adapters that declare a built-in with one of these\n * `commonName`s must accept (at least) every input the baseline schema\n * accepts. Extra optional fields are encouraged.\n *\n * Used both as runtime values (spread into `ToolSet`s for inspection) and as\n * a vocabulary source — `HarnessV1BuiltinToolName` is derived from its keys.\n */\nexport const HARNESS_V1_BUILTIN_TOOLS = {\n read: tool({\n description: 'Read file contents',\n inputSchema: z.object({ file_path: z.string() }),\n outputSchema: z.unknown(),\n }),\n write: tool({\n description: 'Write content to a file',\n inputSchema: z.object({ file_path: z.string(), content: z.string() }),\n outputSchema: z.unknown(),\n }),\n edit: tool({\n description: 'Edit a file by replacing text',\n inputSchema: z.object({\n file_path: z.string(),\n old_string: z.string(),\n new_string: z.string(),\n }),\n outputSchema: z.unknown(),\n }),\n bash: tool({\n description: 'Execute a shell command',\n inputSchema: z.object({ command: z.string() }),\n outputSchema: z.unknown(),\n }),\n grep: tool({\n description: 'Search file contents with regex',\n inputSchema: z.object({ pattern: z.string() }),\n outputSchema: z.unknown(),\n }),\n glob: tool({\n description: 'Find files matching a glob pattern',\n inputSchema: z.object({ pattern: z.string() }),\n outputSchema: z.unknown(),\n }),\n webSearch: tool({\n description: 'Search the web',\n inputSchema: z.object({ query: z.string() }),\n outputSchema: z.unknown(),\n }),\n} as const;\n\nexport type HarnessV1BuiltinToolName = keyof typeof HARNESS_V1_BUILTIN_TOOLS;\n\nexport const HARNESS_V1_BUILTIN_TOOL_NAMES = Object.keys(\n HARNESS_V1_BUILTIN_TOOLS,\n) as ReadonlyArray<HarnessV1BuiltinToolName>;\n\nexport type HarnessV1BuiltinToolUseKind = 'readonly' | 'edit' | 'bash';\n\n/**\n * A tool that the adapter's underlying runtime exposes natively. Extends the\n * AI SDK `Tool` shape with two optional harness-specific fields:\n *\n * - `nativeName`: the name as the underlying runtime knows it. Required\n * only when the tool's key in the harness's `builtinTools` is not the\n * native name — i.e. when the tool maps to a `commonName` (e.g. key\n * `'bash'` for Claude Code's native `'Bash'`). Tools without a common\n * equivalent are keyed by their native name directly, so `nativeName`\n * is redundant and omitted.\n * - `commonName`: cross-harness label drawn from\n * `HARNESS_V1_BUILTIN_TOOL_NAMES`. Set when the tool maps to a familiar\n * capability; consumers use it to recognize, e.g., that Claude Code's\n * `Bash` and Codex's `shell` are the same kind of tool.\n *\n * Always set both fields together via the `commonTool` helper, or neither\n * (declare the tool with the AI SDK's `tool()` directly).\n */\nexport type HarnessV1BuiltinTool<INPUT = unknown, OUTPUT = unknown> = Tool<\n INPUT,\n OUTPUT,\n any\n> & {\n readonly nativeName?: string;\n readonly commonName?: HarnessV1BuiltinToolName;\n readonly toolUseKind?: HarnessV1BuiltinToolUseKind;\n};\n\ntype InputOf<T> = T extends Tool<infer I, any, any> ? I : never;\n\ntype StandardInputOf<N extends HarnessV1BuiltinToolName> = InputOf<\n (typeof HARNESS_V1_BUILTIN_TOOLS)[N]\n>;\n\n/*\n * Type-level superset check. If `TStandard` is assignable to `TAdapter`\n * (i.e. the adapter accepts every input the standard accepts), the return\n * type is `TOk`. Otherwise it's a tagged error tuple that surfaces a clear\n * TypeScript error at the call site.\n */\ntype SupersetCheck<TStandard, TAdapter, TOk> = TStandard extends TAdapter\n ? TOk\n : [\n 'ERROR: adapter input schema must be a superset of the standard schema',\n { expected: TStandard; got: TAdapter },\n ];\n\n/**\n * Declare a built-in tool that maps to a cross-harness common name. The\n * adapter's input schema must accept every input the standard schema for\n * `commonName` accepts. Extra optional fields are encouraged.\n *\n * If the schema is missing a field the standard requires (or has an\n * incompatible type), the return type collapses to a tagged error tuple,\n * which fails the surrounding `as const satisfies ToolSet` assignment and\n * surfaces a readable TypeScript error at the offending entry.\n */\nexport function commonTool<TName extends HarnessV1BuiltinToolName, TInput>(\n commonName: TName,\n opts: {\n readonly nativeName: string;\n readonly toolUseKind?: HarnessV1BuiltinToolUseKind;\n readonly description?: string;\n readonly inputSchema: FlexibleSchema<TInput>;\n },\n): SupersetCheck<StandardInputOf<TName>, TInput, HarnessV1BuiltinTool<TInput>> {\n return {\n ...tool({\n description: opts.description,\n inputSchema: opts.inputSchema as FlexibleSchema<TInput>,\n }),\n nativeName: opts.nativeName,\n commonName,\n toolUseKind: opts.toolUseKind,\n } as never;\n}\n","import type {\n JSONValue,\n LanguageModelV4FinishReason,\n LanguageModelV4ToolApprovalRequest,\n LanguageModelV4ToolCall,\n LanguageModelV4ToolResult,\n LanguageModelV4Usage,\n SharedV4ProviderMetadata,\n} from '@ai-sdk/provider';\nimport { z } from 'zod/v4';\nimport type { HarnessV1CallWarning } from './harness-v1-call-warning';\nimport type { HarnessV1Metadata } from './harness-v1-metadata';\n\n/**\n * One event emitted by a harness adapter during a prompt turn.\n *\n * Mirrors `LanguageModelV4StreamPart` on the variants it shares so a\n * `HarnessAgent` can pipe events through to AI SDK consumers with minimal\n * translation. Primitive types from the V4 spec (`LanguageModelV4ToolCall`,\n * `LanguageModelV4ToolResult`, `LanguageModelV4ToolApprovalRequest`,\n * `LanguageModelV4Usage`, `LanguageModelV4FinishReason`) are reused\n * verbatim — type-compat tests assert this stays the case.\n *\n * The metadata field is named `harnessMetadata` (not `providerMetadata`)\n * because a harness is a peer to a provider, not a kind of provider. The\n * agent rebinds it when forwarding to AI SDK consumers.\n */\nexport type HarnessV1StreamPart =\n | {\n type: 'stream-start';\n warnings?: ReadonlyArray<HarnessV1CallWarning>;\n /**\n * The model the runtime actually resolved to for this turn, when the\n * adapter learns it at stream start (e.g. Claude Code's `init` message\n * reports the resolved/default model). Surfaced into telemetry as\n * `gen_ai.request.model`. Omitted when the adapter doesn't know it here.\n */\n modelId?: string;\n }\n\n // Text blocks\n | { type: 'text-start'; id: string; harnessMetadata?: HarnessV1Metadata }\n | {\n type: 'text-delta';\n id: string;\n delta: string;\n harnessMetadata?: HarnessV1Metadata;\n }\n | { type: 'text-end'; id: string; harnessMetadata?: HarnessV1Metadata }\n\n // Reasoning blocks\n | { type: 'reasoning-start'; id: string; harnessMetadata?: HarnessV1Metadata }\n | {\n type: 'reasoning-delta';\n id: string;\n delta: string;\n harnessMetadata?: HarnessV1Metadata;\n }\n | { type: 'reasoning-end'; id: string; harnessMetadata?: HarnessV1Metadata }\n\n // Tool calls, approvals, results — reuse V4 primitives.\n //\n // `nativeName` is the only harness-only extension on `tool-call`. It lets\n // adapters surface the runtime's native name for a builtin when it differs\n // from the wire `toolName` (e.g. `toolName: 'bash'`, `nativeName: 'Bash'`).\n //\n // Whether the call was executed by the underlying runtime (Claude Code's\n // built-in `Bash`, Codex's `shell`) vs. needs host dispatch is signalled by\n // the standard `providerExecuted` field on `LanguageModelV4ToolCall` —\n // `true` for runtime-executed builtins, false/undefined for host tools.\n | (LanguageModelV4ToolCall & {\n nativeName?: string;\n })\n | LanguageModelV4ToolApprovalRequest\n | LanguageModelV4ToolResult\n\n // Step boundary inside a multi-step turn.\n | {\n type: 'finish-step';\n finishReason: LanguageModelV4FinishReason;\n usage: LanguageModelV4Usage;\n harnessMetadata?: HarnessV1Metadata;\n }\n\n // Turn end.\n | {\n type: 'finish';\n finishReason: LanguageModelV4FinishReason;\n totalUsage: LanguageModelV4Usage;\n harnessMetadata?: HarnessV1Metadata;\n }\n\n // Workspace file mutation that occurred through an opaque underlying\n // mechanism (one with no visible `tool-call` carrying the same data, e.g.\n // Codex's internal `apply_patch`). Emitted per changed path. Path-only by\n // design — when the mutation goes through a visible tool call, the\n // tool-call/tool-result pair already carries the information.\n | {\n type: 'file-change';\n event: 'create' | 'modify' | 'delete';\n path: string;\n harnessMetadata?: HarnessV1Metadata;\n }\n\n // Context compaction performed by the underlying runtime (Claude Code's\n // native compaction, Pi's summarization). Observation only — the runtime\n // owns the compaction; the harness neither implements nor schedules it.\n // Emitted once, on completion, since `summary`/`tokensAfter` only exist then.\n | {\n type: 'compaction';\n trigger: 'manual' | 'auto';\n summary: string;\n tokensBefore?: number;\n tokensAfter?: number;\n harnessMetadata?: HarnessV1Metadata;\n }\n\n // Errors. Multiple may be emitted in a single turn.\n | { type: 'error'; error: unknown }\n\n // Adapter-specific passthrough. Consumers can opt in to receive these via\n // `HarnessAgent` settings; otherwise they are dropped.\n | { type: 'raw'; rawValue: unknown };\n\n/*\n * Runtime (Zod) encoding of `HarnessV1StreamPart`.\n *\n * `HarnessV1StreamPart` is a compile-time type built on `LanguageModelV4*`\n * types that ship no runtime validator. Bridge adapters receive these parts as\n * JSON across a trust boundary (the sandbox WebSocket), so they need a runtime\n * schema. These schemas ARE that encoding — one source of truth, kept from\n * diverging from the type by the `_assignable` guard below and the mutual\n * `toEqualTypeOf` assertion in `harness-v1-stream-part.test-d.ts`.\n *\n * Members are exported individually so `harness-v1-bridge-protocol.ts` can\n * compose them into the bridge outbound union alongside the transport frames.\n */\n\nconst harnessV1JsonValueSchema: z.ZodType<JSONValue> = z.lazy(() =>\n z.union([\n z.string(),\n z.number(),\n z.boolean(),\n z.null(),\n z.array(harnessV1JsonValueSchema),\n z.record(z.string(), harnessV1JsonValueSchema),\n ]),\n);\n\n/*\n * Tool-result values. The inferred type is the spec's `NonNullable<JSONValue>`\n * (matching `LanguageModelV4ToolResult`), but the runtime validator\n * deliberately also accepts `null`: adapters emit `result: <value> ?? null` for\n * tools that produced no output, and that `null` must survive the trust\n * boundary unchanged (it reaches consumers exactly as it did before this schema\n * existed, when a cast hid it). Leniency at runtime, strictness in the type.\n */\nconst harnessV1ToolResultValueSchema =\n harnessV1JsonValueSchema as unknown as z.ZodType<NonNullable<JSONValue>>;\n\nconst harnessV1JsonObjectSchema = z.record(\n z.string(),\n harnessV1JsonValueSchema,\n) as unknown as z.ZodType<Record<string, JSONValue>>;\n\nconst harnessV1MetadataSchema = z.record(\n z.string(),\n z.record(z.string(), harnessV1JsonValueSchema),\n) as unknown as z.ZodType<HarnessV1Metadata>;\n\nconst harnessV1ProviderMetadataSchema = z.record(\n z.string(),\n z.record(z.string(), harnessV1JsonValueSchema),\n) as unknown as z.ZodType<SharedV4ProviderMetadata>;\n\nconst harnessV1CallWarningSchema = z.union([\n z.object({\n type: z.literal('unsupported-setting'),\n setting: z.string(),\n details: z.string().optional(),\n }),\n z.object({\n type: z.literal('unsupported-tool'),\n tool: z.string(),\n details: z.string().optional(),\n }),\n z.object({ type: z.literal('other'), message: z.string() }),\n]) as z.ZodType<HarnessV1CallWarning>;\n\nconst harnessV1UsageSchema = z.object({\n inputTokens: z.object({\n total: z.number().optional(),\n noCache: z.number().optional(),\n cacheRead: z.number().optional(),\n cacheWrite: z.number().optional(),\n }),\n outputTokens: z.object({\n total: z.number().optional(),\n text: z.number().optional(),\n reasoning: z.number().optional(),\n }),\n raw: harnessV1JsonObjectSchema.optional(),\n}) as unknown as z.ZodType<LanguageModelV4Usage>;\n\nconst harnessV1FinishReasonSchema = z.object({\n unified: z.enum([\n 'stop',\n 'length',\n 'content-filter',\n 'tool-calls',\n 'error',\n 'other',\n ]),\n raw: z.string().optional(),\n}) as unknown as z.ZodType<LanguageModelV4FinishReason>;\n\nexport const harnessV1StreamStartPartSchema = z.object({\n type: z.literal('stream-start'),\n warnings: z.array(harnessV1CallWarningSchema).readonly().optional(),\n modelId: z.string().optional(),\n});\n\nexport const harnessV1TextStartPartSchema = z.object({\n type: z.literal('text-start'),\n id: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1TextDeltaPartSchema = z.object({\n type: z.literal('text-delta'),\n id: z.string(),\n delta: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1TextEndPartSchema = z.object({\n type: z.literal('text-end'),\n id: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1ReasoningStartPartSchema = z.object({\n type: z.literal('reasoning-start'),\n id: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1ReasoningDeltaPartSchema = z.object({\n type: z.literal('reasoning-delta'),\n id: z.string(),\n delta: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1ReasoningEndPartSchema = z.object({\n type: z.literal('reasoning-end'),\n id: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1ToolCallPartSchema = z.object({\n type: z.literal('tool-call'),\n toolCallId: z.string(),\n toolName: z.string(),\n input: z.string(),\n providerExecuted: z.boolean().optional(),\n dynamic: z.boolean().optional(),\n providerMetadata: harnessV1ProviderMetadataSchema.optional(),\n nativeName: z.string().optional(),\n});\n\nexport const harnessV1ToolApprovalRequestPartSchema = z.object({\n type: z.literal('tool-approval-request'),\n approvalId: z.string(),\n toolCallId: z.string(),\n providerMetadata: harnessV1ProviderMetadataSchema.optional(),\n});\n\nexport const harnessV1ToolResultPartSchema = z.object({\n type: z.literal('tool-result'),\n toolCallId: z.string(),\n toolName: z.string(),\n result: harnessV1ToolResultValueSchema,\n isError: z.boolean().optional(),\n preliminary: z.boolean().optional(),\n dynamic: z.boolean().optional(),\n providerMetadata: harnessV1ProviderMetadataSchema.optional(),\n});\n\nexport const harnessV1FinishStepPartSchema = z.object({\n type: z.literal('finish-step'),\n finishReason: harnessV1FinishReasonSchema,\n usage: harnessV1UsageSchema,\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1FinishPartSchema = z.object({\n type: z.literal('finish'),\n finishReason: harnessV1FinishReasonSchema,\n totalUsage: harnessV1UsageSchema,\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1FileChangePartSchema = z.object({\n type: z.literal('file-change'),\n event: z.enum(['create', 'modify', 'delete']),\n path: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1CompactionPartSchema = z.object({\n type: z.literal('compaction'),\n trigger: z.enum(['manual', 'auto']),\n summary: z.string(),\n tokensBefore: z.number().optional(),\n tokensAfter: z.number().optional(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1ErrorPartSchema = z.object({\n type: z.literal('error'),\n error: z.unknown(),\n});\n\nexport const harnessV1RawPartSchema = z.object({\n type: z.literal('raw'),\n rawValue: z.unknown(),\n});\n\n/**\n * Assembled discriminated union over every `HarnessV1StreamPart` variant. Left\n * un-annotated so it keeps its precise inferred type — the protocol layer\n * composes the individual member schemas, and the type test asserts the\n * inferred union equals `HarnessV1StreamPart`.\n */\nexport const harnessV1StreamPartSchema = z.discriminatedUnion('type', [\n harnessV1StreamStartPartSchema,\n harnessV1TextStartPartSchema,\n harnessV1TextDeltaPartSchema,\n harnessV1TextEndPartSchema,\n harnessV1ReasoningStartPartSchema,\n harnessV1ReasoningDeltaPartSchema,\n harnessV1ReasoningEndPartSchema,\n harnessV1ToolCallPartSchema,\n harnessV1ToolApprovalRequestPartSchema,\n harnessV1ToolResultPartSchema,\n harnessV1FinishStepPartSchema,\n harnessV1FinishPartSchema,\n harnessV1FileChangePartSchema,\n harnessV1CompactionPartSchema,\n harnessV1ErrorPartSchema,\n harnessV1RawPartSchema,\n]);\n\n/*\n * Fail-fast guard at the definition site: the schema's output must be\n * assignable to `HarnessV1StreamPart` (catches a schema variant inventing a\n * shape the type does not allow). The reverse direction — the type being a\n * subset of the schema — is covered by the `toEqualTypeOf` assertion in the\n * type test.\n */\nconst _assignable: z.ZodType<HarnessV1StreamPart> = harnessV1StreamPartSchema;\nvoid _assignable;\n","import { z } from 'zod/v4';\nimport {\n harnessV1DebugConfigSchema,\n harnessV1DebugLevelSchema,\n type HarnessV1Diagnostic,\n} from './harness-v1-diagnostic';\nimport {\n harnessV1CompactionPartSchema,\n harnessV1ErrorPartSchema,\n harnessV1FileChangePartSchema,\n harnessV1FinishPartSchema,\n harnessV1FinishStepPartSchema,\n harnessV1RawPartSchema,\n harnessV1ReasoningDeltaPartSchema,\n harnessV1ReasoningEndPartSchema,\n harnessV1ReasoningStartPartSchema,\n harnessV1StreamStartPartSchema,\n harnessV1TextDeltaPartSchema,\n harnessV1TextEndPartSchema,\n harnessV1TextStartPartSchema,\n harnessV1ToolApprovalRequestPartSchema,\n harnessV1ToolCallPartSchema,\n harnessV1ToolResultPartSchema,\n} from './harness-v1-stream-part';\n\n/*\n * The bridge wire protocol shared by every bridge-backed harness adapter.\n *\n * This is the serialization of the host<->runtime contract for adapters that\n * run the agent runtime inside the sandbox and talk to the host over a\n * WebSocket. It exists ONLY because of that transport: untrusted JSON frames\n * crossing the sandbox boundary need runtime validation, the connection needs\n * a handshake, and the host drives turns with serialized commands. Every export\n * here is therefore prefixed `harnessV1Bridge…`.\n *\n * It has three tiers:\n *\n * 1. The OUTBOUND events — `HarnessV1StreamPart` re-expressed as Zod (imported\n * member schemas from `harness-v1-stream-part.ts`), because the part type is\n * compile-time only and the frames need runtime validation at the boundary.\n * 2. The transport/control frames that are NOT consumer events — `bridge-hello`\n * (handshake), `bridge-detach` (resume payload), `bridge-thread` (a resume\n * coordinate some runtimes announce). These ride the same socket.\n * 3. The INBOUND command vocabulary the host sends back: the shared commands\n * live here; the per-adapter `start` payload extends\n * `harnessV1BridgeStartBaseSchema` and assembles the final inbound union in\n * the adapter package.\n *\n * Non-bridge adapters (e.g. Pi) do not use this layer at all — they have no\n * serialization boundary and target the universal `HarnessV1StreamPart` type\n * directly. That is the deliberate split: `harness-v1-stream-part.ts` is the\n * transport-agnostic event vocabulary; this file is the bridge transport.\n */\n\n/**\n * The subset of a host-defined tool that travels on the `start` message. The\n * runtime only needs the name, description, and JSON-Schema input to surface\n * the tool; `execute` stays on the host.\n */\nexport const harnessV1BridgeToolWireSchema = z.object({\n name: z.string(),\n description: z.string().optional(),\n inputSchema: z.unknown().optional(),\n});\n\nexport type HarnessV1BridgeToolWire = z.infer<\n typeof harnessV1BridgeToolWireSchema\n>;\n\nexport const harnessV1BridgePermissionModeSchema = z.enum([\n 'allow-reads',\n 'allow-edits',\n 'allow-all',\n]);\n\nexport const harnessV1BridgeBuiltinToolFilteringSchema = z.discriminatedUnion(\n 'mode',\n [\n z.object({\n mode: z.literal('allow'),\n toolNames: z.array(z.string()),\n }),\n z.object({\n mode: z.literal('deny'),\n toolNames: z.array(z.string()),\n }),\n ],\n);\n\n/**\n * Common fields of the inbound `start` message. Each adapter extends this with\n * its runtime-specific configuration (e.g. `thinking`/`continue` for Claude\n * Code, `reasoningEffort`/`webSearch`/`skills`/`resumeThreadId` for Codex) and\n * assembles the final inbound union from the shared command members below.\n *\n * `debug` carries the general `HarnessV1DebugConfig` — diagnostics config is not\n * a bridge concept, it just happens to ride the `start` frame for bridge-backed\n * adapters.\n */\nexport const harnessV1BridgeStartBaseSchema = z.object({\n type: z.literal('start'),\n prompt: z.string(),\n tools: z.array(harnessV1BridgeToolWireSchema).optional(),\n model: z.string().optional(),\n debug: harnessV1DebugConfigSchema.optional(),\n permissionMode: harnessV1BridgePermissionModeSchema.optional(),\n builtinToolFiltering: harnessV1BridgeBuiltinToolFilteringSchema.optional(),\n});\n\n// --- Transport / control frames (outbound, not consumer events) ---\n\n/**\n * Sent the instant the bridge accepts an authenticated WS connection. The host\n * waits for it before sending `start`/`resume`, because some sandbox runtimes\n * complete the upstream WS handshake before the connection is wired through to\n * the bridge process — anything sent in that gap is dropped. Carries the\n * bridge's lifecycle `state` and highest emitted `seq` for reconnect.\n */\nexport const harnessV1BridgeHelloSchema = z.object({\n type: z.literal('bridge-hello'),\n state: z.string().optional(),\n lastSeq: z.number().optional(),\n});\n\n/**\n * The bridge's reply to an inbound `detach`. Carries the adapter-specific\n * payload the host serializes into lifecycle state `data`.\n */\nexport const harnessV1BridgeDetachSchema = z.object({\n type: z.literal('bridge-detach'),\n data: z.unknown(),\n});\n\n/**\n * A resume coordinate the bridge proactively announces (e.g. Codex's thread id)\n * so the host can cache it for a later resume without waiting for `detach`.\n */\nexport const harnessV1BridgeThreadSchema = z.object({\n type: z.literal('bridge-thread'),\n threadId: z.string(),\n});\n\n// --- Diagnostics frames (outbound, not consumer events) ---\n\n/**\n * One captured console line from inside the sandbox. The bridge line-buffers\n * `process.stdout`/`process.stderr` and emits one of these per complete line.\n * Routed host-side to the diagnostics sink, never to the consumer stream.\n */\nexport const harnessV1BridgeSandboxLogSchema = z.object({\n type: z.literal('sandbox-log'),\n source: z.string(),\n stream: z.enum(['stdout', 'stderr']),\n line: z.string(),\n});\n\n/**\n * A structured diagnostic an adapter emits from inside the bridge via\n * `turn.bridgeLog(...)`. Gated by the session's debug level + subsystem filter.\n */\nexport const harnessV1BridgeDebugEventSchema = z.object({\n type: z.literal('debug-event'),\n level: harnessV1DebugLevelSchema,\n subsystem: z.string(),\n message: z.string(),\n attrs: z.record(z.string(), z.unknown()).optional(),\n error: z\n .object({\n name: z.string().optional(),\n message: z.string(),\n stack: z.string().optional(),\n })\n .optional(),\n});\n\n/**\n * Every frame a bridge can send to the host: the stream-part events plus the\n * transport/control frames. This is the schema the host `SandboxChannel`\n * validates inbound frames against.\n */\nexport const harnessV1BridgeOutboundMessageSchema = z.discriminatedUnion(\n 'type',\n [\n harnessV1StreamStartPartSchema,\n harnessV1TextStartPartSchema,\n harnessV1TextDeltaPartSchema,\n harnessV1TextEndPartSchema,\n harnessV1ReasoningStartPartSchema,\n harnessV1ReasoningDeltaPartSchema,\n harnessV1ReasoningEndPartSchema,\n harnessV1ToolCallPartSchema,\n harnessV1ToolApprovalRequestPartSchema,\n harnessV1ToolResultPartSchema,\n harnessV1FinishStepPartSchema,\n harnessV1FinishPartSchema,\n harnessV1FileChangePartSchema,\n harnessV1CompactionPartSchema,\n harnessV1ErrorPartSchema,\n harnessV1RawPartSchema,\n harnessV1BridgeHelloSchema,\n harnessV1BridgeDetachSchema,\n harnessV1BridgeThreadSchema,\n harnessV1BridgeSandboxLogSchema,\n harnessV1BridgeDebugEventSchema,\n ],\n);\n\nexport type HarnessV1BridgeOutboundMessage = z.infer<\n typeof harnessV1BridgeOutboundMessageSchema\n>;\n\nexport type HarnessV1BridgeSandboxLog = z.infer<\n typeof harnessV1BridgeSandboxLogSchema\n>;\n\nexport type HarnessV1BridgeDebugEvent = z.infer<\n typeof harnessV1BridgeDebugEventSchema\n>;\n\n/**\n * Normalize a bridge diagnostics wire frame into the transport-agnostic\n * `HarnessV1Diagnostic` an adapter reports to the framework. A captured console\n * line maps `stderr` → `warn` and `stdout` → `info`; a structured event passes\n * its fields through. This is the seam where the bridge's serialization is\n * lifted into the general emission shape every harness shares.\n */\nexport function harnessV1DiagnosticFromBridgeFrame(\n frame: HarnessV1BridgeSandboxLog | HarnessV1BridgeDebugEvent,\n context: { sessionId?: string; timestamp: number },\n): HarnessV1Diagnostic {\n if (frame.type === 'sandbox-log') {\n return {\n level: frame.stream === 'stderr' ? 'warn' : 'info',\n message: frame.line,\n subsystem: `sandbox.log.${frame.source}`,\n kind: 'log',\n source: frame.source,\n stream: frame.stream,\n sessionId: context.sessionId,\n timestamp: context.timestamp,\n };\n }\n return {\n level: frame.level,\n message: frame.message,\n subsystem: frame.subsystem,\n kind: 'event',\n attrs: frame.attrs,\n error: frame.error,\n sessionId: context.sessionId,\n timestamp: context.timestamp,\n };\n}\n\n// --- Shared inbound command members (host -> bridge) ---\n\nexport const harnessV1BridgeToolResultInboundSchema = z.object({\n type: z.literal('tool-result'),\n toolCallId: z.string(),\n output: z.unknown(),\n isError: z.boolean().optional(),\n});\n\nexport const harnessV1BridgeToolApprovalResponseInboundSchema = z.object({\n type: z.literal('tool-approval-response'),\n approvalId: z.string(),\n approved: z.boolean(),\n reason: z.string().optional(),\n});\n\nexport const harnessV1BridgeUserMessageInboundSchema = z.object({\n type: z.literal('user-message'),\n text: z.string(),\n});\n\nexport const harnessV1BridgeAbortInboundSchema = z.object({\n type: z.literal('abort'),\n});\n\nexport const harnessV1BridgeShutdownInboundSchema = z.object({\n type: z.literal('shutdown'),\n});\n\n/**\n * Reconnect: after re-establishing the socket the host asks the bridge to\n * replay every buffered event with `seq > lastSeenEventId`.\n */\nexport const harnessV1BridgeResumeInboundSchema = z.object({\n type: z.literal('resume'),\n lastSeenEventId: z.number(),\n});\n\n/**\n * The bridge replies with `bridge-detach` carrying any cached resume payload,\n * then exits.\n */\nexport const harnessV1BridgeDetachInboundSchema = z.object({\n type: z.literal('detach'),\n});\n\n/**\n * The inbound command members shared by every bridge adapter. Spread these\n * alongside the adapter's own `start` schema to build the final inbound union:\n * `z.discriminatedUnion('type', [adapterStartSchema, ...harnessV1BridgeInboundCommandSchemas])`.\n */\nexport const harnessV1BridgeInboundCommandSchemas = [\n harnessV1BridgeToolResultInboundSchema,\n harnessV1BridgeToolApprovalResponseInboundSchema,\n harnessV1BridgeUserMessageInboundSchema,\n harnessV1BridgeAbortInboundSchema,\n harnessV1BridgeShutdownInboundSchema,\n harnessV1BridgeResumeInboundSchema,\n harnessV1BridgeDetachInboundSchema,\n] as const;\n\n/**\n * The JSON line the bridge writes to stdout once its WebSocket server is bound,\n * announcing the port the host should connect to.\n */\nexport const harnessV1BridgeReadySchema = z.object({\n type: z.literal('bridge-ready'),\n port: z.number(),\n});\n\nexport type HarnessV1BridgeReady = z.infer<typeof harnessV1BridgeReadySchema>;\n","import { z } from 'zod/v4';\n\n/*\n * Diagnostics EMISSION contract — part of the `HarnessV1` spec.\n *\n * These are the types a harness adapter produces and receives: an adapter\n * reports a `HarnessV1Diagnostic` to the framework (a bridge adapter normalizes\n * its wire frames into one; a non-bridge adapter constructs one directly), and\n * receives a `HarnessV1DebugConfig` to gate what it emits. They are distinct\n * from the unaffixed host-facing `HarnessDiagnostic` / `HarnessDebugConfig`\n * (the external/telemetry surface) — the framework maps between the two at the\n * boundary, so the emission and consumption surfaces can evolve independently.\n */\n\n/** Severity of a diagnostic, ordered most → least severe. */\nexport const harnessV1DebugLevelSchema = z.enum([\n 'error',\n 'warn',\n 'info',\n 'debug',\n 'trace',\n]);\n\nexport type HarnessV1DebugLevel = z.infer<typeof harnessV1DebugLevelSchema>;\n\n/**\n * Per-session diagnostics configuration the framework hands an adapter (and the\n * host sends on `start.debug`). When absent or `enabled` is false the adapter\n * captures and emits nothing. `subsystems` filters structured events by dotted\n * prefix; console capture is independent of the subsystem filter.\n */\nexport const harnessV1DebugConfigSchema = z.object({\n enabled: z.boolean().optional(),\n level: harnessV1DebugLevelSchema.optional(),\n subsystems: z.array(z.string()).optional(),\n});\n\nexport type HarnessV1DebugConfig = z.infer<typeof harnessV1DebugConfigSchema>;\n\n/**\n * A diagnostic as emitted by a harness adapter. Structurally identical to the\n * host-facing `HarnessDiagnostic` today, but kept separate: this is the spec's\n * emission shape, that is the external consumption shape.\n */\nexport type HarnessV1Diagnostic = {\n /** Severity. */\n readonly level: HarnessV1DebugLevel;\n /** Human-readable line (console capture) or message (structured event). */\n readonly message: string;\n /** Dotted subsystem (`sandbox.log.<source>` for console capture). */\n readonly subsystem: string;\n /** `'log'` = captured console line; `'event'` = structured emission. */\n readonly kind: 'log' | 'event';\n /** Originating source label (console capture). */\n readonly source?: string;\n /** Which standard stream the line came from (console capture). */\n readonly stream?: 'stdout' | 'stderr';\n /** Structured attributes (structured events only). */\n readonly attrs?: Record<string, unknown>;\n /** Error payload (structured events only). */\n readonly error?: { name?: string; message: string; stack?: string };\n /** The harness session this diagnostic originated from. */\n readonly sessionId?: string;\n /** Emission time (epoch ms). */\n readonly timestamp: number;\n};\n","export type HarnessV1BuiltinToolFiltering =\n | {\n mode: 'allow';\n toolNames: string[];\n }\n | {\n mode: 'deny';\n toolNames: string[];\n };\n\nexport function isHarnessV1BuiltinToolIncluded(input: {\n toolName: string;\n toolFiltering: HarnessV1BuiltinToolFiltering | undefined;\n}): boolean {\n if (input.toolFiltering == null) return true;\n return input.toolFiltering.mode === 'allow'\n ? input.toolFiltering.toolNames.includes(input.toolName)\n : !input.toolFiltering.toolNames.includes(input.toolName);\n}\n\nexport function getHarnessV1BuiltinToolFilteringDenialReason(input: {\n toolName: string;\n}): string {\n return `Tool '${input.toolName}' is inactive due to the HarnessAgent tool filtering policy.`;\n}\n","import { AISDKError } from '@ai-sdk/provider';\n\nconst name = 'AI_HarnessError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\n * Base error type for failures originating in or signalled by a harness\n * adapter. Specific failure modes (e.g. unsupported capability) extend this\n * class.\n */\nexport class HarnessError extends AISDKError {\n private readonly [symbol] = true;\n\n constructor({ message, cause }: { message: string; cause?: unknown }) {\n super({ name, message, cause });\n }\n\n static isInstance(error: unknown): error is HarnessError {\n return AISDKError.hasMarker(error, marker);\n }\n}\n","import { AISDKError } from '@ai-sdk/provider';\nimport { HarnessError } from './harness-error';\n\nconst name = 'AI_HarnessCapabilityUnsupportedError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\n * Thrown when a caller asks the harness to do something the adapter (or the\n * supplied sandbox) does not support, e.g. requesting manual compaction from\n * an adapter that only auto-compacts, or invoking `getPortUrl` on a sandbox\n * that does not expose one.\n *\n * The caller supplies the full human-readable message. Optional `harnessId`\n * is recorded as structured context for tooling.\n */\nexport class HarnessCapabilityUnsupportedError extends HarnessError {\n private readonly [symbol] = true;\n\n readonly harnessId?: string;\n\n constructor({\n message,\n harnessId,\n cause,\n }: {\n message: string;\n harnessId?: string;\n cause?: unknown;\n }) {\n super({ message, cause });\n Object.defineProperty(this, 'name', { value: name });\n this.harnessId = harnessId;\n }\n\n static isInstance(\n error: unknown,\n ): error is HarnessCapabilityUnsupportedError {\n return AISDKError.hasMarker(error, marker);\n }\n}\n"],"mappings":"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","names":["z","z","z","z","AISDKError","name","marker","symbol","_a","_b","AISDKError"]}
|
|
1
|
+
{"version":3,"sources":["../src/v1/harness-v1-builtin-tool.ts","../src/v1/harness-v1-stream-part.ts","../src/v1/harness-v1-bridge-protocol.ts","../src/v1/harness-v1-diagnostic.ts","../src/v1/harness-v1-tool-filtering.ts","../src/errors/harness-error.ts","../src/errors/harness-capability-unsupported-error.ts"],"sourcesContent":["import { tool, type FlexibleSchema, type Tool } from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\n\n/**\n * Cross-harness vocabulary of common built-in tool names with their baseline\n * input schemas. Adapters that declare a built-in with one of these\n * `commonName`s must accept (at least) every input the baseline schema\n * accepts. Extra optional fields are encouraged.\n *\n * Used both as runtime values (spread into `ToolSet`s for inspection) and as\n * a vocabulary source — `HarnessV1BuiltinToolName` is derived from its keys.\n */\nexport const HARNESS_V1_BUILTIN_TOOLS = {\n read: tool({\n description: 'Read file contents',\n inputSchema: z.object({ file_path: z.string() }),\n outputSchema: z.unknown(),\n }),\n write: tool({\n description: 'Write content to a file',\n inputSchema: z.object({ file_path: z.string(), content: z.string() }),\n outputSchema: z.unknown(),\n }),\n edit: tool({\n description: 'Edit a file by replacing text',\n inputSchema: z.object({\n file_path: z.string(),\n old_string: z.string(),\n new_string: z.string(),\n }),\n outputSchema: z.unknown(),\n }),\n bash: tool({\n description: 'Execute a shell command',\n inputSchema: z.object({ command: z.string() }),\n outputSchema: z.unknown(),\n }),\n grep: tool({\n description: 'Search file contents with regex',\n inputSchema: z.object({ pattern: z.string() }),\n outputSchema: z.unknown(),\n }),\n glob: tool({\n description: 'Find files matching a glob pattern',\n inputSchema: z.object({ pattern: z.string() }),\n outputSchema: z.unknown(),\n }),\n webSearch: tool({\n description: 'Search the web',\n inputSchema: z.object({ query: z.string() }),\n outputSchema: z.unknown(),\n }),\n} as const;\n\nexport type HarnessV1BuiltinToolName = keyof typeof HARNESS_V1_BUILTIN_TOOLS;\n\nexport const HARNESS_V1_BUILTIN_TOOL_NAMES = Object.keys(\n HARNESS_V1_BUILTIN_TOOLS,\n) as ReadonlyArray<HarnessV1BuiltinToolName>;\n\nexport type HarnessV1BuiltinToolUseKind = 'readonly' | 'edit' | 'bash';\n\n/**\n * A tool that the adapter's underlying runtime exposes natively. Extends the\n * AI SDK `Tool` shape with two optional harness-specific fields:\n *\n * - `nativeName`: the name as the underlying runtime knows it. Required\n * only when the tool's key in the harness's `builtinTools` is not the\n * native name — i.e. when the tool maps to a `commonName` (e.g. key\n * `'bash'` for Claude Code's native `'Bash'`). Tools without a common\n * equivalent are keyed by their native name directly, so `nativeName`\n * is redundant and omitted.\n * - `commonName`: cross-harness label drawn from\n * `HARNESS_V1_BUILTIN_TOOL_NAMES`. Set when the tool maps to a familiar\n * capability; consumers use it to recognize, e.g., that Claude Code's\n * `Bash` and Codex's `shell` are the same kind of tool.\n *\n * Always set both fields together via the `commonTool` helper, or neither\n * (declare the tool with the AI SDK's `tool()` directly).\n */\nexport type HarnessV1BuiltinTool<INPUT = unknown, OUTPUT = unknown> = Tool<\n INPUT,\n OUTPUT,\n any\n> & {\n readonly nativeName?: string;\n readonly commonName?: HarnessV1BuiltinToolName;\n readonly toolUseKind?: HarnessV1BuiltinToolUseKind;\n};\n\ntype InputOf<T> = T extends Tool<infer I, any, any> ? I : never;\n\ntype StandardInputOf<N extends HarnessV1BuiltinToolName> = InputOf<\n (typeof HARNESS_V1_BUILTIN_TOOLS)[N]\n>;\n\n/*\n * Type-level superset check. If `TStandard` is assignable to `TAdapter`\n * (i.e. the adapter accepts every input the standard accepts), the return\n * type is `TOk`. Otherwise it's a tagged error tuple that surfaces a clear\n * TypeScript error at the call site.\n */\ntype SupersetCheck<TStandard, TAdapter, TOk> = TStandard extends TAdapter\n ? TOk\n : [\n 'ERROR: adapter input schema must be a superset of the standard schema',\n { expected: TStandard; got: TAdapter },\n ];\n\n/**\n * Declare a built-in tool that maps to a cross-harness common name. The\n * adapter's input schema must accept every input the standard schema for\n * `commonName` accepts. Extra optional fields are encouraged.\n *\n * If the schema is missing a field the standard requires (or has an\n * incompatible type), the return type collapses to a tagged error tuple,\n * which fails the surrounding `as const satisfies ToolSet` assignment and\n * surfaces a readable TypeScript error at the offending entry.\n */\nexport function commonTool<TName extends HarnessV1BuiltinToolName, TInput>(\n commonName: TName,\n opts: {\n readonly nativeName: string;\n readonly toolUseKind?: HarnessV1BuiltinToolUseKind;\n readonly description?: string;\n readonly inputSchema: FlexibleSchema<TInput>;\n },\n): SupersetCheck<StandardInputOf<TName>, TInput, HarnessV1BuiltinTool<TInput>> {\n return {\n ...tool({\n description: opts.description,\n inputSchema: opts.inputSchema as FlexibleSchema<TInput>,\n }),\n nativeName: opts.nativeName,\n commonName,\n toolUseKind: opts.toolUseKind,\n } as never;\n}\n","import type {\n JSONValue,\n LanguageModelV4FinishReason,\n LanguageModelV4ToolApprovalRequest,\n LanguageModelV4ToolCall,\n LanguageModelV4ToolResult,\n LanguageModelV4Usage,\n SharedV4ProviderMetadata,\n} from '@ai-sdk/provider';\nimport { z } from 'zod/v4';\nimport type { HarnessV1CallWarning } from './harness-v1-call-warning';\nimport type { HarnessV1Metadata } from './harness-v1-metadata';\n\n/**\n * One event emitted by a harness adapter during a prompt turn.\n *\n * Mirrors `LanguageModelV4StreamPart` on the variants it shares so a\n * `HarnessAgent` can pipe events through to AI SDK consumers with minimal\n * translation. Primitive types from the V4 spec (`LanguageModelV4ToolCall`,\n * `LanguageModelV4ToolResult`, `LanguageModelV4ToolApprovalRequest`,\n * `LanguageModelV4Usage`, `LanguageModelV4FinishReason`) are reused\n * verbatim — type-compat tests assert this stays the case.\n *\n * The metadata field is named `harnessMetadata` (not `providerMetadata`)\n * because a harness is a peer to a provider, not a kind of provider. The\n * agent rebinds it when forwarding to AI SDK consumers.\n */\nexport type HarnessV1StreamPart =\n | {\n type: 'stream-start';\n warnings?: ReadonlyArray<HarnessV1CallWarning>;\n /**\n * The model the runtime actually resolved to for this turn, when the\n * adapter learns it at stream start (e.g. Claude Code's `init` message\n * reports the resolved/default model). Surfaced into telemetry as\n * `gen_ai.request.model`. Omitted when the adapter doesn't know it here.\n */\n modelId?: string;\n }\n\n // Text blocks\n | { type: 'text-start'; id: string; harnessMetadata?: HarnessV1Metadata }\n | {\n type: 'text-delta';\n id: string;\n delta: string;\n harnessMetadata?: HarnessV1Metadata;\n }\n | { type: 'text-end'; id: string; harnessMetadata?: HarnessV1Metadata }\n\n // Reasoning blocks\n | { type: 'reasoning-start'; id: string; harnessMetadata?: HarnessV1Metadata }\n | {\n type: 'reasoning-delta';\n id: string;\n delta: string;\n harnessMetadata?: HarnessV1Metadata;\n }\n | { type: 'reasoning-end'; id: string; harnessMetadata?: HarnessV1Metadata }\n\n // Tool calls, approvals, results — reuse V4 primitives.\n //\n // `nativeName` is the only harness-only extension on `tool-call`. It lets\n // adapters surface the runtime's native name for a builtin when it differs\n // from the wire `toolName` (e.g. `toolName: 'bash'`, `nativeName: 'Bash'`).\n //\n // Whether the call was executed by the underlying runtime (Claude Code's\n // built-in `Bash`, Codex's `shell`) vs. needs host dispatch is signalled by\n // the standard `providerExecuted` field on `LanguageModelV4ToolCall` —\n // `true` for runtime-executed builtins, false/undefined for host tools.\n | (LanguageModelV4ToolCall & {\n nativeName?: string;\n })\n | LanguageModelV4ToolApprovalRequest\n | LanguageModelV4ToolResult\n\n // Step boundary inside a multi-step turn.\n | {\n type: 'finish-step';\n finishReason: LanguageModelV4FinishReason;\n usage: LanguageModelV4Usage;\n harnessMetadata?: HarnessV1Metadata;\n }\n\n // Turn end.\n | {\n type: 'finish';\n finishReason: LanguageModelV4FinishReason;\n totalUsage: LanguageModelV4Usage;\n harnessMetadata?: HarnessV1Metadata;\n }\n\n // Workspace file mutation that occurred through an opaque underlying\n // mechanism (one with no visible `tool-call` carrying the same data, e.g.\n // Codex's internal `apply_patch`). Emitted per changed path. Path-only by\n // design — when the mutation goes through a visible tool call, the\n // tool-call/tool-result pair already carries the information.\n | {\n type: 'file-change';\n event: 'create' | 'modify' | 'delete';\n path: string;\n harnessMetadata?: HarnessV1Metadata;\n }\n\n // Context compaction performed by the underlying runtime (Claude Code's\n // native compaction, Pi's summarization). Observation only — the runtime\n // owns the compaction; the harness neither implements nor schedules it.\n // Emitted once, on completion, since `summary`/`tokensAfter` only exist then.\n | {\n type: 'compaction';\n trigger: 'manual' | 'auto';\n summary: string;\n tokensBefore?: number;\n tokensAfter?: number;\n harnessMetadata?: HarnessV1Metadata;\n }\n\n // Errors. Multiple may be emitted in a single turn.\n | { type: 'error'; error: unknown }\n\n // Adapter-specific passthrough. Consumers can opt in to receive these via\n // `HarnessAgent` settings; otherwise they are dropped.\n | { type: 'raw'; rawValue: unknown };\n\n/*\n * Runtime (Zod) encoding of `HarnessV1StreamPart`.\n *\n * `HarnessV1StreamPart` is a compile-time type built on `LanguageModelV4*`\n * types that ship no runtime validator. Bridge adapters receive these parts as\n * JSON across a trust boundary (the sandbox WebSocket), so they need a runtime\n * schema. These schemas ARE that encoding — one source of truth, kept from\n * diverging from the type by the `_assignable` guard below and the mutual\n * `toEqualTypeOf` assertion in `harness-v1-stream-part.test-d.ts`.\n *\n * Members are exported individually so `harness-v1-bridge-protocol.ts` can\n * compose them into the bridge outbound union alongside the transport frames.\n */\n\nconst harnessV1JsonValueSchema: z.ZodType<JSONValue> = z.lazy(() =>\n z.union([\n z.string(),\n z.number(),\n z.boolean(),\n z.null(),\n z.array(harnessV1JsonValueSchema),\n z.record(z.string(), harnessV1JsonValueSchema),\n ]),\n);\n\n/*\n * Tool-result values. The inferred type is the spec's `NonNullable<JSONValue>`\n * (matching `LanguageModelV4ToolResult`), but the runtime validator\n * deliberately also accepts `null`: adapters emit `result: <value> ?? null` for\n * tools that produced no output, and that `null` must survive the trust\n * boundary unchanged (it reaches consumers exactly as it did before this schema\n * existed, when a cast hid it). Leniency at runtime, strictness in the type.\n */\nconst harnessV1ToolResultValueSchema =\n harnessV1JsonValueSchema as unknown as z.ZodType<NonNullable<JSONValue>>;\n\nconst harnessV1JsonObjectSchema = z.record(\n z.string(),\n harnessV1JsonValueSchema,\n) as unknown as z.ZodType<Record<string, JSONValue>>;\n\nconst harnessV1MetadataSchema = z.record(\n z.string(),\n z.record(z.string(), harnessV1JsonValueSchema),\n) as unknown as z.ZodType<HarnessV1Metadata>;\n\nconst harnessV1ProviderMetadataSchema = z.record(\n z.string(),\n z.record(z.string(), harnessV1JsonValueSchema),\n) as unknown as z.ZodType<SharedV4ProviderMetadata>;\n\nconst harnessV1CallWarningSchema = z.union([\n z.object({\n type: z.literal('unsupported-setting'),\n setting: z.string(),\n details: z.string().optional(),\n }),\n z.object({\n type: z.literal('unsupported-tool'),\n tool: z.string(),\n details: z.string().optional(),\n }),\n z.object({ type: z.literal('other'), message: z.string() }),\n]) as z.ZodType<HarnessV1CallWarning>;\n\nconst harnessV1UsageSchema = z.object({\n inputTokens: z.object({\n total: z.number().optional(),\n noCache: z.number().optional(),\n cacheRead: z.number().optional(),\n cacheWrite: z.number().optional(),\n }),\n outputTokens: z.object({\n total: z.number().optional(),\n text: z.number().optional(),\n reasoning: z.number().optional(),\n }),\n raw: harnessV1JsonObjectSchema.optional(),\n}) as unknown as z.ZodType<LanguageModelV4Usage>;\n\nconst harnessV1FinishReasonSchema = z.object({\n unified: z.enum([\n 'stop',\n 'length',\n 'content-filter',\n 'tool-calls',\n 'error',\n 'other',\n ]),\n raw: z.string().optional(),\n}) as unknown as z.ZodType<LanguageModelV4FinishReason>;\n\nexport const harnessV1StreamStartPartSchema = z.object({\n type: z.literal('stream-start'),\n warnings: z.array(harnessV1CallWarningSchema).readonly().optional(),\n modelId: z.string().optional(),\n});\n\nexport const harnessV1TextStartPartSchema = z.object({\n type: z.literal('text-start'),\n id: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1TextDeltaPartSchema = z.object({\n type: z.literal('text-delta'),\n id: z.string(),\n delta: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1TextEndPartSchema = z.object({\n type: z.literal('text-end'),\n id: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1ReasoningStartPartSchema = z.object({\n type: z.literal('reasoning-start'),\n id: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1ReasoningDeltaPartSchema = z.object({\n type: z.literal('reasoning-delta'),\n id: z.string(),\n delta: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1ReasoningEndPartSchema = z.object({\n type: z.literal('reasoning-end'),\n id: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1ToolCallPartSchema = z.object({\n type: z.literal('tool-call'),\n toolCallId: z.string(),\n toolName: z.string(),\n input: z.string(),\n providerExecuted: z.boolean().optional(),\n dynamic: z.boolean().optional(),\n providerMetadata: harnessV1ProviderMetadataSchema.optional(),\n nativeName: z.string().optional(),\n});\n\nexport const harnessV1ToolApprovalRequestPartSchema = z.object({\n type: z.literal('tool-approval-request'),\n approvalId: z.string(),\n toolCallId: z.string(),\n providerMetadata: harnessV1ProviderMetadataSchema.optional(),\n});\n\nexport const harnessV1ToolResultPartSchema = z.object({\n type: z.literal('tool-result'),\n toolCallId: z.string(),\n toolName: z.string(),\n result: harnessV1ToolResultValueSchema,\n isError: z.boolean().optional(),\n preliminary: z.boolean().optional(),\n dynamic: z.boolean().optional(),\n providerMetadata: harnessV1ProviderMetadataSchema.optional(),\n});\n\nexport const harnessV1FinishStepPartSchema = z.object({\n type: z.literal('finish-step'),\n finishReason: harnessV1FinishReasonSchema,\n usage: harnessV1UsageSchema,\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1FinishPartSchema = z.object({\n type: z.literal('finish'),\n finishReason: harnessV1FinishReasonSchema,\n totalUsage: harnessV1UsageSchema,\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1FileChangePartSchema = z.object({\n type: z.literal('file-change'),\n event: z.enum(['create', 'modify', 'delete']),\n path: z.string(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1CompactionPartSchema = z.object({\n type: z.literal('compaction'),\n trigger: z.enum(['manual', 'auto']),\n summary: z.string(),\n tokensBefore: z.number().optional(),\n tokensAfter: z.number().optional(),\n harnessMetadata: harnessV1MetadataSchema.optional(),\n});\n\nexport const harnessV1ErrorPartSchema = z.object({\n type: z.literal('error'),\n error: z.unknown(),\n});\n\nexport const harnessV1RawPartSchema = z.object({\n type: z.literal('raw'),\n rawValue: z.unknown(),\n});\n\n/**\n * Assembled discriminated union over every `HarnessV1StreamPart` variant. Left\n * un-annotated so it keeps its precise inferred type — the protocol layer\n * composes the individual member schemas, and the type test asserts the\n * inferred union equals `HarnessV1StreamPart`.\n */\nexport const harnessV1StreamPartSchema = z.discriminatedUnion('type', [\n harnessV1StreamStartPartSchema,\n harnessV1TextStartPartSchema,\n harnessV1TextDeltaPartSchema,\n harnessV1TextEndPartSchema,\n harnessV1ReasoningStartPartSchema,\n harnessV1ReasoningDeltaPartSchema,\n harnessV1ReasoningEndPartSchema,\n harnessV1ToolCallPartSchema,\n harnessV1ToolApprovalRequestPartSchema,\n harnessV1ToolResultPartSchema,\n harnessV1FinishStepPartSchema,\n harnessV1FinishPartSchema,\n harnessV1FileChangePartSchema,\n harnessV1CompactionPartSchema,\n harnessV1ErrorPartSchema,\n harnessV1RawPartSchema,\n]);\n\n/*\n * Fail-fast guard at the definition site: the schema's output must be\n * assignable to `HarnessV1StreamPart` (catches a schema variant inventing a\n * shape the type does not allow). The reverse direction — the type being a\n * subset of the schema — is covered by the `toEqualTypeOf` assertion in the\n * type test.\n */\nconst _assignable: z.ZodType<HarnessV1StreamPart> = harnessV1StreamPartSchema;\nvoid _assignable;\n","import { z } from 'zod/v4';\nimport {\n harnessV1DebugConfigSchema,\n harnessV1DebugLevelSchema,\n type HarnessV1Diagnostic,\n} from './harness-v1-diagnostic';\nimport {\n harnessV1CompactionPartSchema,\n harnessV1ErrorPartSchema,\n harnessV1FileChangePartSchema,\n harnessV1FinishPartSchema,\n harnessV1FinishStepPartSchema,\n harnessV1RawPartSchema,\n harnessV1ReasoningDeltaPartSchema,\n harnessV1ReasoningEndPartSchema,\n harnessV1ReasoningStartPartSchema,\n harnessV1StreamStartPartSchema,\n harnessV1TextDeltaPartSchema,\n harnessV1TextEndPartSchema,\n harnessV1TextStartPartSchema,\n harnessV1ToolApprovalRequestPartSchema,\n harnessV1ToolCallPartSchema,\n harnessV1ToolResultPartSchema,\n} from './harness-v1-stream-part';\n\n/*\n * The bridge wire protocol shared by every bridge-backed harness adapter.\n *\n * This is the serialization of the host<->runtime contract for adapters that\n * run the agent runtime inside the sandbox and talk to the host over a\n * WebSocket. It exists ONLY because of that transport: untrusted JSON frames\n * crossing the sandbox boundary need runtime validation, the connection needs\n * a handshake, and the host drives turns with serialized commands. Every export\n * here is therefore prefixed `harnessV1Bridge…`.\n *\n * It has three tiers:\n *\n * 1. The OUTBOUND events — `HarnessV1StreamPart` re-expressed as Zod (imported\n * member schemas from `harness-v1-stream-part.ts`), because the part type is\n * compile-time only and the frames need runtime validation at the boundary.\n * 2. The transport/control frames that are NOT consumer events — `bridge-hello`\n * (handshake), `bridge-detach` (resume payload), `bridge-thread` (a resume\n * coordinate some runtimes announce). These ride the same socket.\n * 3. The INBOUND command vocabulary the host sends back: the shared commands\n * live here; the per-adapter `start` payload extends\n * `harnessV1BridgeStartBaseSchema` and assembles the final inbound union in\n * the adapter package.\n *\n * Non-bridge adapters (e.g. Pi) do not use this layer at all — they have no\n * serialization boundary and target the universal `HarnessV1StreamPart` type\n * directly. That is the deliberate split: `harness-v1-stream-part.ts` is the\n * transport-agnostic event vocabulary; this file is the bridge transport.\n */\n\n/**\n * The subset of a host-defined tool that travels on the `start` message. The\n * runtime only needs the name, description, and JSON-Schema input to surface\n * the tool; `execute` stays on the host.\n */\nexport const harnessV1BridgeToolWireSchema = z.object({\n name: z.string(),\n description: z.string().optional(),\n inputSchema: z.unknown().optional(),\n});\n\nexport type HarnessV1BridgeToolWire = z.infer<\n typeof harnessV1BridgeToolWireSchema\n>;\n\nexport const harnessV1BridgePermissionModeSchema = z.enum([\n 'allow-reads',\n 'allow-edits',\n 'allow-all',\n]);\n\nexport const harnessV1BridgeBuiltinToolFilteringSchema = z.discriminatedUnion(\n 'mode',\n [\n z.object({\n mode: z.literal('allow'),\n toolNames: z.array(z.string()),\n }),\n z.object({\n mode: z.literal('deny'),\n toolNames: z.array(z.string()),\n }),\n ],\n);\n\n/**\n * Common fields of the inbound `start` message. Each adapter extends this with\n * its runtime-specific configuration (e.g. `thinking`/`continue` for Claude\n * Code, `reasoningEffort`/`webSearch`/`skills`/`resumeThreadId` for Codex) and\n * assembles the final inbound union from the shared command members below.\n *\n * `debug` carries the general `HarnessV1DebugConfig` — diagnostics config is not\n * a bridge concept, it just happens to ride the `start` frame for bridge-backed\n * adapters.\n */\nexport const harnessV1BridgeStartBaseSchema = z.object({\n type: z.literal('start'),\n prompt: z.string(),\n tools: z.array(harnessV1BridgeToolWireSchema).optional(),\n model: z.string().optional(),\n debug: harnessV1DebugConfigSchema.optional(),\n permissionMode: harnessV1BridgePermissionModeSchema.optional(),\n builtinToolFiltering: harnessV1BridgeBuiltinToolFilteringSchema.optional(),\n});\n\n// --- Transport / control frames (outbound, not consumer events) ---\n\n/**\n * Sent the instant the bridge accepts an authenticated WS connection. The host\n * waits for it before sending `start`/`resume`, because some sandbox runtimes\n * complete the upstream WS handshake before the connection is wired through to\n * the bridge process — anything sent in that gap is dropped. Carries the\n * bridge's lifecycle `state` and highest emitted `seq` for reconnect.\n */\nexport const harnessV1BridgeHelloSchema = z.object({\n type: z.literal('bridge-hello'),\n state: z.string().optional(),\n lastSeq: z.number().optional(),\n});\n\n/**\n * The bridge's reply to an inbound `detach`. Carries the adapter-specific\n * payload the host serializes into lifecycle state `data`.\n */\nexport const harnessV1BridgeDetachSchema = z.object({\n type: z.literal('bridge-detach'),\n data: z.unknown(),\n});\n\n/**\n * A resume coordinate the bridge proactively announces (e.g. Codex's thread id)\n * so the host can cache it for a later resume without waiting for `detach`.\n */\nexport const harnessV1BridgeThreadSchema = z.object({\n type: z.literal('bridge-thread'),\n threadId: z.string(),\n});\n\n/**\n * Acknowledgement for an inbound `interrupt` command. The host waits for this\n * before freezing its replay cursor so the adapter-specific interrupt has\n * actually reached the underlying runtime.\n */\nexport const harnessV1BridgeInterruptedSchema = z.object({\n type: z.literal('bridge-interrupted'),\n ok: z.boolean(),\n error: z.unknown().optional(),\n});\n\n// --- Diagnostics frames (outbound, not consumer events) ---\n\n/**\n * One captured console line from inside the sandbox. The bridge line-buffers\n * `process.stdout`/`process.stderr` and emits one of these per complete line.\n * Routed host-side to the diagnostics sink, never to the consumer stream.\n */\nexport const harnessV1BridgeSandboxLogSchema = z.object({\n type: z.literal('sandbox-log'),\n source: z.string(),\n stream: z.enum(['stdout', 'stderr']),\n line: z.string(),\n});\n\n/**\n * A structured diagnostic an adapter emits from inside the bridge via\n * `turn.bridgeLog(...)`. Gated by the session's debug level + subsystem filter.\n */\nexport const harnessV1BridgeDebugEventSchema = z.object({\n type: z.literal('debug-event'),\n level: harnessV1DebugLevelSchema,\n subsystem: z.string(),\n message: z.string(),\n attrs: z.record(z.string(), z.unknown()).optional(),\n error: z\n .object({\n name: z.string().optional(),\n message: z.string(),\n stack: z.string().optional(),\n })\n .optional(),\n});\n\n/**\n * Every frame a bridge can send to the host: the stream-part events plus the\n * transport/control frames. This is the schema the host `SandboxChannel`\n * validates inbound frames against.\n */\nexport const harnessV1BridgeOutboundMessageSchema = z.discriminatedUnion(\n 'type',\n [\n harnessV1StreamStartPartSchema,\n harnessV1TextStartPartSchema,\n harnessV1TextDeltaPartSchema,\n harnessV1TextEndPartSchema,\n harnessV1ReasoningStartPartSchema,\n harnessV1ReasoningDeltaPartSchema,\n harnessV1ReasoningEndPartSchema,\n harnessV1ToolCallPartSchema,\n harnessV1ToolApprovalRequestPartSchema,\n harnessV1ToolResultPartSchema,\n harnessV1FinishStepPartSchema,\n harnessV1FinishPartSchema,\n harnessV1FileChangePartSchema,\n harnessV1CompactionPartSchema,\n harnessV1ErrorPartSchema,\n harnessV1RawPartSchema,\n harnessV1BridgeHelloSchema,\n harnessV1BridgeDetachSchema,\n harnessV1BridgeThreadSchema,\n harnessV1BridgeInterruptedSchema,\n harnessV1BridgeSandboxLogSchema,\n harnessV1BridgeDebugEventSchema,\n ],\n);\n\nexport type HarnessV1BridgeOutboundMessage = z.infer<\n typeof harnessV1BridgeOutboundMessageSchema\n>;\n\nexport type HarnessV1BridgeSandboxLog = z.infer<\n typeof harnessV1BridgeSandboxLogSchema\n>;\n\nexport type HarnessV1BridgeDebugEvent = z.infer<\n typeof harnessV1BridgeDebugEventSchema\n>;\n\n/**\n * Normalize a bridge diagnostics wire frame into the transport-agnostic\n * `HarnessV1Diagnostic` an adapter reports to the framework. A captured console\n * line maps `stderr` → `warn` and `stdout` → `info`; a structured event passes\n * its fields through. This is the seam where the bridge's serialization is\n * lifted into the general emission shape every harness shares.\n */\nexport function harnessV1DiagnosticFromBridgeFrame(\n frame: HarnessV1BridgeSandboxLog | HarnessV1BridgeDebugEvent,\n context: { sessionId?: string; timestamp: number },\n): HarnessV1Diagnostic {\n if (frame.type === 'sandbox-log') {\n return {\n level: frame.stream === 'stderr' ? 'warn' : 'info',\n message: frame.line,\n subsystem: `sandbox.log.${frame.source}`,\n kind: 'log',\n source: frame.source,\n stream: frame.stream,\n sessionId: context.sessionId,\n timestamp: context.timestamp,\n };\n }\n return {\n level: frame.level,\n message: frame.message,\n subsystem: frame.subsystem,\n kind: 'event',\n attrs: frame.attrs,\n error: frame.error,\n sessionId: context.sessionId,\n timestamp: context.timestamp,\n };\n}\n\n// --- Shared inbound command members (host -> bridge) ---\n\nexport const harnessV1BridgeToolResultInboundSchema = z.object({\n type: z.literal('tool-result'),\n toolCallId: z.string(),\n output: z.unknown(),\n isError: z.boolean().optional(),\n});\n\nexport const harnessV1BridgeToolApprovalResponseInboundSchema = z.object({\n type: z.literal('tool-approval-response'),\n approvalId: z.string(),\n approved: z.boolean(),\n reason: z.string().optional(),\n});\n\nexport const harnessV1BridgeUserMessageInboundSchema = z.object({\n type: z.literal('user-message'),\n text: z.string(),\n});\n\nexport const harnessV1BridgeAbortInboundSchema = z.object({\n type: z.literal('abort'),\n});\n\nexport const harnessV1BridgeInterruptInboundSchema = z.object({\n type: z.literal('interrupt'),\n});\n\nexport const harnessV1BridgeShutdownInboundSchema = z.object({\n type: z.literal('shutdown'),\n});\n\n/**\n * Reconnect: after re-establishing the socket the host asks the bridge to\n * replay every buffered event with `seq > lastSeenEventId`.\n */\nexport const harnessV1BridgeResumeInboundSchema = z.object({\n type: z.literal('resume'),\n lastSeenEventId: z.number(),\n});\n\n/**\n * The bridge replies with `bridge-detach` carrying any cached resume payload,\n * then exits.\n */\nexport const harnessV1BridgeDetachInboundSchema = z.object({\n type: z.literal('detach'),\n});\n\n/**\n * The inbound command members shared by every bridge adapter. Spread these\n * alongside the adapter's own `start` schema to build the final inbound union:\n * `z.discriminatedUnion('type', [adapterStartSchema, ...harnessV1BridgeInboundCommandSchemas])`.\n */\nexport const harnessV1BridgeInboundCommandSchemas = [\n harnessV1BridgeToolResultInboundSchema,\n harnessV1BridgeToolApprovalResponseInboundSchema,\n harnessV1BridgeUserMessageInboundSchema,\n harnessV1BridgeAbortInboundSchema,\n harnessV1BridgeInterruptInboundSchema,\n harnessV1BridgeShutdownInboundSchema,\n harnessV1BridgeResumeInboundSchema,\n harnessV1BridgeDetachInboundSchema,\n] as const;\n\n/**\n * The JSON line the bridge writes to stdout once its WebSocket server is bound,\n * announcing the port the host should connect to.\n */\nexport const harnessV1BridgeReadySchema = z.object({\n type: z.literal('bridge-ready'),\n port: z.number(),\n});\n\nexport type HarnessV1BridgeReady = z.infer<typeof harnessV1BridgeReadySchema>;\n","import { z } from 'zod/v4';\n\n/*\n * Diagnostics EMISSION contract — part of the `HarnessV1` spec.\n *\n * These are the types a harness adapter produces and receives: an adapter\n * reports a `HarnessV1Diagnostic` to the framework (a bridge adapter normalizes\n * its wire frames into one; a non-bridge adapter constructs one directly), and\n * receives a `HarnessV1DebugConfig` to gate what it emits. They are distinct\n * from the unaffixed host-facing `HarnessDiagnostic` / `HarnessDebugConfig`\n * (the external/telemetry surface) — the framework maps between the two at the\n * boundary, so the emission and consumption surfaces can evolve independently.\n */\n\n/** Severity of a diagnostic, ordered most → least severe. */\nexport const harnessV1DebugLevelSchema = z.enum([\n 'error',\n 'warn',\n 'info',\n 'debug',\n 'trace',\n]);\n\nexport type HarnessV1DebugLevel = z.infer<typeof harnessV1DebugLevelSchema>;\n\n/**\n * Per-session diagnostics configuration the framework hands an adapter (and the\n * host sends on `start.debug`). When absent or `enabled` is false the adapter\n * captures and emits nothing. `subsystems` filters structured events by dotted\n * prefix; console capture is independent of the subsystem filter.\n */\nexport const harnessV1DebugConfigSchema = z.object({\n enabled: z.boolean().optional(),\n level: harnessV1DebugLevelSchema.optional(),\n subsystems: z.array(z.string()).optional(),\n});\n\nexport type HarnessV1DebugConfig = z.infer<typeof harnessV1DebugConfigSchema>;\n\n/**\n * A diagnostic as emitted by a harness adapter. Structurally identical to the\n * host-facing `HarnessDiagnostic` today, but kept separate: this is the spec's\n * emission shape, that is the external consumption shape.\n */\nexport type HarnessV1Diagnostic = {\n /** Severity. */\n readonly level: HarnessV1DebugLevel;\n /** Human-readable line (console capture) or message (structured event). */\n readonly message: string;\n /** Dotted subsystem (`sandbox.log.<source>` for console capture). */\n readonly subsystem: string;\n /** `'log'` = captured console line; `'event'` = structured emission. */\n readonly kind: 'log' | 'event';\n /** Originating source label (console capture). */\n readonly source?: string;\n /** Which standard stream the line came from (console capture). */\n readonly stream?: 'stdout' | 'stderr';\n /** Structured attributes (structured events only). */\n readonly attrs?: Record<string, unknown>;\n /** Error payload (structured events only). */\n readonly error?: { name?: string; message: string; stack?: string };\n /** The harness session this diagnostic originated from. */\n readonly sessionId?: string;\n /** Emission time (epoch ms). */\n readonly timestamp: number;\n};\n","export type HarnessV1BuiltinToolFiltering =\n | {\n mode: 'allow';\n toolNames: string[];\n }\n | {\n mode: 'deny';\n toolNames: string[];\n };\n\nexport function isHarnessV1BuiltinToolIncluded(input: {\n toolName: string;\n toolFiltering: HarnessV1BuiltinToolFiltering | undefined;\n}): boolean {\n if (input.toolFiltering == null) return true;\n return input.toolFiltering.mode === 'allow'\n ? input.toolFiltering.toolNames.includes(input.toolName)\n : !input.toolFiltering.toolNames.includes(input.toolName);\n}\n\nexport function getHarnessV1BuiltinToolFilteringDenialReason(input: {\n toolName: string;\n}): string {\n return `Tool '${input.toolName}' is inactive due to the HarnessAgent tool filtering policy.`;\n}\n","import { AISDKError } from '@ai-sdk/provider';\n\nconst name = 'AI_HarnessError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\n * Base error type for failures originating in or signalled by a harness\n * adapter. Specific failure modes (e.g. unsupported capability) extend this\n * class.\n */\nexport class HarnessError extends AISDKError {\n private readonly [symbol] = true;\n\n constructor({ message, cause }: { message: string; cause?: unknown }) {\n super({ name, message, cause });\n }\n\n static isInstance(error: unknown): error is HarnessError {\n return AISDKError.hasMarker(error, marker);\n }\n}\n","import { AISDKError } from '@ai-sdk/provider';\nimport { HarnessError } from './harness-error';\n\nconst name = 'AI_HarnessCapabilityUnsupportedError';\nconst marker = `vercel.ai.error.${name}`;\nconst symbol = Symbol.for(marker);\n\n/**\n * Thrown when a caller asks the harness to do something the adapter (or the\n * supplied sandbox) does not support, e.g. requesting manual compaction from\n * an adapter that only auto-compacts, or invoking `getPortUrl` on a sandbox\n * that does not expose one.\n *\n * The caller supplies the full human-readable message. Optional `harnessId`\n * is recorded as structured context for tooling.\n */\nexport class HarnessCapabilityUnsupportedError extends HarnessError {\n private readonly [symbol] = true;\n\n readonly harnessId?: string;\n\n constructor({\n message,\n harnessId,\n cause,\n }: {\n message: string;\n harnessId?: string;\n cause?: unknown;\n }) {\n super({ message, cause });\n Object.defineProperty(this, 'name', { value: name });\n this.harnessId = harnessId;\n }\n\n static isInstance(\n error: unknown,\n ): error is HarnessCapabilityUnsupportedError {\n return AISDKError.hasMarker(error, marker);\n }\n}\n"],"mappings":"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","names":["z","z","z","z","AISDKError","name","marker","symbol","_a","_b","AISDKError"]}
|