@mastra/core
Version:
237 lines (236 loc) • 6.88 kB
JavaScript
let crypto = require("crypto");
//#region src/llm/model/aisdk/generate-to-stream.ts
/**
* Converts a doGenerate result to a ReadableStream format.
* This is shared between V2 and V3 model wrappers since the content/result structure is compatible.
*/
function createStreamFromGenerateResult(result) {
return new ReadableStream({ start(controller) {
controller.enqueue({
type: "stream-start",
warnings: result.warnings
});
controller.enqueue({
type: "response-metadata",
id: result.response?.id,
modelId: result.response?.modelId,
timestamp: result.response?.timestamp
});
const toolCallMeta = {};
for (const message of result.content) if (message.type === "tool-call") {
const toolCall = message;
toolCallMeta[toolCall.toolCallId] = { providerExecuted: toolCall.providerExecuted };
controller.enqueue({
type: "tool-input-start",
id: toolCall.toolCallId,
toolName: toolCall.toolName,
providerExecuted: toolCall.providerExecuted,
dynamic: toolCall.dynamic,
providerMetadata: toolCall.providerMetadata
});
controller.enqueue({
type: "tool-input-delta",
id: toolCall.toolCallId,
delta: toolCall.input,
providerMetadata: toolCall.providerMetadata
});
controller.enqueue({
type: "tool-input-end",
id: toolCall.toolCallId,
providerMetadata: toolCall.providerMetadata
});
controller.enqueue(toolCall);
} else if (message.type === "tool-result") {
const toolResult = message;
const meta = toolCallMeta[toolResult.toolCallId];
if (meta?.providerExecuted) controller.enqueue({
...toolResult,
providerExecuted: meta.providerExecuted
});
else controller.enqueue(message);
} else if (message.type === "text") {
const text = message;
const id = `msg_${(0, crypto.randomUUID)()}`;
controller.enqueue({
type: "text-start",
id,
providerMetadata: text.providerMetadata
});
controller.enqueue({
type: "text-delta",
id,
delta: text.text
});
controller.enqueue({
type: "text-end",
id
});
} else if (message.type === "reasoning") {
const id = `reasoning_${(0, crypto.randomUUID)()}`;
const reasoning = message;
controller.enqueue({
type: "reasoning-start",
id,
providerMetadata: reasoning.providerMetadata
});
controller.enqueue({
type: "reasoning-delta",
id,
delta: reasoning.text,
providerMetadata: reasoning.providerMetadata
});
controller.enqueue({
type: "reasoning-end",
id,
providerMetadata: reasoning.providerMetadata
});
} else if (message.type === "file") {
const file = message;
controller.enqueue({
type: "file",
mediaType: file.mediaType,
data: file.data
});
} else if (message.type === "source") {
const source = message;
if (source.sourceType === "url") controller.enqueue({
type: "source",
id: source.id,
sourceType: "url",
url: source.url,
title: source.title,
providerMetadata: source.providerMetadata
});
else controller.enqueue({
type: "source",
id: source.id,
sourceType: "document",
mediaType: source.mediaType,
filename: source.filename,
title: source.title,
providerMetadata: source.providerMetadata
});
}
controller.enqueue({
type: "finish",
finishReason: result.finishReason,
usage: result.usage,
providerMetadata: result.providerMetadata
});
controller.close();
} });
}
//#endregion
//#region src/llm/model/aisdk/v5/model.ts
/**
* Strips per-tool `strict` from function tools (V2 providers don't support it)
* and, when any tool had `strict: true`, injects `strictJsonSchema: true` into
* the OpenAI provider options so the V2 OpenAI provider enables strict mode
* globally for all tools.
*/
function applyStrictForV2(options) {
if (!options.tools?.length) return options;
let hasStrictTool = false;
const sanitizedTools = options.tools.map((tool) => {
if (tool.type !== "function" || !("strict" in tool)) return tool;
if (tool.strict === true) hasStrictTool = true;
const { strict: _strict, ...rest } = tool;
return rest;
});
let result = {
...options,
tools: sanitizedTools
};
if (hasStrictTool) {
const existingOpenai = options.providerOptions?.openai ?? {};
if (existingOpenai.strictJsonSchema == null) result = {
...result,
providerOptions: {
...options.providerOptions,
openai: {
...existingOpenai,
strictJsonSchema: true
}
}
};
}
return result;
}
/**
* Wrapper class for AI SDK V5 (LanguageModelV2) that converts doGenerate to return
* a stream format for consistency with Mastra's streaming architecture.
*/
var AISDKV5LanguageModel = class {
/**
* The language model must specify which language model interface version it implements.
*/
specificationVersion = "v2";
/**
* Name of the provider for logging purposes.
*/
provider;
/**
* Provider-specific model ID for logging purposes.
*/
modelId;
gatewayId;
/**
* Supported URL patterns by media type for the provider.
*
* The keys are media type patterns or full media types (e.g. `*\/*` for everything, `audio/*`, `video/*`, or `application/pdf`).
* and the values are arrays of regular expressions that match the URL paths.
* The matching should be against lower-case URLs.
* Matched URLs are supported natively by the model and are not downloaded.
* @returns A map of supported URL patterns by media type (as a promise or a plain object).
*/
supportedUrls;
#model;
constructor(config) {
this.#model = config;
this.provider = this.#model.provider;
this.modelId = this.#model.modelId;
this.gatewayId = config.gatewayId;
this.supportedUrls = this.#model.supportedUrls;
}
async doGenerate(options) {
const result = await this.#model.doGenerate(applyStrictForV2(options));
return {
...result,
request: result.request,
response: result.response,
stream: createStreamFromGenerateResult(result)
};
}
async doStream(options) {
return await this.#model.doStream(applyStrictForV2(options));
}
/**
* Custom serialization for tracing/observability spans.
* `#model` is already a true JS private field and not enumerable, so
* the wrapped provider SDK client can't leak. This method makes the
* safe shape explicit and avoids walking `supportedUrls` (a
* PromiseLike / regex map that isn't useful in spans).
*/
serializeForSpan() {
return {
specificationVersion: this.specificationVersion,
modelId: this.modelId,
provider: this.provider,
gatewayId: this.gatewayId
};
}
};
//#endregion
Object.defineProperty(exports, "AISDKV5LanguageModel", {
enumerable: true,
get: function() {
return AISDKV5LanguageModel;
}
});
Object.defineProperty(exports, "createStreamFromGenerateResult", {
enumerable: true,
get: function() {
return createStreamFromGenerateResult;
}
});
//# sourceMappingURL=model-CxJfDXLP.cjs.map