UNPKG

@langchain/langgraph

Version:
1 lines 10.6 kB
{"version":3,"file":"messages.cjs","names":["BaseCallbackHandler","AIMessageChunk"],"sources":["../../src/pregel/messages.ts"],"sourcesContent":["import {\n BaseCallbackHandler,\n HandleLLMNewTokenCallbackFields,\n NewTokenIndices,\n} from \"@langchain/core/callbacks/base\";\nimport {\n AIMessageChunk,\n BaseMessage,\n isBaseMessage,\n isBaseMessageChunk,\n isToolMessage,\n} from \"@langchain/core/messages\";\nimport { Serialized } from \"@langchain/core/load/serializable\";\nimport {\n ChatGeneration,\n ChatGenerationChunk,\n LLMResult,\n} from \"@langchain/core/outputs\";\nimport { ChainValues } from \"@langchain/core/utils/types\";\n\nimport { TAG_HIDDEN, TAG_NOSTREAM } from \"../constants.js\";\nimport { StreamChunk } from \"./stream.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Meta = [string[], Record<string, any>];\n\nfunction isChatGenerationChunk(x: unknown): x is ChatGenerationChunk {\n return isBaseMessage((x as ChatGenerationChunk)?.message);\n}\n\nfunction normalizeStreamMetadata(\n metadata?: Record<string, unknown>,\n tags?: string[],\n name?: string\n): Meta | undefined {\n if (!metadata) {\n return undefined;\n }\n const streamNamespace = metadata.langgraph_checkpoint_ns as\n | string\n | undefined;\n const checkpointNs = metadata.checkpoint_ns as string | undefined;\n const namespace = streamNamespace ?? checkpointNs;\n if (!namespace) {\n return undefined;\n }\n return [namespace.split(\"|\"), { tags, name, ...metadata }];\n}\n\n/**\n * A callback handler that implements stream_mode=messages.\n * Collects messages from (1) chat model stream events and (2) node outputs.\n */\n// TODO: Make this import and explicitly implement the\n// CallbackHandlerPrefersStreaming interface once we drop support for core 0.2\nexport class StreamMessagesHandler extends BaseCallbackHandler {\n name = \"StreamMessagesHandler\";\n\n streamFn: (streamChunk: StreamChunk) => void;\n\n metadatas: Record<string, Meta | undefined> = {};\n\n seen: Record<string, BaseMessage> = {};\n\n emittedChatModelRunIds: Record<string, boolean> = {};\n\n stableMessageIdMap: Record<string, string> = {};\n\n lc_prefer_streaming = true;\n\n constructor(streamFn: (streamChunk: StreamChunk) => void) {\n super();\n this.streamFn = streamFn;\n }\n\n _emit(\n meta: Meta,\n message: BaseMessage,\n runId: string | undefined,\n dedupe = false\n ) {\n if (\n dedupe &&\n message.id !== undefined &&\n this.seen[message.id] !== undefined\n ) {\n return;\n }\n\n let messageId = message.id;\n\n if (runId != null) {\n if (isToolMessage(message)) {\n // Distinguish tool messages by tool call ID.\n messageId ??= `run-${runId}-tool-${message.tool_call_id}`;\n } else {\n // For instance in ChatAnthropic, the first chunk has an message ID\n // but the subsequent chunks do not. To avoid clients seeing two messages\n // we rename the message ID if it's being auto-set to `run-${runId}`\n // (see https://github.com/langchain-ai/langchainjs/pull/6646).\n if (messageId == null || messageId === `run-${runId}`) {\n messageId =\n this.stableMessageIdMap[runId] ?? messageId ?? `run-${runId}`;\n }\n\n this.stableMessageIdMap[runId] ??= messageId;\n }\n }\n\n if (messageId !== message.id) {\n // eslint-disable-next-line no-param-reassign\n message.id = messageId;\n\n // eslint-disable-next-line no-param-reassign\n message.lc_kwargs.id = messageId;\n }\n\n if (message.id != null) this.seen[message.id] = message;\n this.streamFn([meta[0], \"messages\", [message, meta[1]]]);\n }\n\n handleChatModelStart(\n _llm: Serialized,\n _messages: BaseMessage[][],\n runId: string,\n _parentRunId?: string,\n _extraParams?: Record<string, unknown>,\n tags?: string[],\n metadata?: Record<string, unknown>,\n name?: string\n ) {\n if (\n metadata &&\n // Include legacy LangGraph SDK tag\n (!tags || (!tags.includes(TAG_NOSTREAM) && !tags.includes(\"nostream\")))\n ) {\n this.metadatas[runId] = normalizeStreamMetadata(metadata, tags, name);\n }\n }\n\n handleLLMNewToken(\n token: string,\n _idx: NewTokenIndices,\n runId: string,\n _parentRunId?: string,\n _tags?: string[],\n fields?: HandleLLMNewTokenCallbackFields\n ) {\n const chunk = fields?.chunk;\n this.emittedChatModelRunIds[runId] = true;\n if (this.metadatas[runId] !== undefined) {\n if (isChatGenerationChunk(chunk)) {\n this._emit(this.metadatas[runId], chunk.message, runId);\n } else {\n this._emit(\n this.metadatas[runId],\n new AIMessageChunk({ content: token }),\n runId\n );\n }\n }\n }\n\n handleLLMEnd(output: LLMResult, runId: string) {\n // Filter out runs that we do not have metadata for\n if (this.metadatas[runId] === undefined) return;\n\n // In JS, non-streaming runs do not call handleLLMNewToken at the model level\n if (!this.emittedChatModelRunIds[runId]) {\n const chatGeneration = output.generations?.[0]?.[0] as ChatGeneration;\n if (isBaseMessage(chatGeneration?.message)) {\n this._emit(this.metadatas[runId], chatGeneration?.message, runId, true);\n }\n delete this.emittedChatModelRunIds[runId];\n }\n delete this.metadatas[runId];\n delete this.stableMessageIdMap[runId];\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n handleLLMError(_err: any, runId: string) {\n delete this.metadatas[runId];\n }\n\n handleChainStart(\n _chain: Serialized,\n inputs: ChainValues,\n runId: string,\n _parentRunId?: string,\n tags?: string[],\n metadata?: Record<string, unknown>,\n _runType?: string,\n name?: string\n ) {\n if (\n metadata !== undefined &&\n name === metadata.langgraph_node &&\n (tags === undefined || !tags.includes(TAG_HIDDEN))\n ) {\n this.metadatas[runId] = normalizeStreamMetadata(metadata, tags, name);\n\n if (typeof inputs === \"object\") {\n for (const value of Object.values(inputs)) {\n if (\n (isBaseMessage(value) || isBaseMessageChunk(value)) &&\n value.id !== undefined\n ) {\n this.seen[value.id] = value;\n } else if (Array.isArray(value)) {\n for (const item of value) {\n if (\n (isBaseMessage(item) || isBaseMessageChunk(item)) &&\n item.id !== undefined\n ) {\n this.seen[item.id] = item;\n }\n }\n }\n }\n }\n }\n }\n\n handleChainEnd(outputs: ChainValues, runId: string) {\n const metadata = this.metadatas[runId];\n delete this.metadatas[runId];\n if (metadata !== undefined) {\n if (isBaseMessage(outputs)) {\n this._emit(metadata, outputs, runId, true);\n } else if (Array.isArray(outputs)) {\n for (const value of outputs) {\n if (isBaseMessage(value)) {\n this._emit(metadata, value, runId, true);\n }\n }\n } else if (outputs != null && typeof outputs === \"object\") {\n for (const value of Object.values(outputs)) {\n if (isBaseMessage(value)) {\n this._emit(metadata, value, runId, true);\n } else if (Array.isArray(value)) {\n for (const item of value) {\n if (isBaseMessage(item)) {\n this._emit(metadata, item, runId, true);\n }\n }\n }\n }\n }\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n handleChainError(_err: any, runId: string) {\n delete this.metadatas[runId];\n }\n}\n"],"mappings":"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"}