@ai-sdk/harness 1.0.166 → 1.0.168

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,26 @@
1
1
  # @ai-sdk/harness
2
2
 
3
+ ## 1.0.168
4
+
5
+ ### Patch Changes
6
+
7
+ - 033f8d9: fix(harness): preserve execution-denied outputs for denied host tool calls without invoking the tool's `toModelOutput` converter
8
+ - e7a8988: fix(harness): preserve differing runtime-native tool names in `providerMetadata[harnessId].nativeToolName` on tool calls and their approval requests
9
+ - 2c12e25: fix(harness): fix completed host tool results being silently lost when a WebSocket enters CLOSING before the channel detects the disconnect
10
+ - 6eab0f7: Fix turns hanging when a built-in tool approval and a host tool call share an assistant message. Pause for the approval without waiting for runtime echoes of completed host tools, preserving their results and original call metadata across consecutive approval pauses and session resumes until the runtime echo arrives, without executing them again or emitting duplicate results.
11
+ - Updated dependencies [0cc4921]
12
+ - Updated dependencies [61a315e]
13
+ - Updated dependencies [077cfb3]
14
+ - Updated dependencies [eb768e2]
15
+ - ai@7.0.157
16
+ - @ai-sdk/provider-utils@5.0.71
17
+
18
+ ## 1.0.167
19
+
20
+ ### Patch Changes
21
+
22
+ - ai@7.0.156
23
+
3
24
  ## 1.0.166
4
25
 
5
26
  ### Patch Changes
@@ -1744,6 +1744,7 @@ function runPrompt(input) {
1744
1744
  let deferredPauseFinishStep;
1745
1745
  let ignoredFinishStep;
1746
1746
  const hostToolCallIdsAwaitingEcho = /* @__PURE__ */ new Set();
1747
+ const submittedHostToolResults = /* @__PURE__ */ new Map();
1747
1748
  const buildModelCallContent = () => {
1748
1749
  const parts = [];
1749
1750
  if (stepText) parts.push({
@@ -1815,6 +1816,34 @@ function runPrompt(input) {
1815
1816
  };
1816
1817
  const pauseForHostInput = async (finishStep) => {
1817
1818
  await waitForOutstandingHostToolExecutions();
1819
+ for (const submission of submittedHostToolResults.values()) {
1820
+ const { toolCallId, ...completedResult } = submission;
1821
+ const rawToolCall = rawToolCallsByToolCallId.get(toolCallId);
1822
+ const toolCall = toolCallsByToolCallId.get(toolCallId);
1823
+ const pendingResult = pendingResultsByToolCallId.get(toolCallId) ?? (rawToolCall == null ? void 0 : {
1824
+ toolCallId,
1825
+ toolName: rawToolCall.toolName,
1826
+ input: rawToolCall.input,
1827
+ ...rawToolCall.providerMetadata !== void 0 ? { providerOptions: rawToolCall.providerMetadata } : {}
1828
+ });
1829
+ if (pendingResult == null) continue;
1830
+ onPendingToolResult({
1831
+ ...pendingResult,
1832
+ completedResult
1833
+ });
1834
+ const toolOutput = toolExecutions.get(toolCallId)?.toolOutput;
1835
+ if (toolCall != null && toolOutput != null && !settledHostToolCallIds.has(toolCallId)) enqueueHostToolOutcome({
1836
+ toolCall,
1837
+ outcome: toolOutput.type === "tool-error" ? {
1838
+ ok: false,
1839
+ error: toolOutput.error
1840
+ } : {
1841
+ ok: true,
1842
+ output: toolOutput.output
1843
+ },
1844
+ isContinuation: false
1845
+ });
1846
+ }
1818
1847
  closingResumedStep = false;
1819
1848
  await completeStep({
1820
1849
  finishReason: toolCallsFinishReason,
@@ -1865,6 +1894,10 @@ function runPrompt(input) {
1865
1894
  return pendingResult;
1866
1895
  };
1867
1896
  const enqueueHostToolOutcome = (options) => {
1897
+ const enqueue = (part) => {
1898
+ if (options.isContinuation === false) result.enqueue(part);
1899
+ else result.enqueueContinuation(part);
1900
+ };
1868
1901
  if (options.outcome.ok) {
1869
1902
  const stripped = stripWorkDir({
1870
1903
  type: "tool-result",
@@ -1872,7 +1905,7 @@ function runPrompt(input) {
1872
1905
  toolName: options.toolCall.toolName,
1873
1906
  result: options.outcome.output
1874
1907
  }, input.sessionWorkDir);
1875
- result.enqueueContinuation({
1908
+ enqueue({
1876
1909
  type: "tool-result",
1877
1910
  toolCallId: options.toolCall.toolCallId,
1878
1911
  toolName: options.toolCall.toolName,
@@ -1881,7 +1914,7 @@ function runPrompt(input) {
1881
1914
  });
1882
1915
  return;
1883
1916
  }
1884
- result.enqueueContinuation({
1917
+ enqueue({
1885
1918
  type: "tool-error",
1886
1919
  toolCallId: options.toolCall.toolCallId,
1887
1920
  toolName: options.toolCall.toolName,
@@ -1915,6 +1948,7 @@ function runPrompt(input) {
1915
1948
  }
1916
1949
  if (!input.isTurnSuspending?.()) {
1917
1950
  if (!settledHostToolCallIds.has(submission.toolCallId)) hostToolCallIdsAwaitingEcho.add(submission.toolCallId);
1951
+ submittedHostToolResults.set(submission.toolCallId, submission);
1918
1952
  return control.submitToolResult(submission);
1919
1953
  }
1920
1954
  const toolCall = rawToolCallsByToolCallId.get(submission.toolCallId) ?? pendingResultsByToolCallId.get(submission.toolCallId) ?? pendingToolApprovals.find((approval) => approval.toolCallId === submission.toolCallId);
@@ -1954,7 +1988,6 @@ function runPrompt(input) {
1954
1988
  toolCallId: pendingResult.toolCallId,
1955
1989
  ...submission
1956
1990
  });
1957
- pendingResultsByToolCallId.delete(pendingResult.toolCallId);
1958
1991
  };
1959
1992
  const processPendingApprovalContinuation = async (approval, continuation) => {
1960
1993
  const rawToolCall = (approval.kind === "builtin" ? rawToolCallsByToolCallId.get(approval.toolCallId) : void 0) ?? {
@@ -1970,7 +2003,8 @@ function runPrompt(input) {
1970
2003
  if (approval.kind === "custom" && continuation.approved) {
1971
2004
  validatedToolCall = asToolCallTextStreamPart({ part: await validateToolCall({
1972
2005
  event: rawToolCall,
1973
- tools: input.tools
2006
+ tools: input.tools,
2007
+ harnessId: input.harness.harnessId
1974
2008
  }) });
1975
2009
  toolCall = displayHostToolCall({
1976
2010
  toolCall: validatedToolCall,
@@ -2002,11 +2036,18 @@ function runPrompt(input) {
2002
2036
  }
2003
2037
  settledHostToolCallIds.add(approval.toolCallId);
2004
2038
  if (!continuation.approved) {
2039
+ const output = {
2040
+ type: "execution-denied",
2041
+ reason: continuation.reason
2042
+ };
2005
2043
  await submitToolResult({
2006
2044
  toolCallId: approval.toolCallId,
2007
- output: {
2008
- type: "execution-denied",
2009
- reason: continuation.reason
2045
+ output,
2046
+ toolResult: {
2047
+ type: "tool-result",
2048
+ toolCallId: approval.toolCallId,
2049
+ toolName: approval.toolName,
2050
+ output
2010
2051
  }
2011
2052
  });
2012
2053
  return "continued";
@@ -2109,7 +2150,11 @@ function runPrompt(input) {
2109
2150
  result.enqueueRaw(value.rawValue);
2110
2151
  continue;
2111
2152
  }
2112
- if (value.type === "tool-result") hostToolCallIdsAwaitingEcho.delete(value.toolCallId);
2153
+ if (value.type === "tool-result") {
2154
+ hostToolCallIdsAwaitingEcho.delete(value.toolCallId);
2155
+ submittedHostToolResults.delete(value.toolCallId);
2156
+ pendingResultsByToolCallId.delete(value.toolCallId);
2157
+ }
2113
2158
  if (pendingStopBoundary != null) {
2114
2159
  if (value.type === "finish") releasePendingStopBoundary();
2115
2160
  else if ((await Promise.all(input.stopConditions.map((condition) => condition({ steps: completedSteps })))).some(Boolean)) {
@@ -2142,7 +2187,7 @@ function runPrompt(input) {
2142
2187
  if (value.type === "finish-step") {
2143
2188
  if (hostInputPauseRequested) {
2144
2189
  await waitForOutstandingHostToolExecutions();
2145
- if (hostToolCallIdsAwaitingEcho.size === 0) {
2190
+ if (hostToolCallIdsAwaitingEcho.size === 0 || [...pendingApprovalsByApprovalId.values()].some((approval) => approval.kind === "builtin")) {
2146
2191
  await pauseForHostInput(value);
2147
2192
  return;
2148
2193
  }
@@ -2236,7 +2281,8 @@ function runPrompt(input) {
2236
2281
  });
2237
2282
  const parsedToolCall = asToolCallTextStreamPart({ part: await validateToolCall({
2238
2283
  event: isHostTool ? value : displayValue,
2239
- tools: isFilteredBuiltinDynamicCall ? void 0 : input.tools
2284
+ tools: isFilteredBuiltinDynamicCall ? void 0 : input.tools,
2285
+ harnessId: input.harness.harnessId
2240
2286
  }) });
2241
2287
  validatedHostToolCall = isHostTool ? parsedToolCall : void 0;
2242
2288
  const displayToolCall = isHostTool ? displayHostToolCall({
@@ -2338,7 +2384,13 @@ function runPrompt(input) {
2338
2384
  };
2339
2385
  await submitToolResult({
2340
2386
  toolCallId: toolCall.toolCallId,
2341
- output
2387
+ output,
2388
+ toolResult: {
2389
+ type: "tool-result",
2390
+ toolCallId: toolCall.toolCallId,
2391
+ toolName: toolCall.toolName,
2392
+ output
2393
+ }
2342
2394
  });
2343
2395
  const execution = toolExecutions.get(toolCall.toolCallId);
2344
2396
  if (execution != null) execution.toolOutput = toToolOutput({
@@ -2402,7 +2454,13 @@ function runPrompt(input) {
2402
2454
  if (execution != null) await publishToolExecutionStart(execution);
2403
2455
  await submitToolResult({
2404
2456
  toolCallId: toolCall.toolCallId,
2405
- output
2457
+ output,
2458
+ toolResult: {
2459
+ type: "tool-result",
2460
+ toolCallId: toolCall.toolCallId,
2461
+ toolName: toolCall.toolName,
2462
+ output
2463
+ }
2406
2464
  });
2407
2465
  if (execution != null) {
2408
2466
  execution.toolOutput = toToolOutput({
@@ -2657,7 +2715,14 @@ async function maybeExecuteHostTool(input) {
2657
2715
  }
2658
2716
  }
2659
2717
  async function validateToolCall(args) {
2660
- const { event, tools } = args;
2718
+ const { event, tools, harnessId } = args;
2719
+ const providerMetadata = event.nativeName !== void 0 && event.nativeName !== event.toolName ? {
2720
+ ...event.providerMetadata,
2721
+ [harnessId]: {
2722
+ ...event.providerMetadata?.[harnessId],
2723
+ nativeToolName: event.nativeName
2724
+ }
2725
+ } : event.providerMetadata;
2661
2726
  const toolCall = {
2662
2727
  type: "tool-call",
2663
2728
  toolCallId: event.toolCallId,
@@ -2665,7 +2730,7 @@ async function validateToolCall(args) {
2665
2730
  input: event.input,
2666
2731
  ...event.providerExecuted !== void 0 ? { providerExecuted: event.providerExecuted } : {},
2667
2732
  ...event.dynamic !== void 0 ? { dynamic: event.dynamic } : {},
2668
- ...event.providerMetadata !== void 0 ? { providerMetadata: event.providerMetadata } : {}
2733
+ ...providerMetadata !== void 0 ? { providerMetadata } : {}
2669
2734
  };
2670
2735
  return await parseToolCall({
2671
2736
  toolCall,