@langchain/core
Version:
Core LangChain.js abstractions and schemas
598 lines (596 loc) • 24.2 kB
text/typescript
import { ContentBlock } from "./content/index.cjs";
import { ResponseMetadata, UsageMetadata } from "./metadata.cjs";
import { $MergeDiscriminatedUnion, $MergeObjects } from "./utils.cjs";
//#region src/messages/message.d.ts
/**
* Represents the possible types of messages in the system.
* Includes standard message types ("ai", "human", "tool", "system")
* and allows for custom string types that are non-null.
*
* @example
* ```ts
* // Standard message types
* const messageType1: MessageType = "ai";
* const messageType2: MessageType = "human";
*
* // Custom message type
* const messageType3: MessageType = "custom_type";
* ```
*/
type MessageType = "ai" | "human" | "tool" | "system" | (string & NonNullable<unknown>);
/**
* Represents the output version format for message content.
*
* This type determines how the content field is structured in a message:
* - "v0": Content is represented as a simple string or array of content blocks
* - provides backward compatibility with simpler content representations
* - "v1": Content follows the structured ContentBlock format with typed discriminated unions
* - enables full type safety and structured content block handling
*
* @example
* ```ts
* // v0 format - simple content representation
* const v0Message: Message<{ outputVersion: "v0", content: ... }> = {
* type: "human",
* content: "Hello world" // string | Array<ContentBlock | ContentBlock.Text>
* };
*
* // v1 format - structured content blocks
* const v1Message: Message<{ outputVersion: "v1", content: ... }> = {
* type: "human",
* content: [
* { type: "text", text: "Hello world" },
* { type: "image", image_url: "..." }
* ] // Array<ContentBlock | ...> (determined by the structure)
* };
* ```
*/
type MessageOutputVersion = "v0" | "v1";
/**
* Represents the input and output types of a tool that can be used in messages.
*
* @template TInput - The type of input the tool accepts.
* @template TOutput - The type of output the tool produces.
*
* @example
* ```ts
* // Tool that takes a string input and returns a number
* interface StringToNumberTool extends MessageToolDefinition<string, number> {
* input: string;
* output: number;
* }
* ```
*/
interface MessageToolDefinition<TInput = unknown, TOutput = unknown> {
input: TInput;
output: TOutput;
}
/**
* Represents a structured set of tools by mapping tool names to definitions
* that can be used in messages.
*
* @example
* ```ts
* interface MyToolSet extends MessageToolSet {
* calculator: MessageToolDefinition<
* { operation: string; numbers: number[] },
* number
* >;
* translator: MessageToolDefinition<
* { text: string; targetLanguage: string },
* string
* >;
* }
* ```
*/
interface MessageToolSet {
[key: string]: MessageToolDefinition;
}
/**
* Represents a tool call block within a message structure by mapping tool names to their
* corresponding tool call formats, including the input arguments and an optional identifier.
*
* @template TStructure - A message structure type that may contain tool definitions
*
* @example
* ```ts
* // Given a message structure with a calculator tool:
* interface MyStructure extends MessageStructure {
* tools: {
* calculator: MessageToolDefinition<{ operation: string, numbers: number[] }, number>
* }
* }
*
* // The tool call block would be:
* type CalcToolCall = $MessageToolCallBlock<MyStructure>;
* // Resolves to:
* // {
* // type: "tool_call";
* // name: "calculator";
* // args: { operation: string, numbers: number[] };
* // id?: string;
* // }
* ```
*/
type $MessageToolCallBlock<TStructure extends MessageStructure> = TStructure["tools"] extends MessageToolSet ? { [K in keyof TStructure["tools"]]: K extends string ? TStructure["tools"][K] extends MessageToolDefinition ? ContentBlock.Tools.ToolCall<K, TStructure["tools"][K]["input"]> : never : never }[keyof TStructure["tools"]] : never;
/**
* Core interface that defines the structure of messages.
*
* @example
* ```ts
* // Basic message structure with just content blocks
* interface SimpleMessageStructure extends MessageStructure {
* content: {
* human: ContentBlock.Text;
* // allows for text + reasoning blocks in ai messages
* ai: ContentBlock.Text | ContentBlock.Reasoning;
* }
* }
*
* // Message structure with tools and properties
* interface AdvancedMessageStructure extends MessageStructure {
* tools: {
* calculator: MessageToolDefinition<
* { operation: string; numbers: number[] },
* number
* >;
* };
* content: {
* // allows for text + image blocks in human messages
* human: ContentBlock.Text | ContentBlock.Multimodal.Image;
* // only allows for text blocks in ai messages
* ai: ContentBlock.Text;
* };
* properties: {
* // pins properties to ai messages
* ai: {
* response_metadata: {
* confidence: number;
* model: string;
* };
* };
* }
* }
*
* // Using with $MergeMessageStructure to combine structures
* // The resulting type when passed into BaseMessage will have a calculator tool,
* // allow for text + image blocks in human messages,
* // and text + reasoning blocks + additional arbitrary properties in ai messages.
* type CombinedStructure = $MergeMessageStructure<
* SimpleMessageStructure,
* AdvancedMessageStructure
* >;
*
* // Using in a Message object
* const message: Message<CombinedStructure> = {
* id: "msg-123",
* type: "human",
* content: [
* { type: "text", text: "Hello!" }
* { type: "image", mimeType: "image/jpeg", url: "https://example.com/image.jpg" }
* // this block will throw an error because it's not defined in the structure
* { type: "reasoning", reasoning: "The answer is 42" }
* ]
* };
* ```
*/
interface MessageStructure {
/**
* Optional output version for the message structure.
* If not provided, defaults to "v0".
*/
readonly outputVersion?: MessageOutputVersion;
/**
* Optional set of tool definitions that can be used in messages.
* Each tool is defined with input/output types and can be referenced in tool messages.
*/
readonly tools?: MessageToolSet;
/**
* Optional mapping of message types to their allowed content blocks.
* Each message type can specify what content block types it supports (text, images, etc).
*/
readonly content?: Partial<{ [key in MessageType]: ContentBlock }>;
/**
* Optional mapping of message types to arbitrary property objects.
* Allows attaching custom metadata or other information to specific message types.
*/
readonly properties?: Partial<{ [key in MessageType]: Record<string, unknown> }>;
}
/**
* Normalizes an arbitrary type to a message output version or undefined.
* Accepts unknown and narrows to a valid MessageOutputVersion if present.
*/
type $NormalizeMessageOutputVersion<T> = Extract<T, MessageOutputVersion> | undefined;
/**
* Merges two output version types from message structures.
*
* This utility type determines the resulting output version when combining two message structures.
* The merge logic follows these rules:
*
* - If both T and U are undefined, defaults to "v0" for backwards compatibility
* - If T is undefined but U is defined, uses U's version
* - If U is undefined but T is defined, uses T's version
* - If both T and U are defined, U takes precedence (later structure wins)
*
* @template T - The output version from the first message structure
* @template U - The output version from the second message structure
*
* @example
* ```ts
* // Both undefined - defaults to "v0"
* type Result1 = $MergeOutputVersion<undefined, undefined>; // "v0"
*
* // One defined - uses the defined version
* type Result2 = $MergeOutputVersion<undefined, "v1">; // "v1"
* type Result3 = $MergeOutputVersion<"v0", undefined>; // "v0"
*
* // Both defined - second takes precedence
* type Result4 = $MergeOutputVersion<"v0", "v1">; // "v1"
* ```
*/
type $MergeOutputVersion<T, U> = $NormalizeMessageOutputVersion<T> extends infer TV ? $NormalizeMessageOutputVersion<U> extends infer UV ? [TV, UV] extends [undefined, undefined] ? "v0" : [TV] extends [undefined] ? Exclude<UV, undefined> : [UV] extends [undefined] ? Exclude<TV, undefined> : UV : never : never;
/**
* Merges two content definition objects from message structures.
*
* This utility type combines content definitions from two message structures, handling
* the merging of content block types for each message type. The merge logic follows
* these rules:
*
* - For keys that exist in both T and U: Merges the content blocks using discriminated
* union merging based on the "type" property. This allows combining different content
* block types (e.g., text + image) for the same message type.
* - For keys that exist only in T: Uses T's content definition as-is
* - For keys that exist only in U: Uses U's content definition as-is
*
* @template T - The content definition from the first message structure
* @template U - The content definition from the second message structure
*
* @example
* ```ts
* // T allows text content for human messages
* type ContentA = {
* human: ContentBlock.Text;
* };
*
* // U allows image content for human messages and text for AI messages
* type ContentB = {
* human: ContentBlock.Multimodal.Image;
* ai: ContentBlock.Text;
* };
*
* // Merged result allows both text and images for human messages, text for AI
* type Merged = $MergeContentDefinition<ContentA, ContentB>;
* // Result: {
* // human: ContentBlock.Text | ContentBlock.Multimodal.Image;
* // ai: ContentBlock.Text;
* // }
* ```
*/
type $MergeContentDefinition<T, U> = { [K in keyof T | keyof U as Extract<(K extends keyof T ? T[K] : never) | (K extends keyof U ? U[K] : never), ContentBlock> extends never ? never : K]: K extends keyof T ? K extends keyof U ? $MergeDiscriminatedUnion<Extract<T[K], ContentBlock>, Extract<U[K], ContentBlock>, "type"> : Extract<T[K], ContentBlock> : K extends keyof U ? Extract<U[K], ContentBlock> : never };
/**
* Merges two message structures A and B into a combined structure.
* This is a type utility that handles merging of tools, content blocks, and properties
* from two message structures. The resulting type is usable as its own message structure.
*
* @example
* ```ts
* // Structure A allows text in human messages and has a confidence property on AI messages
* interface StructureA extends MessageStructure {
* content: {
* human: ContentBlock.Text;
* };
* properties: {
* ai: { confidence: number };
* }
* }
*
* // Structure B allows images in human messages and has a model property on AI messages
* interface StructureB extends MessageStructure {
* content: {
* human: ContentBlock.Multimodal.Image;
* };
* properties: {
* ai: { model: string };
* }
* }
*
* // Merged structure allows both text and images in human messages
* // AI messages have both confidence and model properties
* type Merged = $MergeMessageStructure<StructureA, StructureB>;
* ```
*
* @template A - First message structure to merge
* @template B - Second message structure to merge (takes precedence over A)
*/
type $MergeMessageStructure<T extends MessageStructure, U extends MessageStructure> = {
outputVersion: $MergeOutputVersion<T["outputVersion"], U["outputVersion"]>;
tools: $MergeObjects<T["tools"], U["tools"]>;
content: $MergeContentDefinition<T["content"], U["content"]>;
properties: $MergeObjects<T["properties"], U["properties"]>;
};
/**
* Standard message structured used to define the most basic message structure that's
* used throughout the library.
*
* This is also the message structure that's used when a message structure is not provided.
*/
interface StandardMessageStructure extends MessageStructure {
content: {
/** Text content for AI messages */
ai: ContentBlock.Text;
/** Text content for human messages */
human: ContentBlock.Text;
/** Text content for system messages */
system: ContentBlock.Text;
/** Text content for tool messages */
tool: ContentBlock.Text;
};
properties: {
/** Properties specific to AI messages */
ai: {
/** Metadata about the AI model response */
response_metadata: ResponseMetadata;
/** Usage statistics for the AI response */
usage_metadata: UsageMetadata;
};
human: {
/** Metadata about the human message */
response_metadata: Record<string, unknown>;
};
system: {
/** Metadata about the system message */
response_metadata: Record<string, unknown>;
};
tool: {
/** Metadata about the tool message */
response_metadata: Record<string, unknown>;
};
};
}
/**
* Takes a message structure type T and normalizes it by merging it with the standard message structure.
* If T is already a standard message structure, returns T unchanged.
*
* This ensures that any custom message structure includes all the standard message structure fields
* by default while allowing overrides and extensions.
*
* @template T - The message structure type to normalize, must extend MessageStructure
* @returns Either T if it's already a standard structure, or the merged result of T with standard structure
*/
type $NormalizedMessageStructure<T extends MessageStructure> = T extends StandardMessageStructure ? T : $MergeMessageStructure<StandardMessageStructure, T>;
/**
* Infers the content blocks for a specific message type in a message structure.
*
* This utility type extracts the content block type that corresponds to a given message type
* from the message structure's content definition.
*
* @template TStructure - The message structure to infer content from
* @template TRole - The message role/type to get content for (e.g., "ai", "human", "system", "tool")
* @returns The content block type for the specified type, or never if its not defined in the structure
*
* @example
* ```ts
* interface MyStructure extends MessageStructure {
* content: {
* human: ContentBlock.Text;
* ai: ContentBlock.Text | ContentBlock.ToolCall;
* };
* }
*
* type HumanContent = $InferMessageContentBlocks<MyStructure, "human">;
* // HumanContent = ContentBlock.Text
*
* type AIContent = $InferMessageContentBlocks<MyStructure, "ai">;
* // AIContent = ContentBlock.Text | ContentBlock.ToolCall
* ```
*/
type $InferMessageContentBlocks<TStructure extends MessageStructure, TRole extends MessageType> = $NormalizedMessageStructure<TStructure> extends infer S ? S extends MessageStructure ? S["content"] extends infer C ? C extends Record<PropertyKey, ContentBlock> ? TRole extends keyof C ? [$MessageToolCallBlock<TStructure>] extends [never] ? C[TRole] : $MergeDiscriminatedUnion<NonNullable<C[TRole]>, $MessageToolCallBlock<TStructure>, "type"> : never : never : never : never : never;
/**
* Infers the content type for a specific message type from a message structure.
*
* This utility type determines the appropriate content type based on the message structure's
* output version and the specified message type. The content type varies depending on the
* output version (see {@link MessageOutputVersion})
*
* @template TStructure - The message structure to infer content from
* @template TRole - The message role/type to get content for (e.g., "ai", "human", "system", "tool")
* @returns The content type for the specified role based on the output version
*
* @example
* ```ts
* interface MyStructure extends MessageStructure {
* outputVersion: "v0";
* content: {
* human: ContentBlock.Text;
* ai: ContentBlock.Text | ContentBlock.ToolCall;
* };
* }
*
* type HumanContentV0 = $InferMessageContent<MyStructure, "human">;
* // HumanContentV0 = string | Array<ContentBlock | ContentBlock.Text>
*
* interface MyStructureV1 extends MessageStructure {
* outputVersion: "v1";
* content: {
* human: ContentBlock.Text;
* ai: ContentBlock.Text | ContentBlock.Reasoning;
* };
* }
*
* type HumanContentV1 = $InferMessageContent<MyStructureV1, "human">;
* // HumanContentV1 = ContentBlock.Text
*
* type AIContentV1 = $InferMessageContent<MyStructureV1, "ai">;
* // AIContentV1 = ContentBlock.Text | ContentBlock.Reasoning
* ```
*/
type $InferMessageContent<TStructure extends MessageStructure, TRole extends MessageType> = TStructure["outputVersion"] extends "v1" ? Array<$InferMessageContentBlocks<TStructure, TRole>> : string | Array<ContentBlock | ContentBlock.Text>;
/**
* Infers the properties for a specific message type from a message structure.
*
* This utility type extracts the properties object that corresponds to a given message type
* from the message structure's properties definition, and excludes the reserved
* "content" and "type" properties to avoid conflicts with the core message structure.
*
* If the specified type is not defined in the message structure's properties, it returns
* a generic Record<string, unknown> type to allow for arbitrary properties.
*
* @template TStructure - The message structure to infer properties from
* @template TRole - The message type/role to get properties for (e.g., "ai", "human", "system", "tool")
* @returns The properties object type for the specified type, excluding "content" and "type"
*
* @example
* ```ts
* interface MyStructure extends MessageStructure {
* properties: {
* ai: {
* response_metadata: { model: string };
* usage_metadata: { tokens: number };
* content: string; // This will be omitted
* type: string; // This will be omitted
* };
* human: { metadata: Record<string, unknown> };
* };
* }
*
* type AIProperties = $InferMessageProperties<MyStructure, "ai">;
* // AIProperties = { response_metadata: { model: string }; usage_metadata: { tokens: number } }
*
* type HumanProperties = $InferMessageProperties<MyStructure, "human">;
* // HumanProperties = { metadata: Record<string, unknown> }
*
* type SystemProperties = $InferMessageProperties<MyStructure, "system">;
* // SystemProperties = Record<string, unknown> (fallback for undefined role)
* ```
*/
type $InferMessageProperties<TStructure extends MessageStructure, TRole extends MessageType> = $NormalizedMessageStructure<TStructure> extends infer S ? S extends MessageStructure ? S["properties"] extends infer P | undefined ? P extends Record<PropertyKey, unknown> ? TRole extends keyof P ? Omit<P[TRole], "content" | "type"> : Record<string, unknown> : Record<string, unknown> : Record<string, unknown> : never : never;
/**
* Infers the type of a specific property for a message type from a message structure.
*
* This utility type extracts the type of a single property by name from the properties
* object that corresponds to a given message type. If the specified property key does
* not exist in the type's properties, it returns `never`.
*
* @template TStructure - The message structure to infer the property from
* @template TRole - The message type/role to get the property for (e.g., "ai", "human", "system", "tool")
* @template K - The property key to extract the type for
* @returns The type of the specified property, or `never` if the property doesn't exist
*
* @example
* ```ts
* interface MyStructure extends MessageStructure {
* properties: {
* ai: {
* response_metadata: { model: string; temperature: number };
* usage_metadata: { input_tokens: number; output_tokens: number };
* };
* human: { metadata: Record<string, unknown> };
* };
* }
*
* type ResponseMetadata = $InferMessageProperty<MyStructure, "ai", "response_metadata">;
* // ResponseMetadata = { model: string; temperature: number }
*
* type UsageMetadata = $InferMessageProperty<MyStructure, "ai", "usage_metadata">;
* // UsageMetadata = { input_tokens: number; output_tokens: number }
*
* type NonExistentProperty = $InferMessageProperty<MyStructure, "ai", "nonExistent">;
* // NonExistentProperty = Record<string, unknown>
*
* type HumanMetadata = $InferMessageProperty<MyStructure, "human", "metadata">;
* // HumanMetadata = Record<string, unknown>
* ```
*/
type $InferMessageProperty<TStructure extends MessageStructure, TRole extends MessageType, K extends string> = K extends keyof $InferMessageProperties<TStructure, TRole> ? $InferMessageProperties<TStructure, TRole>[K] : never;
/**
* Infers the response metadata type for a specific message type from a message structure.
*
* This utility type extracts the `response_metadata` property type for a given message type.
*
* @template TStructure - The message structure to infer the response metadata from
* @template TRole - The message type/role to get the response metadata for (e.g., "ai", "human", "system", "tool")
* @returns The type of the response_metadata property, or `Record<string, unknown>` as fallback
*
* @example
* ```ts
* interface MyStructure extends MessageStructure {
* properties: {
* ai: {
* response_metadata: { model: string; temperature: number; tokens: number };
* };
* human: { metadata: Record<string, unknown> };
* };
* }
*
* type AIResponseMetadata = $InferResponseMetadata<MyStructure, "ai">;
* // AIResponseMetadata = { model: string; temperature: number; tokens: number }
*
* type HumanResponseMetadata = $InferResponseMetadata<MyStructure, "human">;
* // HumanResponseMetadata = Record<string, unknown> (fallback since not defined)
* ```
*/
type $InferResponseMetadata<TStructure extends MessageStructure, TRole extends MessageType> = $InferMessageProperty<TStructure, TRole, "response_metadata"> extends infer P ? [P] extends [never] ? Record<string, unknown> : P : never;
/**
* Represents a message object that organizes context for an LLM.
*
* @example
* ```ts
* // Basic message with text content
* const message: Message = {
* id: "msg-123",
* name: "user",
* type: "human",
* content: [{ type: "text", text: "Hello!" }]
* };
*
* // Basic ai message interface extension
* interface MyMessage extends Message<StandardMessageStructure, "ai"> {
* // Additional AI-specific properties can be added here
* }
*`
* // Custom message structure
* interface CustomStructure extends MessageStructure {
* content: {
* ai: ContentBlock.Text | ContentBlock.ToolCall<"search", { query: string }>;
* human: ContentBlock.Text | ContentBlock.Multimodal.Image;
* };
* }
*
* // Create a message with custom structure
* const message: Message<CustomStructure> = {
* id: "msg-123",
* name: "user",
* type: "ai",
* content: [
* { type: "text", text: "Hello!" },
* {
* type: "tool_call",
* name: "search",
* args: { query: "What is the capital of France?" }
* }
* ]
* };
* ```
*/
interface Message<TStructure extends MessageStructure = StandardMessageStructure, TRole extends MessageType = MessageType> {
/** The message type/role */
readonly type: TRole;
/** Unique identifier for this message */
id?: string;
/** Optional name/identifier for the entity that created this message */
name?: string;
/** Array of content blocks that make up the message content */
content: $InferMessageContent<TStructure, TRole>;
/** Metadata about the message */
response_metadata?: Partial<$InferResponseMetadata<TStructure, TRole>>;
}
/**
* Type guard to check if a value is a valid Message object.
*
* @param message - The value to check
* @returns true if the value is a valid Message object, false otherwise
*/
declare function isMessage(message: unknown): message is Message;
//#endregion
export { $InferMessageContent, $InferMessageContentBlocks, $InferMessageProperties, $InferMessageProperty, $InferResponseMetadata, $MergeContentDefinition, $MergeMessageStructure, $MergeOutputVersion, $MessageToolCallBlock, $NormalizedMessageStructure, Message, MessageOutputVersion, MessageStructure, MessageToolDefinition, MessageToolSet, MessageType, StandardMessageStructure, isMessage };
//# sourceMappingURL=message.d.cts.map