@ai-sdk/harness-claude-code 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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # @ai-sdk/harness-claude-code
2
2
 
3
+ ## 1.0.151
4
+
5
+ ### Patch Changes
6
+
7
+ - c357e52: chore(harness): update primary harness SDKs to their latest versions
8
+ - @ai-sdk/harness@1.0.147
9
+
10
+ ## 1.0.150
11
+
12
+ ### Patch Changes
13
+
14
+ - 0887035: fix(harness-claude-code): close compaction events emitted outside a model step
15
+ - 714f3fc: fix(harness-claude-code): report host tool calls rejected by MCP input validation
16
+ - Updated dependencies [4dbc902]
17
+ - @ai-sdk/provider@4.0.26
18
+ - @ai-sdk/harness@1.0.146
19
+ - @ai-sdk/provider-utils@5.0.58
20
+
3
21
  ## 1.0.149
4
22
 
5
23
  ### Patch Changes
@@ -5,6 +5,7 @@ import { argv, env, pid, stdout } from "node:process";
5
5
  import { WebSocketServer } from "ws";
6
6
  import * as claudeAgentSdk from "@anthropic-ai/claude-agent-sdk";
7
7
  import * as mcpServerModule from "@modelcontextprotocol/sdk/server/mcp.js";
8
+ import { isDeepStrictEqual } from "node:util";
8
9
  import { z } from "zod/v4";
9
10
  //#region ../harness/dist/bridge/index.js
10
11
  const DEBUG_LEVEL_WEIGHT = {
@@ -632,7 +633,8 @@ function createClaudeStreamEventState() {
632
633
  pendingStepUsage: void 0,
633
634
  pendingResponseUsage: void 0,
634
635
  stepOpen: false,
635
- mcpToolUseIds: /* @__PURE__ */ new Set(),
636
+ mcpToolCalls: /* @__PURE__ */ new Map(),
637
+ mcpHandlerCalls: /* @__PURE__ */ new Map(),
636
638
  externalMcpToolUseIds: /* @__PURE__ */ new Set(),
637
639
  structuredOutputToolUseIds: /* @__PURE__ */ new Set(),
638
640
  observedTerminalError: void 0
@@ -729,7 +731,10 @@ function createEmitStreamEvent({ state, emit, emitWarning, emitTerminalError, on
729
731
  }
730
732
  if (block.name.startsWith(HOST_TOOL_PREFIX)) {
731
733
  state.pendingStepToolUseIds.add(block.id);
732
- state.mcpToolUseIds.add(block.id);
734
+ state.mcpToolCalls.set(block.id, {
735
+ toolName: block.name.slice(20),
736
+ input: block.input ?? {}
737
+ });
733
738
  opensStep = true;
734
739
  continue;
735
740
  }
@@ -767,9 +772,37 @@ function createEmitStreamEvent({ state, emit, emitWarning, emitTerminalError, on
767
772
  const toolUseResult = messageContent.filter((block) => block.type === "tool_result").length === 1 ? msg.tool_use_result : void 0;
768
773
  for (const block of messageContent) if (block.type === "tool_result" && typeof block.tool_use_id === "string") {
769
774
  if (state.structuredOutputToolUseIds.delete(block.tool_use_id)) continue;
770
- if (state.mcpToolUseIds.has(block.tool_use_id)) {
771
- state.mcpToolUseIds.delete(block.tool_use_id);
775
+ const mcpToolCall = state.mcpToolCalls.get(block.tool_use_id);
776
+ if (mcpToolCall != null) {
777
+ const handlerReportedCall = takeMcpHandlerCall({
778
+ state,
779
+ toolCallId: block.tool_use_id,
780
+ toolCall: mcpToolCall
781
+ });
782
+ state.mcpToolCalls.delete(block.tool_use_id);
772
783
  state.pendingStepToolUseIds.delete(block.tool_use_id);
784
+ if (handlerReportedCall) continue;
785
+ const isError = !!block.is_error;
786
+ const result = toolUseResult !== void 0 ? toolUseResult : resolveToolResult({
787
+ toolName: mcpToolCall.toolName,
788
+ dynamic: false,
789
+ isError,
790
+ rawContent: block.content
791
+ });
792
+ emit({
793
+ type: "tool-call",
794
+ toolCallId: block.tool_use_id,
795
+ toolName: mcpToolCall.toolName,
796
+ input: JSON.stringify(mcpToolCall.input),
797
+ providerExecuted: true
798
+ });
799
+ emit({
800
+ type: "tool-result",
801
+ toolCallId: block.tool_use_id,
802
+ toolName: mcpToolCall.toolName,
803
+ result,
804
+ isError
805
+ });
773
806
  continue;
774
807
  }
775
808
  state.approvalRequestedToolUseIds.delete(block.tool_use_id);
@@ -801,6 +834,20 @@ function createEmitStreamEvent({ state, emit, emitWarning, emitTerminalError, on
801
834
  }
802
835
  };
803
836
  }
837
+ function takeMcpHandlerCall({ state, toolCallId, toolCall }) {
838
+ if (state.mcpHandlerCalls.delete(toolCallId)) return true;
839
+ for (const [handlerCallId, handlerCall] of state.mcpHandlerCalls) if (handlerCall.toolName === toolCall.toolName && isDeepStrictEqual(handlerCall.input, toolCall.input)) {
840
+ state.mcpHandlerCalls.delete(handlerCallId);
841
+ return true;
842
+ }
843
+ const matchingHandlerCallIds = Array.from(state.mcpHandlerCalls).filter(([, handlerCall]) => handlerCall.toolName === toolCall.toolName).map(([handlerCallId]) => handlerCallId);
844
+ 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
+ }
849
+ return false;
850
+ }
804
851
  function finishApprovalStep({ state, emit, approvalId }) {
805
852
  state.stepOpen = true;
806
853
  state.pendingStepToolUseIds.delete(approvalId);
@@ -1414,6 +1461,10 @@ async function runTurn(start, turn) {
1414
1461
  const [input, extra] = handlerArgs;
1415
1462
  const metadataToolCallId = extra._meta?.["claudecode/toolUseId"];
1416
1463
  const toolCallId = typeof metadataToolCallId === "string" ? metadataToolCallId : randomUUID();
1464
+ streamEventState.mcpHandlerCalls.set(toolCallId, {
1465
+ toolName: tool.name,
1466
+ input
1467
+ });
1417
1468
  emit({
1418
1469
  type: "tool-call",
1419
1470
  toolCallId,
@@ -1443,7 +1494,15 @@ async function runTurn(start, turn) {
1443
1494
  instance: server
1444
1495
  };
1445
1496
  }
1446
- const compaction = createCompactionLatch((event) => emit(event));
1497
+ const compaction = createCompactionLatch((event) => {
1498
+ const hasOpenStep = streamEventState.stepOpen;
1499
+ emit(event);
1500
+ if (!hasOpenStep) emitFinishStep({
1501
+ state: streamEventState,
1502
+ emit,
1503
+ usage: void 0
1504
+ });
1505
+ });
1447
1506
  const queryInput = createQueryInput({
1448
1507
  initialUserMessage: start.prompt,
1449
1508
  userMessages: turn.experimental_userMessages,