@ai-sdk/harness 1.0.70 → 1.0.71

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,15 @@
1
1
  # @ai-sdk/harness
2
2
 
3
+ ## 1.0.71
4
+
5
+ ### Patch Changes
6
+
7
+ - 8d717b3: Execute independent host tool calls concurrently within a harness step.
8
+ - Updated dependencies [dc8caae]
9
+ - Updated dependencies [72ec74f]
10
+ - Updated dependencies [c5b0515]
11
+ - ai@7.0.65
12
+
3
13
  ## 1.0.70
4
14
 
5
15
  ### Patch Changes
@@ -1476,6 +1476,23 @@ function runPrompt(input) {
1476
1476
  let pendingStopBoundary;
1477
1477
  let finalFinish;
1478
1478
  const completedSteps = [];
1479
+ const outstandingHostToolExecutions = [];
1480
+ const startHostToolExecution = (execution) => {
1481
+ outstandingHostToolExecutions.push(execution);
1482
+ void execution.catch(() => {
1483
+ });
1484
+ };
1485
+ const waitForOutstandingHostToolExecutions = async () => {
1486
+ if (outstandingHostToolExecutions.length === 0) return;
1487
+ const executions = outstandingHostToolExecutions.splice(0);
1488
+ const results = await Promise.allSettled(executions);
1489
+ const failedExecution = results.find(
1490
+ (result2) => result2.status === "rejected"
1491
+ );
1492
+ if (failedExecution != null) {
1493
+ throw failedExecution.reason;
1494
+ }
1495
+ };
1479
1496
  const releasePendingStopBoundary = () => {
1480
1497
  var _a6;
1481
1498
  (_a6 = pendingStopBoundary == null ? void 0 : pendingStopBoundary.releaseCheckpoint) == null ? void 0 : _a6.call(pendingStopBoundary);
@@ -1531,6 +1548,7 @@ function runPrompt(input) {
1531
1548
  return step;
1532
1549
  };
1533
1550
  const finishForHostInputPause = async (options) => {
1551
+ await waitForOutstandingHostToolExecutions();
1534
1552
  if (options.completeCurrentStep) {
1535
1553
  await completeStep({
1536
1554
  finishReason: toolCallsFinishReason,
@@ -1799,6 +1817,7 @@ function runPrompt(input) {
1799
1817
  }
1800
1818
  }
1801
1819
  if (value.type === "error" && displayValue.type === "error") {
1820
+ await waitForOutstandingHostToolExecutions();
1802
1821
  await telemetry.error(value.error);
1803
1822
  logBridgeError({
1804
1823
  harnessId: input.harness.harnessId,
@@ -1892,6 +1911,7 @@ function runPrompt(input) {
1892
1911
  return;
1893
1912
  }
1894
1913
  if (value.type === "finish-step") {
1914
+ await waitForOutstandingHostToolExecutions();
1895
1915
  await completeStep({
1896
1916
  finishReason: value.finishReason,
1897
1917
  usage: value.usage,
@@ -1906,6 +1926,7 @@ function runPrompt(input) {
1906
1926
  }
1907
1927
  }
1908
1928
  if (value.type === "finish") {
1929
+ await waitForOutstandingHostToolExecutions();
1909
1930
  finalFinish = value;
1910
1931
  await telemetry.end({
1911
1932
  finishReason: value.finishReason,
@@ -2009,41 +2030,51 @@ function runPrompt(input) {
2009
2030
  await finishForHostInputPause({ completeCurrentStep: true });
2010
2031
  return;
2011
2032
  }
2012
- const execution = await maybeExecuteHostTool({
2013
- event: toolCall,
2014
- tools: activeTools,
2015
- wrappedExecuteTool: telemetry.executeTool,
2016
- sandboxSession: input.sandboxSession,
2017
- abortSignal: input.abortSignal,
2018
- control,
2019
- onPreliminaryResult: (preliminaryOutput) => {
2020
- const stripped = stripWorkDir(
2021
- {
2022
- type: "tool-result",
2023
- toolCallId: toolCall.toolCallId,
2024
- toolName: toolCall.toolName,
2025
- result: preliminaryOutput
2026
- },
2027
- input.sessionWorkDir
2028
- );
2029
- result.enqueue({
2030
- type: "tool-result",
2031
- toolCallId: toolCall.toolCallId,
2032
- toolName: toolCall.toolName,
2033
- input: void 0,
2034
- output: stripped.result,
2035
- preliminary: true
2036
- });
2037
- }
2038
- });
2039
- if (!execution.executed) {
2033
+ if (!isExecutableTool(activeTools[toolCall.toolName])) {
2040
2034
  recordPendingToolResult({ toolCall });
2041
2035
  await finishForHostInputPause({ completeCurrentStep: true });
2042
2036
  return;
2043
2037
  }
2044
- await telemetry.toolEnd(toolCall.toolCallId, execution.outcome);
2038
+ startHostToolExecution(
2039
+ (async () => {
2040
+ const execution = await maybeExecuteHostTool({
2041
+ event: toolCall,
2042
+ tools: activeTools,
2043
+ wrappedExecuteTool: telemetry.executeTool,
2044
+ sandboxSession: input.sandboxSession,
2045
+ abortSignal: input.abortSignal,
2046
+ control,
2047
+ onPreliminaryResult: (preliminaryOutput) => {
2048
+ const stripped = stripWorkDir(
2049
+ {
2050
+ type: "tool-result",
2051
+ toolCallId: toolCall.toolCallId,
2052
+ toolName: toolCall.toolName,
2053
+ result: preliminaryOutput
2054
+ },
2055
+ input.sessionWorkDir
2056
+ );
2057
+ result.enqueue({
2058
+ type: "tool-result",
2059
+ toolCallId: toolCall.toolCallId,
2060
+ toolName: toolCall.toolName,
2061
+ input: void 0,
2062
+ output: stripped.result,
2063
+ preliminary: true
2064
+ });
2065
+ }
2066
+ });
2067
+ if (!execution.executed) {
2068
+ throw new Error(
2069
+ `Harness '${input.harness.harnessId}' could not execute host tool '${toolCall.toolName}'.`
2070
+ );
2071
+ }
2072
+ await telemetry.toolEnd(toolCall.toolCallId, execution.outcome);
2073
+ })()
2074
+ );
2045
2075
  }
2046
2076
  }
2077
+ await waitForOutstandingHostToolExecutions();
2047
2078
  const isTurnSuspending = ((_j = input.isTurnSuspending) == null ? void 0 : _j.call(input)) === true;
2048
2079
  if (isTurnSuspending) {
2049
2080
  if (finalFinish == null) {
@@ -2062,6 +2093,10 @@ function runPrompt(input) {
2062
2093
  } : void 0
2063
2094
  );
2064
2095
  } catch (err) {
2096
+ try {
2097
+ await waitForOutstandingHostToolExecutions();
2098
+ } catch (e) {
2099
+ }
2065
2100
  await telemetry.error(err);
2066
2101
  logBridgeError({
2067
2102
  harnessId: input.harness.harnessId,