@ai-sdk/harness 1.0.142 → 1.0.144

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/harness",
3
- "version": "1.0.142",
3
+ "version": "1.0.144",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -44,9 +44,9 @@
44
44
  }
45
45
  },
46
46
  "dependencies": {
47
- "@ai-sdk/provider": "4.0.24",
48
- "@ai-sdk/provider-utils": "5.0.56",
49
- "ai": "7.0.131"
47
+ "@ai-sdk/provider": "4.0.25",
48
+ "@ai-sdk/provider-utils": "5.0.57",
49
+ "ai": "7.0.133"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "ws": "^8.21.0",
@@ -58,7 +58,7 @@
58
58
  }
59
59
  },
60
60
  "devDependencies": {
61
- "@ai-sdk/otel": "1.0.131",
61
+ "@ai-sdk/otel": "1.0.133",
62
62
  "@opentelemetry/sdk-trace-base": "2.7.1",
63
63
  "@types/node": "22.19.19",
64
64
  "@types/ws": "^8.5.13",
@@ -247,6 +247,14 @@ export class HarnessStreamTextResult<
247
247
  this.fullStreamController.enqueue(part);
248
248
  }
249
249
 
250
+ /**
251
+ * Push adapter-specific raw data to `fullStream` without attributing it to a
252
+ * model step.
253
+ */
254
+ enqueueRaw(rawValue: unknown): void {
255
+ this.fullStreamController.enqueue({ type: 'raw', rawValue });
256
+ }
257
+
250
258
  /**
251
259
  * Drop content replayed while a suspended host-input pause closes its
252
260
  * already-recorded model step.
@@ -33,7 +33,9 @@ import {
33
33
  type LanguageModelV4Usage,
34
34
  } from '@ai-sdk/provider';
35
35
  import {
36
+ addLanguageModelUsage,
36
37
  asLanguageModelUsage,
38
+ createNullLanguageModelUsage,
37
39
  parseToolCall,
38
40
  validateToolContext,
39
41
  } from 'ai/internal';
@@ -342,7 +344,6 @@ export function runPrompt<
342
344
  let pendingStopBoundary:
343
345
  | {
344
346
  finishReason: LanguageModelV4FinishReason;
345
- usage: LanguageModelV4Usage;
346
347
  releaseCheckpoint: (() => void) | undefined;
347
348
  }
348
349
  | undefined;
@@ -866,6 +867,14 @@ export function runPrompt<
866
867
  }
867
868
  if (value == null) continue;
868
869
 
870
+ // `raw` is out-of-band adapter data: it must not open a step (span),
871
+ // become part of one, or trigger a pending stop-condition check, so
872
+ // pass it straight through.
873
+ if (value.type === 'raw') {
874
+ result.enqueueRaw(value.rawValue);
875
+ continue;
876
+ }
877
+
869
878
  if (pendingStopBoundary != null) {
870
879
  if (value.type === 'finish') {
871
880
  releasePendingStopBoundary();
@@ -879,11 +888,13 @@ export function runPrompt<
879
888
  ).some(Boolean)
880
889
  ) {
881
890
  await input.onStopConditionMet?.();
882
- const { usage } = pendingStopBoundary;
883
891
  releasePendingStopBoundary();
884
892
  await lifecycle.end({
885
893
  steps: completedSteps,
886
- usage: asLanguageModelUsage(usage),
894
+ usage: completedSteps.reduce(
895
+ (total, step) => addLanguageModelUsage(total, step.usage),
896
+ createNullLanguageModelUsage(),
897
+ ),
887
898
  });
888
899
  await result.finish();
889
900
  return;
@@ -1046,9 +1057,28 @@ export function runPrompt<
1046
1057
  toolName: value.toolName,
1047
1058
  })
1048
1059
  );
1060
+ /*
1061
+ * An MCP tool named `read` can take different input from a builtin
1062
+ * `read` that is disabled for this session. The builtin's schema
1063
+ * remains in input.tools, so validating a provider-executed dynamic
1064
+ * MCP call against it would reject valid MCP input. Skip that schema
1065
+ * only when no active host tool owns the same name.
1066
+ */
1067
+ const isFilteredBuiltinDynamicCall =
1068
+ displayValue.providerExecuted === true &&
1069
+ displayValue.dynamic === true &&
1070
+ hasTool({
1071
+ tools: input.harness.builtinTools,
1072
+ toolName: displayValue.toolName,
1073
+ }) &&
1074
+ !isHarnessV1BuiltinToolIncluded({
1075
+ toolName: displayValue.toolName,
1076
+ toolFiltering: input.builtinToolFiltering,
1077
+ }) &&
1078
+ !hasTool({ tools: activeTools, toolName: displayValue.toolName });
1049
1079
  const parsed = await validateToolCall<TOOLS>({
1050
1080
  event: isHostTool ? value : displayValue,
1051
- tools: input.tools,
1081
+ tools: isFilteredBuiltinDynamicCall ? undefined : input.tools,
1052
1082
  });
1053
1083
  const parsedToolCall = asToolCallTextStreamPart({ part: parsed });
1054
1084
  validatedHostToolCall = isHostTool ? parsedToolCall : undefined;
@@ -1186,7 +1216,6 @@ export function runPrompt<
1186
1216
  if (input.stopConditions != null && input.stopConditions.length > 0) {
1187
1217
  pendingStopBoundary = {
1188
1218
  finishReason: value.finishReason,
1189
- usage: value.usage,
1190
1219
  releaseCheckpoint: pinSandboxChannelEventCheckpoint(value),
1191
1220
  };
1192
1221
  }
@@ -1692,7 +1721,7 @@ async function maybeExecuteHostTool<TOOLS extends ToolSet>(input: {
1692
1721
  */
1693
1722
  export async function validateToolCall<TOOLS extends ToolSet>(args: {
1694
1723
  event: Extract<HarnessV1StreamPart, { type: 'tool-call' }>;
1695
- tools: TOOLS;
1724
+ tools: TOOLS | undefined;
1696
1725
  }): Promise<TextStreamPart<TOOLS>> {
1697
1726
  const { event, tools } = args;
1698
1727
  const toolCall: LanguageModelV4ToolCall = {