Sign In

ai

Package Overview
Dependencies
Maintainers
5
Versions
1455
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ai - npm Package Compare versions

Comparing version
6.0.259
to
6.0.260
+7
src/generate-text/is-tool-execution-allowed-finish-reason.ts
import type { FinishReason } from '../types';
export function isToolExecutionAllowedFinishReason(
finishReason: FinishReason,
): boolean {
return finishReason === 'stop' || finishReason === 'tool-calls';
}
+1
-1

@@ -167,3 +167,3 @@ "use strict";

// src/version.ts
var VERSION = true ? "6.0.259" : "0.0.0-test";
var VERSION = true ? "6.0.260" : "0.0.0-test";

@@ -170,0 +170,0 @@ // src/util/download/download.ts

@@ -147,3 +147,3 @@ // internal/index.ts

// src/version.ts
var VERSION = true ? "6.0.259" : "0.0.0-test";
var VERSION = true ? "6.0.260" : "0.0.0-test";

@@ -150,0 +150,0 @@ // src/util/download/download.ts

{
"name": "ai",
"version": "6.0.259",
"version": "6.0.260",
"description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.",

@@ -5,0 +5,0 @@ "license": "Apache-2.0",

@@ -67,2 +67,8 @@ import type {

async function markPromiseAsHandled<T>(promise: Promise<T>): Promise<void> {
try {
await promise;
} catch {}
}
/**

@@ -590,2 +596,3 @@ * Callback that is set using the `onError` option.

let error: unknown | undefined;
let terminalError: { error: unknown } | undefined;

@@ -703,2 +710,15 @@ // pipe chunks through a transformation stream that extracts metadata:

case 'error': {
if (terminalError === undefined) {
const wrappedError = wrapGatewayError(chunk.error);
terminalError = { error: wrappedError };
error = wrappedError;
finishReason = 'error';
self.rejectResultPromises(wrappedError);
}
controller.enqueue(chunk);
break;
}
case 'finish': {

@@ -711,3 +731,6 @@ // send final text delta:

// store finish reason for telemetry:
finishReason = chunk.finishReason.unified;
finishReason =
terminalError === undefined
? chunk.finishReason.unified
: 'error';

@@ -720,3 +743,3 @@ // store usage and metadata for promises and onFinish callback:

...chunk,
finishReason: chunk.finishReason.unified,
finishReason,
usage,

@@ -733,2 +756,6 @@ response: fullResponse,

if (terminalError !== undefined) {
break;
}
// resolve promises that can be resolved now:

@@ -855,6 +882,14 @@ self._usage.resolve(usage);

stitchableStream.addStream(transformedStream);
stitchableStream.addStream(transformedStream, {
onError(error) {
const wrappedError = wrapGatewayError(error);
self.rejectResultPromises(wrappedError);
void onError({ error: wrappedError });
},
});
},
})
.catch(error => {
self.rejectResultPromises(error);
// add an empty stream with an error to break the stream:

@@ -877,2 +912,25 @@ stitchableStream.addStream(

private rejectResultPromises(error: unknown) {
this.rejectResultPromise({ delayedPromise: this._object, error });
this.rejectResultPromise({ delayedPromise: this._usage, error });
this.rejectResultPromise({ delayedPromise: this._providerMetadata, error });
this.rejectResultPromise({ delayedPromise: this._warnings, error });
this.rejectResultPromise({ delayedPromise: this._request, error });
this.rejectResultPromise({ delayedPromise: this._response, error });
this.rejectResultPromise({ delayedPromise: this._finishReason, error });
}
private rejectResultPromise<T>({
delayedPromise,
error,
}: {
delayedPromise: DelayedPromise<T>;
error: unknown;
}) {
if (delayedPromise.isPending()) {
delayedPromise.reject(error);
markPromiseAsHandled(delayedPromise.promise);
}
}
get object() {

@@ -879,0 +937,0 @@ return this._object.promise;

@@ -74,2 +74,3 @@ import type {

import { isApprovalNeeded } from './is-approval-needed';
import { isToolExecutionAllowedFinishReason } from './is-tool-execution-allowed-finish-reason';
import { maybeSignApproval } from './tool-approval-signature';

@@ -1035,3 +1036,8 @@ import { validateApprovedToolApprovals } from './validate-tool-approvals';

if (stepToolSet != null) {
if (
stepToolSet != null &&
isToolExecutionAllowedFinishReason(
currentModelResponse.finishReason.unified,
)
) {
clientToolOutputs.push(

@@ -1038,0 +1044,0 @@ ...(await executeTools({

@@ -31,2 +31,3 @@ import type {

import { isApprovalNeeded } from './is-approval-needed';
import { isToolExecutionAllowedFinishReason } from './is-tool-execution-allowed-finish-reason';
import { maybeSignApproval } from './tool-approval-signature';

@@ -204,2 +205,3 @@ import { parseToolCall } from './parse-tool-call';

const outstandingToolResults = new Set<string>();
const toolCallsToExecute: Array<TypedToolCall<TOOLS>> = [];

@@ -229,2 +231,37 @@ // keep track of parsed tool calls so provider-emitted approval requests can reference them

function executeToolCallAfterFinish(toolCall: TypedToolCall<TOOLS>) {
const toolExecutionId = generateId(); // use our own id to guarantee uniqueness
outstandingToolResults.add(toolExecutionId);
executeToolCall({
toolCall,
tools,
tracer,
telemetry,
messages,
abortSignal,
experimental_context,
stepNumber,
model,
onToolCallStart,
onToolCallFinish,
onPreliminaryToolResult: result => {
enqueueToolResult(result);
},
})
.then(result => {
enqueueToolResult(result);
})
.catch(error => {
enqueueToolResult({
type: 'error',
error,
});
})
.finally(() => {
outstandingToolResults.delete(toolExecutionId);
attemptClose();
});
}
// forward stream

@@ -285,2 +322,11 @@ const forwardStream = new TransformStream<

};
if (isToolExecutionAllowedFinishReason(chunk.finishReason.unified)) {
for (const toolCall of toolCallsToExecute.splice(0)) {
executeToolCallAfterFinish(toolCall);
}
} else {
toolCallsToExecute.length = 0;
}
break;

@@ -322,3 +368,3 @@ }

toolCallsByToolCallId.set(toolCall.toolCallId, toolCall);
controller.enqueue(toolCall);
controller.enqueue({ ...toolCall });

@@ -389,37 +435,3 @@ if (toolCall.invalid) {

if (tool.execute != null && toolCall.providerExecuted !== true) {
const toolExecutionId = generateId(); // use our own id to guarantee uniqueness
outstandingToolResults.add(toolExecutionId);
// Note: we don't await the tool execution here (by leaving out 'await' on recordSpan),
// because we want to process the next chunk as soon as possible.
// This is important for the case where the tool execution takes a long time.
executeToolCall({
toolCall,
tools,
tracer,
telemetry,
messages,
abortSignal,
experimental_context,
stepNumber,
model,
onToolCallStart,
onToolCallFinish,
onPreliminaryToolResult: result => {
enqueueToolResult(result);
},
})
.then(result => {
enqueueToolResult(result);
})
.catch(error => {
enqueueToolResult({
type: 'error',
error,
});
})
.finally(() => {
outstandingToolResults.delete(toolExecutionId);
attemptClose();
});
toolCallsToExecute.push(toolCall);
}

@@ -426,0 +438,0 @@ } catch (error) {

@@ -61,3 +61,3 @@ import {

part.state === 'approval-responded' ||
part.state === 'output-available' ||
(part.state === 'output-available' && part.preliminary !== true) ||
part.state === 'output-error' ||

@@ -64,0 +64,0 @@ part.state === 'output-denied',

@@ -11,7 +11,15 @@ import { createResolvablePromise } from './create-resolvable-promise';

stream: ReadableStream<T>;
addStream: (innerStream: ReadableStream<T>) => void;
addStream: (
innerStream: ReadableStream<T>,
callbacks?: {
onError?: (error: unknown) => void;
},
) => void;
close: () => void;
terminate: () => void;
} {
let innerStreamReaders: ReadableStreamDefaultReader<T>[] = [];
let innerStreams: Array<{
reader: ReadableStreamDefaultReader<T>;
onError?: (error: unknown) => void;
}> = [];
let controller: ReadableStreamDefaultController<T> | null = null;

@@ -25,4 +33,4 @@ let isClosed = false;

innerStreamReaders.forEach(reader => reader.cancel());
innerStreamReaders = [];
innerStreams.forEach(({ reader }) => reader.cancel());
innerStreams = [];
controller?.close();

@@ -33,3 +41,3 @@ };

// Case 1: Outer stream is closed and no more inner streams
if (isClosed && innerStreamReaders.length === 0) {
if (isClosed && innerStreams.length === 0) {
controller?.close();

@@ -41,3 +49,3 @@ return;

// wait for a new inner stream to be added or the outer stream to close
if (innerStreamReaders.length === 0) {
if (innerStreams.length === 0) {
waitForNewStream = createResolvablePromise<void>();

@@ -49,9 +57,9 @@ await waitForNewStream.promise;

try {
const { value, done } = await innerStreamReaders[0].read();
const { value, done } = await innerStreams[0].reader.read();
if (done) {
// Case 3: Current inner stream is done
innerStreamReaders.shift(); // Remove the finished stream
innerStreams.shift(); // Remove the finished stream
if (innerStreamReaders.length === 0 && isClosed) {
if (innerStreams.length === 0 && isClosed) {
// when closed and no more inner streams, stop pulling

@@ -69,4 +77,5 @@ controller?.close();

// Case 5: Current inner stream throws an error
innerStreams[0].onError?.(error);
controller?.error(error);
innerStreamReaders.shift(); // Remove the errored stream
innerStreams.shift(); // Remove the errored stream
terminate(); // we have errored, terminate all streams

@@ -83,10 +92,15 @@ }

async cancel() {
for (const reader of innerStreamReaders) {
for (const { reader } of innerStreams) {
await reader.cancel();
}
innerStreamReaders = [];
innerStreams = [];
isClosed = true;
},
}),
addStream: (innerStream: ReadableStream<T>) => {
addStream: (
innerStream: ReadableStream<T>,
callbacks?: {
onError?: (error: unknown) => void;
},
) => {
if (isClosed) {

@@ -96,3 +110,6 @@ throw new Error('Cannot add inner stream: outer stream is closed');

innerStreamReaders.push(innerStream.getReader());
innerStreams.push({
reader: innerStream.getReader(),
...callbacks,
});
waitForNewStream.resolve();

@@ -109,3 +126,3 @@ },

if (innerStreamReaders.length === 0) {
if (innerStreams.length === 0) {
controller?.close();

@@ -112,0 +129,0 @@ }

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display