@ai-sdk/harness 1.0.149 → 1.0.151
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/dist/agent/index.d.ts +6 -5
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +263 -70
- package/dist/agent/index.js.map +1 -1
- package/dist/bridge/index.d.ts +18 -1
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/index.js +51 -1
- package/dist/bridge/index.js.map +1 -1
- package/dist/index.d.ts +3 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +24 -3
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +164 -4
- package/dist/utils/index.js.map +1 -1
- package/package.json +3 -3
- package/src/agent/harness-agent-tool-approval-continuation.ts +7 -1
- package/src/agent/internal/harness-stream-text-result.ts +143 -27
- package/src/agent/internal/run-prompt.ts +155 -58
- package/src/agent/internal/translate-stream-part.ts +20 -3
- package/src/bridge/index.ts +4 -0
- package/src/utils/convert-harness-tool-model-output.ts +66 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/normalize-harness-tool-model-output.ts +66 -0
- package/src/v1/harness-v1-prompt-control.ts +3 -0
- package/src/v1/harness-v1-stream-part.ts +10 -11
package/dist/agent/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AISDKError, getErrorMessage } from "@ai-sdk/provider";
|
|
2
|
-
import { DelayedPromise, asArray, asSchema, executeTool, generateId, isExecutableTool, normalizeHeaders, safeParseJSON, safeValidateTypes, validateTypes } from "@ai-sdk/provider-utils";
|
|
2
|
+
import { DelayedPromise, asArray, asSchema, convertInlineFileDataToUint8Array, convertUint8ArrayToBase64, detectMediaType, executeTool, generateId, getTopLevelMediaType, isExecutableTool, isFullMediaType, normalizeHeaders, safeParseJSON, safeValidateTypes, validateTypes } from "@ai-sdk/provider-utils";
|
|
3
3
|
import path, { posix } from "node:path";
|
|
4
|
-
import { DefaultStepResult, addLanguageModelUsage, asLanguageModelUsage, createAsyncIterableStream, createNullLanguageModelUsage, createRestrictedTelemetryDispatcher, mergeCallbacks, parseToolCall, toResponseMessages, validateToolContext } from "ai/internal";
|
|
4
|
+
import { DefaultStepResult, addLanguageModelUsage, asLanguageModelUsage, createAsyncIterableStream, createNullLanguageModelUsage, createRestrictedTelemetryDispatcher, createToolModelOutput, mergeCallbacks, parseToolCall, toResponseMessages, validateToolContext } from "ai/internal";
|
|
5
5
|
import { NoSuchToolError, createUIMessageStreamResponse, toUIMessageStream } from "ai";
|
|
6
6
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
7
7
|
//#region src/errors/harness-error.ts
|
|
@@ -226,6 +226,9 @@ async function toHarnessStream(options) {
|
|
|
226
226
|
* and throw a clear error.
|
|
227
227
|
*/
|
|
228
228
|
var HarnessStreamTextResult = class {
|
|
229
|
+
setToolModelOutput(input) {
|
|
230
|
+
this.toolModelOutputs.set(input.toolCallId, input.output);
|
|
231
|
+
}
|
|
229
232
|
constructor(options) {
|
|
230
233
|
this._content = new DelayedPromise();
|
|
231
234
|
this._text = new DelayedPromise();
|
|
@@ -251,9 +254,12 @@ var HarnessStreamTextResult = class {
|
|
|
251
254
|
this._providerMetadata = new DelayedPromise();
|
|
252
255
|
this.stepsBuffer = [];
|
|
253
256
|
this.currentStepContent = [];
|
|
257
|
+
this.currentStepTextContent = /* @__PURE__ */ new Map();
|
|
258
|
+
this.currentStepReasoningContent = /* @__PURE__ */ new Map();
|
|
254
259
|
this.currentStepWarnings = [];
|
|
255
260
|
this.stepNumber = 0;
|
|
256
261
|
this.stepStarted = false;
|
|
262
|
+
this.toolModelOutputs = /* @__PURE__ */ new Map();
|
|
257
263
|
this.accumulatedUsage = createNullLanguageModelUsage();
|
|
258
264
|
this.finalProviderMetadata = void 0;
|
|
259
265
|
this.finalFinishReason = "other";
|
|
@@ -319,6 +325,8 @@ var HarnessStreamTextResult = class {
|
|
|
319
325
|
*/
|
|
320
326
|
discardCurrentStepContent() {
|
|
321
327
|
this.currentStepContent = [];
|
|
328
|
+
this.currentStepTextContent.clear();
|
|
329
|
+
this.currentStepReasoningContent.clear();
|
|
322
330
|
this.currentStepWarnings = [];
|
|
323
331
|
this.stepStarted = false;
|
|
324
332
|
}
|
|
@@ -372,6 +380,8 @@ var HarnessStreamTextResult = class {
|
|
|
372
380
|
if (this.currentStepWarnings.length > 0) this.aggregateWarnings.push(...this.currentStepWarnings);
|
|
373
381
|
this.stepNumber += 1;
|
|
374
382
|
this.currentStepContent = [];
|
|
383
|
+
this.currentStepTextContent.clear();
|
|
384
|
+
this.currentStepReasoningContent.clear();
|
|
375
385
|
this.currentStepWarnings = [];
|
|
376
386
|
this.stepStarted = false;
|
|
377
387
|
return step;
|
|
@@ -426,8 +436,8 @@ var HarnessStreamTextResult = class {
|
|
|
426
436
|
const aggregatedContent = this.stepsBuffer.flatMap((s) => s.content);
|
|
427
437
|
this._content.resolve(aggregatedContent);
|
|
428
438
|
this._text.resolve(finalStep.text);
|
|
429
|
-
this._reasoning.resolve(
|
|
430
|
-
this._reasoningText.resolve(
|
|
439
|
+
this._reasoning.resolve(finalStep.content.filter((part) => part.type === "reasoning" || part.type === "reasoning-file"));
|
|
440
|
+
this._reasoningText.resolve(finalStep.reasoningText);
|
|
431
441
|
this._files.resolve(this.stepsBuffer.flatMap((s) => s.files));
|
|
432
442
|
this._sources.resolve(this.stepsBuffer.flatMap((s) => s.sources));
|
|
433
443
|
this._toolCalls.resolve(this.stepsBuffer.flatMap((s) => s.toolCalls));
|
|
@@ -445,10 +455,20 @@ var HarnessStreamTextResult = class {
|
|
|
445
455
|
this._request.resolve(finalStep.request);
|
|
446
456
|
this._response.resolve(finalStep.response);
|
|
447
457
|
this._providerMetadata.resolve(this.finalProviderMetadata);
|
|
448
|
-
const
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
458
|
+
const responseTools = {};
|
|
459
|
+
for (const [name, tool] of Object.entries(this.tools)) responseTools[name] = {
|
|
460
|
+
...tool,
|
|
461
|
+
toModelOutput: (options) => this.toolModelOutputs.get(options.toolCallId) ?? createToolModelOutput({
|
|
462
|
+
...options,
|
|
463
|
+
tool,
|
|
464
|
+
errorMode: "none"
|
|
465
|
+
})
|
|
466
|
+
};
|
|
467
|
+
const responseMessages = [];
|
|
468
|
+
for (const step of this.stepsBuffer) responseMessages.push(...await toResponseMessages({
|
|
469
|
+
content: step.content,
|
|
470
|
+
tools: responseTools
|
|
471
|
+
}));
|
|
452
472
|
this._responseMessages.resolve(responseMessages);
|
|
453
473
|
this.fullStreamController.enqueue({
|
|
454
474
|
type: "finish",
|
|
@@ -640,12 +660,14 @@ var HarnessStreamTextResult = class {
|
|
|
640
660
|
reader.releaseLock();
|
|
641
661
|
}
|
|
642
662
|
}
|
|
643
|
-
toUIMessageStream({ originalMessages, generateMessageId, onEnd, onFinish, messageMetadata, sendReasoning, sendSources, sendStart, sendFinish, onError } = {}) {
|
|
663
|
+
toUIMessageStream({ originalMessages, generateMessageId, onStepEnd, onStepFinish, onEnd, onFinish, messageMetadata, sendReasoning, sendSources, sendStart, sendFinish, onError } = {}) {
|
|
644
664
|
return createAsyncIterableStream(toUIMessageStream({
|
|
645
665
|
stream: this.stream,
|
|
646
666
|
tools: this.tools,
|
|
647
667
|
originalMessages,
|
|
648
668
|
generateMessageId,
|
|
669
|
+
onStepEnd,
|
|
670
|
+
onStepFinish,
|
|
649
671
|
onEnd,
|
|
650
672
|
onFinish,
|
|
651
673
|
messageMetadata,
|
|
@@ -662,11 +684,13 @@ var HarnessStreamTextResult = class {
|
|
|
662
684
|
pipeTextStreamToResponse() {
|
|
663
685
|
throw notSupportedYet("pipeTextStreamToResponse");
|
|
664
686
|
}
|
|
665
|
-
toUIMessageStreamResponse({ originalMessages, generateMessageId, onEnd, onFinish, messageMetadata, sendReasoning, sendSources, sendStart, sendFinish, onError, ...init } = {}) {
|
|
687
|
+
toUIMessageStreamResponse({ originalMessages, generateMessageId, onStepEnd, onStepFinish, onEnd, onFinish, messageMetadata, sendReasoning, sendSources, sendStart, sendFinish, onError, ...init } = {}) {
|
|
666
688
|
return createUIMessageStreamResponse({
|
|
667
689
|
stream: this.toUIMessageStream({
|
|
668
690
|
originalMessages,
|
|
669
691
|
generateMessageId,
|
|
692
|
+
onStepEnd,
|
|
693
|
+
onStepFinish,
|
|
670
694
|
onEnd,
|
|
671
695
|
onFinish,
|
|
672
696
|
messageMetadata,
|
|
@@ -684,22 +708,71 @@ var HarnessStreamTextResult = class {
|
|
|
684
708
|
}
|
|
685
709
|
appendToCurrentStepContent(part) {
|
|
686
710
|
switch (part.type) {
|
|
687
|
-
case "text-
|
|
688
|
-
const
|
|
689
|
-
if (last && last.type === "text") last.text += part.text;
|
|
690
|
-
else this.currentStepContent.push({
|
|
711
|
+
case "text-start": {
|
|
712
|
+
const content = {
|
|
691
713
|
type: "text",
|
|
692
|
-
text:
|
|
693
|
-
|
|
714
|
+
text: "",
|
|
715
|
+
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
716
|
+
};
|
|
717
|
+
this.currentStepTextContent.set(part.id, content);
|
|
718
|
+
this.currentStepContent.push(content);
|
|
694
719
|
return;
|
|
695
720
|
}
|
|
696
|
-
case "
|
|
697
|
-
|
|
698
|
-
if (
|
|
699
|
-
|
|
721
|
+
case "text-delta": {
|
|
722
|
+
let content = this.currentStepTextContent.get(part.id);
|
|
723
|
+
if (content == null) {
|
|
724
|
+
content = {
|
|
725
|
+
type: "text",
|
|
726
|
+
text: "",
|
|
727
|
+
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
728
|
+
};
|
|
729
|
+
this.currentStepTextContent.set(part.id, content);
|
|
730
|
+
this.currentStepContent.push(content);
|
|
731
|
+
}
|
|
732
|
+
content.text += part.text;
|
|
733
|
+
if (part.providerMetadata != null) content.providerMetadata = part.providerMetadata;
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
case "text-end": {
|
|
737
|
+
const content = this.currentStepTextContent.get(part.id);
|
|
738
|
+
if (content != null) {
|
|
739
|
+
if (part.providerMetadata != null) content.providerMetadata = part.providerMetadata;
|
|
740
|
+
if (part.citations != null) content.citations = part.citations;
|
|
741
|
+
this.currentStepTextContent.delete(part.id);
|
|
742
|
+
}
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
case "reasoning-start": {
|
|
746
|
+
const content = {
|
|
700
747
|
type: "reasoning",
|
|
701
|
-
text:
|
|
702
|
-
|
|
748
|
+
text: "",
|
|
749
|
+
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
750
|
+
};
|
|
751
|
+
this.currentStepReasoningContent.set(part.id, content);
|
|
752
|
+
this.currentStepContent.push(content);
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
case "reasoning-delta": {
|
|
756
|
+
let content = this.currentStepReasoningContent.get(part.id);
|
|
757
|
+
if (content == null) {
|
|
758
|
+
content = {
|
|
759
|
+
type: "reasoning",
|
|
760
|
+
text: "",
|
|
761
|
+
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
762
|
+
};
|
|
763
|
+
this.currentStepReasoningContent.set(part.id, content);
|
|
764
|
+
this.currentStepContent.push(content);
|
|
765
|
+
}
|
|
766
|
+
content.text += part.text;
|
|
767
|
+
if (part.providerMetadata != null) content.providerMetadata = part.providerMetadata;
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
case "reasoning-end": {
|
|
771
|
+
const content = this.currentStepReasoningContent.get(part.id);
|
|
772
|
+
if (content != null) {
|
|
773
|
+
if (part.providerMetadata != null) content.providerMetadata = part.providerMetadata;
|
|
774
|
+
this.currentStepReasoningContent.delete(part.id);
|
|
775
|
+
}
|
|
703
776
|
return;
|
|
704
777
|
}
|
|
705
778
|
case "tool-call":
|
|
@@ -869,11 +942,12 @@ function translateStreamPart(event, options = {}) {
|
|
|
869
942
|
case "tool-call": return [];
|
|
870
943
|
case "tool-approval-request": return [];
|
|
871
944
|
case "tool-result":
|
|
872
|
-
|
|
945
|
+
const toolCall = options.getToolCall?.(event.toolCallId);
|
|
946
|
+
if (event.isError === true && (toolCall?.providerExecuted ?? options.isProviderExecuted?.(event.toolCallId) ?? true)) return [{
|
|
873
947
|
type: "tool-error",
|
|
874
948
|
toolCallId: event.toolCallId,
|
|
875
949
|
toolName: event.toolName,
|
|
876
|
-
input:
|
|
950
|
+
input: toolCall?.input,
|
|
877
951
|
error: event.result,
|
|
878
952
|
providerExecuted: true,
|
|
879
953
|
...event.dynamic !== void 0 ? { dynamic: event.dynamic } : {},
|
|
@@ -883,8 +957,9 @@ function translateStreamPart(event, options = {}) {
|
|
|
883
957
|
type: "tool-result",
|
|
884
958
|
toolCallId: event.toolCallId,
|
|
885
959
|
toolName: event.toolName,
|
|
886
|
-
input:
|
|
960
|
+
input: toolCall?.input,
|
|
887
961
|
output: event.result,
|
|
962
|
+
...toolCall?.providerExecuted !== void 0 ? { providerExecuted: toolCall.providerExecuted } : {},
|
|
888
963
|
...event.preliminary !== void 0 ? { preliminary: event.preliminary } : {},
|
|
889
964
|
...event.dynamic !== void 0 ? { dynamic: event.dynamic } : {},
|
|
890
965
|
...event.providerMetadata !== void 0 ? { providerMetadata: event.providerMetadata } : {}
|
|
@@ -1438,6 +1513,46 @@ function pinSandboxChannelEventCheckpoint(event) {
|
|
|
1438
1513
|
return event[sandboxChannelEventCheckpointSymbol]?.pin();
|
|
1439
1514
|
}
|
|
1440
1515
|
//#endregion
|
|
1516
|
+
//#region src/utils/normalize-harness-tool-model-output.ts
|
|
1517
|
+
function normalizeHarnessToolModelOutput({ output }) {
|
|
1518
|
+
try {
|
|
1519
|
+
return output.type !== "content" ? output : {
|
|
1520
|
+
...output,
|
|
1521
|
+
value: output.value.map((part) => {
|
|
1522
|
+
if (part.type === "text") return part;
|
|
1523
|
+
const file = part.type === "image-data" || part.type === "file-data" ? {
|
|
1524
|
+
...part,
|
|
1525
|
+
type: "file",
|
|
1526
|
+
data: {
|
|
1527
|
+
type: "data",
|
|
1528
|
+
data: part.data
|
|
1529
|
+
}
|
|
1530
|
+
} : part;
|
|
1531
|
+
if (file.type !== "file" || file.data.type !== "data" || getTopLevelMediaType(file.mediaType) !== "image") throw new Error(`Unsupported content '${part.type}'${file.type === "file" ? ` (${file.mediaType}, ${file.data.type})` : ""}.`);
|
|
1532
|
+
const data = typeof file.data.data === "string" ? file.data.data : convertUint8ArrayToBase64(convertInlineFileDataToUint8Array(file.data));
|
|
1533
|
+
const mediaType = isFullMediaType(file.mediaType) ? file.mediaType : detectMediaType({
|
|
1534
|
+
data,
|
|
1535
|
+
topLevelType: "image"
|
|
1536
|
+
});
|
|
1537
|
+
if (mediaType == null) throw new Error("Cannot detect the inline image media type.");
|
|
1538
|
+
return {
|
|
1539
|
+
...file,
|
|
1540
|
+
mediaType,
|
|
1541
|
+
data: {
|
|
1542
|
+
type: "data",
|
|
1543
|
+
data
|
|
1544
|
+
}
|
|
1545
|
+
};
|
|
1546
|
+
})
|
|
1547
|
+
};
|
|
1548
|
+
} catch (cause) {
|
|
1549
|
+
throw new HarnessCapabilityUnsupportedError({
|
|
1550
|
+
message: `Harnesses support only text and inline images in tool model output. ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
1551
|
+
cause
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
//#endregion
|
|
1441
1556
|
//#region src/agent/internal/run-prompt.ts
|
|
1442
1557
|
const invalidToolInputMessage = "Tool input validation failed.";
|
|
1443
1558
|
function unwrapToolResultOutput(toolResult) {
|
|
@@ -1565,10 +1680,13 @@ function runPrompt(input) {
|
|
|
1565
1680
|
const stripToolInputWorkDir = createToolInputWorkDirStripper({ sessionWorkDir: input.sessionWorkDir });
|
|
1566
1681
|
const toolCallsByToolCallId = /* @__PURE__ */ new Map();
|
|
1567
1682
|
const rawToolCallsByToolCallId = /* @__PURE__ */ new Map();
|
|
1568
|
-
const translateOptions = {
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1683
|
+
const translateOptions = {
|
|
1684
|
+
getToolCall: (toolCallId) => toolCallsByToolCallId.get(toolCallId),
|
|
1685
|
+
isProviderExecuted: (toolCallId) => {
|
|
1686
|
+
const rawToolCall = rawToolCallsByToolCallId.get(toolCallId);
|
|
1687
|
+
return rawToolCall == null || rawToolCall.providerExecuted === true;
|
|
1688
|
+
}
|
|
1689
|
+
};
|
|
1572
1690
|
const pendingApprovalsByApprovalId = new Map(pendingToolApprovals.map((approval) => [approval.approvalId, approval]));
|
|
1573
1691
|
const pendingApprovalsByToolCallId = new Map(pendingToolApprovals.map((approval) => [approval.toolCallId, approval]));
|
|
1574
1692
|
const continuationsByApprovalId = new Map((input.toolApprovalContinuations ?? []).map((continuation) => [continuation.approvalId, continuation]));
|
|
@@ -1622,9 +1740,10 @@ function runPrompt(input) {
|
|
|
1622
1740
|
toolExecutions.clear();
|
|
1623
1741
|
bufferedToolOutcomes = [];
|
|
1624
1742
|
};
|
|
1625
|
-
let
|
|
1626
|
-
let
|
|
1627
|
-
let
|
|
1743
|
+
let hostInputPauseRequested = false;
|
|
1744
|
+
let deferredPauseFinishStep;
|
|
1745
|
+
let ignoredFinishStep;
|
|
1746
|
+
const hostToolCallIdsAwaitingEcho = /* @__PURE__ */ new Set();
|
|
1628
1747
|
const buildModelCallContent = () => {
|
|
1629
1748
|
const parts = [];
|
|
1630
1749
|
if (stepText) parts.push({
|
|
@@ -1648,9 +1767,7 @@ function runPrompt(input) {
|
|
|
1648
1767
|
stepApprovalRequests = [];
|
|
1649
1768
|
bufferedToolOutcomes = [];
|
|
1650
1769
|
toolExecutions.clear();
|
|
1651
|
-
|
|
1652
|
-
observedStepToolCallCount = 0;
|
|
1653
|
-
pauseAfterStepToolCalls = false;
|
|
1770
|
+
ignoredFinishStep = void 0;
|
|
1654
1771
|
};
|
|
1655
1772
|
const zeroUsage = {
|
|
1656
1773
|
inputTokens: {
|
|
@@ -1687,20 +1804,25 @@ function runPrompt(input) {
|
|
|
1687
1804
|
resetStepContent();
|
|
1688
1805
|
return step;
|
|
1689
1806
|
};
|
|
1690
|
-
const finishForHostInputPause = async (
|
|
1807
|
+
const finishForHostInputPause = async () => {
|
|
1691
1808
|
await waitForOutstandingHostToolExecutions();
|
|
1692
|
-
|
|
1693
|
-
finishReason: toolCallsFinishReason,
|
|
1694
|
-
usage: zeroUsage,
|
|
1695
|
-
providerMetadata: void 0
|
|
1696
|
-
});
|
|
1697
|
-
else await publishToolExecutions();
|
|
1809
|
+
await publishToolExecutions();
|
|
1698
1810
|
await lifecycle.end({
|
|
1699
1811
|
steps: completedSteps,
|
|
1700
1812
|
usage: asLanguageModelUsage(zeroUsage)
|
|
1701
1813
|
});
|
|
1702
1814
|
await result.finish();
|
|
1703
1815
|
};
|
|
1816
|
+
const pauseForHostInput = async (finishStep) => {
|
|
1817
|
+
await waitForOutstandingHostToolExecutions();
|
|
1818
|
+
closingResumedStep = false;
|
|
1819
|
+
await completeStep({
|
|
1820
|
+
finishReason: toolCallsFinishReason,
|
|
1821
|
+
usage: finishStep?.usage ?? zeroUsage,
|
|
1822
|
+
providerMetadata: finishStep?.harnessMetadata
|
|
1823
|
+
});
|
|
1824
|
+
await finishForHostInputPause();
|
|
1825
|
+
};
|
|
1704
1826
|
const enqueueApprovalRequest = (approval) => {
|
|
1705
1827
|
const part = {
|
|
1706
1828
|
type: "tool-approval-request",
|
|
@@ -1768,7 +1890,33 @@ function runPrompt(input) {
|
|
|
1768
1890
|
});
|
|
1769
1891
|
};
|
|
1770
1892
|
const submitToolResult = async (submission) => {
|
|
1771
|
-
if (
|
|
1893
|
+
if (submission.toolResult != null) {
|
|
1894
|
+
let output;
|
|
1895
|
+
try {
|
|
1896
|
+
output = normalizeHarnessToolModelOutput({ output: submission.toolResult.output });
|
|
1897
|
+
} catch (error) {
|
|
1898
|
+
if (!continuationsByToolCallId.has(submission.toolCallId) || !HarnessCapabilityUnsupportedError.isInstance(error)) throw error;
|
|
1899
|
+
output = {
|
|
1900
|
+
type: "text",
|
|
1901
|
+
value: JSON.stringify(submission.output) ?? "null"
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
submission = {
|
|
1905
|
+
...submission,
|
|
1906
|
+
toolResult: {
|
|
1907
|
+
...submission.toolResult,
|
|
1908
|
+
output
|
|
1909
|
+
}
|
|
1910
|
+
};
|
|
1911
|
+
result.setToolModelOutput({
|
|
1912
|
+
toolCallId: submission.toolCallId,
|
|
1913
|
+
output
|
|
1914
|
+
});
|
|
1915
|
+
}
|
|
1916
|
+
if (!input.isTurnSuspending?.()) {
|
|
1917
|
+
if (!settledHostToolCallIds.has(submission.toolCallId)) hostToolCallIdsAwaitingEcho.add(submission.toolCallId);
|
|
1918
|
+
return control.submitToolResult(submission);
|
|
1919
|
+
}
|
|
1772
1920
|
const toolCall = rawToolCallsByToolCallId.get(submission.toolCallId) ?? pendingResultsByToolCallId.get(submission.toolCallId) ?? pendingToolApprovals.find((approval) => approval.toolCallId === submission.toolCallId);
|
|
1773
1921
|
if (toolCall == null) throw new Error(`Unknown suspended tool call '${submission.toolCallId}'.`);
|
|
1774
1922
|
const { toolCallId, ...completedResult } = submission;
|
|
@@ -1915,7 +2063,7 @@ function runPrompt(input) {
|
|
|
1915
2063
|
});
|
|
1916
2064
|
if (!execution.executed) {
|
|
1917
2065
|
recordPendingToolResult({ toolCall: rawToolCall });
|
|
1918
|
-
await finishForHostInputPause(
|
|
2066
|
+
await finishForHostInputPause();
|
|
1919
2067
|
return "awaiting-tool-result";
|
|
1920
2068
|
}
|
|
1921
2069
|
const toolExecution = toolExecutions.get(rawToolCall.toolCallId);
|
|
@@ -1947,8 +2095,8 @@ function runPrompt(input) {
|
|
|
1947
2095
|
}
|
|
1948
2096
|
}
|
|
1949
2097
|
while (true) {
|
|
1950
|
-
if (
|
|
1951
|
-
await
|
|
2098
|
+
if (deferredPauseFinishStep != null && hostToolCallIdsAwaitingEcho.size === 0) {
|
|
2099
|
+
await pauseForHostInput(deferredPauseFinishStep);
|
|
1952
2100
|
return;
|
|
1953
2101
|
}
|
|
1954
2102
|
const { value, done } = await reader.read();
|
|
@@ -1961,6 +2109,7 @@ function runPrompt(input) {
|
|
|
1961
2109
|
result.enqueueRaw(value.rawValue);
|
|
1962
2110
|
continue;
|
|
1963
2111
|
}
|
|
2112
|
+
if (value.type === "tool-result") hostToolCallIdsAwaitingEcho.delete(value.toolCallId);
|
|
1964
2113
|
if (pendingStopBoundary != null) {
|
|
1965
2114
|
if (value.type === "finish") releasePendingStopBoundary();
|
|
1966
2115
|
else if ((await Promise.all(input.stopConditions.map((condition) => condition({ steps: completedSteps })))).some(Boolean)) {
|
|
@@ -1990,6 +2139,43 @@ function runPrompt(input) {
|
|
|
1990
2139
|
const settledHostInputReplay = (displayValue.type === "tool-call" || displayValue.type === "tool-result" || displayValue.type === "tool-approval-request") && settledHostToolCallIds.has(displayValue.toolCallId);
|
|
1991
2140
|
const settledBuiltinApprovalReplay = (displayValue.type === "tool-call" || displayValue.type === "tool-approval-request") && settledBuiltinApprovalToolCallIds.has(displayValue.toolCallId);
|
|
1992
2141
|
if (settledHostInputReplay || settledBuiltinApprovalReplay) continue;
|
|
2142
|
+
if (value.type === "finish-step") {
|
|
2143
|
+
if (hostInputPauseRequested) {
|
|
2144
|
+
await waitForOutstandingHostToolExecutions();
|
|
2145
|
+
if (hostToolCallIdsAwaitingEcho.size === 0) {
|
|
2146
|
+
await pauseForHostInput(value);
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
deferredPauseFinishStep = value;
|
|
2150
|
+
continue;
|
|
2151
|
+
}
|
|
2152
|
+
if (hostToolCallIdsAwaitingEcho.size > 0) {
|
|
2153
|
+
ignoredFinishStep = value;
|
|
2154
|
+
continue;
|
|
2155
|
+
}
|
|
2156
|
+
ignoredFinishStep = void 0;
|
|
2157
|
+
}
|
|
2158
|
+
if (value.type === "finish") {
|
|
2159
|
+
if (hostInputPauseRequested) {
|
|
2160
|
+
await pauseForHostInput(deferredPauseFinishStep);
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
2163
|
+
if (ignoredFinishStep != null) {
|
|
2164
|
+
const finishStep = ignoredFinishStep;
|
|
2165
|
+
ignoredFinishStep = void 0;
|
|
2166
|
+
await waitForOutstandingHostToolExecutions();
|
|
2167
|
+
if (closingResumedStep) {
|
|
2168
|
+
closingResumedStep = false;
|
|
2169
|
+
await publishToolExecutions();
|
|
2170
|
+
resetStepContent();
|
|
2171
|
+
result.discardCurrentStepContent();
|
|
2172
|
+
} else await completeStep({
|
|
2173
|
+
finishReason: finishStep.finishReason,
|
|
2174
|
+
usage: finishStep.usage,
|
|
2175
|
+
providerMetadata: finishStep.harnessMetadata
|
|
2176
|
+
});
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
1993
2179
|
if (displayValue.type === "finish-step" && closingResumedStep) {
|
|
1994
2180
|
closingResumedStep = false;
|
|
1995
2181
|
await publishToolExecutions();
|
|
@@ -2006,6 +2192,7 @@ function runPrompt(input) {
|
|
|
2006
2192
|
toolFiltering: input.builtinToolFiltering
|
|
2007
2193
|
})) {
|
|
2008
2194
|
if (control.submitToolApproval == null) throw new Error(`Harness '${input.harness.harnessId}' emitted a built-in tool approval request but does not support approval responses.`);
|
|
2195
|
+
hostToolCallIdsAwaitingEcho.add(displayValue.toolCallId);
|
|
2009
2196
|
await control.submitToolApproval({
|
|
2010
2197
|
approvalId: displayValue.approvalId,
|
|
2011
2198
|
approved: false,
|
|
@@ -2063,8 +2250,6 @@ function runPrompt(input) {
|
|
|
2063
2250
|
if (value.type === "text-delta") stepText += value.delta;
|
|
2064
2251
|
else if (value.type === "reasoning-delta") stepReasoning += value.delta;
|
|
2065
2252
|
if (value.type === "tool-call") {
|
|
2066
|
-
observedStepToolCallCount += 1;
|
|
2067
|
-
expectedStepToolCallCount ??= value.stepToolCallCount;
|
|
2068
2253
|
const toolCall = toolCallsByToolCallId.get(value.toolCallId);
|
|
2069
2254
|
if (toolCall != null) {
|
|
2070
2255
|
stepToolCalls.push(toolCall);
|
|
@@ -2115,8 +2300,8 @@ function runPrompt(input) {
|
|
|
2115
2300
|
approvalId: pendingApproval.approvalId,
|
|
2116
2301
|
toolCall
|
|
2117
2302
|
});
|
|
2118
|
-
|
|
2119
|
-
|
|
2303
|
+
hostInputPauseRequested = true;
|
|
2304
|
+
continue;
|
|
2120
2305
|
}
|
|
2121
2306
|
if (value.type === "finish-step") {
|
|
2122
2307
|
await waitForOutstandingHostToolExecutions();
|
|
@@ -2167,12 +2352,8 @@ function runPrompt(input) {
|
|
|
2167
2352
|
}
|
|
2168
2353
|
if (isClientExecutedBuiltin) {
|
|
2169
2354
|
recordPendingToolResult({ toolCall });
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
continue;
|
|
2173
|
-
}
|
|
2174
|
-
await finishForHostInputPause({ completeCurrentStep: true });
|
|
2175
|
-
return;
|
|
2355
|
+
hostInputPauseRequested = true;
|
|
2356
|
+
continue;
|
|
2176
2357
|
}
|
|
2177
2358
|
if (validatedHostToolCall == null) throw new Error(`Harness '${input.harness.harnessId}' could not validate host tool '${toolCall.toolName}'.`);
|
|
2178
2359
|
if (validatedHostToolCall.invalid) {
|
|
@@ -2260,22 +2441,15 @@ function runPrompt(input) {
|
|
|
2260
2441
|
approvalId: pendingApproval.approvalId,
|
|
2261
2442
|
toolCall: pendingParsedToolCall
|
|
2262
2443
|
});
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
continue;
|
|
2266
|
-
}
|
|
2267
|
-
await finishForHostInputPause({ completeCurrentStep: true });
|
|
2268
|
-
return;
|
|
2444
|
+
hostInputPauseRequested = true;
|
|
2445
|
+
continue;
|
|
2269
2446
|
}
|
|
2270
2447
|
if (!isExecutableTool(activeTools[toolCall.toolName])) {
|
|
2271
2448
|
recordPendingToolResult({ toolCall });
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
continue;
|
|
2275
|
-
}
|
|
2276
|
-
await finishForHostInputPause({ completeCurrentStep: true });
|
|
2277
|
-
return;
|
|
2449
|
+
hostInputPauseRequested = true;
|
|
2450
|
+
continue;
|
|
2278
2451
|
}
|
|
2452
|
+
hostToolCallIdsAwaitingEcho.add(toolCall.toolCallId);
|
|
2279
2453
|
startHostToolExecution((async () => {
|
|
2280
2454
|
const toolExecution = toolExecutions.get(toolCall.toolCallId);
|
|
2281
2455
|
if (toolExecution == null) throw new Error(`Harness '${input.harness.harnessId}' could not track host tool '${toolCall.toolName}'.`);
|
|
@@ -2318,6 +2492,10 @@ function runPrompt(input) {
|
|
|
2318
2492
|
})());
|
|
2319
2493
|
}
|
|
2320
2494
|
}
|
|
2495
|
+
if (hostInputPauseRequested && input.isTurnSuspending?.() !== true) {
|
|
2496
|
+
await pauseForHostInput(deferredPauseFinishStep);
|
|
2497
|
+
return;
|
|
2498
|
+
}
|
|
2321
2499
|
await waitForOutstandingHostToolExecutions();
|
|
2322
2500
|
if (input.isTurnSuspending?.() === true) {
|
|
2323
2501
|
await publishToolExecutions();
|
|
@@ -2442,7 +2620,19 @@ async function maybeExecuteHostTool(input) {
|
|
|
2442
2620
|
});
|
|
2443
2621
|
await input.submitToolResult({
|
|
2444
2622
|
toolCallId: input.event.toolCallId,
|
|
2445
|
-
output
|
|
2623
|
+
output,
|
|
2624
|
+
...tool.toModelOutput == null ? {} : { toolResult: {
|
|
2625
|
+
type: "tool-result",
|
|
2626
|
+
toolCallId: input.event.toolCallId,
|
|
2627
|
+
toolName: input.event.toolName,
|
|
2628
|
+
output: await createToolModelOutput({
|
|
2629
|
+
toolCallId: input.event.toolCallId,
|
|
2630
|
+
input: input.parsedToolCall.input,
|
|
2631
|
+
output,
|
|
2632
|
+
tool,
|
|
2633
|
+
errorMode: "none"
|
|
2634
|
+
})
|
|
2635
|
+
} }
|
|
2446
2636
|
});
|
|
2447
2637
|
return {
|
|
2448
2638
|
executed: true,
|
|
@@ -3034,6 +3224,9 @@ var HarnessAgentSession = class {
|
|
|
3034
3224
|
* locally to find the original tool call before it can resume the paused turn.
|
|
3035
3225
|
* Responses that already have a tool result are ignored, because those
|
|
3036
3226
|
* approvals were already consumed by a prior continuation.
|
|
3227
|
+
* An `execution-denied` result is synthesized by `convertToModelMessages`
|
|
3228
|
+
* for a newly denied approval; it does not mean the harness has received
|
|
3229
|
+
* the decision, so that approval response must still continue the turn.
|
|
3037
3230
|
*/
|
|
3038
3231
|
function collectHarnessAgentToolApprovalContinuations(input) {
|
|
3039
3232
|
const lastMessage = input.messages.at(-1);
|
|
@@ -3046,7 +3239,7 @@ function collectHarnessAgentToolApprovalContinuations(input) {
|
|
|
3046
3239
|
else if (part.type === "tool-approval-request") approvalRequestsByApprovalId.set(part.approvalId, part);
|
|
3047
3240
|
}
|
|
3048
3241
|
const toolResultIds = /* @__PURE__ */ new Set();
|
|
3049
|
-
for (const part of lastMessage.content) if (part.type === "tool-result") toolResultIds.add(part.toolCallId);
|
|
3242
|
+
for (const part of lastMessage.content) if (part.type === "tool-result" && part.output.type !== "execution-denied") toolResultIds.add(part.toolCallId);
|
|
3050
3243
|
const continuations = [];
|
|
3051
3244
|
for (const part of lastMessage.content) {
|
|
3052
3245
|
if (part.type !== "tool-approval-response") continue;
|