9938 lines
309 KiB
JavaScript
9938 lines
309 KiB
JavaScript
"use strict";
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __export = (target, all) => {
|
|
for (var name17 in all)
|
|
__defProp(target, name17, { get: all[name17], enumerable: true });
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
|
|
// src/index.ts
|
|
var src_exports = {};
|
|
__export(src_exports, {
|
|
AISDKError: () => import_provider17.AISDKError,
|
|
APICallError: () => import_provider17.APICallError,
|
|
AbstractChat: () => AbstractChat,
|
|
DefaultChatTransport: () => DefaultChatTransport,
|
|
DownloadError: () => DownloadError,
|
|
EmptyResponseBodyError: () => import_provider17.EmptyResponseBodyError,
|
|
Experimental_Agent: () => Agent,
|
|
HttpChatTransport: () => HttpChatTransport,
|
|
InvalidArgumentError: () => InvalidArgumentError,
|
|
InvalidDataContentError: () => InvalidDataContentError,
|
|
InvalidMessageRoleError: () => InvalidMessageRoleError,
|
|
InvalidPromptError: () => import_provider17.InvalidPromptError,
|
|
InvalidResponseDataError: () => import_provider17.InvalidResponseDataError,
|
|
InvalidStreamPartError: () => InvalidStreamPartError,
|
|
InvalidToolInputError: () => InvalidToolInputError,
|
|
JSONParseError: () => import_provider17.JSONParseError,
|
|
JsonToSseTransformStream: () => JsonToSseTransformStream,
|
|
LoadAPIKeyError: () => import_provider17.LoadAPIKeyError,
|
|
MCPClientError: () => MCPClientError,
|
|
MessageConversionError: () => MessageConversionError,
|
|
NoContentGeneratedError: () => import_provider17.NoContentGeneratedError,
|
|
NoImageGeneratedError: () => NoImageGeneratedError,
|
|
NoObjectGeneratedError: () => NoObjectGeneratedError,
|
|
NoOutputGeneratedError: () => NoOutputGeneratedError,
|
|
NoOutputSpecifiedError: () => NoOutputSpecifiedError,
|
|
NoSuchModelError: () => import_provider17.NoSuchModelError,
|
|
NoSuchProviderError: () => NoSuchProviderError,
|
|
NoSuchToolError: () => NoSuchToolError,
|
|
Output: () => output_exports,
|
|
RetryError: () => RetryError,
|
|
SerialJobExecutor: () => SerialJobExecutor,
|
|
TextStreamChatTransport: () => TextStreamChatTransport,
|
|
ToolCallRepairError: () => ToolCallRepairError,
|
|
TypeValidationError: () => import_provider17.TypeValidationError,
|
|
UI_MESSAGE_STREAM_HEADERS: () => UI_MESSAGE_STREAM_HEADERS,
|
|
UnsupportedFunctionalityError: () => import_provider17.UnsupportedFunctionalityError,
|
|
UnsupportedModelVersionError: () => UnsupportedModelVersionError,
|
|
asSchema: () => import_provider_utils28.asSchema,
|
|
assistantModelMessageSchema: () => assistantModelMessageSchema,
|
|
callCompletionApi: () => callCompletionApi,
|
|
consumeStream: () => consumeStream,
|
|
convertFileListToFileUIParts: () => convertFileListToFileUIParts,
|
|
convertToCoreMessages: () => convertToCoreMessages,
|
|
convertToModelMessages: () => convertToModelMessages,
|
|
coreAssistantMessageSchema: () => coreAssistantMessageSchema,
|
|
coreMessageSchema: () => coreMessageSchema,
|
|
coreSystemMessageSchema: () => coreSystemMessageSchema,
|
|
coreToolMessageSchema: () => coreToolMessageSchema,
|
|
coreUserMessageSchema: () => coreUserMessageSchema,
|
|
cosineSimilarity: () => cosineSimilarity,
|
|
createIdGenerator: () => import_provider_utils28.createIdGenerator,
|
|
createProviderRegistry: () => createProviderRegistry,
|
|
createTextStreamResponse: () => createTextStreamResponse,
|
|
createUIMessageStream: () => createUIMessageStream,
|
|
createUIMessageStreamResponse: () => createUIMessageStreamResponse,
|
|
customProvider: () => customProvider,
|
|
defaultSettingsMiddleware: () => defaultSettingsMiddleware,
|
|
dynamicTool: () => import_provider_utils28.dynamicTool,
|
|
embed: () => embed,
|
|
embedMany: () => embedMany,
|
|
experimental_createMCPClient: () => createMCPClient,
|
|
experimental_createProviderRegistry: () => experimental_createProviderRegistry,
|
|
experimental_customProvider: () => experimental_customProvider,
|
|
experimental_generateImage: () => generateImage,
|
|
experimental_generateSpeech: () => generateSpeech,
|
|
experimental_transcribe: () => transcribe,
|
|
extractReasoningMiddleware: () => extractReasoningMiddleware,
|
|
generateId: () => import_provider_utils28.generateId,
|
|
generateObject: () => generateObject,
|
|
generateText: () => generateText,
|
|
getTextFromDataUrl: () => getTextFromDataUrl,
|
|
getToolName: () => getToolName,
|
|
hasToolCall: () => hasToolCall,
|
|
isDeepEqualData: () => isDeepEqualData,
|
|
isToolUIPart: () => isToolUIPart,
|
|
jsonSchema: () => import_provider_utils28.jsonSchema,
|
|
lastAssistantMessageIsCompleteWithToolCalls: () => lastAssistantMessageIsCompleteWithToolCalls,
|
|
modelMessageSchema: () => modelMessageSchema,
|
|
parsePartialJson: () => parsePartialJson,
|
|
pipeTextStreamToResponse: () => pipeTextStreamToResponse,
|
|
pipeUIMessageStreamToResponse: () => pipeUIMessageStreamToResponse,
|
|
readUIMessageStream: () => readUIMessageStream,
|
|
simulateReadableStream: () => simulateReadableStream,
|
|
simulateStreamingMiddleware: () => simulateStreamingMiddleware,
|
|
smoothStream: () => smoothStream,
|
|
stepCountIs: () => stepCountIs,
|
|
streamObject: () => streamObject,
|
|
streamText: () => streamText,
|
|
systemModelMessageSchema: () => systemModelMessageSchema,
|
|
tool: () => import_provider_utils28.tool,
|
|
toolModelMessageSchema: () => toolModelMessageSchema,
|
|
userModelMessageSchema: () => userModelMessageSchema,
|
|
wrapLanguageModel: () => wrapLanguageModel,
|
|
wrapProvider: () => wrapProvider,
|
|
zodSchema: () => import_provider_utils28.zodSchema
|
|
});
|
|
module.exports = __toCommonJS(src_exports);
|
|
var import_provider_utils28 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/generate-text/generate-text.ts
|
|
var import_provider_utils9 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/error/no-output-specified-error.ts
|
|
var import_provider = require("@ai-sdk/provider");
|
|
var name = "AI_NoOutputSpecifiedError";
|
|
var marker = `vercel.ai.error.${name}`;
|
|
var symbol = Symbol.for(marker);
|
|
var _a;
|
|
var NoOutputSpecifiedError = class extends import_provider.AISDKError {
|
|
// used in isInstance
|
|
constructor({ message = "No output specified." } = {}) {
|
|
super({ name, message });
|
|
this[_a] = true;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider.AISDKError.hasMarker(error, marker);
|
|
}
|
|
};
|
|
_a = symbol;
|
|
|
|
// src/model/resolve-model.ts
|
|
var import_gateway = require("@ai-sdk/gateway");
|
|
|
|
// src/error/index.ts
|
|
var import_provider17 = require("@ai-sdk/provider");
|
|
|
|
// src/error/invalid-argument-error.ts
|
|
var import_provider2 = require("@ai-sdk/provider");
|
|
var name2 = "AI_InvalidArgumentError";
|
|
var marker2 = `vercel.ai.error.${name2}`;
|
|
var symbol2 = Symbol.for(marker2);
|
|
var _a2;
|
|
var InvalidArgumentError = class extends import_provider2.AISDKError {
|
|
constructor({
|
|
parameter,
|
|
value,
|
|
message
|
|
}) {
|
|
super({
|
|
name: name2,
|
|
message: `Invalid argument for parameter ${parameter}: ${message}`
|
|
});
|
|
this[_a2] = true;
|
|
this.parameter = parameter;
|
|
this.value = value;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider2.AISDKError.hasMarker(error, marker2);
|
|
}
|
|
};
|
|
_a2 = symbol2;
|
|
|
|
// src/error/invalid-stream-part-error.ts
|
|
var import_provider3 = require("@ai-sdk/provider");
|
|
var name3 = "AI_InvalidStreamPartError";
|
|
var marker3 = `vercel.ai.error.${name3}`;
|
|
var symbol3 = Symbol.for(marker3);
|
|
var _a3;
|
|
var InvalidStreamPartError = class extends import_provider3.AISDKError {
|
|
constructor({
|
|
chunk,
|
|
message
|
|
}) {
|
|
super({ name: name3, message });
|
|
this[_a3] = true;
|
|
this.chunk = chunk;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider3.AISDKError.hasMarker(error, marker3);
|
|
}
|
|
};
|
|
_a3 = symbol3;
|
|
|
|
// src/error/invalid-tool-input-error.ts
|
|
var import_provider4 = require("@ai-sdk/provider");
|
|
var name4 = "AI_InvalidToolInputError";
|
|
var marker4 = `vercel.ai.error.${name4}`;
|
|
var symbol4 = Symbol.for(marker4);
|
|
var _a4;
|
|
var InvalidToolInputError = class extends import_provider4.AISDKError {
|
|
constructor({
|
|
toolInput,
|
|
toolName,
|
|
cause,
|
|
message = `Invalid input for tool ${toolName}: ${(0, import_provider4.getErrorMessage)(cause)}`
|
|
}) {
|
|
super({ name: name4, message, cause });
|
|
this[_a4] = true;
|
|
this.toolInput = toolInput;
|
|
this.toolName = toolName;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider4.AISDKError.hasMarker(error, marker4);
|
|
}
|
|
};
|
|
_a4 = symbol4;
|
|
|
|
// src/error/mcp-client-error.ts
|
|
var import_provider5 = require("@ai-sdk/provider");
|
|
var name5 = "AI_MCPClientError";
|
|
var marker5 = `vercel.ai.error.${name5}`;
|
|
var symbol5 = Symbol.for(marker5);
|
|
var _a5;
|
|
var MCPClientError = class extends import_provider5.AISDKError {
|
|
constructor({
|
|
name: name17 = "MCPClientError",
|
|
message,
|
|
cause
|
|
}) {
|
|
super({ name: name17, message, cause });
|
|
this[_a5] = true;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider5.AISDKError.hasMarker(error, marker5);
|
|
}
|
|
};
|
|
_a5 = symbol5;
|
|
|
|
// src/error/no-image-generated-error.ts
|
|
var import_provider6 = require("@ai-sdk/provider");
|
|
var name6 = "AI_NoImageGeneratedError";
|
|
var marker6 = `vercel.ai.error.${name6}`;
|
|
var symbol6 = Symbol.for(marker6);
|
|
var _a6;
|
|
var NoImageGeneratedError = class extends import_provider6.AISDKError {
|
|
constructor({
|
|
message = "No image generated.",
|
|
cause,
|
|
responses
|
|
}) {
|
|
super({ name: name6, message, cause });
|
|
this[_a6] = true;
|
|
this.responses = responses;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider6.AISDKError.hasMarker(error, marker6);
|
|
}
|
|
};
|
|
_a6 = symbol6;
|
|
|
|
// src/error/no-object-generated-error.ts
|
|
var import_provider7 = require("@ai-sdk/provider");
|
|
var name7 = "AI_NoObjectGeneratedError";
|
|
var marker7 = `vercel.ai.error.${name7}`;
|
|
var symbol7 = Symbol.for(marker7);
|
|
var _a7;
|
|
var NoObjectGeneratedError = class extends import_provider7.AISDKError {
|
|
constructor({
|
|
message = "No object generated.",
|
|
cause,
|
|
text: text2,
|
|
response,
|
|
usage,
|
|
finishReason
|
|
}) {
|
|
super({ name: name7, message, cause });
|
|
this[_a7] = true;
|
|
this.text = text2;
|
|
this.response = response;
|
|
this.usage = usage;
|
|
this.finishReason = finishReason;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider7.AISDKError.hasMarker(error, marker7);
|
|
}
|
|
};
|
|
_a7 = symbol7;
|
|
|
|
// src/error/no-output-generated-error.ts
|
|
var import_provider8 = require("@ai-sdk/provider");
|
|
var name8 = "AI_NoOutputGeneratedError";
|
|
var marker8 = `vercel.ai.error.${name8}`;
|
|
var symbol8 = Symbol.for(marker8);
|
|
var _a8;
|
|
var NoOutputGeneratedError = class extends import_provider8.AISDKError {
|
|
// used in isInstance
|
|
constructor({
|
|
message = "No output generated.",
|
|
cause
|
|
} = {}) {
|
|
super({ name: name8, message, cause });
|
|
this[_a8] = true;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider8.AISDKError.hasMarker(error, marker8);
|
|
}
|
|
};
|
|
_a8 = symbol8;
|
|
|
|
// src/error/no-such-tool-error.ts
|
|
var import_provider9 = require("@ai-sdk/provider");
|
|
var name9 = "AI_NoSuchToolError";
|
|
var marker9 = `vercel.ai.error.${name9}`;
|
|
var symbol9 = Symbol.for(marker9);
|
|
var _a9;
|
|
var NoSuchToolError = class extends import_provider9.AISDKError {
|
|
constructor({
|
|
toolName,
|
|
availableTools = void 0,
|
|
message = `Model tried to call unavailable tool '${toolName}'. ${availableTools === void 0 ? "No tools are available." : `Available tools: ${availableTools.join(", ")}.`}`
|
|
}) {
|
|
super({ name: name9, message });
|
|
this[_a9] = true;
|
|
this.toolName = toolName;
|
|
this.availableTools = availableTools;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider9.AISDKError.hasMarker(error, marker9);
|
|
}
|
|
};
|
|
_a9 = symbol9;
|
|
|
|
// src/error/tool-call-repair-error.ts
|
|
var import_provider10 = require("@ai-sdk/provider");
|
|
var name10 = "AI_ToolCallRepairError";
|
|
var marker10 = `vercel.ai.error.${name10}`;
|
|
var symbol10 = Symbol.for(marker10);
|
|
var _a10;
|
|
var ToolCallRepairError = class extends import_provider10.AISDKError {
|
|
constructor({
|
|
cause,
|
|
originalError,
|
|
message = `Error repairing tool call: ${(0, import_provider10.getErrorMessage)(cause)}`
|
|
}) {
|
|
super({ name: name10, message, cause });
|
|
this[_a10] = true;
|
|
this.originalError = originalError;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider10.AISDKError.hasMarker(error, marker10);
|
|
}
|
|
};
|
|
_a10 = symbol10;
|
|
|
|
// src/error/unsupported-model-version-error.ts
|
|
var import_provider11 = require("@ai-sdk/provider");
|
|
var UnsupportedModelVersionError = class extends import_provider11.AISDKError {
|
|
constructor(options) {
|
|
super({
|
|
name: "AI_UnsupportedModelVersionError",
|
|
message: `Unsupported model version ${options.version} for provider "${options.provider}" and model "${options.modelId}". AI SDK 5 only supports models that implement specification version "v2".`
|
|
});
|
|
this.version = options.version;
|
|
this.provider = options.provider;
|
|
this.modelId = options.modelId;
|
|
}
|
|
};
|
|
|
|
// src/prompt/invalid-data-content-error.ts
|
|
var import_provider12 = require("@ai-sdk/provider");
|
|
var name11 = "AI_InvalidDataContentError";
|
|
var marker11 = `vercel.ai.error.${name11}`;
|
|
var symbol11 = Symbol.for(marker11);
|
|
var _a11;
|
|
var InvalidDataContentError = class extends import_provider12.AISDKError {
|
|
constructor({
|
|
content,
|
|
cause,
|
|
message = `Invalid data content. Expected a base64 string, Uint8Array, ArrayBuffer, or Buffer, but got ${typeof content}.`
|
|
}) {
|
|
super({ name: name11, message, cause });
|
|
this[_a11] = true;
|
|
this.content = content;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider12.AISDKError.hasMarker(error, marker11);
|
|
}
|
|
};
|
|
_a11 = symbol11;
|
|
|
|
// src/prompt/invalid-message-role-error.ts
|
|
var import_provider13 = require("@ai-sdk/provider");
|
|
var name12 = "AI_InvalidMessageRoleError";
|
|
var marker12 = `vercel.ai.error.${name12}`;
|
|
var symbol12 = Symbol.for(marker12);
|
|
var _a12;
|
|
var InvalidMessageRoleError = class extends import_provider13.AISDKError {
|
|
constructor({
|
|
role,
|
|
message = `Invalid message role: '${role}'. Must be one of: "system", "user", "assistant", "tool".`
|
|
}) {
|
|
super({ name: name12, message });
|
|
this[_a12] = true;
|
|
this.role = role;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider13.AISDKError.hasMarker(error, marker12);
|
|
}
|
|
};
|
|
_a12 = symbol12;
|
|
|
|
// src/prompt/message-conversion-error.ts
|
|
var import_provider14 = require("@ai-sdk/provider");
|
|
var name13 = "AI_MessageConversionError";
|
|
var marker13 = `vercel.ai.error.${name13}`;
|
|
var symbol13 = Symbol.for(marker13);
|
|
var _a13;
|
|
var MessageConversionError = class extends import_provider14.AISDKError {
|
|
constructor({
|
|
originalMessage,
|
|
message
|
|
}) {
|
|
super({ name: name13, message });
|
|
this[_a13] = true;
|
|
this.originalMessage = originalMessage;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider14.AISDKError.hasMarker(error, marker13);
|
|
}
|
|
};
|
|
_a13 = symbol13;
|
|
|
|
// src/util/download-error.ts
|
|
var import_provider15 = require("@ai-sdk/provider");
|
|
var name14 = "AI_DownloadError";
|
|
var marker14 = `vercel.ai.error.${name14}`;
|
|
var symbol14 = Symbol.for(marker14);
|
|
var _a14;
|
|
var DownloadError = class extends import_provider15.AISDKError {
|
|
constructor({
|
|
url,
|
|
statusCode,
|
|
statusText,
|
|
cause,
|
|
message = cause == null ? `Failed to download ${url}: ${statusCode} ${statusText}` : `Failed to download ${url}: ${cause}`
|
|
}) {
|
|
super({ name: name14, message, cause });
|
|
this[_a14] = true;
|
|
this.url = url;
|
|
this.statusCode = statusCode;
|
|
this.statusText = statusText;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider15.AISDKError.hasMarker(error, marker14);
|
|
}
|
|
};
|
|
_a14 = symbol14;
|
|
|
|
// src/util/retry-error.ts
|
|
var import_provider16 = require("@ai-sdk/provider");
|
|
var name15 = "AI_RetryError";
|
|
var marker15 = `vercel.ai.error.${name15}`;
|
|
var symbol15 = Symbol.for(marker15);
|
|
var _a15;
|
|
var RetryError = class extends import_provider16.AISDKError {
|
|
constructor({
|
|
message,
|
|
reason,
|
|
errors
|
|
}) {
|
|
super({ name: name15, message });
|
|
this[_a15] = true;
|
|
this.reason = reason;
|
|
this.errors = errors;
|
|
this.lastError = errors[errors.length - 1];
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider16.AISDKError.hasMarker(error, marker15);
|
|
}
|
|
};
|
|
_a15 = symbol15;
|
|
|
|
// src/model/resolve-model.ts
|
|
function resolveLanguageModel(model) {
|
|
if (typeof model !== "string") {
|
|
if (model.specificationVersion !== "v2") {
|
|
throw new UnsupportedModelVersionError({
|
|
version: model.specificationVersion,
|
|
provider: model.provider,
|
|
modelId: model.modelId
|
|
});
|
|
}
|
|
return model;
|
|
}
|
|
return getGlobalProvider().languageModel(model);
|
|
}
|
|
function resolveEmbeddingModel(model) {
|
|
if (typeof model !== "string") {
|
|
if (model.specificationVersion !== "v2") {
|
|
throw new UnsupportedModelVersionError({
|
|
version: model.specificationVersion,
|
|
provider: model.provider,
|
|
modelId: model.modelId
|
|
});
|
|
}
|
|
return model;
|
|
}
|
|
return getGlobalProvider().textEmbeddingModel(
|
|
model
|
|
);
|
|
}
|
|
function getGlobalProvider() {
|
|
var _a17;
|
|
return (_a17 = globalThis.AI_SDK_DEFAULT_PROVIDER) != null ? _a17 : import_gateway.gateway;
|
|
}
|
|
|
|
// src/prompt/convert-to-language-model-prompt.ts
|
|
var import_provider_utils3 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/util/detect-media-type.ts
|
|
var import_provider_utils = require("@ai-sdk/provider-utils");
|
|
var imageMediaTypeSignatures = [
|
|
{
|
|
mediaType: "image/gif",
|
|
bytesPrefix: [71, 73, 70],
|
|
base64Prefix: "R0lG"
|
|
},
|
|
{
|
|
mediaType: "image/png",
|
|
bytesPrefix: [137, 80, 78, 71],
|
|
base64Prefix: "iVBORw"
|
|
},
|
|
{
|
|
mediaType: "image/jpeg",
|
|
bytesPrefix: [255, 216],
|
|
base64Prefix: "/9j/"
|
|
},
|
|
{
|
|
mediaType: "image/webp",
|
|
bytesPrefix: [82, 73, 70, 70],
|
|
base64Prefix: "UklGRg"
|
|
},
|
|
{
|
|
mediaType: "image/bmp",
|
|
bytesPrefix: [66, 77],
|
|
base64Prefix: "Qk"
|
|
},
|
|
{
|
|
mediaType: "image/tiff",
|
|
bytesPrefix: [73, 73, 42, 0],
|
|
base64Prefix: "SUkqAA"
|
|
},
|
|
{
|
|
mediaType: "image/tiff",
|
|
bytesPrefix: [77, 77, 0, 42],
|
|
base64Prefix: "TU0AKg"
|
|
},
|
|
{
|
|
mediaType: "image/avif",
|
|
bytesPrefix: [
|
|
0,
|
|
0,
|
|
0,
|
|
32,
|
|
102,
|
|
116,
|
|
121,
|
|
112,
|
|
97,
|
|
118,
|
|
105,
|
|
102
|
|
],
|
|
base64Prefix: "AAAAIGZ0eXBhdmlm"
|
|
},
|
|
{
|
|
mediaType: "image/heic",
|
|
bytesPrefix: [
|
|
0,
|
|
0,
|
|
0,
|
|
32,
|
|
102,
|
|
116,
|
|
121,
|
|
112,
|
|
104,
|
|
101,
|
|
105,
|
|
99
|
|
],
|
|
base64Prefix: "AAAAIGZ0eXBoZWlj"
|
|
}
|
|
];
|
|
var audioMediaTypeSignatures = [
|
|
{
|
|
mediaType: "audio/mpeg",
|
|
bytesPrefix: [255, 251],
|
|
base64Prefix: "//s="
|
|
},
|
|
{
|
|
mediaType: "audio/mpeg",
|
|
bytesPrefix: [255, 250],
|
|
base64Prefix: "//o="
|
|
},
|
|
{
|
|
mediaType: "audio/mpeg",
|
|
bytesPrefix: [255, 243],
|
|
base64Prefix: "//M="
|
|
},
|
|
{
|
|
mediaType: "audio/mpeg",
|
|
bytesPrefix: [255, 242],
|
|
base64Prefix: "//I="
|
|
},
|
|
{
|
|
mediaType: "audio/mpeg",
|
|
bytesPrefix: [255, 227],
|
|
base64Prefix: "/+M="
|
|
},
|
|
{
|
|
mediaType: "audio/mpeg",
|
|
bytesPrefix: [255, 226],
|
|
base64Prefix: "/+I="
|
|
},
|
|
{
|
|
mediaType: "audio/wav",
|
|
bytesPrefix: [82, 73, 70, 70],
|
|
base64Prefix: "UklGR"
|
|
},
|
|
{
|
|
mediaType: "audio/ogg",
|
|
bytesPrefix: [79, 103, 103, 83],
|
|
base64Prefix: "T2dnUw"
|
|
},
|
|
{
|
|
mediaType: "audio/flac",
|
|
bytesPrefix: [102, 76, 97, 67],
|
|
base64Prefix: "ZkxhQw"
|
|
},
|
|
{
|
|
mediaType: "audio/aac",
|
|
bytesPrefix: [64, 21, 0, 0],
|
|
base64Prefix: "QBUA"
|
|
},
|
|
{
|
|
mediaType: "audio/mp4",
|
|
bytesPrefix: [102, 116, 121, 112],
|
|
base64Prefix: "ZnR5cA"
|
|
},
|
|
{
|
|
mediaType: "audio/webm",
|
|
bytesPrefix: [26, 69, 223, 163],
|
|
base64Prefix: "GkXf"
|
|
}
|
|
];
|
|
var stripID3 = (data) => {
|
|
const bytes = typeof data === "string" ? (0, import_provider_utils.convertBase64ToUint8Array)(data) : data;
|
|
const id3Size = (bytes[6] & 127) << 21 | (bytes[7] & 127) << 14 | (bytes[8] & 127) << 7 | bytes[9] & 127;
|
|
return bytes.slice(id3Size + 10);
|
|
};
|
|
function stripID3TagsIfPresent(data) {
|
|
const hasId3 = typeof data === "string" && data.startsWith("SUQz") || typeof data !== "string" && data.length > 10 && data[0] === 73 && // 'I'
|
|
data[1] === 68 && // 'D'
|
|
data[2] === 51;
|
|
return hasId3 ? stripID3(data) : data;
|
|
}
|
|
function detectMediaType({
|
|
data,
|
|
signatures
|
|
}) {
|
|
const processedData = stripID3TagsIfPresent(data);
|
|
for (const signature of signatures) {
|
|
if (typeof processedData === "string" ? processedData.startsWith(signature.base64Prefix) : processedData.length >= signature.bytesPrefix.length && signature.bytesPrefix.every(
|
|
(byte, index) => processedData[index] === byte
|
|
)) {
|
|
return signature.mediaType;
|
|
}
|
|
}
|
|
return void 0;
|
|
}
|
|
|
|
// src/util/download.ts
|
|
async function download({ url }) {
|
|
var _a17;
|
|
const urlText = url.toString();
|
|
try {
|
|
const response = await fetch(urlText);
|
|
if (!response.ok) {
|
|
throw new DownloadError({
|
|
url: urlText,
|
|
statusCode: response.status,
|
|
statusText: response.statusText
|
|
});
|
|
}
|
|
return {
|
|
data: new Uint8Array(await response.arrayBuffer()),
|
|
mediaType: (_a17 = response.headers.get("content-type")) != null ? _a17 : void 0
|
|
};
|
|
} catch (error) {
|
|
if (DownloadError.isInstance(error)) {
|
|
throw error;
|
|
}
|
|
throw new DownloadError({ url: urlText, cause: error });
|
|
}
|
|
}
|
|
|
|
// src/prompt/data-content.ts
|
|
var import_provider18 = require("@ai-sdk/provider");
|
|
var import_provider_utils2 = require("@ai-sdk/provider-utils");
|
|
var import_v4 = require("zod/v4");
|
|
|
|
// src/prompt/split-data-url.ts
|
|
function splitDataUrl(dataUrl) {
|
|
try {
|
|
const [header, base64Content] = dataUrl.split(",");
|
|
return {
|
|
mediaType: header.split(";")[0].split(":")[1],
|
|
base64Content
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
mediaType: void 0,
|
|
base64Content: void 0
|
|
};
|
|
}
|
|
}
|
|
|
|
// src/prompt/data-content.ts
|
|
var dataContentSchema = import_v4.z.union([
|
|
import_v4.z.string(),
|
|
import_v4.z.instanceof(Uint8Array),
|
|
import_v4.z.instanceof(ArrayBuffer),
|
|
import_v4.z.custom(
|
|
// Buffer might not be available in some environments such as CloudFlare:
|
|
(value) => {
|
|
var _a17, _b;
|
|
return (_b = (_a17 = globalThis.Buffer) == null ? void 0 : _a17.isBuffer(value)) != null ? _b : false;
|
|
},
|
|
{ message: "Must be a Buffer" }
|
|
)
|
|
]);
|
|
function convertToLanguageModelV2DataContent(content) {
|
|
if (content instanceof Uint8Array) {
|
|
return { data: content, mediaType: void 0 };
|
|
}
|
|
if (content instanceof ArrayBuffer) {
|
|
return { data: new Uint8Array(content), mediaType: void 0 };
|
|
}
|
|
if (typeof content === "string") {
|
|
try {
|
|
content = new URL(content);
|
|
} catch (error) {
|
|
}
|
|
}
|
|
if (content instanceof URL && content.protocol === "data:") {
|
|
const { mediaType: dataUrlMediaType, base64Content } = splitDataUrl(
|
|
content.toString()
|
|
);
|
|
if (dataUrlMediaType == null || base64Content == null) {
|
|
throw new import_provider18.AISDKError({
|
|
name: "InvalidDataContentError",
|
|
message: `Invalid data URL format in content ${content.toString()}`
|
|
});
|
|
}
|
|
return { data: base64Content, mediaType: dataUrlMediaType };
|
|
}
|
|
return { data: content, mediaType: void 0 };
|
|
}
|
|
function convertDataContentToBase64String(content) {
|
|
if (typeof content === "string") {
|
|
return content;
|
|
}
|
|
if (content instanceof ArrayBuffer) {
|
|
return (0, import_provider_utils2.convertUint8ArrayToBase64)(new Uint8Array(content));
|
|
}
|
|
return (0, import_provider_utils2.convertUint8ArrayToBase64)(content);
|
|
}
|
|
function convertDataContentToUint8Array(content) {
|
|
if (content instanceof Uint8Array) {
|
|
return content;
|
|
}
|
|
if (typeof content === "string") {
|
|
try {
|
|
return (0, import_provider_utils2.convertBase64ToUint8Array)(content);
|
|
} catch (error) {
|
|
throw new InvalidDataContentError({
|
|
message: "Invalid data content. Content string is not a base64-encoded media.",
|
|
content,
|
|
cause: error
|
|
});
|
|
}
|
|
}
|
|
if (content instanceof ArrayBuffer) {
|
|
return new Uint8Array(content);
|
|
}
|
|
throw new InvalidDataContentError({ content });
|
|
}
|
|
|
|
// src/prompt/convert-to-language-model-prompt.ts
|
|
async function convertToLanguageModelPrompt({
|
|
prompt,
|
|
supportedUrls,
|
|
downloadImplementation = download
|
|
}) {
|
|
const downloadedAssets = await downloadAssets(
|
|
prompt.messages,
|
|
downloadImplementation,
|
|
supportedUrls
|
|
);
|
|
return [
|
|
...prompt.system != null ? [{ role: "system", content: prompt.system }] : [],
|
|
...prompt.messages.map(
|
|
(message) => convertToLanguageModelMessage({ message, downloadedAssets })
|
|
)
|
|
];
|
|
}
|
|
function convertToLanguageModelMessage({
|
|
message,
|
|
downloadedAssets
|
|
}) {
|
|
const role = message.role;
|
|
switch (role) {
|
|
case "system": {
|
|
return {
|
|
role: "system",
|
|
content: message.content,
|
|
providerOptions: message.providerOptions
|
|
};
|
|
}
|
|
case "user": {
|
|
if (typeof message.content === "string") {
|
|
return {
|
|
role: "user",
|
|
content: [{ type: "text", text: message.content }],
|
|
providerOptions: message.providerOptions
|
|
};
|
|
}
|
|
return {
|
|
role: "user",
|
|
content: message.content.map((part) => convertPartToLanguageModelPart(part, downloadedAssets)).filter((part) => part.type !== "text" || part.text !== ""),
|
|
providerOptions: message.providerOptions
|
|
};
|
|
}
|
|
case "assistant": {
|
|
if (typeof message.content === "string") {
|
|
return {
|
|
role: "assistant",
|
|
content: [{ type: "text", text: message.content }],
|
|
providerOptions: message.providerOptions
|
|
};
|
|
}
|
|
return {
|
|
role: "assistant",
|
|
content: message.content.filter(
|
|
// remove empty text parts:
|
|
(part) => part.type !== "text" || part.text !== ""
|
|
).map((part) => {
|
|
const providerOptions = part.providerOptions;
|
|
switch (part.type) {
|
|
case "file": {
|
|
const { data, mediaType } = convertToLanguageModelV2DataContent(
|
|
part.data
|
|
);
|
|
return {
|
|
type: "file",
|
|
data,
|
|
filename: part.filename,
|
|
mediaType: mediaType != null ? mediaType : part.mediaType,
|
|
providerOptions
|
|
};
|
|
}
|
|
case "reasoning": {
|
|
return {
|
|
type: "reasoning",
|
|
text: part.text,
|
|
providerOptions
|
|
};
|
|
}
|
|
case "text": {
|
|
return {
|
|
type: "text",
|
|
text: part.text,
|
|
providerOptions
|
|
};
|
|
}
|
|
case "tool-call": {
|
|
return {
|
|
type: "tool-call",
|
|
toolCallId: part.toolCallId,
|
|
toolName: part.toolName,
|
|
input: part.input,
|
|
providerExecuted: part.providerExecuted,
|
|
providerOptions
|
|
};
|
|
}
|
|
case "tool-result": {
|
|
return {
|
|
type: "tool-result",
|
|
toolCallId: part.toolCallId,
|
|
toolName: part.toolName,
|
|
output: part.output,
|
|
providerOptions
|
|
};
|
|
}
|
|
}
|
|
}),
|
|
providerOptions: message.providerOptions
|
|
};
|
|
}
|
|
case "tool": {
|
|
return {
|
|
role: "tool",
|
|
content: message.content.map((part) => ({
|
|
type: "tool-result",
|
|
toolCallId: part.toolCallId,
|
|
toolName: part.toolName,
|
|
output: part.output,
|
|
providerOptions: part.providerOptions
|
|
})),
|
|
providerOptions: message.providerOptions
|
|
};
|
|
}
|
|
default: {
|
|
const _exhaustiveCheck = role;
|
|
throw new InvalidMessageRoleError({ role: _exhaustiveCheck });
|
|
}
|
|
}
|
|
}
|
|
async function downloadAssets(messages, downloadImplementation, supportedUrls) {
|
|
const urls = messages.filter((message) => message.role === "user").map((message) => message.content).filter(
|
|
(content) => Array.isArray(content)
|
|
).flat().filter(
|
|
(part) => part.type === "image" || part.type === "file"
|
|
).map((part) => {
|
|
var _a17;
|
|
const mediaType = (_a17 = part.mediaType) != null ? _a17 : part.type === "image" ? "image/*" : void 0;
|
|
let data = part.type === "image" ? part.image : part.data;
|
|
if (typeof data === "string") {
|
|
try {
|
|
data = new URL(data);
|
|
} catch (ignored) {
|
|
}
|
|
}
|
|
return { mediaType, data };
|
|
}).filter(
|
|
(part) => part.data instanceof URL && part.mediaType != null && !(0, import_provider_utils3.isUrlSupported)({
|
|
url: part.data.toString(),
|
|
mediaType: part.mediaType,
|
|
supportedUrls
|
|
})
|
|
).map((part) => part.data);
|
|
const downloadedImages = await Promise.all(
|
|
urls.map(async (url) => ({
|
|
url,
|
|
data: await downloadImplementation({ url })
|
|
}))
|
|
);
|
|
return Object.fromEntries(
|
|
downloadedImages.map(({ url, data }) => [url.toString(), data])
|
|
);
|
|
}
|
|
function convertPartToLanguageModelPart(part, downloadedAssets) {
|
|
var _a17;
|
|
if (part.type === "text") {
|
|
return {
|
|
type: "text",
|
|
text: part.text,
|
|
providerOptions: part.providerOptions
|
|
};
|
|
}
|
|
let originalData;
|
|
const type = part.type;
|
|
switch (type) {
|
|
case "image":
|
|
originalData = part.image;
|
|
break;
|
|
case "file":
|
|
originalData = part.data;
|
|
break;
|
|
default:
|
|
throw new Error(`Unsupported part type: ${type}`);
|
|
}
|
|
const { data: convertedData, mediaType: convertedMediaType } = convertToLanguageModelV2DataContent(originalData);
|
|
let mediaType = convertedMediaType != null ? convertedMediaType : part.mediaType;
|
|
let data = convertedData;
|
|
if (data instanceof URL) {
|
|
const downloadedFile = downloadedAssets[data.toString()];
|
|
if (downloadedFile) {
|
|
data = downloadedFile.data;
|
|
mediaType != null ? mediaType : mediaType = downloadedFile.mediaType;
|
|
}
|
|
}
|
|
switch (type) {
|
|
case "image": {
|
|
if (data instanceof Uint8Array || typeof data === "string") {
|
|
mediaType = (_a17 = detectMediaType({ data, signatures: imageMediaTypeSignatures })) != null ? _a17 : mediaType;
|
|
}
|
|
return {
|
|
type: "file",
|
|
mediaType: mediaType != null ? mediaType : "image/*",
|
|
// any image
|
|
filename: void 0,
|
|
data,
|
|
providerOptions: part.providerOptions
|
|
};
|
|
}
|
|
case "file": {
|
|
if (mediaType == null) {
|
|
throw new Error(`Media type is missing for file part`);
|
|
}
|
|
return {
|
|
type: "file",
|
|
mediaType,
|
|
filename: part.filename,
|
|
data,
|
|
providerOptions: part.providerOptions
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
// src/prompt/prepare-call-settings.ts
|
|
function prepareCallSettings({
|
|
maxOutputTokens,
|
|
temperature,
|
|
topP,
|
|
topK,
|
|
presencePenalty,
|
|
frequencyPenalty,
|
|
seed,
|
|
stopSequences
|
|
}) {
|
|
if (maxOutputTokens != null) {
|
|
if (!Number.isInteger(maxOutputTokens)) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "maxOutputTokens",
|
|
value: maxOutputTokens,
|
|
message: "maxOutputTokens must be an integer"
|
|
});
|
|
}
|
|
if (maxOutputTokens < 1) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "maxOutputTokens",
|
|
value: maxOutputTokens,
|
|
message: "maxOutputTokens must be >= 1"
|
|
});
|
|
}
|
|
}
|
|
if (temperature != null) {
|
|
if (typeof temperature !== "number") {
|
|
throw new InvalidArgumentError({
|
|
parameter: "temperature",
|
|
value: temperature,
|
|
message: "temperature must be a number"
|
|
});
|
|
}
|
|
}
|
|
if (topP != null) {
|
|
if (typeof topP !== "number") {
|
|
throw new InvalidArgumentError({
|
|
parameter: "topP",
|
|
value: topP,
|
|
message: "topP must be a number"
|
|
});
|
|
}
|
|
}
|
|
if (topK != null) {
|
|
if (typeof topK !== "number") {
|
|
throw new InvalidArgumentError({
|
|
parameter: "topK",
|
|
value: topK,
|
|
message: "topK must be a number"
|
|
});
|
|
}
|
|
}
|
|
if (presencePenalty != null) {
|
|
if (typeof presencePenalty !== "number") {
|
|
throw new InvalidArgumentError({
|
|
parameter: "presencePenalty",
|
|
value: presencePenalty,
|
|
message: "presencePenalty must be a number"
|
|
});
|
|
}
|
|
}
|
|
if (frequencyPenalty != null) {
|
|
if (typeof frequencyPenalty !== "number") {
|
|
throw new InvalidArgumentError({
|
|
parameter: "frequencyPenalty",
|
|
value: frequencyPenalty,
|
|
message: "frequencyPenalty must be a number"
|
|
});
|
|
}
|
|
}
|
|
if (seed != null) {
|
|
if (!Number.isInteger(seed)) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "seed",
|
|
value: seed,
|
|
message: "seed must be an integer"
|
|
});
|
|
}
|
|
}
|
|
return {
|
|
maxOutputTokens,
|
|
temperature,
|
|
topP,
|
|
topK,
|
|
presencePenalty,
|
|
frequencyPenalty,
|
|
stopSequences,
|
|
seed
|
|
};
|
|
}
|
|
|
|
// src/prompt/prepare-tools-and-tool-choice.ts
|
|
var import_provider_utils4 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/util/is-non-empty-object.ts
|
|
function isNonEmptyObject(object2) {
|
|
return object2 != null && Object.keys(object2).length > 0;
|
|
}
|
|
|
|
// src/prompt/prepare-tools-and-tool-choice.ts
|
|
function prepareToolsAndToolChoice({
|
|
tools,
|
|
toolChoice,
|
|
activeTools
|
|
}) {
|
|
if (!isNonEmptyObject(tools)) {
|
|
return {
|
|
tools: void 0,
|
|
toolChoice: void 0
|
|
};
|
|
}
|
|
const filteredTools = activeTools != null ? Object.entries(tools).filter(
|
|
([name17]) => activeTools.includes(name17)
|
|
) : Object.entries(tools);
|
|
return {
|
|
tools: filteredTools.map(([name17, tool3]) => {
|
|
const toolType = tool3.type;
|
|
switch (toolType) {
|
|
case void 0:
|
|
case "dynamic":
|
|
case "function":
|
|
return {
|
|
type: "function",
|
|
name: name17,
|
|
description: tool3.description,
|
|
inputSchema: (0, import_provider_utils4.asSchema)(tool3.inputSchema).jsonSchema,
|
|
providerOptions: tool3.providerOptions
|
|
};
|
|
case "provider-defined":
|
|
return {
|
|
type: "provider-defined",
|
|
name: name17,
|
|
id: tool3.id,
|
|
args: tool3.args
|
|
};
|
|
default: {
|
|
const exhaustiveCheck = toolType;
|
|
throw new Error(`Unsupported tool type: ${exhaustiveCheck}`);
|
|
}
|
|
}
|
|
}),
|
|
toolChoice: toolChoice == null ? { type: "auto" } : typeof toolChoice === "string" ? { type: toolChoice } : { type: "tool", toolName: toolChoice.toolName }
|
|
};
|
|
}
|
|
|
|
// src/prompt/standardize-prompt.ts
|
|
var import_provider19 = require("@ai-sdk/provider");
|
|
var import_provider_utils5 = require("@ai-sdk/provider-utils");
|
|
var import_v46 = require("zod/v4");
|
|
|
|
// src/prompt/message.ts
|
|
var import_v45 = require("zod/v4");
|
|
|
|
// src/types/provider-metadata.ts
|
|
var import_v43 = require("zod/v4");
|
|
|
|
// src/types/json-value.ts
|
|
var import_v42 = require("zod/v4");
|
|
var jsonValueSchema = import_v42.z.lazy(
|
|
() => import_v42.z.union([
|
|
import_v42.z.null(),
|
|
import_v42.z.string(),
|
|
import_v42.z.number(),
|
|
import_v42.z.boolean(),
|
|
import_v42.z.record(import_v42.z.string(), jsonValueSchema),
|
|
import_v42.z.array(jsonValueSchema)
|
|
])
|
|
);
|
|
|
|
// src/types/provider-metadata.ts
|
|
var providerMetadataSchema = import_v43.z.record(
|
|
import_v43.z.string(),
|
|
import_v43.z.record(import_v43.z.string(), jsonValueSchema)
|
|
);
|
|
|
|
// src/prompt/content-part.ts
|
|
var import_v44 = require("zod/v4");
|
|
var textPartSchema = import_v44.z.object({
|
|
type: import_v44.z.literal("text"),
|
|
text: import_v44.z.string(),
|
|
providerOptions: providerMetadataSchema.optional()
|
|
});
|
|
var imagePartSchema = import_v44.z.object({
|
|
type: import_v44.z.literal("image"),
|
|
image: import_v44.z.union([dataContentSchema, import_v44.z.instanceof(URL)]),
|
|
mediaType: import_v44.z.string().optional(),
|
|
providerOptions: providerMetadataSchema.optional()
|
|
});
|
|
var filePartSchema = import_v44.z.object({
|
|
type: import_v44.z.literal("file"),
|
|
data: import_v44.z.union([dataContentSchema, import_v44.z.instanceof(URL)]),
|
|
filename: import_v44.z.string().optional(),
|
|
mediaType: import_v44.z.string(),
|
|
providerOptions: providerMetadataSchema.optional()
|
|
});
|
|
var reasoningPartSchema = import_v44.z.object({
|
|
type: import_v44.z.literal("reasoning"),
|
|
text: import_v44.z.string(),
|
|
providerOptions: providerMetadataSchema.optional()
|
|
});
|
|
var toolCallPartSchema = import_v44.z.object({
|
|
type: import_v44.z.literal("tool-call"),
|
|
toolCallId: import_v44.z.string(),
|
|
toolName: import_v44.z.string(),
|
|
input: import_v44.z.unknown(),
|
|
providerOptions: providerMetadataSchema.optional(),
|
|
providerExecuted: import_v44.z.boolean().optional()
|
|
});
|
|
var outputSchema = import_v44.z.discriminatedUnion("type", [
|
|
import_v44.z.object({
|
|
type: import_v44.z.literal("text"),
|
|
value: import_v44.z.string()
|
|
}),
|
|
import_v44.z.object({
|
|
type: import_v44.z.literal("json"),
|
|
value: jsonValueSchema
|
|
}),
|
|
import_v44.z.object({
|
|
type: import_v44.z.literal("error-text"),
|
|
value: import_v44.z.string()
|
|
}),
|
|
import_v44.z.object({
|
|
type: import_v44.z.literal("error-json"),
|
|
value: jsonValueSchema
|
|
}),
|
|
import_v44.z.object({
|
|
type: import_v44.z.literal("content"),
|
|
value: import_v44.z.array(
|
|
import_v44.z.union([
|
|
import_v44.z.object({
|
|
type: import_v44.z.literal("text"),
|
|
text: import_v44.z.string()
|
|
}),
|
|
import_v44.z.object({
|
|
type: import_v44.z.literal("media"),
|
|
data: import_v44.z.string(),
|
|
mediaType: import_v44.z.string()
|
|
})
|
|
])
|
|
)
|
|
})
|
|
]);
|
|
var toolResultPartSchema = import_v44.z.object({
|
|
type: import_v44.z.literal("tool-result"),
|
|
toolCallId: import_v44.z.string(),
|
|
toolName: import_v44.z.string(),
|
|
output: outputSchema,
|
|
providerOptions: providerMetadataSchema.optional()
|
|
});
|
|
|
|
// src/prompt/message.ts
|
|
var systemModelMessageSchema = import_v45.z.object(
|
|
{
|
|
role: import_v45.z.literal("system"),
|
|
content: import_v45.z.string(),
|
|
providerOptions: providerMetadataSchema.optional()
|
|
}
|
|
);
|
|
var coreSystemMessageSchema = systemModelMessageSchema;
|
|
var userModelMessageSchema = import_v45.z.object({
|
|
role: import_v45.z.literal("user"),
|
|
content: import_v45.z.union([
|
|
import_v45.z.string(),
|
|
import_v45.z.array(import_v45.z.union([textPartSchema, imagePartSchema, filePartSchema]))
|
|
]),
|
|
providerOptions: providerMetadataSchema.optional()
|
|
});
|
|
var coreUserMessageSchema = userModelMessageSchema;
|
|
var assistantModelMessageSchema = import_v45.z.object({
|
|
role: import_v45.z.literal("assistant"),
|
|
content: import_v45.z.union([
|
|
import_v45.z.string(),
|
|
import_v45.z.array(
|
|
import_v45.z.union([
|
|
textPartSchema,
|
|
filePartSchema,
|
|
reasoningPartSchema,
|
|
toolCallPartSchema,
|
|
toolResultPartSchema
|
|
])
|
|
)
|
|
]),
|
|
providerOptions: providerMetadataSchema.optional()
|
|
});
|
|
var coreAssistantMessageSchema = assistantModelMessageSchema;
|
|
var toolModelMessageSchema = import_v45.z.object({
|
|
role: import_v45.z.literal("tool"),
|
|
content: import_v45.z.array(toolResultPartSchema),
|
|
providerOptions: providerMetadataSchema.optional()
|
|
});
|
|
var coreToolMessageSchema = toolModelMessageSchema;
|
|
var modelMessageSchema = import_v45.z.union([
|
|
systemModelMessageSchema,
|
|
userModelMessageSchema,
|
|
assistantModelMessageSchema,
|
|
toolModelMessageSchema
|
|
]);
|
|
var coreMessageSchema = modelMessageSchema;
|
|
|
|
// src/prompt/standardize-prompt.ts
|
|
async function standardizePrompt(prompt) {
|
|
if (prompt.prompt == null && prompt.messages == null) {
|
|
throw new import_provider19.InvalidPromptError({
|
|
prompt,
|
|
message: "prompt or messages must be defined"
|
|
});
|
|
}
|
|
if (prompt.prompt != null && prompt.messages != null) {
|
|
throw new import_provider19.InvalidPromptError({
|
|
prompt,
|
|
message: "prompt and messages cannot be defined at the same time"
|
|
});
|
|
}
|
|
if (prompt.system != null && typeof prompt.system !== "string") {
|
|
throw new import_provider19.InvalidPromptError({
|
|
prompt,
|
|
message: "system must be a string"
|
|
});
|
|
}
|
|
let messages;
|
|
if (prompt.prompt != null && typeof prompt.prompt === "string") {
|
|
messages = [{ role: "user", content: prompt.prompt }];
|
|
} else if (prompt.prompt != null && Array.isArray(prompt.prompt)) {
|
|
messages = prompt.prompt;
|
|
} else if (prompt.messages != null) {
|
|
messages = prompt.messages;
|
|
} else {
|
|
throw new import_provider19.InvalidPromptError({
|
|
prompt,
|
|
message: "prompt or messages must be defined"
|
|
});
|
|
}
|
|
if (messages.length === 0) {
|
|
throw new import_provider19.InvalidPromptError({
|
|
prompt,
|
|
message: "messages must not be empty"
|
|
});
|
|
}
|
|
const validationResult = await (0, import_provider_utils5.safeValidateTypes)({
|
|
value: messages,
|
|
schema: import_v46.z.array(modelMessageSchema)
|
|
});
|
|
if (!validationResult.success) {
|
|
throw new import_provider19.InvalidPromptError({
|
|
prompt,
|
|
message: "The messages must be a ModelMessage[]. If you have passed a UIMessage[], you can use convertToModelMessages to convert them.",
|
|
cause: validationResult.error
|
|
});
|
|
}
|
|
return {
|
|
messages,
|
|
system: prompt.system
|
|
};
|
|
}
|
|
|
|
// src/prompt/wrap-gateway-error.ts
|
|
var import_gateway2 = require("@ai-sdk/gateway");
|
|
var import_provider20 = require("@ai-sdk/provider");
|
|
function wrapGatewayError(error) {
|
|
if (import_gateway2.GatewayAuthenticationError.isInstance(error) || import_gateway2.GatewayModelNotFoundError.isInstance(error)) {
|
|
return new import_provider20.AISDKError({
|
|
name: "GatewayError",
|
|
message: "Vercel AI Gateway access failed. If you want to use AI SDK providers directly, use the providers, e.g. @ai-sdk/openai, or register a different global default provider.",
|
|
cause: error
|
|
});
|
|
}
|
|
return error;
|
|
}
|
|
|
|
// src/telemetry/assemble-operation-name.ts
|
|
function assembleOperationName({
|
|
operationId,
|
|
telemetry
|
|
}) {
|
|
return {
|
|
// standardized operation and resource name:
|
|
"operation.name": `${operationId}${(telemetry == null ? void 0 : telemetry.functionId) != null ? ` ${telemetry.functionId}` : ""}`,
|
|
"resource.name": telemetry == null ? void 0 : telemetry.functionId,
|
|
// detailed, AI SDK specific data:
|
|
"ai.operationId": operationId,
|
|
"ai.telemetry.functionId": telemetry == null ? void 0 : telemetry.functionId
|
|
};
|
|
}
|
|
|
|
// src/telemetry/get-base-telemetry-attributes.ts
|
|
function getBaseTelemetryAttributes({
|
|
model,
|
|
settings,
|
|
telemetry,
|
|
headers
|
|
}) {
|
|
var _a17;
|
|
return {
|
|
"ai.model.provider": model.provider,
|
|
"ai.model.id": model.modelId,
|
|
// settings:
|
|
...Object.entries(settings).reduce((attributes, [key, value]) => {
|
|
attributes[`ai.settings.${key}`] = value;
|
|
return attributes;
|
|
}, {}),
|
|
// add metadata as attributes:
|
|
...Object.entries((_a17 = telemetry == null ? void 0 : telemetry.metadata) != null ? _a17 : {}).reduce(
|
|
(attributes, [key, value]) => {
|
|
attributes[`ai.telemetry.metadata.${key}`] = value;
|
|
return attributes;
|
|
},
|
|
{}
|
|
),
|
|
// request headers
|
|
...Object.entries(headers != null ? headers : {}).reduce((attributes, [key, value]) => {
|
|
if (value !== void 0) {
|
|
attributes[`ai.request.headers.${key}`] = value;
|
|
}
|
|
return attributes;
|
|
}, {})
|
|
};
|
|
}
|
|
|
|
// src/telemetry/get-tracer.ts
|
|
var import_api = require("@opentelemetry/api");
|
|
|
|
// src/telemetry/noop-tracer.ts
|
|
var noopTracer = {
|
|
startSpan() {
|
|
return noopSpan;
|
|
},
|
|
startActiveSpan(name17, arg1, arg2, arg3) {
|
|
if (typeof arg1 === "function") {
|
|
return arg1(noopSpan);
|
|
}
|
|
if (typeof arg2 === "function") {
|
|
return arg2(noopSpan);
|
|
}
|
|
if (typeof arg3 === "function") {
|
|
return arg3(noopSpan);
|
|
}
|
|
}
|
|
};
|
|
var noopSpan = {
|
|
spanContext() {
|
|
return noopSpanContext;
|
|
},
|
|
setAttribute() {
|
|
return this;
|
|
},
|
|
setAttributes() {
|
|
return this;
|
|
},
|
|
addEvent() {
|
|
return this;
|
|
},
|
|
addLink() {
|
|
return this;
|
|
},
|
|
addLinks() {
|
|
return this;
|
|
},
|
|
setStatus() {
|
|
return this;
|
|
},
|
|
updateName() {
|
|
return this;
|
|
},
|
|
end() {
|
|
return this;
|
|
},
|
|
isRecording() {
|
|
return false;
|
|
},
|
|
recordException() {
|
|
return this;
|
|
}
|
|
};
|
|
var noopSpanContext = {
|
|
traceId: "",
|
|
spanId: "",
|
|
traceFlags: 0
|
|
};
|
|
|
|
// src/telemetry/get-tracer.ts
|
|
function getTracer({
|
|
isEnabled = false,
|
|
tracer
|
|
} = {}) {
|
|
if (!isEnabled) {
|
|
return noopTracer;
|
|
}
|
|
if (tracer) {
|
|
return tracer;
|
|
}
|
|
return import_api.trace.getTracer("ai");
|
|
}
|
|
|
|
// src/telemetry/record-span.ts
|
|
var import_api2 = require("@opentelemetry/api");
|
|
function recordSpan({
|
|
name: name17,
|
|
tracer,
|
|
attributes,
|
|
fn,
|
|
endWhenDone = true
|
|
}) {
|
|
return tracer.startActiveSpan(name17, { attributes }, async (span) => {
|
|
try {
|
|
const result = await fn(span);
|
|
if (endWhenDone) {
|
|
span.end();
|
|
}
|
|
return result;
|
|
} catch (error) {
|
|
try {
|
|
recordErrorOnSpan(span, error);
|
|
} finally {
|
|
span.end();
|
|
}
|
|
throw error;
|
|
}
|
|
});
|
|
}
|
|
function recordErrorOnSpan(span, error) {
|
|
if (error instanceof Error) {
|
|
span.recordException({
|
|
name: error.name,
|
|
message: error.message,
|
|
stack: error.stack
|
|
});
|
|
span.setStatus({
|
|
code: import_api2.SpanStatusCode.ERROR,
|
|
message: error.message
|
|
});
|
|
} else {
|
|
span.setStatus({ code: import_api2.SpanStatusCode.ERROR });
|
|
}
|
|
}
|
|
|
|
// src/telemetry/select-telemetry-attributes.ts
|
|
function selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes
|
|
}) {
|
|
if ((telemetry == null ? void 0 : telemetry.isEnabled) !== true) {
|
|
return {};
|
|
}
|
|
return Object.entries(attributes).reduce((attributes2, [key, value]) => {
|
|
if (value == null) {
|
|
return attributes2;
|
|
}
|
|
if (typeof value === "object" && "input" in value && typeof value.input === "function") {
|
|
if ((telemetry == null ? void 0 : telemetry.recordInputs) === false) {
|
|
return attributes2;
|
|
}
|
|
const result = value.input();
|
|
return result == null ? attributes2 : { ...attributes2, [key]: result };
|
|
}
|
|
if (typeof value === "object" && "output" in value && typeof value.output === "function") {
|
|
if ((telemetry == null ? void 0 : telemetry.recordOutputs) === false) {
|
|
return attributes2;
|
|
}
|
|
const result = value.output();
|
|
return result == null ? attributes2 : { ...attributes2, [key]: result };
|
|
}
|
|
return { ...attributes2, [key]: value };
|
|
}, {});
|
|
}
|
|
|
|
// src/telemetry/stringify-for-telemetry.ts
|
|
function stringifyForTelemetry(prompt) {
|
|
return JSON.stringify(
|
|
prompt.map((message) => ({
|
|
...message,
|
|
content: typeof message.content === "string" ? message.content : message.content.map(
|
|
(part) => part.type === "file" ? {
|
|
...part,
|
|
data: part.data instanceof Uint8Array ? convertDataContentToBase64String(part.data) : part.data
|
|
} : part
|
|
)
|
|
}))
|
|
);
|
|
}
|
|
|
|
// src/types/usage.ts
|
|
function addLanguageModelUsage(usage1, usage2) {
|
|
return {
|
|
inputTokens: addTokenCounts(usage1.inputTokens, usage2.inputTokens),
|
|
outputTokens: addTokenCounts(usage1.outputTokens, usage2.outputTokens),
|
|
totalTokens: addTokenCounts(usage1.totalTokens, usage2.totalTokens),
|
|
reasoningTokens: addTokenCounts(
|
|
usage1.reasoningTokens,
|
|
usage2.reasoningTokens
|
|
),
|
|
cachedInputTokens: addTokenCounts(
|
|
usage1.cachedInputTokens,
|
|
usage2.cachedInputTokens
|
|
)
|
|
};
|
|
}
|
|
function addTokenCounts(tokenCount1, tokenCount2) {
|
|
return tokenCount1 == null && tokenCount2 == null ? void 0 : (tokenCount1 != null ? tokenCount1 : 0) + (tokenCount2 != null ? tokenCount2 : 0);
|
|
}
|
|
|
|
// src/util/as-array.ts
|
|
function asArray(value) {
|
|
return value === void 0 ? [] : Array.isArray(value) ? value : [value];
|
|
}
|
|
|
|
// src/util/retry-with-exponential-backoff.ts
|
|
var import_provider21 = require("@ai-sdk/provider");
|
|
var import_provider_utils6 = require("@ai-sdk/provider-utils");
|
|
function getRetryDelayInMs({
|
|
error,
|
|
exponentialBackoffDelay
|
|
}) {
|
|
const headers = error.responseHeaders;
|
|
if (!headers)
|
|
return exponentialBackoffDelay;
|
|
let ms;
|
|
const retryAfterMs = headers["retry-after-ms"];
|
|
if (retryAfterMs) {
|
|
const timeoutMs = parseFloat(retryAfterMs);
|
|
if (!Number.isNaN(timeoutMs)) {
|
|
ms = timeoutMs;
|
|
}
|
|
}
|
|
const retryAfter = headers["retry-after"];
|
|
if (retryAfter && ms === void 0) {
|
|
const timeoutSeconds = parseFloat(retryAfter);
|
|
if (!Number.isNaN(timeoutSeconds)) {
|
|
ms = timeoutSeconds * 1e3;
|
|
} else {
|
|
ms = Date.parse(retryAfter) - Date.now();
|
|
}
|
|
}
|
|
if (ms != null && !Number.isNaN(ms) && 0 <= ms && (ms < 60 * 1e3 || ms < exponentialBackoffDelay)) {
|
|
return ms;
|
|
}
|
|
return exponentialBackoffDelay;
|
|
}
|
|
var retryWithExponentialBackoffRespectingRetryHeaders = ({
|
|
maxRetries = 2,
|
|
initialDelayInMs = 2e3,
|
|
backoffFactor = 2,
|
|
abortSignal
|
|
} = {}) => async (f) => _retryWithExponentialBackoff(f, {
|
|
maxRetries,
|
|
delayInMs: initialDelayInMs,
|
|
backoffFactor,
|
|
abortSignal
|
|
});
|
|
async function _retryWithExponentialBackoff(f, {
|
|
maxRetries,
|
|
delayInMs,
|
|
backoffFactor,
|
|
abortSignal
|
|
}, errors = []) {
|
|
try {
|
|
return await f();
|
|
} catch (error) {
|
|
if ((0, import_provider_utils6.isAbortError)(error)) {
|
|
throw error;
|
|
}
|
|
if (maxRetries === 0) {
|
|
throw error;
|
|
}
|
|
const errorMessage = (0, import_provider_utils6.getErrorMessage)(error);
|
|
const newErrors = [...errors, error];
|
|
const tryNumber = newErrors.length;
|
|
if (tryNumber > maxRetries) {
|
|
throw new RetryError({
|
|
message: `Failed after ${tryNumber} attempts. Last error: ${errorMessage}`,
|
|
reason: "maxRetriesExceeded",
|
|
errors: newErrors
|
|
});
|
|
}
|
|
if (error instanceof Error && import_provider21.APICallError.isInstance(error) && error.isRetryable === true && tryNumber <= maxRetries) {
|
|
await (0, import_provider_utils6.delay)(
|
|
getRetryDelayInMs({
|
|
error,
|
|
exponentialBackoffDelay: delayInMs
|
|
}),
|
|
{ abortSignal }
|
|
);
|
|
return _retryWithExponentialBackoff(
|
|
f,
|
|
{
|
|
maxRetries,
|
|
delayInMs: backoffFactor * delayInMs,
|
|
backoffFactor,
|
|
abortSignal
|
|
},
|
|
newErrors
|
|
);
|
|
}
|
|
if (tryNumber === 1) {
|
|
throw error;
|
|
}
|
|
throw new RetryError({
|
|
message: `Failed after ${tryNumber} attempts with non-retryable error: '${errorMessage}'`,
|
|
reason: "errorNotRetryable",
|
|
errors: newErrors
|
|
});
|
|
}
|
|
}
|
|
|
|
// src/util/prepare-retries.ts
|
|
function prepareRetries({
|
|
maxRetries,
|
|
abortSignal
|
|
}) {
|
|
if (maxRetries != null) {
|
|
if (!Number.isInteger(maxRetries)) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "maxRetries",
|
|
value: maxRetries,
|
|
message: "maxRetries must be an integer"
|
|
});
|
|
}
|
|
if (maxRetries < 0) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "maxRetries",
|
|
value: maxRetries,
|
|
message: "maxRetries must be >= 0"
|
|
});
|
|
}
|
|
}
|
|
const maxRetriesResult = maxRetries != null ? maxRetries : 2;
|
|
return {
|
|
maxRetries: maxRetriesResult,
|
|
retry: retryWithExponentialBackoffRespectingRetryHeaders({
|
|
maxRetries: maxRetriesResult,
|
|
abortSignal
|
|
})
|
|
};
|
|
}
|
|
|
|
// src/generate-text/extract-content-text.ts
|
|
function extractContentText(content) {
|
|
const parts = content.filter(
|
|
(content2) => content2.type === "text"
|
|
);
|
|
if (parts.length === 0) {
|
|
return void 0;
|
|
}
|
|
return parts.map((content2) => content2.text).join("");
|
|
}
|
|
|
|
// src/generate-text/generated-file.ts
|
|
var import_provider_utils7 = require("@ai-sdk/provider-utils");
|
|
var DefaultGeneratedFile = class {
|
|
constructor({
|
|
data,
|
|
mediaType
|
|
}) {
|
|
const isUint8Array = data instanceof Uint8Array;
|
|
this.base64Data = isUint8Array ? void 0 : data;
|
|
this.uint8ArrayData = isUint8Array ? data : void 0;
|
|
this.mediaType = mediaType;
|
|
}
|
|
// lazy conversion with caching to avoid unnecessary conversion overhead:
|
|
get base64() {
|
|
if (this.base64Data == null) {
|
|
this.base64Data = (0, import_provider_utils7.convertUint8ArrayToBase64)(this.uint8ArrayData);
|
|
}
|
|
return this.base64Data;
|
|
}
|
|
// lazy conversion with caching to avoid unnecessary conversion overhead:
|
|
get uint8Array() {
|
|
if (this.uint8ArrayData == null) {
|
|
this.uint8ArrayData = (0, import_provider_utils7.convertBase64ToUint8Array)(this.base64Data);
|
|
}
|
|
return this.uint8ArrayData;
|
|
}
|
|
};
|
|
var DefaultGeneratedFileWithType = class extends DefaultGeneratedFile {
|
|
constructor(options) {
|
|
super(options);
|
|
this.type = "file";
|
|
}
|
|
};
|
|
|
|
// src/generate-text/parse-tool-call.ts
|
|
var import_provider_utils8 = require("@ai-sdk/provider-utils");
|
|
async function parseToolCall({
|
|
toolCall,
|
|
tools,
|
|
repairToolCall,
|
|
system,
|
|
messages
|
|
}) {
|
|
try {
|
|
if (tools == null) {
|
|
throw new NoSuchToolError({ toolName: toolCall.toolName });
|
|
}
|
|
try {
|
|
return await doParseToolCall({ toolCall, tools });
|
|
} catch (error) {
|
|
if (repairToolCall == null || !(NoSuchToolError.isInstance(error) || InvalidToolInputError.isInstance(error))) {
|
|
throw error;
|
|
}
|
|
let repairedToolCall = null;
|
|
try {
|
|
repairedToolCall = await repairToolCall({
|
|
toolCall,
|
|
tools,
|
|
inputSchema: ({ toolName }) => {
|
|
const { inputSchema } = tools[toolName];
|
|
return (0, import_provider_utils8.asSchema)(inputSchema).jsonSchema;
|
|
},
|
|
system,
|
|
messages,
|
|
error
|
|
});
|
|
} catch (repairError) {
|
|
throw new ToolCallRepairError({
|
|
cause: repairError,
|
|
originalError: error
|
|
});
|
|
}
|
|
if (repairedToolCall == null) {
|
|
throw error;
|
|
}
|
|
return await doParseToolCall({ toolCall: repairedToolCall, tools });
|
|
}
|
|
} catch (error) {
|
|
return {
|
|
type: "tool-call",
|
|
toolCallId: toolCall.toolCallId,
|
|
toolName: toolCall.toolName,
|
|
input: toolCall.input,
|
|
dynamic: true,
|
|
invalid: true,
|
|
error
|
|
};
|
|
}
|
|
}
|
|
async function doParseToolCall({
|
|
toolCall,
|
|
tools
|
|
}) {
|
|
const toolName = toolCall.toolName;
|
|
const tool3 = tools[toolName];
|
|
if (tool3 == null) {
|
|
throw new NoSuchToolError({
|
|
toolName: toolCall.toolName,
|
|
availableTools: Object.keys(tools)
|
|
});
|
|
}
|
|
const schema = (0, import_provider_utils8.asSchema)(tool3.inputSchema);
|
|
const parseResult = toolCall.input.trim() === "" ? await (0, import_provider_utils8.safeValidateTypes)({ value: {}, schema }) : await (0, import_provider_utils8.safeParseJSON)({ text: toolCall.input, schema });
|
|
if (parseResult.success === false) {
|
|
throw new InvalidToolInputError({
|
|
toolName,
|
|
toolInput: toolCall.input,
|
|
cause: parseResult.error
|
|
});
|
|
}
|
|
return tool3.type === "dynamic" ? {
|
|
type: "tool-call",
|
|
toolCallId: toolCall.toolCallId,
|
|
toolName: toolCall.toolName,
|
|
input: parseResult.value,
|
|
providerExecuted: toolCall.providerExecuted,
|
|
providerMetadata: toolCall.providerMetadata,
|
|
dynamic: true
|
|
} : {
|
|
type: "tool-call",
|
|
toolCallId: toolCall.toolCallId,
|
|
toolName,
|
|
input: parseResult.value,
|
|
providerExecuted: toolCall.providerExecuted,
|
|
providerMetadata: toolCall.providerMetadata
|
|
};
|
|
}
|
|
|
|
// src/generate-text/step-result.ts
|
|
var DefaultStepResult = class {
|
|
constructor({
|
|
content,
|
|
finishReason,
|
|
usage,
|
|
warnings,
|
|
request,
|
|
response,
|
|
providerMetadata
|
|
}) {
|
|
this.content = content;
|
|
this.finishReason = finishReason;
|
|
this.usage = usage;
|
|
this.warnings = warnings;
|
|
this.request = request;
|
|
this.response = response;
|
|
this.providerMetadata = providerMetadata;
|
|
}
|
|
get text() {
|
|
return this.content.filter((part) => part.type === "text").map((part) => part.text).join("");
|
|
}
|
|
get reasoning() {
|
|
return this.content.filter((part) => part.type === "reasoning");
|
|
}
|
|
get reasoningText() {
|
|
return this.reasoning.length === 0 ? void 0 : this.reasoning.map((part) => part.text).join("");
|
|
}
|
|
get files() {
|
|
return this.content.filter((part) => part.type === "file").map((part) => part.file);
|
|
}
|
|
get sources() {
|
|
return this.content.filter((part) => part.type === "source");
|
|
}
|
|
get toolCalls() {
|
|
return this.content.filter((part) => part.type === "tool-call");
|
|
}
|
|
get staticToolCalls() {
|
|
return this.toolCalls.filter(
|
|
(toolCall) => toolCall.dynamic === false
|
|
);
|
|
}
|
|
get dynamicToolCalls() {
|
|
return this.toolCalls.filter(
|
|
(toolCall) => toolCall.dynamic === true
|
|
);
|
|
}
|
|
get toolResults() {
|
|
return this.content.filter((part) => part.type === "tool-result");
|
|
}
|
|
get staticToolResults() {
|
|
return this.toolResults.filter(
|
|
(toolResult) => toolResult.dynamic === false
|
|
);
|
|
}
|
|
get dynamicToolResults() {
|
|
return this.toolResults.filter(
|
|
(toolResult) => toolResult.dynamic === true
|
|
);
|
|
}
|
|
};
|
|
|
|
// src/generate-text/stop-condition.ts
|
|
function stepCountIs(stepCount) {
|
|
return ({ steps }) => steps.length === stepCount;
|
|
}
|
|
function hasToolCall(toolName) {
|
|
return ({ steps }) => {
|
|
var _a17, _b, _c;
|
|
return (_c = (_b = (_a17 = steps[steps.length - 1]) == null ? void 0 : _a17.toolCalls) == null ? void 0 : _b.some(
|
|
(toolCall) => toolCall.toolName === toolName
|
|
)) != null ? _c : false;
|
|
};
|
|
}
|
|
async function isStopConditionMet({
|
|
stopConditions,
|
|
steps
|
|
}) {
|
|
return (await Promise.all(stopConditions.map((condition) => condition({ steps })))).some((result) => result);
|
|
}
|
|
|
|
// src/prompt/create-tool-model-output.ts
|
|
var import_provider22 = require("@ai-sdk/provider");
|
|
function createToolModelOutput({
|
|
output,
|
|
tool: tool3,
|
|
errorMode
|
|
}) {
|
|
if (errorMode === "text") {
|
|
return { type: "error-text", value: (0, import_provider22.getErrorMessage)(output) };
|
|
} else if (errorMode === "json") {
|
|
return { type: "error-json", value: toJSONValue(output) };
|
|
}
|
|
if (tool3 == null ? void 0 : tool3.toModelOutput) {
|
|
return tool3.toModelOutput(output);
|
|
}
|
|
return typeof output === "string" ? { type: "text", value: output } : { type: "json", value: toJSONValue(output) };
|
|
}
|
|
function toJSONValue(value) {
|
|
return value === void 0 ? null : value;
|
|
}
|
|
|
|
// src/generate-text/to-response-messages.ts
|
|
function toResponseMessages({
|
|
content: inputContent,
|
|
tools
|
|
}) {
|
|
const responseMessages = [];
|
|
const content = inputContent.filter((part) => part.type !== "source").filter(
|
|
(part) => (part.type !== "tool-result" || part.providerExecuted) && (part.type !== "tool-error" || part.providerExecuted)
|
|
).filter((part) => part.type !== "text" || part.text.length > 0).map((part) => {
|
|
switch (part.type) {
|
|
case "text":
|
|
return {
|
|
type: "text",
|
|
text: part.text,
|
|
providerOptions: part.providerMetadata
|
|
};
|
|
case "reasoning":
|
|
return {
|
|
type: "reasoning",
|
|
text: part.text,
|
|
providerOptions: part.providerMetadata
|
|
};
|
|
case "file":
|
|
return {
|
|
type: "file",
|
|
data: part.file.base64,
|
|
mediaType: part.file.mediaType,
|
|
providerOptions: part.providerMetadata
|
|
};
|
|
case "tool-call":
|
|
return {
|
|
type: "tool-call",
|
|
toolCallId: part.toolCallId,
|
|
toolName: part.toolName,
|
|
input: part.input,
|
|
providerExecuted: part.providerExecuted,
|
|
providerOptions: part.providerMetadata
|
|
};
|
|
case "tool-result":
|
|
return {
|
|
type: "tool-result",
|
|
toolCallId: part.toolCallId,
|
|
toolName: part.toolName,
|
|
output: createToolModelOutput({
|
|
tool: tools == null ? void 0 : tools[part.toolName],
|
|
output: part.output,
|
|
errorMode: "none"
|
|
}),
|
|
providerExecuted: true,
|
|
providerOptions: part.providerMetadata
|
|
};
|
|
case "tool-error":
|
|
return {
|
|
type: "tool-result",
|
|
toolCallId: part.toolCallId,
|
|
toolName: part.toolName,
|
|
output: createToolModelOutput({
|
|
tool: tools == null ? void 0 : tools[part.toolName],
|
|
output: part.error,
|
|
errorMode: "json"
|
|
}),
|
|
providerOptions: part.providerMetadata
|
|
};
|
|
}
|
|
});
|
|
if (content.length > 0) {
|
|
responseMessages.push({
|
|
role: "assistant",
|
|
content
|
|
});
|
|
}
|
|
const toolResultContent = inputContent.filter((part) => part.type === "tool-result" || part.type === "tool-error").filter((part) => !part.providerExecuted).map((toolResult) => ({
|
|
type: "tool-result",
|
|
toolCallId: toolResult.toolCallId,
|
|
toolName: toolResult.toolName,
|
|
output: createToolModelOutput({
|
|
tool: tools == null ? void 0 : tools[toolResult.toolName],
|
|
output: toolResult.type === "tool-result" ? toolResult.output : toolResult.error,
|
|
errorMode: toolResult.type === "tool-error" ? "text" : "none"
|
|
})
|
|
}));
|
|
if (toolResultContent.length > 0) {
|
|
responseMessages.push({
|
|
role: "tool",
|
|
content: toolResultContent
|
|
});
|
|
}
|
|
return responseMessages;
|
|
}
|
|
|
|
// src/generate-text/generate-text.ts
|
|
var originalGenerateId = (0, import_provider_utils9.createIdGenerator)({
|
|
prefix: "aitxt",
|
|
size: 24
|
|
});
|
|
async function generateText({
|
|
model: modelArg,
|
|
tools,
|
|
toolChoice,
|
|
system,
|
|
prompt,
|
|
messages,
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal,
|
|
headers,
|
|
stopWhen = stepCountIs(1),
|
|
experimental_output: output,
|
|
experimental_telemetry: telemetry,
|
|
providerOptions,
|
|
experimental_activeTools,
|
|
activeTools = experimental_activeTools,
|
|
experimental_prepareStep,
|
|
prepareStep = experimental_prepareStep,
|
|
experimental_repairToolCall: repairToolCall,
|
|
experimental_context,
|
|
_internal: {
|
|
generateId: generateId3 = originalGenerateId,
|
|
currentDate = () => /* @__PURE__ */ new Date()
|
|
} = {},
|
|
onStepFinish,
|
|
...settings
|
|
}) {
|
|
const model = resolveLanguageModel(modelArg);
|
|
const stopConditions = asArray(stopWhen);
|
|
const { maxRetries, retry } = prepareRetries({
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal
|
|
});
|
|
const callSettings = prepareCallSettings(settings);
|
|
const baseTelemetryAttributes = getBaseTelemetryAttributes({
|
|
model,
|
|
telemetry,
|
|
headers,
|
|
settings: { ...callSettings, maxRetries }
|
|
});
|
|
const initialPrompt = await standardizePrompt({
|
|
system,
|
|
prompt,
|
|
messages
|
|
});
|
|
const tracer = getTracer(telemetry);
|
|
try {
|
|
return await recordSpan({
|
|
name: "ai.generateText",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.generateText",
|
|
telemetry
|
|
}),
|
|
...baseTelemetryAttributes,
|
|
// model:
|
|
"ai.model.provider": model.provider,
|
|
"ai.model.id": model.modelId,
|
|
// specific settings that only make sense on the outer level:
|
|
"ai.prompt": {
|
|
input: () => JSON.stringify({ system, prompt, messages })
|
|
}
|
|
}
|
|
}),
|
|
tracer,
|
|
fn: async (span) => {
|
|
var _a17, _b, _c, _d, _e, _f;
|
|
const callSettings2 = prepareCallSettings(settings);
|
|
let currentModelResponse;
|
|
let clientToolCalls = [];
|
|
let clientToolOutputs = [];
|
|
const responseMessages = [];
|
|
const steps = [];
|
|
do {
|
|
const stepInputMessages = [
|
|
...initialPrompt.messages,
|
|
...responseMessages
|
|
];
|
|
const prepareStepResult = await (prepareStep == null ? void 0 : prepareStep({
|
|
model,
|
|
steps,
|
|
stepNumber: steps.length,
|
|
messages: stepInputMessages
|
|
}));
|
|
const promptMessages = await convertToLanguageModelPrompt({
|
|
prompt: {
|
|
system: (_a17 = prepareStepResult == null ? void 0 : prepareStepResult.system) != null ? _a17 : initialPrompt.system,
|
|
messages: (_b = prepareStepResult == null ? void 0 : prepareStepResult.messages) != null ? _b : stepInputMessages
|
|
},
|
|
supportedUrls: await model.supportedUrls
|
|
});
|
|
const stepModel = resolveLanguageModel(
|
|
(_c = prepareStepResult == null ? void 0 : prepareStepResult.model) != null ? _c : model
|
|
);
|
|
const { toolChoice: stepToolChoice, tools: stepTools } = prepareToolsAndToolChoice({
|
|
tools,
|
|
toolChoice: (_d = prepareStepResult == null ? void 0 : prepareStepResult.toolChoice) != null ? _d : toolChoice,
|
|
activeTools: (_e = prepareStepResult == null ? void 0 : prepareStepResult.activeTools) != null ? _e : activeTools
|
|
});
|
|
currentModelResponse = await retry(
|
|
() => {
|
|
var _a18;
|
|
return recordSpan({
|
|
name: "ai.generateText.doGenerate",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.generateText.doGenerate",
|
|
telemetry
|
|
}),
|
|
...baseTelemetryAttributes,
|
|
// model:
|
|
"ai.model.provider": stepModel.provider,
|
|
"ai.model.id": stepModel.modelId,
|
|
// prompt:
|
|
"ai.prompt.messages": {
|
|
input: () => stringifyForTelemetry(promptMessages)
|
|
},
|
|
"ai.prompt.tools": {
|
|
// convert the language model level tools:
|
|
input: () => stepTools == null ? void 0 : stepTools.map((tool3) => JSON.stringify(tool3))
|
|
},
|
|
"ai.prompt.toolChoice": {
|
|
input: () => stepToolChoice != null ? JSON.stringify(stepToolChoice) : void 0
|
|
},
|
|
// standardized gen-ai llm span attributes:
|
|
"gen_ai.system": stepModel.provider,
|
|
"gen_ai.request.model": stepModel.modelId,
|
|
"gen_ai.request.frequency_penalty": settings.frequencyPenalty,
|
|
"gen_ai.request.max_tokens": settings.maxOutputTokens,
|
|
"gen_ai.request.presence_penalty": settings.presencePenalty,
|
|
"gen_ai.request.stop_sequences": settings.stopSequences,
|
|
"gen_ai.request.temperature": (_a18 = settings.temperature) != null ? _a18 : void 0,
|
|
"gen_ai.request.top_k": settings.topK,
|
|
"gen_ai.request.top_p": settings.topP
|
|
}
|
|
}),
|
|
tracer,
|
|
fn: async (span2) => {
|
|
var _a19, _b2, _c2, _d2, _e2, _f2, _g, _h;
|
|
const result = await stepModel.doGenerate({
|
|
...callSettings2,
|
|
tools: stepTools,
|
|
toolChoice: stepToolChoice,
|
|
responseFormat: output == null ? void 0 : output.responseFormat,
|
|
prompt: promptMessages,
|
|
providerOptions,
|
|
abortSignal,
|
|
headers
|
|
});
|
|
const responseData = {
|
|
id: (_b2 = (_a19 = result.response) == null ? void 0 : _a19.id) != null ? _b2 : generateId3(),
|
|
timestamp: (_d2 = (_c2 = result.response) == null ? void 0 : _c2.timestamp) != null ? _d2 : currentDate(),
|
|
modelId: (_f2 = (_e2 = result.response) == null ? void 0 : _e2.modelId) != null ? _f2 : stepModel.modelId,
|
|
headers: (_g = result.response) == null ? void 0 : _g.headers,
|
|
body: (_h = result.response) == null ? void 0 : _h.body
|
|
};
|
|
span2.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.response.finishReason": result.finishReason,
|
|
"ai.response.text": {
|
|
output: () => extractContentText(result.content)
|
|
},
|
|
"ai.response.toolCalls": {
|
|
output: () => {
|
|
const toolCalls = asToolCalls(result.content);
|
|
return toolCalls == null ? void 0 : JSON.stringify(toolCalls);
|
|
}
|
|
},
|
|
"ai.response.id": responseData.id,
|
|
"ai.response.model": responseData.modelId,
|
|
"ai.response.timestamp": responseData.timestamp.toISOString(),
|
|
"ai.response.providerMetadata": JSON.stringify(
|
|
result.providerMetadata
|
|
),
|
|
// TODO rename telemetry attributes to inputTokens and outputTokens
|
|
"ai.usage.promptTokens": result.usage.inputTokens,
|
|
"ai.usage.completionTokens": result.usage.outputTokens,
|
|
// standardized gen-ai llm span attributes:
|
|
"gen_ai.response.finish_reasons": [result.finishReason],
|
|
"gen_ai.response.id": responseData.id,
|
|
"gen_ai.response.model": responseData.modelId,
|
|
"gen_ai.usage.input_tokens": result.usage.inputTokens,
|
|
"gen_ai.usage.output_tokens": result.usage.outputTokens
|
|
}
|
|
})
|
|
);
|
|
return { ...result, response: responseData };
|
|
}
|
|
});
|
|
}
|
|
);
|
|
const stepToolCalls = await Promise.all(
|
|
currentModelResponse.content.filter(
|
|
(part) => part.type === "tool-call"
|
|
).map(
|
|
(toolCall) => parseToolCall({
|
|
toolCall,
|
|
tools,
|
|
repairToolCall,
|
|
system,
|
|
messages: stepInputMessages
|
|
})
|
|
)
|
|
);
|
|
for (const toolCall of stepToolCalls) {
|
|
if (toolCall.invalid) {
|
|
continue;
|
|
}
|
|
const tool3 = tools[toolCall.toolName];
|
|
if ((tool3 == null ? void 0 : tool3.onInputAvailable) != null) {
|
|
await tool3.onInputAvailable({
|
|
input: toolCall.input,
|
|
toolCallId: toolCall.toolCallId,
|
|
messages: stepInputMessages,
|
|
abortSignal,
|
|
experimental_context
|
|
});
|
|
}
|
|
}
|
|
const invalidToolCalls = stepToolCalls.filter(
|
|
(toolCall) => toolCall.invalid && toolCall.dynamic
|
|
);
|
|
clientToolOutputs = [];
|
|
for (const toolCall of invalidToolCalls) {
|
|
clientToolOutputs.push({
|
|
type: "tool-error",
|
|
toolCallId: toolCall.toolCallId,
|
|
toolName: toolCall.toolName,
|
|
input: toolCall.input,
|
|
error: (0, import_provider_utils9.getErrorMessage)(toolCall.error),
|
|
dynamic: true
|
|
});
|
|
}
|
|
clientToolCalls = stepToolCalls.filter(
|
|
(toolCall) => !toolCall.providerExecuted
|
|
);
|
|
if (tools != null) {
|
|
clientToolOutputs.push(
|
|
...await executeTools({
|
|
toolCalls: clientToolCalls.filter(
|
|
(toolCall) => !toolCall.invalid
|
|
),
|
|
tools,
|
|
tracer,
|
|
telemetry,
|
|
messages: stepInputMessages,
|
|
abortSignal,
|
|
experimental_context
|
|
})
|
|
);
|
|
}
|
|
const stepContent = asContent({
|
|
content: currentModelResponse.content,
|
|
toolCalls: stepToolCalls,
|
|
toolOutputs: clientToolOutputs
|
|
});
|
|
responseMessages.push(
|
|
...toResponseMessages({
|
|
content: stepContent,
|
|
tools
|
|
})
|
|
);
|
|
const currentStepResult = new DefaultStepResult({
|
|
content: stepContent,
|
|
finishReason: currentModelResponse.finishReason,
|
|
usage: currentModelResponse.usage,
|
|
warnings: currentModelResponse.warnings,
|
|
providerMetadata: currentModelResponse.providerMetadata,
|
|
request: (_f = currentModelResponse.request) != null ? _f : {},
|
|
response: {
|
|
...currentModelResponse.response,
|
|
// deep clone msgs to avoid mutating past messages in multi-step:
|
|
messages: structuredClone(responseMessages)
|
|
}
|
|
});
|
|
steps.push(currentStepResult);
|
|
await (onStepFinish == null ? void 0 : onStepFinish(currentStepResult));
|
|
} while (
|
|
// there are tool calls:
|
|
clientToolCalls.length > 0 && // all current tool calls have outputs (incl. execution errors):
|
|
clientToolOutputs.length === clientToolCalls.length && // continue until a stop condition is met:
|
|
!await isStopConditionMet({ stopConditions, steps })
|
|
);
|
|
span.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.response.finishReason": currentModelResponse.finishReason,
|
|
"ai.response.text": {
|
|
output: () => extractContentText(currentModelResponse.content)
|
|
},
|
|
"ai.response.toolCalls": {
|
|
output: () => {
|
|
const toolCalls = asToolCalls(currentModelResponse.content);
|
|
return toolCalls == null ? void 0 : JSON.stringify(toolCalls);
|
|
}
|
|
},
|
|
"ai.response.providerMetadata": JSON.stringify(
|
|
currentModelResponse.providerMetadata
|
|
),
|
|
// TODO rename telemetry attributes to inputTokens and outputTokens
|
|
"ai.usage.promptTokens": currentModelResponse.usage.inputTokens,
|
|
"ai.usage.completionTokens": currentModelResponse.usage.outputTokens
|
|
}
|
|
})
|
|
);
|
|
const lastStep = steps[steps.length - 1];
|
|
return new DefaultGenerateTextResult({
|
|
steps,
|
|
resolvedOutput: await (output == null ? void 0 : output.parseOutput(
|
|
{ text: lastStep.text },
|
|
{
|
|
response: lastStep.response,
|
|
usage: lastStep.usage,
|
|
finishReason: lastStep.finishReason
|
|
}
|
|
))
|
|
});
|
|
}
|
|
});
|
|
} catch (error) {
|
|
throw wrapGatewayError(error);
|
|
}
|
|
}
|
|
async function executeTools({
|
|
toolCalls,
|
|
tools,
|
|
tracer,
|
|
telemetry,
|
|
messages,
|
|
abortSignal,
|
|
experimental_context
|
|
}) {
|
|
const toolOutputs = await Promise.all(
|
|
toolCalls.map(async ({ toolCallId, toolName, input }) => {
|
|
const tool3 = tools[toolName];
|
|
if ((tool3 == null ? void 0 : tool3.execute) == null) {
|
|
return void 0;
|
|
}
|
|
return recordSpan({
|
|
name: "ai.toolCall",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.toolCall",
|
|
telemetry
|
|
}),
|
|
"ai.toolCall.name": toolName,
|
|
"ai.toolCall.id": toolCallId,
|
|
"ai.toolCall.args": {
|
|
output: () => JSON.stringify(input)
|
|
}
|
|
}
|
|
}),
|
|
tracer,
|
|
fn: async (span) => {
|
|
try {
|
|
const stream = (0, import_provider_utils9.executeTool)({
|
|
execute: tool3.execute.bind(tool3),
|
|
input,
|
|
options: {
|
|
toolCallId,
|
|
messages,
|
|
abortSignal,
|
|
experimental_context
|
|
}
|
|
});
|
|
let output;
|
|
for await (const part of stream) {
|
|
if (part.type === "final") {
|
|
output = part.output;
|
|
}
|
|
}
|
|
try {
|
|
span.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.toolCall.result": {
|
|
output: () => JSON.stringify(output)
|
|
}
|
|
}
|
|
})
|
|
);
|
|
} catch (ignored) {
|
|
}
|
|
return {
|
|
type: "tool-result",
|
|
toolCallId,
|
|
toolName,
|
|
input,
|
|
output,
|
|
dynamic: tool3.type === "dynamic"
|
|
};
|
|
} catch (error) {
|
|
recordErrorOnSpan(span, error);
|
|
return {
|
|
type: "tool-error",
|
|
toolCallId,
|
|
toolName,
|
|
input,
|
|
error,
|
|
dynamic: tool3.type === "dynamic"
|
|
};
|
|
}
|
|
}
|
|
});
|
|
})
|
|
);
|
|
return toolOutputs.filter(
|
|
(output) => output != null
|
|
);
|
|
}
|
|
var DefaultGenerateTextResult = class {
|
|
constructor(options) {
|
|
this.steps = options.steps;
|
|
this.resolvedOutput = options.resolvedOutput;
|
|
}
|
|
get finalStep() {
|
|
return this.steps[this.steps.length - 1];
|
|
}
|
|
get content() {
|
|
return this.finalStep.content;
|
|
}
|
|
get text() {
|
|
return this.finalStep.text;
|
|
}
|
|
get files() {
|
|
return this.finalStep.files;
|
|
}
|
|
get reasoningText() {
|
|
return this.finalStep.reasoningText;
|
|
}
|
|
get reasoning() {
|
|
return this.finalStep.reasoning;
|
|
}
|
|
get toolCalls() {
|
|
return this.finalStep.toolCalls;
|
|
}
|
|
get staticToolCalls() {
|
|
return this.finalStep.staticToolCalls;
|
|
}
|
|
get dynamicToolCalls() {
|
|
return this.finalStep.dynamicToolCalls;
|
|
}
|
|
get toolResults() {
|
|
return this.finalStep.toolResults;
|
|
}
|
|
get staticToolResults() {
|
|
return this.finalStep.staticToolResults;
|
|
}
|
|
get dynamicToolResults() {
|
|
return this.finalStep.dynamicToolResults;
|
|
}
|
|
get sources() {
|
|
return this.finalStep.sources;
|
|
}
|
|
get finishReason() {
|
|
return this.finalStep.finishReason;
|
|
}
|
|
get warnings() {
|
|
return this.finalStep.warnings;
|
|
}
|
|
get providerMetadata() {
|
|
return this.finalStep.providerMetadata;
|
|
}
|
|
get response() {
|
|
return this.finalStep.response;
|
|
}
|
|
get request() {
|
|
return this.finalStep.request;
|
|
}
|
|
get usage() {
|
|
return this.finalStep.usage;
|
|
}
|
|
get totalUsage() {
|
|
return this.steps.reduce(
|
|
(totalUsage, step) => {
|
|
return addLanguageModelUsage(totalUsage, step.usage);
|
|
},
|
|
{
|
|
inputTokens: void 0,
|
|
outputTokens: void 0,
|
|
totalTokens: void 0,
|
|
reasoningTokens: void 0,
|
|
cachedInputTokens: void 0
|
|
}
|
|
);
|
|
}
|
|
get experimental_output() {
|
|
if (this.resolvedOutput == null) {
|
|
throw new NoOutputSpecifiedError();
|
|
}
|
|
return this.resolvedOutput;
|
|
}
|
|
};
|
|
function asToolCalls(content) {
|
|
const parts = content.filter(
|
|
(part) => part.type === "tool-call"
|
|
);
|
|
if (parts.length === 0) {
|
|
return void 0;
|
|
}
|
|
return parts.map((toolCall) => ({
|
|
toolCallId: toolCall.toolCallId,
|
|
toolName: toolCall.toolName,
|
|
input: toolCall.input
|
|
}));
|
|
}
|
|
function asContent({
|
|
content,
|
|
toolCalls,
|
|
toolOutputs
|
|
}) {
|
|
return [
|
|
...content.map((part) => {
|
|
switch (part.type) {
|
|
case "text":
|
|
case "reasoning":
|
|
case "source":
|
|
return part;
|
|
case "file": {
|
|
return {
|
|
type: "file",
|
|
file: new DefaultGeneratedFile(part)
|
|
};
|
|
}
|
|
case "tool-call": {
|
|
return toolCalls.find(
|
|
(toolCall) => toolCall.toolCallId === part.toolCallId
|
|
);
|
|
}
|
|
case "tool-result": {
|
|
const toolCall = toolCalls.find(
|
|
(toolCall2) => toolCall2.toolCallId === part.toolCallId
|
|
);
|
|
if (toolCall == null) {
|
|
throw new Error(`Tool call ${part.toolCallId} not found.`);
|
|
}
|
|
if (part.isError) {
|
|
return {
|
|
type: "tool-error",
|
|
toolCallId: part.toolCallId,
|
|
toolName: part.toolName,
|
|
input: toolCall.input,
|
|
error: part.result,
|
|
providerExecuted: true,
|
|
dynamic: toolCall.dynamic
|
|
};
|
|
}
|
|
return {
|
|
type: "tool-result",
|
|
toolCallId: part.toolCallId,
|
|
toolName: part.toolName,
|
|
input: toolCall.input,
|
|
output: part.result,
|
|
providerExecuted: true,
|
|
dynamic: toolCall.dynamic
|
|
};
|
|
}
|
|
}
|
|
}),
|
|
...toolOutputs
|
|
];
|
|
}
|
|
|
|
// src/generate-text/stream-text.ts
|
|
var import_provider23 = require("@ai-sdk/provider");
|
|
var import_provider_utils13 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/util/prepare-headers.ts
|
|
function prepareHeaders(headers, defaultHeaders) {
|
|
const responseHeaders = new Headers(headers != null ? headers : {});
|
|
for (const [key, value] of Object.entries(defaultHeaders)) {
|
|
if (!responseHeaders.has(key)) {
|
|
responseHeaders.set(key, value);
|
|
}
|
|
}
|
|
return responseHeaders;
|
|
}
|
|
|
|
// src/text-stream/create-text-stream-response.ts
|
|
function createTextStreamResponse({
|
|
status,
|
|
statusText,
|
|
headers,
|
|
textStream
|
|
}) {
|
|
return new Response(textStream.pipeThrough(new TextEncoderStream()), {
|
|
status: status != null ? status : 200,
|
|
statusText,
|
|
headers: prepareHeaders(headers, {
|
|
"content-type": "text/plain; charset=utf-8"
|
|
})
|
|
});
|
|
}
|
|
|
|
// src/util/write-to-server-response.ts
|
|
function writeToServerResponse({
|
|
response,
|
|
status,
|
|
statusText,
|
|
headers,
|
|
stream
|
|
}) {
|
|
response.writeHead(status != null ? status : 200, statusText, headers);
|
|
const reader = stream.getReader();
|
|
const read = async () => {
|
|
try {
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done)
|
|
break;
|
|
response.write(value);
|
|
}
|
|
} catch (error) {
|
|
throw error;
|
|
} finally {
|
|
response.end();
|
|
}
|
|
};
|
|
read();
|
|
}
|
|
|
|
// src/text-stream/pipe-text-stream-to-response.ts
|
|
function pipeTextStreamToResponse({
|
|
response,
|
|
status,
|
|
statusText,
|
|
headers,
|
|
textStream
|
|
}) {
|
|
writeToServerResponse({
|
|
response,
|
|
status,
|
|
statusText,
|
|
headers: Object.fromEntries(
|
|
prepareHeaders(headers, {
|
|
"content-type": "text/plain; charset=utf-8"
|
|
}).entries()
|
|
),
|
|
stream: textStream.pipeThrough(new TextEncoderStream())
|
|
});
|
|
}
|
|
|
|
// src/ui-message-stream/json-to-sse-transform-stream.ts
|
|
var JsonToSseTransformStream = class extends TransformStream {
|
|
constructor() {
|
|
super({
|
|
transform(part, controller) {
|
|
controller.enqueue(`data: ${JSON.stringify(part)}
|
|
|
|
`);
|
|
},
|
|
flush(controller) {
|
|
controller.enqueue("data: [DONE]\n\n");
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
// src/ui-message-stream/ui-message-stream-headers.ts
|
|
var UI_MESSAGE_STREAM_HEADERS = {
|
|
"content-type": "text/event-stream",
|
|
"cache-control": "no-cache",
|
|
connection: "keep-alive",
|
|
"x-vercel-ai-ui-message-stream": "v1",
|
|
"x-accel-buffering": "no"
|
|
// disable nginx buffering
|
|
};
|
|
|
|
// src/ui-message-stream/create-ui-message-stream-response.ts
|
|
function createUIMessageStreamResponse({
|
|
status,
|
|
statusText,
|
|
headers,
|
|
stream,
|
|
consumeSseStream
|
|
}) {
|
|
let sseStream = stream.pipeThrough(new JsonToSseTransformStream());
|
|
if (consumeSseStream) {
|
|
const [stream1, stream2] = sseStream.tee();
|
|
sseStream = stream1;
|
|
consumeSseStream({ stream: stream2 });
|
|
}
|
|
return new Response(sseStream.pipeThrough(new TextEncoderStream()), {
|
|
status,
|
|
statusText,
|
|
headers: prepareHeaders(headers, UI_MESSAGE_STREAM_HEADERS)
|
|
});
|
|
}
|
|
|
|
// src/ui-message-stream/get-response-ui-message-id.ts
|
|
function getResponseUIMessageId({
|
|
originalMessages,
|
|
responseMessageId
|
|
}) {
|
|
if (originalMessages == null) {
|
|
return void 0;
|
|
}
|
|
const lastMessage = originalMessages[originalMessages.length - 1];
|
|
return (lastMessage == null ? void 0 : lastMessage.role) === "assistant" ? lastMessage.id : typeof responseMessageId === "function" ? responseMessageId() : responseMessageId;
|
|
}
|
|
|
|
// src/ui/process-ui-message-stream.ts
|
|
var import_provider_utils11 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/ui-message-stream/ui-message-chunks.ts
|
|
var import_v47 = require("zod/v4");
|
|
var uiMessageChunkSchema = import_v47.z.union([
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("text-start"),
|
|
id: import_v47.z.string(),
|
|
providerMetadata: providerMetadataSchema.optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("text-delta"),
|
|
id: import_v47.z.string(),
|
|
delta: import_v47.z.string(),
|
|
providerMetadata: providerMetadataSchema.optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("text-end"),
|
|
id: import_v47.z.string(),
|
|
providerMetadata: providerMetadataSchema.optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("error"),
|
|
errorText: import_v47.z.string()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("tool-input-start"),
|
|
toolCallId: import_v47.z.string(),
|
|
toolName: import_v47.z.string(),
|
|
providerExecuted: import_v47.z.boolean().optional(),
|
|
dynamic: import_v47.z.boolean().optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("tool-input-delta"),
|
|
toolCallId: import_v47.z.string(),
|
|
inputTextDelta: import_v47.z.string()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("tool-input-available"),
|
|
toolCallId: import_v47.z.string(),
|
|
toolName: import_v47.z.string(),
|
|
input: import_v47.z.unknown(),
|
|
providerExecuted: import_v47.z.boolean().optional(),
|
|
providerMetadata: providerMetadataSchema.optional(),
|
|
dynamic: import_v47.z.boolean().optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("tool-input-error"),
|
|
toolCallId: import_v47.z.string(),
|
|
toolName: import_v47.z.string(),
|
|
input: import_v47.z.unknown(),
|
|
providerExecuted: import_v47.z.boolean().optional(),
|
|
providerMetadata: providerMetadataSchema.optional(),
|
|
dynamic: import_v47.z.boolean().optional(),
|
|
errorText: import_v47.z.string()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("tool-output-available"),
|
|
toolCallId: import_v47.z.string(),
|
|
output: import_v47.z.unknown(),
|
|
providerExecuted: import_v47.z.boolean().optional(),
|
|
dynamic: import_v47.z.boolean().optional(),
|
|
preliminary: import_v47.z.boolean().optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("tool-output-error"),
|
|
toolCallId: import_v47.z.string(),
|
|
errorText: import_v47.z.string(),
|
|
providerExecuted: import_v47.z.boolean().optional(),
|
|
dynamic: import_v47.z.boolean().optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("reasoning"),
|
|
text: import_v47.z.string(),
|
|
providerMetadata: providerMetadataSchema.optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("reasoning-start"),
|
|
id: import_v47.z.string(),
|
|
providerMetadata: providerMetadataSchema.optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("reasoning-delta"),
|
|
id: import_v47.z.string(),
|
|
delta: import_v47.z.string(),
|
|
providerMetadata: providerMetadataSchema.optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("reasoning-end"),
|
|
id: import_v47.z.string(),
|
|
providerMetadata: providerMetadataSchema.optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("reasoning-part-finish")
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("source-url"),
|
|
sourceId: import_v47.z.string(),
|
|
url: import_v47.z.string(),
|
|
title: import_v47.z.string().optional(),
|
|
providerMetadata: providerMetadataSchema.optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("source-document"),
|
|
sourceId: import_v47.z.string(),
|
|
mediaType: import_v47.z.string(),
|
|
title: import_v47.z.string(),
|
|
filename: import_v47.z.string().optional(),
|
|
providerMetadata: providerMetadataSchema.optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("file"),
|
|
url: import_v47.z.string(),
|
|
mediaType: import_v47.z.string(),
|
|
providerMetadata: providerMetadataSchema.optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.string().startsWith("data-"),
|
|
id: import_v47.z.string().optional(),
|
|
data: import_v47.z.unknown(),
|
|
transient: import_v47.z.boolean().optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("start-step")
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("finish-step")
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("start"),
|
|
messageId: import_v47.z.string().optional(),
|
|
messageMetadata: import_v47.z.unknown().optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("finish"),
|
|
messageMetadata: import_v47.z.unknown().optional()
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("abort")
|
|
}),
|
|
import_v47.z.strictObject({
|
|
type: import_v47.z.literal("message-metadata"),
|
|
messageMetadata: import_v47.z.unknown()
|
|
})
|
|
]);
|
|
function isDataUIMessageChunk(chunk) {
|
|
return chunk.type.startsWith("data-");
|
|
}
|
|
|
|
// src/util/merge-objects.ts
|
|
function mergeObjects(base, overrides) {
|
|
if (base === void 0 && overrides === void 0) {
|
|
return void 0;
|
|
}
|
|
if (base === void 0) {
|
|
return overrides;
|
|
}
|
|
if (overrides === void 0) {
|
|
return base;
|
|
}
|
|
const result = { ...base };
|
|
for (const key in overrides) {
|
|
if (Object.prototype.hasOwnProperty.call(overrides, key)) {
|
|
const overridesValue = overrides[key];
|
|
if (overridesValue === void 0)
|
|
continue;
|
|
const baseValue = key in base ? base[key] : void 0;
|
|
const isSourceObject = overridesValue !== null && typeof overridesValue === "object" && !Array.isArray(overridesValue) && !(overridesValue instanceof Date) && !(overridesValue instanceof RegExp);
|
|
const isTargetObject = baseValue !== null && baseValue !== void 0 && typeof baseValue === "object" && !Array.isArray(baseValue) && !(baseValue instanceof Date) && !(baseValue instanceof RegExp);
|
|
if (isSourceObject && isTargetObject) {
|
|
result[key] = mergeObjects(
|
|
baseValue,
|
|
overridesValue
|
|
);
|
|
} else {
|
|
result[key] = overridesValue;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// src/util/parse-partial-json.ts
|
|
var import_provider_utils10 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/util/fix-json.ts
|
|
function fixJson(input) {
|
|
const stack = ["ROOT"];
|
|
let lastValidIndex = -1;
|
|
let literalStart = null;
|
|
function processValueStart(char, i, swapState) {
|
|
{
|
|
switch (char) {
|
|
case '"': {
|
|
lastValidIndex = i;
|
|
stack.pop();
|
|
stack.push(swapState);
|
|
stack.push("INSIDE_STRING");
|
|
break;
|
|
}
|
|
case "f":
|
|
case "t":
|
|
case "n": {
|
|
lastValidIndex = i;
|
|
literalStart = i;
|
|
stack.pop();
|
|
stack.push(swapState);
|
|
stack.push("INSIDE_LITERAL");
|
|
break;
|
|
}
|
|
case "-": {
|
|
stack.pop();
|
|
stack.push(swapState);
|
|
stack.push("INSIDE_NUMBER");
|
|
break;
|
|
}
|
|
case "0":
|
|
case "1":
|
|
case "2":
|
|
case "3":
|
|
case "4":
|
|
case "5":
|
|
case "6":
|
|
case "7":
|
|
case "8":
|
|
case "9": {
|
|
lastValidIndex = i;
|
|
stack.pop();
|
|
stack.push(swapState);
|
|
stack.push("INSIDE_NUMBER");
|
|
break;
|
|
}
|
|
case "{": {
|
|
lastValidIndex = i;
|
|
stack.pop();
|
|
stack.push(swapState);
|
|
stack.push("INSIDE_OBJECT_START");
|
|
break;
|
|
}
|
|
case "[": {
|
|
lastValidIndex = i;
|
|
stack.pop();
|
|
stack.push(swapState);
|
|
stack.push("INSIDE_ARRAY_START");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function processAfterObjectValue(char, i) {
|
|
switch (char) {
|
|
case ",": {
|
|
stack.pop();
|
|
stack.push("INSIDE_OBJECT_AFTER_COMMA");
|
|
break;
|
|
}
|
|
case "}": {
|
|
lastValidIndex = i;
|
|
stack.pop();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
function processAfterArrayValue(char, i) {
|
|
switch (char) {
|
|
case ",": {
|
|
stack.pop();
|
|
stack.push("INSIDE_ARRAY_AFTER_COMMA");
|
|
break;
|
|
}
|
|
case "]": {
|
|
lastValidIndex = i;
|
|
stack.pop();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for (let i = 0; i < input.length; i++) {
|
|
const char = input[i];
|
|
const currentState = stack[stack.length - 1];
|
|
switch (currentState) {
|
|
case "ROOT":
|
|
processValueStart(char, i, "FINISH");
|
|
break;
|
|
case "INSIDE_OBJECT_START": {
|
|
switch (char) {
|
|
case '"': {
|
|
stack.pop();
|
|
stack.push("INSIDE_OBJECT_KEY");
|
|
break;
|
|
}
|
|
case "}": {
|
|
lastValidIndex = i;
|
|
stack.pop();
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case "INSIDE_OBJECT_AFTER_COMMA": {
|
|
switch (char) {
|
|
case '"': {
|
|
stack.pop();
|
|
stack.push("INSIDE_OBJECT_KEY");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case "INSIDE_OBJECT_KEY": {
|
|
switch (char) {
|
|
case '"': {
|
|
stack.pop();
|
|
stack.push("INSIDE_OBJECT_AFTER_KEY");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case "INSIDE_OBJECT_AFTER_KEY": {
|
|
switch (char) {
|
|
case ":": {
|
|
stack.pop();
|
|
stack.push("INSIDE_OBJECT_BEFORE_VALUE");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case "INSIDE_OBJECT_BEFORE_VALUE": {
|
|
processValueStart(char, i, "INSIDE_OBJECT_AFTER_VALUE");
|
|
break;
|
|
}
|
|
case "INSIDE_OBJECT_AFTER_VALUE": {
|
|
processAfterObjectValue(char, i);
|
|
break;
|
|
}
|
|
case "INSIDE_STRING": {
|
|
switch (char) {
|
|
case '"': {
|
|
stack.pop();
|
|
lastValidIndex = i;
|
|
break;
|
|
}
|
|
case "\\": {
|
|
stack.push("INSIDE_STRING_ESCAPE");
|
|
break;
|
|
}
|
|
default: {
|
|
lastValidIndex = i;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case "INSIDE_ARRAY_START": {
|
|
switch (char) {
|
|
case "]": {
|
|
lastValidIndex = i;
|
|
stack.pop();
|
|
break;
|
|
}
|
|
default: {
|
|
lastValidIndex = i;
|
|
processValueStart(char, i, "INSIDE_ARRAY_AFTER_VALUE");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case "INSIDE_ARRAY_AFTER_VALUE": {
|
|
switch (char) {
|
|
case ",": {
|
|
stack.pop();
|
|
stack.push("INSIDE_ARRAY_AFTER_COMMA");
|
|
break;
|
|
}
|
|
case "]": {
|
|
lastValidIndex = i;
|
|
stack.pop();
|
|
break;
|
|
}
|
|
default: {
|
|
lastValidIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case "INSIDE_ARRAY_AFTER_COMMA": {
|
|
processValueStart(char, i, "INSIDE_ARRAY_AFTER_VALUE");
|
|
break;
|
|
}
|
|
case "INSIDE_STRING_ESCAPE": {
|
|
stack.pop();
|
|
lastValidIndex = i;
|
|
break;
|
|
}
|
|
case "INSIDE_NUMBER": {
|
|
switch (char) {
|
|
case "0":
|
|
case "1":
|
|
case "2":
|
|
case "3":
|
|
case "4":
|
|
case "5":
|
|
case "6":
|
|
case "7":
|
|
case "8":
|
|
case "9": {
|
|
lastValidIndex = i;
|
|
break;
|
|
}
|
|
case "e":
|
|
case "E":
|
|
case "-":
|
|
case ".": {
|
|
break;
|
|
}
|
|
case ",": {
|
|
stack.pop();
|
|
if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") {
|
|
processAfterArrayValue(char, i);
|
|
}
|
|
if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") {
|
|
processAfterObjectValue(char, i);
|
|
}
|
|
break;
|
|
}
|
|
case "}": {
|
|
stack.pop();
|
|
if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") {
|
|
processAfterObjectValue(char, i);
|
|
}
|
|
break;
|
|
}
|
|
case "]": {
|
|
stack.pop();
|
|
if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") {
|
|
processAfterArrayValue(char, i);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
stack.pop();
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case "INSIDE_LITERAL": {
|
|
const partialLiteral = input.substring(literalStart, i + 1);
|
|
if (!"false".startsWith(partialLiteral) && !"true".startsWith(partialLiteral) && !"null".startsWith(partialLiteral)) {
|
|
stack.pop();
|
|
if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") {
|
|
processAfterObjectValue(char, i);
|
|
} else if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") {
|
|
processAfterArrayValue(char, i);
|
|
}
|
|
} else {
|
|
lastValidIndex = i;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
let result = input.slice(0, lastValidIndex + 1);
|
|
for (let i = stack.length - 1; i >= 0; i--) {
|
|
const state = stack[i];
|
|
switch (state) {
|
|
case "INSIDE_STRING": {
|
|
result += '"';
|
|
break;
|
|
}
|
|
case "INSIDE_OBJECT_KEY":
|
|
case "INSIDE_OBJECT_AFTER_KEY":
|
|
case "INSIDE_OBJECT_AFTER_COMMA":
|
|
case "INSIDE_OBJECT_START":
|
|
case "INSIDE_OBJECT_BEFORE_VALUE":
|
|
case "INSIDE_OBJECT_AFTER_VALUE": {
|
|
result += "}";
|
|
break;
|
|
}
|
|
case "INSIDE_ARRAY_START":
|
|
case "INSIDE_ARRAY_AFTER_COMMA":
|
|
case "INSIDE_ARRAY_AFTER_VALUE": {
|
|
result += "]";
|
|
break;
|
|
}
|
|
case "INSIDE_LITERAL": {
|
|
const partialLiteral = input.substring(literalStart, input.length);
|
|
if ("true".startsWith(partialLiteral)) {
|
|
result += "true".slice(partialLiteral.length);
|
|
} else if ("false".startsWith(partialLiteral)) {
|
|
result += "false".slice(partialLiteral.length);
|
|
} else if ("null".startsWith(partialLiteral)) {
|
|
result += "null".slice(partialLiteral.length);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// src/util/parse-partial-json.ts
|
|
async function parsePartialJson(jsonText) {
|
|
if (jsonText === void 0) {
|
|
return { value: void 0, state: "undefined-input" };
|
|
}
|
|
let result = await (0, import_provider_utils10.safeParseJSON)({ text: jsonText });
|
|
if (result.success) {
|
|
return { value: result.value, state: "successful-parse" };
|
|
}
|
|
result = await (0, import_provider_utils10.safeParseJSON)({ text: fixJson(jsonText) });
|
|
if (result.success) {
|
|
return { value: result.value, state: "repaired-parse" };
|
|
}
|
|
return { value: void 0, state: "failed-parse" };
|
|
}
|
|
|
|
// src/ui/ui-messages.ts
|
|
function isToolUIPart(part) {
|
|
return part.type.startsWith("tool-");
|
|
}
|
|
function getToolName(part) {
|
|
return part.type.split("-").slice(1).join("-");
|
|
}
|
|
|
|
// src/ui/process-ui-message-stream.ts
|
|
function createStreamingUIMessageState({
|
|
lastMessage,
|
|
messageId
|
|
}) {
|
|
return {
|
|
message: (lastMessage == null ? void 0 : lastMessage.role) === "assistant" ? lastMessage : {
|
|
id: messageId,
|
|
metadata: void 0,
|
|
role: "assistant",
|
|
parts: []
|
|
},
|
|
activeTextParts: {},
|
|
activeReasoningParts: {},
|
|
partialToolCalls: {}
|
|
};
|
|
}
|
|
function processUIMessageStream({
|
|
stream,
|
|
messageMetadataSchema,
|
|
dataPartSchemas,
|
|
runUpdateMessageJob,
|
|
onError,
|
|
onToolCall,
|
|
onData
|
|
}) {
|
|
return stream.pipeThrough(
|
|
new TransformStream({
|
|
async transform(chunk, controller) {
|
|
await runUpdateMessageJob(async ({ state, write }) => {
|
|
var _a17, _b, _c, _d;
|
|
function getToolInvocation(toolCallId) {
|
|
const toolInvocations = state.message.parts.filter(isToolUIPart);
|
|
const toolInvocation = toolInvocations.find(
|
|
(invocation) => invocation.toolCallId === toolCallId
|
|
);
|
|
if (toolInvocation == null) {
|
|
throw new Error(
|
|
"tool-output-error must be preceded by a tool-input-available"
|
|
);
|
|
}
|
|
return toolInvocation;
|
|
}
|
|
function getDynamicToolInvocation(toolCallId) {
|
|
const toolInvocations = state.message.parts.filter(
|
|
(part) => part.type === "dynamic-tool"
|
|
);
|
|
const toolInvocation = toolInvocations.find(
|
|
(invocation) => invocation.toolCallId === toolCallId
|
|
);
|
|
if (toolInvocation == null) {
|
|
throw new Error(
|
|
"tool-output-error must be preceded by a tool-input-available"
|
|
);
|
|
}
|
|
return toolInvocation;
|
|
}
|
|
function updateToolPart(options) {
|
|
var _a18;
|
|
const part = state.message.parts.find(
|
|
(part2) => isToolUIPart(part2) && part2.toolCallId === options.toolCallId
|
|
);
|
|
const anyOptions = options;
|
|
const anyPart = part;
|
|
if (part != null) {
|
|
part.state = options.state;
|
|
anyPart.input = anyOptions.input;
|
|
anyPart.output = anyOptions.output;
|
|
anyPart.errorText = anyOptions.errorText;
|
|
anyPart.rawInput = anyOptions.rawInput;
|
|
anyPart.preliminary = anyOptions.preliminary;
|
|
anyPart.providerExecuted = (_a18 = anyOptions.providerExecuted) != null ? _a18 : part.providerExecuted;
|
|
if (anyOptions.providerMetadata != null && part.state === "input-available") {
|
|
part.callProviderMetadata = anyOptions.providerMetadata;
|
|
}
|
|
} else {
|
|
state.message.parts.push({
|
|
type: `tool-${options.toolName}`,
|
|
toolCallId: options.toolCallId,
|
|
state: options.state,
|
|
input: anyOptions.input,
|
|
output: anyOptions.output,
|
|
rawInput: anyOptions.rawInput,
|
|
errorText: anyOptions.errorText,
|
|
providerExecuted: anyOptions.providerExecuted,
|
|
preliminary: anyOptions.preliminary,
|
|
...anyOptions.providerMetadata != null ? { callProviderMetadata: anyOptions.providerMetadata } : {}
|
|
});
|
|
}
|
|
}
|
|
function updateDynamicToolPart(options) {
|
|
var _a18;
|
|
const part = state.message.parts.find(
|
|
(part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId
|
|
);
|
|
const anyOptions = options;
|
|
const anyPart = part;
|
|
if (part != null) {
|
|
part.state = options.state;
|
|
anyPart.toolName = options.toolName;
|
|
anyPart.input = anyOptions.input;
|
|
anyPart.output = anyOptions.output;
|
|
anyPart.errorText = anyOptions.errorText;
|
|
anyPart.rawInput = (_a18 = anyOptions.rawInput) != null ? _a18 : anyPart.rawInput;
|
|
anyPart.preliminary = anyOptions.preliminary;
|
|
if (anyOptions.providerMetadata != null && part.state === "input-available") {
|
|
part.callProviderMetadata = anyOptions.providerMetadata;
|
|
}
|
|
} else {
|
|
state.message.parts.push({
|
|
type: "dynamic-tool",
|
|
toolName: options.toolName,
|
|
toolCallId: options.toolCallId,
|
|
state: options.state,
|
|
input: anyOptions.input,
|
|
output: anyOptions.output,
|
|
errorText: anyOptions.errorText,
|
|
preliminary: anyOptions.preliminary,
|
|
...anyOptions.providerMetadata != null ? { callProviderMetadata: anyOptions.providerMetadata } : {}
|
|
});
|
|
}
|
|
}
|
|
async function updateMessageMetadata(metadata) {
|
|
if (metadata != null) {
|
|
const mergedMetadata = state.message.metadata != null ? mergeObjects(state.message.metadata, metadata) : metadata;
|
|
if (messageMetadataSchema != null) {
|
|
await (0, import_provider_utils11.validateTypes)({
|
|
value: mergedMetadata,
|
|
schema: messageMetadataSchema
|
|
});
|
|
}
|
|
state.message.metadata = mergedMetadata;
|
|
}
|
|
}
|
|
switch (chunk.type) {
|
|
case "text-start": {
|
|
const textPart = {
|
|
type: "text",
|
|
text: "",
|
|
providerMetadata: chunk.providerMetadata,
|
|
state: "streaming"
|
|
};
|
|
state.activeTextParts[chunk.id] = textPart;
|
|
state.message.parts.push(textPart);
|
|
write();
|
|
break;
|
|
}
|
|
case "text-delta": {
|
|
const textPart = state.activeTextParts[chunk.id];
|
|
textPart.text += chunk.delta;
|
|
textPart.providerMetadata = (_a17 = chunk.providerMetadata) != null ? _a17 : textPart.providerMetadata;
|
|
write();
|
|
break;
|
|
}
|
|
case "text-end": {
|
|
const textPart = state.activeTextParts[chunk.id];
|
|
textPart.state = "done";
|
|
textPart.providerMetadata = (_b = chunk.providerMetadata) != null ? _b : textPart.providerMetadata;
|
|
delete state.activeTextParts[chunk.id];
|
|
write();
|
|
break;
|
|
}
|
|
case "reasoning-start": {
|
|
const reasoningPart = {
|
|
type: "reasoning",
|
|
text: "",
|
|
providerMetadata: chunk.providerMetadata,
|
|
state: "streaming"
|
|
};
|
|
state.activeReasoningParts[chunk.id] = reasoningPart;
|
|
state.message.parts.push(reasoningPart);
|
|
write();
|
|
break;
|
|
}
|
|
case "reasoning-delta": {
|
|
const reasoningPart = state.activeReasoningParts[chunk.id];
|
|
reasoningPart.text += chunk.delta;
|
|
reasoningPart.providerMetadata = (_c = chunk.providerMetadata) != null ? _c : reasoningPart.providerMetadata;
|
|
write();
|
|
break;
|
|
}
|
|
case "reasoning-end": {
|
|
const reasoningPart = state.activeReasoningParts[chunk.id];
|
|
reasoningPart.providerMetadata = (_d = chunk.providerMetadata) != null ? _d : reasoningPart.providerMetadata;
|
|
reasoningPart.state = "done";
|
|
delete state.activeReasoningParts[chunk.id];
|
|
write();
|
|
break;
|
|
}
|
|
case "file": {
|
|
state.message.parts.push({
|
|
type: "file",
|
|
mediaType: chunk.mediaType,
|
|
url: chunk.url
|
|
});
|
|
write();
|
|
break;
|
|
}
|
|
case "source-url": {
|
|
state.message.parts.push({
|
|
type: "source-url",
|
|
sourceId: chunk.sourceId,
|
|
url: chunk.url,
|
|
title: chunk.title,
|
|
providerMetadata: chunk.providerMetadata
|
|
});
|
|
write();
|
|
break;
|
|
}
|
|
case "source-document": {
|
|
state.message.parts.push({
|
|
type: "source-document",
|
|
sourceId: chunk.sourceId,
|
|
mediaType: chunk.mediaType,
|
|
title: chunk.title,
|
|
filename: chunk.filename,
|
|
providerMetadata: chunk.providerMetadata
|
|
});
|
|
write();
|
|
break;
|
|
}
|
|
case "tool-input-start": {
|
|
const toolInvocations = state.message.parts.filter(isToolUIPart);
|
|
state.partialToolCalls[chunk.toolCallId] = {
|
|
text: "",
|
|
toolName: chunk.toolName,
|
|
index: toolInvocations.length,
|
|
dynamic: chunk.dynamic
|
|
};
|
|
if (chunk.dynamic) {
|
|
updateDynamicToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: chunk.toolName,
|
|
state: "input-streaming",
|
|
input: void 0
|
|
});
|
|
} else {
|
|
updateToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: chunk.toolName,
|
|
state: "input-streaming",
|
|
input: void 0,
|
|
providerExecuted: chunk.providerExecuted
|
|
});
|
|
}
|
|
write();
|
|
break;
|
|
}
|
|
case "tool-input-delta": {
|
|
const partialToolCall = state.partialToolCalls[chunk.toolCallId];
|
|
partialToolCall.text += chunk.inputTextDelta;
|
|
const { value: partialArgs } = await parsePartialJson(
|
|
partialToolCall.text
|
|
);
|
|
if (partialToolCall.dynamic) {
|
|
updateDynamicToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: partialToolCall.toolName,
|
|
state: "input-streaming",
|
|
input: partialArgs
|
|
});
|
|
} else {
|
|
updateToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: partialToolCall.toolName,
|
|
state: "input-streaming",
|
|
input: partialArgs
|
|
});
|
|
}
|
|
write();
|
|
break;
|
|
}
|
|
case "tool-input-available": {
|
|
if (chunk.dynamic) {
|
|
updateDynamicToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: chunk.toolName,
|
|
state: "input-available",
|
|
input: chunk.input,
|
|
providerMetadata: chunk.providerMetadata
|
|
});
|
|
} else {
|
|
updateToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: chunk.toolName,
|
|
state: "input-available",
|
|
input: chunk.input,
|
|
providerExecuted: chunk.providerExecuted,
|
|
providerMetadata: chunk.providerMetadata
|
|
});
|
|
}
|
|
write();
|
|
if (onToolCall && !chunk.providerExecuted) {
|
|
await onToolCall({
|
|
toolCall: chunk
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "tool-input-error": {
|
|
if (chunk.dynamic) {
|
|
updateDynamicToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: chunk.toolName,
|
|
state: "output-error",
|
|
input: chunk.input,
|
|
errorText: chunk.errorText,
|
|
providerMetadata: chunk.providerMetadata
|
|
});
|
|
} else {
|
|
updateToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: chunk.toolName,
|
|
state: "output-error",
|
|
input: void 0,
|
|
rawInput: chunk.input,
|
|
errorText: chunk.errorText,
|
|
providerExecuted: chunk.providerExecuted,
|
|
providerMetadata: chunk.providerMetadata
|
|
});
|
|
}
|
|
write();
|
|
break;
|
|
}
|
|
case "tool-output-available": {
|
|
if (chunk.dynamic) {
|
|
const toolInvocation = getDynamicToolInvocation(
|
|
chunk.toolCallId
|
|
);
|
|
updateDynamicToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: toolInvocation.toolName,
|
|
state: "output-available",
|
|
input: toolInvocation.input,
|
|
output: chunk.output,
|
|
preliminary: chunk.preliminary
|
|
});
|
|
} else {
|
|
const toolInvocation = getToolInvocation(chunk.toolCallId);
|
|
updateToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: getToolName(toolInvocation),
|
|
state: "output-available",
|
|
input: toolInvocation.input,
|
|
output: chunk.output,
|
|
providerExecuted: chunk.providerExecuted,
|
|
preliminary: chunk.preliminary
|
|
});
|
|
}
|
|
write();
|
|
break;
|
|
}
|
|
case "tool-output-error": {
|
|
if (chunk.dynamic) {
|
|
const toolInvocation = getDynamicToolInvocation(
|
|
chunk.toolCallId
|
|
);
|
|
updateDynamicToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: toolInvocation.toolName,
|
|
state: "output-error",
|
|
input: toolInvocation.input,
|
|
errorText: chunk.errorText
|
|
});
|
|
} else {
|
|
const toolInvocation = getToolInvocation(chunk.toolCallId);
|
|
updateToolPart({
|
|
toolCallId: chunk.toolCallId,
|
|
toolName: getToolName(toolInvocation),
|
|
state: "output-error",
|
|
input: toolInvocation.input,
|
|
rawInput: toolInvocation.rawInput,
|
|
errorText: chunk.errorText
|
|
});
|
|
}
|
|
write();
|
|
break;
|
|
}
|
|
case "start-step": {
|
|
state.message.parts.push({ type: "step-start" });
|
|
break;
|
|
}
|
|
case "finish-step": {
|
|
state.activeTextParts = {};
|
|
state.activeReasoningParts = {};
|
|
break;
|
|
}
|
|
case "start": {
|
|
if (chunk.messageId != null) {
|
|
state.message.id = chunk.messageId;
|
|
}
|
|
await updateMessageMetadata(chunk.messageMetadata);
|
|
if (chunk.messageId != null || chunk.messageMetadata != null) {
|
|
write();
|
|
}
|
|
break;
|
|
}
|
|
case "finish": {
|
|
await updateMessageMetadata(chunk.messageMetadata);
|
|
if (chunk.messageMetadata != null) {
|
|
write();
|
|
}
|
|
break;
|
|
}
|
|
case "message-metadata": {
|
|
await updateMessageMetadata(chunk.messageMetadata);
|
|
if (chunk.messageMetadata != null) {
|
|
write();
|
|
}
|
|
break;
|
|
}
|
|
case "error": {
|
|
onError == null ? void 0 : onError(new Error(chunk.errorText));
|
|
break;
|
|
}
|
|
default: {
|
|
if (isDataUIMessageChunk(chunk)) {
|
|
if ((dataPartSchemas == null ? void 0 : dataPartSchemas[chunk.type]) != null) {
|
|
await (0, import_provider_utils11.validateTypes)({
|
|
value: chunk.data,
|
|
schema: dataPartSchemas[chunk.type]
|
|
});
|
|
}
|
|
const dataChunk = chunk;
|
|
if (dataChunk.transient) {
|
|
onData == null ? void 0 : onData(dataChunk);
|
|
break;
|
|
}
|
|
const existingUIPart = dataChunk.id != null ? state.message.parts.find(
|
|
(chunkArg) => dataChunk.type === chunkArg.type && dataChunk.id === chunkArg.id
|
|
) : void 0;
|
|
if (existingUIPart != null) {
|
|
existingUIPart.data = dataChunk.data;
|
|
} else {
|
|
state.message.parts.push(dataChunk);
|
|
}
|
|
onData == null ? void 0 : onData(dataChunk);
|
|
write();
|
|
}
|
|
}
|
|
}
|
|
controller.enqueue(chunk);
|
|
});
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
// src/ui-message-stream/handle-ui-message-stream-finish.ts
|
|
function handleUIMessageStreamFinish({
|
|
messageId,
|
|
originalMessages = [],
|
|
onFinish,
|
|
onError,
|
|
stream
|
|
}) {
|
|
let lastMessage = originalMessages == null ? void 0 : originalMessages[originalMessages.length - 1];
|
|
if ((lastMessage == null ? void 0 : lastMessage.role) !== "assistant") {
|
|
lastMessage = void 0;
|
|
} else {
|
|
messageId = lastMessage.id;
|
|
}
|
|
let isAborted = false;
|
|
const idInjectedStream = stream.pipeThrough(
|
|
new TransformStream({
|
|
transform(chunk, controller) {
|
|
if (chunk.type === "start") {
|
|
const startChunk = chunk;
|
|
if (startChunk.messageId == null && messageId != null) {
|
|
startChunk.messageId = messageId;
|
|
}
|
|
}
|
|
if (chunk.type === "abort") {
|
|
isAborted = true;
|
|
}
|
|
controller.enqueue(chunk);
|
|
}
|
|
})
|
|
);
|
|
if (onFinish == null) {
|
|
return idInjectedStream;
|
|
}
|
|
const state = createStreamingUIMessageState({
|
|
lastMessage: lastMessage ? structuredClone(lastMessage) : void 0,
|
|
messageId: messageId != null ? messageId : ""
|
|
// will be overridden by the stream
|
|
});
|
|
const runUpdateMessageJob = async (job) => {
|
|
await job({ state, write: () => {
|
|
} });
|
|
};
|
|
return processUIMessageStream({
|
|
stream: idInjectedStream,
|
|
runUpdateMessageJob,
|
|
onError
|
|
}).pipeThrough(
|
|
new TransformStream({
|
|
transform(chunk, controller) {
|
|
controller.enqueue(chunk);
|
|
},
|
|
async flush() {
|
|
const isContinuation = state.message.id === (lastMessage == null ? void 0 : lastMessage.id);
|
|
await onFinish({
|
|
isAborted,
|
|
isContinuation,
|
|
responseMessage: state.message,
|
|
messages: [
|
|
...isContinuation ? originalMessages.slice(0, -1) : originalMessages,
|
|
state.message
|
|
]
|
|
});
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
// src/ui-message-stream/pipe-ui-message-stream-to-response.ts
|
|
function pipeUIMessageStreamToResponse({
|
|
response,
|
|
status,
|
|
statusText,
|
|
headers,
|
|
stream,
|
|
consumeSseStream
|
|
}) {
|
|
let sseStream = stream.pipeThrough(new JsonToSseTransformStream());
|
|
if (consumeSseStream) {
|
|
const [stream1, stream2] = sseStream.tee();
|
|
sseStream = stream1;
|
|
consumeSseStream({ stream: stream2 });
|
|
}
|
|
writeToServerResponse({
|
|
response,
|
|
status,
|
|
statusText,
|
|
headers: Object.fromEntries(
|
|
prepareHeaders(headers, UI_MESSAGE_STREAM_HEADERS).entries()
|
|
),
|
|
stream: sseStream.pipeThrough(new TextEncoderStream())
|
|
});
|
|
}
|
|
|
|
// src/util/async-iterable-stream.ts
|
|
function createAsyncIterableStream(source) {
|
|
const stream = source.pipeThrough(new TransformStream());
|
|
stream[Symbol.asyncIterator] = () => {
|
|
const reader = stream.getReader();
|
|
return {
|
|
async next() {
|
|
const { done, value } = await reader.read();
|
|
return done ? { done: true, value: void 0 } : { done: false, value };
|
|
}
|
|
};
|
|
};
|
|
return stream;
|
|
}
|
|
|
|
// src/util/consume-stream.ts
|
|
async function consumeStream({
|
|
stream,
|
|
onError
|
|
}) {
|
|
const reader = stream.getReader();
|
|
try {
|
|
while (true) {
|
|
const { done } = await reader.read();
|
|
if (done)
|
|
break;
|
|
}
|
|
} catch (error) {
|
|
onError == null ? void 0 : onError(error);
|
|
} finally {
|
|
reader.releaseLock();
|
|
}
|
|
}
|
|
|
|
// src/util/create-resolvable-promise.ts
|
|
function createResolvablePromise() {
|
|
let resolve2;
|
|
let reject;
|
|
const promise = new Promise((res, rej) => {
|
|
resolve2 = res;
|
|
reject = rej;
|
|
});
|
|
return {
|
|
promise,
|
|
resolve: resolve2,
|
|
reject
|
|
};
|
|
}
|
|
|
|
// src/util/create-stitchable-stream.ts
|
|
function createStitchableStream() {
|
|
let innerStreamReaders = [];
|
|
let controller = null;
|
|
let isClosed = false;
|
|
let waitForNewStream = createResolvablePromise();
|
|
const terminate = () => {
|
|
isClosed = true;
|
|
waitForNewStream.resolve();
|
|
innerStreamReaders.forEach((reader) => reader.cancel());
|
|
innerStreamReaders = [];
|
|
controller == null ? void 0 : controller.close();
|
|
};
|
|
const processPull = async () => {
|
|
if (isClosed && innerStreamReaders.length === 0) {
|
|
controller == null ? void 0 : controller.close();
|
|
return;
|
|
}
|
|
if (innerStreamReaders.length === 0) {
|
|
waitForNewStream = createResolvablePromise();
|
|
await waitForNewStream.promise;
|
|
return processPull();
|
|
}
|
|
try {
|
|
const { value, done } = await innerStreamReaders[0].read();
|
|
if (done) {
|
|
innerStreamReaders.shift();
|
|
if (innerStreamReaders.length > 0) {
|
|
await processPull();
|
|
} else if (isClosed) {
|
|
controller == null ? void 0 : controller.close();
|
|
}
|
|
} else {
|
|
controller == null ? void 0 : controller.enqueue(value);
|
|
}
|
|
} catch (error) {
|
|
controller == null ? void 0 : controller.error(error);
|
|
innerStreamReaders.shift();
|
|
terminate();
|
|
}
|
|
};
|
|
return {
|
|
stream: new ReadableStream({
|
|
start(controllerParam) {
|
|
controller = controllerParam;
|
|
},
|
|
pull: processPull,
|
|
async cancel() {
|
|
for (const reader of innerStreamReaders) {
|
|
await reader.cancel();
|
|
}
|
|
innerStreamReaders = [];
|
|
isClosed = true;
|
|
}
|
|
}),
|
|
addStream: (innerStream) => {
|
|
if (isClosed) {
|
|
throw new Error("Cannot add inner stream: outer stream is closed");
|
|
}
|
|
innerStreamReaders.push(innerStream.getReader());
|
|
waitForNewStream.resolve();
|
|
},
|
|
/**
|
|
* Gracefully close the outer stream. This will let the inner streams
|
|
* finish processing and then close the outer stream.
|
|
*/
|
|
close: () => {
|
|
isClosed = true;
|
|
waitForNewStream.resolve();
|
|
if (innerStreamReaders.length === 0) {
|
|
controller == null ? void 0 : controller.close();
|
|
}
|
|
},
|
|
/**
|
|
* Immediately close the outer stream. This will cancel all inner streams
|
|
* and close the outer stream.
|
|
*/
|
|
terminate
|
|
};
|
|
}
|
|
|
|
// src/util/delayed-promise.ts
|
|
var DelayedPromise = class {
|
|
constructor() {
|
|
this.status = { type: "pending" };
|
|
this._resolve = void 0;
|
|
this._reject = void 0;
|
|
}
|
|
get promise() {
|
|
if (this._promise) {
|
|
return this._promise;
|
|
}
|
|
this._promise = new Promise((resolve2, reject) => {
|
|
if (this.status.type === "resolved") {
|
|
resolve2(this.status.value);
|
|
} else if (this.status.type === "rejected") {
|
|
reject(this.status.error);
|
|
}
|
|
this._resolve = resolve2;
|
|
this._reject = reject;
|
|
});
|
|
return this._promise;
|
|
}
|
|
resolve(value) {
|
|
var _a17;
|
|
this.status = { type: "resolved", value };
|
|
if (this._promise) {
|
|
(_a17 = this._resolve) == null ? void 0 : _a17.call(this, value);
|
|
}
|
|
}
|
|
reject(error) {
|
|
var _a17;
|
|
this.status = { type: "rejected", error };
|
|
if (this._promise) {
|
|
(_a17 = this._reject) == null ? void 0 : _a17.call(this, error);
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/util/filter-stream-errors.ts
|
|
function filterStreamErrors(readable, onError) {
|
|
return new ReadableStream({
|
|
async start(controller) {
|
|
const reader = readable.getReader();
|
|
try {
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done) {
|
|
controller.close();
|
|
break;
|
|
}
|
|
controller.enqueue(value);
|
|
}
|
|
} catch (error) {
|
|
await onError({ error, controller });
|
|
}
|
|
},
|
|
cancel(reason) {
|
|
return readable.cancel(reason);
|
|
}
|
|
});
|
|
}
|
|
|
|
// src/util/now.ts
|
|
function now() {
|
|
var _a17, _b;
|
|
return (_b = (_a17 = globalThis == null ? void 0 : globalThis.performance) == null ? void 0 : _a17.now()) != null ? _b : Date.now();
|
|
}
|
|
|
|
// src/generate-text/run-tools-transformation.ts
|
|
var import_provider_utils12 = require("@ai-sdk/provider-utils");
|
|
function runToolsTransformation({
|
|
tools,
|
|
generatorStream,
|
|
tracer,
|
|
telemetry,
|
|
system,
|
|
messages,
|
|
abortSignal,
|
|
repairToolCall,
|
|
experimental_context
|
|
}) {
|
|
let toolResultsStreamController = null;
|
|
const toolResultsStream = new ReadableStream({
|
|
start(controller) {
|
|
toolResultsStreamController = controller;
|
|
}
|
|
});
|
|
const outstandingToolResults = /* @__PURE__ */ new Set();
|
|
const toolInputs = /* @__PURE__ */ new Map();
|
|
let canClose = false;
|
|
let finishChunk = void 0;
|
|
function attemptClose() {
|
|
if (canClose && outstandingToolResults.size === 0) {
|
|
if (finishChunk != null) {
|
|
toolResultsStreamController.enqueue(finishChunk);
|
|
}
|
|
toolResultsStreamController.close();
|
|
}
|
|
}
|
|
const forwardStream = new TransformStream({
|
|
async transform(chunk, controller) {
|
|
const chunkType = chunk.type;
|
|
switch (chunkType) {
|
|
case "stream-start":
|
|
case "text-start":
|
|
case "text-delta":
|
|
case "text-end":
|
|
case "reasoning-start":
|
|
case "reasoning-delta":
|
|
case "reasoning-end":
|
|
case "tool-input-start":
|
|
case "tool-input-delta":
|
|
case "tool-input-end":
|
|
case "source":
|
|
case "response-metadata":
|
|
case "error":
|
|
case "raw": {
|
|
controller.enqueue(chunk);
|
|
break;
|
|
}
|
|
case "file": {
|
|
controller.enqueue({
|
|
type: "file",
|
|
file: new DefaultGeneratedFileWithType({
|
|
data: chunk.data,
|
|
mediaType: chunk.mediaType
|
|
})
|
|
});
|
|
break;
|
|
}
|
|
case "finish": {
|
|
finishChunk = {
|
|
type: "finish",
|
|
finishReason: chunk.finishReason,
|
|
usage: chunk.usage,
|
|
providerMetadata: chunk.providerMetadata
|
|
};
|
|
break;
|
|
}
|
|
case "tool-call": {
|
|
try {
|
|
const toolCall = await parseToolCall({
|
|
toolCall: chunk,
|
|
tools,
|
|
repairToolCall,
|
|
system,
|
|
messages
|
|
});
|
|
controller.enqueue(toolCall);
|
|
if (toolCall.invalid) {
|
|
toolResultsStreamController.enqueue({
|
|
type: "tool-error",
|
|
toolCallId: toolCall.toolCallId,
|
|
toolName: toolCall.toolName,
|
|
input: toolCall.input,
|
|
error: (0, import_provider_utils12.getErrorMessage)(toolCall.error),
|
|
dynamic: true
|
|
});
|
|
break;
|
|
}
|
|
const tool3 = tools[toolCall.toolName];
|
|
toolInputs.set(toolCall.toolCallId, toolCall.input);
|
|
if (tool3.onInputAvailable != null) {
|
|
await tool3.onInputAvailable({
|
|
input: toolCall.input,
|
|
toolCallId: toolCall.toolCallId,
|
|
messages,
|
|
abortSignal,
|
|
experimental_context
|
|
});
|
|
}
|
|
if (tool3.execute != null && toolCall.providerExecuted !== true) {
|
|
const toolExecutionId = (0, import_provider_utils12.generateId)();
|
|
outstandingToolResults.add(toolExecutionId);
|
|
recordSpan({
|
|
name: "ai.toolCall",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.toolCall",
|
|
telemetry
|
|
}),
|
|
"ai.toolCall.name": toolCall.toolName,
|
|
"ai.toolCall.id": toolCall.toolCallId,
|
|
"ai.toolCall.args": {
|
|
output: () => JSON.stringify(toolCall.input)
|
|
}
|
|
}
|
|
}),
|
|
tracer,
|
|
fn: async (span) => {
|
|
let output;
|
|
try {
|
|
const stream = (0, import_provider_utils12.executeTool)({
|
|
execute: tool3.execute.bind(tool3),
|
|
input: toolCall.input,
|
|
options: {
|
|
toolCallId: toolCall.toolCallId,
|
|
messages,
|
|
abortSignal,
|
|
experimental_context
|
|
}
|
|
});
|
|
for await (const part of stream) {
|
|
toolResultsStreamController.enqueue({
|
|
...toolCall,
|
|
type: "tool-result",
|
|
output: part.output,
|
|
...part.type === "preliminary" && {
|
|
preliminary: true
|
|
}
|
|
});
|
|
if (part.type === "final") {
|
|
output = part.output;
|
|
}
|
|
}
|
|
} catch (error) {
|
|
recordErrorOnSpan(span, error);
|
|
toolResultsStreamController.enqueue({
|
|
...toolCall,
|
|
type: "tool-error",
|
|
error
|
|
});
|
|
outstandingToolResults.delete(toolExecutionId);
|
|
attemptClose();
|
|
return;
|
|
}
|
|
outstandingToolResults.delete(toolExecutionId);
|
|
attemptClose();
|
|
try {
|
|
span.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.toolCall.result": {
|
|
output: () => JSON.stringify(output)
|
|
}
|
|
}
|
|
})
|
|
);
|
|
} catch (ignored) {
|
|
}
|
|
}
|
|
});
|
|
}
|
|
} catch (error) {
|
|
toolResultsStreamController.enqueue({ type: "error", error });
|
|
}
|
|
break;
|
|
}
|
|
case "tool-result": {
|
|
const toolName = chunk.toolName;
|
|
if (chunk.isError) {
|
|
toolResultsStreamController.enqueue({
|
|
type: "tool-error",
|
|
toolCallId: chunk.toolCallId,
|
|
toolName,
|
|
input: toolInputs.get(chunk.toolCallId),
|
|
providerExecuted: chunk.providerExecuted,
|
|
error: chunk.result
|
|
});
|
|
} else {
|
|
controller.enqueue({
|
|
type: "tool-result",
|
|
toolCallId: chunk.toolCallId,
|
|
toolName,
|
|
input: toolInputs.get(chunk.toolCallId),
|
|
output: chunk.result,
|
|
providerExecuted: chunk.providerExecuted
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
const _exhaustiveCheck = chunkType;
|
|
throw new Error(`Unhandled chunk type: ${_exhaustiveCheck}`);
|
|
}
|
|
}
|
|
},
|
|
flush() {
|
|
canClose = true;
|
|
attemptClose();
|
|
}
|
|
});
|
|
return new ReadableStream({
|
|
async start(controller) {
|
|
return Promise.all([
|
|
generatorStream.pipeThrough(forwardStream).pipeTo(
|
|
new WritableStream({
|
|
write(chunk) {
|
|
controller.enqueue(chunk);
|
|
},
|
|
close() {
|
|
}
|
|
})
|
|
),
|
|
toolResultsStream.pipeTo(
|
|
new WritableStream({
|
|
write(chunk) {
|
|
controller.enqueue(chunk);
|
|
},
|
|
close() {
|
|
controller.close();
|
|
}
|
|
})
|
|
)
|
|
]);
|
|
}
|
|
});
|
|
}
|
|
|
|
// src/generate-text/stream-text.ts
|
|
var originalGenerateId2 = (0, import_provider_utils13.createIdGenerator)({
|
|
prefix: "aitxt",
|
|
size: 24
|
|
});
|
|
function streamText({
|
|
model,
|
|
tools,
|
|
toolChoice,
|
|
system,
|
|
prompt,
|
|
messages,
|
|
maxRetries,
|
|
abortSignal,
|
|
headers,
|
|
stopWhen = stepCountIs(1),
|
|
experimental_output: output,
|
|
experimental_telemetry: telemetry,
|
|
prepareStep,
|
|
providerOptions,
|
|
experimental_activeTools,
|
|
activeTools = experimental_activeTools,
|
|
experimental_repairToolCall: repairToolCall,
|
|
experimental_transform: transform,
|
|
includeRawChunks = false,
|
|
onChunk,
|
|
onError = ({ error }) => {
|
|
console.error(error);
|
|
},
|
|
onFinish,
|
|
onAbort,
|
|
onStepFinish,
|
|
experimental_context,
|
|
_internal: {
|
|
now: now2 = now,
|
|
generateId: generateId3 = originalGenerateId2,
|
|
currentDate = () => /* @__PURE__ */ new Date()
|
|
} = {},
|
|
...settings
|
|
}) {
|
|
return new DefaultStreamTextResult({
|
|
model: resolveLanguageModel(model),
|
|
telemetry,
|
|
headers,
|
|
settings,
|
|
maxRetries,
|
|
abortSignal,
|
|
system,
|
|
prompt,
|
|
messages,
|
|
tools,
|
|
toolChoice,
|
|
transforms: asArray(transform),
|
|
activeTools,
|
|
repairToolCall,
|
|
stopConditions: asArray(stopWhen),
|
|
output,
|
|
providerOptions,
|
|
prepareStep,
|
|
includeRawChunks,
|
|
onChunk,
|
|
onError,
|
|
onFinish,
|
|
onAbort,
|
|
onStepFinish,
|
|
now: now2,
|
|
currentDate,
|
|
generateId: generateId3,
|
|
experimental_context
|
|
});
|
|
}
|
|
function createOutputTransformStream(output) {
|
|
if (!output) {
|
|
return new TransformStream({
|
|
transform(chunk, controller) {
|
|
controller.enqueue({ part: chunk, partialOutput: void 0 });
|
|
}
|
|
});
|
|
}
|
|
let firstTextChunkId = void 0;
|
|
let text2 = "";
|
|
let textChunk = "";
|
|
let lastPublishedJson = "";
|
|
function publishTextChunk({
|
|
controller,
|
|
partialOutput = void 0
|
|
}) {
|
|
controller.enqueue({
|
|
part: {
|
|
type: "text-delta",
|
|
id: firstTextChunkId,
|
|
text: textChunk
|
|
},
|
|
partialOutput
|
|
});
|
|
textChunk = "";
|
|
}
|
|
return new TransformStream({
|
|
async transform(chunk, controller) {
|
|
if (chunk.type === "finish-step" && textChunk.length > 0) {
|
|
publishTextChunk({ controller });
|
|
}
|
|
if (chunk.type !== "text-delta" && chunk.type !== "text-start" && chunk.type !== "text-end") {
|
|
controller.enqueue({ part: chunk, partialOutput: void 0 });
|
|
return;
|
|
}
|
|
if (firstTextChunkId == null) {
|
|
firstTextChunkId = chunk.id;
|
|
} else if (chunk.id !== firstTextChunkId) {
|
|
controller.enqueue({ part: chunk, partialOutput: void 0 });
|
|
return;
|
|
}
|
|
if (chunk.type === "text-start") {
|
|
controller.enqueue({ part: chunk, partialOutput: void 0 });
|
|
return;
|
|
}
|
|
if (chunk.type === "text-end") {
|
|
if (textChunk.length > 0) {
|
|
publishTextChunk({ controller });
|
|
}
|
|
controller.enqueue({ part: chunk, partialOutput: void 0 });
|
|
return;
|
|
}
|
|
text2 += chunk.text;
|
|
textChunk += chunk.text;
|
|
const result = await output.parsePartial({ text: text2 });
|
|
if (result != null) {
|
|
const currentJson = JSON.stringify(result.partial);
|
|
if (currentJson !== lastPublishedJson) {
|
|
publishTextChunk({ controller, partialOutput: result.partial });
|
|
lastPublishedJson = currentJson;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
var DefaultStreamTextResult = class {
|
|
constructor({
|
|
model,
|
|
telemetry,
|
|
headers,
|
|
settings,
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal,
|
|
system,
|
|
prompt,
|
|
messages,
|
|
tools,
|
|
toolChoice,
|
|
transforms,
|
|
activeTools,
|
|
repairToolCall,
|
|
stopConditions,
|
|
output,
|
|
providerOptions,
|
|
prepareStep,
|
|
includeRawChunks,
|
|
now: now2,
|
|
currentDate,
|
|
generateId: generateId3,
|
|
onChunk,
|
|
onError,
|
|
onFinish,
|
|
onAbort,
|
|
onStepFinish,
|
|
experimental_context
|
|
}) {
|
|
this._totalUsage = new DelayedPromise();
|
|
this._finishReason = new DelayedPromise();
|
|
this._steps = new DelayedPromise();
|
|
this.output = output;
|
|
this.includeRawChunks = includeRawChunks;
|
|
this.tools = tools;
|
|
let stepFinish;
|
|
let recordedContent = [];
|
|
const recordedResponseMessages = [];
|
|
let recordedFinishReason = void 0;
|
|
let recordedTotalUsage = void 0;
|
|
let recordedRequest = {};
|
|
let recordedWarnings = [];
|
|
const recordedSteps = [];
|
|
let rootSpan;
|
|
let activeTextContent = {};
|
|
let activeReasoningContent = {};
|
|
const eventProcessor = new TransformStream({
|
|
async transform(chunk, controller) {
|
|
var _a17, _b, _c;
|
|
controller.enqueue(chunk);
|
|
const { part } = chunk;
|
|
if (part.type === "text-delta" || part.type === "reasoning-delta" || part.type === "source" || part.type === "tool-call" || part.type === "tool-result" || part.type === "tool-input-start" || part.type === "tool-input-delta" || part.type === "raw") {
|
|
await (onChunk == null ? void 0 : onChunk({ chunk: part }));
|
|
}
|
|
if (part.type === "error") {
|
|
await onError({ error: wrapGatewayError(part.error) });
|
|
}
|
|
if (part.type === "text-start") {
|
|
activeTextContent[part.id] = {
|
|
type: "text",
|
|
text: "",
|
|
providerMetadata: part.providerMetadata
|
|
};
|
|
recordedContent.push(activeTextContent[part.id]);
|
|
}
|
|
if (part.type === "text-delta") {
|
|
const activeText = activeTextContent[part.id];
|
|
if (activeText == null) {
|
|
controller.enqueue({
|
|
part: {
|
|
type: "error",
|
|
error: `text part ${part.id} not found`
|
|
},
|
|
partialOutput: void 0
|
|
});
|
|
return;
|
|
}
|
|
activeText.text += part.text;
|
|
activeText.providerMetadata = (_a17 = part.providerMetadata) != null ? _a17 : activeText.providerMetadata;
|
|
}
|
|
if (part.type === "text-end") {
|
|
delete activeTextContent[part.id];
|
|
}
|
|
if (part.type === "reasoning-start") {
|
|
activeReasoningContent[part.id] = {
|
|
type: "reasoning",
|
|
text: "",
|
|
providerMetadata: part.providerMetadata
|
|
};
|
|
recordedContent.push(activeReasoningContent[part.id]);
|
|
}
|
|
if (part.type === "reasoning-delta") {
|
|
const activeReasoning = activeReasoningContent[part.id];
|
|
if (activeReasoning == null) {
|
|
controller.enqueue({
|
|
part: {
|
|
type: "error",
|
|
error: `reasoning part ${part.id} not found`
|
|
},
|
|
partialOutput: void 0
|
|
});
|
|
return;
|
|
}
|
|
activeReasoning.text += part.text;
|
|
activeReasoning.providerMetadata = (_b = part.providerMetadata) != null ? _b : activeReasoning.providerMetadata;
|
|
}
|
|
if (part.type === "reasoning-end") {
|
|
const activeReasoning = activeReasoningContent[part.id];
|
|
if (activeReasoning == null) {
|
|
controller.enqueue({
|
|
part: {
|
|
type: "error",
|
|
error: `reasoning part ${part.id} not found`
|
|
},
|
|
partialOutput: void 0
|
|
});
|
|
return;
|
|
}
|
|
activeReasoning.providerMetadata = (_c = part.providerMetadata) != null ? _c : activeReasoning.providerMetadata;
|
|
delete activeReasoningContent[part.id];
|
|
}
|
|
if (part.type === "file") {
|
|
recordedContent.push({ type: "file", file: part.file });
|
|
}
|
|
if (part.type === "source") {
|
|
recordedContent.push(part);
|
|
}
|
|
if (part.type === "tool-call") {
|
|
recordedContent.push(part);
|
|
}
|
|
if (part.type === "tool-result" && !part.preliminary) {
|
|
recordedContent.push(part);
|
|
}
|
|
if (part.type === "tool-error") {
|
|
recordedContent.push(part);
|
|
}
|
|
if (part.type === "start-step") {
|
|
recordedRequest = part.request;
|
|
recordedWarnings = part.warnings;
|
|
}
|
|
if (part.type === "finish-step") {
|
|
const stepMessages = toResponseMessages({
|
|
content: recordedContent,
|
|
tools
|
|
});
|
|
const currentStepResult = new DefaultStepResult({
|
|
content: recordedContent,
|
|
finishReason: part.finishReason,
|
|
usage: part.usage,
|
|
warnings: recordedWarnings,
|
|
request: recordedRequest,
|
|
response: {
|
|
...part.response,
|
|
messages: [...recordedResponseMessages, ...stepMessages]
|
|
},
|
|
providerMetadata: part.providerMetadata
|
|
});
|
|
await (onStepFinish == null ? void 0 : onStepFinish(currentStepResult));
|
|
recordedSteps.push(currentStepResult);
|
|
recordedContent = [];
|
|
activeReasoningContent = {};
|
|
activeTextContent = {};
|
|
recordedResponseMessages.push(...stepMessages);
|
|
stepFinish.resolve();
|
|
}
|
|
if (part.type === "finish") {
|
|
recordedTotalUsage = part.totalUsage;
|
|
recordedFinishReason = part.finishReason;
|
|
}
|
|
},
|
|
async flush(controller) {
|
|
try {
|
|
if (recordedSteps.length === 0) {
|
|
const error = new NoOutputGeneratedError({
|
|
message: "No output generated. Check the stream for errors."
|
|
});
|
|
self._finishReason.reject(error);
|
|
self._totalUsage.reject(error);
|
|
self._steps.reject(error);
|
|
return;
|
|
}
|
|
const finishReason = recordedFinishReason != null ? recordedFinishReason : "unknown";
|
|
const totalUsage = recordedTotalUsage != null ? recordedTotalUsage : {
|
|
inputTokens: void 0,
|
|
outputTokens: void 0,
|
|
totalTokens: void 0
|
|
};
|
|
self._finishReason.resolve(finishReason);
|
|
self._totalUsage.resolve(totalUsage);
|
|
self._steps.resolve(recordedSteps);
|
|
const finalStep = recordedSteps[recordedSteps.length - 1];
|
|
await (onFinish == null ? void 0 : onFinish({
|
|
finishReason,
|
|
totalUsage,
|
|
usage: finalStep.usage,
|
|
content: finalStep.content,
|
|
text: finalStep.text,
|
|
reasoningText: finalStep.reasoningText,
|
|
reasoning: finalStep.reasoning,
|
|
files: finalStep.files,
|
|
sources: finalStep.sources,
|
|
toolCalls: finalStep.toolCalls,
|
|
staticToolCalls: finalStep.staticToolCalls,
|
|
dynamicToolCalls: finalStep.dynamicToolCalls,
|
|
toolResults: finalStep.toolResults,
|
|
staticToolResults: finalStep.staticToolResults,
|
|
dynamicToolResults: finalStep.dynamicToolResults,
|
|
request: finalStep.request,
|
|
response: finalStep.response,
|
|
warnings: finalStep.warnings,
|
|
providerMetadata: finalStep.providerMetadata,
|
|
steps: recordedSteps
|
|
}));
|
|
rootSpan.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.response.finishReason": finishReason,
|
|
"ai.response.text": { output: () => finalStep.text },
|
|
"ai.response.toolCalls": {
|
|
output: () => {
|
|
var _a17;
|
|
return ((_a17 = finalStep.toolCalls) == null ? void 0 : _a17.length) ? JSON.stringify(finalStep.toolCalls) : void 0;
|
|
}
|
|
},
|
|
"ai.response.providerMetadata": JSON.stringify(
|
|
finalStep.providerMetadata
|
|
),
|
|
"ai.usage.inputTokens": totalUsage.inputTokens,
|
|
"ai.usage.outputTokens": totalUsage.outputTokens,
|
|
"ai.usage.totalTokens": totalUsage.totalTokens,
|
|
"ai.usage.reasoningTokens": totalUsage.reasoningTokens,
|
|
"ai.usage.cachedInputTokens": totalUsage.cachedInputTokens
|
|
}
|
|
})
|
|
);
|
|
} catch (error) {
|
|
controller.error(error);
|
|
} finally {
|
|
rootSpan.end();
|
|
}
|
|
}
|
|
});
|
|
const stitchableStream = createStitchableStream();
|
|
this.addStream = stitchableStream.addStream;
|
|
this.closeStream = stitchableStream.close;
|
|
let stream = stitchableStream.stream;
|
|
stream = filterStreamErrors(stream, ({ error, controller }) => {
|
|
if ((0, import_provider_utils13.isAbortError)(error) && (abortSignal == null ? void 0 : abortSignal.aborted)) {
|
|
onAbort == null ? void 0 : onAbort({ steps: recordedSteps });
|
|
controller.enqueue({ type: "abort" });
|
|
controller.close();
|
|
} else {
|
|
controller.error(error);
|
|
}
|
|
});
|
|
stream = stream.pipeThrough(
|
|
new TransformStream({
|
|
start(controller) {
|
|
controller.enqueue({ type: "start" });
|
|
}
|
|
})
|
|
);
|
|
for (const transform of transforms) {
|
|
stream = stream.pipeThrough(
|
|
transform({
|
|
tools,
|
|
stopStream() {
|
|
stitchableStream.terminate();
|
|
}
|
|
})
|
|
);
|
|
}
|
|
this.baseStream = stream.pipeThrough(createOutputTransformStream(output)).pipeThrough(eventProcessor);
|
|
const { maxRetries, retry } = prepareRetries({
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal
|
|
});
|
|
const tracer = getTracer(telemetry);
|
|
const callSettings = prepareCallSettings(settings);
|
|
const baseTelemetryAttributes = getBaseTelemetryAttributes({
|
|
model,
|
|
telemetry,
|
|
headers,
|
|
settings: { ...callSettings, maxRetries }
|
|
});
|
|
const self = this;
|
|
recordSpan({
|
|
name: "ai.streamText",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({ operationId: "ai.streamText", telemetry }),
|
|
...baseTelemetryAttributes,
|
|
// specific settings that only make sense on the outer level:
|
|
"ai.prompt": {
|
|
input: () => JSON.stringify({ system, prompt, messages })
|
|
}
|
|
}
|
|
}),
|
|
tracer,
|
|
endWhenDone: false,
|
|
fn: async (rootSpanArg) => {
|
|
rootSpan = rootSpanArg;
|
|
async function streamStep({
|
|
currentStep,
|
|
responseMessages,
|
|
usage
|
|
}) {
|
|
var _a17, _b, _c, _d, _e;
|
|
const includeRawChunks2 = self.includeRawChunks;
|
|
stepFinish = new DelayedPromise();
|
|
const initialPrompt = await standardizePrompt({
|
|
system,
|
|
prompt,
|
|
messages
|
|
});
|
|
const stepInputMessages = [
|
|
...initialPrompt.messages,
|
|
...responseMessages
|
|
];
|
|
const prepareStepResult = await (prepareStep == null ? void 0 : prepareStep({
|
|
model,
|
|
steps: recordedSteps,
|
|
stepNumber: recordedSteps.length,
|
|
messages: stepInputMessages
|
|
}));
|
|
const promptMessages = await convertToLanguageModelPrompt({
|
|
prompt: {
|
|
system: (_a17 = prepareStepResult == null ? void 0 : prepareStepResult.system) != null ? _a17 : initialPrompt.system,
|
|
messages: (_b = prepareStepResult == null ? void 0 : prepareStepResult.messages) != null ? _b : stepInputMessages
|
|
},
|
|
supportedUrls: await model.supportedUrls
|
|
});
|
|
const stepModel = resolveLanguageModel(
|
|
(_c = prepareStepResult == null ? void 0 : prepareStepResult.model) != null ? _c : model
|
|
);
|
|
const { toolChoice: stepToolChoice, tools: stepTools } = prepareToolsAndToolChoice({
|
|
tools,
|
|
toolChoice: (_d = prepareStepResult == null ? void 0 : prepareStepResult.toolChoice) != null ? _d : toolChoice,
|
|
activeTools: (_e = prepareStepResult == null ? void 0 : prepareStepResult.activeTools) != null ? _e : activeTools
|
|
});
|
|
const {
|
|
result: { stream: stream2, response, request },
|
|
doStreamSpan,
|
|
startTimestampMs
|
|
} = await retry(
|
|
() => recordSpan({
|
|
name: "ai.streamText.doStream",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.streamText.doStream",
|
|
telemetry
|
|
}),
|
|
...baseTelemetryAttributes,
|
|
// model:
|
|
"ai.model.provider": stepModel.provider,
|
|
"ai.model.id": stepModel.modelId,
|
|
// prompt:
|
|
"ai.prompt.messages": {
|
|
input: () => stringifyForTelemetry(promptMessages)
|
|
},
|
|
"ai.prompt.tools": {
|
|
// convert the language model level tools:
|
|
input: () => stepTools == null ? void 0 : stepTools.map((tool3) => JSON.stringify(tool3))
|
|
},
|
|
"ai.prompt.toolChoice": {
|
|
input: () => stepToolChoice != null ? JSON.stringify(stepToolChoice) : void 0
|
|
},
|
|
// standardized gen-ai llm span attributes:
|
|
"gen_ai.system": stepModel.provider,
|
|
"gen_ai.request.model": stepModel.modelId,
|
|
"gen_ai.request.frequency_penalty": callSettings.frequencyPenalty,
|
|
"gen_ai.request.max_tokens": callSettings.maxOutputTokens,
|
|
"gen_ai.request.presence_penalty": callSettings.presencePenalty,
|
|
"gen_ai.request.stop_sequences": callSettings.stopSequences,
|
|
"gen_ai.request.temperature": callSettings.temperature,
|
|
"gen_ai.request.top_k": callSettings.topK,
|
|
"gen_ai.request.top_p": callSettings.topP
|
|
}
|
|
}),
|
|
tracer,
|
|
endWhenDone: false,
|
|
fn: async (doStreamSpan2) => {
|
|
return {
|
|
startTimestampMs: now2(),
|
|
// get before the call
|
|
doStreamSpan: doStreamSpan2,
|
|
result: await stepModel.doStream({
|
|
...callSettings,
|
|
tools: stepTools,
|
|
toolChoice: stepToolChoice,
|
|
responseFormat: output == null ? void 0 : output.responseFormat,
|
|
prompt: promptMessages,
|
|
providerOptions,
|
|
abortSignal,
|
|
headers,
|
|
includeRawChunks: includeRawChunks2
|
|
})
|
|
};
|
|
}
|
|
})
|
|
);
|
|
const streamWithToolResults = runToolsTransformation({
|
|
tools,
|
|
generatorStream: stream2,
|
|
tracer,
|
|
telemetry,
|
|
system,
|
|
messages: stepInputMessages,
|
|
repairToolCall,
|
|
abortSignal,
|
|
experimental_context
|
|
});
|
|
const stepRequest = request != null ? request : {};
|
|
const stepToolCalls = [];
|
|
const stepToolOutputs = [];
|
|
let warnings;
|
|
const activeToolCallToolNames = {};
|
|
let stepFinishReason = "unknown";
|
|
let stepUsage = {
|
|
inputTokens: void 0,
|
|
outputTokens: void 0,
|
|
totalTokens: void 0
|
|
};
|
|
let stepProviderMetadata;
|
|
let stepFirstChunk = true;
|
|
let stepResponse = {
|
|
id: generateId3(),
|
|
timestamp: currentDate(),
|
|
modelId: model.modelId
|
|
};
|
|
let activeText = "";
|
|
self.addStream(
|
|
streamWithToolResults.pipeThrough(
|
|
new TransformStream({
|
|
async transform(chunk, controller) {
|
|
var _a18, _b2, _c2, _d2;
|
|
if (chunk.type === "stream-start") {
|
|
warnings = chunk.warnings;
|
|
return;
|
|
}
|
|
if (stepFirstChunk) {
|
|
const msToFirstChunk = now2() - startTimestampMs;
|
|
stepFirstChunk = false;
|
|
doStreamSpan.addEvent("ai.stream.firstChunk", {
|
|
"ai.response.msToFirstChunk": msToFirstChunk
|
|
});
|
|
doStreamSpan.setAttributes({
|
|
"ai.response.msToFirstChunk": msToFirstChunk
|
|
});
|
|
controller.enqueue({
|
|
type: "start-step",
|
|
request: stepRequest,
|
|
warnings: warnings != null ? warnings : []
|
|
});
|
|
}
|
|
const chunkType = chunk.type;
|
|
switch (chunkType) {
|
|
case "text-start":
|
|
case "text-end": {
|
|
controller.enqueue(chunk);
|
|
break;
|
|
}
|
|
case "text-delta": {
|
|
if (chunk.delta.length > 0) {
|
|
controller.enqueue({
|
|
type: "text-delta",
|
|
id: chunk.id,
|
|
text: chunk.delta,
|
|
providerMetadata: chunk.providerMetadata
|
|
});
|
|
activeText += chunk.delta;
|
|
}
|
|
break;
|
|
}
|
|
case "reasoning-start":
|
|
case "reasoning-end": {
|
|
controller.enqueue(chunk);
|
|
break;
|
|
}
|
|
case "reasoning-delta": {
|
|
controller.enqueue({
|
|
type: "reasoning-delta",
|
|
id: chunk.id,
|
|
text: chunk.delta,
|
|
providerMetadata: chunk.providerMetadata
|
|
});
|
|
break;
|
|
}
|
|
case "tool-call": {
|
|
controller.enqueue(chunk);
|
|
stepToolCalls.push(chunk);
|
|
break;
|
|
}
|
|
case "tool-result": {
|
|
controller.enqueue(chunk);
|
|
if (!chunk.preliminary) {
|
|
stepToolOutputs.push(chunk);
|
|
}
|
|
break;
|
|
}
|
|
case "tool-error": {
|
|
controller.enqueue(chunk);
|
|
stepToolOutputs.push(chunk);
|
|
break;
|
|
}
|
|
case "response-metadata": {
|
|
stepResponse = {
|
|
id: (_a18 = chunk.id) != null ? _a18 : stepResponse.id,
|
|
timestamp: (_b2 = chunk.timestamp) != null ? _b2 : stepResponse.timestamp,
|
|
modelId: (_c2 = chunk.modelId) != null ? _c2 : stepResponse.modelId
|
|
};
|
|
break;
|
|
}
|
|
case "finish": {
|
|
stepUsage = chunk.usage;
|
|
stepFinishReason = chunk.finishReason;
|
|
stepProviderMetadata = chunk.providerMetadata;
|
|
const msToFinish = now2() - startTimestampMs;
|
|
doStreamSpan.addEvent("ai.stream.finish");
|
|
doStreamSpan.setAttributes({
|
|
"ai.response.msToFinish": msToFinish,
|
|
"ai.response.avgOutputTokensPerSecond": 1e3 * ((_d2 = stepUsage.outputTokens) != null ? _d2 : 0) / msToFinish
|
|
});
|
|
break;
|
|
}
|
|
case "file": {
|
|
controller.enqueue(chunk);
|
|
break;
|
|
}
|
|
case "source": {
|
|
controller.enqueue(chunk);
|
|
break;
|
|
}
|
|
case "tool-input-start": {
|
|
activeToolCallToolNames[chunk.id] = chunk.toolName;
|
|
const tool3 = tools == null ? void 0 : tools[chunk.toolName];
|
|
if ((tool3 == null ? void 0 : tool3.onInputStart) != null) {
|
|
await tool3.onInputStart({
|
|
toolCallId: chunk.id,
|
|
messages: stepInputMessages,
|
|
abortSignal,
|
|
experimental_context
|
|
});
|
|
}
|
|
controller.enqueue({
|
|
...chunk,
|
|
dynamic: (tool3 == null ? void 0 : tool3.type) === "dynamic"
|
|
});
|
|
break;
|
|
}
|
|
case "tool-input-end": {
|
|
delete activeToolCallToolNames[chunk.id];
|
|
controller.enqueue(chunk);
|
|
break;
|
|
}
|
|
case "tool-input-delta": {
|
|
const toolName = activeToolCallToolNames[chunk.id];
|
|
const tool3 = tools == null ? void 0 : tools[toolName];
|
|
if ((tool3 == null ? void 0 : tool3.onInputDelta) != null) {
|
|
await tool3.onInputDelta({
|
|
inputTextDelta: chunk.delta,
|
|
toolCallId: chunk.id,
|
|
messages: stepInputMessages,
|
|
abortSignal,
|
|
experimental_context
|
|
});
|
|
}
|
|
controller.enqueue(chunk);
|
|
break;
|
|
}
|
|
case "error": {
|
|
controller.enqueue(chunk);
|
|
stepFinishReason = "error";
|
|
break;
|
|
}
|
|
case "raw": {
|
|
if (includeRawChunks2) {
|
|
controller.enqueue(chunk);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
const exhaustiveCheck = chunkType;
|
|
throw new Error(`Unknown chunk type: ${exhaustiveCheck}`);
|
|
}
|
|
}
|
|
},
|
|
// invoke onFinish callback and resolve toolResults promise when the stream is about to close:
|
|
async flush(controller) {
|
|
const stepToolCallsJson = stepToolCalls.length > 0 ? JSON.stringify(stepToolCalls) : void 0;
|
|
try {
|
|
doStreamSpan.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.response.finishReason": stepFinishReason,
|
|
"ai.response.text": {
|
|
output: () => activeText
|
|
},
|
|
"ai.response.toolCalls": {
|
|
output: () => stepToolCallsJson
|
|
},
|
|
"ai.response.id": stepResponse.id,
|
|
"ai.response.model": stepResponse.modelId,
|
|
"ai.response.timestamp": stepResponse.timestamp.toISOString(),
|
|
"ai.response.providerMetadata": JSON.stringify(stepProviderMetadata),
|
|
"ai.usage.inputTokens": stepUsage.inputTokens,
|
|
"ai.usage.outputTokens": stepUsage.outputTokens,
|
|
"ai.usage.totalTokens": stepUsage.totalTokens,
|
|
"ai.usage.reasoningTokens": stepUsage.reasoningTokens,
|
|
"ai.usage.cachedInputTokens": stepUsage.cachedInputTokens,
|
|
// standardized gen-ai llm span attributes:
|
|
"gen_ai.response.finish_reasons": [stepFinishReason],
|
|
"gen_ai.response.id": stepResponse.id,
|
|
"gen_ai.response.model": stepResponse.modelId,
|
|
"gen_ai.usage.input_tokens": stepUsage.inputTokens,
|
|
"gen_ai.usage.output_tokens": stepUsage.outputTokens
|
|
}
|
|
})
|
|
);
|
|
} catch (error) {
|
|
} finally {
|
|
doStreamSpan.end();
|
|
}
|
|
controller.enqueue({
|
|
type: "finish-step",
|
|
finishReason: stepFinishReason,
|
|
usage: stepUsage,
|
|
providerMetadata: stepProviderMetadata,
|
|
response: {
|
|
...stepResponse,
|
|
headers: response == null ? void 0 : response.headers
|
|
}
|
|
});
|
|
const combinedUsage = addLanguageModelUsage(usage, stepUsage);
|
|
await stepFinish.promise;
|
|
const clientToolCalls = stepToolCalls.filter(
|
|
(toolCall) => toolCall.providerExecuted !== true
|
|
);
|
|
const clientToolOutputs = stepToolOutputs.filter(
|
|
(toolOutput) => toolOutput.providerExecuted !== true
|
|
);
|
|
if (clientToolCalls.length > 0 && // all current tool calls have outputs (incl. execution errors):
|
|
clientToolOutputs.length === clientToolCalls.length && // continue until a stop condition is met:
|
|
!await isStopConditionMet({
|
|
stopConditions,
|
|
steps: recordedSteps
|
|
})) {
|
|
responseMessages.push(
|
|
...toResponseMessages({
|
|
content: (
|
|
// use transformed content to create the messages for the next step:
|
|
recordedSteps[recordedSteps.length - 1].content
|
|
),
|
|
tools
|
|
})
|
|
);
|
|
try {
|
|
await streamStep({
|
|
currentStep: currentStep + 1,
|
|
responseMessages,
|
|
usage: combinedUsage
|
|
});
|
|
} catch (error) {
|
|
controller.enqueue({
|
|
type: "error",
|
|
error
|
|
});
|
|
self.closeStream();
|
|
}
|
|
} else {
|
|
controller.enqueue({
|
|
type: "finish",
|
|
finishReason: stepFinishReason,
|
|
totalUsage: combinedUsage
|
|
});
|
|
self.closeStream();
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
}
|
|
await streamStep({
|
|
currentStep: 0,
|
|
responseMessages: [],
|
|
usage: {
|
|
inputTokens: void 0,
|
|
outputTokens: void 0,
|
|
totalTokens: void 0
|
|
}
|
|
});
|
|
}
|
|
}).catch((error) => {
|
|
self.addStream(
|
|
new ReadableStream({
|
|
start(controller) {
|
|
controller.enqueue({ type: "error", error });
|
|
controller.close();
|
|
}
|
|
})
|
|
);
|
|
self.closeStream();
|
|
});
|
|
}
|
|
get steps() {
|
|
this.consumeStream();
|
|
return this._steps.promise;
|
|
}
|
|
get finalStep() {
|
|
return this.steps.then((steps) => steps[steps.length - 1]);
|
|
}
|
|
get content() {
|
|
return this.finalStep.then((step) => step.content);
|
|
}
|
|
get warnings() {
|
|
return this.finalStep.then((step) => step.warnings);
|
|
}
|
|
get providerMetadata() {
|
|
return this.finalStep.then((step) => step.providerMetadata);
|
|
}
|
|
get text() {
|
|
return this.finalStep.then((step) => step.text);
|
|
}
|
|
get reasoningText() {
|
|
return this.finalStep.then((step) => step.reasoningText);
|
|
}
|
|
get reasoning() {
|
|
return this.finalStep.then((step) => step.reasoning);
|
|
}
|
|
get sources() {
|
|
return this.finalStep.then((step) => step.sources);
|
|
}
|
|
get files() {
|
|
return this.finalStep.then((step) => step.files);
|
|
}
|
|
get toolCalls() {
|
|
return this.finalStep.then((step) => step.toolCalls);
|
|
}
|
|
get staticToolCalls() {
|
|
return this.finalStep.then((step) => step.staticToolCalls);
|
|
}
|
|
get dynamicToolCalls() {
|
|
return this.finalStep.then((step) => step.dynamicToolCalls);
|
|
}
|
|
get toolResults() {
|
|
return this.finalStep.then((step) => step.toolResults);
|
|
}
|
|
get staticToolResults() {
|
|
return this.finalStep.then((step) => step.staticToolResults);
|
|
}
|
|
get dynamicToolResults() {
|
|
return this.finalStep.then((step) => step.dynamicToolResults);
|
|
}
|
|
get usage() {
|
|
return this.finalStep.then((step) => step.usage);
|
|
}
|
|
get request() {
|
|
return this.finalStep.then((step) => step.request);
|
|
}
|
|
get response() {
|
|
return this.finalStep.then((step) => step.response);
|
|
}
|
|
get totalUsage() {
|
|
this.consumeStream();
|
|
return this._totalUsage.promise;
|
|
}
|
|
get finishReason() {
|
|
this.consumeStream();
|
|
return this._finishReason.promise;
|
|
}
|
|
/**
|
|
Split out a new stream from the original stream.
|
|
The original stream is replaced to allow for further splitting,
|
|
since we do not know how many times the stream will be split.
|
|
|
|
Note: this leads to buffering the stream content on the server.
|
|
However, the LLM results are expected to be small enough to not cause issues.
|
|
*/
|
|
teeStream() {
|
|
const [stream1, stream2] = this.baseStream.tee();
|
|
this.baseStream = stream2;
|
|
return stream1;
|
|
}
|
|
get textStream() {
|
|
return createAsyncIterableStream(
|
|
this.teeStream().pipeThrough(
|
|
new TransformStream({
|
|
transform({ part }, controller) {
|
|
if (part.type === "text-delta") {
|
|
controller.enqueue(part.text);
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
}
|
|
get fullStream() {
|
|
return createAsyncIterableStream(
|
|
this.teeStream().pipeThrough(
|
|
new TransformStream({
|
|
transform({ part }, controller) {
|
|
controller.enqueue(part);
|
|
}
|
|
})
|
|
)
|
|
);
|
|
}
|
|
async consumeStream(options) {
|
|
var _a17;
|
|
try {
|
|
await consumeStream({
|
|
stream: this.fullStream,
|
|
onError: options == null ? void 0 : options.onError
|
|
});
|
|
} catch (error) {
|
|
(_a17 = options == null ? void 0 : options.onError) == null ? void 0 : _a17.call(options, error);
|
|
}
|
|
}
|
|
get experimental_partialOutputStream() {
|
|
if (this.output == null) {
|
|
throw new NoOutputSpecifiedError();
|
|
}
|
|
return createAsyncIterableStream(
|
|
this.teeStream().pipeThrough(
|
|
new TransformStream({
|
|
transform({ partialOutput }, controller) {
|
|
if (partialOutput != null) {
|
|
controller.enqueue(partialOutput);
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
}
|
|
toUIMessageStream({
|
|
originalMessages,
|
|
generateMessageId,
|
|
onFinish,
|
|
messageMetadata,
|
|
sendReasoning = true,
|
|
sendSources = false,
|
|
sendStart = true,
|
|
sendFinish = true,
|
|
onError = import_provider23.getErrorMessage
|
|
} = {}) {
|
|
const responseMessageId = generateMessageId != null ? getResponseUIMessageId({
|
|
originalMessages,
|
|
responseMessageId: generateMessageId
|
|
}) : void 0;
|
|
const toolNamesByCallId = {};
|
|
const isDynamic = (toolCallId) => {
|
|
var _a17, _b;
|
|
const toolName = toolNamesByCallId[toolCallId];
|
|
const dynamic = ((_b = (_a17 = this.tools) == null ? void 0 : _a17[toolName]) == null ? void 0 : _b.type) === "dynamic";
|
|
return dynamic ? true : void 0;
|
|
};
|
|
const baseStream = this.fullStream.pipeThrough(
|
|
new TransformStream({
|
|
transform: async (part, controller) => {
|
|
const messageMetadataValue = messageMetadata == null ? void 0 : messageMetadata({ part });
|
|
const partType = part.type;
|
|
switch (partType) {
|
|
case "text-start": {
|
|
controller.enqueue({
|
|
type: "text-start",
|
|
id: part.id,
|
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
});
|
|
break;
|
|
}
|
|
case "text-delta": {
|
|
controller.enqueue({
|
|
type: "text-delta",
|
|
id: part.id,
|
|
delta: part.text,
|
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
});
|
|
break;
|
|
}
|
|
case "text-end": {
|
|
controller.enqueue({
|
|
type: "text-end",
|
|
id: part.id,
|
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
});
|
|
break;
|
|
}
|
|
case "reasoning-start": {
|
|
controller.enqueue({
|
|
type: "reasoning-start",
|
|
id: part.id,
|
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
});
|
|
break;
|
|
}
|
|
case "reasoning-delta": {
|
|
if (sendReasoning) {
|
|
controller.enqueue({
|
|
type: "reasoning-delta",
|
|
id: part.id,
|
|
delta: part.text,
|
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "reasoning-end": {
|
|
controller.enqueue({
|
|
type: "reasoning-end",
|
|
id: part.id,
|
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
});
|
|
break;
|
|
}
|
|
case "file": {
|
|
controller.enqueue({
|
|
type: "file",
|
|
mediaType: part.file.mediaType,
|
|
url: `data:${part.file.mediaType};base64,${part.file.base64}`
|
|
});
|
|
break;
|
|
}
|
|
case "source": {
|
|
if (sendSources && part.sourceType === "url") {
|
|
controller.enqueue({
|
|
type: "source-url",
|
|
sourceId: part.id,
|
|
url: part.url,
|
|
title: part.title,
|
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
});
|
|
}
|
|
if (sendSources && part.sourceType === "document") {
|
|
controller.enqueue({
|
|
type: "source-document",
|
|
sourceId: part.id,
|
|
mediaType: part.mediaType,
|
|
title: part.title,
|
|
filename: part.filename,
|
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {}
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "tool-input-start": {
|
|
toolNamesByCallId[part.id] = part.toolName;
|
|
const dynamic = isDynamic(part.id);
|
|
controller.enqueue({
|
|
type: "tool-input-start",
|
|
toolCallId: part.id,
|
|
toolName: part.toolName,
|
|
...part.providerExecuted != null ? { providerExecuted: part.providerExecuted } : {},
|
|
...dynamic != null ? { dynamic } : {}
|
|
});
|
|
break;
|
|
}
|
|
case "tool-input-delta": {
|
|
controller.enqueue({
|
|
type: "tool-input-delta",
|
|
toolCallId: part.id,
|
|
inputTextDelta: part.delta
|
|
});
|
|
break;
|
|
}
|
|
case "tool-call": {
|
|
toolNamesByCallId[part.toolCallId] = part.toolName;
|
|
const dynamic = isDynamic(part.toolCallId);
|
|
if (part.invalid) {
|
|
controller.enqueue({
|
|
type: "tool-input-error",
|
|
toolCallId: part.toolCallId,
|
|
toolName: part.toolName,
|
|
input: part.input,
|
|
...part.providerExecuted != null ? { providerExecuted: part.providerExecuted } : {},
|
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {},
|
|
...dynamic != null ? { dynamic } : {},
|
|
errorText: onError(part.error)
|
|
});
|
|
} else {
|
|
controller.enqueue({
|
|
type: "tool-input-available",
|
|
toolCallId: part.toolCallId,
|
|
toolName: part.toolName,
|
|
input: part.input,
|
|
...part.providerExecuted != null ? { providerExecuted: part.providerExecuted } : {},
|
|
...part.providerMetadata != null ? { providerMetadata: part.providerMetadata } : {},
|
|
...dynamic != null ? { dynamic } : {}
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "tool-result": {
|
|
const dynamic = isDynamic(part.toolCallId);
|
|
controller.enqueue({
|
|
type: "tool-output-available",
|
|
toolCallId: part.toolCallId,
|
|
output: part.output,
|
|
...part.providerExecuted != null ? { providerExecuted: part.providerExecuted } : {},
|
|
...part.preliminary != null ? { preliminary: part.preliminary } : {},
|
|
...dynamic != null ? { dynamic } : {}
|
|
});
|
|
break;
|
|
}
|
|
case "tool-error": {
|
|
const dynamic = isDynamic(part.toolCallId);
|
|
controller.enqueue({
|
|
type: "tool-output-error",
|
|
toolCallId: part.toolCallId,
|
|
errorText: onError(part.error),
|
|
...part.providerExecuted != null ? { providerExecuted: part.providerExecuted } : {},
|
|
...dynamic != null ? { dynamic } : {}
|
|
});
|
|
break;
|
|
}
|
|
case "error": {
|
|
controller.enqueue({
|
|
type: "error",
|
|
errorText: onError(part.error)
|
|
});
|
|
break;
|
|
}
|
|
case "start-step": {
|
|
controller.enqueue({ type: "start-step" });
|
|
break;
|
|
}
|
|
case "finish-step": {
|
|
controller.enqueue({ type: "finish-step" });
|
|
break;
|
|
}
|
|
case "start": {
|
|
if (sendStart) {
|
|
controller.enqueue({
|
|
type: "start",
|
|
...messageMetadataValue != null ? { messageMetadata: messageMetadataValue } : {},
|
|
...responseMessageId != null ? { messageId: responseMessageId } : {}
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "finish": {
|
|
if (sendFinish) {
|
|
controller.enqueue({
|
|
type: "finish",
|
|
...messageMetadataValue != null ? { messageMetadata: messageMetadataValue } : {}
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case "abort": {
|
|
controller.enqueue(part);
|
|
break;
|
|
}
|
|
case "tool-input-end": {
|
|
break;
|
|
}
|
|
case "raw": {
|
|
break;
|
|
}
|
|
default: {
|
|
const exhaustiveCheck = partType;
|
|
throw new Error(`Unknown chunk type: ${exhaustiveCheck}`);
|
|
}
|
|
}
|
|
if (messageMetadataValue != null && partType !== "start" && partType !== "finish") {
|
|
controller.enqueue({
|
|
type: "message-metadata",
|
|
messageMetadata: messageMetadataValue
|
|
});
|
|
}
|
|
}
|
|
})
|
|
);
|
|
return createAsyncIterableStream(
|
|
handleUIMessageStreamFinish({
|
|
stream: baseStream,
|
|
messageId: responseMessageId != null ? responseMessageId : generateMessageId == null ? void 0 : generateMessageId(),
|
|
originalMessages,
|
|
onFinish,
|
|
onError
|
|
})
|
|
);
|
|
}
|
|
pipeUIMessageStreamToResponse(response, {
|
|
originalMessages,
|
|
generateMessageId,
|
|
onFinish,
|
|
messageMetadata,
|
|
sendReasoning,
|
|
sendSources,
|
|
sendFinish,
|
|
sendStart,
|
|
onError,
|
|
...init
|
|
} = {}) {
|
|
pipeUIMessageStreamToResponse({
|
|
response,
|
|
stream: this.toUIMessageStream({
|
|
originalMessages,
|
|
generateMessageId,
|
|
onFinish,
|
|
messageMetadata,
|
|
sendReasoning,
|
|
sendSources,
|
|
sendFinish,
|
|
sendStart,
|
|
onError
|
|
}),
|
|
...init
|
|
});
|
|
}
|
|
pipeTextStreamToResponse(response, init) {
|
|
pipeTextStreamToResponse({
|
|
response,
|
|
textStream: this.textStream,
|
|
...init
|
|
});
|
|
}
|
|
toUIMessageStreamResponse({
|
|
originalMessages,
|
|
generateMessageId,
|
|
onFinish,
|
|
messageMetadata,
|
|
sendReasoning,
|
|
sendSources,
|
|
sendFinish,
|
|
sendStart,
|
|
onError,
|
|
...init
|
|
} = {}) {
|
|
return createUIMessageStreamResponse({
|
|
stream: this.toUIMessageStream({
|
|
originalMessages,
|
|
generateMessageId,
|
|
onFinish,
|
|
messageMetadata,
|
|
sendReasoning,
|
|
sendSources,
|
|
sendFinish,
|
|
sendStart,
|
|
onError
|
|
}),
|
|
...init
|
|
});
|
|
}
|
|
toTextStreamResponse(init) {
|
|
return createTextStreamResponse({
|
|
textStream: this.textStream,
|
|
...init
|
|
});
|
|
}
|
|
};
|
|
|
|
// src/agent/agent.ts
|
|
var Agent = class {
|
|
constructor(settings) {
|
|
this.settings = settings;
|
|
}
|
|
async generate(options) {
|
|
return generateText({ ...this.settings, ...options });
|
|
}
|
|
stream(options) {
|
|
return streamText({ ...this.settings, ...options });
|
|
}
|
|
};
|
|
|
|
// src/embed/embed.ts
|
|
async function embed({
|
|
model: modelArg,
|
|
value,
|
|
providerOptions,
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal,
|
|
headers,
|
|
experimental_telemetry: telemetry
|
|
}) {
|
|
const model = resolveEmbeddingModel(modelArg);
|
|
const { maxRetries, retry } = prepareRetries({
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal
|
|
});
|
|
const baseTelemetryAttributes = getBaseTelemetryAttributes({
|
|
model,
|
|
telemetry,
|
|
headers,
|
|
settings: { maxRetries }
|
|
});
|
|
const tracer = getTracer(telemetry);
|
|
return recordSpan({
|
|
name: "ai.embed",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({ operationId: "ai.embed", telemetry }),
|
|
...baseTelemetryAttributes,
|
|
"ai.value": { input: () => JSON.stringify(value) }
|
|
}
|
|
}),
|
|
tracer,
|
|
fn: async (span) => {
|
|
const { embedding, usage, response, providerMetadata } = await retry(
|
|
() => (
|
|
// nested spans to align with the embedMany telemetry data:
|
|
recordSpan({
|
|
name: "ai.embed.doEmbed",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.embed.doEmbed",
|
|
telemetry
|
|
}),
|
|
...baseTelemetryAttributes,
|
|
// specific settings that only make sense on the outer level:
|
|
"ai.values": { input: () => [JSON.stringify(value)] }
|
|
}
|
|
}),
|
|
tracer,
|
|
fn: async (doEmbedSpan) => {
|
|
var _a17;
|
|
const modelResponse = await model.doEmbed({
|
|
values: [value],
|
|
abortSignal,
|
|
headers,
|
|
providerOptions
|
|
});
|
|
const embedding2 = modelResponse.embeddings[0];
|
|
const usage2 = (_a17 = modelResponse.usage) != null ? _a17 : { tokens: NaN };
|
|
doEmbedSpan.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.embeddings": {
|
|
output: () => modelResponse.embeddings.map(
|
|
(embedding3) => JSON.stringify(embedding3)
|
|
)
|
|
},
|
|
"ai.usage.tokens": usage2.tokens
|
|
}
|
|
})
|
|
);
|
|
return {
|
|
embedding: embedding2,
|
|
usage: usage2,
|
|
providerMetadata: modelResponse.providerMetadata,
|
|
response: modelResponse.response
|
|
};
|
|
}
|
|
})
|
|
)
|
|
);
|
|
span.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.embedding": { output: () => JSON.stringify(embedding) },
|
|
"ai.usage.tokens": usage.tokens
|
|
}
|
|
})
|
|
);
|
|
return new DefaultEmbedResult({
|
|
value,
|
|
embedding,
|
|
usage,
|
|
providerMetadata,
|
|
response
|
|
});
|
|
}
|
|
});
|
|
}
|
|
var DefaultEmbedResult = class {
|
|
constructor(options) {
|
|
this.value = options.value;
|
|
this.embedding = options.embedding;
|
|
this.usage = options.usage;
|
|
this.providerMetadata = options.providerMetadata;
|
|
this.response = options.response;
|
|
}
|
|
};
|
|
|
|
// src/util/split-array.ts
|
|
function splitArray(array, chunkSize) {
|
|
if (chunkSize <= 0) {
|
|
throw new Error("chunkSize must be greater than 0");
|
|
}
|
|
const result = [];
|
|
for (let i = 0; i < array.length; i += chunkSize) {
|
|
result.push(array.slice(i, i + chunkSize));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// src/embed/embed-many.ts
|
|
async function embedMany({
|
|
model: modelArg,
|
|
values,
|
|
maxParallelCalls = Infinity,
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal,
|
|
headers,
|
|
providerOptions,
|
|
experimental_telemetry: telemetry
|
|
}) {
|
|
const model = resolveEmbeddingModel(modelArg);
|
|
const { maxRetries, retry } = prepareRetries({
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal
|
|
});
|
|
const baseTelemetryAttributes = getBaseTelemetryAttributes({
|
|
model,
|
|
telemetry,
|
|
headers,
|
|
settings: { maxRetries }
|
|
});
|
|
const tracer = getTracer(telemetry);
|
|
return recordSpan({
|
|
name: "ai.embedMany",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({ operationId: "ai.embedMany", telemetry }),
|
|
...baseTelemetryAttributes,
|
|
// specific settings that only make sense on the outer level:
|
|
"ai.values": {
|
|
input: () => values.map((value) => JSON.stringify(value))
|
|
}
|
|
}
|
|
}),
|
|
tracer,
|
|
fn: async (span) => {
|
|
var _a17;
|
|
const [maxEmbeddingsPerCall, supportsParallelCalls] = await Promise.all([
|
|
model.maxEmbeddingsPerCall,
|
|
model.supportsParallelCalls
|
|
]);
|
|
if (maxEmbeddingsPerCall == null || maxEmbeddingsPerCall === Infinity) {
|
|
const { embeddings: embeddings2, usage, response, providerMetadata: providerMetadata2 } = await retry(
|
|
() => {
|
|
return recordSpan({
|
|
name: "ai.embedMany.doEmbed",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.embedMany.doEmbed",
|
|
telemetry
|
|
}),
|
|
...baseTelemetryAttributes,
|
|
// specific settings that only make sense on the outer level:
|
|
"ai.values": {
|
|
input: () => values.map((value) => JSON.stringify(value))
|
|
}
|
|
}
|
|
}),
|
|
tracer,
|
|
fn: async (doEmbedSpan) => {
|
|
var _a18;
|
|
const modelResponse = await model.doEmbed({
|
|
values,
|
|
abortSignal,
|
|
headers,
|
|
providerOptions
|
|
});
|
|
const embeddings3 = modelResponse.embeddings;
|
|
const usage2 = (_a18 = modelResponse.usage) != null ? _a18 : { tokens: NaN };
|
|
doEmbedSpan.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.embeddings": {
|
|
output: () => embeddings3.map(
|
|
(embedding) => JSON.stringify(embedding)
|
|
)
|
|
},
|
|
"ai.usage.tokens": usage2.tokens
|
|
}
|
|
})
|
|
);
|
|
return {
|
|
embeddings: embeddings3,
|
|
usage: usage2,
|
|
providerMetadata: modelResponse.providerMetadata,
|
|
response: modelResponse.response
|
|
};
|
|
}
|
|
});
|
|
}
|
|
);
|
|
span.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.embeddings": {
|
|
output: () => embeddings2.map((embedding) => JSON.stringify(embedding))
|
|
},
|
|
"ai.usage.tokens": usage.tokens
|
|
}
|
|
})
|
|
);
|
|
return new DefaultEmbedManyResult({
|
|
values,
|
|
embeddings: embeddings2,
|
|
usage,
|
|
providerMetadata: providerMetadata2,
|
|
responses: [response]
|
|
});
|
|
}
|
|
const valueChunks = splitArray(values, maxEmbeddingsPerCall);
|
|
const embeddings = [];
|
|
const responses = [];
|
|
let tokens = 0;
|
|
let providerMetadata;
|
|
const parallelChunks = splitArray(
|
|
valueChunks,
|
|
supportsParallelCalls ? maxParallelCalls : 1
|
|
);
|
|
for (const parallelChunk of parallelChunks) {
|
|
const results = await Promise.all(
|
|
parallelChunk.map((chunk) => {
|
|
return retry(() => {
|
|
return recordSpan({
|
|
name: "ai.embedMany.doEmbed",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.embedMany.doEmbed",
|
|
telemetry
|
|
}),
|
|
...baseTelemetryAttributes,
|
|
// specific settings that only make sense on the outer level:
|
|
"ai.values": {
|
|
input: () => chunk.map((value) => JSON.stringify(value))
|
|
}
|
|
}
|
|
}),
|
|
tracer,
|
|
fn: async (doEmbedSpan) => {
|
|
var _a18;
|
|
const modelResponse = await model.doEmbed({
|
|
values: chunk,
|
|
abortSignal,
|
|
headers,
|
|
providerOptions
|
|
});
|
|
const embeddings2 = modelResponse.embeddings;
|
|
const usage = (_a18 = modelResponse.usage) != null ? _a18 : { tokens: NaN };
|
|
doEmbedSpan.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.embeddings": {
|
|
output: () => embeddings2.map(
|
|
(embedding) => JSON.stringify(embedding)
|
|
)
|
|
},
|
|
"ai.usage.tokens": usage.tokens
|
|
}
|
|
})
|
|
);
|
|
return {
|
|
embeddings: embeddings2,
|
|
usage,
|
|
providerMetadata: modelResponse.providerMetadata,
|
|
response: modelResponse.response
|
|
};
|
|
}
|
|
});
|
|
});
|
|
})
|
|
);
|
|
for (const result of results) {
|
|
embeddings.push(...result.embeddings);
|
|
responses.push(result.response);
|
|
tokens += result.usage.tokens;
|
|
if (result.providerMetadata) {
|
|
if (!providerMetadata) {
|
|
providerMetadata = { ...result.providerMetadata };
|
|
} else {
|
|
for (const [providerName, metadata] of Object.entries(
|
|
result.providerMetadata
|
|
)) {
|
|
providerMetadata[providerName] = {
|
|
...(_a17 = providerMetadata[providerName]) != null ? _a17 : {},
|
|
...metadata
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
span.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.embeddings": {
|
|
output: () => embeddings.map((embedding) => JSON.stringify(embedding))
|
|
},
|
|
"ai.usage.tokens": tokens
|
|
}
|
|
})
|
|
);
|
|
return new DefaultEmbedManyResult({
|
|
values,
|
|
embeddings,
|
|
usage: { tokens },
|
|
providerMetadata,
|
|
responses
|
|
});
|
|
}
|
|
});
|
|
}
|
|
var DefaultEmbedManyResult = class {
|
|
constructor(options) {
|
|
this.values = options.values;
|
|
this.embeddings = options.embeddings;
|
|
this.usage = options.usage;
|
|
this.providerMetadata = options.providerMetadata;
|
|
this.responses = options.responses;
|
|
}
|
|
};
|
|
|
|
// src/generate-image/generate-image.ts
|
|
async function generateImage({
|
|
model,
|
|
prompt,
|
|
n = 1,
|
|
maxImagesPerCall,
|
|
size,
|
|
aspectRatio,
|
|
seed,
|
|
providerOptions,
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal,
|
|
headers
|
|
}) {
|
|
var _a17, _b;
|
|
if (model.specificationVersion !== "v2") {
|
|
throw new UnsupportedModelVersionError({
|
|
version: model.specificationVersion,
|
|
provider: model.provider,
|
|
modelId: model.modelId
|
|
});
|
|
}
|
|
const { retry } = prepareRetries({
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal
|
|
});
|
|
const maxImagesPerCallWithDefault = (_a17 = maxImagesPerCall != null ? maxImagesPerCall : await invokeModelMaxImagesPerCall(model)) != null ? _a17 : 1;
|
|
const callCount = Math.ceil(n / maxImagesPerCallWithDefault);
|
|
const callImageCounts = Array.from({ length: callCount }, (_, i) => {
|
|
if (i < callCount - 1) {
|
|
return maxImagesPerCallWithDefault;
|
|
}
|
|
const remainder = n % maxImagesPerCallWithDefault;
|
|
return remainder === 0 ? maxImagesPerCallWithDefault : remainder;
|
|
});
|
|
const results = await Promise.all(
|
|
callImageCounts.map(
|
|
async (callImageCount) => retry(
|
|
() => model.doGenerate({
|
|
prompt,
|
|
n: callImageCount,
|
|
abortSignal,
|
|
headers,
|
|
size,
|
|
aspectRatio,
|
|
seed,
|
|
providerOptions: providerOptions != null ? providerOptions : {}
|
|
})
|
|
)
|
|
)
|
|
);
|
|
const images = [];
|
|
const warnings = [];
|
|
const responses = [];
|
|
const providerMetadata = {};
|
|
for (const result of results) {
|
|
images.push(
|
|
...result.images.map(
|
|
(image) => {
|
|
var _a18;
|
|
return new DefaultGeneratedFile({
|
|
data: image,
|
|
mediaType: (_a18 = detectMediaType({
|
|
data: image,
|
|
signatures: imageMediaTypeSignatures
|
|
})) != null ? _a18 : "image/png"
|
|
});
|
|
}
|
|
)
|
|
);
|
|
warnings.push(...result.warnings);
|
|
if (result.providerMetadata) {
|
|
for (const [providerName, metadata] of Object.entries(result.providerMetadata)) {
|
|
(_b = providerMetadata[providerName]) != null ? _b : providerMetadata[providerName] = { images: [] };
|
|
providerMetadata[providerName].images.push(
|
|
...result.providerMetadata[providerName].images
|
|
);
|
|
}
|
|
}
|
|
responses.push(result.response);
|
|
}
|
|
if (!images.length) {
|
|
throw new NoImageGeneratedError({ responses });
|
|
}
|
|
return new DefaultGenerateImageResult({
|
|
images,
|
|
warnings,
|
|
responses,
|
|
providerMetadata
|
|
});
|
|
}
|
|
var DefaultGenerateImageResult = class {
|
|
constructor(options) {
|
|
this.images = options.images;
|
|
this.warnings = options.warnings;
|
|
this.responses = options.responses;
|
|
this.providerMetadata = options.providerMetadata;
|
|
}
|
|
get image() {
|
|
return this.images[0];
|
|
}
|
|
};
|
|
async function invokeModelMaxImagesPerCall(model) {
|
|
const isFunction = model.maxImagesPerCall instanceof Function;
|
|
if (!isFunction) {
|
|
return model.maxImagesPerCall;
|
|
}
|
|
return model.maxImagesPerCall({
|
|
modelId: model.modelId
|
|
});
|
|
}
|
|
|
|
// src/generate-object/generate-object.ts
|
|
var import_provider_utils16 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/generate-object/output-strategy.ts
|
|
var import_provider24 = require("@ai-sdk/provider");
|
|
var import_provider_utils14 = require("@ai-sdk/provider-utils");
|
|
var noSchemaOutputStrategy = {
|
|
type: "no-schema",
|
|
jsonSchema: void 0,
|
|
async validatePartialResult({ value, textDelta }) {
|
|
return { success: true, value: { partial: value, textDelta } };
|
|
},
|
|
async validateFinalResult(value, context) {
|
|
return value === void 0 ? {
|
|
success: false,
|
|
error: new NoObjectGeneratedError({
|
|
message: "No object generated: response did not match schema.",
|
|
text: context.text,
|
|
response: context.response,
|
|
usage: context.usage,
|
|
finishReason: context.finishReason
|
|
})
|
|
} : { success: true, value };
|
|
},
|
|
createElementStream() {
|
|
throw new import_provider24.UnsupportedFunctionalityError({
|
|
functionality: "element streams in no-schema mode"
|
|
});
|
|
}
|
|
};
|
|
var objectOutputStrategy = (schema) => ({
|
|
type: "object",
|
|
jsonSchema: schema.jsonSchema,
|
|
async validatePartialResult({ value, textDelta }) {
|
|
return {
|
|
success: true,
|
|
value: {
|
|
// Note: currently no validation of partial results:
|
|
partial: value,
|
|
textDelta
|
|
}
|
|
};
|
|
},
|
|
async validateFinalResult(value) {
|
|
return (0, import_provider_utils14.safeValidateTypes)({ value, schema });
|
|
},
|
|
createElementStream() {
|
|
throw new import_provider24.UnsupportedFunctionalityError({
|
|
functionality: "element streams in object mode"
|
|
});
|
|
}
|
|
});
|
|
var arrayOutputStrategy = (schema) => {
|
|
const { $schema, ...itemSchema } = schema.jsonSchema;
|
|
return {
|
|
type: "enum",
|
|
// wrap in object that contains array of elements, since most LLMs will not
|
|
// be able to generate an array directly:
|
|
// possible future optimization: use arrays directly when model supports grammar-guided generation
|
|
jsonSchema: {
|
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
type: "object",
|
|
properties: {
|
|
elements: { type: "array", items: itemSchema }
|
|
},
|
|
required: ["elements"],
|
|
additionalProperties: false
|
|
},
|
|
async validatePartialResult({
|
|
value,
|
|
latestObject,
|
|
isFirstDelta,
|
|
isFinalDelta
|
|
}) {
|
|
var _a17;
|
|
if (!(0, import_provider24.isJSONObject)(value) || !(0, import_provider24.isJSONArray)(value.elements)) {
|
|
return {
|
|
success: false,
|
|
error: new import_provider24.TypeValidationError({
|
|
value,
|
|
cause: "value must be an object that contains an array of elements"
|
|
})
|
|
};
|
|
}
|
|
const inputArray = value.elements;
|
|
const resultArray = [];
|
|
for (let i = 0; i < inputArray.length; i++) {
|
|
const element = inputArray[i];
|
|
const result = await (0, import_provider_utils14.safeValidateTypes)({ value: element, schema });
|
|
if (i === inputArray.length - 1 && !isFinalDelta) {
|
|
continue;
|
|
}
|
|
if (!result.success) {
|
|
return result;
|
|
}
|
|
resultArray.push(result.value);
|
|
}
|
|
const publishedElementCount = (_a17 = latestObject == null ? void 0 : latestObject.length) != null ? _a17 : 0;
|
|
let textDelta = "";
|
|
if (isFirstDelta) {
|
|
textDelta += "[";
|
|
}
|
|
if (publishedElementCount > 0) {
|
|
textDelta += ",";
|
|
}
|
|
textDelta += resultArray.slice(publishedElementCount).map((element) => JSON.stringify(element)).join(",");
|
|
if (isFinalDelta) {
|
|
textDelta += "]";
|
|
}
|
|
return {
|
|
success: true,
|
|
value: {
|
|
partial: resultArray,
|
|
textDelta
|
|
}
|
|
};
|
|
},
|
|
async validateFinalResult(value) {
|
|
if (!(0, import_provider24.isJSONObject)(value) || !(0, import_provider24.isJSONArray)(value.elements)) {
|
|
return {
|
|
success: false,
|
|
error: new import_provider24.TypeValidationError({
|
|
value,
|
|
cause: "value must be an object that contains an array of elements"
|
|
})
|
|
};
|
|
}
|
|
const inputArray = value.elements;
|
|
for (const element of inputArray) {
|
|
const result = await (0, import_provider_utils14.safeValidateTypes)({ value: element, schema });
|
|
if (!result.success) {
|
|
return result;
|
|
}
|
|
}
|
|
return { success: true, value: inputArray };
|
|
},
|
|
createElementStream(originalStream) {
|
|
let publishedElements = 0;
|
|
return createAsyncIterableStream(
|
|
originalStream.pipeThrough(
|
|
new TransformStream({
|
|
transform(chunk, controller) {
|
|
switch (chunk.type) {
|
|
case "object": {
|
|
const array = chunk.object;
|
|
for (; publishedElements < array.length; publishedElements++) {
|
|
controller.enqueue(array[publishedElements]);
|
|
}
|
|
break;
|
|
}
|
|
case "text-delta":
|
|
case "finish":
|
|
case "error":
|
|
break;
|
|
default: {
|
|
const _exhaustiveCheck = chunk;
|
|
throw new Error(
|
|
`Unsupported chunk type: ${_exhaustiveCheck}`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
}
|
|
};
|
|
};
|
|
var enumOutputStrategy = (enumValues) => {
|
|
return {
|
|
type: "enum",
|
|
// wrap in object that contains result, since most LLMs will not
|
|
// be able to generate an enum value directly:
|
|
// possible future optimization: use enums directly when model supports top-level enums
|
|
jsonSchema: {
|
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
type: "object",
|
|
properties: {
|
|
result: { type: "string", enum: enumValues }
|
|
},
|
|
required: ["result"],
|
|
additionalProperties: false
|
|
},
|
|
async validateFinalResult(value) {
|
|
if (!(0, import_provider24.isJSONObject)(value) || typeof value.result !== "string") {
|
|
return {
|
|
success: false,
|
|
error: new import_provider24.TypeValidationError({
|
|
value,
|
|
cause: 'value must be an object that contains a string in the "result" property.'
|
|
})
|
|
};
|
|
}
|
|
const result = value.result;
|
|
return enumValues.includes(result) ? { success: true, value: result } : {
|
|
success: false,
|
|
error: new import_provider24.TypeValidationError({
|
|
value,
|
|
cause: "value must be a string in the enum"
|
|
})
|
|
};
|
|
},
|
|
async validatePartialResult({ value, textDelta }) {
|
|
if (!(0, import_provider24.isJSONObject)(value) || typeof value.result !== "string") {
|
|
return {
|
|
success: false,
|
|
error: new import_provider24.TypeValidationError({
|
|
value,
|
|
cause: 'value must be an object that contains a string in the "result" property.'
|
|
})
|
|
};
|
|
}
|
|
const result = value.result;
|
|
const possibleEnumValues = enumValues.filter(
|
|
(enumValue) => enumValue.startsWith(result)
|
|
);
|
|
if (value.result.length === 0 || possibleEnumValues.length === 0) {
|
|
return {
|
|
success: false,
|
|
error: new import_provider24.TypeValidationError({
|
|
value,
|
|
cause: "value must be a string in the enum"
|
|
})
|
|
};
|
|
}
|
|
return {
|
|
success: true,
|
|
value: {
|
|
partial: possibleEnumValues.length > 1 ? result : possibleEnumValues[0],
|
|
textDelta
|
|
}
|
|
};
|
|
},
|
|
createElementStream() {
|
|
throw new import_provider24.UnsupportedFunctionalityError({
|
|
functionality: "element streams in enum mode"
|
|
});
|
|
}
|
|
};
|
|
};
|
|
function getOutputStrategy({
|
|
output,
|
|
schema,
|
|
enumValues
|
|
}) {
|
|
switch (output) {
|
|
case "object":
|
|
return objectOutputStrategy((0, import_provider_utils14.asSchema)(schema));
|
|
case "array":
|
|
return arrayOutputStrategy((0, import_provider_utils14.asSchema)(schema));
|
|
case "enum":
|
|
return enumOutputStrategy(enumValues);
|
|
case "no-schema":
|
|
return noSchemaOutputStrategy;
|
|
default: {
|
|
const _exhaustiveCheck = output;
|
|
throw new Error(`Unsupported output: ${_exhaustiveCheck}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// src/generate-object/parse-and-validate-object-result.ts
|
|
var import_provider25 = require("@ai-sdk/provider");
|
|
var import_provider_utils15 = require("@ai-sdk/provider-utils");
|
|
async function parseAndValidateObjectResult(result, outputStrategy, context) {
|
|
const parseResult = await (0, import_provider_utils15.safeParseJSON)({ text: result });
|
|
if (!parseResult.success) {
|
|
throw new NoObjectGeneratedError({
|
|
message: "No object generated: could not parse the response.",
|
|
cause: parseResult.error,
|
|
text: result,
|
|
response: context.response,
|
|
usage: context.usage,
|
|
finishReason: context.finishReason
|
|
});
|
|
}
|
|
const validationResult = await outputStrategy.validateFinalResult(
|
|
parseResult.value,
|
|
{
|
|
text: result,
|
|
response: context.response,
|
|
usage: context.usage
|
|
}
|
|
);
|
|
if (!validationResult.success) {
|
|
throw new NoObjectGeneratedError({
|
|
message: "No object generated: response did not match schema.",
|
|
cause: validationResult.error,
|
|
text: result,
|
|
response: context.response,
|
|
usage: context.usage,
|
|
finishReason: context.finishReason
|
|
});
|
|
}
|
|
return validationResult.value;
|
|
}
|
|
async function parseAndValidateObjectResultWithRepair(result, outputStrategy, repairText, context) {
|
|
try {
|
|
return await parseAndValidateObjectResult(result, outputStrategy, context);
|
|
} catch (error) {
|
|
if (repairText != null && NoObjectGeneratedError.isInstance(error) && (import_provider25.JSONParseError.isInstance(error.cause) || import_provider25.TypeValidationError.isInstance(error.cause))) {
|
|
const repairedText = await repairText({
|
|
text: result,
|
|
error: error.cause
|
|
});
|
|
if (repairedText === null) {
|
|
throw error;
|
|
}
|
|
return await parseAndValidateObjectResult(
|
|
repairedText,
|
|
outputStrategy,
|
|
context
|
|
);
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// src/generate-object/validate-object-generation-input.ts
|
|
function validateObjectGenerationInput({
|
|
output,
|
|
schema,
|
|
schemaName,
|
|
schemaDescription,
|
|
enumValues
|
|
}) {
|
|
if (output != null && output !== "object" && output !== "array" && output !== "enum" && output !== "no-schema") {
|
|
throw new InvalidArgumentError({
|
|
parameter: "output",
|
|
value: output,
|
|
message: "Invalid output type."
|
|
});
|
|
}
|
|
if (output === "no-schema") {
|
|
if (schema != null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "schema",
|
|
value: schema,
|
|
message: "Schema is not supported for no-schema output."
|
|
});
|
|
}
|
|
if (schemaDescription != null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "schemaDescription",
|
|
value: schemaDescription,
|
|
message: "Schema description is not supported for no-schema output."
|
|
});
|
|
}
|
|
if (schemaName != null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "schemaName",
|
|
value: schemaName,
|
|
message: "Schema name is not supported for no-schema output."
|
|
});
|
|
}
|
|
if (enumValues != null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "enumValues",
|
|
value: enumValues,
|
|
message: "Enum values are not supported for no-schema output."
|
|
});
|
|
}
|
|
}
|
|
if (output === "object") {
|
|
if (schema == null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "schema",
|
|
value: schema,
|
|
message: "Schema is required for object output."
|
|
});
|
|
}
|
|
if (enumValues != null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "enumValues",
|
|
value: enumValues,
|
|
message: "Enum values are not supported for object output."
|
|
});
|
|
}
|
|
}
|
|
if (output === "array") {
|
|
if (schema == null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "schema",
|
|
value: schema,
|
|
message: "Element schema is required for array output."
|
|
});
|
|
}
|
|
if (enumValues != null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "enumValues",
|
|
value: enumValues,
|
|
message: "Enum values are not supported for array output."
|
|
});
|
|
}
|
|
}
|
|
if (output === "enum") {
|
|
if (schema != null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "schema",
|
|
value: schema,
|
|
message: "Schema is not supported for enum output."
|
|
});
|
|
}
|
|
if (schemaDescription != null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "schemaDescription",
|
|
value: schemaDescription,
|
|
message: "Schema description is not supported for enum output."
|
|
});
|
|
}
|
|
if (schemaName != null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "schemaName",
|
|
value: schemaName,
|
|
message: "Schema name is not supported for enum output."
|
|
});
|
|
}
|
|
if (enumValues == null) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "enumValues",
|
|
value: enumValues,
|
|
message: "Enum values are required for enum output."
|
|
});
|
|
}
|
|
for (const value of enumValues) {
|
|
if (typeof value !== "string") {
|
|
throw new InvalidArgumentError({
|
|
parameter: "enumValues",
|
|
value,
|
|
message: "Enum values must be strings."
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// src/generate-object/generate-object.ts
|
|
var originalGenerateId3 = (0, import_provider_utils16.createIdGenerator)({ prefix: "aiobj", size: 24 });
|
|
async function generateObject(options) {
|
|
const {
|
|
model: modelArg,
|
|
output = "object",
|
|
system,
|
|
prompt,
|
|
messages,
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal,
|
|
headers,
|
|
experimental_repairText: repairText,
|
|
experimental_telemetry: telemetry,
|
|
providerOptions,
|
|
_internal: {
|
|
generateId: generateId3 = originalGenerateId3,
|
|
currentDate = () => /* @__PURE__ */ new Date()
|
|
} = {},
|
|
...settings
|
|
} = options;
|
|
const model = resolveLanguageModel(modelArg);
|
|
const enumValues = "enum" in options ? options.enum : void 0;
|
|
const {
|
|
schema: inputSchema,
|
|
schemaDescription,
|
|
schemaName
|
|
} = "schema" in options ? options : {};
|
|
validateObjectGenerationInput({
|
|
output,
|
|
schema: inputSchema,
|
|
schemaName,
|
|
schemaDescription,
|
|
enumValues
|
|
});
|
|
const { maxRetries, retry } = prepareRetries({
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal
|
|
});
|
|
const outputStrategy = getOutputStrategy({
|
|
output,
|
|
schema: inputSchema,
|
|
enumValues
|
|
});
|
|
const callSettings = prepareCallSettings(settings);
|
|
const baseTelemetryAttributes = getBaseTelemetryAttributes({
|
|
model,
|
|
telemetry,
|
|
headers,
|
|
settings: { ...callSettings, maxRetries }
|
|
});
|
|
const tracer = getTracer(telemetry);
|
|
try {
|
|
return await recordSpan({
|
|
name: "ai.generateObject",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.generateObject",
|
|
telemetry
|
|
}),
|
|
...baseTelemetryAttributes,
|
|
// specific settings that only make sense on the outer level:
|
|
"ai.prompt": {
|
|
input: () => JSON.stringify({ system, prompt, messages })
|
|
},
|
|
"ai.schema": outputStrategy.jsonSchema != null ? { input: () => JSON.stringify(outputStrategy.jsonSchema) } : void 0,
|
|
"ai.schema.name": schemaName,
|
|
"ai.schema.description": schemaDescription,
|
|
"ai.settings.output": outputStrategy.type
|
|
}
|
|
}),
|
|
tracer,
|
|
fn: async (span) => {
|
|
var _a17;
|
|
let result;
|
|
let finishReason;
|
|
let usage;
|
|
let warnings;
|
|
let response;
|
|
let request;
|
|
let resultProviderMetadata;
|
|
const standardizedPrompt = await standardizePrompt({
|
|
system,
|
|
prompt,
|
|
messages
|
|
});
|
|
const promptMessages = await convertToLanguageModelPrompt({
|
|
prompt: standardizedPrompt,
|
|
supportedUrls: await model.supportedUrls
|
|
});
|
|
const generateResult = await retry(
|
|
() => recordSpan({
|
|
name: "ai.generateObject.doGenerate",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.generateObject.doGenerate",
|
|
telemetry
|
|
}),
|
|
...baseTelemetryAttributes,
|
|
"ai.prompt.messages": {
|
|
input: () => stringifyForTelemetry(promptMessages)
|
|
},
|
|
// standardized gen-ai llm span attributes:
|
|
"gen_ai.system": model.provider,
|
|
"gen_ai.request.model": model.modelId,
|
|
"gen_ai.request.frequency_penalty": callSettings.frequencyPenalty,
|
|
"gen_ai.request.max_tokens": callSettings.maxOutputTokens,
|
|
"gen_ai.request.presence_penalty": callSettings.presencePenalty,
|
|
"gen_ai.request.temperature": callSettings.temperature,
|
|
"gen_ai.request.top_k": callSettings.topK,
|
|
"gen_ai.request.top_p": callSettings.topP
|
|
}
|
|
}),
|
|
tracer,
|
|
fn: async (span2) => {
|
|
var _a18, _b, _c, _d, _e, _f, _g, _h;
|
|
const result2 = await model.doGenerate({
|
|
responseFormat: {
|
|
type: "json",
|
|
schema: outputStrategy.jsonSchema,
|
|
name: schemaName,
|
|
description: schemaDescription
|
|
},
|
|
...prepareCallSettings(settings),
|
|
prompt: promptMessages,
|
|
providerOptions,
|
|
abortSignal,
|
|
headers
|
|
});
|
|
const responseData = {
|
|
id: (_b = (_a18 = result2.response) == null ? void 0 : _a18.id) != null ? _b : generateId3(),
|
|
timestamp: (_d = (_c = result2.response) == null ? void 0 : _c.timestamp) != null ? _d : currentDate(),
|
|
modelId: (_f = (_e = result2.response) == null ? void 0 : _e.modelId) != null ? _f : model.modelId,
|
|
headers: (_g = result2.response) == null ? void 0 : _g.headers,
|
|
body: (_h = result2.response) == null ? void 0 : _h.body
|
|
};
|
|
const text2 = extractContentText(result2.content);
|
|
if (text2 === void 0) {
|
|
throw new NoObjectGeneratedError({
|
|
message: "No object generated: the model did not return a response.",
|
|
response: responseData,
|
|
usage: result2.usage,
|
|
finishReason: result2.finishReason
|
|
});
|
|
}
|
|
span2.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.response.finishReason": result2.finishReason,
|
|
"ai.response.object": { output: () => text2 },
|
|
"ai.response.id": responseData.id,
|
|
"ai.response.model": responseData.modelId,
|
|
"ai.response.timestamp": responseData.timestamp.toISOString(),
|
|
"ai.response.providerMetadata": JSON.stringify(
|
|
result2.providerMetadata
|
|
),
|
|
// TODO rename telemetry attributes to inputTokens and outputTokens
|
|
"ai.usage.promptTokens": result2.usage.inputTokens,
|
|
"ai.usage.completionTokens": result2.usage.outputTokens,
|
|
// standardized gen-ai llm span attributes:
|
|
"gen_ai.response.finish_reasons": [result2.finishReason],
|
|
"gen_ai.response.id": responseData.id,
|
|
"gen_ai.response.model": responseData.modelId,
|
|
"gen_ai.usage.input_tokens": result2.usage.inputTokens,
|
|
"gen_ai.usage.output_tokens": result2.usage.outputTokens
|
|
}
|
|
})
|
|
);
|
|
return { ...result2, objectText: text2, responseData };
|
|
}
|
|
})
|
|
);
|
|
result = generateResult.objectText;
|
|
finishReason = generateResult.finishReason;
|
|
usage = generateResult.usage;
|
|
warnings = generateResult.warnings;
|
|
resultProviderMetadata = generateResult.providerMetadata;
|
|
request = (_a17 = generateResult.request) != null ? _a17 : {};
|
|
response = generateResult.responseData;
|
|
const object2 = await parseAndValidateObjectResultWithRepair(
|
|
result,
|
|
outputStrategy,
|
|
repairText,
|
|
{
|
|
response,
|
|
usage,
|
|
finishReason
|
|
}
|
|
);
|
|
span.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.response.finishReason": finishReason,
|
|
"ai.response.object": {
|
|
output: () => JSON.stringify(object2)
|
|
},
|
|
"ai.response.providerMetadata": JSON.stringify(
|
|
resultProviderMetadata
|
|
),
|
|
// TODO rename telemetry attributes to inputTokens and outputTokens
|
|
"ai.usage.promptTokens": usage.inputTokens,
|
|
"ai.usage.completionTokens": usage.outputTokens
|
|
}
|
|
})
|
|
);
|
|
return new DefaultGenerateObjectResult({
|
|
object: object2,
|
|
finishReason,
|
|
usage,
|
|
warnings,
|
|
request,
|
|
response,
|
|
providerMetadata: resultProviderMetadata
|
|
});
|
|
}
|
|
});
|
|
} catch (error) {
|
|
throw wrapGatewayError(error);
|
|
}
|
|
}
|
|
var DefaultGenerateObjectResult = class {
|
|
constructor(options) {
|
|
this.object = options.object;
|
|
this.finishReason = options.finishReason;
|
|
this.usage = options.usage;
|
|
this.warnings = options.warnings;
|
|
this.providerMetadata = options.providerMetadata;
|
|
this.response = options.response;
|
|
this.request = options.request;
|
|
}
|
|
toJsonResponse(init) {
|
|
var _a17;
|
|
return new Response(JSON.stringify(this.object), {
|
|
status: (_a17 = init == null ? void 0 : init.status) != null ? _a17 : 200,
|
|
headers: prepareHeaders(init == null ? void 0 : init.headers, {
|
|
"content-type": "application/json; charset=utf-8"
|
|
})
|
|
});
|
|
}
|
|
};
|
|
|
|
// src/generate-object/stream-object.ts
|
|
var import_provider_utils18 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/util/cosine-similarity.ts
|
|
function cosineSimilarity(vector1, vector2) {
|
|
if (vector1.length !== vector2.length) {
|
|
throw new InvalidArgumentError({
|
|
parameter: "vector1,vector2",
|
|
value: { vector1Length: vector1.length, vector2Length: vector2.length },
|
|
message: `Vectors must have the same length`
|
|
});
|
|
}
|
|
const n = vector1.length;
|
|
if (n === 0) {
|
|
return 0;
|
|
}
|
|
let magnitudeSquared1 = 0;
|
|
let magnitudeSquared2 = 0;
|
|
let dotProduct = 0;
|
|
for (let i = 0; i < n; i++) {
|
|
const value1 = vector1[i];
|
|
const value2 = vector2[i];
|
|
magnitudeSquared1 += value1 * value1;
|
|
magnitudeSquared2 += value2 * value2;
|
|
dotProduct += value1 * value2;
|
|
}
|
|
return magnitudeSquared1 === 0 || magnitudeSquared2 === 0 ? 0 : dotProduct / (Math.sqrt(magnitudeSquared1) * Math.sqrt(magnitudeSquared2));
|
|
}
|
|
|
|
// src/util/data-url.ts
|
|
function getTextFromDataUrl(dataUrl) {
|
|
const [header, base64Content] = dataUrl.split(",");
|
|
const mediaType = header.split(";")[0].split(":")[1];
|
|
if (mediaType == null || base64Content == null) {
|
|
throw new Error("Invalid data URL format");
|
|
}
|
|
try {
|
|
return window.atob(base64Content);
|
|
} catch (error) {
|
|
throw new Error(`Error decoding data URL`);
|
|
}
|
|
}
|
|
|
|
// src/util/is-deep-equal-data.ts
|
|
function isDeepEqualData(obj1, obj2) {
|
|
if (obj1 === obj2)
|
|
return true;
|
|
if (obj1 == null || obj2 == null)
|
|
return false;
|
|
if (typeof obj1 !== "object" && typeof obj2 !== "object")
|
|
return obj1 === obj2;
|
|
if (obj1.constructor !== obj2.constructor)
|
|
return false;
|
|
if (obj1 instanceof Date && obj2 instanceof Date) {
|
|
return obj1.getTime() === obj2.getTime();
|
|
}
|
|
if (Array.isArray(obj1)) {
|
|
if (obj1.length !== obj2.length)
|
|
return false;
|
|
for (let i = 0; i < obj1.length; i++) {
|
|
if (!isDeepEqualData(obj1[i], obj2[i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
const keys1 = Object.keys(obj1);
|
|
const keys2 = Object.keys(obj2);
|
|
if (keys1.length !== keys2.length)
|
|
return false;
|
|
for (const key of keys1) {
|
|
if (!keys2.includes(key))
|
|
return false;
|
|
if (!isDeepEqualData(obj1[key], obj2[key]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// src/util/serial-job-executor.ts
|
|
var SerialJobExecutor = class {
|
|
constructor() {
|
|
this.queue = [];
|
|
this.isProcessing = false;
|
|
}
|
|
async processQueue() {
|
|
if (this.isProcessing) {
|
|
return;
|
|
}
|
|
this.isProcessing = true;
|
|
while (this.queue.length > 0) {
|
|
await this.queue[0]();
|
|
this.queue.shift();
|
|
}
|
|
this.isProcessing = false;
|
|
}
|
|
async run(job) {
|
|
return new Promise((resolve2, reject) => {
|
|
this.queue.push(async () => {
|
|
try {
|
|
await job();
|
|
resolve2();
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
});
|
|
void this.processQueue();
|
|
});
|
|
}
|
|
};
|
|
|
|
// src/util/simulate-readable-stream.ts
|
|
var import_provider_utils17 = require("@ai-sdk/provider-utils");
|
|
function simulateReadableStream({
|
|
chunks,
|
|
initialDelayInMs = 0,
|
|
chunkDelayInMs = 0,
|
|
_internal
|
|
}) {
|
|
var _a17;
|
|
const delay2 = (_a17 = _internal == null ? void 0 : _internal.delay) != null ? _a17 : import_provider_utils17.delay;
|
|
let index = 0;
|
|
return new ReadableStream({
|
|
async pull(controller) {
|
|
if (index < chunks.length) {
|
|
await delay2(index === 0 ? initialDelayInMs : chunkDelayInMs);
|
|
controller.enqueue(chunks[index++]);
|
|
} else {
|
|
controller.close();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// src/generate-object/stream-object.ts
|
|
var originalGenerateId4 = (0, import_provider_utils18.createIdGenerator)({ prefix: "aiobj", size: 24 });
|
|
function streamObject(options) {
|
|
const {
|
|
model,
|
|
output = "object",
|
|
system,
|
|
prompt,
|
|
messages,
|
|
maxRetries,
|
|
abortSignal,
|
|
headers,
|
|
experimental_repairText: repairText,
|
|
experimental_telemetry: telemetry,
|
|
providerOptions,
|
|
onError = ({ error }) => {
|
|
console.error(error);
|
|
},
|
|
onFinish,
|
|
_internal: {
|
|
generateId: generateId3 = originalGenerateId4,
|
|
currentDate = () => /* @__PURE__ */ new Date(),
|
|
now: now2 = now
|
|
} = {},
|
|
...settings
|
|
} = options;
|
|
const enumValues = "enum" in options && options.enum ? options.enum : void 0;
|
|
const {
|
|
schema: inputSchema,
|
|
schemaDescription,
|
|
schemaName
|
|
} = "schema" in options ? options : {};
|
|
validateObjectGenerationInput({
|
|
output,
|
|
schema: inputSchema,
|
|
schemaName,
|
|
schemaDescription,
|
|
enumValues
|
|
});
|
|
const outputStrategy = getOutputStrategy({
|
|
output,
|
|
schema: inputSchema,
|
|
enumValues
|
|
});
|
|
return new DefaultStreamObjectResult({
|
|
model,
|
|
telemetry,
|
|
headers,
|
|
settings,
|
|
maxRetries,
|
|
abortSignal,
|
|
outputStrategy,
|
|
system,
|
|
prompt,
|
|
messages,
|
|
schemaName,
|
|
schemaDescription,
|
|
providerOptions,
|
|
repairText,
|
|
onError,
|
|
onFinish,
|
|
generateId: generateId3,
|
|
currentDate,
|
|
now: now2
|
|
});
|
|
}
|
|
var DefaultStreamObjectResult = class {
|
|
constructor({
|
|
model: modelArg,
|
|
headers,
|
|
telemetry,
|
|
settings,
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal,
|
|
outputStrategy,
|
|
system,
|
|
prompt,
|
|
messages,
|
|
schemaName,
|
|
schemaDescription,
|
|
providerOptions,
|
|
repairText,
|
|
onError,
|
|
onFinish,
|
|
generateId: generateId3,
|
|
currentDate,
|
|
now: now2
|
|
}) {
|
|
this._object = new DelayedPromise();
|
|
this._usage = new DelayedPromise();
|
|
this._providerMetadata = new DelayedPromise();
|
|
this._warnings = new DelayedPromise();
|
|
this._request = new DelayedPromise();
|
|
this._response = new DelayedPromise();
|
|
this._finishReason = new DelayedPromise();
|
|
const model = resolveLanguageModel(modelArg);
|
|
const { maxRetries, retry } = prepareRetries({
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal
|
|
});
|
|
const callSettings = prepareCallSettings(settings);
|
|
const baseTelemetryAttributes = getBaseTelemetryAttributes({
|
|
model,
|
|
telemetry,
|
|
headers,
|
|
settings: { ...callSettings, maxRetries }
|
|
});
|
|
const tracer = getTracer(telemetry);
|
|
const self = this;
|
|
const stitchableStream = createStitchableStream();
|
|
const eventProcessor = new TransformStream({
|
|
transform(chunk, controller) {
|
|
controller.enqueue(chunk);
|
|
if (chunk.type === "error") {
|
|
onError({ error: wrapGatewayError(chunk.error) });
|
|
}
|
|
}
|
|
});
|
|
this.baseStream = stitchableStream.stream.pipeThrough(eventProcessor);
|
|
recordSpan({
|
|
name: "ai.streamObject",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.streamObject",
|
|
telemetry
|
|
}),
|
|
...baseTelemetryAttributes,
|
|
// specific settings that only make sense on the outer level:
|
|
"ai.prompt": {
|
|
input: () => JSON.stringify({ system, prompt, messages })
|
|
},
|
|
"ai.schema": outputStrategy.jsonSchema != null ? { input: () => JSON.stringify(outputStrategy.jsonSchema) } : void 0,
|
|
"ai.schema.name": schemaName,
|
|
"ai.schema.description": schemaDescription,
|
|
"ai.settings.output": outputStrategy.type
|
|
}
|
|
}),
|
|
tracer,
|
|
endWhenDone: false,
|
|
fn: async (rootSpan) => {
|
|
const standardizedPrompt = await standardizePrompt({
|
|
system,
|
|
prompt,
|
|
messages
|
|
});
|
|
const callOptions = {
|
|
responseFormat: {
|
|
type: "json",
|
|
schema: outputStrategy.jsonSchema,
|
|
name: schemaName,
|
|
description: schemaDescription
|
|
},
|
|
...prepareCallSettings(settings),
|
|
prompt: await convertToLanguageModelPrompt({
|
|
prompt: standardizedPrompt,
|
|
supportedUrls: await model.supportedUrls
|
|
}),
|
|
providerOptions,
|
|
abortSignal,
|
|
headers,
|
|
includeRawChunks: false
|
|
};
|
|
const transformer = {
|
|
transform: (chunk, controller) => {
|
|
switch (chunk.type) {
|
|
case "text-delta":
|
|
controller.enqueue(chunk.delta);
|
|
break;
|
|
case "response-metadata":
|
|
case "finish":
|
|
case "error":
|
|
controller.enqueue(chunk);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
const {
|
|
result: { stream, response, request },
|
|
doStreamSpan,
|
|
startTimestampMs
|
|
} = await retry(
|
|
() => recordSpan({
|
|
name: "ai.streamObject.doStream",
|
|
attributes: selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
...assembleOperationName({
|
|
operationId: "ai.streamObject.doStream",
|
|
telemetry
|
|
}),
|
|
...baseTelemetryAttributes,
|
|
"ai.prompt.messages": {
|
|
input: () => stringifyForTelemetry(callOptions.prompt)
|
|
},
|
|
// standardized gen-ai llm span attributes:
|
|
"gen_ai.system": model.provider,
|
|
"gen_ai.request.model": model.modelId,
|
|
"gen_ai.request.frequency_penalty": callSettings.frequencyPenalty,
|
|
"gen_ai.request.max_tokens": callSettings.maxOutputTokens,
|
|
"gen_ai.request.presence_penalty": callSettings.presencePenalty,
|
|
"gen_ai.request.temperature": callSettings.temperature,
|
|
"gen_ai.request.top_k": callSettings.topK,
|
|
"gen_ai.request.top_p": callSettings.topP
|
|
}
|
|
}),
|
|
tracer,
|
|
endWhenDone: false,
|
|
fn: async (doStreamSpan2) => ({
|
|
startTimestampMs: now2(),
|
|
doStreamSpan: doStreamSpan2,
|
|
result: await model.doStream(callOptions)
|
|
})
|
|
})
|
|
);
|
|
self._request.resolve(request != null ? request : {});
|
|
let warnings;
|
|
let usage = {
|
|
inputTokens: void 0,
|
|
outputTokens: void 0,
|
|
totalTokens: void 0
|
|
};
|
|
let finishReason;
|
|
let providerMetadata;
|
|
let object2;
|
|
let error;
|
|
let accumulatedText = "";
|
|
let textDelta = "";
|
|
let fullResponse = {
|
|
id: generateId3(),
|
|
timestamp: currentDate(),
|
|
modelId: model.modelId
|
|
};
|
|
let latestObjectJson = void 0;
|
|
let latestObject = void 0;
|
|
let isFirstChunk = true;
|
|
let isFirstDelta = true;
|
|
const transformedStream = stream.pipeThrough(new TransformStream(transformer)).pipeThrough(
|
|
new TransformStream({
|
|
async transform(chunk, controller) {
|
|
var _a17, _b, _c;
|
|
if (typeof chunk === "object" && chunk.type === "stream-start") {
|
|
warnings = chunk.warnings;
|
|
return;
|
|
}
|
|
if (isFirstChunk) {
|
|
const msToFirstChunk = now2() - startTimestampMs;
|
|
isFirstChunk = false;
|
|
doStreamSpan.addEvent("ai.stream.firstChunk", {
|
|
"ai.stream.msToFirstChunk": msToFirstChunk
|
|
});
|
|
doStreamSpan.setAttributes({
|
|
"ai.stream.msToFirstChunk": msToFirstChunk
|
|
});
|
|
}
|
|
if (typeof chunk === "string") {
|
|
accumulatedText += chunk;
|
|
textDelta += chunk;
|
|
const { value: currentObjectJson, state: parseState } = await parsePartialJson(accumulatedText);
|
|
if (currentObjectJson !== void 0 && !isDeepEqualData(latestObjectJson, currentObjectJson)) {
|
|
const validationResult = await outputStrategy.validatePartialResult({
|
|
value: currentObjectJson,
|
|
textDelta,
|
|
latestObject,
|
|
isFirstDelta,
|
|
isFinalDelta: parseState === "successful-parse"
|
|
});
|
|
if (validationResult.success && !isDeepEqualData(
|
|
latestObject,
|
|
validationResult.value.partial
|
|
)) {
|
|
latestObjectJson = currentObjectJson;
|
|
latestObject = validationResult.value.partial;
|
|
controller.enqueue({
|
|
type: "object",
|
|
object: latestObject
|
|
});
|
|
controller.enqueue({
|
|
type: "text-delta",
|
|
textDelta: validationResult.value.textDelta
|
|
});
|
|
textDelta = "";
|
|
isFirstDelta = false;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
switch (chunk.type) {
|
|
case "response-metadata": {
|
|
fullResponse = {
|
|
id: (_a17 = chunk.id) != null ? _a17 : fullResponse.id,
|
|
timestamp: (_b = chunk.timestamp) != null ? _b : fullResponse.timestamp,
|
|
modelId: (_c = chunk.modelId) != null ? _c : fullResponse.modelId
|
|
};
|
|
break;
|
|
}
|
|
case "finish": {
|
|
if (textDelta !== "") {
|
|
controller.enqueue({ type: "text-delta", textDelta });
|
|
}
|
|
finishReason = chunk.finishReason;
|
|
usage = chunk.usage;
|
|
providerMetadata = chunk.providerMetadata;
|
|
controller.enqueue({
|
|
...chunk,
|
|
usage,
|
|
response: fullResponse
|
|
});
|
|
self._usage.resolve(usage);
|
|
self._providerMetadata.resolve(providerMetadata);
|
|
self._response.resolve({
|
|
...fullResponse,
|
|
headers: response == null ? void 0 : response.headers
|
|
});
|
|
self._finishReason.resolve(finishReason != null ? finishReason : "unknown");
|
|
try {
|
|
object2 = await parseAndValidateObjectResultWithRepair(
|
|
accumulatedText,
|
|
outputStrategy,
|
|
repairText,
|
|
{
|
|
response: fullResponse,
|
|
usage,
|
|
finishReason
|
|
}
|
|
);
|
|
self._object.resolve(object2);
|
|
} catch (e) {
|
|
error = e;
|
|
self._object.reject(e);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
controller.enqueue(chunk);
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
// invoke onFinish callback and resolve toolResults promise when the stream is about to close:
|
|
async flush(controller) {
|
|
try {
|
|
const finalUsage = usage != null ? usage : {
|
|
promptTokens: NaN,
|
|
completionTokens: NaN,
|
|
totalTokens: NaN
|
|
};
|
|
doStreamSpan.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.response.finishReason": finishReason,
|
|
"ai.response.object": {
|
|
output: () => JSON.stringify(object2)
|
|
},
|
|
"ai.response.id": fullResponse.id,
|
|
"ai.response.model": fullResponse.modelId,
|
|
"ai.response.timestamp": fullResponse.timestamp.toISOString(),
|
|
"ai.response.providerMetadata": JSON.stringify(providerMetadata),
|
|
"ai.usage.inputTokens": finalUsage.inputTokens,
|
|
"ai.usage.outputTokens": finalUsage.outputTokens,
|
|
"ai.usage.totalTokens": finalUsage.totalTokens,
|
|
"ai.usage.reasoningTokens": finalUsage.reasoningTokens,
|
|
"ai.usage.cachedInputTokens": finalUsage.cachedInputTokens,
|
|
// standardized gen-ai llm span attributes:
|
|
"gen_ai.response.finish_reasons": [finishReason],
|
|
"gen_ai.response.id": fullResponse.id,
|
|
"gen_ai.response.model": fullResponse.modelId,
|
|
"gen_ai.usage.input_tokens": finalUsage.inputTokens,
|
|
"gen_ai.usage.output_tokens": finalUsage.outputTokens
|
|
}
|
|
})
|
|
);
|
|
doStreamSpan.end();
|
|
rootSpan.setAttributes(
|
|
selectTelemetryAttributes({
|
|
telemetry,
|
|
attributes: {
|
|
"ai.usage.inputTokens": finalUsage.inputTokens,
|
|
"ai.usage.outputTokens": finalUsage.outputTokens,
|
|
"ai.usage.totalTokens": finalUsage.totalTokens,
|
|
"ai.usage.reasoningTokens": finalUsage.reasoningTokens,
|
|
"ai.usage.cachedInputTokens": finalUsage.cachedInputTokens,
|
|
"ai.response.object": {
|
|
output: () => JSON.stringify(object2)
|
|
},
|
|
"ai.response.providerMetadata": JSON.stringify(providerMetadata)
|
|
}
|
|
})
|
|
);
|
|
await (onFinish == null ? void 0 : onFinish({
|
|
usage: finalUsage,
|
|
object: object2,
|
|
error,
|
|
response: {
|
|
...fullResponse,
|
|
headers: response == null ? void 0 : response.headers
|
|
},
|
|
warnings,
|
|
providerMetadata
|
|
}));
|
|
} catch (error2) {
|
|
controller.enqueue({ type: "error", error: error2 });
|
|
} finally {
|
|
rootSpan.end();
|
|
}
|
|
}
|
|
})
|
|
);
|
|
stitchableStream.addStream(transformedStream);
|
|
}
|
|
}).catch((error) => {
|
|
stitchableStream.addStream(
|
|
new ReadableStream({
|
|
start(controller) {
|
|
controller.enqueue({ type: "error", error });
|
|
controller.close();
|
|
}
|
|
})
|
|
);
|
|
}).finally(() => {
|
|
stitchableStream.close();
|
|
});
|
|
this.outputStrategy = outputStrategy;
|
|
}
|
|
get object() {
|
|
return this._object.promise;
|
|
}
|
|
get usage() {
|
|
return this._usage.promise;
|
|
}
|
|
get providerMetadata() {
|
|
return this._providerMetadata.promise;
|
|
}
|
|
get warnings() {
|
|
return this._warnings.promise;
|
|
}
|
|
get request() {
|
|
return this._request.promise;
|
|
}
|
|
get response() {
|
|
return this._response.promise;
|
|
}
|
|
get finishReason() {
|
|
return this._finishReason.promise;
|
|
}
|
|
get partialObjectStream() {
|
|
return createAsyncIterableStream(
|
|
this.baseStream.pipeThrough(
|
|
new TransformStream({
|
|
transform(chunk, controller) {
|
|
switch (chunk.type) {
|
|
case "object":
|
|
controller.enqueue(chunk.object);
|
|
break;
|
|
case "text-delta":
|
|
case "finish":
|
|
case "error":
|
|
break;
|
|
default: {
|
|
const _exhaustiveCheck = chunk;
|
|
throw new Error(`Unsupported chunk type: ${_exhaustiveCheck}`);
|
|
}
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
}
|
|
get elementStream() {
|
|
return this.outputStrategy.createElementStream(this.baseStream);
|
|
}
|
|
get textStream() {
|
|
return createAsyncIterableStream(
|
|
this.baseStream.pipeThrough(
|
|
new TransformStream({
|
|
transform(chunk, controller) {
|
|
switch (chunk.type) {
|
|
case "text-delta":
|
|
controller.enqueue(chunk.textDelta);
|
|
break;
|
|
case "object":
|
|
case "finish":
|
|
case "error":
|
|
break;
|
|
default: {
|
|
const _exhaustiveCheck = chunk;
|
|
throw new Error(`Unsupported chunk type: ${_exhaustiveCheck}`);
|
|
}
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
}
|
|
get fullStream() {
|
|
return createAsyncIterableStream(this.baseStream);
|
|
}
|
|
pipeTextStreamToResponse(response, init) {
|
|
pipeTextStreamToResponse({
|
|
response,
|
|
textStream: this.textStream,
|
|
...init
|
|
});
|
|
}
|
|
toTextStreamResponse(init) {
|
|
return createTextStreamResponse({
|
|
textStream: this.textStream,
|
|
...init
|
|
});
|
|
}
|
|
};
|
|
|
|
// src/error/no-speech-generated-error.ts
|
|
var import_provider26 = require("@ai-sdk/provider");
|
|
var NoSpeechGeneratedError = class extends import_provider26.AISDKError {
|
|
constructor(options) {
|
|
super({
|
|
name: "AI_NoSpeechGeneratedError",
|
|
message: "No speech audio generated."
|
|
});
|
|
this.responses = options.responses;
|
|
}
|
|
};
|
|
|
|
// src/generate-speech/generated-audio-file.ts
|
|
var DefaultGeneratedAudioFile = class extends DefaultGeneratedFile {
|
|
constructor({
|
|
data,
|
|
mediaType
|
|
}) {
|
|
super({ data, mediaType });
|
|
let format = "mp3";
|
|
if (mediaType) {
|
|
const mediaTypeParts = mediaType.split("/");
|
|
if (mediaTypeParts.length === 2) {
|
|
if (mediaType !== "audio/mpeg") {
|
|
format = mediaTypeParts[1];
|
|
}
|
|
}
|
|
}
|
|
if (!format) {
|
|
throw new Error(
|
|
"Audio format must be provided or determinable from media type"
|
|
);
|
|
}
|
|
this.format = format;
|
|
}
|
|
};
|
|
|
|
// src/generate-speech/generate-speech.ts
|
|
async function generateSpeech({
|
|
model,
|
|
text: text2,
|
|
voice,
|
|
outputFormat,
|
|
instructions,
|
|
speed,
|
|
language,
|
|
providerOptions = {},
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal,
|
|
headers
|
|
}) {
|
|
var _a17;
|
|
if (model.specificationVersion !== "v2") {
|
|
throw new UnsupportedModelVersionError({
|
|
version: model.specificationVersion,
|
|
provider: model.provider,
|
|
modelId: model.modelId
|
|
});
|
|
}
|
|
const { retry } = prepareRetries({
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal
|
|
});
|
|
const result = await retry(
|
|
() => model.doGenerate({
|
|
text: text2,
|
|
voice,
|
|
outputFormat,
|
|
instructions,
|
|
speed,
|
|
language,
|
|
abortSignal,
|
|
headers,
|
|
providerOptions
|
|
})
|
|
);
|
|
if (!result.audio || result.audio.length === 0) {
|
|
throw new NoSpeechGeneratedError({ responses: [result.response] });
|
|
}
|
|
return new DefaultSpeechResult({
|
|
audio: new DefaultGeneratedAudioFile({
|
|
data: result.audio,
|
|
mediaType: (_a17 = detectMediaType({
|
|
data: result.audio,
|
|
signatures: audioMediaTypeSignatures
|
|
})) != null ? _a17 : "audio/mp3"
|
|
}),
|
|
warnings: result.warnings,
|
|
responses: [result.response],
|
|
providerMetadata: result.providerMetadata
|
|
});
|
|
}
|
|
var DefaultSpeechResult = class {
|
|
constructor(options) {
|
|
var _a17;
|
|
this.audio = options.audio;
|
|
this.warnings = options.warnings;
|
|
this.responses = options.responses;
|
|
this.providerMetadata = (_a17 = options.providerMetadata) != null ? _a17 : {};
|
|
}
|
|
};
|
|
|
|
// src/generate-text/output.ts
|
|
var output_exports = {};
|
|
__export(output_exports, {
|
|
object: () => object,
|
|
text: () => text
|
|
});
|
|
var import_provider_utils19 = require("@ai-sdk/provider-utils");
|
|
var text = () => ({
|
|
type: "text",
|
|
responseFormat: { type: "text" },
|
|
async parsePartial({ text: text2 }) {
|
|
return { partial: text2 };
|
|
},
|
|
async parseOutput({ text: text2 }) {
|
|
return text2;
|
|
}
|
|
});
|
|
var object = ({
|
|
schema: inputSchema
|
|
}) => {
|
|
const schema = (0, import_provider_utils19.asSchema)(inputSchema);
|
|
return {
|
|
type: "object",
|
|
responseFormat: {
|
|
type: "json",
|
|
schema: schema.jsonSchema
|
|
},
|
|
async parsePartial({ text: text2 }) {
|
|
const result = await parsePartialJson(text2);
|
|
switch (result.state) {
|
|
case "failed-parse":
|
|
case "undefined-input":
|
|
return void 0;
|
|
case "repaired-parse":
|
|
case "successful-parse":
|
|
return {
|
|
// Note: currently no validation of partial results:
|
|
partial: result.value
|
|
};
|
|
default: {
|
|
const _exhaustiveCheck = result.state;
|
|
throw new Error(`Unsupported parse state: ${_exhaustiveCheck}`);
|
|
}
|
|
}
|
|
},
|
|
async parseOutput({ text: text2 }, context) {
|
|
const parseResult = await (0, import_provider_utils19.safeParseJSON)({ text: text2 });
|
|
if (!parseResult.success) {
|
|
throw new NoObjectGeneratedError({
|
|
message: "No object generated: could not parse the response.",
|
|
cause: parseResult.error,
|
|
text: text2,
|
|
response: context.response,
|
|
usage: context.usage,
|
|
finishReason: context.finishReason
|
|
});
|
|
}
|
|
const validationResult = await (0, import_provider_utils19.safeValidateTypes)({
|
|
value: parseResult.value,
|
|
schema
|
|
});
|
|
if (!validationResult.success) {
|
|
throw new NoObjectGeneratedError({
|
|
message: "No object generated: response did not match schema.",
|
|
cause: validationResult.error,
|
|
text: text2,
|
|
response: context.response,
|
|
usage: context.usage,
|
|
finishReason: context.finishReason
|
|
});
|
|
}
|
|
return validationResult.value;
|
|
}
|
|
};
|
|
};
|
|
|
|
// src/generate-text/smooth-stream.ts
|
|
var import_provider_utils20 = require("@ai-sdk/provider-utils");
|
|
var import_provider27 = require("@ai-sdk/provider");
|
|
var CHUNKING_REGEXPS = {
|
|
word: /\S+\s+/m,
|
|
line: /\n+/m
|
|
};
|
|
function smoothStream({
|
|
delayInMs = 10,
|
|
chunking = "word",
|
|
_internal: { delay: delay2 = import_provider_utils20.delay } = {}
|
|
} = {}) {
|
|
let detectChunk;
|
|
if (typeof chunking === "function") {
|
|
detectChunk = (buffer) => {
|
|
const match = chunking(buffer);
|
|
if (match == null) {
|
|
return null;
|
|
}
|
|
if (!match.length) {
|
|
throw new Error(`Chunking function must return a non-empty string.`);
|
|
}
|
|
if (!buffer.startsWith(match)) {
|
|
throw new Error(
|
|
`Chunking function must return a match that is a prefix of the buffer. Received: "${match}" expected to start with "${buffer}"`
|
|
);
|
|
}
|
|
return match;
|
|
};
|
|
} else {
|
|
const chunkingRegex = typeof chunking === "string" ? CHUNKING_REGEXPS[chunking] : chunking;
|
|
if (chunkingRegex == null) {
|
|
throw new import_provider27.InvalidArgumentError({
|
|
argument: "chunking",
|
|
message: `Chunking must be "word" or "line" or a RegExp. Received: ${chunking}`
|
|
});
|
|
}
|
|
detectChunk = (buffer) => {
|
|
const match = chunkingRegex.exec(buffer);
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
return buffer.slice(0, match.index) + (match == null ? void 0 : match[0]);
|
|
};
|
|
}
|
|
return () => {
|
|
let buffer = "";
|
|
let id = "";
|
|
return new TransformStream({
|
|
async transform(chunk, controller) {
|
|
if (chunk.type !== "text-delta") {
|
|
if (buffer.length > 0) {
|
|
controller.enqueue({ type: "text-delta", text: buffer, id });
|
|
buffer = "";
|
|
}
|
|
controller.enqueue(chunk);
|
|
return;
|
|
}
|
|
if (chunk.id !== id && buffer.length > 0) {
|
|
controller.enqueue({ type: "text-delta", text: buffer, id });
|
|
buffer = "";
|
|
}
|
|
buffer += chunk.text;
|
|
id = chunk.id;
|
|
let match;
|
|
while ((match = detectChunk(buffer)) != null) {
|
|
controller.enqueue({ type: "text-delta", text: match, id });
|
|
buffer = buffer.slice(match.length);
|
|
await delay2(delayInMs);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
}
|
|
|
|
// src/middleware/default-settings-middleware.ts
|
|
function defaultSettingsMiddleware({
|
|
settings
|
|
}) {
|
|
return {
|
|
middlewareVersion: "v2",
|
|
transformParams: async ({ params }) => {
|
|
return mergeObjects(settings, params);
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/util/get-potential-start-index.ts
|
|
function getPotentialStartIndex(text2, searchedText) {
|
|
if (searchedText.length === 0) {
|
|
return null;
|
|
}
|
|
const directIndex = text2.indexOf(searchedText);
|
|
if (directIndex !== -1) {
|
|
return directIndex;
|
|
}
|
|
for (let i = text2.length - 1; i >= 0; i--) {
|
|
const suffix = text2.substring(i);
|
|
if (searchedText.startsWith(suffix)) {
|
|
return i;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// src/middleware/extract-reasoning-middleware.ts
|
|
function extractReasoningMiddleware({
|
|
tagName,
|
|
separator = "\n",
|
|
startWithReasoning = false
|
|
}) {
|
|
const openingTag = `<${tagName}>`;
|
|
const closingTag = `</${tagName}>`;
|
|
return {
|
|
middlewareVersion: "v2",
|
|
wrapGenerate: async ({ doGenerate }) => {
|
|
const { content, ...rest } = await doGenerate();
|
|
const transformedContent = [];
|
|
for (const part of content) {
|
|
if (part.type !== "text") {
|
|
transformedContent.push(part);
|
|
continue;
|
|
}
|
|
const text2 = startWithReasoning ? openingTag + part.text : part.text;
|
|
const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, "gs");
|
|
const matches = Array.from(text2.matchAll(regexp));
|
|
if (!matches.length) {
|
|
transformedContent.push(part);
|
|
continue;
|
|
}
|
|
const reasoningText = matches.map((match) => match[1]).join(separator);
|
|
let textWithoutReasoning = text2;
|
|
for (let i = matches.length - 1; i >= 0; i--) {
|
|
const match = matches[i];
|
|
const beforeMatch = textWithoutReasoning.slice(0, match.index);
|
|
const afterMatch = textWithoutReasoning.slice(
|
|
match.index + match[0].length
|
|
);
|
|
textWithoutReasoning = beforeMatch + (beforeMatch.length > 0 && afterMatch.length > 0 ? separator : "") + afterMatch;
|
|
}
|
|
transformedContent.push({
|
|
type: "reasoning",
|
|
text: reasoningText
|
|
});
|
|
transformedContent.push({
|
|
type: "text",
|
|
text: textWithoutReasoning
|
|
});
|
|
}
|
|
return { content: transformedContent, ...rest };
|
|
},
|
|
wrapStream: async ({ doStream }) => {
|
|
const { stream, ...rest } = await doStream();
|
|
const reasoningExtractions = {};
|
|
let delayedTextStart;
|
|
return {
|
|
stream: stream.pipeThrough(
|
|
new TransformStream({
|
|
transform: (chunk, controller) => {
|
|
if (chunk.type === "text-start") {
|
|
delayedTextStart = chunk;
|
|
return;
|
|
}
|
|
if (chunk.type === "text-end" && delayedTextStart) {
|
|
controller.enqueue(delayedTextStart);
|
|
delayedTextStart = void 0;
|
|
}
|
|
if (chunk.type !== "text-delta") {
|
|
controller.enqueue(chunk);
|
|
return;
|
|
}
|
|
if (reasoningExtractions[chunk.id] == null) {
|
|
reasoningExtractions[chunk.id] = {
|
|
isFirstReasoning: true,
|
|
isFirstText: true,
|
|
afterSwitch: false,
|
|
isReasoning: startWithReasoning,
|
|
buffer: "",
|
|
idCounter: 0,
|
|
textId: chunk.id
|
|
};
|
|
}
|
|
const activeExtraction = reasoningExtractions[chunk.id];
|
|
activeExtraction.buffer += chunk.delta;
|
|
function publish(text2) {
|
|
if (text2.length > 0) {
|
|
const prefix = activeExtraction.afterSwitch && (activeExtraction.isReasoning ? !activeExtraction.isFirstReasoning : !activeExtraction.isFirstText) ? separator : "";
|
|
if (activeExtraction.isReasoning && (activeExtraction.afterSwitch || activeExtraction.isFirstReasoning)) {
|
|
controller.enqueue({
|
|
type: "reasoning-start",
|
|
id: `reasoning-${activeExtraction.idCounter}`
|
|
});
|
|
}
|
|
if (activeExtraction.isReasoning) {
|
|
controller.enqueue({
|
|
type: "reasoning-delta",
|
|
delta: prefix + text2,
|
|
id: `reasoning-${activeExtraction.idCounter}`
|
|
});
|
|
} else {
|
|
if (delayedTextStart) {
|
|
controller.enqueue(delayedTextStart);
|
|
delayedTextStart = void 0;
|
|
}
|
|
controller.enqueue({
|
|
type: "text-delta",
|
|
delta: prefix + text2,
|
|
id: activeExtraction.textId
|
|
});
|
|
}
|
|
activeExtraction.afterSwitch = false;
|
|
if (activeExtraction.isReasoning) {
|
|
activeExtraction.isFirstReasoning = false;
|
|
} else {
|
|
activeExtraction.isFirstText = false;
|
|
}
|
|
}
|
|
}
|
|
do {
|
|
const nextTag = activeExtraction.isReasoning ? closingTag : openingTag;
|
|
const startIndex = getPotentialStartIndex(
|
|
activeExtraction.buffer,
|
|
nextTag
|
|
);
|
|
if (startIndex == null) {
|
|
publish(activeExtraction.buffer);
|
|
activeExtraction.buffer = "";
|
|
break;
|
|
}
|
|
publish(activeExtraction.buffer.slice(0, startIndex));
|
|
const foundFullMatch = startIndex + nextTag.length <= activeExtraction.buffer.length;
|
|
if (foundFullMatch) {
|
|
activeExtraction.buffer = activeExtraction.buffer.slice(
|
|
startIndex + nextTag.length
|
|
);
|
|
if (activeExtraction.isReasoning) {
|
|
controller.enqueue({
|
|
type: "reasoning-end",
|
|
id: `reasoning-${activeExtraction.idCounter++}`
|
|
});
|
|
}
|
|
activeExtraction.isReasoning = !activeExtraction.isReasoning;
|
|
activeExtraction.afterSwitch = true;
|
|
} else {
|
|
activeExtraction.buffer = activeExtraction.buffer.slice(startIndex);
|
|
break;
|
|
}
|
|
} while (true);
|
|
}
|
|
})
|
|
),
|
|
...rest
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/middleware/simulate-streaming-middleware.ts
|
|
function simulateStreamingMiddleware() {
|
|
return {
|
|
middlewareVersion: "v2",
|
|
wrapStream: async ({ doGenerate }) => {
|
|
const result = await doGenerate();
|
|
let id = 0;
|
|
const simulatedStream = new ReadableStream({
|
|
start(controller) {
|
|
controller.enqueue({
|
|
type: "stream-start",
|
|
warnings: result.warnings
|
|
});
|
|
controller.enqueue({ type: "response-metadata", ...result.response });
|
|
for (const part of result.content) {
|
|
switch (part.type) {
|
|
case "text": {
|
|
if (part.text.length > 0) {
|
|
controller.enqueue({ type: "text-start", id: String(id) });
|
|
controller.enqueue({
|
|
type: "text-delta",
|
|
id: String(id),
|
|
delta: part.text
|
|
});
|
|
controller.enqueue({ type: "text-end", id: String(id) });
|
|
id++;
|
|
}
|
|
break;
|
|
}
|
|
case "reasoning": {
|
|
controller.enqueue({
|
|
type: "reasoning-start",
|
|
id: String(id),
|
|
providerMetadata: part.providerMetadata
|
|
});
|
|
controller.enqueue({
|
|
type: "reasoning-delta",
|
|
id: String(id),
|
|
delta: part.text
|
|
});
|
|
controller.enqueue({ type: "reasoning-end", id: String(id) });
|
|
id++;
|
|
break;
|
|
}
|
|
default: {
|
|
controller.enqueue(part);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
controller.enqueue({
|
|
type: "finish",
|
|
finishReason: result.finishReason,
|
|
usage: result.usage,
|
|
providerMetadata: result.providerMetadata
|
|
});
|
|
controller.close();
|
|
}
|
|
});
|
|
return {
|
|
stream: simulatedStream,
|
|
request: result.request,
|
|
response: result.response
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/middleware/wrap-language-model.ts
|
|
var wrapLanguageModel = ({
|
|
model,
|
|
middleware: middlewareArg,
|
|
modelId,
|
|
providerId
|
|
}) => {
|
|
return asArray(middlewareArg).reverse().reduce((wrappedModel, middleware) => {
|
|
return doWrap({ model: wrappedModel, middleware, modelId, providerId });
|
|
}, model);
|
|
};
|
|
var doWrap = ({
|
|
model,
|
|
middleware: {
|
|
transformParams,
|
|
wrapGenerate,
|
|
wrapStream,
|
|
overrideProvider,
|
|
overrideModelId,
|
|
overrideSupportedUrls
|
|
},
|
|
modelId,
|
|
providerId
|
|
}) => {
|
|
var _a17, _b, _c;
|
|
async function doTransform({
|
|
params,
|
|
type
|
|
}) {
|
|
return transformParams ? await transformParams({ params, type, model }) : params;
|
|
}
|
|
return {
|
|
specificationVersion: "v2",
|
|
provider: (_a17 = providerId != null ? providerId : overrideProvider == null ? void 0 : overrideProvider({ model })) != null ? _a17 : model.provider,
|
|
modelId: (_b = modelId != null ? modelId : overrideModelId == null ? void 0 : overrideModelId({ model })) != null ? _b : model.modelId,
|
|
supportedUrls: (_c = overrideSupportedUrls == null ? void 0 : overrideSupportedUrls({ model })) != null ? _c : model.supportedUrls,
|
|
async doGenerate(params) {
|
|
const transformedParams = await doTransform({ params, type: "generate" });
|
|
const doGenerate = async () => model.doGenerate(transformedParams);
|
|
const doStream = async () => model.doStream(transformedParams);
|
|
return wrapGenerate ? wrapGenerate({
|
|
doGenerate,
|
|
doStream,
|
|
params: transformedParams,
|
|
model
|
|
}) : doGenerate();
|
|
},
|
|
async doStream(params) {
|
|
const transformedParams = await doTransform({ params, type: "stream" });
|
|
const doGenerate = async () => model.doGenerate(transformedParams);
|
|
const doStream = async () => model.doStream(transformedParams);
|
|
return wrapStream ? wrapStream({ doGenerate, doStream, params: transformedParams, model }) : doStream();
|
|
}
|
|
};
|
|
};
|
|
|
|
// src/middleware/wrap-provider.ts
|
|
function wrapProvider({
|
|
provider,
|
|
languageModelMiddleware
|
|
}) {
|
|
const wrappedProvider = {
|
|
languageModel(modelId) {
|
|
let model = provider.languageModel(modelId);
|
|
model = wrapLanguageModel({
|
|
model,
|
|
middleware: languageModelMiddleware
|
|
});
|
|
return model;
|
|
},
|
|
textEmbeddingModel: provider.textEmbeddingModel,
|
|
imageModel: provider.imageModel,
|
|
transcriptionModel: provider.transcriptionModel,
|
|
speechModel: provider.speechModel
|
|
};
|
|
return wrappedProvider;
|
|
}
|
|
|
|
// src/registry/custom-provider.ts
|
|
var import_provider28 = require("@ai-sdk/provider");
|
|
function customProvider({
|
|
languageModels,
|
|
textEmbeddingModels,
|
|
imageModels,
|
|
transcriptionModels,
|
|
speechModels,
|
|
fallbackProvider
|
|
}) {
|
|
return {
|
|
languageModel(modelId) {
|
|
if (languageModels != null && modelId in languageModels) {
|
|
return languageModels[modelId];
|
|
}
|
|
if (fallbackProvider) {
|
|
return fallbackProvider.languageModel(modelId);
|
|
}
|
|
throw new import_provider28.NoSuchModelError({ modelId, modelType: "languageModel" });
|
|
},
|
|
textEmbeddingModel(modelId) {
|
|
if (textEmbeddingModels != null && modelId in textEmbeddingModels) {
|
|
return textEmbeddingModels[modelId];
|
|
}
|
|
if (fallbackProvider) {
|
|
return fallbackProvider.textEmbeddingModel(modelId);
|
|
}
|
|
throw new import_provider28.NoSuchModelError({ modelId, modelType: "textEmbeddingModel" });
|
|
},
|
|
imageModel(modelId) {
|
|
if (imageModels != null && modelId in imageModels) {
|
|
return imageModels[modelId];
|
|
}
|
|
if (fallbackProvider == null ? void 0 : fallbackProvider.imageModel) {
|
|
return fallbackProvider.imageModel(modelId);
|
|
}
|
|
throw new import_provider28.NoSuchModelError({ modelId, modelType: "imageModel" });
|
|
},
|
|
transcriptionModel(modelId) {
|
|
if (transcriptionModels != null && modelId in transcriptionModels) {
|
|
return transcriptionModels[modelId];
|
|
}
|
|
if (fallbackProvider == null ? void 0 : fallbackProvider.transcriptionModel) {
|
|
return fallbackProvider.transcriptionModel(modelId);
|
|
}
|
|
throw new import_provider28.NoSuchModelError({ modelId, modelType: "transcriptionModel" });
|
|
},
|
|
speechModel(modelId) {
|
|
if (speechModels != null && modelId in speechModels) {
|
|
return speechModels[modelId];
|
|
}
|
|
if (fallbackProvider == null ? void 0 : fallbackProvider.speechModel) {
|
|
return fallbackProvider.speechModel(modelId);
|
|
}
|
|
throw new import_provider28.NoSuchModelError({ modelId, modelType: "speechModel" });
|
|
}
|
|
};
|
|
}
|
|
var experimental_customProvider = customProvider;
|
|
|
|
// src/registry/no-such-provider-error.ts
|
|
var import_provider29 = require("@ai-sdk/provider");
|
|
var name16 = "AI_NoSuchProviderError";
|
|
var marker16 = `vercel.ai.error.${name16}`;
|
|
var symbol16 = Symbol.for(marker16);
|
|
var _a16;
|
|
var NoSuchProviderError = class extends import_provider29.NoSuchModelError {
|
|
constructor({
|
|
modelId,
|
|
modelType,
|
|
providerId,
|
|
availableProviders,
|
|
message = `No such provider: ${providerId} (available providers: ${availableProviders.join()})`
|
|
}) {
|
|
super({ errorName: name16, modelId, modelType, message });
|
|
this[_a16] = true;
|
|
this.providerId = providerId;
|
|
this.availableProviders = availableProviders;
|
|
}
|
|
static isInstance(error) {
|
|
return import_provider29.AISDKError.hasMarker(error, marker16);
|
|
}
|
|
};
|
|
_a16 = symbol16;
|
|
|
|
// src/registry/provider-registry.ts
|
|
var import_provider30 = require("@ai-sdk/provider");
|
|
function createProviderRegistry(providers, {
|
|
separator = ":",
|
|
languageModelMiddleware
|
|
} = {}) {
|
|
const registry = new DefaultProviderRegistry({
|
|
separator,
|
|
languageModelMiddleware
|
|
});
|
|
for (const [id, provider] of Object.entries(providers)) {
|
|
registry.registerProvider({ id, provider });
|
|
}
|
|
return registry;
|
|
}
|
|
var experimental_createProviderRegistry = createProviderRegistry;
|
|
var DefaultProviderRegistry = class {
|
|
constructor({
|
|
separator,
|
|
languageModelMiddleware
|
|
}) {
|
|
this.providers = {};
|
|
this.separator = separator;
|
|
this.languageModelMiddleware = languageModelMiddleware;
|
|
}
|
|
registerProvider({
|
|
id,
|
|
provider
|
|
}) {
|
|
this.providers[id] = provider;
|
|
}
|
|
getProvider(id, modelType) {
|
|
const provider = this.providers[id];
|
|
if (provider == null) {
|
|
throw new NoSuchProviderError({
|
|
modelId: id,
|
|
modelType,
|
|
providerId: id,
|
|
availableProviders: Object.keys(this.providers)
|
|
});
|
|
}
|
|
return provider;
|
|
}
|
|
splitId(id, modelType) {
|
|
const index = id.indexOf(this.separator);
|
|
if (index === -1) {
|
|
throw new import_provider30.NoSuchModelError({
|
|
modelId: id,
|
|
modelType,
|
|
message: `Invalid ${modelType} id for registry: ${id} (must be in the format "providerId${this.separator}modelId")`
|
|
});
|
|
}
|
|
return [id.slice(0, index), id.slice(index + this.separator.length)];
|
|
}
|
|
languageModel(id) {
|
|
var _a17, _b;
|
|
const [providerId, modelId] = this.splitId(id, "languageModel");
|
|
let model = (_b = (_a17 = this.getProvider(providerId, "languageModel")).languageModel) == null ? void 0 : _b.call(
|
|
_a17,
|
|
modelId
|
|
);
|
|
if (model == null) {
|
|
throw new import_provider30.NoSuchModelError({ modelId: id, modelType: "languageModel" });
|
|
}
|
|
if (this.languageModelMiddleware != null) {
|
|
model = wrapLanguageModel({
|
|
model,
|
|
middleware: this.languageModelMiddleware
|
|
});
|
|
}
|
|
return model;
|
|
}
|
|
textEmbeddingModel(id) {
|
|
var _a17;
|
|
const [providerId, modelId] = this.splitId(id, "textEmbeddingModel");
|
|
const provider = this.getProvider(providerId, "textEmbeddingModel");
|
|
const model = (_a17 = provider.textEmbeddingModel) == null ? void 0 : _a17.call(provider, modelId);
|
|
if (model == null) {
|
|
throw new import_provider30.NoSuchModelError({
|
|
modelId: id,
|
|
modelType: "textEmbeddingModel"
|
|
});
|
|
}
|
|
return model;
|
|
}
|
|
imageModel(id) {
|
|
var _a17;
|
|
const [providerId, modelId] = this.splitId(id, "imageModel");
|
|
const provider = this.getProvider(providerId, "imageModel");
|
|
const model = (_a17 = provider.imageModel) == null ? void 0 : _a17.call(provider, modelId);
|
|
if (model == null) {
|
|
throw new import_provider30.NoSuchModelError({ modelId: id, modelType: "imageModel" });
|
|
}
|
|
return model;
|
|
}
|
|
transcriptionModel(id) {
|
|
var _a17;
|
|
const [providerId, modelId] = this.splitId(id, "transcriptionModel");
|
|
const provider = this.getProvider(providerId, "transcriptionModel");
|
|
const model = (_a17 = provider.transcriptionModel) == null ? void 0 : _a17.call(provider, modelId);
|
|
if (model == null) {
|
|
throw new import_provider30.NoSuchModelError({
|
|
modelId: id,
|
|
modelType: "transcriptionModel"
|
|
});
|
|
}
|
|
return model;
|
|
}
|
|
speechModel(id) {
|
|
var _a17;
|
|
const [providerId, modelId] = this.splitId(id, "speechModel");
|
|
const provider = this.getProvider(providerId, "speechModel");
|
|
const model = (_a17 = provider.speechModel) == null ? void 0 : _a17.call(provider, modelId);
|
|
if (model == null) {
|
|
throw new import_provider30.NoSuchModelError({ modelId: id, modelType: "speechModel" });
|
|
}
|
|
return model;
|
|
}
|
|
};
|
|
|
|
// src/tool/mcp/mcp-client.ts
|
|
var import_provider_utils22 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/tool/mcp/mcp-sse-transport.ts
|
|
var import_provider_utils21 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/tool/mcp/json-rpc-message.ts
|
|
var import_v49 = require("zod/v4");
|
|
|
|
// src/tool/mcp/types.ts
|
|
var import_v48 = require("zod/v4");
|
|
var LATEST_PROTOCOL_VERSION = "2025-06-18";
|
|
var SUPPORTED_PROTOCOL_VERSIONS = [
|
|
LATEST_PROTOCOL_VERSION,
|
|
"2025-03-26",
|
|
"2024-11-05"
|
|
];
|
|
var ClientOrServerImplementationSchema = import_v48.z.looseObject({
|
|
name: import_v48.z.string(),
|
|
version: import_v48.z.string()
|
|
});
|
|
var BaseParamsSchema = import_v48.z.looseObject({
|
|
_meta: import_v48.z.optional(import_v48.z.object({}).loose())
|
|
});
|
|
var ResultSchema = BaseParamsSchema;
|
|
var RequestSchema = import_v48.z.object({
|
|
method: import_v48.z.string(),
|
|
params: import_v48.z.optional(BaseParamsSchema)
|
|
});
|
|
var ServerCapabilitiesSchema = import_v48.z.looseObject({
|
|
experimental: import_v48.z.optional(import_v48.z.object({}).loose()),
|
|
logging: import_v48.z.optional(import_v48.z.object({}).loose()),
|
|
prompts: import_v48.z.optional(
|
|
import_v48.z.looseObject({
|
|
listChanged: import_v48.z.optional(import_v48.z.boolean())
|
|
})
|
|
),
|
|
resources: import_v48.z.optional(
|
|
import_v48.z.looseObject({
|
|
subscribe: import_v48.z.optional(import_v48.z.boolean()),
|
|
listChanged: import_v48.z.optional(import_v48.z.boolean())
|
|
})
|
|
),
|
|
tools: import_v48.z.optional(
|
|
import_v48.z.looseObject({
|
|
listChanged: import_v48.z.optional(import_v48.z.boolean())
|
|
})
|
|
)
|
|
});
|
|
var InitializeResultSchema = ResultSchema.extend({
|
|
protocolVersion: import_v48.z.string(),
|
|
capabilities: ServerCapabilitiesSchema,
|
|
serverInfo: ClientOrServerImplementationSchema,
|
|
instructions: import_v48.z.optional(import_v48.z.string())
|
|
});
|
|
var PaginatedResultSchema = ResultSchema.extend({
|
|
nextCursor: import_v48.z.optional(import_v48.z.string())
|
|
});
|
|
var ToolSchema = import_v48.z.object({
|
|
name: import_v48.z.string(),
|
|
description: import_v48.z.optional(import_v48.z.string()),
|
|
inputSchema: import_v48.z.object({
|
|
type: import_v48.z.literal("object"),
|
|
properties: import_v48.z.optional(import_v48.z.object({}).loose())
|
|
}).loose()
|
|
}).loose();
|
|
var ListToolsResultSchema = PaginatedResultSchema.extend({
|
|
tools: import_v48.z.array(ToolSchema)
|
|
});
|
|
var TextContentSchema = import_v48.z.object({
|
|
type: import_v48.z.literal("text"),
|
|
text: import_v48.z.string()
|
|
}).loose();
|
|
var ImageContentSchema = import_v48.z.object({
|
|
type: import_v48.z.literal("image"),
|
|
data: import_v48.z.base64(),
|
|
mimeType: import_v48.z.string()
|
|
}).loose();
|
|
var ResourceContentsSchema = import_v48.z.object({
|
|
/**
|
|
* The URI of this resource.
|
|
*/
|
|
uri: import_v48.z.string(),
|
|
/**
|
|
* The MIME type of this resource, if known.
|
|
*/
|
|
mimeType: import_v48.z.optional(import_v48.z.string())
|
|
}).loose();
|
|
var TextResourceContentsSchema = ResourceContentsSchema.extend({
|
|
text: import_v48.z.string()
|
|
});
|
|
var BlobResourceContentsSchema = ResourceContentsSchema.extend({
|
|
blob: import_v48.z.base64()
|
|
});
|
|
var EmbeddedResourceSchema = import_v48.z.object({
|
|
type: import_v48.z.literal("resource"),
|
|
resource: import_v48.z.union([TextResourceContentsSchema, BlobResourceContentsSchema])
|
|
}).loose();
|
|
var CallToolResultSchema = ResultSchema.extend({
|
|
content: import_v48.z.array(
|
|
import_v48.z.union([TextContentSchema, ImageContentSchema, EmbeddedResourceSchema])
|
|
),
|
|
isError: import_v48.z.boolean().default(false).optional()
|
|
}).or(
|
|
ResultSchema.extend({
|
|
toolResult: import_v48.z.unknown()
|
|
})
|
|
);
|
|
|
|
// src/tool/mcp/json-rpc-message.ts
|
|
var JSONRPC_VERSION = "2.0";
|
|
var JSONRPCRequestSchema = import_v49.z.object({
|
|
jsonrpc: import_v49.z.literal(JSONRPC_VERSION),
|
|
id: import_v49.z.union([import_v49.z.string(), import_v49.z.number().int()])
|
|
}).merge(RequestSchema).strict();
|
|
var JSONRPCResponseSchema = import_v49.z.object({
|
|
jsonrpc: import_v49.z.literal(JSONRPC_VERSION),
|
|
id: import_v49.z.union([import_v49.z.string(), import_v49.z.number().int()]),
|
|
result: ResultSchema
|
|
}).strict();
|
|
var JSONRPCErrorSchema = import_v49.z.object({
|
|
jsonrpc: import_v49.z.literal(JSONRPC_VERSION),
|
|
id: import_v49.z.union([import_v49.z.string(), import_v49.z.number().int()]),
|
|
error: import_v49.z.object({
|
|
code: import_v49.z.number().int(),
|
|
message: import_v49.z.string(),
|
|
data: import_v49.z.optional(import_v49.z.unknown())
|
|
})
|
|
}).strict();
|
|
var JSONRPCNotificationSchema = import_v49.z.object({
|
|
jsonrpc: import_v49.z.literal(JSONRPC_VERSION)
|
|
}).merge(
|
|
import_v49.z.object({
|
|
method: import_v49.z.string(),
|
|
params: import_v49.z.optional(BaseParamsSchema)
|
|
})
|
|
).strict();
|
|
var JSONRPCMessageSchema = import_v49.z.union([
|
|
JSONRPCRequestSchema,
|
|
JSONRPCNotificationSchema,
|
|
JSONRPCResponseSchema,
|
|
JSONRPCErrorSchema
|
|
]);
|
|
|
|
// src/tool/mcp/mcp-sse-transport.ts
|
|
var SseMCPTransport = class {
|
|
constructor({
|
|
url,
|
|
headers
|
|
}) {
|
|
this.connected = false;
|
|
this.url = new URL(url);
|
|
this.headers = headers;
|
|
}
|
|
async start() {
|
|
return new Promise((resolve2, reject) => {
|
|
if (this.connected) {
|
|
return resolve2();
|
|
}
|
|
this.abortController = new AbortController();
|
|
const establishConnection = async () => {
|
|
var _a17, _b, _c;
|
|
try {
|
|
const headers = new Headers(this.headers);
|
|
headers.set("Accept", "text/event-stream");
|
|
const response = await fetch(this.url.href, {
|
|
headers,
|
|
signal: (_a17 = this.abortController) == null ? void 0 : _a17.signal
|
|
});
|
|
if (!response.ok || !response.body) {
|
|
const error = new MCPClientError({
|
|
message: `MCP SSE Transport Error: ${response.status} ${response.statusText}`
|
|
});
|
|
(_b = this.onerror) == null ? void 0 : _b.call(this, error);
|
|
return reject(error);
|
|
}
|
|
const stream = response.body.pipeThrough(new TextDecoderStream()).pipeThrough(new import_provider_utils21.EventSourceParserStream());
|
|
const reader = stream.getReader();
|
|
const processEvents = async () => {
|
|
var _a18, _b2, _c2;
|
|
try {
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done) {
|
|
if (this.connected) {
|
|
this.connected = false;
|
|
throw new MCPClientError({
|
|
message: "MCP SSE Transport Error: Connection closed unexpectedly"
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
const { event, data } = value;
|
|
if (event === "endpoint") {
|
|
this.endpoint = new URL(data, this.url);
|
|
if (this.endpoint.origin !== this.url.origin) {
|
|
throw new MCPClientError({
|
|
message: `MCP SSE Transport Error: Endpoint origin does not match connection origin: ${this.endpoint.origin}`
|
|
});
|
|
}
|
|
this.connected = true;
|
|
resolve2();
|
|
} else if (event === "message") {
|
|
try {
|
|
const message = JSONRPCMessageSchema.parse(
|
|
JSON.parse(data)
|
|
);
|
|
(_a18 = this.onmessage) == null ? void 0 : _a18.call(this, message);
|
|
} catch (error) {
|
|
const e = new MCPClientError({
|
|
message: "MCP SSE Transport Error: Failed to parse message",
|
|
cause: error
|
|
});
|
|
(_b2 = this.onerror) == null ? void 0 : _b2.call(this, e);
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof Error && error.name === "AbortError") {
|
|
return;
|
|
}
|
|
(_c2 = this.onerror) == null ? void 0 : _c2.call(this, error);
|
|
reject(error);
|
|
}
|
|
};
|
|
this.sseConnection = {
|
|
close: () => reader.cancel()
|
|
};
|
|
processEvents();
|
|
} catch (error) {
|
|
if (error instanceof Error && error.name === "AbortError") {
|
|
return;
|
|
}
|
|
(_c = this.onerror) == null ? void 0 : _c.call(this, error);
|
|
reject(error);
|
|
}
|
|
};
|
|
establishConnection();
|
|
});
|
|
}
|
|
async close() {
|
|
var _a17, _b, _c;
|
|
this.connected = false;
|
|
(_a17 = this.sseConnection) == null ? void 0 : _a17.close();
|
|
(_b = this.abortController) == null ? void 0 : _b.abort();
|
|
(_c = this.onclose) == null ? void 0 : _c.call(this);
|
|
}
|
|
async send(message) {
|
|
var _a17, _b, _c;
|
|
if (!this.endpoint || !this.connected) {
|
|
throw new MCPClientError({
|
|
message: "MCP SSE Transport Error: Not connected"
|
|
});
|
|
}
|
|
try {
|
|
const headers = new Headers(this.headers);
|
|
headers.set("Content-Type", "application/json");
|
|
const init = {
|
|
method: "POST",
|
|
headers,
|
|
body: JSON.stringify(message),
|
|
signal: (_a17 = this.abortController) == null ? void 0 : _a17.signal
|
|
};
|
|
const response = await fetch(this.endpoint, init);
|
|
if (!response.ok) {
|
|
const text2 = await response.text().catch(() => null);
|
|
const error = new MCPClientError({
|
|
message: `MCP SSE Transport Error: POSTing to endpoint (HTTP ${response.status}): ${text2}`
|
|
});
|
|
(_b = this.onerror) == null ? void 0 : _b.call(this, error);
|
|
return;
|
|
}
|
|
} catch (error) {
|
|
(_c = this.onerror) == null ? void 0 : _c.call(this, error);
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/tool/mcp/mcp-transport.ts
|
|
function createMcpTransport(config) {
|
|
if (config.type !== "sse") {
|
|
throw new MCPClientError({
|
|
message: "Unsupported or invalid transport configuration. If you are using a custom transport, make sure it implements the MCPTransport interface."
|
|
});
|
|
}
|
|
return new SseMCPTransport(config);
|
|
}
|
|
function isCustomMcpTransport(transport) {
|
|
return "start" in transport && typeof transport.start === "function" && "send" in transport && typeof transport.send === "function" && "close" in transport && typeof transport.close === "function";
|
|
}
|
|
|
|
// src/tool/mcp/mcp-client.ts
|
|
var CLIENT_VERSION = "1.0.0";
|
|
async function createMCPClient(config) {
|
|
const client = new DefaultMCPClient(config);
|
|
await client.init();
|
|
return client;
|
|
}
|
|
var DefaultMCPClient = class {
|
|
constructor({
|
|
transport: transportConfig,
|
|
name: name17 = "ai-sdk-mcp-client",
|
|
onUncaughtError
|
|
}) {
|
|
this.requestMessageId = 0;
|
|
this.responseHandlers = /* @__PURE__ */ new Map();
|
|
this.serverCapabilities = {};
|
|
this.isClosed = true;
|
|
this.onUncaughtError = onUncaughtError;
|
|
if (isCustomMcpTransport(transportConfig)) {
|
|
this.transport = transportConfig;
|
|
} else {
|
|
this.transport = createMcpTransport(transportConfig);
|
|
}
|
|
this.transport.onclose = () => this.onClose();
|
|
this.transport.onerror = (error) => this.onError(error);
|
|
this.transport.onmessage = (message) => {
|
|
if ("method" in message) {
|
|
this.onError(
|
|
new MCPClientError({
|
|
message: "Unsupported message type"
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
this.onResponse(message);
|
|
};
|
|
this.clientInfo = {
|
|
name: name17,
|
|
version: CLIENT_VERSION
|
|
};
|
|
}
|
|
async init() {
|
|
try {
|
|
await this.transport.start();
|
|
this.isClosed = false;
|
|
const result = await this.request({
|
|
request: {
|
|
method: "initialize",
|
|
params: {
|
|
protocolVersion: LATEST_PROTOCOL_VERSION,
|
|
capabilities: {},
|
|
clientInfo: this.clientInfo
|
|
}
|
|
},
|
|
resultSchema: InitializeResultSchema
|
|
});
|
|
if (result === void 0) {
|
|
throw new MCPClientError({
|
|
message: "Server sent invalid initialize result"
|
|
});
|
|
}
|
|
if (!SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) {
|
|
throw new MCPClientError({
|
|
message: `Server's protocol version is not supported: ${result.protocolVersion}`
|
|
});
|
|
}
|
|
this.serverCapabilities = result.capabilities;
|
|
await this.notification({
|
|
method: "notifications/initialized"
|
|
});
|
|
return this;
|
|
} catch (error) {
|
|
await this.close();
|
|
throw error;
|
|
}
|
|
}
|
|
async close() {
|
|
var _a17;
|
|
if (this.isClosed)
|
|
return;
|
|
await ((_a17 = this.transport) == null ? void 0 : _a17.close());
|
|
this.onClose();
|
|
}
|
|
assertCapability(method) {
|
|
switch (method) {
|
|
case "initialize":
|
|
break;
|
|
case "tools/list":
|
|
case "tools/call":
|
|
if (!this.serverCapabilities.tools) {
|
|
throw new MCPClientError({
|
|
message: `Server does not support tools`
|
|
});
|
|
}
|
|
break;
|
|
default:
|
|
throw new MCPClientError({
|
|
message: `Unsupported method: ${method}`
|
|
});
|
|
}
|
|
}
|
|
async request({
|
|
request,
|
|
resultSchema,
|
|
options
|
|
}) {
|
|
return new Promise((resolve2, reject) => {
|
|
if (this.isClosed) {
|
|
return reject(
|
|
new MCPClientError({
|
|
message: "Attempted to send a request from a closed client"
|
|
})
|
|
);
|
|
}
|
|
this.assertCapability(request.method);
|
|
const signal = options == null ? void 0 : options.signal;
|
|
signal == null ? void 0 : signal.throwIfAborted();
|
|
const messageId = this.requestMessageId++;
|
|
const jsonrpcRequest = {
|
|
...request,
|
|
jsonrpc: "2.0",
|
|
id: messageId
|
|
};
|
|
const cleanup = () => {
|
|
this.responseHandlers.delete(messageId);
|
|
};
|
|
this.responseHandlers.set(messageId, (response) => {
|
|
if (signal == null ? void 0 : signal.aborted) {
|
|
return reject(
|
|
new MCPClientError({
|
|
message: "Request was aborted",
|
|
cause: signal.reason
|
|
})
|
|
);
|
|
}
|
|
if (response instanceof Error) {
|
|
return reject(response);
|
|
}
|
|
try {
|
|
const result = resultSchema.parse(response.result);
|
|
resolve2(result);
|
|
} catch (error) {
|
|
const parseError = new MCPClientError({
|
|
message: "Failed to parse server response",
|
|
cause: error
|
|
});
|
|
reject(parseError);
|
|
}
|
|
});
|
|
this.transport.send(jsonrpcRequest).catch((error) => {
|
|
cleanup();
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
async listTools({
|
|
params,
|
|
options
|
|
} = {}) {
|
|
try {
|
|
return this.request({
|
|
request: { method: "tools/list", params },
|
|
resultSchema: ListToolsResultSchema,
|
|
options
|
|
});
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
async callTool({
|
|
name: name17,
|
|
args,
|
|
options
|
|
}) {
|
|
try {
|
|
return this.request({
|
|
request: { method: "tools/call", params: { name: name17, arguments: args } },
|
|
resultSchema: CallToolResultSchema,
|
|
options: {
|
|
signal: options == null ? void 0 : options.abortSignal
|
|
}
|
|
});
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
async notification(notification) {
|
|
const jsonrpcNotification = {
|
|
...notification,
|
|
jsonrpc: "2.0"
|
|
};
|
|
await this.transport.send(jsonrpcNotification);
|
|
}
|
|
/**
|
|
* Returns a set of AI SDK tools from the MCP server
|
|
* @returns A record of tool names to their implementations
|
|
*/
|
|
async tools({
|
|
schemas = "automatic"
|
|
} = {}) {
|
|
var _a17;
|
|
const tools = {};
|
|
try {
|
|
const listToolsResult = await this.listTools();
|
|
for (const { name: name17, description, inputSchema } of listToolsResult.tools) {
|
|
if (schemas !== "automatic" && !(name17 in schemas)) {
|
|
continue;
|
|
}
|
|
const self = this;
|
|
const execute = async (args, options) => {
|
|
var _a18;
|
|
(_a18 = options == null ? void 0 : options.abortSignal) == null ? void 0 : _a18.throwIfAborted();
|
|
return self.callTool({ name: name17, args, options });
|
|
};
|
|
const toolWithExecute = schemas === "automatic" ? (0, import_provider_utils22.dynamicTool)({
|
|
description,
|
|
inputSchema: (0, import_provider_utils22.jsonSchema)({
|
|
...inputSchema,
|
|
properties: (_a17 = inputSchema.properties) != null ? _a17 : {},
|
|
additionalProperties: false
|
|
}),
|
|
execute
|
|
}) : (0, import_provider_utils22.tool)({
|
|
description,
|
|
inputSchema: schemas[name17].inputSchema,
|
|
execute
|
|
});
|
|
tools[name17] = toolWithExecute;
|
|
}
|
|
return tools;
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
onClose() {
|
|
if (this.isClosed)
|
|
return;
|
|
this.isClosed = true;
|
|
const error = new MCPClientError({
|
|
message: "Connection closed"
|
|
});
|
|
for (const handler of this.responseHandlers.values()) {
|
|
handler(error);
|
|
}
|
|
this.responseHandlers.clear();
|
|
}
|
|
onError(error) {
|
|
if (this.onUncaughtError) {
|
|
this.onUncaughtError(error);
|
|
}
|
|
}
|
|
onResponse(response) {
|
|
const messageId = Number(response.id);
|
|
const handler = this.responseHandlers.get(messageId);
|
|
if (handler === void 0) {
|
|
throw new MCPClientError({
|
|
message: `Protocol error: Received a response for an unknown message ID: ${JSON.stringify(
|
|
response
|
|
)}`
|
|
});
|
|
}
|
|
this.responseHandlers.delete(messageId);
|
|
handler(
|
|
"result" in response ? response : new MCPClientError({
|
|
message: response.error.message,
|
|
cause: response.error
|
|
})
|
|
);
|
|
}
|
|
};
|
|
|
|
// src/error/no-transcript-generated-error.ts
|
|
var import_provider31 = require("@ai-sdk/provider");
|
|
var NoTranscriptGeneratedError = class extends import_provider31.AISDKError {
|
|
constructor(options) {
|
|
super({
|
|
name: "AI_NoTranscriptGeneratedError",
|
|
message: "No transcript generated."
|
|
});
|
|
this.responses = options.responses;
|
|
}
|
|
};
|
|
|
|
// src/transcribe/transcribe.ts
|
|
async function transcribe({
|
|
model,
|
|
audio,
|
|
providerOptions = {},
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal,
|
|
headers
|
|
}) {
|
|
if (model.specificationVersion !== "v2") {
|
|
throw new UnsupportedModelVersionError({
|
|
version: model.specificationVersion,
|
|
provider: model.provider,
|
|
modelId: model.modelId
|
|
});
|
|
}
|
|
const { retry } = prepareRetries({
|
|
maxRetries: maxRetriesArg,
|
|
abortSignal
|
|
});
|
|
const audioData = audio instanceof URL ? (await download({ url: audio })).data : convertDataContentToUint8Array(audio);
|
|
const result = await retry(
|
|
() => {
|
|
var _a17;
|
|
return model.doGenerate({
|
|
audio: audioData,
|
|
abortSignal,
|
|
headers,
|
|
providerOptions,
|
|
mediaType: (_a17 = detectMediaType({
|
|
data: audioData,
|
|
signatures: audioMediaTypeSignatures
|
|
})) != null ? _a17 : "audio/wav"
|
|
});
|
|
}
|
|
);
|
|
if (!result.text) {
|
|
throw new NoTranscriptGeneratedError({ responses: [result.response] });
|
|
}
|
|
return new DefaultTranscriptionResult({
|
|
text: result.text,
|
|
segments: result.segments,
|
|
language: result.language,
|
|
durationInSeconds: result.durationInSeconds,
|
|
warnings: result.warnings,
|
|
responses: [result.response],
|
|
providerMetadata: result.providerMetadata
|
|
});
|
|
}
|
|
var DefaultTranscriptionResult = class {
|
|
constructor(options) {
|
|
var _a17;
|
|
this.text = options.text;
|
|
this.segments = options.segments;
|
|
this.language = options.language;
|
|
this.durationInSeconds = options.durationInSeconds;
|
|
this.warnings = options.warnings;
|
|
this.responses = options.responses;
|
|
this.providerMetadata = (_a17 = options.providerMetadata) != null ? _a17 : {};
|
|
}
|
|
};
|
|
|
|
// src/ui/call-completion-api.ts
|
|
var import_provider_utils23 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/ui/process-text-stream.ts
|
|
async function processTextStream({
|
|
stream,
|
|
onTextPart
|
|
}) {
|
|
const reader = stream.pipeThrough(new TextDecoderStream()).getReader();
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done) {
|
|
break;
|
|
}
|
|
await onTextPart(value);
|
|
}
|
|
}
|
|
|
|
// src/ui/call-completion-api.ts
|
|
var getOriginalFetch = () => fetch;
|
|
async function callCompletionApi({
|
|
api,
|
|
prompt,
|
|
credentials,
|
|
headers,
|
|
body,
|
|
streamProtocol = "data",
|
|
setCompletion,
|
|
setLoading,
|
|
setError,
|
|
setAbortController,
|
|
onFinish,
|
|
onError,
|
|
fetch: fetch2 = getOriginalFetch()
|
|
}) {
|
|
var _a17;
|
|
try {
|
|
setLoading(true);
|
|
setError(void 0);
|
|
const abortController = new AbortController();
|
|
setAbortController(abortController);
|
|
setCompletion("");
|
|
const response = await fetch2(api, {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
prompt,
|
|
...body
|
|
}),
|
|
credentials,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
...headers
|
|
},
|
|
signal: abortController.signal
|
|
}).catch((err) => {
|
|
throw err;
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(
|
|
(_a17 = await response.text()) != null ? _a17 : "Failed to fetch the chat response."
|
|
);
|
|
}
|
|
if (!response.body) {
|
|
throw new Error("The response body is empty.");
|
|
}
|
|
let result = "";
|
|
switch (streamProtocol) {
|
|
case "text": {
|
|
await processTextStream({
|
|
stream: response.body,
|
|
onTextPart: (chunk) => {
|
|
result += chunk;
|
|
setCompletion(result);
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
case "data": {
|
|
await consumeStream({
|
|
stream: (0, import_provider_utils23.parseJsonEventStream)({
|
|
stream: response.body,
|
|
schema: uiMessageChunkSchema
|
|
}).pipeThrough(
|
|
new TransformStream({
|
|
async transform(part) {
|
|
if (!part.success) {
|
|
throw part.error;
|
|
}
|
|
const streamPart = part.value;
|
|
if (streamPart.type === "text-delta") {
|
|
result += streamPart.delta;
|
|
setCompletion(result);
|
|
} else if (streamPart.type === "error") {
|
|
throw new Error(streamPart.errorText);
|
|
}
|
|
}
|
|
})
|
|
),
|
|
onError: (error) => {
|
|
throw error;
|
|
}
|
|
});
|
|
break;
|
|
}
|
|
default: {
|
|
const exhaustiveCheck = streamProtocol;
|
|
throw new Error(`Unknown stream protocol: ${exhaustiveCheck}`);
|
|
}
|
|
}
|
|
if (onFinish) {
|
|
onFinish(prompt, result);
|
|
}
|
|
setAbortController(null);
|
|
return result;
|
|
} catch (err) {
|
|
if (err.name === "AbortError") {
|
|
setAbortController(null);
|
|
return null;
|
|
}
|
|
if (err instanceof Error) {
|
|
if (onError) {
|
|
onError(err);
|
|
}
|
|
}
|
|
setError(err);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
// src/ui/chat.ts
|
|
var import_provider_utils26 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/ui/convert-file-list-to-file-ui-parts.ts
|
|
async function convertFileListToFileUIParts(files) {
|
|
if (files == null) {
|
|
return [];
|
|
}
|
|
if (!globalThis.FileList || !(files instanceof globalThis.FileList)) {
|
|
throw new Error("FileList is not supported in the current environment");
|
|
}
|
|
return Promise.all(
|
|
Array.from(files).map(async (file) => {
|
|
const { name: name17, type } = file;
|
|
const dataUrl = await new Promise((resolve2, reject) => {
|
|
const reader = new FileReader();
|
|
reader.onload = (readerEvent) => {
|
|
var _a17;
|
|
resolve2((_a17 = readerEvent.target) == null ? void 0 : _a17.result);
|
|
};
|
|
reader.onerror = (error) => reject(error);
|
|
reader.readAsDataURL(file);
|
|
});
|
|
return {
|
|
type: "file",
|
|
mediaType: type,
|
|
filename: name17,
|
|
url: dataUrl
|
|
};
|
|
})
|
|
);
|
|
}
|
|
|
|
// src/ui/default-chat-transport.ts
|
|
var import_provider_utils25 = require("@ai-sdk/provider-utils");
|
|
|
|
// src/ui/http-chat-transport.ts
|
|
var import_provider_utils24 = require("@ai-sdk/provider-utils");
|
|
var HttpChatTransport = class {
|
|
constructor({
|
|
api = "/api/chat",
|
|
credentials,
|
|
headers,
|
|
body,
|
|
fetch: fetch2,
|
|
prepareSendMessagesRequest,
|
|
prepareReconnectToStreamRequest
|
|
}) {
|
|
this.api = api;
|
|
this.credentials = credentials;
|
|
this.headers = headers;
|
|
this.body = body;
|
|
this.fetch = fetch2;
|
|
this.prepareSendMessagesRequest = prepareSendMessagesRequest;
|
|
this.prepareReconnectToStreamRequest = prepareReconnectToStreamRequest;
|
|
}
|
|
async sendMessages({
|
|
abortSignal,
|
|
...options
|
|
}) {
|
|
var _a17, _b, _c, _d, _e;
|
|
const resolvedBody = await (0, import_provider_utils24.resolve)(this.body);
|
|
const resolvedHeaders = await (0, import_provider_utils24.resolve)(this.headers);
|
|
const resolvedCredentials = await (0, import_provider_utils24.resolve)(this.credentials);
|
|
const preparedRequest = await ((_a17 = this.prepareSendMessagesRequest) == null ? void 0 : _a17.call(this, {
|
|
api: this.api,
|
|
id: options.chatId,
|
|
messages: options.messages,
|
|
body: { ...resolvedBody, ...options.body },
|
|
headers: { ...resolvedHeaders, ...options.headers },
|
|
credentials: resolvedCredentials,
|
|
requestMetadata: options.metadata,
|
|
trigger: options.trigger,
|
|
messageId: options.messageId
|
|
}));
|
|
const api = (_b = preparedRequest == null ? void 0 : preparedRequest.api) != null ? _b : this.api;
|
|
const headers = (preparedRequest == null ? void 0 : preparedRequest.headers) !== void 0 ? preparedRequest.headers : { ...resolvedHeaders, ...options.headers };
|
|
const body = (preparedRequest == null ? void 0 : preparedRequest.body) !== void 0 ? preparedRequest.body : {
|
|
...resolvedBody,
|
|
...options.body,
|
|
id: options.chatId,
|
|
messages: options.messages,
|
|
trigger: options.trigger,
|
|
messageId: options.messageId
|
|
};
|
|
const credentials = (_c = preparedRequest == null ? void 0 : preparedRequest.credentials) != null ? _c : resolvedCredentials;
|
|
const fetch2 = (_d = this.fetch) != null ? _d : globalThis.fetch;
|
|
const response = await fetch2(api, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
...headers
|
|
},
|
|
body: JSON.stringify(body),
|
|
credentials,
|
|
signal: abortSignal
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(
|
|
(_e = await response.text()) != null ? _e : "Failed to fetch the chat response."
|
|
);
|
|
}
|
|
if (!response.body) {
|
|
throw new Error("The response body is empty.");
|
|
}
|
|
return this.processResponseStream(response.body);
|
|
}
|
|
async reconnectToStream(options) {
|
|
var _a17, _b, _c, _d, _e;
|
|
const resolvedBody = await (0, import_provider_utils24.resolve)(this.body);
|
|
const resolvedHeaders = await (0, import_provider_utils24.resolve)(this.headers);
|
|
const resolvedCredentials = await (0, import_provider_utils24.resolve)(this.credentials);
|
|
const preparedRequest = await ((_a17 = this.prepareReconnectToStreamRequest) == null ? void 0 : _a17.call(this, {
|
|
api: this.api,
|
|
id: options.chatId,
|
|
body: { ...resolvedBody, ...options.body },
|
|
headers: { ...resolvedHeaders, ...options.headers },
|
|
credentials: resolvedCredentials,
|
|
requestMetadata: options.metadata
|
|
}));
|
|
const api = (_b = preparedRequest == null ? void 0 : preparedRequest.api) != null ? _b : `${this.api}/${options.chatId}/stream`;
|
|
const headers = (preparedRequest == null ? void 0 : preparedRequest.headers) !== void 0 ? preparedRequest.headers : { ...resolvedHeaders, ...options.headers };
|
|
const credentials = (_c = preparedRequest == null ? void 0 : preparedRequest.credentials) != null ? _c : resolvedCredentials;
|
|
const fetch2 = (_d = this.fetch) != null ? _d : globalThis.fetch;
|
|
const response = await fetch2(api, {
|
|
method: "GET",
|
|
headers,
|
|
credentials
|
|
});
|
|
if (response.status === 204) {
|
|
return null;
|
|
}
|
|
if (!response.ok) {
|
|
throw new Error(
|
|
(_e = await response.text()) != null ? _e : "Failed to fetch the chat response."
|
|
);
|
|
}
|
|
if (!response.body) {
|
|
throw new Error("The response body is empty.");
|
|
}
|
|
return this.processResponseStream(response.body);
|
|
}
|
|
};
|
|
|
|
// src/ui/default-chat-transport.ts
|
|
var DefaultChatTransport = class extends HttpChatTransport {
|
|
constructor(options = {}) {
|
|
super(options);
|
|
}
|
|
processResponseStream(stream) {
|
|
return (0, import_provider_utils25.parseJsonEventStream)({
|
|
stream,
|
|
schema: uiMessageChunkSchema
|
|
}).pipeThrough(
|
|
new TransformStream({
|
|
async transform(chunk, controller) {
|
|
if (!chunk.success) {
|
|
throw chunk.error;
|
|
}
|
|
controller.enqueue(chunk.value);
|
|
}
|
|
})
|
|
);
|
|
}
|
|
};
|
|
|
|
// src/ui/chat.ts
|
|
var AbstractChat = class {
|
|
constructor({
|
|
generateId: generateId3 = import_provider_utils26.generateId,
|
|
id = generateId3(),
|
|
transport = new DefaultChatTransport(),
|
|
messageMetadataSchema,
|
|
dataPartSchemas,
|
|
state,
|
|
onError,
|
|
onToolCall,
|
|
onFinish,
|
|
onData,
|
|
sendAutomaticallyWhen
|
|
}) {
|
|
this.activeResponse = void 0;
|
|
this.jobExecutor = new SerialJobExecutor();
|
|
/**
|
|
* Appends or replaces a user message to the chat list. This triggers the API call to fetch
|
|
* the assistant's response.
|
|
*
|
|
* If a messageId is provided, the message will be replaced.
|
|
*/
|
|
this.sendMessage = async (message, options) => {
|
|
var _a17, _b, _c, _d;
|
|
if (message == null) {
|
|
await this.makeRequest({
|
|
trigger: "submit-message",
|
|
messageId: (_a17 = this.lastMessage) == null ? void 0 : _a17.id,
|
|
...options
|
|
});
|
|
return;
|
|
}
|
|
let uiMessage;
|
|
if ("text" in message || "files" in message) {
|
|
const fileParts = Array.isArray(message.files) ? message.files : await convertFileListToFileUIParts(message.files);
|
|
uiMessage = {
|
|
parts: [
|
|
...fileParts,
|
|
..."text" in message && message.text != null ? [{ type: "text", text: message.text }] : []
|
|
]
|
|
};
|
|
} else {
|
|
uiMessage = message;
|
|
}
|
|
if (message.messageId != null) {
|
|
const messageIndex = this.state.messages.findIndex(
|
|
(m) => m.id === message.messageId
|
|
);
|
|
if (messageIndex === -1) {
|
|
throw new Error(`message with id ${message.messageId} not found`);
|
|
}
|
|
if (this.state.messages[messageIndex].role !== "user") {
|
|
throw new Error(
|
|
`message with id ${message.messageId} is not a user message`
|
|
);
|
|
}
|
|
this.state.messages = this.state.messages.slice(0, messageIndex + 1);
|
|
this.state.replaceMessage(messageIndex, {
|
|
...uiMessage,
|
|
id: message.messageId,
|
|
role: (_b = uiMessage.role) != null ? _b : "user",
|
|
metadata: message.metadata
|
|
});
|
|
} else {
|
|
this.state.pushMessage({
|
|
...uiMessage,
|
|
id: (_c = uiMessage.id) != null ? _c : this.generateId(),
|
|
role: (_d = uiMessage.role) != null ? _d : "user",
|
|
metadata: message.metadata
|
|
});
|
|
}
|
|
await this.makeRequest({
|
|
trigger: "submit-message",
|
|
messageId: message.messageId,
|
|
...options
|
|
});
|
|
};
|
|
/**
|
|
* Regenerate the assistant message with the provided message id.
|
|
* If no message id is provided, the last assistant message will be regenerated.
|
|
*/
|
|
this.regenerate = async ({
|
|
messageId,
|
|
...options
|
|
} = {}) => {
|
|
const messageIndex = messageId == null ? this.state.messages.length - 1 : this.state.messages.findIndex((message) => message.id === messageId);
|
|
if (messageIndex === -1) {
|
|
throw new Error(`message ${messageId} not found`);
|
|
}
|
|
this.state.messages = this.state.messages.slice(
|
|
0,
|
|
// if the message is a user message, we need to include it in the request:
|
|
this.messages[messageIndex].role === "assistant" ? messageIndex : messageIndex + 1
|
|
);
|
|
await this.makeRequest({
|
|
trigger: "regenerate-message",
|
|
messageId,
|
|
...options
|
|
});
|
|
};
|
|
/**
|
|
* Attempt to resume an ongoing streaming response.
|
|
*/
|
|
this.resumeStream = async (options = {}) => {
|
|
await this.makeRequest({ trigger: "resume-stream", ...options });
|
|
};
|
|
/**
|
|
* Clear the error state and set the status to ready if the chat is in an error state.
|
|
*/
|
|
this.clearError = () => {
|
|
if (this.status === "error") {
|
|
this.state.error = void 0;
|
|
this.setStatus({ status: "ready" });
|
|
}
|
|
};
|
|
this.addToolResult = async ({
|
|
tool: tool3,
|
|
toolCallId,
|
|
output
|
|
}) => this.jobExecutor.run(async () => {
|
|
var _a17, _b;
|
|
const messages = this.state.messages;
|
|
const lastMessage = messages[messages.length - 1];
|
|
this.state.replaceMessage(messages.length - 1, {
|
|
...lastMessage,
|
|
parts: lastMessage.parts.map(
|
|
(part) => isToolUIPart(part) && part.toolCallId === toolCallId ? { ...part, state: "output-available", output } : part
|
|
)
|
|
});
|
|
if (this.activeResponse) {
|
|
this.activeResponse.state.message.parts = this.activeResponse.state.message.parts.map(
|
|
(part) => isToolUIPart(part) && part.toolCallId === toolCallId ? {
|
|
...part,
|
|
state: "output-available",
|
|
output,
|
|
errorText: void 0
|
|
} : part
|
|
);
|
|
}
|
|
if (this.status !== "streaming" && this.status !== "submitted" && ((_a17 = this.sendAutomaticallyWhen) == null ? void 0 : _a17.call(this, { messages: this.state.messages }))) {
|
|
this.makeRequest({
|
|
trigger: "submit-message",
|
|
messageId: (_b = this.lastMessage) == null ? void 0 : _b.id
|
|
});
|
|
}
|
|
});
|
|
/**
|
|
* Abort the current request immediately, keep the generated tokens if any.
|
|
*/
|
|
this.stop = async () => {
|
|
var _a17;
|
|
if (this.status !== "streaming" && this.status !== "submitted")
|
|
return;
|
|
if ((_a17 = this.activeResponse) == null ? void 0 : _a17.abortController) {
|
|
this.activeResponse.abortController.abort();
|
|
}
|
|
};
|
|
this.id = id;
|
|
this.transport = transport;
|
|
this.generateId = generateId3;
|
|
this.messageMetadataSchema = messageMetadataSchema;
|
|
this.dataPartSchemas = dataPartSchemas;
|
|
this.state = state;
|
|
this.onError = onError;
|
|
this.onToolCall = onToolCall;
|
|
this.onFinish = onFinish;
|
|
this.onData = onData;
|
|
this.sendAutomaticallyWhen = sendAutomaticallyWhen;
|
|
}
|
|
/**
|
|
* Hook status:
|
|
*
|
|
* - `submitted`: The message has been sent to the API and we're awaiting the start of the response stream.
|
|
* - `streaming`: The response is actively streaming in from the API, receiving chunks of data.
|
|
* - `ready`: The full response has been received and processed; a new user message can be submitted.
|
|
* - `error`: An error occurred during the API request, preventing successful completion.
|
|
*/
|
|
get status() {
|
|
return this.state.status;
|
|
}
|
|
setStatus({
|
|
status,
|
|
error
|
|
}) {
|
|
if (this.status === status)
|
|
return;
|
|
this.state.status = status;
|
|
this.state.error = error;
|
|
}
|
|
get error() {
|
|
return this.state.error;
|
|
}
|
|
get messages() {
|
|
return this.state.messages;
|
|
}
|
|
get lastMessage() {
|
|
return this.state.messages[this.state.messages.length - 1];
|
|
}
|
|
set messages(messages) {
|
|
this.state.messages = messages;
|
|
}
|
|
async makeRequest({
|
|
trigger,
|
|
metadata,
|
|
headers,
|
|
body,
|
|
messageId
|
|
}) {
|
|
var _a17, _b, _c;
|
|
this.setStatus({ status: "submitted", error: void 0 });
|
|
const lastMessage = this.lastMessage;
|
|
try {
|
|
const activeResponse = {
|
|
state: createStreamingUIMessageState({
|
|
lastMessage: this.state.snapshot(lastMessage),
|
|
messageId: this.generateId()
|
|
}),
|
|
abortController: new AbortController()
|
|
};
|
|
this.activeResponse = activeResponse;
|
|
let stream;
|
|
if (trigger === "resume-stream") {
|
|
const reconnect = await this.transport.reconnectToStream({
|
|
chatId: this.id,
|
|
metadata,
|
|
headers,
|
|
body
|
|
});
|
|
if (reconnect == null) {
|
|
this.setStatus({ status: "ready" });
|
|
return;
|
|
}
|
|
stream = reconnect;
|
|
} else {
|
|
stream = await this.transport.sendMessages({
|
|
chatId: this.id,
|
|
messages: this.state.messages,
|
|
abortSignal: activeResponse.abortController.signal,
|
|
metadata,
|
|
headers,
|
|
body,
|
|
trigger,
|
|
messageId
|
|
});
|
|
}
|
|
const runUpdateMessageJob = (job) => (
|
|
// serialize the job execution to avoid race conditions:
|
|
this.jobExecutor.run(
|
|
() => job({
|
|
state: activeResponse.state,
|
|
write: () => {
|
|
var _a18;
|
|
this.setStatus({ status: "streaming" });
|
|
const replaceLastMessage = activeResponse.state.message.id === ((_a18 = this.lastMessage) == null ? void 0 : _a18.id);
|
|
if (replaceLastMessage) {
|
|
this.state.replaceMessage(
|
|
this.state.messages.length - 1,
|
|
activeResponse.state.message
|
|
);
|
|
} else {
|
|
this.state.pushMessage(activeResponse.state.message);
|
|
}
|
|
}
|
|
})
|
|
)
|
|
);
|
|
await consumeStream({
|
|
stream: processUIMessageStream({
|
|
stream,
|
|
onToolCall: this.onToolCall,
|
|
onData: this.onData,
|
|
messageMetadataSchema: this.messageMetadataSchema,
|
|
dataPartSchemas: this.dataPartSchemas,
|
|
runUpdateMessageJob,
|
|
onError: (error) => {
|
|
throw error;
|
|
}
|
|
}),
|
|
onError: (error) => {
|
|
throw error;
|
|
}
|
|
});
|
|
(_a17 = this.onFinish) == null ? void 0 : _a17.call(this, { message: activeResponse.state.message });
|
|
this.setStatus({ status: "ready" });
|
|
} catch (err) {
|
|
if (err.name === "AbortError") {
|
|
this.setStatus({ status: "ready" });
|
|
return null;
|
|
}
|
|
if (this.onError && err instanceof Error) {
|
|
this.onError(err);
|
|
}
|
|
this.setStatus({ status: "error", error: err });
|
|
} finally {
|
|
this.activeResponse = void 0;
|
|
}
|
|
if ((_b = this.sendAutomaticallyWhen) == null ? void 0 : _b.call(this, { messages: this.state.messages })) {
|
|
await this.makeRequest({
|
|
trigger: "submit-message",
|
|
messageId: (_c = this.lastMessage) == null ? void 0 : _c.id,
|
|
metadata,
|
|
headers,
|
|
body
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
// src/ui/convert-to-model-messages.ts
|
|
function convertToModelMessages(messages, options) {
|
|
const modelMessages = [];
|
|
if (options == null ? void 0 : options.ignoreIncompleteToolCalls) {
|
|
messages = messages.map((message) => ({
|
|
...message,
|
|
parts: message.parts.filter(
|
|
(part) => !isToolUIPart(part) || part.state !== "input-streaming" && part.state !== "input-available"
|
|
)
|
|
}));
|
|
}
|
|
for (const message of messages) {
|
|
switch (message.role) {
|
|
case "system": {
|
|
const textParts = message.parts.filter((part) => part.type === "text");
|
|
const providerMetadata = textParts.reduce((acc, part) => {
|
|
if (part.providerMetadata != null) {
|
|
return { ...acc, ...part.providerMetadata };
|
|
}
|
|
return acc;
|
|
}, {});
|
|
modelMessages.push({
|
|
role: "system",
|
|
content: textParts.map((part) => part.text).join(""),
|
|
...Object.keys(providerMetadata).length > 0 ? { providerOptions: providerMetadata } : {}
|
|
});
|
|
break;
|
|
}
|
|
case "user": {
|
|
modelMessages.push({
|
|
role: "user",
|
|
content: message.parts.filter(
|
|
(part) => part.type === "text" || part.type === "file"
|
|
).map((part) => {
|
|
switch (part.type) {
|
|
case "text":
|
|
return {
|
|
type: "text",
|
|
text: part.text,
|
|
...part.providerMetadata != null ? { providerOptions: part.providerMetadata } : {}
|
|
};
|
|
case "file":
|
|
return {
|
|
type: "file",
|
|
mediaType: part.mediaType,
|
|
filename: part.filename,
|
|
data: part.url,
|
|
...part.providerMetadata != null ? { providerOptions: part.providerMetadata } : {}
|
|
};
|
|
default:
|
|
return part;
|
|
}
|
|
})
|
|
});
|
|
break;
|
|
}
|
|
case "assistant": {
|
|
if (message.parts != null) {
|
|
let processBlock2 = function() {
|
|
var _a17, _b;
|
|
if (block.length === 0) {
|
|
return;
|
|
}
|
|
const content = [];
|
|
for (const part of block) {
|
|
if (part.type === "text") {
|
|
content.push({
|
|
type: "text",
|
|
text: part.text,
|
|
...part.providerMetadata != null ? { providerOptions: part.providerMetadata } : {}
|
|
});
|
|
} else if (part.type === "file") {
|
|
content.push({
|
|
type: "file",
|
|
mediaType: part.mediaType,
|
|
filename: part.filename,
|
|
data: part.url
|
|
});
|
|
} else if (part.type === "reasoning") {
|
|
content.push({
|
|
type: "reasoning",
|
|
text: part.text,
|
|
providerOptions: part.providerMetadata
|
|
});
|
|
} else if (part.type === "dynamic-tool") {
|
|
const toolName = part.toolName;
|
|
if (part.state === "input-streaming") {
|
|
throw new MessageConversionError({
|
|
originalMessage: message,
|
|
message: `incomplete tool input is not supported: ${part.toolCallId}`
|
|
});
|
|
} else {
|
|
content.push({
|
|
type: "tool-call",
|
|
toolCallId: part.toolCallId,
|
|
toolName,
|
|
input: part.input,
|
|
...part.callProviderMetadata != null ? { providerOptions: part.callProviderMetadata } : {}
|
|
});
|
|
}
|
|
} else if (isToolUIPart(part)) {
|
|
const toolName = getToolName(part);
|
|
if (part.state === "input-streaming") {
|
|
throw new MessageConversionError({
|
|
originalMessage: message,
|
|
message: `incomplete tool input is not supported: ${part.toolCallId}`
|
|
});
|
|
} else {
|
|
content.push({
|
|
type: "tool-call",
|
|
toolCallId: part.toolCallId,
|
|
toolName,
|
|
input: part.state === "output-error" ? (_a17 = part.input) != null ? _a17 : part.rawInput : part.input,
|
|
providerExecuted: part.providerExecuted,
|
|
...part.callProviderMetadata != null ? { providerOptions: part.callProviderMetadata } : {}
|
|
});
|
|
if (part.providerExecuted === true && (part.state === "output-available" || part.state === "output-error")) {
|
|
content.push({
|
|
type: "tool-result",
|
|
toolCallId: part.toolCallId,
|
|
toolName,
|
|
output: createToolModelOutput({
|
|
output: part.state === "output-error" ? part.errorText : part.output,
|
|
tool: (_b = options == null ? void 0 : options.tools) == null ? void 0 : _b[toolName],
|
|
errorMode: part.state === "output-error" ? "json" : "none"
|
|
})
|
|
});
|
|
}
|
|
}
|
|
} else {
|
|
const _exhaustiveCheck = part;
|
|
throw new Error(`Unsupported part: ${_exhaustiveCheck}`);
|
|
}
|
|
}
|
|
modelMessages.push({
|
|
role: "assistant",
|
|
content
|
|
});
|
|
const toolParts = block.filter(
|
|
(part) => isToolUIPart(part) && part.providerExecuted !== true || part.type === "dynamic-tool"
|
|
);
|
|
if (toolParts.length > 0) {
|
|
modelMessages.push({
|
|
role: "tool",
|
|
content: toolParts.map((toolPart) => {
|
|
var _a18;
|
|
switch (toolPart.state) {
|
|
case "output-error":
|
|
case "output-available": {
|
|
const toolName = toolPart.type === "dynamic-tool" ? toolPart.toolName : getToolName(toolPart);
|
|
return {
|
|
type: "tool-result",
|
|
toolCallId: toolPart.toolCallId,
|
|
toolName,
|
|
output: createToolModelOutput({
|
|
output: toolPart.state === "output-error" ? toolPart.errorText : toolPart.output,
|
|
tool: (_a18 = options == null ? void 0 : options.tools) == null ? void 0 : _a18[toolName],
|
|
errorMode: toolPart.state === "output-error" ? "text" : "none"
|
|
})
|
|
};
|
|
}
|
|
default: {
|
|
throw new MessageConversionError({
|
|
originalMessage: message,
|
|
message: `Unsupported tool part state: ${toolPart.state}`
|
|
});
|
|
}
|
|
}
|
|
})
|
|
});
|
|
}
|
|
block = [];
|
|
};
|
|
var processBlock = processBlock2;
|
|
let block = [];
|
|
for (const part of message.parts) {
|
|
if (part.type === "text" || part.type === "reasoning" || part.type === "file" || part.type === "dynamic-tool" || isToolUIPart(part)) {
|
|
block.push(part);
|
|
} else if (part.type === "step-start") {
|
|
processBlock2();
|
|
}
|
|
}
|
|
processBlock2();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
const _exhaustiveCheck = message.role;
|
|
throw new MessageConversionError({
|
|
originalMessage: message,
|
|
message: `Unsupported role: ${_exhaustiveCheck}`
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return modelMessages;
|
|
}
|
|
var convertToCoreMessages = convertToModelMessages;
|
|
|
|
// src/ui/last-assistant-message-is-complete-with-tool-calls.ts
|
|
function lastAssistantMessageIsCompleteWithToolCalls({
|
|
messages
|
|
}) {
|
|
const message = messages[messages.length - 1];
|
|
if (!message) {
|
|
return false;
|
|
}
|
|
if (message.role !== "assistant") {
|
|
return false;
|
|
}
|
|
const lastStepStartIndex = message.parts.reduce((lastIndex, part, index) => {
|
|
return part.type === "step-start" ? index : lastIndex;
|
|
}, -1);
|
|
const lastStepToolInvocations = message.parts.slice(lastStepStartIndex + 1).filter((part) => isToolUIPart(part) || part.type === "dynamic-tool");
|
|
return lastStepToolInvocations.length > 0 && lastStepToolInvocations.every((part) => part.state === "output-available");
|
|
}
|
|
|
|
// src/ui/transform-text-to-ui-message-stream.ts
|
|
function transformTextToUiMessageStream({
|
|
stream
|
|
}) {
|
|
return stream.pipeThrough(
|
|
new TransformStream({
|
|
start(controller) {
|
|
controller.enqueue({ type: "start" });
|
|
controller.enqueue({ type: "start-step" });
|
|
controller.enqueue({ type: "text-start", id: "text-1" });
|
|
},
|
|
async transform(part, controller) {
|
|
controller.enqueue({ type: "text-delta", id: "text-1", delta: part });
|
|
},
|
|
async flush(controller) {
|
|
controller.enqueue({ type: "text-end", id: "text-1" });
|
|
controller.enqueue({ type: "finish-step" });
|
|
controller.enqueue({ type: "finish" });
|
|
}
|
|
})
|
|
);
|
|
}
|
|
|
|
// src/ui/text-stream-chat-transport.ts
|
|
var TextStreamChatTransport = class extends HttpChatTransport {
|
|
constructor(options = {}) {
|
|
super(options);
|
|
}
|
|
processResponseStream(stream) {
|
|
return transformTextToUiMessageStream({
|
|
stream: stream.pipeThrough(new TextDecoderStream())
|
|
});
|
|
}
|
|
};
|
|
|
|
// src/ui-message-stream/create-ui-message-stream.ts
|
|
var import_provider_utils27 = require("@ai-sdk/provider-utils");
|
|
function createUIMessageStream({
|
|
execute,
|
|
onError = import_provider_utils27.getErrorMessage,
|
|
originalMessages,
|
|
onFinish,
|
|
generateId: generateId3 = import_provider_utils27.generateId
|
|
}) {
|
|
let controller;
|
|
const ongoingStreamPromises = [];
|
|
const stream = new ReadableStream({
|
|
start(controllerArg) {
|
|
controller = controllerArg;
|
|
}
|
|
});
|
|
function safeEnqueue(data) {
|
|
try {
|
|
controller.enqueue(data);
|
|
} catch (error) {
|
|
}
|
|
}
|
|
try {
|
|
const result = execute({
|
|
writer: {
|
|
write(part) {
|
|
safeEnqueue(part);
|
|
},
|
|
merge(streamArg) {
|
|
ongoingStreamPromises.push(
|
|
(async () => {
|
|
const reader = streamArg.getReader();
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done)
|
|
break;
|
|
safeEnqueue(value);
|
|
}
|
|
})().catch((error) => {
|
|
safeEnqueue({
|
|
type: "error",
|
|
errorText: onError(error)
|
|
});
|
|
})
|
|
);
|
|
},
|
|
onError
|
|
}
|
|
});
|
|
if (result) {
|
|
ongoingStreamPromises.push(
|
|
result.catch((error) => {
|
|
safeEnqueue({
|
|
type: "error",
|
|
errorText: onError(error)
|
|
});
|
|
})
|
|
);
|
|
}
|
|
} catch (error) {
|
|
safeEnqueue({
|
|
type: "error",
|
|
errorText: onError(error)
|
|
});
|
|
}
|
|
const waitForStreams = new Promise(async (resolve2) => {
|
|
while (ongoingStreamPromises.length > 0) {
|
|
await ongoingStreamPromises.shift();
|
|
}
|
|
resolve2();
|
|
});
|
|
waitForStreams.finally(() => {
|
|
try {
|
|
controller.close();
|
|
} catch (error) {
|
|
}
|
|
});
|
|
return handleUIMessageStreamFinish({
|
|
stream,
|
|
messageId: generateId3(),
|
|
originalMessages,
|
|
onFinish,
|
|
onError
|
|
});
|
|
}
|
|
|
|
// src/ui-message-stream/read-ui-message-stream.ts
|
|
function readUIMessageStream({
|
|
message,
|
|
stream,
|
|
onError,
|
|
terminateOnError = false
|
|
}) {
|
|
var _a17;
|
|
let controller;
|
|
let hasErrored = false;
|
|
const outputStream = new ReadableStream({
|
|
start(controllerParam) {
|
|
controller = controllerParam;
|
|
}
|
|
});
|
|
const state = createStreamingUIMessageState({
|
|
messageId: (_a17 = message == null ? void 0 : message.id) != null ? _a17 : "",
|
|
lastMessage: message
|
|
});
|
|
const handleError = (error) => {
|
|
onError == null ? void 0 : onError(error);
|
|
if (!hasErrored && terminateOnError) {
|
|
hasErrored = true;
|
|
controller == null ? void 0 : controller.error(error);
|
|
}
|
|
};
|
|
consumeStream({
|
|
stream: processUIMessageStream({
|
|
stream,
|
|
runUpdateMessageJob(job) {
|
|
return job({
|
|
state,
|
|
write: () => {
|
|
controller == null ? void 0 : controller.enqueue(structuredClone(state.message));
|
|
}
|
|
});
|
|
},
|
|
onError: handleError
|
|
}),
|
|
onError: handleError
|
|
}).finally(() => {
|
|
if (!hasErrored) {
|
|
controller == null ? void 0 : controller.close();
|
|
}
|
|
});
|
|
return createAsyncIterableStream(outputStream);
|
|
}
|
|
// Annotate the CommonJS export names for ESM import in node:
|
|
0 && (module.exports = {
|
|
AISDKError,
|
|
APICallError,
|
|
AbstractChat,
|
|
DefaultChatTransport,
|
|
DownloadError,
|
|
EmptyResponseBodyError,
|
|
Experimental_Agent,
|
|
HttpChatTransport,
|
|
InvalidArgumentError,
|
|
InvalidDataContentError,
|
|
InvalidMessageRoleError,
|
|
InvalidPromptError,
|
|
InvalidResponseDataError,
|
|
InvalidStreamPartError,
|
|
InvalidToolInputError,
|
|
JSONParseError,
|
|
JsonToSseTransformStream,
|
|
LoadAPIKeyError,
|
|
MCPClientError,
|
|
MessageConversionError,
|
|
NoContentGeneratedError,
|
|
NoImageGeneratedError,
|
|
NoObjectGeneratedError,
|
|
NoOutputGeneratedError,
|
|
NoOutputSpecifiedError,
|
|
NoSuchModelError,
|
|
NoSuchProviderError,
|
|
NoSuchToolError,
|
|
Output,
|
|
RetryError,
|
|
SerialJobExecutor,
|
|
TextStreamChatTransport,
|
|
ToolCallRepairError,
|
|
TypeValidationError,
|
|
UI_MESSAGE_STREAM_HEADERS,
|
|
UnsupportedFunctionalityError,
|
|
UnsupportedModelVersionError,
|
|
asSchema,
|
|
assistantModelMessageSchema,
|
|
callCompletionApi,
|
|
consumeStream,
|
|
convertFileListToFileUIParts,
|
|
convertToCoreMessages,
|
|
convertToModelMessages,
|
|
coreAssistantMessageSchema,
|
|
coreMessageSchema,
|
|
coreSystemMessageSchema,
|
|
coreToolMessageSchema,
|
|
coreUserMessageSchema,
|
|
cosineSimilarity,
|
|
createIdGenerator,
|
|
createProviderRegistry,
|
|
createTextStreamResponse,
|
|
createUIMessageStream,
|
|
createUIMessageStreamResponse,
|
|
customProvider,
|
|
defaultSettingsMiddleware,
|
|
dynamicTool,
|
|
embed,
|
|
embedMany,
|
|
experimental_createMCPClient,
|
|
experimental_createProviderRegistry,
|
|
experimental_customProvider,
|
|
experimental_generateImage,
|
|
experimental_generateSpeech,
|
|
experimental_transcribe,
|
|
extractReasoningMiddleware,
|
|
generateId,
|
|
generateObject,
|
|
generateText,
|
|
getTextFromDataUrl,
|
|
getToolName,
|
|
hasToolCall,
|
|
isDeepEqualData,
|
|
isToolUIPart,
|
|
jsonSchema,
|
|
lastAssistantMessageIsCompleteWithToolCalls,
|
|
modelMessageSchema,
|
|
parsePartialJson,
|
|
pipeTextStreamToResponse,
|
|
pipeUIMessageStreamToResponse,
|
|
readUIMessageStream,
|
|
simulateReadableStream,
|
|
simulateStreamingMiddleware,
|
|
smoothStream,
|
|
stepCountIs,
|
|
streamObject,
|
|
streamText,
|
|
systemModelMessageSchema,
|
|
tool,
|
|
toolModelMessageSchema,
|
|
userModelMessageSchema,
|
|
wrapLanguageModel,
|
|
wrapProvider,
|
|
zodSchema
|
|
});
|
|
//# sourceMappingURL=index.js.map
|