@ai-sdk/harness 1.0.38 → 1.0.40
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 +17 -0
- package/dist/agent/index.d.ts +19 -4
- package/dist/agent/index.js +189 -57
- package/dist/agent/index.js.map +1 -1
- package/dist/bridge/index.js +8 -1
- package/dist/bridge/index.js.map +1 -1
- package/dist/utils/index.d.ts +5 -1
- package/dist/utils/index.js +37 -5
- package/dist/utils/index.js.map +1 -1
- package/package.json +2 -2
- package/src/agent/harness-agent-session.ts +38 -8
- package/src/agent/harness-agent-settings.ts +25 -1
- package/src/agent/harness-agent.ts +17 -2
- package/src/agent/internal/harness-stream-text-result.ts +27 -0
- package/src/agent/internal/run-prompt.ts +144 -42
- package/src/agent/internal/turn-telemetry.ts +18 -4
- package/src/bridge/index.ts +11 -1
- package/src/utils/sandbox-channel.ts +61 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @ai-sdk/harness
|
|
2
2
|
|
|
3
|
+
## 1.0.40
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 59a2306: fix(harness): execute host tools through telemetry context wrappers
|
|
8
|
+
- 5f65e61: feat(harness): add support for `stopWhen` control to `HarnessAgent` (e.g. `isStepCount(1)`)
|
|
9
|
+
- Updated dependencies [7f6650b]
|
|
10
|
+
- Updated dependencies [106ea59]
|
|
11
|
+
- ai@7.0.35
|
|
12
|
+
|
|
13
|
+
## 1.0.39
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 86a84c9: fix(harness): settle a turn aborted by the caller's abortSignal with an `abort` stream part instead of an AbortError `error` part, matching `streamText`'s abort contract
|
|
18
|
+
- ai@7.0.34
|
|
19
|
+
|
|
3
20
|
## 1.0.38
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as _ai_sdk_provider_utils from '@ai-sdk/provider-utils';
|
|
2
|
-
import { Experimental_SandboxSession, UserModelMessage, ToolSet, FlexibleSchema, Tool, ToolApprovalResponse, ModelMessage
|
|
3
|
-
import { ToolApprovalStatus, TelemetryOptions, ActiveTools, StreamTextResult, Agent, AgentCallParameters, GenerateTextResult, AgentStreamParameters, Telemetry } from 'ai';
|
|
2
|
+
import { Experimental_SandboxSession, UserModelMessage, ToolSet, FlexibleSchema, Tool, Context, Arrayable, ToolApprovalResponse, ModelMessage } from '@ai-sdk/provider-utils';
|
|
3
|
+
import { StopCondition, ToolApprovalStatus, TelemetryOptions, ActiveTools, StreamTextResult, Agent, AgentCallParameters, GenerateTextResult, AgentStreamParameters, Telemetry } from 'ai';
|
|
4
4
|
import { z } from 'zod/v4';
|
|
5
5
|
import { JSONValue, LanguageModelV4ToolCall, LanguageModelV4ToolApprovalRequest, LanguageModelV4ToolResult, LanguageModelV4FinishReason, LanguageModelV4Usage, JSONSchema7, AISDKError } from '@ai-sdk/provider';
|
|
6
6
|
|
|
@@ -1143,7 +1143,7 @@ type HarnessAgentToolFilteringSettings<TOOLS extends ToolSet> = {
|
|
|
1143
1143
|
*/
|
|
1144
1144
|
readonly inactiveTools?: HarnessTools<TOOLS>;
|
|
1145
1145
|
};
|
|
1146
|
-
type HarnessAgentSettings<THarness extends HarnessAgentAdapter<any> = HarnessAgentAdapter, TUserTools extends ToolSet = {}> = {
|
|
1146
|
+
type HarnessAgentSettings<THarness extends HarnessAgentAdapter<any> = HarnessAgentAdapter, TUserTools extends ToolSet = {}, RUNTIME_CONTEXT extends Context = Context> = {
|
|
1147
1147
|
/**
|
|
1148
1148
|
* The harness adapter driving the underlying agent runtime. Its
|
|
1149
1149
|
* `builtinTools` are merged with the user-defined `tools` and exposed to
|
|
@@ -1177,6 +1177,16 @@ type HarnessAgentSettings<THarness extends HarnessAgentAdapter<any> = HarnessAge
|
|
|
1177
1177
|
* later turns or when resuming a previously ended session.
|
|
1178
1178
|
*/
|
|
1179
1179
|
readonly instructions?: string;
|
|
1180
|
+
/**
|
|
1181
|
+
* Conditions that stop the current result after a completed harness tool
|
|
1182
|
+
* step that can continue into another model step. The underlying turn remains
|
|
1183
|
+
* unfinished and can be suspended and continued.
|
|
1184
|
+
*
|
|
1185
|
+
* A terminal text-only step finishes naturally and is not stopped early.
|
|
1186
|
+
*
|
|
1187
|
+
* When omitted, the harness runs until the turn naturally finishes or pauses.
|
|
1188
|
+
*/
|
|
1189
|
+
readonly stopWhen?: Arrayable<StopCondition<NoInfer<HarnessAllTools<THarness, TUserTools>>, RUNTIME_CONTEXT>>;
|
|
1180
1190
|
/**
|
|
1181
1191
|
* Built-in tool permission mode. Defaults to `'allow-all'`, preserving the
|
|
1182
1192
|
* existing bypass-permissions behavior unless users opt in.
|
|
@@ -1303,6 +1313,7 @@ declare class HarnessAgentSession {
|
|
|
1303
1313
|
private turnState;
|
|
1304
1314
|
private turnSequence;
|
|
1305
1315
|
private activeTurnSequence;
|
|
1316
|
+
private suspendedTurnState;
|
|
1306
1317
|
/**
|
|
1307
1318
|
* Whether this session was created from `resumeFrom` or `continueFrom`.
|
|
1308
1319
|
* Captured at construction so it survives lifecycle cleanup.
|
|
@@ -1332,6 +1343,7 @@ declare class HarnessAgentSession {
|
|
|
1332
1343
|
runtimeContext: RUNTIME_CONTEXT;
|
|
1333
1344
|
abortSignal: AbortSignal | undefined;
|
|
1334
1345
|
telemetry: TelemetryOptions | undefined;
|
|
1346
|
+
stopConditions: ReadonlyArray<StopCondition<TOOLS, RUNTIME_CONTEXT>>;
|
|
1335
1347
|
}): HarnessAgentTurnResult<TOOLS, RUNTIME_CONTEXT>;
|
|
1336
1348
|
continueTurn<TOOLS extends ToolSet, RUNTIME_CONTEXT extends Context>(options: {
|
|
1337
1349
|
instructions: string | undefined;
|
|
@@ -1342,6 +1354,7 @@ declare class HarnessAgentSession {
|
|
|
1342
1354
|
runtimeContext: RUNTIME_CONTEXT;
|
|
1343
1355
|
abortSignal: AbortSignal | undefined;
|
|
1344
1356
|
telemetry: TelemetryOptions | undefined;
|
|
1357
|
+
stopConditions: ReadonlyArray<StopCondition<TOOLS, RUNTIME_CONTEXT>>;
|
|
1345
1358
|
toolApprovalContinuations?: readonly HarnessAgentToolApprovalContinuation[] | undefined;
|
|
1346
1359
|
toolResultContinuations?: readonly HarnessAgentToolResultContinuation[] | undefined;
|
|
1347
1360
|
}): HarnessAgentTurnResult<TOOLS, RUNTIME_CONTEXT>;
|
|
@@ -1392,6 +1405,7 @@ declare class HarnessAgentSession {
|
|
|
1392
1405
|
private getPendingToolResults;
|
|
1393
1406
|
private addPendingToolState;
|
|
1394
1407
|
private suspendCurrentTurn;
|
|
1408
|
+
private captureStopConditionBoundary;
|
|
1395
1409
|
private toResumeStateWithContinuation;
|
|
1396
1410
|
private requirePromptableTurn;
|
|
1397
1411
|
private requireContinuableTurn;
|
|
@@ -1461,11 +1475,12 @@ declare class HarnessAgent<THarness extends HarnessAgentAdapter<any> = HarnessAg
|
|
|
1461
1475
|
*/
|
|
1462
1476
|
readonly tools: HarnessAllTools<THarness, TUserTools>;
|
|
1463
1477
|
private readonly settings;
|
|
1478
|
+
private readonly stopConditions;
|
|
1464
1479
|
private readonly sandboxConfig;
|
|
1465
1480
|
private readonly activeUserTools;
|
|
1466
1481
|
private readonly builtinToolFiltering;
|
|
1467
1482
|
private readonly permissionMode;
|
|
1468
|
-
constructor(settings: HarnessAgentSettings<THarness, TUserTools>);
|
|
1483
|
+
constructor(settings: HarnessAgentSettings<THarness, TUserTools, RUNTIME_CONTEXT>);
|
|
1469
1484
|
/** Identifier of the harness backing this agent. */
|
|
1470
1485
|
get harnessId(): string;
|
|
1471
1486
|
/**
|
package/dist/agent/index.js
CHANGED
|
@@ -40,6 +40,7 @@ var HarnessCapabilityUnsupportedError = class extends (_b2 = HarnessError, _a2 =
|
|
|
40
40
|
|
|
41
41
|
// src/agent/harness-agent.ts
|
|
42
42
|
import {
|
|
43
|
+
asArray as asArray2,
|
|
43
44
|
asSchema,
|
|
44
45
|
generateId as generateId5
|
|
45
46
|
} from "@ai-sdk/provider-utils";
|
|
@@ -181,8 +182,11 @@ import {
|
|
|
181
182
|
executeTool,
|
|
182
183
|
generateId as generateId4,
|
|
183
184
|
isExecutableTool,
|
|
184
|
-
safeParseJSON
|
|
185
|
+
safeParseJSON as safeParseJSON2
|
|
185
186
|
} from "@ai-sdk/provider-utils";
|
|
187
|
+
import {
|
|
188
|
+
getErrorMessage
|
|
189
|
+
} from "@ai-sdk/provider";
|
|
186
190
|
import { parseToolCall } from "ai/internal";
|
|
187
191
|
|
|
188
192
|
// src/agent/internal/harness-stream-text-result.ts
|
|
@@ -457,6 +461,24 @@ var HarnessStreamTextResult = class {
|
|
|
457
461
|
});
|
|
458
462
|
this.fullStreamController.close();
|
|
459
463
|
}
|
|
464
|
+
/**
|
|
465
|
+
* Settle the turn as user-aborted: emit a final `abort` part — matching
|
|
466
|
+
* `streamText`'s abort contract — and close the stream, instead of
|
|
467
|
+
* surfacing an `error` part. `toUIMessageStream` consumers then observe
|
|
468
|
+
* an `abort` chunk (and `isAborted: true`) rather than a spurious
|
|
469
|
+
* `onError`. The delayed promise accessors still reject with the
|
|
470
|
+
* underlying abort error so awaiting consumers do not hang. Idempotent.
|
|
471
|
+
*/
|
|
472
|
+
abort(input) {
|
|
473
|
+
if (this.settled) return;
|
|
474
|
+
this.settled = true;
|
|
475
|
+
this.fullStreamController.enqueue({
|
|
476
|
+
type: "abort",
|
|
477
|
+
...input.reason !== void 0 ? { reason: input.reason } : {}
|
|
478
|
+
});
|
|
479
|
+
this.fullStreamController.close();
|
|
480
|
+
this.rejectDelayedPromises(input.error);
|
|
481
|
+
}
|
|
460
482
|
/**
|
|
461
483
|
* Surface a fatal error as a stream `error` part + reject every delayed
|
|
462
484
|
* promise so awaiting consumers stop hanging. Idempotent.
|
|
@@ -469,6 +491,9 @@ var HarnessStreamTextResult = class {
|
|
|
469
491
|
error
|
|
470
492
|
});
|
|
471
493
|
this.fullStreamController.close();
|
|
494
|
+
this.rejectDelayedPromises(error);
|
|
495
|
+
}
|
|
496
|
+
rejectDelayedPromises(error) {
|
|
472
497
|
for (const dp of [
|
|
473
498
|
this._content,
|
|
474
499
|
this._text,
|
|
@@ -596,6 +621,7 @@ var HarnessStreamTextResult = class {
|
|
|
596
621
|
toUIMessageStream({
|
|
597
622
|
originalMessages,
|
|
598
623
|
generateMessageId,
|
|
624
|
+
onEnd,
|
|
599
625
|
onFinish,
|
|
600
626
|
messageMetadata,
|
|
601
627
|
sendReasoning,
|
|
@@ -610,6 +636,7 @@ var HarnessStreamTextResult = class {
|
|
|
610
636
|
tools: this.tools,
|
|
611
637
|
originalMessages,
|
|
612
638
|
generateMessageId,
|
|
639
|
+
onEnd,
|
|
613
640
|
onFinish,
|
|
614
641
|
messageMetadata,
|
|
615
642
|
sendReasoning,
|
|
@@ -629,6 +656,7 @@ var HarnessStreamTextResult = class {
|
|
|
629
656
|
toUIMessageStreamResponse({
|
|
630
657
|
originalMessages,
|
|
631
658
|
generateMessageId,
|
|
659
|
+
onEnd,
|
|
632
660
|
onFinish,
|
|
633
661
|
messageMetadata,
|
|
634
662
|
sendReasoning,
|
|
@@ -642,6 +670,7 @@ var HarnessStreamTextResult = class {
|
|
|
642
670
|
stream: this.toUIMessageStream({
|
|
643
671
|
originalMessages,
|
|
644
672
|
generateMessageId,
|
|
673
|
+
onEnd,
|
|
645
674
|
onFinish,
|
|
646
675
|
messageMetadata,
|
|
647
676
|
sendReasoning,
|
|
@@ -896,7 +925,10 @@ var NOOP = {
|
|
|
896
925
|
},
|
|
897
926
|
stepFinish() {
|
|
898
927
|
},
|
|
899
|
-
toolStart() {
|
|
928
|
+
async toolStart() {
|
|
929
|
+
},
|
|
930
|
+
async executeTool({ execute }) {
|
|
931
|
+
return await execute();
|
|
900
932
|
},
|
|
901
933
|
toolEnd() {
|
|
902
934
|
},
|
|
@@ -1055,11 +1087,12 @@ function createTurnTelemetry(opts) {
|
|
|
1055
1087
|
stepOpen = false;
|
|
1056
1088
|
stepNumber += 1;
|
|
1057
1089
|
},
|
|
1058
|
-
toolStart(call) {
|
|
1090
|
+
async toolStart(call) {
|
|
1059
1091
|
var _a4;
|
|
1060
1092
|
ensureStepOpen();
|
|
1093
|
+
if (openTools.has(call.toolCallId)) return;
|
|
1061
1094
|
openTools.set(call.toolCallId, call);
|
|
1062
|
-
(_a4 = dispatcher.onToolExecutionStart) == null ? void 0 : _a4.call(
|
|
1095
|
+
await ((_a4 = dispatcher.onToolExecutionStart) == null ? void 0 : _a4.call(
|
|
1063
1096
|
dispatcher,
|
|
1064
1097
|
cast({
|
|
1065
1098
|
callId,
|
|
@@ -1073,7 +1106,11 @@ function createTurnTelemetry(opts) {
|
|
|
1073
1106
|
},
|
|
1074
1107
|
toolContext: void 0
|
|
1075
1108
|
})
|
|
1076
|
-
);
|
|
1109
|
+
));
|
|
1110
|
+
},
|
|
1111
|
+
async executeTool({ toolCallId, execute }) {
|
|
1112
|
+
if (dispatcher.executeTool == null) return await execute();
|
|
1113
|
+
return await dispatcher.executeTool({ callId, toolCallId, execute });
|
|
1077
1114
|
},
|
|
1078
1115
|
toolEnd(toolCallId, output) {
|
|
1079
1116
|
var _a4;
|
|
@@ -1235,6 +1272,20 @@ function logBridgeError({
|
|
|
1235
1272
|
}
|
|
1236
1273
|
}
|
|
1237
1274
|
|
|
1275
|
+
// src/utils/sandbox-channel.ts
|
|
1276
|
+
import {
|
|
1277
|
+
safeParseJSON,
|
|
1278
|
+
safeValidateTypes as safeValidateTypes2
|
|
1279
|
+
} from "@ai-sdk/provider-utils";
|
|
1280
|
+
var sandboxChannelEventCheckpointSymbol = /* @__PURE__ */ Symbol.for(
|
|
1281
|
+
"vercel.ai.harness.sandboxChannelEventCheckpoint"
|
|
1282
|
+
);
|
|
1283
|
+
function pinSandboxChannelEventCheckpoint(event) {
|
|
1284
|
+
var _a3;
|
|
1285
|
+
if (event == null || typeof event !== "object") return void 0;
|
|
1286
|
+
return (_a3 = event[sandboxChannelEventCheckpointSymbol]) == null ? void 0 : _a3.pin();
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1238
1289
|
// src/agent/internal/run-prompt.ts
|
|
1239
1290
|
function runPrompt(input) {
|
|
1240
1291
|
var _a3, _b3, _c, _d, _e, _f, _g;
|
|
@@ -1265,8 +1316,20 @@ function runPrompt(input) {
|
|
|
1265
1316
|
promptText: input.prompt != null ? promptToText(input.prompt) : "",
|
|
1266
1317
|
runtimeContext: input.runtimeContext
|
|
1267
1318
|
});
|
|
1319
|
+
const settleFailure = (err) => {
|
|
1320
|
+
var _a4, _b4;
|
|
1321
|
+
(_a4 = input.onTurnFailed) == null ? void 0 : _a4.call(input);
|
|
1322
|
+
if ((_b4 = input.abortSignal) == null ? void 0 : _b4.aborted) {
|
|
1323
|
+
result.abort({
|
|
1324
|
+
error: err,
|
|
1325
|
+
...input.abortSignal.reason !== void 0 ? { reason: getErrorMessage(input.abortSignal.reason) } : {}
|
|
1326
|
+
});
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
result.fail(err);
|
|
1330
|
+
};
|
|
1268
1331
|
const done = (async () => {
|
|
1269
|
-
var _a4, _b4, _c2, _d2, _e2, _f2, _g2, _h, _i, _j, _k
|
|
1332
|
+
var _a4, _b4, _c2, _d2, _e2, _f2, _g2, _h, _i, _j, _k;
|
|
1270
1333
|
let bridge;
|
|
1271
1334
|
try {
|
|
1272
1335
|
bridge = await toHarnessStream({
|
|
@@ -1297,8 +1360,7 @@ function runPrompt(input) {
|
|
|
1297
1360
|
context: "failed to start harness turn",
|
|
1298
1361
|
error: err
|
|
1299
1362
|
});
|
|
1300
|
-
(
|
|
1301
|
-
result.fail(err);
|
|
1363
|
+
settleFailure(err);
|
|
1302
1364
|
return;
|
|
1303
1365
|
}
|
|
1304
1366
|
const { stream, control } = bridge;
|
|
@@ -1312,7 +1374,7 @@ function runPrompt(input) {
|
|
|
1312
1374
|
pendingToolApprovals.map((approval) => [approval.toolCallId, approval])
|
|
1313
1375
|
);
|
|
1314
1376
|
const continuationsByApprovalId = new Map(
|
|
1315
|
-
((
|
|
1377
|
+
((_a4 = input.toolApprovalContinuations) != null ? _a4 : []).map((continuation) => [
|
|
1316
1378
|
continuation.approvalResponse.approvalId,
|
|
1317
1379
|
continuation
|
|
1318
1380
|
])
|
|
@@ -1324,14 +1386,21 @@ function runPrompt(input) {
|
|
|
1324
1386
|
])
|
|
1325
1387
|
);
|
|
1326
1388
|
const continuationsByToolCallId = new Map(
|
|
1327
|
-
((
|
|
1389
|
+
((_b4 = input.toolResultContinuations) != null ? _b4 : []).map((continuation) => [
|
|
1328
1390
|
continuation.toolCallId,
|
|
1329
1391
|
continuation
|
|
1330
1392
|
])
|
|
1331
1393
|
);
|
|
1332
1394
|
const settledHostToolCallIds = /* @__PURE__ */ new Set();
|
|
1333
1395
|
let closingResumedStep = false;
|
|
1396
|
+
let pendingStopBoundary;
|
|
1334
1397
|
let finalFinish;
|
|
1398
|
+
const completedSteps = [];
|
|
1399
|
+
const releasePendingStopBoundary = () => {
|
|
1400
|
+
var _a5;
|
|
1401
|
+
(_a5 = pendingStopBoundary == null ? void 0 : pendingStopBoundary.releaseCheckpoint) == null ? void 0 : _a5.call(pendingStopBoundary);
|
|
1402
|
+
pendingStopBoundary = void 0;
|
|
1403
|
+
};
|
|
1335
1404
|
let stepText = "";
|
|
1336
1405
|
let stepReasoning = "";
|
|
1337
1406
|
let stepToolCalls = [];
|
|
@@ -1372,12 +1441,14 @@ function runPrompt(input) {
|
|
|
1372
1441
|
content: buildStepContent()
|
|
1373
1442
|
});
|
|
1374
1443
|
resetStepContent();
|
|
1375
|
-
|
|
1444
|
+
const step = result.finishStep({
|
|
1376
1445
|
finishReason: input2.finishReason,
|
|
1377
1446
|
usage: input2.usage,
|
|
1378
1447
|
providerMetadata: input2.providerMetadata,
|
|
1379
1448
|
warnings: []
|
|
1380
1449
|
});
|
|
1450
|
+
completedSteps.push(step);
|
|
1451
|
+
return step;
|
|
1381
1452
|
};
|
|
1382
1453
|
const finishForHostInputPause = async (options) => {
|
|
1383
1454
|
if (options.completeCurrentStep) {
|
|
@@ -1478,9 +1549,16 @@ function runPrompt(input) {
|
|
|
1478
1549
|
toolName: approval.toolName,
|
|
1479
1550
|
input: approval.input
|
|
1480
1551
|
};
|
|
1552
|
+
telemetry.start(input.session.modelId);
|
|
1553
|
+
await telemetry.toolStart({
|
|
1554
|
+
toolCallId: rawToolCall.toolCallId,
|
|
1555
|
+
toolName: rawToolCall.toolName,
|
|
1556
|
+
input: rawToolCall.input
|
|
1557
|
+
});
|
|
1481
1558
|
const execution = await maybeExecuteHostTool({
|
|
1482
1559
|
event: rawToolCall,
|
|
1483
1560
|
tools: activeTools,
|
|
1561
|
+
wrappedExecuteTool: telemetry.executeTool,
|
|
1484
1562
|
sandboxSession: input.sandboxSession,
|
|
1485
1563
|
abortSignal: input.abortSignal,
|
|
1486
1564
|
control,
|
|
@@ -1538,8 +1616,29 @@ function runPrompt(input) {
|
|
|
1538
1616
|
}
|
|
1539
1617
|
while (true) {
|
|
1540
1618
|
const { value, done: done2 } = await reader.read();
|
|
1541
|
-
if (done2)
|
|
1619
|
+
if (done2) {
|
|
1620
|
+
releasePendingStopBoundary();
|
|
1621
|
+
break;
|
|
1622
|
+
}
|
|
1542
1623
|
if (value == null) continue;
|
|
1624
|
+
if (pendingStopBoundary != null) {
|
|
1625
|
+
if (value.type === "finish") {
|
|
1626
|
+
releasePendingStopBoundary();
|
|
1627
|
+
} else if ((await Promise.all(
|
|
1628
|
+
input.stopConditions.map(
|
|
1629
|
+
(condition) => condition({ steps: completedSteps })
|
|
1630
|
+
)
|
|
1631
|
+
)).some(Boolean)) {
|
|
1632
|
+
await ((_c2 = input.onStopConditionMet) == null ? void 0 : _c2.call(input));
|
|
1633
|
+
const { finishReason, usage } = pendingStopBoundary;
|
|
1634
|
+
releasePendingStopBoundary();
|
|
1635
|
+
telemetry.end({ finishReason, usage });
|
|
1636
|
+
await result.finish();
|
|
1637
|
+
return;
|
|
1638
|
+
} else {
|
|
1639
|
+
releasePendingStopBoundary();
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1543
1642
|
if (value.type === "stream-start") {
|
|
1544
1643
|
telemetry.start((_d2 = value.modelId) != null ? _d2 : input.session.modelId);
|
|
1545
1644
|
}
|
|
@@ -1587,6 +1686,17 @@ function runPrompt(input) {
|
|
|
1587
1686
|
continue;
|
|
1588
1687
|
}
|
|
1589
1688
|
}
|
|
1689
|
+
if (value.type === "error" && displayValue.type === "error") {
|
|
1690
|
+
telemetry.error(value.error);
|
|
1691
|
+
logBridgeError({
|
|
1692
|
+
harnessId: input.harness.harnessId,
|
|
1693
|
+
sessionId: input.session.sessionId,
|
|
1694
|
+
context: "harness stream error",
|
|
1695
|
+
error: value.error
|
|
1696
|
+
});
|
|
1697
|
+
settleFailure(displayValue.error);
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1590
1700
|
for (const part of translateStreamPart(displayValue)) {
|
|
1591
1701
|
result.enqueue(part);
|
|
1592
1702
|
}
|
|
@@ -1612,7 +1722,7 @@ function runPrompt(input) {
|
|
|
1612
1722
|
toolName: value.toolName,
|
|
1613
1723
|
input: value.input
|
|
1614
1724
|
});
|
|
1615
|
-
telemetry.toolStart({
|
|
1725
|
+
await telemetry.toolStart({
|
|
1616
1726
|
toolCallId: value.toolCallId,
|
|
1617
1727
|
toolName: value.toolName,
|
|
1618
1728
|
input: value.input
|
|
@@ -1675,6 +1785,13 @@ function runPrompt(input) {
|
|
|
1675
1785
|
usage: value.usage,
|
|
1676
1786
|
providerMetadata: value.harnessMetadata
|
|
1677
1787
|
});
|
|
1788
|
+
if (input.stopConditions != null && input.stopConditions.length > 0) {
|
|
1789
|
+
pendingStopBoundary = {
|
|
1790
|
+
finishReason: value.finishReason,
|
|
1791
|
+
usage: value.usage,
|
|
1792
|
+
releaseCheckpoint: pinSandboxChannelEventCheckpoint(value)
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1678
1795
|
}
|
|
1679
1796
|
if (value.type === "finish") {
|
|
1680
1797
|
finalFinish = value;
|
|
@@ -1783,6 +1900,7 @@ function runPrompt(input) {
|
|
|
1783
1900
|
const execution = await maybeExecuteHostTool({
|
|
1784
1901
|
event: toolCall,
|
|
1785
1902
|
tools: activeTools,
|
|
1903
|
+
wrappedExecuteTool: telemetry.executeTool,
|
|
1786
1904
|
sandboxSession: input.sandboxSession,
|
|
1787
1905
|
abortSignal: input.abortSignal,
|
|
1788
1906
|
control,
|
|
@@ -1813,23 +1931,11 @@ function runPrompt(input) {
|
|
|
1813
1931
|
}
|
|
1814
1932
|
telemetry.toolEnd(toolCall.toolCallId, execution.outcome);
|
|
1815
1933
|
}
|
|
1816
|
-
if (value.type === "error") {
|
|
1817
|
-
telemetry.error(value.error);
|
|
1818
|
-
logBridgeError({
|
|
1819
|
-
harnessId: input.harness.harnessId,
|
|
1820
|
-
sessionId: input.session.sessionId,
|
|
1821
|
-
context: "harness stream error",
|
|
1822
|
-
error: value.error
|
|
1823
|
-
});
|
|
1824
|
-
(_j = input.onTurnFailed) == null ? void 0 : _j.call(input);
|
|
1825
|
-
result.fail(value.error);
|
|
1826
|
-
return;
|
|
1827
|
-
}
|
|
1828
1934
|
}
|
|
1829
1935
|
if (finalFinish != null) {
|
|
1830
|
-
(
|
|
1936
|
+
(_j = input.onTurnFinished) == null ? void 0 : _j.call(input);
|
|
1831
1937
|
} else {
|
|
1832
|
-
(
|
|
1938
|
+
(_k = input.onTurnFailed) == null ? void 0 : _k.call(input);
|
|
1833
1939
|
}
|
|
1834
1940
|
await result.finish(
|
|
1835
1941
|
finalFinish ? {
|
|
@@ -1846,9 +1952,9 @@ function runPrompt(input) {
|
|
|
1846
1952
|
context: "harness turn failed",
|
|
1847
1953
|
error: err
|
|
1848
1954
|
});
|
|
1849
|
-
(
|
|
1850
|
-
result.fail(err);
|
|
1955
|
+
settleFailure(err);
|
|
1851
1956
|
} finally {
|
|
1957
|
+
releasePendingStopBoundary();
|
|
1852
1958
|
reader.releaseLock();
|
|
1853
1959
|
}
|
|
1854
1960
|
})();
|
|
@@ -1870,28 +1976,34 @@ function hasTool(input) {
|
|
|
1870
1976
|
async function maybeExecuteHostTool(input) {
|
|
1871
1977
|
const tool = input.tools[input.event.toolName];
|
|
1872
1978
|
if (!isExecutableTool(tool)) return { executed: false };
|
|
1873
|
-
const parsed = await
|
|
1979
|
+
const parsed = await safeParseJSON2({ text: input.event.input });
|
|
1874
1980
|
const args = parsed.success ? parsed.value : input.event.input;
|
|
1875
1981
|
try {
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1982
|
+
const output = await input.wrappedExecuteTool({
|
|
1983
|
+
toolCallId: input.event.toolCallId,
|
|
1984
|
+
execute: async () => {
|
|
1985
|
+
let output2;
|
|
1986
|
+
const stream = executeTool({
|
|
1987
|
+
tool,
|
|
1988
|
+
input: args,
|
|
1989
|
+
options: {
|
|
1990
|
+
toolCallId: input.event.toolCallId,
|
|
1991
|
+
messages: [],
|
|
1992
|
+
abortSignal: input.abortSignal,
|
|
1993
|
+
context: void 0,
|
|
1994
|
+
experimental_sandbox: input.sandboxSession
|
|
1995
|
+
}
|
|
1996
|
+
});
|
|
1997
|
+
for await (const part of stream) {
|
|
1998
|
+
if (part.type === "preliminary") {
|
|
1999
|
+
input.onPreliminaryResult(part.output);
|
|
2000
|
+
} else {
|
|
2001
|
+
output2 = part.output;
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
return output2;
|
|
1886
2005
|
}
|
|
1887
2006
|
});
|
|
1888
|
-
for await (const part of stream) {
|
|
1889
|
-
if (part.type === "preliminary") {
|
|
1890
|
-
input.onPreliminaryResult(part.output);
|
|
1891
|
-
} else {
|
|
1892
|
-
output = part.output;
|
|
1893
|
-
}
|
|
1894
|
-
}
|
|
1895
2007
|
await input.control.submitToolResult({
|
|
1896
2008
|
toolCallId: input.event.toolCallId,
|
|
1897
2009
|
output
|
|
@@ -2009,6 +2121,7 @@ var HarnessAgentSession = class {
|
|
|
2009
2121
|
runtimeContext: options.runtimeContext,
|
|
2010
2122
|
abortSignal: options.abortSignal,
|
|
2011
2123
|
telemetry: options.telemetry,
|
|
2124
|
+
stopConditions: options.stopConditions,
|
|
2012
2125
|
toolApproval: this.toolApproval,
|
|
2013
2126
|
pendingToolApprovals: this.getPendingToolApprovals(),
|
|
2014
2127
|
pendingToolResults: this.getPendingToolResults(),
|
|
@@ -2031,7 +2144,8 @@ var HarnessAgentSession = class {
|
|
|
2031
2144
|
},
|
|
2032
2145
|
onTurnFailed: () => {
|
|
2033
2146
|
this.finishTrackedTurn({ turnId });
|
|
2034
|
-
}
|
|
2147
|
+
},
|
|
2148
|
+
onStopConditionMet: () => this.captureStopConditionBoundary({ session, turnId })
|
|
2035
2149
|
});
|
|
2036
2150
|
return turn;
|
|
2037
2151
|
} catch (error) {
|
|
@@ -2059,6 +2173,7 @@ var HarnessAgentSession = class {
|
|
|
2059
2173
|
runtimeContext: options.runtimeContext,
|
|
2060
2174
|
abortSignal: options.abortSignal,
|
|
2061
2175
|
telemetry: options.telemetry,
|
|
2176
|
+
stopConditions: options.stopConditions,
|
|
2062
2177
|
toolApproval: this.toolApproval,
|
|
2063
2178
|
pendingToolApprovals: this.getPendingToolApprovals(),
|
|
2064
2179
|
pendingToolResults: this.getPendingToolResults(),
|
|
@@ -2083,7 +2198,8 @@ var HarnessAgentSession = class {
|
|
|
2083
2198
|
},
|
|
2084
2199
|
onTurnFailed: () => {
|
|
2085
2200
|
this.finishTrackedTurn({ turnId });
|
|
2086
|
-
}
|
|
2201
|
+
},
|
|
2202
|
+
onStopConditionMet: () => this.captureStopConditionBoundary({ session, turnId })
|
|
2087
2203
|
});
|
|
2088
2204
|
return turn;
|
|
2089
2205
|
} catch (error) {
|
|
@@ -2249,14 +2365,25 @@ var HarnessAgentSession = class {
|
|
|
2249
2365
|
};
|
|
2250
2366
|
}
|
|
2251
2367
|
async suspendCurrentTurn(options) {
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2368
|
+
var _a3;
|
|
2369
|
+
(_a3 = this.suspendedTurnState) != null ? _a3 : this.suspendedTurnState = (async () => {
|
|
2370
|
+
const raw = await options.session.doSuspendTurn();
|
|
2371
|
+
const validated = await validateLifecycleStateData({
|
|
2372
|
+
harness: this.harness,
|
|
2373
|
+
state: raw,
|
|
2374
|
+
expectedType: "continue-turn"
|
|
2375
|
+
});
|
|
2376
|
+
return this.addPendingToolState(validated);
|
|
2377
|
+
})();
|
|
2378
|
+
const state = await this.suspendedTurnState;
|
|
2258
2379
|
this.turnState = "suspended";
|
|
2259
|
-
return
|
|
2380
|
+
return state;
|
|
2381
|
+
}
|
|
2382
|
+
async captureStopConditionBoundary(options) {
|
|
2383
|
+
if (this.sessionState !== "active" || this.activeTurnSequence !== options.turnId) {
|
|
2384
|
+
return;
|
|
2385
|
+
}
|
|
2386
|
+
await this.suspendCurrentTurn({ session: options.session });
|
|
2260
2387
|
}
|
|
2261
2388
|
toResumeStateWithContinuation(options) {
|
|
2262
2389
|
const { continueFrom } = options;
|
|
@@ -2305,6 +2432,7 @@ var HarnessAgentSession = class {
|
|
|
2305
2432
|
startTrackedTurn() {
|
|
2306
2433
|
const turnId = ++this.turnSequence;
|
|
2307
2434
|
this.activeTurnSequence = turnId;
|
|
2435
|
+
this.suspendedTurnState = void 0;
|
|
2308
2436
|
this.turnState = "running";
|
|
2309
2437
|
return turnId;
|
|
2310
2438
|
}
|
|
@@ -2313,6 +2441,7 @@ var HarnessAgentSession = class {
|
|
|
2313
2441
|
if (this.activeTurnSequence !== options.turnId) return;
|
|
2314
2442
|
this.pendingToolApprovals.clear();
|
|
2315
2443
|
this.pendingToolResults.clear();
|
|
2444
|
+
this.suspendedTurnState = void 0;
|
|
2316
2445
|
this.turnState = "idle";
|
|
2317
2446
|
}
|
|
2318
2447
|
endLocalHandle(options) {
|
|
@@ -2833,6 +2962,7 @@ var HarnessAgent = class {
|
|
|
2833
2962
|
const sandboxConfig = resolveSandboxConfig(settings);
|
|
2834
2963
|
validateSandboxBootstrapSettings(sandboxConfig);
|
|
2835
2964
|
this.settings = settings;
|
|
2965
|
+
this.stopConditions = settings.stopWhen == null ? [] : asArray2(settings.stopWhen);
|
|
2836
2966
|
this.sandboxConfig = sandboxConfig;
|
|
2837
2967
|
this.id = settings.id;
|
|
2838
2968
|
const userTools = (_a3 = settings.tools) != null ? _a3 : {};
|
|
@@ -3080,6 +3210,7 @@ var HarnessAgent = class {
|
|
|
3080
3210
|
runtimeContext: input.runtimeContext,
|
|
3081
3211
|
abortSignal: input.abortSignal,
|
|
3082
3212
|
telemetry: this.settings.telemetry,
|
|
3213
|
+
stopConditions: this.stopConditions,
|
|
3083
3214
|
toolApprovalContinuations: input.turnInput.toolApprovalContinuations,
|
|
3084
3215
|
toolResultContinuations: input.turnInput.toolResultContinuations
|
|
3085
3216
|
});
|
|
@@ -3093,7 +3224,8 @@ var HarnessAgent = class {
|
|
|
3093
3224
|
builtinToolFiltering: this.builtinToolFiltering,
|
|
3094
3225
|
runtimeContext: input.runtimeContext,
|
|
3095
3226
|
abortSignal: input.abortSignal,
|
|
3096
|
-
telemetry: this.settings.telemetry
|
|
3227
|
+
telemetry: this.settings.telemetry,
|
|
3228
|
+
stopConditions: this.stopConditions
|
|
3097
3229
|
});
|
|
3098
3230
|
}
|
|
3099
3231
|
async _acquireSandbox(input) {
|