UNPKG

@langchain/core

Version:
268 lines (266 loc) 10 kB
import { Serializable } from "../load/serializable.js"; import { isDataContentBlock } from "./content/data.js"; import { convertToV1FromAnthropicInput } from "./block_translators/anthropic.js"; import { convertToV1FromDataContent } from "./block_translators/data.js"; import { convertToV1FromChatCompletionsInput } from "./block_translators/openai.js"; import { isMessage } from "./message.js"; import { convertToFormattedString } from "./format.js"; //#region src/messages/base.ts /** @internal */ const MESSAGE_SYMBOL = Symbol.for("langchain.message"); function mergeContent(firstContent, secondContent) { if (typeof firstContent === "string") { if (firstContent === "") return secondContent; if (typeof secondContent === "string") return firstContent + secondContent; else if (Array.isArray(secondContent) && secondContent.some((c) => isDataContentBlock(c))) return [{ type: "text", source_type: "text", text: firstContent }, ...secondContent]; else return [{ type: "text", text: firstContent }, ...secondContent]; } else if (Array.isArray(secondContent)) return _mergeLists(firstContent, secondContent) ?? [...firstContent, ...secondContent]; else if (secondContent === "") return firstContent; else if (Array.isArray(firstContent) && firstContent.some((c) => isDataContentBlock(c))) return [...firstContent, { type: "file", source_type: "text", text: secondContent }]; else return [...firstContent, { type: "text", text: secondContent }]; } /** * 'Merge' two statuses. If either value passed is 'error', it will return 'error'. Else * it will return 'success'. * * @param {"success" | "error" | undefined} left The existing value to 'merge' with the new value. * @param {"success" | "error" | undefined} right The new value to 'merge' with the existing value * @returns {"success" | "error"} The 'merged' value. */ function _mergeStatus(left, right) { if (left === "error" || right === "error") return "error"; return "success"; } function stringifyWithDepthLimit(obj, depthLimit) { function helper(obj$1, currentDepth) { if (typeof obj$1 !== "object" || obj$1 === null || obj$1 === void 0) return obj$1; if (currentDepth >= depthLimit) { if (Array.isArray(obj$1)) return "[Array]"; return "[Object]"; } if (Array.isArray(obj$1)) return obj$1.map((item) => helper(item, currentDepth + 1)); const result = {}; for (const key of Object.keys(obj$1)) result[key] = helper(obj$1[key], currentDepth + 1); return result; } return JSON.stringify(helper(obj, 0), null, 2); } /** * Base class for all types of messages in a conversation. It includes * properties like `content`, `name`, and `additional_kwargs`. It also * includes methods like `toDict()` and `_getType()`. */ var BaseMessage = class extends Serializable { lc_namespace = ["langchain_core", "messages"]; lc_serializable = true; get lc_aliases() { return { additional_kwargs: "additional_kwargs", response_metadata: "response_metadata" }; } [MESSAGE_SYMBOL] = true; id; name; content; additional_kwargs; response_metadata; /** * @deprecated Use .getType() instead or import the proper typeguard. * For example: * * ```ts * import { isAIMessage } from "@langchain/core/messages"; * * const message = new AIMessage("Hello!"); * isAIMessage(message); // true * ``` */ _getType() { return this.type; } /** * @deprecated Use .type instead * The type of the message. */ getType() { return this._getType(); } constructor(arg) { const fields = typeof arg === "string" || Array.isArray(arg) ? { content: arg } : arg; if (!fields.additional_kwargs) fields.additional_kwargs = {}; if (!fields.response_metadata) fields.response_metadata = {}; super(fields); this.name = fields.name; if (fields.content === void 0 && fields.contentBlocks !== void 0) { this.content = fields.contentBlocks; this.response_metadata = { output_version: "v1", ...fields.response_metadata }; } else if (fields.content !== void 0) { this.content = fields.content ?? []; this.response_metadata = fields.response_metadata; } else { this.content = []; this.response_metadata = fields.response_metadata; } this.additional_kwargs = fields.additional_kwargs; this.id = fields.id; } /** Get text content of the message. */ get text() { if (typeof this.content === "string") return this.content; if (!Array.isArray(this.content)) return ""; return this.content.map((c) => { if (typeof c === "string") return c; if (c.type === "text") return c.text; return ""; }).join(""); } get contentBlocks() { const blocks = typeof this.content === "string" ? [{ type: "text", text: this.content }] : this.content; const parsingSteps = [ convertToV1FromDataContent, convertToV1FromChatCompletionsInput, convertToV1FromAnthropicInput ]; const parsedBlocks = parsingSteps.reduce((blocks$1, step) => step(blocks$1), blocks); return parsedBlocks; } toDict() { return { type: this.getType(), data: this.toJSON().kwargs }; } static lc_name() { return "BaseMessage"; } get _printableFields() { return { id: this.id, content: this.content, name: this.name, additional_kwargs: this.additional_kwargs, response_metadata: this.response_metadata }; } static isInstance(obj) { return typeof obj === "object" && obj !== null && MESSAGE_SYMBOL in obj && obj[MESSAGE_SYMBOL] === true && isMessage(obj); } _updateId(value) { this.id = value; this.lc_kwargs.id = value; } get [Symbol.toStringTag]() { return this.constructor.lc_name(); } [Symbol.for("nodejs.util.inspect.custom")](depth) { if (depth === null) return this; const printable = stringifyWithDepthLimit(this._printableFields, Math.max(4, depth)); return `${this.constructor.lc_name()} ${printable}`; } toFormattedString(format = "pretty") { return convertToFormattedString(this, format); } }; function isOpenAIToolCallArray(value) { return Array.isArray(value) && value.every((v) => typeof v.index === "number"); } function _mergeDicts(left = {}, right = {}) { const merged = { ...left }; for (const [key, value] of Object.entries(right)) if (merged[key] == null) merged[key] = value; else if (value == null) continue; else if (typeof merged[key] !== typeof value || Array.isArray(merged[key]) !== Array.isArray(value)) throw new Error(`field[${key}] already exists in the message chunk, but with a different type.`); else if (typeof merged[key] === "string") if (key === "type") continue; else if ([ "id", "name", "output_version", "model_provider" ].includes(key)) merged[key] = value; else merged[key] += value; else if (typeof merged[key] === "object" && !Array.isArray(merged[key])) merged[key] = _mergeDicts(merged[key], value); else if (Array.isArray(merged[key])) merged[key] = _mergeLists(merged[key], value); else if (merged[key] === value) continue; else console.warn(`field[${key}] already exists in this message chunk and value has unsupported type.`); return merged; } function _mergeLists(left, right) { if (left === void 0 && right === void 0) return void 0; else if (left === void 0 || right === void 0) return left || right; else { const merged = [...left]; for (const item of right) if (typeof item === "object" && item !== null && "index" in item && typeof item.index === "number") { const toMerge = merged.findIndex((leftItem) => { const isObject = typeof leftItem === "object"; const indiciesMatch = "index" in leftItem && leftItem.index === item.index; const idsMatch = "id" in leftItem && "id" in item && leftItem?.id === item?.id; const eitherItemMissingID = !("id" in leftItem) || !leftItem?.id || !("id" in item) || !item?.id; return isObject && indiciesMatch && (idsMatch || eitherItemMissingID); }); if (toMerge !== -1 && typeof merged[toMerge] === "object" && merged[toMerge] !== null) merged[toMerge] = _mergeDicts(merged[toMerge], item); else merged.push(item); } else if (typeof item === "object" && item !== null && "text" in item && item.text === "") continue; else merged.push(item); return merged; } } function _mergeObj(left, right) { if (!left && !right) throw new Error("Cannot merge two undefined objects."); if (!left || !right) return left || right; else if (typeof left !== typeof right) throw new Error(`Cannot merge objects of different types.\nLeft ${typeof left}\nRight ${typeof right}`); else if (typeof left === "string" && typeof right === "string") return left + right; else if (Array.isArray(left) && Array.isArray(right)) return _mergeLists(left, right); else if (typeof left === "object" && typeof right === "object") return _mergeDicts(left, right); else if (left === right) return left; else throw new Error(`Can not merge objects of different types.\nLeft ${left}\nRight ${right}`); } /** * Represents a chunk of a message, which can be concatenated with other * message chunks. It includes a method `_merge_kwargs_dict()` for merging * additional keyword arguments from another `BaseMessageChunk` into this * one. It also overrides the `__add__()` method to support concatenation * of `BaseMessageChunk` instances. */ var BaseMessageChunk = class extends BaseMessage { static isInstance(obj) { return super.isInstance(obj) && "concat" in obj && typeof obj.concat === "function"; } }; function _isMessageFieldWithRole(x) { return typeof x.role === "string"; } /** * @deprecated Use {@link BaseMessage.isInstance} instead */ function isBaseMessage(messageLike) { return typeof messageLike?._getType === "function"; } /** * @deprecated Use {@link BaseMessageChunk.isInstance} instead */ function isBaseMessageChunk(messageLike) { return isBaseMessage(messageLike) && typeof messageLike.concat === "function"; } //#endregion export { BaseMessage, BaseMessageChunk, _isMessageFieldWithRole, _mergeDicts, _mergeLists, _mergeObj, _mergeStatus, isBaseMessage, isBaseMessageChunk, isOpenAIToolCallArray, mergeContent }; //# sourceMappingURL=base.js.map