UNPKG

@mastra/core

Version:
511 lines (509 loc) • 16.9 kB
let _ai_sdk_provider_utils_v5 = require("@ai-sdk/provider-utils-v5"); //#region src/agent/message-list/prompt/data-content.ts /** Converts data content to a base64-encoded string. @param content - Data content to convert. @returns Base64-encoded string. */ function convertDataContentToBase64String(content) { if (typeof content === "string") return content; if (content instanceof ArrayBuffer) return (0, _ai_sdk_provider_utils_v5.convertUint8ArrayToBase64)(new Uint8Array(content)); return (0, _ai_sdk_provider_utils_v5.convertUint8ArrayToBase64)(content); } //#endregion //#region src/agent/signals.ts function isMastraSignalMessage(message) { return message.role === "signal"; } /** * True for a signal DB message created with `transient: true`. * * @mastra/memory keeps a matching local predicate because its peer range includes core versions * without this export. Keep both copies in sync until that peer range can be tightened. * * @experimental Agent signals are experimental and may change in a future release. */ function isTransientSignalMessage(message) { if (message.role !== "signal") return false; const metadata = message.content?.metadata; if (!metadata || typeof metadata !== "object") return false; const signal = metadata.signal; return !!signal && typeof signal === "object" && !Array.isArray(signal) && signal.transient === true; } function normalizeSignalType(input) { if (input.type === "user-message") return { type: "user", tagName: input.tagName ?? "user" }; if (input.type === "system-reminder") return { type: "reactive", tagName: input.tagName ?? "system-reminder" }; if (input.type === "user" || input.type === "state" || input.type === "notification") return { type: input.type, tagName: input.tagName ?? input.type }; if (input.type === "reactive") return { type: "reactive", tagName: input.tagName ?? "system-reminder" }; throw new Error(`Invalid signal type: ${input.type}. Use a supported signal type and set tagName for custom XML tags.`); } function normalizeSignal(signal) { const { type, tagName } = normalizeSignalType(signal); return { ...signal, type, tagName, id: signal.id ?? crypto.randomUUID(), createdAt: signal.createdAt instanceof Date ? signal.createdAt : signal.createdAt ? new Date(signal.createdAt) : /* @__PURE__ */ new Date(), acceptedAt: signal.acceptedAt instanceof Date ? signal.acceptedAt : signal.acceptedAt ? new Date(signal.acceptedAt) : void 0 }; } function escapeXml(value) { return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;"); } function escapeXmlAttribute(value) { return escapeXml(value).replaceAll("\"", "&quot;"); } const XML_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_.-]*$/; function assertXmlName(name, label) { if (!XML_NAME_PATTERN.test(name)) throw new Error(`Invalid signal XML ${label}: ${name}`); } function signalAttributesToXml(attributes) { if (!attributes) return ""; const serialized = Object.entries(attributes).filter((entry) => entry[1] !== null && entry[1] !== void 0).map(([key, value]) => { assertXmlName(key, "attribute name"); return `${key}="${escapeXmlAttribute(String(value))}"`; }).join(" "); return serialized ? ` ${serialized}` : ""; } function signalToXmlMarkup(signal) { const tagName = signal.tagName ?? normalizeSignalType(signal).tagName; assertXmlName(tagName, "tag name"); const attributesXml = signalAttributesToXml(signal.attributes); if (!signal.contents) return `<${tagName}${attributesXml} />`; return `<${tagName}${attributesXml}>${escapeXml(signal.contents)}</${tagName}>`; } function legacyContentsToSignalContents(value) { if (typeof value === "string") return value; if (Array.isArray(value)) { const parts = []; for (const entry of value) { if (typeof entry === "string") { parts.push({ type: "text", text: entry }); continue; } const decoded = legacyEntryToParts(entry); if (!decoded) return void 0; parts.push(...decoded); } return collapseLegacyParts(parts); } const decoded = legacyEntryToParts(value); return decoded ? collapseLegacyParts(decoded) : void 0; } function legacyEntryToParts(entry) { if (!entry || typeof entry !== "object") return void 0; const record = entry; if (record.role === "user" && "content" in record) { const content = record.content; if (typeof content === "string") return [{ type: "text", text: content }]; if (Array.isArray(content)) { const inner = []; for (const part of content) { const decoded = legacyPartToSignalPart(part); if (!decoded) return void 0; inner.push(decoded); } return inner; } return; } const part = legacyPartToSignalPart(record); return part ? [part] : void 0; } function legacyPartToSignalPart(part) { if (!part || typeof part !== "object") return void 0; const record = part; const providerOptions = record.providerOptions && typeof record.providerOptions === "object" && !Array.isArray(record.providerOptions) ? record.providerOptions : void 0; if (record.type === "text" && typeof record.text === "string") return { type: "text", text: record.text, ...providerOptions ? { providerOptions } : {} }; if (record.type === "file" || record.type === "image") { const data = record.type === "image" ? record.image ?? record.data : record.data; if (typeof data !== "string") return void 0; const mediaType = typeof record.mediaType === "string" ? record.mediaType : typeof record.mimeType === "string" ? record.mimeType : record.type === "image" ? "image/png" : ""; if (!mediaType) return void 0; return { type: "file", data, mediaType, ...typeof record.filename === "string" ? { filename: record.filename } : {}, ...providerOptions ? { providerOptions } : {} }; } } function collapseLegacyParts(parts) { if (parts.length === 0) return void 0; const first = parts[0]; if (parts.length === 1 && first?.type === "text") return first.text; return parts; } function contentsToSignalParts(contents) { if (typeof contents === "string") return [{ type: "text", text: contents }]; return contents.map((part) => { if (part.type === "file") return { type: "file", data: part.data instanceof URL ? part.data.toString() : convertDataContentToBase64String(part.data), mediaType: part.mediaType, ...part.filename ? { filename: part.filename } : {}, ...part.providerOptions ? { providerOptions: part.providerOptions } : {} }; return { type: "text", text: part.text, ...part.providerOptions ? { providerOptions: part.providerOptions } : {} }; }); } function storagePartsToSignalParts(parts) { const out = []; for (const part of parts) { const providerOptions = part.providerMetadata; if (part.type === "text") out.push({ type: "text", text: part.text, ...providerOptions ? { providerOptions } : {} }); else if (part.type === "file" && typeof part.data === "string") { const file = part; out.push({ type: "file", data: file.data, mediaType: typeof file.mimeType === "string" ? file.mimeType : "", ...typeof file.filename === "string" ? { filename: file.filename } : {}, ...providerOptions ? { providerOptions } : {} }); } } return out; } function partsToSignalContents(parts) { if (parts.length === 1 && parts[0]?.type === "text" && !parts[0].providerOptions) return parts[0].text; return parts.map((part) => part.type === "file" ? { type: "file", data: part.data, mediaType: part.mediaType, ...part.filename ? { filename: part.filename } : {}, ...part.providerOptions ? { providerOptions: part.providerOptions } : {} } : { type: "text", text: part.text, ...part.providerOptions ? { providerOptions: part.providerOptions } : {} }); } function hasMeaningfulAttributes(attributes) { if (!attributes) return false; return Object.keys(attributes).some((key) => { const value = attributes[key]; return value !== null && value !== void 0; }); } function injectMarkerInline(signal, parts) { let wrapped = false; const out = []; for (const part of parts) if (!wrapped && part.type === "text") { wrapped = true; out.push({ ...part, text: signalToXmlMarkup({ ...signal, contents: part.text }) }); } else out.push(part); if (!wrapped) { const markerText = signalToXmlMarkup({ type: signal.type, tagName: signal.tagName, attributes: signal.attributes }); out.unshift({ type: "text", text: markerText }); } return out; } function signalToLLMMessage(signal, parts) { const isUserMessage = signal.type === "user"; const hasAttrs = hasMeaningfulAttributes(signal.attributes); const anyPartProviderOptions = parts.some((part) => part.providerOptions); let content; if (isUserMessage && !hasAttrs) content = parts.length === 1 && parts[0]?.type === "text" && !parts[0].providerOptions ? parts[0].text : parts; else if (parts.every((part) => part.type === "text") && !anyPartProviderOptions) content = signalToXmlMarkup({ ...signal, contents: parts.map((part) => part.text).join("\n") }); else content = injectMarkerInline(signal, parts); return { role: "user", content, ...signal.providerOptions ? { providerOptions: signal.providerOptions } : {} }; } function signalToDataPart(signal, parts) { return { type: signal.type === "user" ? "data-user-message" : "data-signal", data: { id: signal.id, type: signal.type, tagName: signal.tagName, contents: partsToSignalContents(parts), createdAt: signal.createdAt.toISOString(), ...signal.acceptedAt ? { acceptedAt: signal.acceptedAt.toISOString() } : {}, ...signal.attributes ? { attributes: signal.attributes } : {}, ...signal.metadata ? { metadata: signal.metadata } : {}, ...signal.providerOptions ? { providerOptions: signal.providerOptions } : {}, ...signal.transient ? { transient: true } : {} }, transient: true }; } function signalToDBMessage(signal, parts, options) { const storageParts = parts.length > 0 ? parts.map((part) => part.type === "file" ? { type: "file", data: part.data, mimeType: part.mediaType, ...part.filename ? { filename: part.filename } : {}, ...part.providerOptions ? { providerMetadata: part.providerOptions } : {} } : { type: "text", text: part.text, ...part.providerOptions ? { providerMetadata: part.providerOptions } : {} }) : [{ type: "text", text: "" }]; return { id: signal.id, role: "signal", createdAt: signal.createdAt, threadId: options?.threadId, resourceId: options?.resourceId, type: signal.tagName, content: { format: 2, parts: storageParts, ...signal.providerOptions ? { providerMetadata: signal.providerOptions } : {}, metadata: { signal: { id: signal.id, type: signal.type, tagName: signal.tagName, createdAt: signal.createdAt.toISOString(), ...signal.acceptedAt ? { acceptedAt: signal.acceptedAt.toISOString() } : {}, ...signal.attributes ? { attributes: signal.attributes } : {}, ...signal.metadata ? { metadata: signal.metadata } : {}, ...signal.transient ? { transient: true } : {} } } } }; } function isCreatedAgentSignal(input) { if (!input || typeof input !== "object" || Array.isArray(input)) return false; return input.__isCreatedSignal === true; } function createSignal(input) { if (input.type === "state" && input.transient !== void 0) throw new Error("state signals cannot be transient"); const signal = normalizeSignal(input); const parts = contentsToSignalParts(signal.contents); const created = { ...signal, __isCreatedSignal: true, toDBMessage: (options) => signalToDBMessage(signal, parts, options), toLLMMessage: () => signalToLLMMessage(signal, parts), toDataPart: () => signalToDataPart(signal, parts) }; if (created.type === "state") { const { transient: _transient, ...stateSignal } = created; return { ...stateSignal, type: created.type }; } return { ...created, type: created.type }; } /** * Resolve delivery option attributes into concrete `attributes` on a signal. * Returns a new signal with the selected branch's `attributes` merged into * top-level `attributes`. * * @experimental */ function resolveDeliveryAttributes(signal, attributes) { if (!attributes || Object.keys(attributes).length === 0) return signal; return createSignal({ ...signal, attributes: { ...signal.attributes, ...attributes } }); } function signalToMessage(signal) { return createSignal(signal).toLLMMessage(); } function signalToMastraDBMessage(signal, options) { return createSignal(signal).toDBMessage(options); } function signalToDataPartFormat(signal) { return createSignal(signal).toDataPart(); } function mastraDBMessageToSignal(message) { const metadataSignal = message.content.metadata?.signal; const signalMetadata = metadataSignal && typeof metadataSignal === "object" && !Array.isArray(metadataSignal) ? metadataSignal : void 0; const type = typeof signalMetadata?.type === "string" ? signalMetadata.type : message.type ?? "user-message"; const tagName = typeof signalMetadata?.tagName === "string" ? signalMetadata.tagName : void 0; const legacyContents = legacyContentsToSignalContents(signalMetadata && "contents" in signalMetadata ? signalMetadata.contents : void 0); const partsContents = partsToSignalContents(storagePartsToSignalParts(message.content.parts)); const contents = legacyContents ?? partsContents; const providerMetadata = message.content.providerMetadata; const base = { id: typeof signalMetadata?.id === "string" ? signalMetadata.id : message.id, createdAt: typeof signalMetadata?.createdAt === "string" ? signalMetadata.createdAt : message.createdAt, acceptedAt: typeof signalMetadata?.acceptedAt === "string" ? signalMetadata.acceptedAt : void 0, attributes: signalMetadata?.attributes && typeof signalMetadata.attributes === "object" && !Array.isArray(signalMetadata.attributes) ? signalMetadata.attributes : void 0, metadata: signalMetadata?.metadata && typeof signalMetadata.metadata === "object" && !Array.isArray(signalMetadata.metadata) ? signalMetadata.metadata : void 0, providerOptions: providerMetadata && typeof providerMetadata === "object" && !Array.isArray(providerMetadata) ? providerMetadata : void 0 }; if (type === "state" && signalMetadata?.transient !== void 0) throw new Error("state signals cannot be transient"); return type === "state" ? createSignal({ ...base, type, tagName, contents }) : createSignal({ ...base, type, tagName, contents, transient: signalMetadata?.transient === true ? true : void 0 }); } function createMessageSignal(input, options) { return createSignal({ ...typeof input === "string" || Array.isArray(input) ? { contents: input } : input, ...options, type: "user", tagName: "user" }); } function dataPartToSignal(part) { if (part.data.type === "state") { if (part.data.transient !== void 0) throw new Error("state signals cannot be transient"); const { transient: _transient, ...data } = part.data; return createSignal({ ...data, type: "state" }); } return createSignal({ ...part.data, type: part.data.type }); } //#endregion Object.defineProperty(exports, "convertDataContentToBase64String", { enumerable: true, get: function() { return convertDataContentToBase64String; } }); Object.defineProperty(exports, "createMessageSignal", { enumerable: true, get: function() { return createMessageSignal; } }); Object.defineProperty(exports, "createSignal", { enumerable: true, get: function() { return createSignal; } }); Object.defineProperty(exports, "dataPartToSignal", { enumerable: true, get: function() { return dataPartToSignal; } }); Object.defineProperty(exports, "isCreatedAgentSignal", { enumerable: true, get: function() { return isCreatedAgentSignal; } }); Object.defineProperty(exports, "isMastraSignalMessage", { enumerable: true, get: function() { return isMastraSignalMessage; } }); Object.defineProperty(exports, "isTransientSignalMessage", { enumerable: true, get: function() { return isTransientSignalMessage; } }); Object.defineProperty(exports, "mastraDBMessageToSignal", { enumerable: true, get: function() { return mastraDBMessageToSignal; } }); Object.defineProperty(exports, "resolveDeliveryAttributes", { enumerable: true, get: function() { return resolveDeliveryAttributes; } }); Object.defineProperty(exports, "signalToDataPartFormat", { enumerable: true, get: function() { return signalToDataPartFormat; } }); Object.defineProperty(exports, "signalToMastraDBMessage", { enumerable: true, get: function() { return signalToMastraDBMessage; } }); Object.defineProperty(exports, "signalToMessage", { enumerable: true, get: function() { return signalToMessage; } }); Object.defineProperty(exports, "signalToXmlMarkup", { enumerable: true, get: function() { return signalToXmlMarkup; } }); //# sourceMappingURL=signals-D2CulJo3.cjs.map