@mastra/core
Version:
511 lines (509 loc) • 16.9 kB
JavaScript
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("&", "&").replaceAll("<", "<").replaceAll(">", ">");
}
function escapeXmlAttribute(value) {
return escapeXml(value).replaceAll("\"", """);
}
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