@ai-sdk/harness-claude-code 1.0.96 → 1.0.97
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 +16 -0
- package/dist/bridge/index.mjs +60 -13
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/bridge/package.json +3 -3
- package/dist/bridge/pnpm-lock.yaml +128 -126
- package/dist/bridge/pnpm-workspace.yaml +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +32 -25
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/bridge/index.ts +69 -8
- package/src/bridge/package.json +3 -3
- package/src/bridge/pnpm-lock.yaml +128 -126
- package/src/bridge/pnpm-workspace.yaml +1 -1
- package/src/claude-code-harness.ts +49 -35
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @ai-sdk/harness-claude-code
|
|
2
2
|
|
|
3
|
+
## 1.0.97
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- cc9f6ce: fix(harness): stop diagnosing caller-initiated aborts as bridge errors, and serialize bridge turns so a start racing an aborted turn's teardown no longer overlaps it (bounded by a teardown grace period, after which the start proceeds as before)
|
|
8
|
+
- 7608210: feat(harness): add `model` parameter to `HarnessAgent` instead of having each harness adapter support it on their own constructor functions
|
|
9
|
+
- f7bd978: chore(harness): update underlying adapter SDKs to their latest versions
|
|
10
|
+
- 14d4fc0: feat(harness): allow changing harness settings between turns via `prepareCall()` support on `HarnessAgent`
|
|
11
|
+
- Updated dependencies [cc9f6ce]
|
|
12
|
+
- Updated dependencies [7608210]
|
|
13
|
+
- Updated dependencies [6f8a2d7]
|
|
14
|
+
- Updated dependencies [14d4fc0]
|
|
15
|
+
- Updated dependencies [90192f1]
|
|
16
|
+
- @ai-sdk/harness@1.0.93
|
|
17
|
+
- @ai-sdk/provider-utils@5.0.33
|
|
18
|
+
|
|
3
19
|
## 1.0.96
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/dist/bridge/index.mjs
CHANGED
|
@@ -141,6 +141,7 @@ var ENV_TRUTHY = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
|
|
|
141
141
|
var WS_OPEN = 1;
|
|
142
142
|
async function runBridge(options) {
|
|
143
143
|
const { bridgeType, bridgeStateDir: bridgeStateDir2, onStart, onStop, onDestroy } = options;
|
|
144
|
+
const teardownGraceMs = options.turnTeardownGraceMs ?? 1e4;
|
|
144
145
|
const expectedToken = options.token ?? procEnv.BRIDGE_CHANNEL_TOKEN ?? "";
|
|
145
146
|
const bridgeWsPort = options.port ?? parseInt(procEnv.BRIDGE_WS_PORT ?? "0", 10);
|
|
146
147
|
const bridgeMetaPath = `${bridgeStateDir2}/bridge-meta.json`;
|
|
@@ -157,6 +158,7 @@ async function runBridge(options) {
|
|
|
157
158
|
let isFirstTurn = true;
|
|
158
159
|
let turnAbort;
|
|
159
160
|
let currentUserMessages;
|
|
161
|
+
let activeTurn;
|
|
160
162
|
let debugConfig;
|
|
161
163
|
let consoleCaptureInstalled = false;
|
|
162
164
|
const envDebugEnabled = ENV_TRUTHY.has(
|
|
@@ -347,10 +349,28 @@ async function runBridge(options) {
|
|
|
347
349
|
const handleInbound = async (msg, ws) => {
|
|
348
350
|
switch (msg.type) {
|
|
349
351
|
case "start": {
|
|
352
|
+
for (; ; ) {
|
|
353
|
+
const pendingTurn = activeTurn;
|
|
354
|
+
if (pendingTurn == null) break;
|
|
355
|
+
turnAbort?.abort();
|
|
356
|
+
currentUserMessages?.close(
|
|
357
|
+
new Error("A new bridge turn replaced the active turn.")
|
|
358
|
+
);
|
|
359
|
+
let graceTimer;
|
|
360
|
+
const settled = await Promise.race([
|
|
361
|
+
pendingTurn.then(() => true),
|
|
362
|
+
new Promise((resolve) => {
|
|
363
|
+
graceTimer = setTimeout(() => resolve(false), teardownGraceMs);
|
|
364
|
+
graceTimer.unref?.();
|
|
365
|
+
})
|
|
366
|
+
]);
|
|
367
|
+
clearTimeout(graceTimer);
|
|
368
|
+
if (!settled) break;
|
|
369
|
+
}
|
|
370
|
+
let turnFinished;
|
|
371
|
+
const thisTurn = new Promise((resolve) => turnFinished = resolve);
|
|
372
|
+
activeTurn = thisTurn;
|
|
350
373
|
activeSocket = ws;
|
|
351
|
-
currentUserMessages?.close(
|
|
352
|
-
new Error("A new bridge turn replaced the active turn.")
|
|
353
|
-
);
|
|
354
374
|
const firstTurn = isFirstTurn;
|
|
355
375
|
isFirstTurn = false;
|
|
356
376
|
eventLog = [];
|
|
@@ -407,8 +427,12 @@ async function runBridge(options) {
|
|
|
407
427
|
if (currentUserMessages === userMessages) {
|
|
408
428
|
currentUserMessages = void 0;
|
|
409
429
|
}
|
|
410
|
-
|
|
411
|
-
|
|
430
|
+
if (activeTurn === thisTurn) {
|
|
431
|
+
activeTurn = void 0;
|
|
432
|
+
currentTurnState = "waiting";
|
|
433
|
+
void writeBridgeMeta("waiting");
|
|
434
|
+
}
|
|
435
|
+
turnFinished();
|
|
412
436
|
}
|
|
413
437
|
return;
|
|
414
438
|
}
|
|
@@ -1185,12 +1209,19 @@ function nativeToolRequiresApproval(input) {
|
|
|
1185
1209
|
async function runTurn(start, turn) {
|
|
1186
1210
|
const emit = (msg) => turn.emit(msg);
|
|
1187
1211
|
const abortCtl = new AbortController();
|
|
1212
|
+
let gracefulAbort;
|
|
1213
|
+
let hardAbortTimer;
|
|
1214
|
+
const onHostAbort = () => {
|
|
1215
|
+
if (gracefulAbort) {
|
|
1216
|
+
gracefulAbort();
|
|
1217
|
+
} else {
|
|
1218
|
+
abortCtl.abort();
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1188
1221
|
if (turn.abortSignal.aborted) {
|
|
1189
1222
|
abortCtl.abort();
|
|
1190
1223
|
} else {
|
|
1191
|
-
turn.abortSignal.addEventListener("abort",
|
|
1192
|
-
once: true
|
|
1193
|
-
});
|
|
1224
|
+
turn.abortSignal.addEventListener("abort", onHostAbort, { once: true });
|
|
1194
1225
|
}
|
|
1195
1226
|
const streamEventState = createClaudeStreamEventState();
|
|
1196
1227
|
const mcpServers = { ...start.mcpServers ?? {} };
|
|
@@ -1304,6 +1335,11 @@ async function runTurn(start, turn) {
|
|
|
1304
1335
|
abortSignal: abortCtl.signal
|
|
1305
1336
|
}
|
|
1306
1337
|
});
|
|
1338
|
+
gracefulAbort = () => {
|
|
1339
|
+
hardAbortTimer = setTimeout(() => abortCtl.abort(), 5e3);
|
|
1340
|
+
hardAbortTimer.unref?.();
|
|
1341
|
+
void Promise.resolve().then(() => q.interrupt()).catch(() => abortCtl.abort());
|
|
1342
|
+
};
|
|
1307
1343
|
let turnUsage;
|
|
1308
1344
|
let totalCostUsd;
|
|
1309
1345
|
let emittedTerminalError = false;
|
|
@@ -1313,10 +1349,12 @@ async function runTurn(start, turn) {
|
|
|
1313
1349
|
if (!normalized || emittedTerminalError || emittedTerminalFinish) return;
|
|
1314
1350
|
streamEventState.observedTerminalError = normalized;
|
|
1315
1351
|
emittedTerminalError = true;
|
|
1316
|
-
turn.
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1352
|
+
if (!turn.abortSignal.aborted) {
|
|
1353
|
+
turn.emitError({
|
|
1354
|
+
error: normalized,
|
|
1355
|
+
message: "claude-code terminal error"
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1320
1358
|
queryInput.close();
|
|
1321
1359
|
abortCtl.abort();
|
|
1322
1360
|
};
|
|
@@ -1385,12 +1423,21 @@ async function runTurn(start, turn) {
|
|
|
1385
1423
|
}
|
|
1386
1424
|
}
|
|
1387
1425
|
} catch (err) {
|
|
1388
|
-
if (!(abortCtl.signal.aborted && emittedTerminalError)) {
|
|
1426
|
+
if (!turn.abortSignal.aborted && !(abortCtl.signal.aborted && emittedTerminalError)) {
|
|
1389
1427
|
turn.emitError({ error: err, message: "claude-code turn failed" });
|
|
1390
1428
|
}
|
|
1391
1429
|
return;
|
|
1392
1430
|
} finally {
|
|
1431
|
+
gracefulAbort = void 0;
|
|
1432
|
+
if (hardAbortTimer != null) clearTimeout(hardAbortTimer);
|
|
1433
|
+
turn.abortSignal.removeEventListener("abort", onHostAbort);
|
|
1393
1434
|
queryInput.close();
|
|
1435
|
+
try {
|
|
1436
|
+
await q.return?.(
|
|
1437
|
+
void 0
|
|
1438
|
+
);
|
|
1439
|
+
} catch {
|
|
1440
|
+
}
|
|
1394
1441
|
}
|
|
1395
1442
|
if (emittedTerminalError) return;
|
|
1396
1443
|
emittedTerminalFinish = true;
|