@ai-sdk/harness 1.0.76 → 1.0.78
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/bridge/index.ts +2 -0
- package/dist/agent/index.d.ts +42 -23
- package/dist/agent/index.js +168 -61
- package/dist/agent/index.js.map +1 -1
- package/dist/bridge/index.d.ts +12 -7
- package/dist/bridge/index.js +140 -5
- package/dist/bridge/index.js.map +1 -1
- package/dist/index.d.ts +38 -13
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +177 -1
- package/dist/utils/index.js +121 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +4 -4
- package/src/agent/harness-agent-session.ts +136 -12
- package/src/agent/harness-agent.ts +54 -22
- package/src/agent/internal/run-prompt.ts +2 -0
- package/src/agent/internal/sandbox-bootstrap.ts +3 -28
- package/src/agent/prepare-sandbox-for-harness.ts +3 -3
- package/src/bridge/index.ts +184 -12
- package/src/utils/bridge-user-message-submitter.ts +96 -0
- package/src/utils/get-restricted-sandbox-session.ts +10 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/resolve-sandbox-default-working-directory.ts +33 -0
- package/src/utils/sandbox-channel.ts +9 -0
- package/src/v1/harness-v1-bridge-protocol.ts +23 -0
- package/src/v1/harness-v1-session.ts +9 -12
- package/src/v1/index.ts +4 -1
package/dist/bridge/index.d.ts
CHANGED
|
@@ -20,6 +20,16 @@ type BridgeEvent = Record<string, unknown> & {
|
|
|
20
20
|
type: string;
|
|
21
21
|
};
|
|
22
22
|
type BridgeDebugLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';
|
|
23
|
+
interface Experimental_BridgeUserMessage {
|
|
24
|
+
readonly messageId: string;
|
|
25
|
+
readonly text: string;
|
|
26
|
+
accept(): void;
|
|
27
|
+
reject(error: unknown): void;
|
|
28
|
+
}
|
|
29
|
+
interface Experimental_BridgeUserMessageQueue extends AsyncIterable<Experimental_BridgeUserMessage> {
|
|
30
|
+
readonly pendingCount: number;
|
|
31
|
+
close(error?: unknown): void;
|
|
32
|
+
}
|
|
23
33
|
/**
|
|
24
34
|
* Per-session diagnostics config. The host resolves it from settings +
|
|
25
35
|
* env and sends it on `start.debug`; the bridge gates console capture and
|
|
@@ -61,12 +71,7 @@ interface BridgeTurn {
|
|
|
61
71
|
approved: boolean;
|
|
62
72
|
reason?: string;
|
|
63
73
|
}>;
|
|
64
|
-
|
|
65
|
-
* Live queue of mid-turn user messages. The runtime pushes inbound
|
|
66
|
-
* `user-message` text here; the adapter drains it as its runtime accepts
|
|
67
|
-
* interactive input.
|
|
68
|
-
*/
|
|
69
|
-
readonly pendingUserMessages: string[];
|
|
74
|
+
readonly experimental_userMessages: Experimental_BridgeUserMessageQueue;
|
|
70
75
|
/** Aborts when the host sends `abort`. */
|
|
71
76
|
readonly abortSignal: AbortSignal;
|
|
72
77
|
/** True for the first turn since this bridge process started. */
|
|
@@ -143,4 +148,4 @@ declare function runBridge<TStart extends {
|
|
|
143
148
|
type: 'start';
|
|
144
149
|
}>(options: RunBridgeOptions<TStart>): Promise<BridgeHandle>;
|
|
145
150
|
|
|
146
|
-
export { type BridgeDebugConfig, type BridgeDebugLevel, type BridgeEvent, type BridgeHandle, type BridgeState, type BridgeTurn, HarnessBridgeCapabilityUnsupportedError, type RunBridgeOptions, runBridge };
|
|
151
|
+
export { type BridgeDebugConfig, type BridgeDebugLevel, type BridgeEvent, type BridgeHandle, type BridgeState, type BridgeTurn, type Experimental_BridgeUserMessage, type Experimental_BridgeUserMessageQueue, HarnessBridgeCapabilityUnsupportedError, type RunBridgeOptions, runBridge };
|
package/dist/bridge/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/bridge/index.ts
|
|
2
2
|
import { appendFile, mkdir, writeFile } from "fs/promises";
|
|
3
3
|
import { existsSync, readFileSync } from "fs";
|
|
4
|
+
import { randomUUID } from "crypto";
|
|
4
5
|
import { env as procEnv, pid, stdout } from "process";
|
|
5
6
|
import { WebSocketServer } from "ws";
|
|
6
7
|
|
|
@@ -51,6 +52,106 @@ function formatBridgeError(err) {
|
|
|
51
52
|
}
|
|
52
53
|
return { message: String(err) };
|
|
53
54
|
}
|
|
55
|
+
function createBridgeUserMessageQueue(options) {
|
|
56
|
+
const messages = [];
|
|
57
|
+
const waiters = [];
|
|
58
|
+
const entries = /* @__PURE__ */ new Map();
|
|
59
|
+
let closed = false;
|
|
60
|
+
let pendingCount = 0;
|
|
61
|
+
const enqueue = (input) => {
|
|
62
|
+
const existing = entries.get(input.messageId);
|
|
63
|
+
if (existing != null) {
|
|
64
|
+
if (existing.response != null) {
|
|
65
|
+
options.respond(existing.response);
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
let settled = false;
|
|
70
|
+
const settle = (response) => {
|
|
71
|
+
if (settled) return;
|
|
72
|
+
settled = true;
|
|
73
|
+
pendingCount--;
|
|
74
|
+
const entry = entries.get(input.messageId);
|
|
75
|
+
if (entry != null) entry.response = response;
|
|
76
|
+
options.respond(response);
|
|
77
|
+
};
|
|
78
|
+
const message = {
|
|
79
|
+
messageId: input.messageId,
|
|
80
|
+
text: input.text,
|
|
81
|
+
accept: () => {
|
|
82
|
+
settle({
|
|
83
|
+
type: "user-message-response",
|
|
84
|
+
messageId: input.messageId,
|
|
85
|
+
accepted: true
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
reject: (error) => {
|
|
89
|
+
settle({
|
|
90
|
+
type: "user-message-response",
|
|
91
|
+
messageId: input.messageId,
|
|
92
|
+
accepted: false,
|
|
93
|
+
error: { message: formatBridgeError(error).message }
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
entries.set(input.messageId, {
|
|
98
|
+
reject: message.reject
|
|
99
|
+
});
|
|
100
|
+
pendingCount++;
|
|
101
|
+
if (closed) {
|
|
102
|
+
message.reject(
|
|
103
|
+
new Error("The bridge turn is no longer accepting user messages.")
|
|
104
|
+
);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const waiter = waiters.shift();
|
|
108
|
+
if (waiter != null) {
|
|
109
|
+
waiter({ done: false, value: message });
|
|
110
|
+
} else {
|
|
111
|
+
messages.push(message);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const close = (error) => {
|
|
115
|
+
if (closed) return;
|
|
116
|
+
closed = true;
|
|
117
|
+
const reason = error ?? new Error("The bridge turn ended before accepting the user message.");
|
|
118
|
+
for (const entry of entries.values()) {
|
|
119
|
+
if (entry.response == null) entry.reject(reason);
|
|
120
|
+
}
|
|
121
|
+
messages.length = 0;
|
|
122
|
+
while (waiters.length > 0) {
|
|
123
|
+
waiters.shift()({ done: true, value: void 0 });
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
return {
|
|
127
|
+
get pendingCount() {
|
|
128
|
+
return pendingCount;
|
|
129
|
+
},
|
|
130
|
+
enqueue,
|
|
131
|
+
close,
|
|
132
|
+
[Symbol.asyncIterator]() {
|
|
133
|
+
return {
|
|
134
|
+
next: () => {
|
|
135
|
+
const message = messages.shift();
|
|
136
|
+
if (message != null) {
|
|
137
|
+
return Promise.resolve({ done: false, value: message });
|
|
138
|
+
}
|
|
139
|
+
if (closed) {
|
|
140
|
+
return Promise.resolve({
|
|
141
|
+
done: true,
|
|
142
|
+
value: void 0
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return new Promise(
|
|
146
|
+
(resolve) => {
|
|
147
|
+
waiters.push(resolve);
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
54
155
|
function parseEnvList(value) {
|
|
55
156
|
if (!value) return void 0;
|
|
56
157
|
const items = value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
@@ -267,6 +368,9 @@ async function runBridge(options) {
|
|
|
267
368
|
switch (msg.type) {
|
|
268
369
|
case "start": {
|
|
269
370
|
activeSocket = ws;
|
|
371
|
+
currentUserMessages?.close(
|
|
372
|
+
new Error("A new bridge turn replaced the active turn.")
|
|
373
|
+
);
|
|
270
374
|
const firstTurn = isFirstTurn;
|
|
271
375
|
isFirstTurn = false;
|
|
272
376
|
eventLog = [];
|
|
@@ -286,6 +390,7 @@ async function runBridge(options) {
|
|
|
286
390
|
if (debugConfig.enabled) {
|
|
287
391
|
installConsoleCapture();
|
|
288
392
|
}
|
|
393
|
+
const userMessages = createBridgeUserMessageQueue({ respond: emit });
|
|
289
394
|
const turn = {
|
|
290
395
|
emit,
|
|
291
396
|
requestToolResult: (toolCallId) => new Promise((resolve) => {
|
|
@@ -294,7 +399,7 @@ async function runBridge(options) {
|
|
|
294
399
|
requestToolApproval: (approvalId) => new Promise((resolve) => {
|
|
295
400
|
pendingToolApprovals.set(approvalId, resolve);
|
|
296
401
|
}),
|
|
297
|
-
|
|
402
|
+
experimental_userMessages: userMessages,
|
|
298
403
|
abortSignal: turnAbort.signal,
|
|
299
404
|
firstTurn,
|
|
300
405
|
bridgeLog: (input) => {
|
|
@@ -312,12 +417,16 @@ async function runBridge(options) {
|
|
|
312
417
|
emitWarning,
|
|
313
418
|
emitError
|
|
314
419
|
};
|
|
315
|
-
currentUserMessages =
|
|
420
|
+
currentUserMessages = userMessages;
|
|
316
421
|
try {
|
|
317
422
|
await onStart(msg, turn);
|
|
318
423
|
} catch (err) {
|
|
319
424
|
emitError({ error: err, message: "bridge turn failed" });
|
|
320
425
|
} finally {
|
|
426
|
+
userMessages.close();
|
|
427
|
+
if (currentUserMessages === userMessages) {
|
|
428
|
+
currentUserMessages = void 0;
|
|
429
|
+
}
|
|
321
430
|
currentTurnState = "waiting";
|
|
322
431
|
void writeBridgeMeta("waiting");
|
|
323
432
|
}
|
|
@@ -339,9 +448,34 @@ async function runBridge(options) {
|
|
|
339
448
|
}
|
|
340
449
|
return;
|
|
341
450
|
}
|
|
342
|
-
case "user-message":
|
|
343
|
-
|
|
451
|
+
case "user-message": {
|
|
452
|
+
const messageId = msg.messageId ?? randomUUID();
|
|
453
|
+
if (currentUserMessages == null) {
|
|
454
|
+
sendControl(ws, {
|
|
455
|
+
type: "user-message-response",
|
|
456
|
+
messageId,
|
|
457
|
+
accepted: false,
|
|
458
|
+
error: { message: "The bridge has no active turn to steer." }
|
|
459
|
+
});
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (ws !== activeSocket) {
|
|
463
|
+
sendControl(ws, {
|
|
464
|
+
type: "user-message-response",
|
|
465
|
+
messageId,
|
|
466
|
+
accepted: false,
|
|
467
|
+
error: {
|
|
468
|
+
message: "The connection does not own the active bridge turn."
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
currentUserMessages.enqueue({
|
|
474
|
+
messageId,
|
|
475
|
+
text: msg.text
|
|
476
|
+
});
|
|
344
477
|
return;
|
|
478
|
+
}
|
|
345
479
|
case "abort":
|
|
346
480
|
turnAbort?.abort();
|
|
347
481
|
return;
|
|
@@ -415,7 +549,8 @@ async function runBridge(options) {
|
|
|
415
549
|
sendControl(ws, {
|
|
416
550
|
type: "bridge-hello",
|
|
417
551
|
state: currentTurnState,
|
|
418
|
-
lastSeq: seqCounter
|
|
552
|
+
lastSeq: seqCounter,
|
|
553
|
+
capabilities: { experimental_userMessageResponses: true }
|
|
419
554
|
});
|
|
420
555
|
ws.on("message", (raw) => {
|
|
421
556
|
let parsed;
|
package/dist/bridge/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bridge/index.ts","../../src/bridge/harness-bridge-capability-unsupported-error.ts"],"sourcesContent":["// Shared in-sandbox bridge runtime. Adapter `bridge.mjs` bundles re-bundle\n// this module (tsup inlines it; `ws` stays external and resolves from the\n// sandbox-installed node_modules). It owns everything generic to the bridge\n// transport — the WebSocket server, token auth, the in-memory event log +\n// monotonic `seq`, resume replay, and the lifecycle/meta files. Any number of\n// hosts may be connected; exactly one of them owns the event stream, and\n// `start`/`resume` transfer that ownership. The adapter supplies only `onStart`\n// (drive its CLI/SDK and translate to wire events) and lifecycle cleanup hooks.\n\nimport { appendFile, mkdir, writeFile } from 'node:fs/promises';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { env as procEnv, pid, stdout } from 'node:process';\nimport { WebSocketServer, type WebSocket } from 'ws';\n\nexport { HarnessBridgeCapabilityUnsupportedError } from './harness-bridge-capability-unsupported-error';\n\nexport type BridgeState = 'init' | 'waiting' | 'running' | 'draining' | 'done';\n\n/** Outbound turn event the adapter emits. `seq` is added by the runtime. */\nexport type BridgeEvent = Record<string, unknown> & { type: string };\n\nexport type BridgeDebugLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\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 /** 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 /**\n * Produce the adapter-defined runtime resume data for `stop`. Defaults to\n * `{}`.\n */\n onStop?(): unknown | Promise<unknown>;\n /**\n * Perform adapter-defined destruction before the bridge exits.\n */\n onDestroy?(): void | Promise<void>;\n /** WS port. Defaults to `BRIDGE_WS_PORT` env (0 = OS-assigned). */\n port?: number;\n /** Auth token. Defaults to `BRIDGE_CHANNEL_TOKEN` env. */\n token?: string;\n /** Called with the bound port once the server is listening. */\n onListening?(port: number): void;\n /**\n * Tear the process down after `stop` / `destroy`. Defaults to closing\n * the server and calling `process.exit(0)`. Overridable for tests.\n */\n onExit?(): void;\n}\n\ntype InboundControl =\n | {\n type: 'tool-result';\n toolCallId: string;\n output: unknown;\n isError?: boolean;\n }\n | {\n type: 'tool-approval-response';\n approvalId: string;\n approved: boolean;\n reason?: string;\n }\n | { type: 'user-message'; text: string }\n | { type: 'abort' }\n | { type: 'stop' }\n | { type: 'destroy' }\n | { type: 'resume'; lastSeenEventId: number };\n\nconst WS_OPEN = 1;\n\n/**\n * Boot the bridge: bind the WebSocket server, announce `bridge-ready`, and\n * service host connections for the lifetime of the process. Resolves once the\n * server is listening; the process then stays alive on the server until a\n * `stop` / `destroy` exits it.\n */\nexport interface BridgeHandle {\n /** The port the WebSocket server bound to. */\n readonly port: number;\n /** Close the WebSocket server. Does not call `process.exit`. */\n close(): Promise<void>;\n}\n\nexport async function runBridge<TStart extends { type: 'start' }>(\n options: RunBridgeOptions<TStart>,\n): Promise<BridgeHandle> {\n const { bridgeType, bridgeStateDir, onStart, onStop, onDestroy } = options;\n const expectedToken = options.token ?? procEnv.BRIDGE_CHANNEL_TOKEN ?? '';\n const bridgeWsPort =\n options.port ?? parseInt(procEnv.BRIDGE_WS_PORT ?? '0', 10);\n\n const bridgeMetaPath = `${bridgeStateDir}/bridge-meta.json`;\n const startConfigPath = `${bridgeStateDir}/start-config.json`;\n const rerunStartConfigPath = `${bridgeStateDir}/rerun-start-config.json`;\n const eventLogPath = `${bridgeStateDir}/event-log.ndjson`;\n\n try {\n await mkdir(bridgeStateDir, { recursive: true });\n } catch {\n // Best-effort; the bridge still runs without its state files.\n }\n\n // ─── mutable runtime state ──────────────────────────────────────────\n let currentBoundPort = 0;\n let currentTurnState: BridgeState = 'init';\n /*\n * The one connection turn events stream to. A socket claims it by asking for\n * work — `start` (a turn) or `resume` (a catch-up) — never by connecting:\n * every event goes here alone, so claiming on connect would silence a turn\n * already streaming to someone else. Any number of sockets may be connected;\n * the others still exchange control frames, they just get no events.\n */\n let activeSocket: WebSocket | undefined;\n let isFirstTurn = true;\n let turnAbort: AbortController | undefined;\n let currentUserMessages: 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 in-flight turn and serve a host's resume cursor —\n * `replay` recovery. Writes are batched on `setImmediate` (single-flight via\n * `flushPromise`) to keep `emit` off the disk hot path.\n */\n let diskBuffer = '';\n let flushPromise: Promise<void> | null = null;\n\n const flushEventsToDisk = async (): Promise<void> => {\n while (diskBuffer.length > 0) {\n const buf = diskBuffer;\n diskBuffer = '';\n await appendFile(eventLogPath, buf).catch(() => {\n // Best-effort crash-recovery mirror; the in-memory log is the source of\n // truth for the live connection.\n });\n }\n };\n\n const scheduleEventFlush = (): void => {\n if (flushPromise) return;\n flushPromise = new Promise<void>(resolve => {\n setImmediate(() => {\n void flushEventsToDisk().finally(resolve);\n });\n }).finally(() => {\n flushPromise = null;\n if (diskBuffer.length > 0) {\n scheduleEventFlush();\n }\n });\n };\n\n const flushPendingEventsToDisk = async (): Promise<void> => {\n if (diskBuffer.length > 0 && !flushPromise) {\n scheduleEventFlush();\n }\n // Await each in-flight flush, re-reading `flushPromise` after every await\n // since a fresh flush may have been scheduled for buffer that arrived while\n // we waited.\n let inFlight = flushPromise;\n while (inFlight) {\n await inFlight;\n inFlight = flushPromise;\n }\n };\n\n /*\n * When respawned for `replay`, reload the previous turn's log from disk before\n * accepting any connection so the very first `resume{lastSeenEventId}` can be\n * served the tail (including the terminal `finish`). The seq counter is\n * restored to the last persisted seq so it stays aligned with the host's\n * long-lived cursor. The file is NOT truncated in this mode — only a fresh\n * `start` (next turn) clears it.\n */\n const replayFromDisk = procEnv.BRIDGE_REPLAY_FROM_DISK === '1';\n if (replayFromDisk && existsSync(eventLogPath)) {\n try {\n const lines = readFileSync(eventLogPath, 'utf8')\n .split('\\n')\n .map(line => line.trim())\n .filter(Boolean);\n eventLog = lines.map(line => ({\n seq: (JSON.parse(line) as { seq: number }).seq,\n line,\n }));\n seqCounter = eventLog.at(-1)?.seq ?? 0;\n } catch {\n // Corrupt/partial log: fall back to an empty log; the host then degrades\n // to `rerun` instead of replaying a malformed tail.\n eventLog = [];\n seqCounter = 0;\n }\n }\n\n const pendingToolResults = new Map<\n string,\n (output: { output: unknown; isError?: boolean }) => void\n >();\n const pendingToolApprovals = new Map<\n string,\n (response: { approved: boolean; reason?: string }) => void\n >();\n\n // ─── persistence (best-effort meta + start config) ──────────────────\n const writeBridgeMeta = async (state: BridgeState): Promise<void> => {\n try {\n await writeFile(\n bridgeMetaPath,\n JSON.stringify({\n type: bridgeType,\n port: currentBoundPort,\n state,\n pid,\n }),\n );\n } catch {\n // Best-effort resilience metadata; not load-bearing for the active turn.\n }\n };\n\n const writeStartConfig = async (start: unknown): Promise<void> => {\n try {\n const serialized = JSON.stringify(start);\n await writeFile(startConfigPath, serialized);\n // Frozen copy: written once, restored over start-config.json by future\n // rerun-mode recovery to re-run the original turn from scratch.\n if (!existsSync(rerunStartConfigPath)) {\n await writeFile(rerunStartConfigPath, serialized);\n }\n } catch {\n // Best-effort.\n }\n };\n\n // ─── wire send + replay ─────────────────────────────────────────────\n const emit = (event: BridgeEvent): void => {\n const seq = ++seqCounter;\n const line = JSON.stringify({ ...event, seq });\n eventLog.push({ seq, line });\n diskBuffer += `${line}\\n`;\n scheduleEventFlush();\n if (activeSocket?.readyState === WS_OPEN) {\n try {\n activeSocket.send(line);\n } catch {\n // Send is best-effort: a dropped socket leaves the event in the log,\n // replayed once the host reconnects and sends `resume`.\n }\n }\n };\n\n const replay = (ws: WebSocket, afterSeq: number): void => {\n for (const entry of eventLog) {\n if (entry.seq > afterSeq && ws.readyState === WS_OPEN) {\n ws.send(entry.line);\n }\n }\n };\n\n // ─── diagnostics ──────────────────────────────────────────────\n const shouldEmitDebugEvent = (\n level: BridgeDebugLevel,\n subsystem: string,\n ): boolean => {\n if (!debugConfig?.enabled) return false;\n const threshold = debugConfig.level ?? 'debug';\n if (DEBUG_LEVEL_WEIGHT[level] > DEBUG_LEVEL_WEIGHT[threshold]) return false;\n return subsystemMatches(debugConfig.subsystems, subsystem);\n };\n\n /*\n * Forward sandbox console output. We line-buffer the original writers (kept so\n * output still reaches the real fds) and emit one `sandbox-log` per complete\n * line. `emit` never writes to stdout/stderr, so there is no recursion.\n * Installed lazily the first time a turn enables diagnostics; once installed,\n * capture is gated per-write on `debugConfig.enabled` so a later turn can\n * disable it. Console capture is independent of the subsystem/level filter.\n */\n const rawStdoutWrite = process.stdout.write.bind(process.stdout);\n const rawStderrWrite = process.stderr.write.bind(process.stderr);\n\n const writeErrorToStderr = (input: {\n message: string;\n error: unknown;\n }): void => {\n try {\n const formatted = formatBridgeError(input.error);\n rawStderrWrite(\n `[harness:${bridgeType}:error] ${input.message}: ${formatted.message}\\n`,\n );\n if (formatted.stack) {\n rawStderrWrite(`${formatted.stack}\\n`);\n }\n } catch {}\n };\n\n const emitWarning = (input: { message: string }): void => {\n try {\n for (const line of input.message.split('\\n')) {\n if (line.trim().length > 0) {\n rawStderrWrite(`[harness:${bridgeType}:warn] ${line}\\n`);\n }\n }\n } catch {}\n };\n\n const emitError = (input: { error: unknown; message?: string }): void => {\n writeErrorToStderr({\n message: input.message ?? 'bridge error',\n error: input.error,\n });\n emit({ type: 'error', error: serialiseError(input.error) });\n };\n\n const installConsoleCapture = (): void => {\n if (consoleCaptureInstalled) return;\n consoleCaptureInstalled = true;\n const buffers: { stdout: string; stderr: string } = {\n stdout: '',\n stderr: '',\n };\n const patch =\n (stream: 'stdout' | 'stderr', raw: typeof process.stdout.write) =>\n (chunk: unknown, encoding?: unknown, cb?: unknown): boolean => {\n if (debugConfig?.enabled) {\n try {\n const enc = typeof encoding === 'string' ? encoding : 'utf8';\n const text =\n typeof chunk === 'string'\n ? chunk\n : Buffer.from(chunk as Uint8Array).toString(\n enc as BufferEncoding,\n );\n const combined = buffers[stream] + text.replace(/\\r\\n/g, '\\n');\n const parts = combined.split('\\n');\n buffers[stream] = parts.pop() ?? '';\n for (const line of parts) {\n const trimmed = line.replace(/\\s+$/, '');\n if (trimmed) {\n emit({\n type: 'sandbox-log',\n source: bridgeType,\n stream,\n line: trimmed,\n });\n }\n }\n } catch {\n // Never let capture break real output.\n }\n }\n return (raw as (c: unknown, e?: unknown, cb?: unknown) => boolean)(\n chunk,\n encoding,\n cb,\n );\n };\n process.stdout.write = patch(\n 'stdout',\n rawStdoutWrite,\n ) as typeof process.stdout.write;\n process.stderr.write = patch(\n 'stderr',\n rawStderrWrite,\n ) as typeof process.stderr.write;\n };\n\n // ─── inbound routing ────────────────────────────────────────────────\n const handleInbound = async (\n msg: TStart | InboundControl,\n ws: WebSocket,\n ): Promise<void> => {\n switch (msg.type) {\n case 'start': {\n activeSocket = ws; // asking for a turn claims the event stream\n const firstTurn = isFirstTurn;\n isFirstTurn = false;\n eventLog = []; // clear previous turn; keep seqCounter monotonic\n // Mirror the in-memory clear to disk: the log tracks only the current\n // turn. Discard any unflushed tail from the prior turn first.\n diskBuffer = '';\n void writeFile(eventLogPath, '').catch(() => {});\n turnAbort = new AbortController();\n currentTurnState = 'running';\n void writeStartConfig(msg);\n void writeBridgeMeta('running');\n const startDebug = (msg as { debug?: BridgeDebugConfig }).debug;\n debugConfig = {\n enabled: startDebug?.enabled ?? envDebugEnabled,\n level:\n startDebug?.level ??\n (procEnv.HARNESS_DEBUG_LEVEL as BridgeDebugLevel | undefined),\n subsystems:\n startDebug?.subsystems ??\n parseEnvList(procEnv.HARNESS_DEBUG_SUBSYSTEMS),\n };\n if (debugConfig.enabled) {\n installConsoleCapture();\n }\n const 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 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 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 activeSocket = ws; // asking for a catch-up claims it too\n // Synchronous, so no event can slip out live ahead of the replayed tail.\n replay(ws, msg.lastSeenEventId);\n return;\n case 'destroy':\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n await onDestroy?.();\n drainThenExit(ws, 1000, 'destroy');\n return;\n case 'stop': {\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n const data = (await onStop?.()) ?? {};\n sendControl(ws, { type: 'bridge-stop', data });\n drainThenExit(ws, 1000, 'stop');\n return;\n }\n }\n };\n\n // ─── server ─────────────────────────────────────────────────────────\n void writeBridgeMeta('init');\n\n const wss = new WebSocketServer({ port: bridgeWsPort, host: '0.0.0.0' });\n\n const exit = (): void => {\n if (options.onExit) {\n options.onExit();\n return;\n }\n wss.close(() => process.exit(0));\n setTimeout(() => process.exit(0), 1000).unref();\n };\n\n const drainThenExit = (ws: WebSocket, code: number, reason: string): void => {\n const start = Date.now();\n const tick = (): void => {\n const drained = ws.bufferedAmount === 0 || ws.readyState !== WS_OPEN;\n if (drained || Date.now() - start >= 5_000) {\n // Flush the on-disk log so a clean stop/destroy leaves a complete\n // event-log.ndjson for any later replay recovery.\n void flushPendingEventsToDisk().finally(() => {\n try {\n ws.close(code, reason);\n } finally {\n exit();\n }\n });\n return;\n }\n setTimeout(tick, 10).unref();\n };\n tick();\n };\n\n wss.on('listening', () => {\n const addr = wss.address();\n currentBoundPort = typeof addr === 'object' && addr ? addr.port : 0;\n currentTurnState = 'waiting';\n void writeBridgeMeta('waiting');\n stdout.write(\n JSON.stringify({\n type: 'bridge-ready',\n port: currentBoundPort,\n }) + '\\n',\n );\n options.onListening?.(currentBoundPort);\n });\n\n wss.on('connection', (ws: WebSocket, req: { url?: string }) => {\n const url = new URL(req.url ?? '/', 'http://localhost');\n if (url.searchParams.get('agent_bridge_token') !== expectedToken) {\n ws.close(1008, 'unauthorized');\n return;\n }\n\n // Announce liveness the instant we accept. Some sandbox runtimes complete\n // the host-side WS handshake before the connection is forwarded here; the\n // host waits for this frame before sending `start`/`resume`.\n sendControl(ws, {\n type: 'bridge-hello',\n state: currentTurnState,\n lastSeq: seqCounter,\n });\n\n ws.on('message', (raw: ArrayBufferLike | string) => {\n let parsed: TStart | InboundControl;\n try {\n const text =\n typeof raw === 'string' ? raw : Buffer.from(raw).toString('utf8');\n parsed = JSON.parse(text) as TStart | InboundControl;\n } catch (err) {\n sendControl(ws, {\n type: 'error',\n error: `protocol parse error: ${(err as Error).message}`,\n });\n return;\n }\n void handleInbound(parsed, ws);\n });\n\n ws.on('close', () => {\n // Only the stream owner's close matters; a socket that never claimed it,\n // or that a later `start`/`resume` displaced, closes as a no-op.\n // Crucially we do NOT abort the in-flight turn: it keeps running and its\n // events accumulate in the log for replay on reconnect.\n if (activeSocket === ws) {\n activeSocket = undefined;\n }\n });\n\n ws.on('error', () => {\n // 'close' follows; nothing to do beyond keeping the process alive.\n });\n });\n\n // Surface bridge-internal crashes to the host instead of dying silently.\n process.on('uncaughtException', err => {\n emitError({ error: err, message: 'uncaught exception' });\n });\n process.on('unhandledRejection', err => {\n emitError({ error: err, message: 'unhandled rejection' });\n });\n\n await new Promise<void>((resolve, reject) => {\n if (wss.address() != null) {\n resolve();\n return;\n }\n\n wss.once('listening', resolve);\n wss.once('error', reject);\n });\n\n return {\n port: currentBoundPort,\n close: () =>\n new Promise<void>(resolve => {\n wss.close(() => resolve());\n }),\n };\n}\n\n/*\n * Control frames answer the socket that sent the frame they reply to, so the\n * target is always explicit. Event streaming is the separate, stateful path\n * (`emit` → `activeSocket`); this one carries no state at all.\n */\nfunction sendControl(\n socket: WebSocket | undefined,\n message: Record<string, unknown>,\n): void {\n if (socket?.readyState === WS_OPEN) {\n try {\n socket.send(JSON.stringify(message));\n } catch {\n // best-effort\n }\n }\n}\n\nfunction serialiseError(err: unknown): unknown {\n if (err instanceof Error) {\n return { name: err.name, message: err.message, stack: err.stack };\n }\n return err;\n}\n","const name = 'AI_HarnessBridgeCapabilityUnsupportedError';\n\n/**\n * Signals an unsupported capability discovered inside a sandbox bridge.\n * `isInstance` also recognizes the serialized error shape received by the\n * host, where it can be translated to `HarnessCapabilityUnsupportedError`.\n */\nexport class HarnessBridgeCapabilityUnsupportedError extends Error {\n readonly harnessId?: string;\n readonly cause?: unknown;\n\n constructor({\n message,\n harnessId,\n cause,\n }: {\n message: string;\n harnessId?: string;\n cause?: unknown;\n }) {\n super(message);\n Object.defineProperty(this, 'name', { value: name });\n this.harnessId = harnessId;\n this.cause = cause;\n }\n\n static isInstance(\n error: unknown,\n ): error is HarnessBridgeCapabilityUnsupportedError {\n return (\n error != null &&\n typeof error === 'object' &&\n 'name' in error &&\n error.name === name &&\n 'message' in error &&\n typeof error.message === 'string'\n );\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/bridge/index.ts","../../src/bridge/harness-bridge-capability-unsupported-error.ts"],"sourcesContent":["// Shared in-sandbox bridge runtime. Adapter `bridge.mjs` bundles re-bundle\n// this module (tsup inlines it; `ws` stays external and resolves from the\n// sandbox-installed node_modules). It owns everything generic to the bridge\n// transport — the WebSocket server, token auth, the in-memory event log +\n// monotonic `seq`, resume replay, and the lifecycle/meta files. Any number of\n// hosts may be connected; exactly one of them owns the event stream, and\n// `start`/`resume` transfer that ownership. The adapter supplies only `onStart`\n// (drive its CLI/SDK and translate to wire events) and lifecycle cleanup hooks.\n\nimport { appendFile, mkdir, writeFile } from 'node:fs/promises';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { randomUUID } from 'node:crypto';\nimport { env as procEnv, pid, stdout } from 'node:process';\nimport { WebSocketServer, type WebSocket } from 'ws';\n\nexport { HarnessBridgeCapabilityUnsupportedError } from './harness-bridge-capability-unsupported-error';\n\nexport type BridgeState = 'init' | 'waiting' | 'running' | 'draining' | 'done';\n\n/** Outbound turn event the adapter emits. `seq` is added by the runtime. */\nexport type BridgeEvent = Record<string, unknown> & { type: string };\n\nexport type BridgeDebugLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nexport interface Experimental_BridgeUserMessage {\n readonly messageId: string;\n readonly text: string;\n accept(): void;\n reject(error: unknown): void;\n}\n\nexport interface Experimental_BridgeUserMessageQueue extends AsyncIterable<Experimental_BridgeUserMessage> {\n readonly pendingCount: number;\n close(error?: unknown): void;\n}\n\ntype InternalBridgeUserMessageQueue = Experimental_BridgeUserMessageQueue & {\n enqueue(input: { messageId: string; text: string }): void;\n};\n\ntype BridgeUserMessageResponse = {\n type: 'user-message-response';\n messageId: string;\n accepted: boolean;\n error?: { message: string };\n};\n\n/**\n * Per-session diagnostics config. The host resolves it from settings +\n * env and sends it on `start.debug`; the bridge gates console capture and\n * structured `debug-event`s on it. When disabled, nothing is captured or\n * emitted and no `seq` is consumed.\n */\nexport interface BridgeDebugConfig {\n enabled?: boolean;\n level?: BridgeDebugLevel;\n subsystems?: string[];\n}\n\nconst DEBUG_LEVEL_WEIGHT: Record<BridgeDebugLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n};\n\n/** Exact-or-dotted-prefix subsystem match (`'bridge'` matches `'bridge.turn'`). */\nfunction subsystemMatches(\n filters: string[] | undefined,\n subsystem: string,\n): boolean {\n if (!filters || filters.length === 0) return true;\n return filters.some(\n filter => subsystem === filter || subsystem.startsWith(`${filter}.`),\n );\n}\n\nfunction formatBridgeError(err: unknown): {\n name?: string;\n message: string;\n stack?: string;\n} {\n if (err instanceof Error) {\n return { name: err.name, message: err.message, stack: err.stack };\n }\n if (typeof err === 'string') {\n return { message: err };\n }\n if (err !== null && typeof err === 'object') {\n try {\n return { message: JSON.stringify(err) };\n } catch {}\n }\n return { message: String(err) };\n}\n\nfunction createBridgeUserMessageQueue(options: {\n respond(response: BridgeUserMessageResponse): void;\n}): InternalBridgeUserMessageQueue {\n const messages: Experimental_BridgeUserMessage[] = [];\n const waiters: Array<\n (result: IteratorResult<Experimental_BridgeUserMessage>) => void\n > = [];\n const entries = new Map<\n string,\n {\n response?: BridgeUserMessageResponse;\n reject(error: unknown): void;\n }\n >();\n let closed = false;\n let pendingCount = 0;\n\n const enqueue = (input: { messageId: string; text: string }): void => {\n const existing = entries.get(input.messageId);\n if (existing != null) {\n if (existing.response != null) {\n options.respond(existing.response);\n }\n return;\n }\n\n let settled = false;\n const settle = (response: BridgeUserMessageResponse): void => {\n if (settled) return;\n settled = true;\n pendingCount--;\n const entry = entries.get(input.messageId);\n if (entry != null) entry.response = response;\n options.respond(response);\n };\n const message: Experimental_BridgeUserMessage = {\n messageId: input.messageId,\n text: input.text,\n accept: () => {\n settle({\n type: 'user-message-response',\n messageId: input.messageId,\n accepted: true,\n });\n },\n reject: error => {\n settle({\n type: 'user-message-response',\n messageId: input.messageId,\n accepted: false,\n error: { message: formatBridgeError(error).message },\n });\n },\n };\n entries.set(input.messageId, {\n reject: message.reject,\n });\n pendingCount++;\n\n if (closed) {\n message.reject(\n new Error('The bridge turn is no longer accepting user messages.'),\n );\n return;\n }\n\n const waiter = waiters.shift();\n if (waiter != null) {\n waiter({ done: false, value: message });\n } else {\n messages.push(message);\n }\n };\n\n const close = (error?: unknown): void => {\n if (closed) return;\n closed = true;\n const reason =\n error ??\n new Error('The bridge turn ended before accepting the user message.');\n for (const entry of entries.values()) {\n if (entry.response == null) entry.reject(reason);\n }\n messages.length = 0;\n while (waiters.length > 0) {\n waiters.shift()!({ done: true, value: undefined });\n }\n };\n\n return {\n get pendingCount() {\n return pendingCount;\n },\n enqueue,\n close,\n [Symbol.asyncIterator]() {\n return {\n next: () => {\n const message = messages.shift();\n if (message != null) {\n return Promise.resolve({ done: false as const, value: message });\n }\n if (closed) {\n return Promise.resolve({\n done: true as const,\n value: undefined,\n });\n }\n return new Promise<IteratorResult<Experimental_BridgeUserMessage>>(\n resolve => {\n waiters.push(resolve);\n },\n );\n },\n };\n },\n };\n}\n\nfunction parseEnvList(value: string | undefined): string[] | undefined {\n if (!value) return undefined;\n const items = value\n .split(',')\n .map(item => item.trim())\n .filter(Boolean);\n return items.length > 0 ? items : undefined;\n}\n\nconst ENV_TRUTHY = new Set(['1', 'true', 'yes', 'on']);\n\n/**\n * Per-turn surface handed to {@link RunBridgeOptions.onStart}. The adapter\n * drives its runtime against these primitives; the runtime owns the transport.\n */\nexport interface BridgeTurn {\n /**\n * Emit a turn event to the host. Stamps a monotonic `seq`, appends to the\n * in-memory replay log, and sends to the live socket (best-effort — if the\n * host is mid-reconnect the event waits in the log and is replayed on\n * resume).\n */\n emit(event: BridgeEvent): void;\n\n /**\n * Register interest in a host-executed tool result and resolve when the\n * matching `tool-result` arrives. The adapter emits the `tool-call` event\n * itself (via {@link emit}) using the same `toolCallId`.\n */\n requestToolResult(\n toolCallId: string,\n ): Promise<{ output: unknown; isError?: boolean }>;\n\n /**\n * Register interest in a host approval decision and resolve when the matching\n * `tool-approval-response` arrives. The adapter emits the\n * `tool-approval-request` event itself using the same `approvalId`.\n */\n requestToolApproval(\n approvalId: string,\n ): Promise<{ approved: boolean; reason?: string }>;\n\n readonly experimental_userMessages: Experimental_BridgeUserMessageQueue;\n\n /** Aborts when the host sends `abort`. */\n readonly abortSignal: AbortSignal;\n\n /** True for the first turn since this bridge process started. */\n readonly firstTurn: boolean;\n\n /**\n * Emit a structured diagnostic. Gated by the session's debug level +\n * subsystem filter; a no-op when diagnostics are disabled. Adapters use this\n * for runtime-level instrumentation; raw `console.*` output is captured and\n * forwarded automatically.\n */\n bridgeLog(input: {\n level?: BridgeDebugLevel;\n subsystem: string;\n message: string;\n attrs?: Record<string, unknown>;\n error?: unknown;\n }): void;\n\n /**\n * Emit a non-fatal bridge warning to stderr using the runtime's harness\n * prefix. This is diagnostic-only: it does not emit a stream event, does not\n * consume a `seq`, and does not fail the turn.\n */\n emitWarning(input: { message: string }): void;\n\n emitError(input: { error: unknown; message?: string }): void;\n}\n\nexport interface RunBridgeOptions<TStart extends { type: 'start' }> {\n /** Identifier written into `bridge-meta.json` (`'claude-code'` / `'codex'`). */\n bridgeType: string;\n /** Directory for `bridge-meta.json` / `start-config.json`. Created if absent. */\n bridgeStateDir: string;\n /** Drive one prompt turn. Rejections surface to the host as an `error` event. */\n onStart(start: TStart, turn: BridgeTurn): Promise<void>;\n /**\n * Produce the adapter-defined runtime resume data for `stop`. Defaults to\n * `{}`.\n */\n onStop?(): unknown | Promise<unknown>;\n /**\n * Perform adapter-defined destruction before the bridge exits.\n */\n onDestroy?(): void | Promise<void>;\n /** WS port. Defaults to `BRIDGE_WS_PORT` env (0 = OS-assigned). */\n port?: number;\n /** Auth token. Defaults to `BRIDGE_CHANNEL_TOKEN` env. */\n token?: string;\n /** Called with the bound port once the server is listening. */\n onListening?(port: number): void;\n /**\n * Tear the process down after `stop` / `destroy`. Defaults to closing\n * the server and calling `process.exit(0)`. Overridable for tests.\n */\n onExit?(): void;\n}\n\ntype InboundControl =\n | {\n type: 'tool-result';\n toolCallId: string;\n output: unknown;\n isError?: boolean;\n }\n | {\n type: 'tool-approval-response';\n approvalId: string;\n approved: boolean;\n reason?: string;\n }\n | { type: 'user-message'; messageId?: string; text: string }\n | { type: 'abort' }\n | { type: 'stop' }\n | { type: 'destroy' }\n | { type: 'resume'; lastSeenEventId: number };\n\nconst WS_OPEN = 1;\n\n/**\n * Boot the bridge: bind the WebSocket server, announce `bridge-ready`, and\n * service host connections for the lifetime of the process. Resolves once the\n * server is listening; the process then stays alive on the server until a\n * `stop` / `destroy` exits it.\n */\nexport interface BridgeHandle {\n /** The port the WebSocket server bound to. */\n readonly port: number;\n /** Close the WebSocket server. Does not call `process.exit`. */\n close(): Promise<void>;\n}\n\nexport async function runBridge<TStart extends { type: 'start' }>(\n options: RunBridgeOptions<TStart>,\n): Promise<BridgeHandle> {\n const { bridgeType, bridgeStateDir, onStart, onStop, onDestroy } = options;\n const expectedToken = options.token ?? procEnv.BRIDGE_CHANNEL_TOKEN ?? '';\n const bridgeWsPort =\n options.port ?? parseInt(procEnv.BRIDGE_WS_PORT ?? '0', 10);\n\n const bridgeMetaPath = `${bridgeStateDir}/bridge-meta.json`;\n const startConfigPath = `${bridgeStateDir}/start-config.json`;\n const rerunStartConfigPath = `${bridgeStateDir}/rerun-start-config.json`;\n const eventLogPath = `${bridgeStateDir}/event-log.ndjson`;\n\n try {\n await mkdir(bridgeStateDir, { recursive: true });\n } catch {\n // Best-effort; the bridge still runs without its state files.\n }\n\n // ─── mutable runtime state ──────────────────────────────────────────\n let currentBoundPort = 0;\n let currentTurnState: BridgeState = 'init';\n /*\n * The one connection turn events stream to. A socket claims it by asking for\n * work — `start` (a turn) or `resume` (a catch-up) — never by connecting:\n * every event goes here alone, so claiming on connect would silence a turn\n * already streaming to someone else. Any number of sockets may be connected;\n * the others still exchange control frames, they just get no events.\n */\n let activeSocket: WebSocket | undefined;\n let isFirstTurn = true;\n let turnAbort: AbortController | undefined;\n let currentUserMessages: InternalBridgeUserMessageQueue | undefined;\n\n // Diagnostics. Resolved per turn from `start.debug` with a sandbox-side\n // env fallback; gates console capture + structured `debug-event`s.\n let debugConfig: BridgeDebugConfig | undefined;\n let consoleCaptureInstalled = false;\n const envDebugEnabled = ENV_TRUTHY.has(\n (procEnv.HARNESS_DEBUG ?? '').toLowerCase(),\n );\n\n // Replay log. `seq` is monotonic across the whole process — never reset —\n // because the host's `SandboxChannel` cursor (`lastSeenEventId`) lives across\n // turns. The log *contents* are cleared at the start of each turn to bound\n // memory; the just-finished turn stays replayable until the next `start`.\n let seqCounter = 0;\n let eventLog: Array<{ seq: number; line: string }> = [];\n\n /*\n * Disk mirror of the in-memory replay log. The in-memory log is lost when the\n * bridge process dies; the on-disk `event-log.ndjson` survives in the sandbox\n * filesystem so a respawned bridge (started with `BRIDGE_REPLAY_FROM_DISK=1`)\n * can reload the in-flight turn and serve a host's resume cursor —\n * `replay` recovery. Writes are batched on `setImmediate` (single-flight via\n * `flushPromise`) to keep `emit` off the disk hot path.\n */\n let diskBuffer = '';\n let flushPromise: Promise<void> | null = null;\n\n const flushEventsToDisk = async (): Promise<void> => {\n while (diskBuffer.length > 0) {\n const buf = diskBuffer;\n diskBuffer = '';\n await appendFile(eventLogPath, buf).catch(() => {\n // Best-effort crash-recovery mirror; the in-memory log is the source of\n // truth for the live connection.\n });\n }\n };\n\n const scheduleEventFlush = (): void => {\n if (flushPromise) return;\n flushPromise = new Promise<void>(resolve => {\n setImmediate(() => {\n void flushEventsToDisk().finally(resolve);\n });\n }).finally(() => {\n flushPromise = null;\n if (diskBuffer.length > 0) {\n scheduleEventFlush();\n }\n });\n };\n\n const flushPendingEventsToDisk = async (): Promise<void> => {\n if (diskBuffer.length > 0 && !flushPromise) {\n scheduleEventFlush();\n }\n // Await each in-flight flush, re-reading `flushPromise` after every await\n // since a fresh flush may have been scheduled for buffer that arrived while\n // we waited.\n let inFlight = flushPromise;\n while (inFlight) {\n await inFlight;\n inFlight = flushPromise;\n }\n };\n\n /*\n * When respawned for `replay`, reload the previous turn's log from disk before\n * accepting any connection so the very first `resume{lastSeenEventId}` can be\n * served the tail (including the terminal `finish`). The seq counter is\n * restored to the last persisted seq so it stays aligned with the host's\n * long-lived cursor. The file is NOT truncated in this mode — only a fresh\n * `start` (next turn) clears it.\n */\n const replayFromDisk = procEnv.BRIDGE_REPLAY_FROM_DISK === '1';\n if (replayFromDisk && existsSync(eventLogPath)) {\n try {\n const lines = readFileSync(eventLogPath, 'utf8')\n .split('\\n')\n .map(line => line.trim())\n .filter(Boolean);\n eventLog = lines.map(line => ({\n seq: (JSON.parse(line) as { seq: number }).seq,\n line,\n }));\n seqCounter = eventLog.at(-1)?.seq ?? 0;\n } catch {\n // Corrupt/partial log: fall back to an empty log; the host then degrades\n // to `rerun` instead of replaying a malformed tail.\n eventLog = [];\n seqCounter = 0;\n }\n }\n\n const pendingToolResults = new Map<\n string,\n (output: { output: unknown; isError?: boolean }) => void\n >();\n const pendingToolApprovals = new Map<\n string,\n (response: { approved: boolean; reason?: string }) => void\n >();\n\n // ─── persistence (best-effort meta + start config) ──────────────────\n const writeBridgeMeta = async (state: BridgeState): Promise<void> => {\n try {\n await writeFile(\n bridgeMetaPath,\n JSON.stringify({\n type: bridgeType,\n port: currentBoundPort,\n state,\n pid,\n }),\n );\n } catch {\n // Best-effort resilience metadata; not load-bearing for the active turn.\n }\n };\n\n const writeStartConfig = async (start: unknown): Promise<void> => {\n try {\n const serialized = JSON.stringify(start);\n await writeFile(startConfigPath, serialized);\n // Frozen copy: written once, restored over start-config.json by future\n // rerun-mode recovery to re-run the original turn from scratch.\n if (!existsSync(rerunStartConfigPath)) {\n await writeFile(rerunStartConfigPath, serialized);\n }\n } catch {\n // Best-effort.\n }\n };\n\n // ─── wire send + replay ─────────────────────────────────────────────\n const emit = (event: BridgeEvent): void => {\n const seq = ++seqCounter;\n const line = JSON.stringify({ ...event, seq });\n eventLog.push({ seq, line });\n diskBuffer += `${line}\\n`;\n scheduleEventFlush();\n if (activeSocket?.readyState === WS_OPEN) {\n try {\n activeSocket.send(line);\n } catch {\n // Send is best-effort: a dropped socket leaves the event in the log,\n // replayed once the host reconnects and sends `resume`.\n }\n }\n };\n\n const replay = (ws: WebSocket, afterSeq: number): void => {\n for (const entry of eventLog) {\n if (entry.seq > afterSeq && ws.readyState === WS_OPEN) {\n ws.send(entry.line);\n }\n }\n };\n\n // ─── diagnostics ──────────────────────────────────────────────\n const shouldEmitDebugEvent = (\n level: BridgeDebugLevel,\n subsystem: string,\n ): boolean => {\n if (!debugConfig?.enabled) return false;\n const threshold = debugConfig.level ?? 'debug';\n if (DEBUG_LEVEL_WEIGHT[level] > DEBUG_LEVEL_WEIGHT[threshold]) return false;\n return subsystemMatches(debugConfig.subsystems, subsystem);\n };\n\n /*\n * Forward sandbox console output. We line-buffer the original writers (kept so\n * output still reaches the real fds) and emit one `sandbox-log` per complete\n * line. `emit` never writes to stdout/stderr, so there is no recursion.\n * Installed lazily the first time a turn enables diagnostics; once installed,\n * capture is gated per-write on `debugConfig.enabled` so a later turn can\n * disable it. Console capture is independent of the subsystem/level filter.\n */\n const rawStdoutWrite = process.stdout.write.bind(process.stdout);\n const rawStderrWrite = process.stderr.write.bind(process.stderr);\n\n const writeErrorToStderr = (input: {\n message: string;\n error: unknown;\n }): void => {\n try {\n const formatted = formatBridgeError(input.error);\n rawStderrWrite(\n `[harness:${bridgeType}:error] ${input.message}: ${formatted.message}\\n`,\n );\n if (formatted.stack) {\n rawStderrWrite(`${formatted.stack}\\n`);\n }\n } catch {}\n };\n\n const emitWarning = (input: { message: string }): void => {\n try {\n for (const line of input.message.split('\\n')) {\n if (line.trim().length > 0) {\n rawStderrWrite(`[harness:${bridgeType}:warn] ${line}\\n`);\n }\n }\n } catch {}\n };\n\n const emitError = (input: { error: unknown; message?: string }): void => {\n writeErrorToStderr({\n message: input.message ?? 'bridge error',\n error: input.error,\n });\n emit({ type: 'error', error: serialiseError(input.error) });\n };\n\n const installConsoleCapture = (): void => {\n if (consoleCaptureInstalled) return;\n consoleCaptureInstalled = true;\n const buffers: { stdout: string; stderr: string } = {\n stdout: '',\n stderr: '',\n };\n const patch =\n (stream: 'stdout' | 'stderr', raw: typeof process.stdout.write) =>\n (chunk: unknown, encoding?: unknown, cb?: unknown): boolean => {\n if (debugConfig?.enabled) {\n try {\n const enc = typeof encoding === 'string' ? encoding : 'utf8';\n const text =\n typeof chunk === 'string'\n ? chunk\n : Buffer.from(chunk as Uint8Array).toString(\n enc as BufferEncoding,\n );\n const combined = buffers[stream] + text.replace(/\\r\\n/g, '\\n');\n const parts = combined.split('\\n');\n buffers[stream] = parts.pop() ?? '';\n for (const line of parts) {\n const trimmed = line.replace(/\\s+$/, '');\n if (trimmed) {\n emit({\n type: 'sandbox-log',\n source: bridgeType,\n stream,\n line: trimmed,\n });\n }\n }\n } catch {\n // Never let capture break real output.\n }\n }\n return (raw as (c: unknown, e?: unknown, cb?: unknown) => boolean)(\n chunk,\n encoding,\n cb,\n );\n };\n process.stdout.write = patch(\n 'stdout',\n rawStdoutWrite,\n ) as typeof process.stdout.write;\n process.stderr.write = patch(\n 'stderr',\n rawStderrWrite,\n ) as typeof process.stderr.write;\n };\n\n // ─── inbound routing ────────────────────────────────────────────────\n const handleInbound = async (\n msg: TStart | InboundControl,\n ws: WebSocket,\n ): Promise<void> => {\n switch (msg.type) {\n case 'start': {\n activeSocket = ws; // asking for a turn claims the event stream\n currentUserMessages?.close(\n new Error('A new bridge turn replaced the active turn.'),\n );\n const firstTurn = isFirstTurn;\n isFirstTurn = false;\n eventLog = []; // clear previous turn; keep seqCounter monotonic\n // Mirror the in-memory clear to disk: the log tracks only the current\n // turn. Discard any unflushed tail from the prior turn first.\n diskBuffer = '';\n void writeFile(eventLogPath, '').catch(() => {});\n turnAbort = new AbortController();\n currentTurnState = 'running';\n void writeStartConfig(msg);\n void writeBridgeMeta('running');\n const startDebug = (msg as { debug?: BridgeDebugConfig }).debug;\n debugConfig = {\n enabled: startDebug?.enabled ?? envDebugEnabled,\n level:\n startDebug?.level ??\n (procEnv.HARNESS_DEBUG_LEVEL as BridgeDebugLevel | undefined),\n subsystems:\n startDebug?.subsystems ??\n parseEnvList(procEnv.HARNESS_DEBUG_SUBSYSTEMS),\n };\n if (debugConfig.enabled) {\n installConsoleCapture();\n }\n const userMessages = createBridgeUserMessageQueue({ respond: emit });\n const turn: BridgeTurn = {\n emit,\n requestToolResult: toolCallId =>\n new Promise(resolve => {\n pendingToolResults.set(toolCallId, resolve);\n }),\n requestToolApproval: approvalId =>\n new Promise(resolve => {\n pendingToolApprovals.set(approvalId, resolve);\n }),\n experimental_userMessages: userMessages,\n abortSignal: turnAbort.signal,\n firstTurn,\n bridgeLog: input => {\n const level = input.level ?? 'debug';\n if (!shouldEmitDebugEvent(level, input.subsystem)) return;\n emit({\n type: 'debug-event',\n level,\n subsystem: input.subsystem,\n message: input.message,\n ...(input.attrs ? { attrs: input.attrs } : {}),\n ...(input.error !== undefined\n ? { error: formatBridgeError(input.error) }\n : {}),\n });\n },\n emitWarning,\n emitError,\n };\n currentUserMessages = userMessages;\n try {\n await onStart(msg as TStart, turn);\n } catch (err) {\n emitError({ error: err, message: 'bridge turn failed' });\n } finally {\n userMessages.close();\n if (currentUserMessages === userMessages) {\n currentUserMessages = undefined;\n }\n 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 const messageId = msg.messageId ?? randomUUID();\n if (currentUserMessages == null) {\n sendControl(ws, {\n type: 'user-message-response',\n messageId,\n accepted: false,\n error: { message: 'The bridge has no active turn to steer.' },\n });\n return;\n }\n if (ws !== activeSocket) {\n sendControl(ws, {\n type: 'user-message-response',\n messageId,\n accepted: false,\n error: {\n message: 'The connection does not own the active bridge turn.',\n },\n });\n return;\n }\n currentUserMessages.enqueue({\n messageId,\n text: msg.text,\n });\n return;\n }\n case 'abort':\n turnAbort?.abort();\n return;\n case 'resume':\n activeSocket = ws; // asking for a catch-up claims it too\n // Synchronous, so no event can slip out live ahead of the replayed tail.\n replay(ws, msg.lastSeenEventId);\n return;\n case 'destroy':\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n await onDestroy?.();\n drainThenExit(ws, 1000, 'destroy');\n return;\n case 'stop': {\n currentTurnState = 'done';\n void writeBridgeMeta('done');\n const data = (await onStop?.()) ?? {};\n sendControl(ws, { type: 'bridge-stop', data });\n drainThenExit(ws, 1000, 'stop');\n return;\n }\n }\n };\n\n // ─── server ─────────────────────────────────────────────────────────\n void writeBridgeMeta('init');\n\n const wss = new WebSocketServer({ port: bridgeWsPort, host: '0.0.0.0' });\n\n const exit = (): void => {\n if (options.onExit) {\n options.onExit();\n return;\n }\n wss.close(() => process.exit(0));\n setTimeout(() => process.exit(0), 1000).unref();\n };\n\n const drainThenExit = (ws: WebSocket, code: number, reason: string): void => {\n const start = Date.now();\n const tick = (): void => {\n const drained = ws.bufferedAmount === 0 || ws.readyState !== WS_OPEN;\n if (drained || Date.now() - start >= 5_000) {\n // Flush the on-disk log so a clean stop/destroy leaves a complete\n // event-log.ndjson for any later replay recovery.\n void flushPendingEventsToDisk().finally(() => {\n try {\n ws.close(code, reason);\n } finally {\n exit();\n }\n });\n return;\n }\n setTimeout(tick, 10).unref();\n };\n tick();\n };\n\n wss.on('listening', () => {\n const addr = wss.address();\n currentBoundPort = typeof addr === 'object' && addr ? addr.port : 0;\n currentTurnState = 'waiting';\n void writeBridgeMeta('waiting');\n stdout.write(\n JSON.stringify({\n type: 'bridge-ready',\n port: currentBoundPort,\n }) + '\\n',\n );\n options.onListening?.(currentBoundPort);\n });\n\n wss.on('connection', (ws: WebSocket, req: { url?: string }) => {\n const url = new URL(req.url ?? '/', 'http://localhost');\n if (url.searchParams.get('agent_bridge_token') !== expectedToken) {\n ws.close(1008, 'unauthorized');\n return;\n }\n\n // Announce liveness the instant we accept. Some sandbox runtimes complete\n // the host-side WS handshake before the connection is forwarded here; the\n // host waits for this frame before sending `start`/`resume`.\n sendControl(ws, {\n type: 'bridge-hello',\n state: currentTurnState,\n lastSeq: seqCounter,\n capabilities: { experimental_userMessageResponses: true },\n });\n\n ws.on('message', (raw: ArrayBufferLike | string) => {\n let parsed: TStart | InboundControl;\n try {\n const text =\n typeof raw === 'string' ? raw : Buffer.from(raw).toString('utf8');\n parsed = JSON.parse(text) as TStart | InboundControl;\n } catch (err) {\n sendControl(ws, {\n type: 'error',\n error: `protocol parse error: ${(err as Error).message}`,\n });\n return;\n }\n void handleInbound(parsed, ws);\n });\n\n ws.on('close', () => {\n // Only the stream owner's close matters; a socket that never claimed it,\n // or that a later `start`/`resume` displaced, closes as a no-op.\n // Crucially we do NOT abort the in-flight turn: it keeps running and its\n // events accumulate in the log for replay on reconnect.\n if (activeSocket === ws) {\n activeSocket = undefined;\n }\n });\n\n ws.on('error', () => {\n // 'close' follows; nothing to do beyond keeping the process alive.\n });\n });\n\n // Surface bridge-internal crashes to the host instead of dying silently.\n process.on('uncaughtException', err => {\n emitError({ error: err, message: 'uncaught exception' });\n });\n process.on('unhandledRejection', err => {\n emitError({ error: err, message: 'unhandled rejection' });\n });\n\n await new Promise<void>((resolve, reject) => {\n if (wss.address() != null) {\n resolve();\n return;\n }\n\n wss.once('listening', resolve);\n wss.once('error', reject);\n });\n\n return {\n port: currentBoundPort,\n close: () =>\n new Promise<void>(resolve => {\n wss.close(() => resolve());\n }),\n };\n}\n\n/*\n * Control frames answer the socket that sent the frame they reply to, so the\n * target is always explicit. Event streaming is the separate, stateful path\n * (`emit` → `activeSocket`); this one carries no state at all.\n */\nfunction sendControl(\n socket: WebSocket | undefined,\n message: Record<string, unknown>,\n): void {\n if (socket?.readyState === WS_OPEN) {\n try {\n socket.send(JSON.stringify(message));\n } catch {\n // best-effort\n }\n }\n}\n\nfunction serialiseError(err: unknown): unknown {\n if (err instanceof Error) {\n return { name: err.name, message: err.message, stack: err.stack };\n }\n return err;\n}\n","const name = 'AI_HarnessBridgeCapabilityUnsupportedError';\n\n/**\n * Signals an unsupported capability discovered inside a sandbox bridge.\n * `isInstance` also recognizes the serialized error shape received by the\n * host, where it can be translated to `HarnessCapabilityUnsupportedError`.\n */\nexport class HarnessBridgeCapabilityUnsupportedError extends Error {\n readonly harnessId?: string;\n readonly cause?: unknown;\n\n constructor({\n message,\n harnessId,\n cause,\n }: {\n message: string;\n harnessId?: string;\n cause?: unknown;\n }) {\n super(message);\n Object.defineProperty(this, 'name', { value: name });\n this.harnessId = harnessId;\n this.cause = cause;\n }\n\n static isInstance(\n error: unknown,\n ): error is HarnessBridgeCapabilityUnsupportedError {\n return (\n error != null &&\n typeof error === 'object' &&\n 'name' in error &&\n error.name === name &&\n 'message' in error &&\n typeof error.message === 'string'\n );\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -887,20 +887,16 @@ type HarnessV1StartOptions = {
|
|
|
887
887
|
*/
|
|
888
888
|
readonly observability?: HarnessV1Observability;
|
|
889
889
|
/**
|
|
890
|
-
*
|
|
891
|
-
*
|
|
892
|
-
*
|
|
893
|
-
*
|
|
894
|
-
* `setRequestTransformations`, `addRequestTransformations`) for bridge
|
|
895
|
-
* wiring. Adapters must not call `stop()` themselves; the agent does that
|
|
896
|
-
* during cleanup.
|
|
890
|
+
* Sandbox session the adapter operates against. Network sandbox sessions
|
|
891
|
+
* expose optional infrastructure capabilities for bridge wiring; caller-
|
|
892
|
+
* provided basic sandbox sessions expose only filesystem and process APIs.
|
|
893
|
+
* Adapters must not stop or destroy the sandbox themselves.
|
|
897
894
|
*/
|
|
898
|
-
readonly sandboxSession: HarnessV1NetworkSandboxSession;
|
|
895
|
+
readonly sandboxSession: HarnessV1NetworkSandboxSession | Experimental_SandboxSession;
|
|
899
896
|
/**
|
|
900
|
-
* Absolute path the adapter runs the agent in for this session. Composed
|
|
901
|
-
* the
|
|
902
|
-
*
|
|
903
|
-
* deriving its own provider-specific path.
|
|
897
|
+
* Absolute path the adapter runs the agent in for this session. Composed
|
|
898
|
+
* underneath the sandbox's resolved default working directory and created
|
|
899
|
+
* before `doStart`.
|
|
904
900
|
*/
|
|
905
901
|
readonly sessionWorkDir: string;
|
|
906
902
|
};
|
|
@@ -1398,6 +1394,17 @@ declare const harnessV1BridgeHelloSchema: z.ZodObject<{
|
|
|
1398
1394
|
type: z.ZodLiteral<"bridge-hello">;
|
|
1399
1395
|
state: z.ZodOptional<z.ZodString>;
|
|
1400
1396
|
lastSeq: z.ZodOptional<z.ZodNumber>;
|
|
1397
|
+
capabilities: z.ZodOptional<z.ZodObject<{
|
|
1398
|
+
experimental_userMessageResponses: z.ZodOptional<z.ZodBoolean>;
|
|
1399
|
+
}, z.core.$strip>>;
|
|
1400
|
+
}, z.core.$strip>;
|
|
1401
|
+
declare const experimental_harnessV1BridgeUserMessageResponseSchema: z.ZodObject<{
|
|
1402
|
+
type: z.ZodLiteral<"user-message-response">;
|
|
1403
|
+
messageId: z.ZodString;
|
|
1404
|
+
accepted: z.ZodBoolean;
|
|
1405
|
+
error: z.ZodOptional<z.ZodObject<{
|
|
1406
|
+
message: z.ZodString;
|
|
1407
|
+
}, z.core.$strip>>;
|
|
1401
1408
|
}, z.core.$strip>;
|
|
1402
1409
|
/**
|
|
1403
1410
|
* The bridge's reply to an inbound `stop`. Carries the adapter-specific
|
|
@@ -1548,6 +1555,16 @@ declare const harnessV1BridgeOutboundMessageSchema: z.ZodDiscriminatedUnion<[z.Z
|
|
|
1548
1555
|
type: z.ZodLiteral<"bridge-hello">;
|
|
1549
1556
|
state: z.ZodOptional<z.ZodString>;
|
|
1550
1557
|
lastSeq: z.ZodOptional<z.ZodNumber>;
|
|
1558
|
+
capabilities: z.ZodOptional<z.ZodObject<{
|
|
1559
|
+
experimental_userMessageResponses: z.ZodOptional<z.ZodBoolean>;
|
|
1560
|
+
}, z.core.$strip>>;
|
|
1561
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1562
|
+
type: z.ZodLiteral<"user-message-response">;
|
|
1563
|
+
messageId: z.ZodString;
|
|
1564
|
+
accepted: z.ZodBoolean;
|
|
1565
|
+
error: z.ZodOptional<z.ZodObject<{
|
|
1566
|
+
message: z.ZodString;
|
|
1567
|
+
}, z.core.$strip>>;
|
|
1551
1568
|
}, z.core.$strip>, z.ZodObject<{
|
|
1552
1569
|
type: z.ZodLiteral<"bridge-stop">;
|
|
1553
1570
|
data: z.ZodUnknown;
|
|
@@ -1581,6 +1598,7 @@ declare const harnessV1BridgeOutboundMessageSchema: z.ZodDiscriminatedUnion<[z.Z
|
|
|
1581
1598
|
}, z.core.$strip>>;
|
|
1582
1599
|
}, z.core.$strip>]>;
|
|
1583
1600
|
type HarnessV1BridgeOutboundMessage = z.infer<typeof harnessV1BridgeOutboundMessageSchema>;
|
|
1601
|
+
type Experimental_HarnessV1BridgeUserMessageResponse = z.infer<typeof experimental_harnessV1BridgeUserMessageResponseSchema>;
|
|
1584
1602
|
type HarnessV1BridgeSandboxLog = z.infer<typeof harnessV1BridgeSandboxLogSchema>;
|
|
1585
1603
|
type HarnessV1BridgeDebugEvent = z.infer<typeof harnessV1BridgeDebugEventSchema>;
|
|
1586
1604
|
/**
|
|
@@ -1607,8 +1625,14 @@ declare const harnessV1BridgeToolApprovalResponseInboundSchema: z.ZodObject<{
|
|
|
1607
1625
|
reason: z.ZodOptional<z.ZodString>;
|
|
1608
1626
|
}, z.core.$strip>;
|
|
1609
1627
|
declare const harnessV1BridgeUserMessageInboundSchema: z.ZodObject<{
|
|
1628
|
+
type: z.ZodLiteral<"user-message">;
|
|
1629
|
+
messageId: z.ZodOptional<z.ZodString>;
|
|
1630
|
+
text: z.ZodString;
|
|
1631
|
+
}, z.core.$strip>;
|
|
1632
|
+
declare const experimental_harnessV1BridgeUserMessageInboundSchema: z.ZodObject<{
|
|
1610
1633
|
type: z.ZodLiteral<"user-message">;
|
|
1611
1634
|
text: z.ZodString;
|
|
1635
|
+
messageId: z.ZodString;
|
|
1612
1636
|
}, z.core.$strip>;
|
|
1613
1637
|
declare const harnessV1BridgeAbortInboundSchema: z.ZodObject<{
|
|
1614
1638
|
type: z.ZodLiteral<"abort">;
|
|
@@ -1648,6 +1672,7 @@ declare const harnessV1BridgeInboundCommandSchemas: readonly [z.ZodObject<{
|
|
|
1648
1672
|
reason: z.ZodOptional<z.ZodString>;
|
|
1649
1673
|
}, z.core.$strip>, z.ZodObject<{
|
|
1650
1674
|
type: z.ZodLiteral<"user-message">;
|
|
1675
|
+
messageId: z.ZodOptional<z.ZodString>;
|
|
1651
1676
|
text: z.ZodString;
|
|
1652
1677
|
}, z.core.$strip>, z.ZodObject<{
|
|
1653
1678
|
type: z.ZodLiteral<"abort">;
|
|
@@ -1723,4 +1748,4 @@ declare class HarnessSandboxAuthenticationError extends HarnessError {
|
|
|
1723
1748
|
static isInstance(error: unknown): error is HarnessSandboxAuthenticationError;
|
|
1724
1749
|
}
|
|
1725
1750
|
|
|
1726
|
-
export { HARNESS_V1_BUILTIN_TOOLS, HARNESS_V1_BUILTIN_TOOL_NAMES, HarnessCapabilityUnsupportedError, HarnessError, HarnessSandboxAuthenticationError, type HarnessV1, type HarnessV1Bootstrap, type HarnessV1BootstrapCommand, type HarnessV1BootstrapFile, type HarnessV1BridgeDebugEvent, type HarnessV1BridgeOutboundMessage, type HarnessV1BridgeReady, type HarnessV1BridgeSandboxLog, type HarnessV1BridgeToolWire, type HarnessV1BuiltinTool, type HarnessV1BuiltinToolFiltering, type HarnessV1BuiltinToolName, type HarnessV1BuiltinToolUseKind, type HarnessV1CallWarning, type HarnessV1ContinueTurnOptions, type HarnessV1ContinueTurnState, type HarnessV1DebugConfig, type HarnessV1DebugLevel, type HarnessV1Diagnostic, type HarnessV1JSONArray, type HarnessV1JSONObject, type HarnessV1JSONSchema, type HarnessV1JSONValue, type HarnessV1LifecycleState, type HarnessV1Metadata, type HarnessV1NetworkPolicy, type HarnessV1NetworkSandboxSession, type HarnessV1Observability, type HarnessV1PendingToolApproval, type HarnessV1PendingToolResult, type HarnessV1PermissionMode, type HarnessV1PortEndpoint, type HarnessV1Prompt, type HarnessV1PromptControl, type HarnessV1PromptTurnOptions, type HarnessV1RequestTransformation, type HarnessV1ResponseFormat, type HarnessV1ResumeSessionState, type HarnessV1SandboxProvider, type HarnessV1Session, type HarnessV1Skill, type HarnessV1StartOptions, type HarnessV1StreamPart, type HarnessV1ToolSpec, commonTool, getHarnessV1BuiltinToolFilteringDenialReason, harnessV1BridgeAbortInboundSchema, harnessV1BridgeBuiltinToolFilteringSchema, harnessV1BridgeDebugEventSchema, harnessV1BridgeDestroyInboundSchema, harnessV1BridgeHelloSchema, harnessV1BridgeInboundCommandSchemas, harnessV1BridgeOutboundMessageSchema, harnessV1BridgePermissionModeSchema, harnessV1BridgeReadySchema, harnessV1BridgeResponseFormatSchema, harnessV1BridgeResumeInboundSchema, harnessV1BridgeSandboxLogSchema, harnessV1BridgeStartBaseSchema, harnessV1BridgeStopInboundSchema, harnessV1BridgeStopSchema, harnessV1BridgeThreadSchema, harnessV1BridgeToolApprovalResponseInboundSchema, harnessV1BridgeToolResultInboundSchema, harnessV1BridgeToolWireSchema, harnessV1BridgeUserMessageInboundSchema, harnessV1DebugConfigSchema, harnessV1DebugLevelSchema, harnessV1DiagnosticFromBridgeFrame, harnessV1ErrorPartSchema, harnessV1FileChangePartSchema, harnessV1FinishPartSchema, harnessV1FinishStepPartSchema, harnessV1RawPartSchema, harnessV1ReasoningDeltaPartSchema, harnessV1ReasoningEndPartSchema, harnessV1ReasoningStartPartSchema, harnessV1StreamPartSchema, harnessV1StreamStartPartSchema, harnessV1TextDeltaPartSchema, harnessV1TextEndPartSchema, harnessV1TextStartPartSchema, harnessV1ToolApprovalRequestPartSchema, harnessV1ToolCallPartSchema, harnessV1ToolResultPartSchema, isHarnessV1BuiltinToolIncluded };
|
|
1751
|
+
export { type Experimental_HarnessV1BridgeUserMessageResponse, HARNESS_V1_BUILTIN_TOOLS, HARNESS_V1_BUILTIN_TOOL_NAMES, HarnessCapabilityUnsupportedError, HarnessError, HarnessSandboxAuthenticationError, type HarnessV1, type HarnessV1Bootstrap, type HarnessV1BootstrapCommand, type HarnessV1BootstrapFile, type HarnessV1BridgeDebugEvent, type HarnessV1BridgeOutboundMessage, type HarnessV1BridgeReady, type HarnessV1BridgeSandboxLog, type HarnessV1BridgeToolWire, type HarnessV1BuiltinTool, type HarnessV1BuiltinToolFiltering, type HarnessV1BuiltinToolName, type HarnessV1BuiltinToolUseKind, type HarnessV1CallWarning, type HarnessV1ContinueTurnOptions, type HarnessV1ContinueTurnState, type HarnessV1DebugConfig, type HarnessV1DebugLevel, type HarnessV1Diagnostic, type HarnessV1JSONArray, type HarnessV1JSONObject, type HarnessV1JSONSchema, type HarnessV1JSONValue, type HarnessV1LifecycleState, type HarnessV1Metadata, type HarnessV1NetworkPolicy, type HarnessV1NetworkSandboxSession, type HarnessV1Observability, type HarnessV1PendingToolApproval, type HarnessV1PendingToolResult, type HarnessV1PermissionMode, type HarnessV1PortEndpoint, type HarnessV1Prompt, type HarnessV1PromptControl, type HarnessV1PromptTurnOptions, type HarnessV1RequestTransformation, type HarnessV1ResponseFormat, type HarnessV1ResumeSessionState, type HarnessV1SandboxProvider, type HarnessV1Session, type HarnessV1Skill, type HarnessV1StartOptions, type HarnessV1StreamPart, type HarnessV1ToolSpec, commonTool, experimental_harnessV1BridgeUserMessageInboundSchema, experimental_harnessV1BridgeUserMessageResponseSchema, getHarnessV1BuiltinToolFilteringDenialReason, harnessV1BridgeAbortInboundSchema, harnessV1BridgeBuiltinToolFilteringSchema, harnessV1BridgeDebugEventSchema, harnessV1BridgeDestroyInboundSchema, harnessV1BridgeHelloSchema, harnessV1BridgeInboundCommandSchemas, harnessV1BridgeOutboundMessageSchema, harnessV1BridgePermissionModeSchema, harnessV1BridgeReadySchema, harnessV1BridgeResponseFormatSchema, harnessV1BridgeResumeInboundSchema, harnessV1BridgeSandboxLogSchema, harnessV1BridgeStartBaseSchema, harnessV1BridgeStopInboundSchema, harnessV1BridgeStopSchema, harnessV1BridgeThreadSchema, harnessV1BridgeToolApprovalResponseInboundSchema, harnessV1BridgeToolResultInboundSchema, harnessV1BridgeToolWireSchema, harnessV1BridgeUserMessageInboundSchema, harnessV1DebugConfigSchema, harnessV1DebugLevelSchema, harnessV1DiagnosticFromBridgeFrame, harnessV1ErrorPartSchema, harnessV1FileChangePartSchema, harnessV1FinishPartSchema, harnessV1FinishStepPartSchema, harnessV1RawPartSchema, harnessV1ReasoningDeltaPartSchema, harnessV1ReasoningEndPartSchema, harnessV1ReasoningStartPartSchema, harnessV1StreamPartSchema, harnessV1StreamStartPartSchema, harnessV1TextDeltaPartSchema, harnessV1TextEndPartSchema, harnessV1TextStartPartSchema, harnessV1ToolApprovalRequestPartSchema, harnessV1ToolCallPartSchema, harnessV1ToolResultPartSchema, isHarnessV1BuiltinToolIncluded };
|
package/dist/index.js
CHANGED
|
@@ -300,7 +300,16 @@ var harnessV1BridgeStartBaseSchema = z4.object({
|
|
|
300
300
|
var harnessV1BridgeHelloSchema = z4.object({
|
|
301
301
|
type: z4.literal("bridge-hello"),
|
|
302
302
|
state: z4.string().optional(),
|
|
303
|
-
lastSeq: z4.number().optional()
|
|
303
|
+
lastSeq: z4.number().optional(),
|
|
304
|
+
capabilities: z4.object({
|
|
305
|
+
experimental_userMessageResponses: z4.boolean().optional()
|
|
306
|
+
}).optional()
|
|
307
|
+
});
|
|
308
|
+
var experimental_harnessV1BridgeUserMessageResponseSchema = z4.object({
|
|
309
|
+
type: z4.literal("user-message-response"),
|
|
310
|
+
messageId: z4.string(),
|
|
311
|
+
accepted: z4.boolean(),
|
|
312
|
+
error: z4.object({ message: z4.string() }).optional()
|
|
304
313
|
});
|
|
305
314
|
var harnessV1BridgeStopSchema = z4.object({
|
|
306
315
|
type: z4.literal("bridge-stop"),
|
|
@@ -348,6 +357,7 @@ var harnessV1BridgeOutboundMessageSchema = z4.discriminatedUnion(
|
|
|
348
357
|
harnessV1ErrorPartSchema,
|
|
349
358
|
harnessV1RawPartSchema,
|
|
350
359
|
harnessV1BridgeHelloSchema,
|
|
360
|
+
experimental_harnessV1BridgeUserMessageResponseSchema,
|
|
351
361
|
harnessV1BridgeStopSchema,
|
|
352
362
|
harnessV1BridgeThreadSchema,
|
|
353
363
|
harnessV1BridgeSandboxLogSchema,
|
|
@@ -392,8 +402,12 @@ var harnessV1BridgeToolApprovalResponseInboundSchema = z4.object({
|
|
|
392
402
|
});
|
|
393
403
|
var harnessV1BridgeUserMessageInboundSchema = z4.object({
|
|
394
404
|
type: z4.literal("user-message"),
|
|
405
|
+
messageId: z4.string().optional(),
|
|
395
406
|
text: z4.string()
|
|
396
407
|
});
|
|
408
|
+
var experimental_harnessV1BridgeUserMessageInboundSchema = harnessV1BridgeUserMessageInboundSchema.extend({
|
|
409
|
+
messageId: z4.string()
|
|
410
|
+
});
|
|
397
411
|
var harnessV1BridgeAbortInboundSchema = z4.object({
|
|
398
412
|
type: z4.literal("abort")
|
|
399
413
|
});
|
|
@@ -496,6 +510,8 @@ export {
|
|
|
496
510
|
HarnessError,
|
|
497
511
|
HarnessSandboxAuthenticationError,
|
|
498
512
|
commonTool,
|
|
513
|
+
experimental_harnessV1BridgeUserMessageInboundSchema,
|
|
514
|
+
experimental_harnessV1BridgeUserMessageResponseSchema,
|
|
499
515
|
getHarnessV1BuiltinToolFilteringDenialReason,
|
|
500
516
|
harnessV1BridgeAbortInboundSchema,
|
|
501
517
|
harnessV1BridgeBuiltinToolFilteringSchema,
|