@ai-sdk/harness-claude-code 1.0.154 → 1.0.156
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 +19 -0
- package/dist/bridge/index.mjs +246 -54
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/src/bridge/create-emit-stream-event.ts +189 -37
- package/src/bridge/index.ts +109 -41
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @ai-sdk/harness-claude-code
|
|
2
2
|
|
|
3
|
+
## 1.0.156
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [2e89fa4]
|
|
8
|
+
- @ai-sdk/provider-utils@5.0.60
|
|
9
|
+
- @ai-sdk/harness@1.0.152
|
|
10
|
+
|
|
11
|
+
## 1.0.155
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 6c65131: feat(harness): consistently support parallel and sequential tool approvals
|
|
16
|
+
- 1bebfcf: feat(harness): add support for tools with `toModelOutput()` transformation
|
|
17
|
+
- 0291550: fix(harness-claude-code): wait for response completion before finishing tool steps
|
|
18
|
+
- Updated dependencies [6c65131]
|
|
19
|
+
- Updated dependencies [1bebfcf]
|
|
20
|
+
- @ai-sdk/harness@1.0.151
|
|
21
|
+
|
|
3
22
|
## 1.0.154
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/dist/bridge/index.mjs
CHANGED
|
@@ -8,6 +8,71 @@ import * as mcpServerModule from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
8
8
|
import { isDeepStrictEqual } from "node:util";
|
|
9
9
|
import { z } from "zod/v4";
|
|
10
10
|
//#region ../harness/dist/bridge/index.js
|
|
11
|
+
const name = "AI_HarnessBridgeCapabilityUnsupportedError";
|
|
12
|
+
/**
|
|
13
|
+
* Signals an unsupported capability discovered inside a sandbox bridge.
|
|
14
|
+
* `isInstance` also recognizes the serialized error shape received by the
|
|
15
|
+
* host, where it can be translated to `HarnessCapabilityUnsupportedError`.
|
|
16
|
+
*/
|
|
17
|
+
var HarnessBridgeCapabilityUnsupportedError = class extends Error {
|
|
18
|
+
constructor({ message, harnessId, cause }) {
|
|
19
|
+
super(message);
|
|
20
|
+
Object.defineProperty(this, "name", { value: name });
|
|
21
|
+
this.harnessId = harnessId;
|
|
22
|
+
this.cause = cause;
|
|
23
|
+
}
|
|
24
|
+
static isInstance(error) {
|
|
25
|
+
return error != null && typeof error === "object" && "name" in error && error.name === name && "message" in error && typeof error.message === "string";
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
function getNormalizedInlineImage(part) {
|
|
29
|
+
if (part.type === "file" && part.mediaType.startsWith("image/") && part.mediaType !== "image/*" && part.data.type === "data" && typeof part.data.data === "string") return {
|
|
30
|
+
data: part.data.data,
|
|
31
|
+
mediaType: part.mediaType
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function convertHarnessToolModelOutput({ output }) {
|
|
35
|
+
switch (output.type) {
|
|
36
|
+
case "text":
|
|
37
|
+
case "error-text": return {
|
|
38
|
+
content: [{
|
|
39
|
+
type: "text",
|
|
40
|
+
text: output.value
|
|
41
|
+
}],
|
|
42
|
+
isError: output.type === "error-text"
|
|
43
|
+
};
|
|
44
|
+
case "json":
|
|
45
|
+
case "error-json": return {
|
|
46
|
+
content: [{
|
|
47
|
+
type: "text",
|
|
48
|
+
text: JSON.stringify(output.value)
|
|
49
|
+
}],
|
|
50
|
+
isError: output.type === "error-json"
|
|
51
|
+
};
|
|
52
|
+
case "execution-denied": return {
|
|
53
|
+
content: [{
|
|
54
|
+
type: "text",
|
|
55
|
+
text: output.reason ?? "Tool execution denied."
|
|
56
|
+
}],
|
|
57
|
+
isError: true
|
|
58
|
+
};
|
|
59
|
+
case "content": return {
|
|
60
|
+
content: output.value.map((part) => {
|
|
61
|
+
if (part.type === "text") return {
|
|
62
|
+
type: "text",
|
|
63
|
+
text: part.text
|
|
64
|
+
};
|
|
65
|
+
const image = getNormalizedInlineImage(part);
|
|
66
|
+
if (image != null) return {
|
|
67
|
+
type: "image",
|
|
68
|
+
...image
|
|
69
|
+
};
|
|
70
|
+
throw new HarnessBridgeCapabilityUnsupportedError({ message: `Harnesses support only text and inline images in tool model output; unsupported content '${part.type}'.` });
|
|
71
|
+
}),
|
|
72
|
+
isError: false
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
11
76
|
const DEBUG_LEVEL_WEIGHT = {
|
|
12
77
|
error: 0,
|
|
13
78
|
warn: 1,
|
|
@@ -632,12 +697,17 @@ function createClaudeStreamEventState() {
|
|
|
632
697
|
pendingStepDeltaUsage: void 0,
|
|
633
698
|
pendingStepUsage: void 0,
|
|
634
699
|
pendingResponseUsage: void 0,
|
|
700
|
+
responseOpen: false,
|
|
635
701
|
stepOpen: false,
|
|
636
702
|
mcpToolCalls: /* @__PURE__ */ new Map(),
|
|
637
703
|
mcpHandlerCalls: /* @__PURE__ */ new Map(),
|
|
638
704
|
externalMcpToolUseIds: /* @__PURE__ */ new Set(),
|
|
639
705
|
structuredOutputToolUseIds: /* @__PURE__ */ new Set(),
|
|
640
|
-
observedTerminalError: void 0
|
|
706
|
+
observedTerminalError: void 0,
|
|
707
|
+
hostInputWaitingToolUseIds: /* @__PURE__ */ new Set(),
|
|
708
|
+
earlyFinishStepToolUseIds: /* @__PURE__ */ new Set(),
|
|
709
|
+
emittedToolCallIds: /* @__PURE__ */ new Set(),
|
|
710
|
+
modelResponseStreaming: false
|
|
641
711
|
};
|
|
642
712
|
}
|
|
643
713
|
const UNRECOVERABLE_API_RETRY_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -730,12 +800,34 @@ function createEmitStreamEvent({ state, emit, emitWarning, emitTerminalError, on
|
|
|
730
800
|
continue;
|
|
731
801
|
}
|
|
732
802
|
if (block.name.startsWith(HOST_TOOL_PREFIX)) {
|
|
803
|
+
const hostToolName = block.name.slice(20);
|
|
733
804
|
state.pendingStepToolUseIds.add(block.id);
|
|
734
805
|
state.mcpToolCalls.set(block.id, {
|
|
735
|
-
toolName:
|
|
806
|
+
toolName: hostToolName,
|
|
736
807
|
input: block.input ?? {}
|
|
737
808
|
});
|
|
738
809
|
opensStep = true;
|
|
810
|
+
const handlerCallId = findMcpHandlerCallId({
|
|
811
|
+
state,
|
|
812
|
+
toolCallId: block.id,
|
|
813
|
+
toolCall: state.mcpToolCalls.get(block.id)
|
|
814
|
+
});
|
|
815
|
+
if (handlerCallId != null) {
|
|
816
|
+
state.mcpHandlerCalls.get(handlerCallId).toolUseId = block.id;
|
|
817
|
+
state.emittedToolCallIds.add(block.id);
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
state.hostInputWaitingToolUseIds.add(block.id);
|
|
821
|
+
if (!state.emittedToolCallIds.has(block.id)) {
|
|
822
|
+
state.emittedToolCallIds.add(block.id);
|
|
823
|
+
emit({
|
|
824
|
+
type: "tool-call",
|
|
825
|
+
toolCallId: block.id,
|
|
826
|
+
toolName: hostToolName,
|
|
827
|
+
input: JSON.stringify(block.input ?? {}),
|
|
828
|
+
providerExecuted: false
|
|
829
|
+
});
|
|
830
|
+
}
|
|
739
831
|
continue;
|
|
740
832
|
}
|
|
741
833
|
state.nativeToolCallNames.set(block.id, block.name);
|
|
@@ -746,9 +838,10 @@ function createEmitStreamEvent({ state, emit, emitWarning, emitTerminalError, on
|
|
|
746
838
|
}
|
|
747
839
|
const dynamic = isExternalMcpTool(block.name);
|
|
748
840
|
if (dynamic) state.externalMcpToolUseIds.add(block.id);
|
|
749
|
-
if (state.approvalRequestedToolUseIds.has(block.id)) continue;
|
|
750
841
|
state.pendingStepToolUseIds.add(block.id);
|
|
751
842
|
opensStep = true;
|
|
843
|
+
if (state.emittedToolCallIds.has(block.id)) continue;
|
|
844
|
+
state.emittedToolCallIds.add(block.id);
|
|
752
845
|
emit({
|
|
753
846
|
type: "tool-call",
|
|
754
847
|
toolCallId: block.id,
|
|
@@ -765,6 +858,10 @@ function createEmitStreamEvent({ state, emit, emitWarning, emitTerminalError, on
|
|
|
765
858
|
state.pendingStepAssistantUsage = usage;
|
|
766
859
|
updatePendingStepUsage(state);
|
|
767
860
|
}
|
|
861
|
+
if (state.hostInputWaitingToolUseIds.size > 0) closeStepIfReady({
|
|
862
|
+
state,
|
|
863
|
+
emit
|
|
864
|
+
});
|
|
768
865
|
}
|
|
769
866
|
return;
|
|
770
867
|
}
|
|
@@ -781,6 +878,7 @@ function createEmitStreamEvent({ state, emit, emitWarning, emitTerminalError, on
|
|
|
781
878
|
});
|
|
782
879
|
state.mcpToolCalls.delete(block.tool_use_id);
|
|
783
880
|
state.pendingStepToolUseIds.delete(block.tool_use_id);
|
|
881
|
+
state.hostInputWaitingToolUseIds.delete(block.tool_use_id);
|
|
784
882
|
if (handlerReportedCall) continue;
|
|
785
883
|
const isError = !!block.is_error;
|
|
786
884
|
const result = toolUseResult !== void 0 ? toolUseResult : resolveToolResult({
|
|
@@ -789,13 +887,16 @@ function createEmitStreamEvent({ state, emit, emitWarning, emitTerminalError, on
|
|
|
789
887
|
isError,
|
|
790
888
|
rawContent: block.content
|
|
791
889
|
});
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
890
|
+
if (!state.emittedToolCallIds.has(block.tool_use_id)) {
|
|
891
|
+
state.emittedToolCallIds.add(block.tool_use_id);
|
|
892
|
+
emit({
|
|
893
|
+
type: "tool-call",
|
|
894
|
+
toolCallId: block.tool_use_id,
|
|
895
|
+
toolName: mcpToolCall.toolName,
|
|
896
|
+
input: JSON.stringify(mcpToolCall.input),
|
|
897
|
+
providerExecuted: true
|
|
898
|
+
});
|
|
899
|
+
}
|
|
799
900
|
emit({
|
|
800
901
|
type: "tool-result",
|
|
801
902
|
toolCallId: block.tool_use_id,
|
|
@@ -835,27 +936,40 @@ function createEmitStreamEvent({ state, emit, emitWarning, emitTerminalError, on
|
|
|
835
936
|
};
|
|
836
937
|
}
|
|
837
938
|
function takeMcpHandlerCall({ state, toolCallId, toolCall }) {
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
}
|
|
939
|
+
const handlerCallId = findMcpHandlerCallId({
|
|
940
|
+
state,
|
|
941
|
+
toolCallId,
|
|
942
|
+
toolCall
|
|
943
|
+
});
|
|
944
|
+
if (handlerCallId != null) return state.mcpHandlerCalls.delete(handlerCallId);
|
|
843
945
|
const matchingHandlerCallIds = Array.from(state.mcpHandlerCalls).filter(([, handlerCall]) => handlerCall.toolName === toolCall.toolName).map(([handlerCallId]) => handlerCallId);
|
|
844
946
|
const matchingToolCallCount = Array.from(state.mcpToolCalls.values()).filter((pendingCall) => pendingCall.toolName === toolCall.toolName).length;
|
|
845
|
-
if (matchingHandlerCallIds.length > 0 && matchingHandlerCallIds.length === matchingToolCallCount)
|
|
846
|
-
state.mcpHandlerCalls.delete(matchingHandlerCallIds[0]);
|
|
847
|
-
return true;
|
|
848
|
-
}
|
|
947
|
+
if (matchingHandlerCallIds.length > 0 && matchingHandlerCallIds.length === matchingToolCallCount) return state.mcpHandlerCalls.delete(matchingHandlerCallIds[0]);
|
|
849
948
|
return false;
|
|
850
949
|
}
|
|
851
|
-
function
|
|
950
|
+
function findMcpHandlerCallId({ state, toolCallId, toolCall }) {
|
|
951
|
+
if (state.mcpHandlerCalls.has(toolCallId)) return toolCallId;
|
|
952
|
+
for (const [handlerCallId, handlerCall] of state.mcpHandlerCalls) {
|
|
953
|
+
if (handlerCall.toolUseId != null && handlerCall.toolUseId !== toolCallId || handlerCallId !== toolCallId && state.mcpToolCalls.has(handlerCallId)) continue;
|
|
954
|
+
if (handlerCall.toolName === toolCall.toolName && isDeepStrictEqual(handlerCall.input, toolCall.input)) return handlerCallId;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
function markWaitingOnHostInput({ state, emit, toolUseId }) {
|
|
852
958
|
state.stepOpen = true;
|
|
853
|
-
state.pendingStepToolUseIds.
|
|
959
|
+
state.pendingStepToolUseIds.add(toolUseId);
|
|
960
|
+
state.hostInputWaitingToolUseIds.add(toolUseId);
|
|
854
961
|
closeStepIfReady({
|
|
855
962
|
state,
|
|
856
963
|
emit
|
|
857
964
|
});
|
|
858
965
|
}
|
|
966
|
+
function clearWaitingOnHostInput({ state, toolUseId }) {
|
|
967
|
+
state.hostInputWaitingToolUseIds.delete(toolUseId);
|
|
968
|
+
}
|
|
969
|
+
function resolveMcpHandlerToolUseId({ state, metadataToolUseId, toolName, input }) {
|
|
970
|
+
if (metadataToolUseId != null) return metadataToolUseId;
|
|
971
|
+
for (const [toolUseId, toolCall] of state.mcpToolCalls) if (!state.mcpHandlerCalls.has(toolUseId) && toolCall.toolName === toolName && isDeepStrictEqual(toolCall.input, input)) return toolUseId;
|
|
972
|
+
}
|
|
859
973
|
function emitFinishStep({ state, emit, usage }) {
|
|
860
974
|
emit({
|
|
861
975
|
type: "finish-step",
|
|
@@ -870,14 +984,37 @@ function emitFinishStep({ state, emit, usage }) {
|
|
|
870
984
|
state.pendingStepDeltaUsage = void 0;
|
|
871
985
|
state.pendingStepUsage = void 0;
|
|
872
986
|
state.pendingStepToolUseIds = /* @__PURE__ */ new Set();
|
|
987
|
+
state.earlyFinishStepToolUseIds = /* @__PURE__ */ new Set();
|
|
873
988
|
state.stepOpen = false;
|
|
874
989
|
}
|
|
875
990
|
function closeStepIfReady({ state, emit }) {
|
|
876
|
-
if (!state.stepOpen || state.
|
|
877
|
-
|
|
991
|
+
if (!state.stepOpen || state.responseOpen || state.partialBlocks.size > 0) return;
|
|
992
|
+
if (state.pendingStepToolUseIds.size === 0) {
|
|
993
|
+
emitFinishStep({
|
|
994
|
+
state,
|
|
995
|
+
emit,
|
|
996
|
+
usage: state.pendingStepUsage
|
|
997
|
+
});
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
emitEarlyFinishStepIfReady({
|
|
878
1001
|
state,
|
|
879
|
-
emit
|
|
880
|
-
|
|
1002
|
+
emit
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
function emitEarlyFinishStepIfReady({ state, emit }) {
|
|
1006
|
+
if (!state.stepOpen || state.partialBlocks.size > 0 || state.modelResponseStreaming || state.pendingStepToolUseIds.size === 0) return;
|
|
1007
|
+
const uncovered = [...state.hostInputWaitingToolUseIds].filter((toolUseId) => state.pendingStepToolUseIds.has(toolUseId) && !state.earlyFinishStepToolUseIds.has(toolUseId));
|
|
1008
|
+
if (uncovered.length === 0) return;
|
|
1009
|
+
for (const toolUseId of uncovered) state.earlyFinishStepToolUseIds.add(toolUseId);
|
|
1010
|
+
emit({
|
|
1011
|
+
type: "finish-step",
|
|
1012
|
+
finishReason: {
|
|
1013
|
+
unified: "tool-calls",
|
|
1014
|
+
raw: "host-input"
|
|
1015
|
+
},
|
|
1016
|
+
usage: defaultUsage(),
|
|
1017
|
+
harnessMetadata: { "claude-code": { inferredStep: true } }
|
|
881
1018
|
});
|
|
882
1019
|
}
|
|
883
1020
|
function formatApiRetryWarning(msg) {
|
|
@@ -894,7 +1031,9 @@ function formatApiRetryWarning(msg) {
|
|
|
894
1031
|
function handleStreamEvent({ event, message, state, send, toCommonName }) {
|
|
895
1032
|
if (!event) return;
|
|
896
1033
|
if (event.type === "message_start") {
|
|
1034
|
+
state.modelResponseStreaming = true;
|
|
897
1035
|
state.pendingResponseUsage = toUsageRecord(event.message?.usage);
|
|
1036
|
+
state.responseOpen = true;
|
|
898
1037
|
return;
|
|
899
1038
|
}
|
|
900
1039
|
if (event.type === "message_delta") {
|
|
@@ -915,6 +1054,12 @@ function handleStreamEvent({ event, message, state, send, toCommonName }) {
|
|
|
915
1054
|
}
|
|
916
1055
|
});
|
|
917
1056
|
state.pendingResponseUsage = void 0;
|
|
1057
|
+
state.modelResponseStreaming = false;
|
|
1058
|
+
state.responseOpen = false;
|
|
1059
|
+
closeStepIfReady({
|
|
1060
|
+
state,
|
|
1061
|
+
emit: send
|
|
1062
|
+
});
|
|
918
1063
|
return;
|
|
919
1064
|
}
|
|
920
1065
|
if (typeof event.index !== "number") return;
|
|
@@ -1355,22 +1500,26 @@ function createPermissionOptions(input) {
|
|
|
1355
1500
|
const approvalId = options.toolUseID;
|
|
1356
1501
|
input.approvalRequestedToolUseIds.add(approvalId);
|
|
1357
1502
|
input.nativeToolCallNames.set(approvalId, toolName);
|
|
1358
|
-
input.
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1503
|
+
if (!input.emittedToolCallIds.has(approvalId)) {
|
|
1504
|
+
input.emittedToolCallIds.add(approvalId);
|
|
1505
|
+
input.emit({
|
|
1506
|
+
type: "tool-call",
|
|
1507
|
+
toolCallId: approvalId,
|
|
1508
|
+
toolName: toCommonName(toolName),
|
|
1509
|
+
nativeName: toolName,
|
|
1510
|
+
input: JSON.stringify(toolInput ?? {}),
|
|
1511
|
+
providerExecuted: true,
|
|
1512
|
+
...isExternalMcpTool(toolName) ? { dynamic: true } : {}
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
const decisionPromise = input.turn.requestToolApproval(approvalId);
|
|
1367
1516
|
input.emit({
|
|
1368
1517
|
type: "tool-approval-request",
|
|
1369
1518
|
approvalId,
|
|
1370
1519
|
toolCallId: approvalId
|
|
1371
1520
|
});
|
|
1372
|
-
input.
|
|
1373
|
-
const decision = await input.
|
|
1521
|
+
input.markWaitingOnHostInput(approvalId);
|
|
1522
|
+
const decision = await decisionPromise.finally(() => input.clearWaitingOnHostInput(approvalId));
|
|
1374
1523
|
return decision.approved ? {
|
|
1375
1524
|
behavior: "allow",
|
|
1376
1525
|
updatedInput: toolInput,
|
|
@@ -1400,6 +1549,7 @@ function createQuestionPreToolUseHook(input) {
|
|
|
1400
1549
|
providerMetadata: { "claude-code": { nativeRequest: nativeInput } }
|
|
1401
1550
|
});
|
|
1402
1551
|
const questionKey = claudeCodeQuestionKey(nativeInput);
|
|
1552
|
+
input.markWaitingOnHostInput(toolCallId);
|
|
1403
1553
|
const nativeResult = toClaudeCodeQuestionResult({
|
|
1404
1554
|
nativeInput,
|
|
1405
1555
|
output: (await input.turn.requestToolResult({
|
|
@@ -1408,7 +1558,7 @@ function createQuestionPreToolUseHook(input) {
|
|
|
1408
1558
|
const nativeRequest = candidate.toolResult?.providerOptions?.["claude-code"]?.nativeRequest;
|
|
1409
1559
|
return nativeRequest != null && claudeCodeQuestionKey(nativeRequest) === questionKey;
|
|
1410
1560
|
}
|
|
1411
|
-
})).output
|
|
1561
|
+
}).finally(() => input.clearWaitingOnHostInput(toolCallId))).output
|
|
1412
1562
|
});
|
|
1413
1563
|
return { hookSpecificOutput: {
|
|
1414
1564
|
hookEventName: "PreToolUse",
|
|
@@ -1461,19 +1611,38 @@ async function runTurn(start, turn) {
|
|
|
1461
1611
|
}, async (...handlerArgs) => {
|
|
1462
1612
|
const [input, extra] = handlerArgs;
|
|
1463
1613
|
const metadataToolCallId = extra._meta?.["claudecode/toolUseId"];
|
|
1464
|
-
const toolCallId =
|
|
1614
|
+
const toolCallId = resolveMcpHandlerToolUseId({
|
|
1615
|
+
state: streamEventState,
|
|
1616
|
+
metadataToolUseId: typeof metadataToolCallId === "string" ? metadataToolCallId : void 0,
|
|
1617
|
+
toolName: tool.name,
|
|
1618
|
+
input
|
|
1619
|
+
}) ?? randomUUID();
|
|
1465
1620
|
streamEventState.mcpHandlerCalls.set(toolCallId, {
|
|
1466
1621
|
toolName: tool.name,
|
|
1467
1622
|
input
|
|
1468
1623
|
});
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1624
|
+
if (!streamEventState.emittedToolCallIds.has(toolCallId)) {
|
|
1625
|
+
streamEventState.emittedToolCallIds.add(toolCallId);
|
|
1626
|
+
emit({
|
|
1627
|
+
type: "tool-call",
|
|
1628
|
+
toolCallId,
|
|
1629
|
+
toolName: tool.name,
|
|
1630
|
+
input: JSON.stringify(input),
|
|
1631
|
+
providerExecuted: false
|
|
1632
|
+
});
|
|
1633
|
+
markWaitingOnHostInput({
|
|
1634
|
+
state: streamEventState,
|
|
1635
|
+
emit,
|
|
1636
|
+
toolUseId: toolCallId
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
const { output, isError, toolResult } = await turn.requestToolResult(toolCallId).finally(() => {
|
|
1640
|
+
clearWaitingOnHostInput({
|
|
1641
|
+
state: streamEventState,
|
|
1642
|
+
toolUseId: toolCallId
|
|
1643
|
+
});
|
|
1644
|
+
if (!streamEventState.mcpToolCalls.has(toolCallId)) streamEventState.pendingStepToolUseIds.delete(toolCallId);
|
|
1475
1645
|
});
|
|
1476
|
-
const { output, isError } = await turn.requestToolResult(toolCallId);
|
|
1477
1646
|
emit({
|
|
1478
1647
|
type: "tool-result",
|
|
1479
1648
|
toolCallId,
|
|
@@ -1481,6 +1650,17 @@ async function runTurn(start, turn) {
|
|
|
1481
1650
|
result: output ?? null,
|
|
1482
1651
|
isError: !!isError
|
|
1483
1652
|
});
|
|
1653
|
+
if (toolResult != null) {
|
|
1654
|
+
const converted = convertHarnessToolModelOutput({ output: toolResult.output });
|
|
1655
|
+
return {
|
|
1656
|
+
content: converted.content.map((part) => part.type === "text" ? part : {
|
|
1657
|
+
type: "image",
|
|
1658
|
+
data: part.data,
|
|
1659
|
+
mimeType: part.mediaType
|
|
1660
|
+
}),
|
|
1661
|
+
isError: isError === true || converted.isError
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1484
1664
|
return {
|
|
1485
1665
|
content: [{
|
|
1486
1666
|
type: "text",
|
|
@@ -1517,20 +1697,32 @@ async function runTurn(start, turn) {
|
|
|
1517
1697
|
inactiveNativeTools,
|
|
1518
1698
|
turn,
|
|
1519
1699
|
emit,
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1700
|
+
markWaitingOnHostInput: (toolUseId) => markWaitingOnHostInput({
|
|
1701
|
+
state: streamEventState,
|
|
1702
|
+
emit,
|
|
1703
|
+
toolUseId
|
|
1704
|
+
}),
|
|
1705
|
+
clearWaitingOnHostInput: (toolUseId) => clearWaitingOnHostInput({
|
|
1706
|
+
state: streamEventState,
|
|
1707
|
+
toolUseId
|
|
1708
|
+
}),
|
|
1527
1709
|
nativeToolCallNames: streamEventState.nativeToolCallNames,
|
|
1528
|
-
approvalRequestedToolUseIds: streamEventState.approvalRequestedToolUseIds
|
|
1710
|
+
approvalRequestedToolUseIds: streamEventState.approvalRequestedToolUseIds,
|
|
1711
|
+
emittedToolCallIds: streamEventState.emittedToolCallIds
|
|
1529
1712
|
});
|
|
1530
1713
|
const questionPreToolUseHook = createQuestionPreToolUseHook({
|
|
1531
1714
|
turn,
|
|
1532
1715
|
emit,
|
|
1533
|
-
nativeToolCallNames: streamEventState.nativeToolCallNames
|
|
1716
|
+
nativeToolCallNames: streamEventState.nativeToolCallNames,
|
|
1717
|
+
markWaitingOnHostInput: (toolUseId) => markWaitingOnHostInput({
|
|
1718
|
+
state: streamEventState,
|
|
1719
|
+
emit,
|
|
1720
|
+
toolUseId
|
|
1721
|
+
}),
|
|
1722
|
+
clearWaitingOnHostInput: (toolUseId) => clearWaitingOnHostInput({
|
|
1723
|
+
state: streamEventState,
|
|
1724
|
+
toolUseId
|
|
1725
|
+
})
|
|
1534
1726
|
});
|
|
1535
1727
|
const q = claudeSdk.query({
|
|
1536
1728
|
prompt: queryInput.input,
|