langchain 1.0.0-alpha.6 → 1.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/ReactAgent.cjs.map +1 -1
- package/dist/agents/ReactAgent.d.cts +1 -2
- package/dist/agents/ReactAgent.d.cts.map +1 -1
- package/dist/agents/ReactAgent.d.ts +1 -2
- package/dist/agents/ReactAgent.d.ts.map +1 -1
- package/dist/agents/ReactAgent.js.map +1 -1
- package/dist/agents/annotation.cjs.map +1 -1
- package/dist/agents/annotation.d.cts +12 -5
- package/dist/agents/annotation.d.cts.map +1 -1
- package/dist/agents/annotation.d.ts +12 -5
- package/dist/agents/annotation.d.ts.map +1 -1
- package/dist/agents/annotation.js.map +1 -1
- package/dist/agents/createAgent.cjs.map +1 -1
- package/dist/agents/createAgent.js.map +1 -1
- package/dist/agents/index.cjs.map +1 -1
- package/dist/agents/index.d.cts +3 -3
- package/dist/agents/index.d.cts.map +1 -1
- package/dist/agents/index.d.ts +3 -3
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/interrupt.d.cts +14 -1
- package/dist/agents/interrupt.d.cts.map +1 -1
- package/dist/agents/interrupt.d.ts +14 -1
- package/dist/agents/interrupt.d.ts.map +1 -1
- package/dist/agents/middlewareAgent/ReactAgent.cjs +262 -55
- package/dist/agents/middlewareAgent/ReactAgent.cjs.map +1 -1
- package/dist/agents/middlewareAgent/ReactAgent.d.cts +97 -10
- package/dist/agents/middlewareAgent/ReactAgent.d.cts.map +1 -1
- package/dist/agents/middlewareAgent/ReactAgent.d.ts +97 -10
- package/dist/agents/middlewareAgent/ReactAgent.d.ts.map +1 -1
- package/dist/agents/middlewareAgent/ReactAgent.js +264 -57
- package/dist/agents/middlewareAgent/ReactAgent.js.map +1 -1
- package/dist/agents/middlewareAgent/annotation.cjs +10 -4
- package/dist/agents/middlewareAgent/annotation.cjs.map +1 -1
- package/dist/agents/middlewareAgent/annotation.js +10 -4
- package/dist/agents/middlewareAgent/annotation.js.map +1 -1
- package/dist/agents/middlewareAgent/constants.d.cts +5 -0
- package/dist/agents/middlewareAgent/constants.d.cts.map +1 -0
- package/dist/agents/middlewareAgent/constants.d.ts +5 -0
- package/dist/agents/middlewareAgent/constants.d.ts.map +1 -0
- package/dist/agents/middlewareAgent/index.cjs.map +1 -1
- package/dist/agents/middlewareAgent/index.js.map +1 -1
- package/dist/agents/middlewareAgent/middleware/bigTool.cjs +162 -0
- package/dist/agents/middlewareAgent/middleware/bigTool.cjs.map +1 -0
- package/dist/agents/middlewareAgent/middleware/bigTool.d.cts +113 -0
- package/dist/agents/middlewareAgent/middleware/bigTool.d.cts.map +1 -0
- package/dist/agents/middlewareAgent/middleware/bigTool.d.ts +113 -0
- package/dist/agents/middlewareAgent/middleware/bigTool.d.ts.map +1 -0
- package/dist/agents/middlewareAgent/middleware/bigTool.js +161 -0
- package/dist/agents/middlewareAgent/middleware/bigTool.js.map +1 -0
- package/dist/agents/middlewareAgent/middleware/dynamicSystemPrompt.cjs +58 -0
- package/dist/agents/middlewareAgent/middleware/dynamicSystemPrompt.cjs.map +1 -0
- package/dist/agents/middlewareAgent/middleware/dynamicSystemPrompt.d.cts +46 -0
- package/dist/agents/middlewareAgent/middleware/dynamicSystemPrompt.d.cts.map +1 -0
- package/dist/agents/middlewareAgent/middleware/dynamicSystemPrompt.d.ts +46 -0
- package/dist/agents/middlewareAgent/middleware/dynamicSystemPrompt.d.ts.map +1 -0
- package/dist/agents/middlewareAgent/middleware/dynamicSystemPrompt.js +58 -0
- package/dist/agents/middlewareAgent/middleware/dynamicSystemPrompt.js.map +1 -0
- package/dist/agents/middlewareAgent/middleware/hitl.cjs +160 -84
- package/dist/agents/middlewareAgent/middleware/hitl.cjs.map +1 -1
- package/dist/agents/middlewareAgent/middleware/hitl.d.cts +271 -51
- package/dist/agents/middlewareAgent/middleware/hitl.d.cts.map +1 -1
- package/dist/agents/middlewareAgent/middleware/hitl.d.ts +271 -51
- package/dist/agents/middlewareAgent/middleware/hitl.d.ts.map +1 -1
- package/dist/agents/middlewareAgent/middleware/hitl.js +161 -85
- package/dist/agents/middlewareAgent/middleware/hitl.js.map +1 -1
- package/dist/agents/middlewareAgent/middleware/index.cjs +6 -0
- package/dist/agents/middlewareAgent/middleware/index.cjs.map +1 -1
- package/dist/agents/middlewareAgent/middleware/index.d.cts +6 -4
- package/dist/agents/middlewareAgent/middleware/index.d.ts +6 -4
- package/dist/agents/middlewareAgent/middleware/index.js +5 -1
- package/dist/agents/middlewareAgent/middleware/index.js.map +1 -1
- package/dist/agents/middlewareAgent/middleware/promptCaching.cjs +24 -8
- package/dist/agents/middlewareAgent/middleware/promptCaching.cjs.map +1 -1
- package/dist/agents/middlewareAgent/middleware/promptCaching.d.cts +51 -6
- package/dist/agents/middlewareAgent/middleware/promptCaching.d.cts.map +1 -1
- package/dist/agents/middlewareAgent/middleware/promptCaching.d.ts +51 -6
- package/dist/agents/middlewareAgent/middleware/promptCaching.d.ts.map +1 -1
- package/dist/agents/middlewareAgent/middleware/promptCaching.js +24 -8
- package/dist/agents/middlewareAgent/middleware/promptCaching.js.map +1 -1
- package/dist/agents/middlewareAgent/middleware/summarization.cjs +24 -12
- package/dist/agents/middlewareAgent/middleware/summarization.cjs.map +1 -1
- package/dist/agents/middlewareAgent/middleware/summarization.d.cts +5 -3
- package/dist/agents/middlewareAgent/middleware/summarization.d.cts.map +1 -1
- package/dist/agents/middlewareAgent/middleware/summarization.d.ts +11 -9
- package/dist/agents/middlewareAgent/middleware/summarization.d.ts.map +1 -1
- package/dist/agents/middlewareAgent/middleware/summarization.js +25 -13
- package/dist/agents/middlewareAgent/middleware/summarization.js.map +1 -1
- package/dist/agents/middlewareAgent/middleware.cjs +8 -5
- package/dist/agents/middlewareAgent/middleware.cjs.map +1 -1
- package/dist/agents/middlewareAgent/middleware.d.cts +67 -7
- package/dist/agents/middlewareAgent/middleware.d.cts.map +1 -1
- package/dist/agents/middlewareAgent/middleware.d.ts +67 -7
- package/dist/agents/middlewareAgent/middleware.d.ts.map +1 -1
- package/dist/agents/middlewareAgent/middleware.js +8 -5
- package/dist/agents/middlewareAgent/middleware.js.map +1 -1
- package/dist/agents/middlewareAgent/nodes/AfterModalNode.cjs +2 -2
- package/dist/agents/middlewareAgent/nodes/AfterModalNode.cjs.map +1 -1
- package/dist/agents/middlewareAgent/nodes/AfterModalNode.js +2 -2
- package/dist/agents/middlewareAgent/nodes/AfterModalNode.js.map +1 -1
- package/dist/agents/middlewareAgent/nodes/AgentNode.cjs +117 -68
- package/dist/agents/middlewareAgent/nodes/AgentNode.cjs.map +1 -1
- package/dist/agents/middlewareAgent/nodes/AgentNode.js +121 -72
- package/dist/agents/middlewareAgent/nodes/AgentNode.js.map +1 -1
- package/dist/agents/middlewareAgent/nodes/BeforeModalNode.cjs +2 -2
- package/dist/agents/middlewareAgent/nodes/BeforeModalNode.cjs.map +1 -1
- package/dist/agents/middlewareAgent/nodes/BeforeModalNode.js +2 -2
- package/dist/agents/middlewareAgent/nodes/BeforeModalNode.js.map +1 -1
- package/dist/agents/middlewareAgent/nodes/middleware.cjs +42 -17
- package/dist/agents/middlewareAgent/nodes/middleware.cjs.map +1 -1
- package/dist/agents/middlewareAgent/nodes/middleware.js +42 -18
- package/dist/agents/middlewareAgent/nodes/middleware.js.map +1 -1
- package/dist/agents/middlewareAgent/nodes/utils.cjs +25 -11
- package/dist/agents/middlewareAgent/nodes/utils.cjs.map +1 -1
- package/dist/agents/middlewareAgent/nodes/utils.js +26 -12
- package/dist/agents/middlewareAgent/nodes/utils.js.map +1 -1
- package/dist/agents/middlewareAgent/types.d.cts +153 -66
- package/dist/agents/middlewareAgent/types.d.cts.map +1 -1
- package/dist/agents/middlewareAgent/types.d.ts +153 -66
- package/dist/agents/middlewareAgent/types.d.ts.map +1 -1
- package/dist/agents/model.cjs +13 -0
- package/dist/agents/model.cjs.map +1 -0
- package/dist/agents/model.js +11 -0
- package/dist/agents/model.js.map +1 -0
- package/dist/agents/nodes/AgentNode.cjs +56 -28
- package/dist/agents/nodes/AgentNode.cjs.map +1 -1
- package/dist/agents/nodes/AgentNode.js +57 -29
- package/dist/agents/nodes/AgentNode.js.map +1 -1
- package/dist/agents/nodes/ToolNode.cjs +1 -1
- package/dist/agents/nodes/ToolNode.cjs.map +1 -1
- package/dist/agents/nodes/ToolNode.d.cts +1 -1
- package/dist/agents/nodes/ToolNode.js +1 -1
- package/dist/agents/nodes/ToolNode.js.map +1 -1
- package/dist/agents/responses.cjs +52 -10
- package/dist/agents/responses.cjs.map +1 -1
- package/dist/agents/responses.d.cts +12 -20
- package/dist/agents/responses.d.cts.map +1 -1
- package/dist/agents/responses.d.ts +12 -20
- package/dist/agents/responses.d.ts.map +1 -1
- package/dist/agents/responses.js +52 -11
- package/dist/agents/responses.js.map +1 -1
- package/dist/agents/types.d.cts +2 -3
- package/dist/agents/types.d.cts.map +1 -1
- package/dist/agents/types.d.ts +2 -3
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/agents/utils.cjs +5 -23
- package/dist/agents/utils.cjs.map +1 -1
- package/dist/agents/utils.js +2 -19
- package/dist/agents/utils.js.map +1 -1
- package/dist/chains/query_constructor/index.d.cts +1 -1
- package/dist/chains/summarization/load.d.ts +2 -2
- package/dist/chains/summarization/load.d.ts.map +1 -1
- package/dist/embeddings/cache_backed.d.ts +1 -1
- package/dist/evaluation/comparison/pairwise.d.cts.map +1 -1
- package/dist/evaluation/comparison/pairwise.d.ts.map +1 -1
- package/dist/evaluation/criteria/criteria.d.cts.map +1 -1
- package/dist/evaluation/criteria/criteria.d.ts.map +1 -1
- package/dist/index.cjs +38 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.js +18 -4
- package/dist/index.js.map +1 -1
- package/dist/langchain-core/dist/messages/base.d.cts.map +1 -1
- package/dist/langchain-core/dist/messages/content/index.d.cts +20 -1
- package/dist/langchain-core/dist/messages/content/index.d.cts.map +1 -1
- package/dist/langchain-core/dist/messages/content/tools.d.cts +67 -6
- package/dist/langchain-core/dist/messages/content/tools.d.cts.map +1 -1
- package/dist/langchain-core/dist/messages/message.d.cts +6 -6
- package/dist/langchain-core/dist/messages/message.d.cts.map +1 -1
- package/dist/langchain-core/dist/utils/types/index.d.cts.map +1 -1
- package/dist/libs/langchain-core/dist/messages/base.d.ts.map +1 -1
- package/dist/libs/langchain-core/dist/messages/content/index.d.ts +20 -1
- package/dist/libs/langchain-core/dist/messages/content/index.d.ts.map +1 -1
- package/dist/libs/langchain-core/dist/messages/content/tools.d.ts +67 -6
- package/dist/libs/langchain-core/dist/messages/content/tools.d.ts.map +1 -1
- package/dist/libs/langchain-core/dist/messages/message.d.ts +6 -6
- package/dist/libs/langchain-core/dist/messages/message.d.ts.map +1 -1
- package/dist/libs/langchain-core/dist/utils/types/index.d.ts.map +1 -1
- package/dist/load/import_map.cjs +1 -1
- package/dist/load/import_map.js +1 -1
- package/dist/output_parsers/structured.d.cts +1 -1
- package/dist/tools/fs.d.cts +1 -1
- package/dist/tools/retriever.d.cts +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarization.cjs","names":["z","messages: BaseMessage[]","textContent: string","options: z.input<typeof contextSchema>","createMiddleware","RemoveMessage","REMOVE_ALL_MESSAGES","systemMessage: SystemMessage | null","conversationMessages: BaseMessage[]","cutoffIndex: number","originalSystemMessage: SystemMessage | null","summary: string","summaryPrefix: string","content","SystemMessage","messagesToKeep: number","message: BaseMessage","aiMessage: AIMessage","aiMessageIndex: number","toolCallIds: Set<string>","messagesToSummarize: BaseMessage[]","model: BaseLanguageModel","summaryPrompt: string","tokenCounter: TokenCounter"],"sources":["../../../../src/agents/middlewareAgent/middleware/summarization.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n BaseMessage,\n AIMessage,\n SystemMessage,\n isToolMessage,\n RemoveMessage,\n trimMessages,\n isSystemMessage,\n isAIMessage,\n} from \"@langchain/core/messages\";\nimport { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport { REMOVE_ALL_MESSAGES } from \"@langchain/langgraph\";\nimport { createMiddleware } from \"../middleware.js\";\n\nconst DEFAULT_SUMMARY_PROMPT = `<role>\nContext Extraction Assistant\n</role>\n\n<primary_objective>\nYour sole objective in this task is to extract the highest quality/most relevant context from the conversation history below.\n</primary_objective>\n\n<objective_information>\nYou're nearing the total number of input tokens you can accept, so you must extract the highest quality/most relevant pieces of information from your conversation history.\nThis context will then overwrite the conversation history presented below. Because of this, ensure the context you extract is only the most important information to your overall goal.\n</objective_information>\n\n<instructions>\nThe conversation history below will be replaced with the context you extract in this step. Because of this, you must do your very best to extract and record all of the most important context from the conversation history.\nYou want to ensure that you don't repeat any actions you've already completed, so the context you extract from the conversation history should be focused on the most important information to your overall goal.\n</instructions>\n\nThe user will message you with the full message history you'll be extracting context from, to then replace. Carefully read over it all, and think deeply about what information is most important to your overall goal that should be saved:\n\nWith all of this in mind, please carefully read over the entire conversation history, and extract the most important and relevant context to replace it so that you can free up space in the conversation history.\nRespond ONLY with the extracted context. Do not include any additional information, or text before or after the extracted context.\n\n<messages>\nMessages to summarize:\n{messages}\n</messages>`;\n\nconst SUMMARY_PREFIX = \"## Previous conversation summary:\";\n\nconst DEFAULT_MESSAGES_TO_KEEP = 20;\nconst DEFAULT_TRIM_TOKEN_LIMIT = 4000;\nconst DEFAULT_FALLBACK_MESSAGE_COUNT = 15;\nconst SEARCH_RANGE_FOR_TOOL_PAIRS = 5;\n\ntype TokenCounter = (messages: BaseMessage[]) => number | Promise<number>;\n\nconst contextSchema = z.object({\n model: z.custom<BaseLanguageModel>(),\n maxTokensBeforeSummary: z.number().optional(),\n messagesToKeep: z.number().default(DEFAULT_MESSAGES_TO_KEEP),\n tokenCounter: z\n .function()\n .args(z.array(z.any()))\n .returns(z.union([z.number(), z.promise(z.number())]))\n .optional(),\n summaryPrompt: z.string().default(DEFAULT_SUMMARY_PROMPT),\n summaryPrefix: z.string().default(SUMMARY_PREFIX),\n});\n\n/**\n * Default token counter that approximates based on character count\n * @param messages Messages to count tokens for\n * @returns Approximate token count\n */\nexport function countTokensApproximately(messages: BaseMessage[]): number {\n let totalChars = 0;\n for (const msg of messages) {\n let textContent: string;\n if (typeof msg.content === \"string\") {\n textContent = msg.content;\n } else if (Array.isArray(msg.content)) {\n textContent = msg.content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (item.type === \"text\" && \"text\" in item) return item.text;\n return \"\";\n })\n .join(\"\");\n } else {\n textContent = \"\";\n }\n totalChars += textContent.length;\n }\n // Approximate 1 token = 4 characters\n return Math.ceil(totalChars / 4);\n}\n\n/**\n * Summarization middleware that automatically summarizes conversation history when token limits are approached.\n *\n * This middleware monitors message token counts and automatically summarizes older\n * messages when a threshold is reached, preserving recent messages and maintaining\n * context continuity by ensuring AI/Tool message pairs remain together.\n *\n * @param options Configuration options for the summarization middleware\n * @returns A middleware instance\n *\n * @example\n * ```ts\n * import { summarizationMiddleware } from \"langchain/middleware\";\n * import { createAgent } from \"langchain\";\n *\n * const agent = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * maxTokensBeforeSummary: 4000,\n * messagesToKeep: 20,\n * })\n * ],\n * });\n *\n * ```\n */\nexport function summarizationMiddleware(\n options: z.input<typeof contextSchema>\n) {\n return createMiddleware({\n name: \"SummarizationMiddleware\",\n contextSchema,\n beforeModel: async (state, runtime) => {\n const config = { ...contextSchema.parse(options), ...runtime.context };\n const { messages } = state;\n\n // Ensure all messages have IDs\n ensureMessageIds(messages);\n\n const tokenCounter = config.tokenCounter || countTokensApproximately;\n const totalTokens = await tokenCounter(messages);\n\n if (\n config.maxTokensBeforeSummary == null ||\n totalTokens < config.maxTokensBeforeSummary\n ) {\n return;\n }\n\n const { systemMessage, conversationMessages } =\n splitSystemMessage(messages);\n const cutoffIndex = findSafeCutoff(\n conversationMessages,\n config.messagesToKeep\n );\n\n if (cutoffIndex <= 0) {\n return;\n }\n\n const { messagesToSummarize, preservedMessages } = partitionMessages(\n systemMessage,\n conversationMessages,\n cutoffIndex\n );\n\n const summary = await createSummary(\n messagesToSummarize,\n config.model,\n config.summaryPrompt,\n tokenCounter\n );\n\n const updatedSystemMessage = buildUpdatedSystemMessage(\n systemMessage,\n summary,\n config.summaryPrefix\n );\n\n return {\n messages: [\n new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),\n updatedSystemMessage,\n ...preservedMessages,\n ],\n };\n },\n });\n}\n\n/**\n * Ensure all messages have unique IDs\n */\nfunction ensureMessageIds(messages: BaseMessage[]): void {\n for (const msg of messages) {\n if (!msg.id) {\n msg.id = uuid();\n }\n }\n}\n\n/**\n * Separate system message from conversation messages\n */\nfunction splitSystemMessage(messages: BaseMessage[]): {\n systemMessage: SystemMessage | null;\n conversationMessages: BaseMessage[];\n} {\n if (messages.length > 0 && isSystemMessage(messages[0])) {\n return {\n systemMessage: messages[0] as SystemMessage,\n conversationMessages: messages.slice(1),\n };\n }\n return {\n systemMessage: null,\n conversationMessages: messages,\n };\n}\n\n/**\n * Partition messages into those to summarize and those to preserve\n */\nfunction partitionMessages(\n systemMessage: SystemMessage | null,\n conversationMessages: BaseMessage[],\n cutoffIndex: number\n): { messagesToSummarize: BaseMessage[]; preservedMessages: BaseMessage[] } {\n const messagesToSummarize = conversationMessages.slice(0, cutoffIndex);\n const preservedMessages = conversationMessages.slice(cutoffIndex);\n\n // Include system message in messages to summarize to capture previous summaries\n if (systemMessage) {\n messagesToSummarize.unshift(systemMessage);\n }\n\n return { messagesToSummarize, preservedMessages };\n}\n\n/**\n * Build updated system message incorporating the summary\n */\nfunction buildUpdatedSystemMessage(\n originalSystemMessage: SystemMessage | null,\n summary: string,\n summaryPrefix: string\n): SystemMessage {\n let originalContent = \"\";\n if (originalSystemMessage) {\n const { content } = originalSystemMessage;\n if (typeof content === \"string\") {\n originalContent = content.split(summaryPrefix)[0].trim();\n }\n }\n\n const content = originalContent\n ? `${originalContent}\\n${summaryPrefix}\\n${summary}`\n : `${summaryPrefix}\\n${summary}`;\n\n return new SystemMessage({\n content,\n id: originalSystemMessage?.id || uuid(),\n });\n}\n\n/**\n * Find safe cutoff point that preserves AI/Tool message pairs\n */\nfunction findSafeCutoff(\n messages: BaseMessage[],\n messagesToKeep: number\n): number {\n if (messages.length <= messagesToKeep) {\n return 0;\n }\n\n const targetCutoff = messages.length - messagesToKeep;\n\n for (let i = targetCutoff; i >= 0; i--) {\n if (isSafeCutoffPoint(messages, i)) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Check if cutting at index would separate AI/Tool message pairs\n */\nfunction isSafeCutoffPoint(\n messages: BaseMessage[],\n cutoffIndex: number\n): boolean {\n if (cutoffIndex >= messages.length) {\n return true;\n }\n\n const searchStart = Math.max(0, cutoffIndex - SEARCH_RANGE_FOR_TOOL_PAIRS);\n const searchEnd = Math.min(\n messages.length,\n cutoffIndex + SEARCH_RANGE_FOR_TOOL_PAIRS\n );\n\n for (let i = searchStart; i < searchEnd; i++) {\n if (!hasToolCalls(messages[i])) {\n continue;\n }\n\n const toolCallIds = extractToolCallIds(messages[i] as AIMessage);\n if (cutoffSeparatesToolPair(messages, i, cutoffIndex, toolCallIds)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if message is an AI message with tool calls\n */\nfunction hasToolCalls(message: BaseMessage): boolean {\n return (\n isAIMessage(message) &&\n \"tool_calls\" in message &&\n Array.isArray(message.tool_calls) &&\n message.tool_calls.length > 0\n );\n}\n\n/**\n * Extract tool call IDs from an AI message\n */\nfunction extractToolCallIds(aiMessage: AIMessage): Set<string> {\n const toolCallIds = new Set<string>();\n if (aiMessage.tool_calls) {\n for (const toolCall of aiMessage.tool_calls) {\n const id =\n typeof toolCall === \"object\" && \"id\" in toolCall ? toolCall.id : null;\n if (id) {\n toolCallIds.add(id);\n }\n }\n }\n return toolCallIds;\n}\n\n/**\n * Check if cutoff separates an AI message from its corresponding tool messages\n */\nfunction cutoffSeparatesToolPair(\n messages: BaseMessage[],\n aiMessageIndex: number,\n cutoffIndex: number,\n toolCallIds: Set<string>\n): boolean {\n for (let j = aiMessageIndex + 1; j < messages.length; j++) {\n const message = messages[j];\n if (isToolMessage(message) && toolCallIds.has(message.tool_call_id)) {\n const aiBeforeCutoff = aiMessageIndex < cutoffIndex;\n const toolBeforeCutoff = j < cutoffIndex;\n if (aiBeforeCutoff !== toolBeforeCutoff) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Generate summary for the given messages\n */\nasync function createSummary(\n messagesToSummarize: BaseMessage[],\n model: BaseLanguageModel,\n summaryPrompt: string,\n tokenCounter: TokenCounter\n): Promise<string> {\n if (!messagesToSummarize.length) {\n return \"No previous conversation history.\";\n }\n\n const trimmedMessages = await trimMessagesForSummary(\n messagesToSummarize,\n tokenCounter\n );\n\n if (!trimmedMessages.length) {\n return \"Previous conversation was too long to summarize.\";\n }\n\n try {\n const formattedPrompt = summaryPrompt.replace(\n \"{messages}\",\n JSON.stringify(trimmedMessages, null, 2)\n );\n const response = await model.invoke(formattedPrompt);\n const { content } = response;\n return typeof content === \"string\"\n ? content.trim()\n : \"Error generating summary: Invalid response format\";\n } catch (e) {\n return `Error generating summary: ${e}`;\n }\n}\n\n/**\n * Trim messages to fit within summary generation limits\n */\nasync function trimMessagesForSummary(\n messages: BaseMessage[],\n tokenCounter: TokenCounter\n): Promise<BaseMessage[]> {\n try {\n return await trimMessages(messages, {\n maxTokens: DEFAULT_TRIM_TOKEN_LIMIT,\n tokenCounter: async (msgs) => Promise.resolve(tokenCounter(msgs)),\n strategy: \"last\",\n allowPartial: true,\n includeSystem: true,\n });\n } catch {\n // Fallback to last N messages if trimming fails\n return messages.slice(-DEFAULT_FALLBACK_MESSAGE_COUNT);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"summarization.cjs","names":["z","messages: BaseMessage[]","textContent: string","options: SummarizationMiddlewareConfig","createMiddleware","RemoveMessage","REMOVE_ALL_MESSAGES","SystemMessage","systemPrompt: SystemMessage | null","conversationMessages: BaseMessage[]","cutoffIndex: number","originalSystemMessage: SystemMessage | null","summary: string","summaryPrefix: string","content","messagesToKeep: number","message: BaseMessage","AIMessage","aiMessage: AIMessage","aiMessageIndex: number","toolCallIds: Set<string>","ToolMessage","messagesToSummarize: BaseMessage[]","model: BaseLanguageModel","summaryPrompt: string","tokenCounter: TokenCounter"],"sources":["../../../../src/agents/middlewareAgent/middleware/summarization.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n BaseMessage,\n AIMessage,\n SystemMessage,\n ToolMessage,\n RemoveMessage,\n trimMessages,\n} from \"@langchain/core/messages\";\nimport { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport {\n interopParse,\n InferInteropZodOutput,\n InferInteropZodInput,\n} from \"@langchain/core/utils/types\";\nimport { REMOVE_ALL_MESSAGES } from \"@langchain/langgraph\";\nimport { createMiddleware } from \"../middleware.js\";\n\nconst DEFAULT_SUMMARY_PROMPT = `<role>\nContext Extraction Assistant\n</role>\n\n<primary_objective>\nYour sole objective in this task is to extract the highest quality/most relevant context from the conversation history below.\n</primary_objective>\n\n<objective_information>\nYou're nearing the total number of input tokens you can accept, so you must extract the highest quality/most relevant pieces of information from your conversation history.\nThis context will then overwrite the conversation history presented below. Because of this, ensure the context you extract is only the most important information to your overall goal.\n</objective_information>\n\n<instructions>\nThe conversation history below will be replaced with the context you extract in this step. Because of this, you must do your very best to extract and record all of the most important context from the conversation history.\nYou want to ensure that you don't repeat any actions you've already completed, so the context you extract from the conversation history should be focused on the most important information to your overall goal.\n</instructions>\n\nThe user will message you with the full message history you'll be extracting context from, to then replace. Carefully read over it all, and think deeply about what information is most important to your overall goal that should be saved:\n\nWith all of this in mind, please carefully read over the entire conversation history, and extract the most important and relevant context to replace it so that you can free up space in the conversation history.\nRespond ONLY with the extracted context. Do not include any additional information, or text before or after the extracted context.\n\n<messages>\nMessages to summarize:\n{messages}\n</messages>`;\n\nconst SUMMARY_PREFIX = \"## Previous conversation summary:\";\n\nconst DEFAULT_MESSAGES_TO_KEEP = 20;\nconst DEFAULT_TRIM_TOKEN_LIMIT = 4000;\nconst DEFAULT_FALLBACK_MESSAGE_COUNT = 15;\nconst SEARCH_RANGE_FOR_TOOL_PAIRS = 5;\n\ntype TokenCounter = (messages: BaseMessage[]) => number | Promise<number>;\n\nconst contextSchema = z.object({\n model: z.custom<BaseLanguageModel>(),\n maxTokensBeforeSummary: z.number().optional(),\n messagesToKeep: z.number().default(DEFAULT_MESSAGES_TO_KEEP),\n tokenCounter: z\n .function()\n .args(z.array(z.any()))\n .returns(z.union([z.number(), z.promise(z.number())]))\n .optional(),\n summaryPrompt: z.string().default(DEFAULT_SUMMARY_PROMPT),\n summaryPrefix: z.string().default(SUMMARY_PREFIX),\n});\n\nexport type SummarizationMiddlewareConfig = InferInteropZodInput<\n typeof contextSchema\n>;\n\n/**\n * Default token counter that approximates based on character count\n * @param messages Messages to count tokens for\n * @returns Approximate token count\n */\nexport function countTokensApproximately(messages: BaseMessage[]): number {\n let totalChars = 0;\n for (const msg of messages) {\n let textContent: string;\n if (typeof msg.content === \"string\") {\n textContent = msg.content;\n } else if (Array.isArray(msg.content)) {\n textContent = msg.content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (item.type === \"text\" && \"text\" in item) return item.text;\n return \"\";\n })\n .join(\"\");\n } else {\n textContent = \"\";\n }\n totalChars += textContent.length;\n }\n // Approximate 1 token = 4 characters\n return Math.ceil(totalChars / 4);\n}\n\n/**\n * Summarization middleware that automatically summarizes conversation history when token limits are approached.\n *\n * This middleware monitors message token counts and automatically summarizes older\n * messages when a threshold is reached, preserving recent messages and maintaining\n * context continuity by ensuring AI/Tool message pairs remain together.\n *\n * @param options Configuration options for the summarization middleware\n * @returns A middleware instance\n *\n * @example\n * ```ts\n * import { summarizationMiddleware } from \"langchain/middleware\";\n * import { createAgent } from \"langchain\";\n *\n * const agent = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * maxTokensBeforeSummary: 4000,\n * messagesToKeep: 20,\n * })\n * ],\n * });\n *\n * ```\n */\nexport function summarizationMiddleware(\n options: SummarizationMiddlewareConfig\n) {\n return createMiddleware({\n name: \"SummarizationMiddleware\",\n contextSchema,\n beforeModel: async (state, runtime) => {\n /**\n * Parse user options to get their explicit values\n */\n const userOptions = interopParse(contextSchema, options);\n\n /**\n * Merge context with user options, preferring user options when context has default values\n */\n const config = {\n model: userOptions.model,\n maxTokensBeforeSummary:\n runtime.context.maxTokensBeforeSummary !== undefined\n ? runtime.context.maxTokensBeforeSummary\n : userOptions.maxTokensBeforeSummary,\n messagesToKeep:\n runtime.context.messagesToKeep === DEFAULT_MESSAGES_TO_KEEP\n ? userOptions.messagesToKeep\n : runtime.context.messagesToKeep ?? userOptions.messagesToKeep,\n tokenCounter:\n runtime.context.tokenCounter !== undefined\n ? runtime.context.tokenCounter\n : userOptions.tokenCounter,\n summaryPrompt:\n runtime.context.summaryPrompt === DEFAULT_SUMMARY_PROMPT\n ? userOptions.summaryPrompt\n : runtime.context.summaryPrompt ?? userOptions.summaryPrompt,\n summaryPrefix:\n runtime.context.summaryPrefix === SUMMARY_PREFIX\n ? userOptions.summaryPrefix\n : runtime.context.summaryPrefix ?? userOptions.summaryPrefix,\n } as InferInteropZodOutput<typeof contextSchema>;\n const { messages } = state;\n\n // Ensure all messages have IDs\n ensureMessageIds(messages);\n\n const tokenCounter = config.tokenCounter || countTokensApproximately;\n const totalTokens = await tokenCounter(messages);\n\n if (\n config.maxTokensBeforeSummary == null ||\n totalTokens < config.maxTokensBeforeSummary\n ) {\n return;\n }\n\n const { systemPrompt, conversationMessages } =\n splitSystemMessage(messages);\n const cutoffIndex = findSafeCutoff(\n conversationMessages,\n config.messagesToKeep\n );\n\n if (cutoffIndex <= 0) {\n return;\n }\n\n const { messagesToSummarize, preservedMessages } = partitionMessages(\n systemPrompt,\n conversationMessages,\n cutoffIndex\n );\n\n const summary = await createSummary(\n messagesToSummarize,\n config.model,\n config.summaryPrompt,\n tokenCounter\n );\n\n const updatedSystemMessage = buildUpdatedSystemMessage(\n systemPrompt,\n summary,\n config.summaryPrefix\n );\n\n return {\n messages: [\n new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),\n updatedSystemMessage,\n ...preservedMessages,\n ],\n };\n },\n });\n}\n\n/**\n * Ensure all messages have unique IDs\n */\nfunction ensureMessageIds(messages: BaseMessage[]): void {\n for (const msg of messages) {\n if (!msg.id) {\n msg.id = uuid();\n }\n }\n}\n\n/**\n * Separate system message from conversation messages\n */\nfunction splitSystemMessage(messages: BaseMessage[]): {\n systemPrompt: SystemMessage | null;\n conversationMessages: BaseMessage[];\n} {\n if (messages.length > 0 && SystemMessage.isInstance(messages[0])) {\n return {\n systemPrompt: messages[0] as SystemMessage,\n conversationMessages: messages.slice(1),\n };\n }\n return {\n systemPrompt: null,\n conversationMessages: messages,\n };\n}\n\n/**\n * Partition messages into those to summarize and those to preserve\n */\nfunction partitionMessages(\n systemPrompt: SystemMessage | null,\n conversationMessages: BaseMessage[],\n cutoffIndex: number\n): { messagesToSummarize: BaseMessage[]; preservedMessages: BaseMessage[] } {\n const messagesToSummarize = conversationMessages.slice(0, cutoffIndex);\n const preservedMessages = conversationMessages.slice(cutoffIndex);\n\n // Include system message in messages to summarize to capture previous summaries\n if (systemPrompt) {\n messagesToSummarize.unshift(systemPrompt);\n }\n\n return { messagesToSummarize, preservedMessages };\n}\n\n/**\n * Build updated system message incorporating the summary\n */\nfunction buildUpdatedSystemMessage(\n originalSystemMessage: SystemMessage | null,\n summary: string,\n summaryPrefix: string\n): SystemMessage {\n let originalContent = \"\";\n if (originalSystemMessage) {\n const { content } = originalSystemMessage;\n if (typeof content === \"string\") {\n originalContent = content.split(summaryPrefix)[0].trim();\n }\n }\n\n const content = originalContent\n ? `${originalContent}\\n${summaryPrefix}\\n${summary}`\n : `${summaryPrefix}\\n${summary}`;\n\n return new SystemMessage({\n content,\n id: originalSystemMessage?.id || uuid(),\n });\n}\n\n/**\n * Find safe cutoff point that preserves AI/Tool message pairs\n */\nfunction findSafeCutoff(\n messages: BaseMessage[],\n messagesToKeep: number\n): number {\n if (messages.length <= messagesToKeep) {\n return 0;\n }\n\n const targetCutoff = messages.length - messagesToKeep;\n\n for (let i = targetCutoff; i >= 0; i--) {\n if (isSafeCutoffPoint(messages, i)) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Check if cutting at index would separate AI/Tool message pairs\n */\nfunction isSafeCutoffPoint(\n messages: BaseMessage[],\n cutoffIndex: number\n): boolean {\n if (cutoffIndex >= messages.length) {\n return true;\n }\n\n const searchStart = Math.max(0, cutoffIndex - SEARCH_RANGE_FOR_TOOL_PAIRS);\n const searchEnd = Math.min(\n messages.length,\n cutoffIndex + SEARCH_RANGE_FOR_TOOL_PAIRS\n );\n\n for (let i = searchStart; i < searchEnd; i++) {\n if (!hasToolCalls(messages[i])) {\n continue;\n }\n\n const toolCallIds = extractToolCallIds(messages[i] as AIMessage);\n if (cutoffSeparatesToolPair(messages, i, cutoffIndex, toolCallIds)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if message is an AI message with tool calls\n */\nfunction hasToolCalls(message: BaseMessage): boolean {\n return (\n AIMessage.isInstance(message) &&\n \"tool_calls\" in message &&\n Array.isArray(message.tool_calls) &&\n message.tool_calls.length > 0\n );\n}\n\n/**\n * Extract tool call IDs from an AI message\n */\nfunction extractToolCallIds(aiMessage: AIMessage): Set<string> {\n const toolCallIds = new Set<string>();\n if (aiMessage.tool_calls) {\n for (const toolCall of aiMessage.tool_calls) {\n const id =\n typeof toolCall === \"object\" && \"id\" in toolCall ? toolCall.id : null;\n if (id) {\n toolCallIds.add(id);\n }\n }\n }\n return toolCallIds;\n}\n\n/**\n * Check if cutoff separates an AI message from its corresponding tool messages\n */\nfunction cutoffSeparatesToolPair(\n messages: BaseMessage[],\n aiMessageIndex: number,\n cutoffIndex: number,\n toolCallIds: Set<string>\n): boolean {\n for (let j = aiMessageIndex + 1; j < messages.length; j++) {\n const message = messages[j];\n if (\n ToolMessage.isInstance(message) &&\n toolCallIds.has(message.tool_call_id)\n ) {\n const aiBeforeCutoff = aiMessageIndex < cutoffIndex;\n const toolBeforeCutoff = j < cutoffIndex;\n if (aiBeforeCutoff !== toolBeforeCutoff) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Generate summary for the given messages\n */\nasync function createSummary(\n messagesToSummarize: BaseMessage[],\n model: BaseLanguageModel,\n summaryPrompt: string,\n tokenCounter: TokenCounter\n): Promise<string> {\n if (!messagesToSummarize.length) {\n return \"No previous conversation history.\";\n }\n\n const trimmedMessages = await trimMessagesForSummary(\n messagesToSummarize,\n tokenCounter\n );\n\n if (!trimmedMessages.length) {\n return \"Previous conversation was too long to summarize.\";\n }\n\n try {\n const formattedPrompt = summaryPrompt.replace(\n \"{messages}\",\n JSON.stringify(trimmedMessages, null, 2)\n );\n const response = await model.invoke(formattedPrompt);\n const { content } = response;\n return typeof content === \"string\"\n ? content.trim()\n : \"Error generating summary: Invalid response format\";\n } catch (e) {\n return `Error generating summary: ${e}`;\n }\n}\n\n/**\n * Trim messages to fit within summary generation limits\n */\nasync function trimMessagesForSummary(\n messages: BaseMessage[],\n tokenCounter: TokenCounter\n): Promise<BaseMessage[]> {\n try {\n return await trimMessages(messages, {\n maxTokens: DEFAULT_TRIM_TOKEN_LIMIT,\n tokenCounter: async (msgs) => Promise.resolve(tokenCounter(msgs)),\n strategy: \"last\",\n allowPartial: true,\n includeSystem: true,\n });\n } catch {\n // Fallback to last N messages if trimming fails\n return messages.slice(-DEFAULT_FALLBACK_MESSAGE_COUNT);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { AgentMiddleware } from "../types.cjs";
|
|
2
2
|
import * as _langchain_core_language_models_base1 from "@langchain/core/language_models/base";
|
|
3
3
|
import { BaseLanguageModel } from "@langchain/core/language_models/base";
|
|
4
|
-
import {
|
|
4
|
+
import { InferInteropZodInput } from "@langchain/core/utils/types";
|
|
5
5
|
import { BaseMessage } from "@langchain/core/messages";
|
|
6
|
+
import { z } from "zod/v3";
|
|
6
7
|
|
|
7
8
|
//#region src/agents/middlewareAgent/middleware/summarization.d.ts
|
|
8
9
|
declare const contextSchema: z.ZodObject<{
|
|
@@ -27,6 +28,7 @@ declare const contextSchema: z.ZodObject<{
|
|
|
27
28
|
summaryPrompt?: string | undefined;
|
|
28
29
|
summaryPrefix?: string | undefined;
|
|
29
30
|
}>;
|
|
31
|
+
type SummarizationMiddlewareConfig = InferInteropZodInput<typeof contextSchema>;
|
|
30
32
|
/**
|
|
31
33
|
* Default token counter that approximates based on character count
|
|
32
34
|
* @param messages Messages to count tokens for
|
|
@@ -62,7 +64,7 @@ declare function countTokensApproximately(messages: BaseMessage[]): number;
|
|
|
62
64
|
*
|
|
63
65
|
* ```
|
|
64
66
|
*/
|
|
65
|
-
declare function summarizationMiddleware(options:
|
|
67
|
+
declare function summarizationMiddleware(options: SummarizationMiddlewareConfig): AgentMiddleware<undefined, z.ZodObject<{
|
|
66
68
|
model: z.ZodType<BaseLanguageModel<any, _langchain_core_language_models_base1.BaseLanguageModelCallOptions>, z.ZodTypeDef, BaseLanguageModel<any, _langchain_core_language_models_base1.BaseLanguageModelCallOptions>>;
|
|
67
69
|
maxTokensBeforeSummary: z.ZodOptional<z.ZodNumber>;
|
|
68
70
|
messagesToKeep: z.ZodDefault<z.ZodNumber>;
|
|
@@ -85,5 +87,5 @@ declare function summarizationMiddleware(options: z.input<typeof contextSchema>)
|
|
|
85
87
|
summaryPrefix?: string | undefined;
|
|
86
88
|
}>, any>;
|
|
87
89
|
//#endregion
|
|
88
|
-
export { countTokensApproximately, summarizationMiddleware };
|
|
90
|
+
export { SummarizationMiddlewareConfig, countTokensApproximately, summarizationMiddleware };
|
|
89
91
|
//# sourceMappingURL=summarization.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarization.d.cts","names":["
|
|
1
|
+
{"version":3,"file":"summarization.d.cts","names":["___types_js3","z","BaseMessage","BaseLanguageModel","InferInteropZodInput","contextSchema","_langchain_core_language_models_base1","BaseLanguageModelCallOptions","ZodTypeDef","ZodType","ZodNumber","ZodOptional","ZodDefault","ZodAny","ZodArray","ZodUnknown","ZodTuple","ZodPromise","ZodUnion","ZodFunction","ZodString","ZodTypeAny","Promise","ZodObject","SummarizationMiddlewareConfig","countTokensApproximately","summarizationMiddleware","AgentMiddleware"],"sources":["../../../../src/agents/middlewareAgent/middleware/summarization.d.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport { BaseMessage } from \"@langchain/core/messages\";\nimport { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport { InferInteropZodInput } from \"@langchain/core/utils/types\";\ndeclare const contextSchema: z.ZodObject<{\n model: z.ZodType<BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>, z.ZodTypeDef, BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>>;\n maxTokensBeforeSummary: z.ZodOptional<z.ZodNumber>;\n messagesToKeep: z.ZodDefault<z.ZodNumber>;\n tokenCounter: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodArray<z.ZodAny, \"many\">], z.ZodUnknown>, z.ZodUnion<[z.ZodNumber, z.ZodPromise<z.ZodNumber>]>>>;\n summaryPrompt: z.ZodDefault<z.ZodString>;\n summaryPrefix: z.ZodDefault<z.ZodString>;\n}, \"strip\", z.ZodTypeAny, {\n model: BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>;\n maxTokensBeforeSummary?: number | undefined;\n messagesToKeep: number;\n tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;\n summaryPrompt: string;\n summaryPrefix: string;\n}, {\n model: BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>;\n maxTokensBeforeSummary?: number | undefined;\n messagesToKeep?: number | undefined;\n tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;\n summaryPrompt?: string | undefined;\n summaryPrefix?: string | undefined;\n}>;\nexport type SummarizationMiddlewareConfig = InferInteropZodInput<typeof contextSchema>;\n/**\n * Default token counter that approximates based on character count\n * @param messages Messages to count tokens for\n * @returns Approximate token count\n */\nexport declare function countTokensApproximately(messages: BaseMessage[]): number;\n/**\n * Summarization middleware that automatically summarizes conversation history when token limits are approached.\n *\n * This middleware monitors message token counts and automatically summarizes older\n * messages when a threshold is reached, preserving recent messages and maintaining\n * context continuity by ensuring AI/Tool message pairs remain together.\n *\n * @param options Configuration options for the summarization middleware\n * @returns A middleware instance\n *\n * @example\n * ```ts\n * import { summarizationMiddleware } from \"langchain/middleware\";\n * import { createAgent } from \"langchain\";\n *\n * const agent = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * maxTokensBeforeSummary: 4000,\n * messagesToKeep: 20,\n * })\n * ],\n * });\n *\n * ```\n */\nexport declare function summarizationMiddleware(options: SummarizationMiddlewareConfig): import(\"../types.js\").AgentMiddleware<undefined, z.ZodObject<{\n model: z.ZodType<BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>, z.ZodTypeDef, BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>>;\n maxTokensBeforeSummary: z.ZodOptional<z.ZodNumber>;\n messagesToKeep: z.ZodDefault<z.ZodNumber>;\n tokenCounter: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodArray<z.ZodAny, \"many\">], z.ZodUnknown>, z.ZodUnion<[z.ZodNumber, z.ZodPromise<z.ZodNumber>]>>>;\n summaryPrompt: z.ZodDefault<z.ZodString>;\n summaryPrefix: z.ZodDefault<z.ZodString>;\n}, \"strip\", z.ZodTypeAny, {\n model: BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>;\n maxTokensBeforeSummary?: number | undefined;\n messagesToKeep: number;\n tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;\n summaryPrompt: string;\n summaryPrefix: string;\n}, {\n model: BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>;\n maxTokensBeforeSummary?: number | undefined;\n messagesToKeep?: number | undefined;\n tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;\n summaryPrompt?: string | undefined;\n summaryPrefix?: string | undefined;\n}>, any>;\nexport {};\n"],"mappings":"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"}
|
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
import { AgentMiddleware } from "../types.js";
|
|
2
2
|
import { BaseMessage } from "@langchain/core/messages";
|
|
3
|
+
import { InferInteropZodInput } from "@langchain/core/utils/types";
|
|
3
4
|
import { z } from "zod/v3";
|
|
4
|
-
import * as
|
|
5
|
+
import * as _langchain_core_language_models_base0 from "@langchain/core/language_models/base";
|
|
5
6
|
import { BaseLanguageModel } from "@langchain/core/language_models/base";
|
|
6
7
|
|
|
7
8
|
//#region src/agents/middlewareAgent/middleware/summarization.d.ts
|
|
8
9
|
declare const contextSchema: z.ZodObject<{
|
|
9
|
-
model: z.ZodType<BaseLanguageModel<any,
|
|
10
|
+
model: z.ZodType<BaseLanguageModel<any, _langchain_core_language_models_base0.BaseLanguageModelCallOptions>, z.ZodTypeDef, BaseLanguageModel<any, _langchain_core_language_models_base0.BaseLanguageModelCallOptions>>;
|
|
10
11
|
maxTokensBeforeSummary: z.ZodOptional<z.ZodNumber>;
|
|
11
12
|
messagesToKeep: z.ZodDefault<z.ZodNumber>;
|
|
12
13
|
tokenCounter: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodArray<z.ZodAny, "many">], z.ZodUnknown>, z.ZodUnion<[z.ZodNumber, z.ZodPromise<z.ZodNumber>]>>>;
|
|
13
14
|
summaryPrompt: z.ZodDefault<z.ZodString>;
|
|
14
15
|
summaryPrefix: z.ZodDefault<z.ZodString>;
|
|
15
16
|
}, "strip", z.ZodTypeAny, {
|
|
16
|
-
model: BaseLanguageModel<any,
|
|
17
|
+
model: BaseLanguageModel<any, _langchain_core_language_models_base0.BaseLanguageModelCallOptions>;
|
|
17
18
|
maxTokensBeforeSummary?: number | undefined;
|
|
18
19
|
messagesToKeep: number;
|
|
19
20
|
tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;
|
|
20
21
|
summaryPrompt: string;
|
|
21
22
|
summaryPrefix: string;
|
|
22
23
|
}, {
|
|
23
|
-
model: BaseLanguageModel<any,
|
|
24
|
+
model: BaseLanguageModel<any, _langchain_core_language_models_base0.BaseLanguageModelCallOptions>;
|
|
24
25
|
maxTokensBeforeSummary?: number | undefined;
|
|
25
26
|
messagesToKeep?: number | undefined;
|
|
26
27
|
tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;
|
|
27
28
|
summaryPrompt?: string | undefined;
|
|
28
29
|
summaryPrefix?: string | undefined;
|
|
29
30
|
}>;
|
|
31
|
+
type SummarizationMiddlewareConfig = InferInteropZodInput<typeof contextSchema>;
|
|
30
32
|
/**
|
|
31
33
|
* Default token counter that approximates based on character count
|
|
32
34
|
* @param messages Messages to count tokens for
|
|
@@ -62,22 +64,22 @@ declare function countTokensApproximately(messages: BaseMessage[]): number;
|
|
|
62
64
|
*
|
|
63
65
|
* ```
|
|
64
66
|
*/
|
|
65
|
-
declare function summarizationMiddleware(options:
|
|
66
|
-
model: z.ZodType<BaseLanguageModel<any,
|
|
67
|
+
declare function summarizationMiddleware(options: SummarizationMiddlewareConfig): AgentMiddleware<undefined, z.ZodObject<{
|
|
68
|
+
model: z.ZodType<BaseLanguageModel<any, _langchain_core_language_models_base0.BaseLanguageModelCallOptions>, z.ZodTypeDef, BaseLanguageModel<any, _langchain_core_language_models_base0.BaseLanguageModelCallOptions>>;
|
|
67
69
|
maxTokensBeforeSummary: z.ZodOptional<z.ZodNumber>;
|
|
68
70
|
messagesToKeep: z.ZodDefault<z.ZodNumber>;
|
|
69
71
|
tokenCounter: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodArray<z.ZodAny, "many">], z.ZodUnknown>, z.ZodUnion<[z.ZodNumber, z.ZodPromise<z.ZodNumber>]>>>;
|
|
70
72
|
summaryPrompt: z.ZodDefault<z.ZodString>;
|
|
71
73
|
summaryPrefix: z.ZodDefault<z.ZodString>;
|
|
72
74
|
}, "strip", z.ZodTypeAny, {
|
|
73
|
-
model: BaseLanguageModel<any,
|
|
75
|
+
model: BaseLanguageModel<any, _langchain_core_language_models_base0.BaseLanguageModelCallOptions>;
|
|
74
76
|
maxTokensBeforeSummary?: number | undefined;
|
|
75
77
|
messagesToKeep: number;
|
|
76
78
|
tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;
|
|
77
79
|
summaryPrompt: string;
|
|
78
80
|
summaryPrefix: string;
|
|
79
81
|
}, {
|
|
80
|
-
model: BaseLanguageModel<any,
|
|
82
|
+
model: BaseLanguageModel<any, _langchain_core_language_models_base0.BaseLanguageModelCallOptions>;
|
|
81
83
|
maxTokensBeforeSummary?: number | undefined;
|
|
82
84
|
messagesToKeep?: number | undefined;
|
|
83
85
|
tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;
|
|
@@ -85,5 +87,5 @@ declare function summarizationMiddleware(options: z.input<typeof contextSchema>)
|
|
|
85
87
|
summaryPrefix?: string | undefined;
|
|
86
88
|
}>, any>;
|
|
87
89
|
//#endregion
|
|
88
|
-
export { countTokensApproximately, summarizationMiddleware };
|
|
90
|
+
export { SummarizationMiddlewareConfig, countTokensApproximately, summarizationMiddleware };
|
|
89
91
|
//# sourceMappingURL=summarization.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarization.d.ts","names":["
|
|
1
|
+
{"version":3,"file":"summarization.d.ts","names":["___types_js0","z","BaseMessage","BaseLanguageModel","InferInteropZodInput","contextSchema","_langchain_core_language_models_base0","BaseLanguageModelCallOptions","ZodTypeDef","ZodType","ZodNumber","ZodOptional","ZodDefault","ZodAny","ZodArray","ZodUnknown","ZodTuple","ZodPromise","ZodUnion","ZodFunction","ZodString","ZodTypeAny","Promise","ZodObject","SummarizationMiddlewareConfig","countTokensApproximately","summarizationMiddleware","AgentMiddleware"],"sources":["../../../../src/agents/middlewareAgent/middleware/summarization.d.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport { BaseMessage } from \"@langchain/core/messages\";\nimport { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport { InferInteropZodInput } from \"@langchain/core/utils/types\";\ndeclare const contextSchema: z.ZodObject<{\n model: z.ZodType<BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>, z.ZodTypeDef, BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>>;\n maxTokensBeforeSummary: z.ZodOptional<z.ZodNumber>;\n messagesToKeep: z.ZodDefault<z.ZodNumber>;\n tokenCounter: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodArray<z.ZodAny, \"many\">], z.ZodUnknown>, z.ZodUnion<[z.ZodNumber, z.ZodPromise<z.ZodNumber>]>>>;\n summaryPrompt: z.ZodDefault<z.ZodString>;\n summaryPrefix: z.ZodDefault<z.ZodString>;\n}, \"strip\", z.ZodTypeAny, {\n model: BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>;\n maxTokensBeforeSummary?: number | undefined;\n messagesToKeep: number;\n tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;\n summaryPrompt: string;\n summaryPrefix: string;\n}, {\n model: BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>;\n maxTokensBeforeSummary?: number | undefined;\n messagesToKeep?: number | undefined;\n tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;\n summaryPrompt?: string | undefined;\n summaryPrefix?: string | undefined;\n}>;\nexport type SummarizationMiddlewareConfig = InferInteropZodInput<typeof contextSchema>;\n/**\n * Default token counter that approximates based on character count\n * @param messages Messages to count tokens for\n * @returns Approximate token count\n */\nexport declare function countTokensApproximately(messages: BaseMessage[]): number;\n/**\n * Summarization middleware that automatically summarizes conversation history when token limits are approached.\n *\n * This middleware monitors message token counts and automatically summarizes older\n * messages when a threshold is reached, preserving recent messages and maintaining\n * context continuity by ensuring AI/Tool message pairs remain together.\n *\n * @param options Configuration options for the summarization middleware\n * @returns A middleware instance\n *\n * @example\n * ```ts\n * import { summarizationMiddleware } from \"langchain/middleware\";\n * import { createAgent } from \"langchain\";\n *\n * const agent = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * maxTokensBeforeSummary: 4000,\n * messagesToKeep: 20,\n * })\n * ],\n * });\n *\n * ```\n */\nexport declare function summarizationMiddleware(options: SummarizationMiddlewareConfig): import(\"../types.js\").AgentMiddleware<undefined, z.ZodObject<{\n model: z.ZodType<BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>, z.ZodTypeDef, BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>>;\n maxTokensBeforeSummary: z.ZodOptional<z.ZodNumber>;\n messagesToKeep: z.ZodDefault<z.ZodNumber>;\n tokenCounter: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodArray<z.ZodAny, \"many\">], z.ZodUnknown>, z.ZodUnion<[z.ZodNumber, z.ZodPromise<z.ZodNumber>]>>>;\n summaryPrompt: z.ZodDefault<z.ZodString>;\n summaryPrefix: z.ZodDefault<z.ZodString>;\n}, \"strip\", z.ZodTypeAny, {\n model: BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>;\n maxTokensBeforeSummary?: number | undefined;\n messagesToKeep: number;\n tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;\n summaryPrompt: string;\n summaryPrefix: string;\n}, {\n model: BaseLanguageModel<any, import(\"@langchain/core/language_models/base\").BaseLanguageModelCallOptions>;\n maxTokensBeforeSummary?: number | undefined;\n messagesToKeep?: number | undefined;\n tokenCounter?: ((args_0: any[], ...args: unknown[]) => number | Promise<number>) | undefined;\n summaryPrompt?: string | undefined;\n summaryPrefix?: string | undefined;\n}>, any>;\nexport {};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createMiddleware } from "../middleware.js";
|
|
2
|
-
import { RemoveMessage, SystemMessage,
|
|
2
|
+
import { AIMessage, RemoveMessage, SystemMessage, ToolMessage, trimMessages } from "@langchain/core/messages";
|
|
3
3
|
import { REMOVE_ALL_MESSAGES } from "@langchain/langgraph";
|
|
4
|
+
import { interopParse } from "@langchain/core/utils/types";
|
|
4
5
|
import { z } from "zod/v3";
|
|
5
6
|
import { v4 } from "uuid";
|
|
6
7
|
|
|
@@ -99,21 +100,32 @@ function summarizationMiddleware(options) {
|
|
|
99
100
|
name: "SummarizationMiddleware",
|
|
100
101
|
contextSchema,
|
|
101
102
|
beforeModel: async (state, runtime) => {
|
|
103
|
+
/**
|
|
104
|
+
* Parse user options to get their explicit values
|
|
105
|
+
*/
|
|
106
|
+
const userOptions = interopParse(contextSchema, options);
|
|
107
|
+
/**
|
|
108
|
+
* Merge context with user options, preferring user options when context has default values
|
|
109
|
+
*/
|
|
102
110
|
const config = {
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
model: userOptions.model,
|
|
112
|
+
maxTokensBeforeSummary: runtime.context.maxTokensBeforeSummary !== void 0 ? runtime.context.maxTokensBeforeSummary : userOptions.maxTokensBeforeSummary,
|
|
113
|
+
messagesToKeep: runtime.context.messagesToKeep === DEFAULT_MESSAGES_TO_KEEP ? userOptions.messagesToKeep : runtime.context.messagesToKeep ?? userOptions.messagesToKeep,
|
|
114
|
+
tokenCounter: runtime.context.tokenCounter !== void 0 ? runtime.context.tokenCounter : userOptions.tokenCounter,
|
|
115
|
+
summaryPrompt: runtime.context.summaryPrompt === DEFAULT_SUMMARY_PROMPT ? userOptions.summaryPrompt : runtime.context.summaryPrompt ?? userOptions.summaryPrompt,
|
|
116
|
+
summaryPrefix: runtime.context.summaryPrefix === SUMMARY_PREFIX ? userOptions.summaryPrefix : runtime.context.summaryPrefix ?? userOptions.summaryPrefix
|
|
105
117
|
};
|
|
106
118
|
const { messages } = state;
|
|
107
119
|
ensureMessageIds(messages);
|
|
108
120
|
const tokenCounter = config.tokenCounter || countTokensApproximately;
|
|
109
121
|
const totalTokens = await tokenCounter(messages);
|
|
110
122
|
if (config.maxTokensBeforeSummary == null || totalTokens < config.maxTokensBeforeSummary) return;
|
|
111
|
-
const {
|
|
123
|
+
const { systemPrompt, conversationMessages } = splitSystemMessage(messages);
|
|
112
124
|
const cutoffIndex = findSafeCutoff(conversationMessages, config.messagesToKeep);
|
|
113
125
|
if (cutoffIndex <= 0) return;
|
|
114
|
-
const { messagesToSummarize, preservedMessages } = partitionMessages(
|
|
126
|
+
const { messagesToSummarize, preservedMessages } = partitionMessages(systemPrompt, conversationMessages, cutoffIndex);
|
|
115
127
|
const summary = await createSummary(messagesToSummarize, config.model, config.summaryPrompt, tokenCounter);
|
|
116
|
-
const updatedSystemMessage = buildUpdatedSystemMessage(
|
|
128
|
+
const updatedSystemMessage = buildUpdatedSystemMessage(systemPrompt, summary, config.summaryPrefix);
|
|
117
129
|
return { messages: [
|
|
118
130
|
new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),
|
|
119
131
|
updatedSystemMessage,
|
|
@@ -132,22 +144,22 @@ function ensureMessageIds(messages) {
|
|
|
132
144
|
* Separate system message from conversation messages
|
|
133
145
|
*/
|
|
134
146
|
function splitSystemMessage(messages) {
|
|
135
|
-
if (messages.length > 0 &&
|
|
136
|
-
|
|
147
|
+
if (messages.length > 0 && SystemMessage.isInstance(messages[0])) return {
|
|
148
|
+
systemPrompt: messages[0],
|
|
137
149
|
conversationMessages: messages.slice(1)
|
|
138
150
|
};
|
|
139
151
|
return {
|
|
140
|
-
|
|
152
|
+
systemPrompt: null,
|
|
141
153
|
conversationMessages: messages
|
|
142
154
|
};
|
|
143
155
|
}
|
|
144
156
|
/**
|
|
145
157
|
* Partition messages into those to summarize and those to preserve
|
|
146
158
|
*/
|
|
147
|
-
function partitionMessages(
|
|
159
|
+
function partitionMessages(systemPrompt, conversationMessages, cutoffIndex) {
|
|
148
160
|
const messagesToSummarize = conversationMessages.slice(0, cutoffIndex);
|
|
149
161
|
const preservedMessages = conversationMessages.slice(cutoffIndex);
|
|
150
|
-
if (
|
|
162
|
+
if (systemPrompt) messagesToSummarize.unshift(systemPrompt);
|
|
151
163
|
return {
|
|
152
164
|
messagesToSummarize,
|
|
153
165
|
preservedMessages
|
|
@@ -195,7 +207,7 @@ function isSafeCutoffPoint(messages, cutoffIndex) {
|
|
|
195
207
|
* Check if message is an AI message with tool calls
|
|
196
208
|
*/
|
|
197
209
|
function hasToolCalls(message) {
|
|
198
|
-
return
|
|
210
|
+
return AIMessage.isInstance(message) && "tool_calls" in message && Array.isArray(message.tool_calls) && message.tool_calls.length > 0;
|
|
199
211
|
}
|
|
200
212
|
/**
|
|
201
213
|
* Extract tool call IDs from an AI message
|
|
@@ -214,7 +226,7 @@ function extractToolCallIds(aiMessage) {
|
|
|
214
226
|
function cutoffSeparatesToolPair(messages, aiMessageIndex, cutoffIndex, toolCallIds) {
|
|
215
227
|
for (let j = aiMessageIndex + 1; j < messages.length; j++) {
|
|
216
228
|
const message = messages[j];
|
|
217
|
-
if (
|
|
229
|
+
if (ToolMessage.isInstance(message) && toolCallIds.has(message.tool_call_id)) {
|
|
218
230
|
const aiBeforeCutoff = aiMessageIndex < cutoffIndex;
|
|
219
231
|
const toolBeforeCutoff = j < cutoffIndex;
|
|
220
232
|
if (aiBeforeCutoff !== toolBeforeCutoff) return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarization.js","names":["messages: BaseMessage[]","textContent: string","options: z.input<typeof contextSchema>","uuid","systemMessage: SystemMessage | null","conversationMessages: BaseMessage[]","cutoffIndex: number","originalSystemMessage: SystemMessage | null","summary: string","summaryPrefix: string","content","messagesToKeep: number","message: BaseMessage","aiMessage: AIMessage","aiMessageIndex: number","toolCallIds: Set<string>","messagesToSummarize: BaseMessage[]","model: BaseLanguageModel","summaryPrompt: string","tokenCounter: TokenCounter"],"sources":["../../../../src/agents/middlewareAgent/middleware/summarization.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n BaseMessage,\n AIMessage,\n SystemMessage,\n isToolMessage,\n RemoveMessage,\n trimMessages,\n isSystemMessage,\n isAIMessage,\n} from \"@langchain/core/messages\";\nimport { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport { REMOVE_ALL_MESSAGES } from \"@langchain/langgraph\";\nimport { createMiddleware } from \"../middleware.js\";\n\nconst DEFAULT_SUMMARY_PROMPT = `<role>\nContext Extraction Assistant\n</role>\n\n<primary_objective>\nYour sole objective in this task is to extract the highest quality/most relevant context from the conversation history below.\n</primary_objective>\n\n<objective_information>\nYou're nearing the total number of input tokens you can accept, so you must extract the highest quality/most relevant pieces of information from your conversation history.\nThis context will then overwrite the conversation history presented below. Because of this, ensure the context you extract is only the most important information to your overall goal.\n</objective_information>\n\n<instructions>\nThe conversation history below will be replaced with the context you extract in this step. Because of this, you must do your very best to extract and record all of the most important context from the conversation history.\nYou want to ensure that you don't repeat any actions you've already completed, so the context you extract from the conversation history should be focused on the most important information to your overall goal.\n</instructions>\n\nThe user will message you with the full message history you'll be extracting context from, to then replace. Carefully read over it all, and think deeply about what information is most important to your overall goal that should be saved:\n\nWith all of this in mind, please carefully read over the entire conversation history, and extract the most important and relevant context to replace it so that you can free up space in the conversation history.\nRespond ONLY with the extracted context. Do not include any additional information, or text before or after the extracted context.\n\n<messages>\nMessages to summarize:\n{messages}\n</messages>`;\n\nconst SUMMARY_PREFIX = \"## Previous conversation summary:\";\n\nconst DEFAULT_MESSAGES_TO_KEEP = 20;\nconst DEFAULT_TRIM_TOKEN_LIMIT = 4000;\nconst DEFAULT_FALLBACK_MESSAGE_COUNT = 15;\nconst SEARCH_RANGE_FOR_TOOL_PAIRS = 5;\n\ntype TokenCounter = (messages: BaseMessage[]) => number | Promise<number>;\n\nconst contextSchema = z.object({\n model: z.custom<BaseLanguageModel>(),\n maxTokensBeforeSummary: z.number().optional(),\n messagesToKeep: z.number().default(DEFAULT_MESSAGES_TO_KEEP),\n tokenCounter: z\n .function()\n .args(z.array(z.any()))\n .returns(z.union([z.number(), z.promise(z.number())]))\n .optional(),\n summaryPrompt: z.string().default(DEFAULT_SUMMARY_PROMPT),\n summaryPrefix: z.string().default(SUMMARY_PREFIX),\n});\n\n/**\n * Default token counter that approximates based on character count\n * @param messages Messages to count tokens for\n * @returns Approximate token count\n */\nexport function countTokensApproximately(messages: BaseMessage[]): number {\n let totalChars = 0;\n for (const msg of messages) {\n let textContent: string;\n if (typeof msg.content === \"string\") {\n textContent = msg.content;\n } else if (Array.isArray(msg.content)) {\n textContent = msg.content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (item.type === \"text\" && \"text\" in item) return item.text;\n return \"\";\n })\n .join(\"\");\n } else {\n textContent = \"\";\n }\n totalChars += textContent.length;\n }\n // Approximate 1 token = 4 characters\n return Math.ceil(totalChars / 4);\n}\n\n/**\n * Summarization middleware that automatically summarizes conversation history when token limits are approached.\n *\n * This middleware monitors message token counts and automatically summarizes older\n * messages when a threshold is reached, preserving recent messages and maintaining\n * context continuity by ensuring AI/Tool message pairs remain together.\n *\n * @param options Configuration options for the summarization middleware\n * @returns A middleware instance\n *\n * @example\n * ```ts\n * import { summarizationMiddleware } from \"langchain/middleware\";\n * import { createAgent } from \"langchain\";\n *\n * const agent = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * maxTokensBeforeSummary: 4000,\n * messagesToKeep: 20,\n * })\n * ],\n * });\n *\n * ```\n */\nexport function summarizationMiddleware(\n options: z.input<typeof contextSchema>\n) {\n return createMiddleware({\n name: \"SummarizationMiddleware\",\n contextSchema,\n beforeModel: async (state, runtime) => {\n const config = { ...contextSchema.parse(options), ...runtime.context };\n const { messages } = state;\n\n // Ensure all messages have IDs\n ensureMessageIds(messages);\n\n const tokenCounter = config.tokenCounter || countTokensApproximately;\n const totalTokens = await tokenCounter(messages);\n\n if (\n config.maxTokensBeforeSummary == null ||\n totalTokens < config.maxTokensBeforeSummary\n ) {\n return;\n }\n\n const { systemMessage, conversationMessages } =\n splitSystemMessage(messages);\n const cutoffIndex = findSafeCutoff(\n conversationMessages,\n config.messagesToKeep\n );\n\n if (cutoffIndex <= 0) {\n return;\n }\n\n const { messagesToSummarize, preservedMessages } = partitionMessages(\n systemMessage,\n conversationMessages,\n cutoffIndex\n );\n\n const summary = await createSummary(\n messagesToSummarize,\n config.model,\n config.summaryPrompt,\n tokenCounter\n );\n\n const updatedSystemMessage = buildUpdatedSystemMessage(\n systemMessage,\n summary,\n config.summaryPrefix\n );\n\n return {\n messages: [\n new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),\n updatedSystemMessage,\n ...preservedMessages,\n ],\n };\n },\n });\n}\n\n/**\n * Ensure all messages have unique IDs\n */\nfunction ensureMessageIds(messages: BaseMessage[]): void {\n for (const msg of messages) {\n if (!msg.id) {\n msg.id = uuid();\n }\n }\n}\n\n/**\n * Separate system message from conversation messages\n */\nfunction splitSystemMessage(messages: BaseMessage[]): {\n systemMessage: SystemMessage | null;\n conversationMessages: BaseMessage[];\n} {\n if (messages.length > 0 && isSystemMessage(messages[0])) {\n return {\n systemMessage: messages[0] as SystemMessage,\n conversationMessages: messages.slice(1),\n };\n }\n return {\n systemMessage: null,\n conversationMessages: messages,\n };\n}\n\n/**\n * Partition messages into those to summarize and those to preserve\n */\nfunction partitionMessages(\n systemMessage: SystemMessage | null,\n conversationMessages: BaseMessage[],\n cutoffIndex: number\n): { messagesToSummarize: BaseMessage[]; preservedMessages: BaseMessage[] } {\n const messagesToSummarize = conversationMessages.slice(0, cutoffIndex);\n const preservedMessages = conversationMessages.slice(cutoffIndex);\n\n // Include system message in messages to summarize to capture previous summaries\n if (systemMessage) {\n messagesToSummarize.unshift(systemMessage);\n }\n\n return { messagesToSummarize, preservedMessages };\n}\n\n/**\n * Build updated system message incorporating the summary\n */\nfunction buildUpdatedSystemMessage(\n originalSystemMessage: SystemMessage | null,\n summary: string,\n summaryPrefix: string\n): SystemMessage {\n let originalContent = \"\";\n if (originalSystemMessage) {\n const { content } = originalSystemMessage;\n if (typeof content === \"string\") {\n originalContent = content.split(summaryPrefix)[0].trim();\n }\n }\n\n const content = originalContent\n ? `${originalContent}\\n${summaryPrefix}\\n${summary}`\n : `${summaryPrefix}\\n${summary}`;\n\n return new SystemMessage({\n content,\n id: originalSystemMessage?.id || uuid(),\n });\n}\n\n/**\n * Find safe cutoff point that preserves AI/Tool message pairs\n */\nfunction findSafeCutoff(\n messages: BaseMessage[],\n messagesToKeep: number\n): number {\n if (messages.length <= messagesToKeep) {\n return 0;\n }\n\n const targetCutoff = messages.length - messagesToKeep;\n\n for (let i = targetCutoff; i >= 0; i--) {\n if (isSafeCutoffPoint(messages, i)) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Check if cutting at index would separate AI/Tool message pairs\n */\nfunction isSafeCutoffPoint(\n messages: BaseMessage[],\n cutoffIndex: number\n): boolean {\n if (cutoffIndex >= messages.length) {\n return true;\n }\n\n const searchStart = Math.max(0, cutoffIndex - SEARCH_RANGE_FOR_TOOL_PAIRS);\n const searchEnd = Math.min(\n messages.length,\n cutoffIndex + SEARCH_RANGE_FOR_TOOL_PAIRS\n );\n\n for (let i = searchStart; i < searchEnd; i++) {\n if (!hasToolCalls(messages[i])) {\n continue;\n }\n\n const toolCallIds = extractToolCallIds(messages[i] as AIMessage);\n if (cutoffSeparatesToolPair(messages, i, cutoffIndex, toolCallIds)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if message is an AI message with tool calls\n */\nfunction hasToolCalls(message: BaseMessage): boolean {\n return (\n isAIMessage(message) &&\n \"tool_calls\" in message &&\n Array.isArray(message.tool_calls) &&\n message.tool_calls.length > 0\n );\n}\n\n/**\n * Extract tool call IDs from an AI message\n */\nfunction extractToolCallIds(aiMessage: AIMessage): Set<string> {\n const toolCallIds = new Set<string>();\n if (aiMessage.tool_calls) {\n for (const toolCall of aiMessage.tool_calls) {\n const id =\n typeof toolCall === \"object\" && \"id\" in toolCall ? toolCall.id : null;\n if (id) {\n toolCallIds.add(id);\n }\n }\n }\n return toolCallIds;\n}\n\n/**\n * Check if cutoff separates an AI message from its corresponding tool messages\n */\nfunction cutoffSeparatesToolPair(\n messages: BaseMessage[],\n aiMessageIndex: number,\n cutoffIndex: number,\n toolCallIds: Set<string>\n): boolean {\n for (let j = aiMessageIndex + 1; j < messages.length; j++) {\n const message = messages[j];\n if (isToolMessage(message) && toolCallIds.has(message.tool_call_id)) {\n const aiBeforeCutoff = aiMessageIndex < cutoffIndex;\n const toolBeforeCutoff = j < cutoffIndex;\n if (aiBeforeCutoff !== toolBeforeCutoff) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Generate summary for the given messages\n */\nasync function createSummary(\n messagesToSummarize: BaseMessage[],\n model: BaseLanguageModel,\n summaryPrompt: string,\n tokenCounter: TokenCounter\n): Promise<string> {\n if (!messagesToSummarize.length) {\n return \"No previous conversation history.\";\n }\n\n const trimmedMessages = await trimMessagesForSummary(\n messagesToSummarize,\n tokenCounter\n );\n\n if (!trimmedMessages.length) {\n return \"Previous conversation was too long to summarize.\";\n }\n\n try {\n const formattedPrompt = summaryPrompt.replace(\n \"{messages}\",\n JSON.stringify(trimmedMessages, null, 2)\n );\n const response = await model.invoke(formattedPrompt);\n const { content } = response;\n return typeof content === \"string\"\n ? content.trim()\n : \"Error generating summary: Invalid response format\";\n } catch (e) {\n return `Error generating summary: ${e}`;\n }\n}\n\n/**\n * Trim messages to fit within summary generation limits\n */\nasync function trimMessagesForSummary(\n messages: BaseMessage[],\n tokenCounter: TokenCounter\n): Promise<BaseMessage[]> {\n try {\n return await trimMessages(messages, {\n maxTokens: DEFAULT_TRIM_TOKEN_LIMIT,\n tokenCounter: async (msgs) => Promise.resolve(tokenCounter(msgs)),\n strategy: \"last\",\n allowPartial: true,\n includeSystem: true,\n });\n } catch {\n // Fallback to last N messages if trimming fails\n return messages.slice(-DEFAULT_FALLBACK_MESSAGE_COUNT);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"summarization.js","names":["messages: BaseMessage[]","textContent: string","options: SummarizationMiddlewareConfig","uuid","systemPrompt: SystemMessage | null","conversationMessages: BaseMessage[]","cutoffIndex: number","originalSystemMessage: SystemMessage | null","summary: string","summaryPrefix: string","content","messagesToKeep: number","message: BaseMessage","aiMessage: AIMessage","aiMessageIndex: number","toolCallIds: Set<string>","messagesToSummarize: BaseMessage[]","model: BaseLanguageModel","summaryPrompt: string","tokenCounter: TokenCounter"],"sources":["../../../../src/agents/middlewareAgent/middleware/summarization.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n BaseMessage,\n AIMessage,\n SystemMessage,\n ToolMessage,\n RemoveMessage,\n trimMessages,\n} from \"@langchain/core/messages\";\nimport { BaseLanguageModel } from \"@langchain/core/language_models/base\";\nimport {\n interopParse,\n InferInteropZodOutput,\n InferInteropZodInput,\n} from \"@langchain/core/utils/types\";\nimport { REMOVE_ALL_MESSAGES } from \"@langchain/langgraph\";\nimport { createMiddleware } from \"../middleware.js\";\n\nconst DEFAULT_SUMMARY_PROMPT = `<role>\nContext Extraction Assistant\n</role>\n\n<primary_objective>\nYour sole objective in this task is to extract the highest quality/most relevant context from the conversation history below.\n</primary_objective>\n\n<objective_information>\nYou're nearing the total number of input tokens you can accept, so you must extract the highest quality/most relevant pieces of information from your conversation history.\nThis context will then overwrite the conversation history presented below. Because of this, ensure the context you extract is only the most important information to your overall goal.\n</objective_information>\n\n<instructions>\nThe conversation history below will be replaced with the context you extract in this step. Because of this, you must do your very best to extract and record all of the most important context from the conversation history.\nYou want to ensure that you don't repeat any actions you've already completed, so the context you extract from the conversation history should be focused on the most important information to your overall goal.\n</instructions>\n\nThe user will message you with the full message history you'll be extracting context from, to then replace. Carefully read over it all, and think deeply about what information is most important to your overall goal that should be saved:\n\nWith all of this in mind, please carefully read over the entire conversation history, and extract the most important and relevant context to replace it so that you can free up space in the conversation history.\nRespond ONLY with the extracted context. Do not include any additional information, or text before or after the extracted context.\n\n<messages>\nMessages to summarize:\n{messages}\n</messages>`;\n\nconst SUMMARY_PREFIX = \"## Previous conversation summary:\";\n\nconst DEFAULT_MESSAGES_TO_KEEP = 20;\nconst DEFAULT_TRIM_TOKEN_LIMIT = 4000;\nconst DEFAULT_FALLBACK_MESSAGE_COUNT = 15;\nconst SEARCH_RANGE_FOR_TOOL_PAIRS = 5;\n\ntype TokenCounter = (messages: BaseMessage[]) => number | Promise<number>;\n\nconst contextSchema = z.object({\n model: z.custom<BaseLanguageModel>(),\n maxTokensBeforeSummary: z.number().optional(),\n messagesToKeep: z.number().default(DEFAULT_MESSAGES_TO_KEEP),\n tokenCounter: z\n .function()\n .args(z.array(z.any()))\n .returns(z.union([z.number(), z.promise(z.number())]))\n .optional(),\n summaryPrompt: z.string().default(DEFAULT_SUMMARY_PROMPT),\n summaryPrefix: z.string().default(SUMMARY_PREFIX),\n});\n\nexport type SummarizationMiddlewareConfig = InferInteropZodInput<\n typeof contextSchema\n>;\n\n/**\n * Default token counter that approximates based on character count\n * @param messages Messages to count tokens for\n * @returns Approximate token count\n */\nexport function countTokensApproximately(messages: BaseMessage[]): number {\n let totalChars = 0;\n for (const msg of messages) {\n let textContent: string;\n if (typeof msg.content === \"string\") {\n textContent = msg.content;\n } else if (Array.isArray(msg.content)) {\n textContent = msg.content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (item.type === \"text\" && \"text\" in item) return item.text;\n return \"\";\n })\n .join(\"\");\n } else {\n textContent = \"\";\n }\n totalChars += textContent.length;\n }\n // Approximate 1 token = 4 characters\n return Math.ceil(totalChars / 4);\n}\n\n/**\n * Summarization middleware that automatically summarizes conversation history when token limits are approached.\n *\n * This middleware monitors message token counts and automatically summarizes older\n * messages when a threshold is reached, preserving recent messages and maintaining\n * context continuity by ensuring AI/Tool message pairs remain together.\n *\n * @param options Configuration options for the summarization middleware\n * @returns A middleware instance\n *\n * @example\n * ```ts\n * import { summarizationMiddleware } from \"langchain/middleware\";\n * import { createAgent } from \"langchain\";\n *\n * const agent = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * maxTokensBeforeSummary: 4000,\n * messagesToKeep: 20,\n * })\n * ],\n * });\n *\n * ```\n */\nexport function summarizationMiddleware(\n options: SummarizationMiddlewareConfig\n) {\n return createMiddleware({\n name: \"SummarizationMiddleware\",\n contextSchema,\n beforeModel: async (state, runtime) => {\n /**\n * Parse user options to get their explicit values\n */\n const userOptions = interopParse(contextSchema, options);\n\n /**\n * Merge context with user options, preferring user options when context has default values\n */\n const config = {\n model: userOptions.model,\n maxTokensBeforeSummary:\n runtime.context.maxTokensBeforeSummary !== undefined\n ? runtime.context.maxTokensBeforeSummary\n : userOptions.maxTokensBeforeSummary,\n messagesToKeep:\n runtime.context.messagesToKeep === DEFAULT_MESSAGES_TO_KEEP\n ? userOptions.messagesToKeep\n : runtime.context.messagesToKeep ?? userOptions.messagesToKeep,\n tokenCounter:\n runtime.context.tokenCounter !== undefined\n ? runtime.context.tokenCounter\n : userOptions.tokenCounter,\n summaryPrompt:\n runtime.context.summaryPrompt === DEFAULT_SUMMARY_PROMPT\n ? userOptions.summaryPrompt\n : runtime.context.summaryPrompt ?? userOptions.summaryPrompt,\n summaryPrefix:\n runtime.context.summaryPrefix === SUMMARY_PREFIX\n ? userOptions.summaryPrefix\n : runtime.context.summaryPrefix ?? userOptions.summaryPrefix,\n } as InferInteropZodOutput<typeof contextSchema>;\n const { messages } = state;\n\n // Ensure all messages have IDs\n ensureMessageIds(messages);\n\n const tokenCounter = config.tokenCounter || countTokensApproximately;\n const totalTokens = await tokenCounter(messages);\n\n if (\n config.maxTokensBeforeSummary == null ||\n totalTokens < config.maxTokensBeforeSummary\n ) {\n return;\n }\n\n const { systemPrompt, conversationMessages } =\n splitSystemMessage(messages);\n const cutoffIndex = findSafeCutoff(\n conversationMessages,\n config.messagesToKeep\n );\n\n if (cutoffIndex <= 0) {\n return;\n }\n\n const { messagesToSummarize, preservedMessages } = partitionMessages(\n systemPrompt,\n conversationMessages,\n cutoffIndex\n );\n\n const summary = await createSummary(\n messagesToSummarize,\n config.model,\n config.summaryPrompt,\n tokenCounter\n );\n\n const updatedSystemMessage = buildUpdatedSystemMessage(\n systemPrompt,\n summary,\n config.summaryPrefix\n );\n\n return {\n messages: [\n new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),\n updatedSystemMessage,\n ...preservedMessages,\n ],\n };\n },\n });\n}\n\n/**\n * Ensure all messages have unique IDs\n */\nfunction ensureMessageIds(messages: BaseMessage[]): void {\n for (const msg of messages) {\n if (!msg.id) {\n msg.id = uuid();\n }\n }\n}\n\n/**\n * Separate system message from conversation messages\n */\nfunction splitSystemMessage(messages: BaseMessage[]): {\n systemPrompt: SystemMessage | null;\n conversationMessages: BaseMessage[];\n} {\n if (messages.length > 0 && SystemMessage.isInstance(messages[0])) {\n return {\n systemPrompt: messages[0] as SystemMessage,\n conversationMessages: messages.slice(1),\n };\n }\n return {\n systemPrompt: null,\n conversationMessages: messages,\n };\n}\n\n/**\n * Partition messages into those to summarize and those to preserve\n */\nfunction partitionMessages(\n systemPrompt: SystemMessage | null,\n conversationMessages: BaseMessage[],\n cutoffIndex: number\n): { messagesToSummarize: BaseMessage[]; preservedMessages: BaseMessage[] } {\n const messagesToSummarize = conversationMessages.slice(0, cutoffIndex);\n const preservedMessages = conversationMessages.slice(cutoffIndex);\n\n // Include system message in messages to summarize to capture previous summaries\n if (systemPrompt) {\n messagesToSummarize.unshift(systemPrompt);\n }\n\n return { messagesToSummarize, preservedMessages };\n}\n\n/**\n * Build updated system message incorporating the summary\n */\nfunction buildUpdatedSystemMessage(\n originalSystemMessage: SystemMessage | null,\n summary: string,\n summaryPrefix: string\n): SystemMessage {\n let originalContent = \"\";\n if (originalSystemMessage) {\n const { content } = originalSystemMessage;\n if (typeof content === \"string\") {\n originalContent = content.split(summaryPrefix)[0].trim();\n }\n }\n\n const content = originalContent\n ? `${originalContent}\\n${summaryPrefix}\\n${summary}`\n : `${summaryPrefix}\\n${summary}`;\n\n return new SystemMessage({\n content,\n id: originalSystemMessage?.id || uuid(),\n });\n}\n\n/**\n * Find safe cutoff point that preserves AI/Tool message pairs\n */\nfunction findSafeCutoff(\n messages: BaseMessage[],\n messagesToKeep: number\n): number {\n if (messages.length <= messagesToKeep) {\n return 0;\n }\n\n const targetCutoff = messages.length - messagesToKeep;\n\n for (let i = targetCutoff; i >= 0; i--) {\n if (isSafeCutoffPoint(messages, i)) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Check if cutting at index would separate AI/Tool message pairs\n */\nfunction isSafeCutoffPoint(\n messages: BaseMessage[],\n cutoffIndex: number\n): boolean {\n if (cutoffIndex >= messages.length) {\n return true;\n }\n\n const searchStart = Math.max(0, cutoffIndex - SEARCH_RANGE_FOR_TOOL_PAIRS);\n const searchEnd = Math.min(\n messages.length,\n cutoffIndex + SEARCH_RANGE_FOR_TOOL_PAIRS\n );\n\n for (let i = searchStart; i < searchEnd; i++) {\n if (!hasToolCalls(messages[i])) {\n continue;\n }\n\n const toolCallIds = extractToolCallIds(messages[i] as AIMessage);\n if (cutoffSeparatesToolPair(messages, i, cutoffIndex, toolCallIds)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if message is an AI message with tool calls\n */\nfunction hasToolCalls(message: BaseMessage): boolean {\n return (\n AIMessage.isInstance(message) &&\n \"tool_calls\" in message &&\n Array.isArray(message.tool_calls) &&\n message.tool_calls.length > 0\n );\n}\n\n/**\n * Extract tool call IDs from an AI message\n */\nfunction extractToolCallIds(aiMessage: AIMessage): Set<string> {\n const toolCallIds = new Set<string>();\n if (aiMessage.tool_calls) {\n for (const toolCall of aiMessage.tool_calls) {\n const id =\n typeof toolCall === \"object\" && \"id\" in toolCall ? toolCall.id : null;\n if (id) {\n toolCallIds.add(id);\n }\n }\n }\n return toolCallIds;\n}\n\n/**\n * Check if cutoff separates an AI message from its corresponding tool messages\n */\nfunction cutoffSeparatesToolPair(\n messages: BaseMessage[],\n aiMessageIndex: number,\n cutoffIndex: number,\n toolCallIds: Set<string>\n): boolean {\n for (let j = aiMessageIndex + 1; j < messages.length; j++) {\n const message = messages[j];\n if (\n ToolMessage.isInstance(message) &&\n toolCallIds.has(message.tool_call_id)\n ) {\n const aiBeforeCutoff = aiMessageIndex < cutoffIndex;\n const toolBeforeCutoff = j < cutoffIndex;\n if (aiBeforeCutoff !== toolBeforeCutoff) {\n return true;\n }\n }\n }\n return false;\n}\n\n/**\n * Generate summary for the given messages\n */\nasync function createSummary(\n messagesToSummarize: BaseMessage[],\n model: BaseLanguageModel,\n summaryPrompt: string,\n tokenCounter: TokenCounter\n): Promise<string> {\n if (!messagesToSummarize.length) {\n return \"No previous conversation history.\";\n }\n\n const trimmedMessages = await trimMessagesForSummary(\n messagesToSummarize,\n tokenCounter\n );\n\n if (!trimmedMessages.length) {\n return \"Previous conversation was too long to summarize.\";\n }\n\n try {\n const formattedPrompt = summaryPrompt.replace(\n \"{messages}\",\n JSON.stringify(trimmedMessages, null, 2)\n );\n const response = await model.invoke(formattedPrompt);\n const { content } = response;\n return typeof content === \"string\"\n ? content.trim()\n : \"Error generating summary: Invalid response format\";\n } catch (e) {\n return `Error generating summary: ${e}`;\n }\n}\n\n/**\n * Trim messages to fit within summary generation limits\n */\nasync function trimMessagesForSummary(\n messages: BaseMessage[],\n tokenCounter: TokenCounter\n): Promise<BaseMessage[]> {\n try {\n return await trimMessages(messages, {\n maxTokens: DEFAULT_TRIM_TOKEN_LIMIT,\n tokenCounter: async (msgs) => Promise.resolve(tokenCounter(msgs)),\n strategy: \"last\",\n allowPartial: true,\n includeSystem: true,\n });\n } catch {\n // Fallback to last N messages if trimming fails\n return messages.slice(-DEFAULT_FALLBACK_MESSAGE_COUNT);\n }\n}\n"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @param config.name - The name of the middleware
|
|
8
8
|
* @param config.stateSchema - The schema of the middleware state
|
|
9
9
|
* @param config.contextSchema - The schema of the middleware context
|
|
10
|
-
* @param config.
|
|
10
|
+
* @param config.modifyModelRequest - The function to prepare the model request
|
|
11
11
|
* @param config.beforeModel - The function to run before the model call
|
|
12
12
|
* @param config.afterModel - The function to run after the model call
|
|
13
13
|
* @returns A middleware instance
|
|
@@ -34,11 +34,14 @@ function createMiddleware(config) {
|
|
|
34
34
|
const middleware = {
|
|
35
35
|
name: config.name,
|
|
36
36
|
stateSchema: config.stateSchema,
|
|
37
|
-
contextSchema: config.contextSchema
|
|
37
|
+
contextSchema: config.contextSchema,
|
|
38
|
+
beforeModelJumpTo: config.beforeModelJumpTo,
|
|
39
|
+
afterModelJumpTo: config.afterModelJumpTo,
|
|
40
|
+
tools: config.tools ?? []
|
|
38
41
|
};
|
|
39
|
-
if (config.
|
|
40
|
-
if (config.beforeModel) middleware.beforeModel = async (state, runtime
|
|
41
|
-
if (config.afterModel) middleware.afterModel = async (state, runtime
|
|
42
|
+
if (config.modifyModelRequest) middleware.modifyModelRequest = async (options, state, runtime) => Promise.resolve(config.modifyModelRequest(options, state, runtime));
|
|
43
|
+
if (config.beforeModel) middleware.beforeModel = async (state, runtime) => Promise.resolve(config.beforeModel(state, runtime));
|
|
44
|
+
if (config.afterModel) middleware.afterModel = async (state, runtime) => Promise.resolve(config.afterModel(state, runtime));
|
|
42
45
|
return middleware;
|
|
43
46
|
}
|
|
44
47
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.cjs","names":["config: {\n name: string;\n stateSchema?: TSchema;\n contextSchema?: TContextSchema;\n prepareModelRequest?: (\n options: ModelRequest,\n state: (TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n TContextSchema extends z.ZodObject<any> ? z.infer<TContextSchema> : {}\n >\n ) => Promise<ModelRequest | void> | ModelRequest | void;\n beforeModel?: (\n state: (TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n TContextSchema extends z.ZodObject<any> ? z.infer<TContextSchema> : {}\n >,\n controls: Controls<\n (TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}) &\n AgentBuiltInState\n >\n ) =>\n | Promise<\n MiddlewareResult<\n Partial<TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}>\n >\n >\n | MiddlewareResult<\n Partial<TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}>\n >;\n afterModel?: (\n state: (TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n TContextSchema extends z.ZodObject<any> ? z.infer<TContextSchema> : {}\n >,\n controls: Controls<\n (TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}) &\n AgentBuiltInState\n >\n ) =>\n | Promise<\n MiddlewareResult<\n Partial<TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}>\n >\n >\n | MiddlewareResult<\n Partial<TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}>\n >;\n}","middleware: AgentMiddleware<TSchema, TContextSchema, any>"],"sources":["../../../src/agents/middlewareAgent/middleware.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { z } from \"zod/v3\";\nimport type {\n AgentMiddleware,\n Runtime,\n Controls,\n MiddlewareResult,\n AgentBuiltInState,\n ModelRequest,\n} from \"./types.js\";\n\n/**\n * Creates a middleware instance with automatic schema inference.\n *\n * @param config - Middleware configuration\n * @param config.name - The name of the middleware\n * @param config.stateSchema - The schema of the middleware state\n * @param config.contextSchema - The schema of the middleware context\n * @param config.prepareModelRequest - The function to prepare the model request\n * @param config.beforeModel - The function to run before the model call\n * @param config.afterModel - The function to run after the model call\n * @returns A middleware instance\n *\n * @example\n * ```ts\n * const authMiddleware = createMiddleware({\n * name: \"AuthMiddleware\",\n * stateSchema: z.object({\n * isAuthenticated: z.boolean().default(false),\n * }),\n * contextSchema: z.object({\n * userId: z.string(),\n * }),\n * beforeModel: async (state, runtime, controls) => {\n * if (!state.isAuthenticated) {\n * return controls.terminate(new Error(\"Not authenticated\"));\n * }\n * },\n * });\n * ```\n */\nexport function createMiddleware<\n TSchema extends z.ZodObject<any> | undefined = undefined,\n TContextSchema extends z.ZodObject<any> | undefined = undefined\n>(config: {\n name: string;\n stateSchema?: TSchema;\n contextSchema?: TContextSchema;\n prepareModelRequest?: (\n options: ModelRequest,\n state: (TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n TContextSchema extends z.ZodObject<any> ? z.infer<TContextSchema> : {}\n >\n ) => Promise<ModelRequest | void> | ModelRequest | void;\n beforeModel?: (\n state: (TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n TContextSchema extends z.ZodObject<any> ? z.infer<TContextSchema> : {}\n >,\n controls: Controls<\n (TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}) &\n AgentBuiltInState\n >\n ) =>\n | Promise<\n MiddlewareResult<\n Partial<TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}>\n >\n >\n | MiddlewareResult<\n Partial<TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}>\n >;\n afterModel?: (\n state: (TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n TContextSchema extends z.ZodObject<any> ? z.infer<TContextSchema> : {}\n >,\n controls: Controls<\n (TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}) &\n AgentBuiltInState\n >\n ) =>\n | Promise<\n MiddlewareResult<\n Partial<TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}>\n >\n >\n | MiddlewareResult<\n Partial<TSchema extends z.ZodObject<any> ? z.infer<TSchema> : {}>\n >;\n}): AgentMiddleware<TSchema, TContextSchema, any> {\n const middleware: AgentMiddleware<TSchema, TContextSchema, any> = {\n name: config.name,\n stateSchema: config.stateSchema,\n contextSchema: config.contextSchema,\n };\n\n if (config.prepareModelRequest) {\n middleware.prepareModelRequest = async (options, state, runtime) =>\n Promise.resolve(config.prepareModelRequest!(options, state, runtime));\n }\n\n if (config.beforeModel) {\n middleware.beforeModel = async (state, runtime, controls) =>\n Promise.resolve(config.beforeModel!(state, runtime, controls));\n }\n\n if (config.afterModel) {\n middleware.afterModel = async (state, runtime, controls) =>\n Promise.resolve(config.afterModel!(state, runtime, controls));\n }\n\n return middleware;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,SAAgB,iBAGdA,QAkDgD;CAChD,MAAMC,aAA4D;EAChE,MAAM,OAAO;EACb,aAAa,OAAO;EACpB,eAAe,OAAO;CACvB;AAED,KAAI,OAAO,qBACT,WAAW,sBAAsB,OAAO,SAAS,OAAO,YACtD,QAAQ,QAAQ,OAAO,oBAAqB,SAAS,OAAO,QAAQ,CAAC;AAGzE,KAAI,OAAO,aACT,WAAW,cAAc,OAAO,OAAO,SAAS,aAC9C,QAAQ,QAAQ,OAAO,YAAa,OAAO,SAAS,SAAS,CAAC;AAGlE,KAAI,OAAO,YACT,WAAW,aAAa,OAAO,OAAO,SAAS,aAC7C,QAAQ,QAAQ,OAAO,WAAY,OAAO,SAAS,SAAS,CAAC;AAGjE,QAAO;AACR"}
|
|
1
|
+
{"version":3,"file":"middleware.cjs","names":["config: {\n /**\n * The name of the middleware\n */\n name: string;\n /**\n * The schema of the middleware state. Middleware state is persisted between multiple invocations. It can be either:\n * - A Zod object\n * - A Zod optional object\n * - A Zod default object\n * - Undefined\n */\n stateSchema?: TSchema;\n /**\n * The schema of the middleware context. Middleware context is read-only and not persisted between multiple invocations. It can be either:\n * - A Zod object\n * - A Zod optional object\n * - A Zod default object\n * - Undefined\n */\n contextSchema?: TContextSchema;\n /**\n * Explitictly defines which targets are allowed to be jumped to from the `beforeModel` hook.\n */\n beforeModelJumpTo?: JumpToTarget[];\n /**\n * Explitictly defines which targets are allowed to be jumped to from the `afterModel` hook.\n */\n afterModelJumpTo?: JumpToTarget[];\n /**\n * Additional tools registered by the middleware.\n */\n tools?: (ClientTool | ServerTool)[];\n /**\n * The function to modify the model request. This function is called after the `beforeModel` hook of this middleware and before the model is invoked.\n * It allows to modify the model request before it is passed to the model.\n *\n * @param request - The model request\n * @param request.model - The model to use for this step.\n * @param request.messages - The messages to send to the model.\n * @param request.systemPrompt - The system message for this step.\n * @param request.toolChoice - The tool choice configuration for this step.\n * @param request.tools - The tools to make available for this step.\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified model request or undefined to pass through\n */\n modifyModelRequest?: (\n options: ModelRequest,\n state: (TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n (TSchema extends InteropZodObject ? InferInteropZodInput<TSchema> : {}) &\n AgentBuiltInState,\n TContextSchema extends InteropZodObject\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodDefault<any>\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodOptional<any>\n ? Partial<InferInteropZodOutput<TContextSchema>>\n : never\n >\n ) => Promise<ModelRequest | void> | ModelRequest | void;\n /**\n * The function to run before the model call. This function is called before the model is invoked and before the `modifyModelRequest` hook.\n * It allows to modify the state of the agent.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n beforeModel?: (\n state: (TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n (TSchema extends InteropZodObject ? InferInteropZodInput<TSchema> : {}) &\n AgentBuiltInState,\n TContextSchema extends InteropZodObject\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodDefault<any>\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodOptional<any>\n ? Partial<InferInteropZodOutput<TContextSchema>>\n : never\n >\n ) =>\n | Promise<\n MiddlewareResult<\n Partial<\n TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}\n >\n >\n >\n | MiddlewareResult<\n Partial<\n TSchema extends InteropZodObject ? InferInteropZodInput<TSchema> : {}\n >\n >;\n /**\n * The function to run after the model call. This function is called after the model is invoked and before any tools are called.\n * It allows to modify the state of the agent after the model is invoked, e.g. to update tool call parameters.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n afterModel?: (\n state: (TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n (TSchema extends InteropZodObject ? InferInteropZodInput<TSchema> : {}) &\n AgentBuiltInState,\n TContextSchema extends InteropZodObject\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodDefault<any>\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodOptional<any>\n ? Partial<InferInteropZodOutput<TContextSchema>>\n : never\n >\n ) =>\n | Promise<\n MiddlewareResult<\n Partial<\n TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}\n >\n >\n >\n | MiddlewareResult<\n Partial<\n TSchema extends InteropZodObject ? InferInteropZodInput<TSchema> : {}\n >\n >;\n}","middleware: AgentMiddleware<TSchema, TContextSchema, any>"],"sources":["../../../src/agents/middlewareAgent/middleware.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type {\n InteropZodObject,\n InteropZodDefault,\n InteropZodOptional,\n InferInteropZodInput,\n InferInteropZodOutput,\n} from \"@langchain/core/utils/types\";\nimport type {\n AgentMiddleware,\n Runtime,\n MiddlewareResult,\n AgentBuiltInState,\n ModelRequest,\n JumpToTarget,\n} from \"./types.js\";\nimport type { ClientTool, ServerTool } from \"../types.js\";\n\n/**\n * Creates a middleware instance with automatic schema inference.\n *\n * @param config - Middleware configuration\n * @param config.name - The name of the middleware\n * @param config.stateSchema - The schema of the middleware state\n * @param config.contextSchema - The schema of the middleware context\n * @param config.modifyModelRequest - The function to prepare the model request\n * @param config.beforeModel - The function to run before the model call\n * @param config.afterModel - The function to run after the model call\n * @returns A middleware instance\n *\n * @example\n * ```ts\n * const authMiddleware = createMiddleware({\n * name: \"AuthMiddleware\",\n * stateSchema: z.object({\n * isAuthenticated: z.boolean().default(false),\n * }),\n * contextSchema: z.object({\n * userId: z.string(),\n * }),\n * beforeModel: async (state, runtime, controls) => {\n * if (!state.isAuthenticated) {\n * return controls.terminate(new Error(\"Not authenticated\"));\n * }\n * },\n * });\n * ```\n */\nexport function createMiddleware<\n TSchema extends InteropZodObject | undefined = undefined,\n TContextSchema extends\n | InteropZodObject\n | InteropZodOptional<InteropZodObject>\n | InteropZodDefault<InteropZodObject>\n | undefined = undefined\n>(config: {\n /**\n * The name of the middleware\n */\n name: string;\n /**\n * The schema of the middleware state. Middleware state is persisted between multiple invocations. It can be either:\n * - A Zod object\n * - A Zod optional object\n * - A Zod default object\n * - Undefined\n */\n stateSchema?: TSchema;\n /**\n * The schema of the middleware context. Middleware context is read-only and not persisted between multiple invocations. It can be either:\n * - A Zod object\n * - A Zod optional object\n * - A Zod default object\n * - Undefined\n */\n contextSchema?: TContextSchema;\n /**\n * Explitictly defines which targets are allowed to be jumped to from the `beforeModel` hook.\n */\n beforeModelJumpTo?: JumpToTarget[];\n /**\n * Explitictly defines which targets are allowed to be jumped to from the `afterModel` hook.\n */\n afterModelJumpTo?: JumpToTarget[];\n /**\n * Additional tools registered by the middleware.\n */\n tools?: (ClientTool | ServerTool)[];\n /**\n * The function to modify the model request. This function is called after the `beforeModel` hook of this middleware and before the model is invoked.\n * It allows to modify the model request before it is passed to the model.\n *\n * @param request - The model request\n * @param request.model - The model to use for this step.\n * @param request.messages - The messages to send to the model.\n * @param request.systemPrompt - The system message for this step.\n * @param request.toolChoice - The tool choice configuration for this step.\n * @param request.tools - The tools to make available for this step.\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified model request or undefined to pass through\n */\n modifyModelRequest?: (\n options: ModelRequest,\n state: (TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n (TSchema extends InteropZodObject ? InferInteropZodInput<TSchema> : {}) &\n AgentBuiltInState,\n TContextSchema extends InteropZodObject\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodDefault<any>\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodOptional<any>\n ? Partial<InferInteropZodOutput<TContextSchema>>\n : never\n >\n ) => Promise<ModelRequest | void> | ModelRequest | void;\n /**\n * The function to run before the model call. This function is called before the model is invoked and before the `modifyModelRequest` hook.\n * It allows to modify the state of the agent.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n beforeModel?: (\n state: (TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n (TSchema extends InteropZodObject ? InferInteropZodInput<TSchema> : {}) &\n AgentBuiltInState,\n TContextSchema extends InteropZodObject\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodDefault<any>\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodOptional<any>\n ? Partial<InferInteropZodOutput<TContextSchema>>\n : never\n >\n ) =>\n | Promise<\n MiddlewareResult<\n Partial<\n TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}\n >\n >\n >\n | MiddlewareResult<\n Partial<\n TSchema extends InteropZodObject ? InferInteropZodInput<TSchema> : {}\n >\n >;\n /**\n * The function to run after the model call. This function is called after the model is invoked and before any tools are called.\n * It allows to modify the state of the agent after the model is invoked, e.g. to update tool call parameters.\n *\n * @param state - The middleware state\n * @param runtime - The middleware runtime\n * @returns The modified middleware state or undefined to pass through\n */\n afterModel?: (\n state: (TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}) &\n AgentBuiltInState,\n runtime: Runtime<\n (TSchema extends InteropZodObject ? InferInteropZodInput<TSchema> : {}) &\n AgentBuiltInState,\n TContextSchema extends InteropZodObject\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodDefault<any>\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodOptional<any>\n ? Partial<InferInteropZodOutput<TContextSchema>>\n : never\n >\n ) =>\n | Promise<\n MiddlewareResult<\n Partial<\n TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}\n >\n >\n >\n | MiddlewareResult<\n Partial<\n TSchema extends InteropZodObject ? InferInteropZodInput<TSchema> : {}\n >\n >;\n}): AgentMiddleware<TSchema, TContextSchema, any> {\n const middleware: AgentMiddleware<TSchema, TContextSchema, any> = {\n name: config.name,\n stateSchema: config.stateSchema,\n contextSchema: config.contextSchema,\n beforeModelJumpTo: config.beforeModelJumpTo,\n afterModelJumpTo: config.afterModelJumpTo,\n tools: config.tools ?? [],\n };\n\n if (config.modifyModelRequest) {\n middleware.modifyModelRequest = async (options, state, runtime) =>\n Promise.resolve(\n config.modifyModelRequest!(\n options,\n state,\n runtime as Runtime<\n (TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}) &\n AgentBuiltInState,\n TContextSchema extends InteropZodObject\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodDefault<any>\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodOptional<any>\n ? Partial<InferInteropZodOutput<TContextSchema>>\n : never\n >\n )\n );\n }\n\n if (config.beforeModel) {\n middleware.beforeModel = async (state, runtime) =>\n Promise.resolve(\n config.beforeModel!(\n state,\n runtime as Runtime<\n (TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}) &\n AgentBuiltInState,\n TContextSchema extends InteropZodObject\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodDefault<any>\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodOptional<any>\n ? Partial<InferInteropZodOutput<TContextSchema>>\n : never\n >\n )\n );\n }\n\n if (config.afterModel) {\n middleware.afterModel = async (state, runtime) =>\n Promise.resolve(\n config.afterModel!(\n state,\n runtime as Runtime<\n (TSchema extends InteropZodObject\n ? InferInteropZodInput<TSchema>\n : {}) &\n AgentBuiltInState,\n TContextSchema extends InteropZodObject\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodDefault<any>\n ? InferInteropZodOutput<TContextSchema>\n : TContextSchema extends InteropZodOptional<any>\n ? Partial<InferInteropZodOutput<TContextSchema>>\n : never\n >\n )\n );\n }\n\n return middleware;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,SAAgB,iBAOdA,QA+IgD;CAChD,MAAMC,aAA4D;EAChE,MAAM,OAAO;EACb,aAAa,OAAO;EACpB,eAAe,OAAO;EACtB,mBAAmB,OAAO;EAC1B,kBAAkB,OAAO;EACzB,OAAO,OAAO,SAAS,CAAE;CAC1B;AAED,KAAI,OAAO,oBACT,WAAW,qBAAqB,OAAO,SAAS,OAAO,YACrD,QAAQ,QACN,OAAO,mBACL,SACA,OACA,QAaD,CACF;AAGL,KAAI,OAAO,aACT,WAAW,cAAc,OAAO,OAAO,YACrC,QAAQ,QACN,OAAO,YACL,OACA,QAaD,CACF;AAGL,KAAI,OAAO,YACT,WAAW,aAAa,OAAO,OAAO,YACpC,QAAQ,QACN,OAAO,WACL,OACA,QAaD,CACF;AAGL,QAAO;AACR"}
|