langchain 1.2.37 → 1.2.38
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/CHANGELOG.md +11 -0
- package/dist/agents/middleware/summarization.cjs +1 -1
- package/dist/agents/middleware/summarization.js +21 -21
- package/dist/agents/middleware/summarization.js.map +1 -1
- package/dist/agents/middleware/toolCallLimit.cjs +1 -1
- package/dist/agents/middleware/toolCallLimit.js +11 -11
- package/dist/agents/middleware/toolCallLimit.js.map +1 -1
- package/dist/agents/nodes/utils.cjs +10 -10
- package/dist/agents/nodes/utils.cjs.map +1 -1
- package/dist/agents/nodes/utils.js +3 -3
- package/dist/agents/nodes/utils.js.map +1 -1
- package/dist/browser.cjs +106 -0
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +29 -1
- package/dist/browser.d.ts +29 -1
- package/dist/browser.js +66 -1
- package/dist/browser.js.map +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# langchain
|
|
2
2
|
|
|
3
|
+
## 1.2.38
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#10527](https://github.com/langchain-ai/langchainjs/pull/10527) [`3408008`](https://github.com/langchain-ai/langchainjs/commit/3408008fe59eb8ee72f733349ae85afe5c23eaca) Thanks [@pawel-twardziak](https://github.com/pawel-twardziak)! - fix(langchain): export createAgent and prebuilt middleware from browser entry point
|
|
8
|
+
|
|
9
|
+
- [#10545](https://github.com/langchain-ai/langchainjs/pull/10545) [`68e0a19`](https://github.com/langchain-ai/langchainjs/commit/68e0a19238be592514b6c01243c41aefaa6a7668) Thanks [@JadenKim-dev](https://github.com/JadenKim-dev)! - fix(langchain): revert zod import in utils.ts to fix v3/v4 interop
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`6933769`](https://github.com/langchain-ai/langchainjs/commit/6933769836fe3cec835588e5f8db9883200865f6), [`50d5f32`](https://github.com/langchain-ai/langchainjs/commit/50d5f32fd30cabebf058b1c13255c1daadde6107), [`5552999`](https://github.com/langchain-ai/langchainjs/commit/555299917c90322e25d7671bad2e20c9b104bad6), [`8331833`](https://github.com/langchain-ai/langchainjs/commit/8331833c93ba907063c9fe28e9f935ed5dfec11c)]:
|
|
12
|
+
- @langchain/core@1.1.37
|
|
13
|
+
|
|
3
14
|
## 1.2.37
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
|
@@ -7,8 +7,8 @@ let _langchain_core_messages = require("@langchain/core/messages");
|
|
|
7
7
|
let _langchain_core_runnables = require("@langchain/core/runnables");
|
|
8
8
|
let _langchain_langgraph = require("@langchain/langgraph");
|
|
9
9
|
let _langchain_core_utils_types = require("@langchain/core/utils/types");
|
|
10
|
-
let zod_v3 = require("zod/v3");
|
|
11
10
|
let zod_v4 = require("zod/v4");
|
|
11
|
+
let zod_v3 = require("zod/v3");
|
|
12
12
|
let uuid = require("uuid");
|
|
13
13
|
let _langchain_core_language_models_base = require("@langchain/core/language_models/base");
|
|
14
14
|
//#region src/agents/middleware/summarization.ts
|
|
@@ -6,8 +6,8 @@ import { AIMessage, HumanMessage, RemoveMessage, SystemMessage, ToolMessage, get
|
|
|
6
6
|
import { mergeConfigs, pickRunnableConfigKeys } from "@langchain/core/runnables";
|
|
7
7
|
import { REMOVE_ALL_MESSAGES } from "@langchain/langgraph";
|
|
8
8
|
import { interopSafeParse } from "@langchain/core/utils/types";
|
|
9
|
-
import { z } from "zod/
|
|
10
|
-
import { z as z$1 } from "zod/
|
|
9
|
+
import { z } from "zod/v4";
|
|
10
|
+
import { z as z$1 } from "zod/v3";
|
|
11
11
|
import { v4 } from "uuid";
|
|
12
12
|
import { getModelContextSize } from "@langchain/core/language_models/base";
|
|
13
13
|
//#region src/agents/middleware/summarization.ts
|
|
@@ -43,11 +43,11 @@ const DEFAULT_MESSAGES_TO_KEEP = 20;
|
|
|
43
43
|
const DEFAULT_TRIM_TOKEN_LIMIT = 4e3;
|
|
44
44
|
const DEFAULT_FALLBACK_MESSAGE_COUNT = 15;
|
|
45
45
|
const SEARCH_RANGE_FOR_TOOL_PAIRS = 5;
|
|
46
|
-
const tokenCounterSchema = z.function().args(z.array(z.custom())).returns(z.union([z.number(), z.promise(z.number())]));
|
|
47
|
-
const contextSizeSchema = z.object({
|
|
48
|
-
fraction: z.number().gt(0, "Fraction must be greater than 0").max(1, "Fraction must be less than or equal to 1").optional(),
|
|
49
|
-
tokens: z.number().positive("Tokens must be greater than 0").optional(),
|
|
50
|
-
messages: z.number().int("Messages must be an integer").positive("Messages must be greater than 0").optional()
|
|
46
|
+
const tokenCounterSchema = z$1.function().args(z$1.array(z$1.custom())).returns(z$1.union([z$1.number(), z$1.promise(z$1.number())]));
|
|
47
|
+
const contextSizeSchema = z$1.object({
|
|
48
|
+
fraction: z$1.number().gt(0, "Fraction must be greater than 0").max(1, "Fraction must be less than or equal to 1").optional(),
|
|
49
|
+
tokens: z$1.number().positive("Tokens must be greater than 0").optional(),
|
|
50
|
+
messages: z$1.number().int("Messages must be an integer").positive("Messages must be greater than 0").optional()
|
|
51
51
|
}).refine((data) => {
|
|
52
52
|
return [
|
|
53
53
|
data.fraction,
|
|
@@ -55,10 +55,10 @@ const contextSizeSchema = z.object({
|
|
|
55
55
|
data.messages
|
|
56
56
|
].filter((v) => v !== void 0).length >= 1;
|
|
57
57
|
}, { message: "At least one of fraction, tokens, or messages must be provided" });
|
|
58
|
-
const keepSchema = z.object({
|
|
59
|
-
fraction: z.number().min(0, "Messages must be non-negative").max(1, "Fraction must be less than or equal to 1").optional(),
|
|
60
|
-
tokens: z.number().min(0, "Tokens must be greater than or equal to 0").optional(),
|
|
61
|
-
messages: z.number().int("Messages must be an integer").min(0, "Messages must be non-negative").optional()
|
|
58
|
+
const keepSchema = z$1.object({
|
|
59
|
+
fraction: z$1.number().min(0, "Messages must be non-negative").max(1, "Fraction must be less than or equal to 1").optional(),
|
|
60
|
+
tokens: z$1.number().min(0, "Tokens must be greater than or equal to 0").optional(),
|
|
61
|
+
messages: z$1.number().int("Messages must be an integer").min(0, "Messages must be non-negative").optional()
|
|
62
62
|
}).refine((data) => {
|
|
63
63
|
return [
|
|
64
64
|
data.fraction,
|
|
@@ -66,16 +66,16 @@ const keepSchema = z.object({
|
|
|
66
66
|
data.messages
|
|
67
67
|
].filter((v) => v !== void 0).length === 1;
|
|
68
68
|
}, { message: "Exactly one of fraction, tokens, or messages must be provided" });
|
|
69
|
-
const contextSchema = z.object({
|
|
70
|
-
model: z.custom(),
|
|
71
|
-
trigger: z.union([contextSizeSchema, z.array(contextSizeSchema)]).optional(),
|
|
69
|
+
const contextSchema = z$1.object({
|
|
70
|
+
model: z$1.custom(),
|
|
71
|
+
trigger: z$1.union([contextSizeSchema, z$1.array(contextSizeSchema)]).optional(),
|
|
72
72
|
keep: keepSchema.optional(),
|
|
73
73
|
tokenCounter: tokenCounterSchema.optional(),
|
|
74
|
-
summaryPrompt: z.string().default(DEFAULT_SUMMARY_PROMPT),
|
|
75
|
-
trimTokensToSummarize: z.number().optional(),
|
|
76
|
-
summaryPrefix: z.string().optional(),
|
|
77
|
-
maxTokensBeforeSummary: z.number().optional(),
|
|
78
|
-
messagesToKeep: z.number().optional()
|
|
74
|
+
summaryPrompt: z$1.string().default(DEFAULT_SUMMARY_PROMPT),
|
|
75
|
+
trimTokensToSummarize: z$1.number().optional(),
|
|
76
|
+
summaryPrefix: z$1.string().optional(),
|
|
77
|
+
maxTokensBeforeSummary: z$1.number().optional(),
|
|
78
|
+
messagesToKeep: z$1.number().optional()
|
|
79
79
|
});
|
|
80
80
|
/**
|
|
81
81
|
* Get max input tokens from model profile or fallback to model name lookup
|
|
@@ -136,10 +136,10 @@ function summarizationMiddleware(options) {
|
|
|
136
136
|
* Parse user options to get their explicit values
|
|
137
137
|
*/
|
|
138
138
|
const { data: userOptions, error } = interopSafeParse(contextSchema, options);
|
|
139
|
-
if (error) throw new Error(`Invalid summarization middleware options: ${z
|
|
139
|
+
if (error) throw new Error(`Invalid summarization middleware options: ${z.prettifyError(error)}`);
|
|
140
140
|
return createMiddleware({
|
|
141
141
|
name: "SummarizationMiddleware",
|
|
142
|
-
contextSchema: contextSchema.extend({ model: z.custom().optional() }),
|
|
142
|
+
contextSchema: contextSchema.extend({ model: z$1.custom().optional() }),
|
|
143
143
|
beforeModel: async (state, runtime) => {
|
|
144
144
|
let trigger = userOptions.trigger;
|
|
145
145
|
let keep = userOptions.keep;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarization.js","names":["z4","uuid"],"sources":["../../../src/agents/middleware/summarization.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport { z as z4 } from \"zod/v4\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n BaseMessage,\n AIMessage,\n SystemMessage,\n ToolMessage,\n RemoveMessage,\n trimMessages,\n HumanMessage,\n getBufferString,\n} from \"@langchain/core/messages\";\nimport {\n BaseLanguageModel,\n getModelContextSize,\n} from \"@langchain/core/language_models/base\";\nimport {\n interopSafeParse,\n InferInteropZodInput,\n InferInteropZodOutput,\n} from \"@langchain/core/utils/types\";\nimport {\n mergeConfigs,\n pickRunnableConfigKeys,\n type RunnableConfig,\n} from \"@langchain/core/runnables\";\nimport { REMOVE_ALL_MESSAGES } from \"@langchain/langgraph\";\nimport { createMiddleware } from \"../middleware.js\";\nimport { countTokensApproximately } from \"./utils.js\";\nimport { hasToolCalls } from \"../utils.js\";\nimport { initChatModel } from \"../../chat_models/universal.js\";\nimport type { Runtime } from \"../runtime.js\";\n\nexport const 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 DEFAULT_SUMMARY_PREFIX = \"Here is a summary of the conversation to date:\";\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\nconst tokenCounterSchema = z\n .function()\n .args(z.array(z.custom<BaseMessage>()))\n .returns(z.union([z.number(), z.promise(z.number())]));\nexport type TokenCounter = (\n messages: BaseMessage[]\n) => number | Promise<number>;\n\nexport const contextSizeSchema = z\n .object({\n /**\n * Fraction of the model's context size to use as the trigger\n */\n fraction: z\n .number()\n .gt(0, \"Fraction must be greater than 0\")\n .max(1, \"Fraction must be less than or equal to 1\")\n .optional(),\n /**\n * Number of tokens to use as the trigger\n */\n tokens: z.number().positive(\"Tokens must be greater than 0\").optional(),\n /**\n * Number of messages to use as the trigger\n */\n messages: z\n .number()\n .int(\"Messages must be an integer\")\n .positive(\"Messages must be greater than 0\")\n .optional(),\n })\n .refine(\n (data) => {\n const count = [data.fraction, data.tokens, data.messages].filter(\n (v) => v !== undefined\n ).length;\n return count >= 1;\n },\n {\n message: \"At least one of fraction, tokens, or messages must be provided\",\n }\n );\nexport type ContextSize = z.infer<typeof contextSizeSchema>;\n\nexport const keepSchema = z\n .object({\n /**\n * Fraction of the model's context size to keep\n */\n fraction: z\n .number()\n .min(0, \"Messages must be non-negative\")\n .max(1, \"Fraction must be less than or equal to 1\")\n .optional(),\n /**\n * Number of tokens to keep\n */\n tokens: z\n .number()\n .min(0, \"Tokens must be greater than or equal to 0\")\n .optional(),\n messages: z\n .number()\n .int(\"Messages must be an integer\")\n .min(0, \"Messages must be non-negative\")\n .optional(),\n })\n .refine(\n (data) => {\n const count = [data.fraction, data.tokens, data.messages].filter(\n (v) => v !== undefined\n ).length;\n return count === 1;\n },\n {\n message: \"Exactly one of fraction, tokens, or messages must be provided\",\n }\n );\nexport type KeepSize = z.infer<typeof keepSchema>;\n\nconst contextSchema = z.object({\n /**\n * Model to use for summarization\n */\n model: z.custom<string | BaseLanguageModel>(),\n /**\n * Trigger conditions for summarization.\n * Can be a single condition object (all properties must be met) or an array of conditions (any condition must be met).\n *\n * @example\n * ```ts\n * // Single condition: trigger if tokens >= 5000 AND messages >= 3\n * trigger: { tokens: 5000, messages: 3 }\n *\n * // Multiple conditions: trigger if (tokens >= 5000 AND messages >= 3) OR (tokens >= 3000 AND messages >= 6)\n * trigger: [\n * { tokens: 5000, messages: 3 },\n * { tokens: 3000, messages: 6 }\n * ]\n * ```\n */\n trigger: z.union([contextSizeSchema, z.array(contextSizeSchema)]).optional(),\n /**\n * Keep conditions for summarization\n */\n keep: keepSchema.optional(),\n /**\n * Token counter function to use for summarization\n */\n tokenCounter: tokenCounterSchema.optional(),\n /**\n * Summary prompt to use for summarization\n * @default {@link DEFAULT_SUMMARY_PROMPT}\n */\n summaryPrompt: z.string().default(DEFAULT_SUMMARY_PROMPT),\n /**\n * Number of tokens to trim to before summarizing\n */\n trimTokensToSummarize: z.number().optional(),\n /**\n * Prefix to add to the summary\n */\n summaryPrefix: z.string().optional(),\n /**\n * @deprecated Use `trigger: { tokens: value }` instead.\n */\n maxTokensBeforeSummary: z.number().optional(),\n /**\n * @deprecated Use `keep: { messages: value }` instead.\n */\n messagesToKeep: z.number().optional(),\n});\n\nexport type SummarizationMiddlewareConfig = InferInteropZodInput<\n typeof contextSchema\n>;\n\n/**\n * Get max input tokens from model profile or fallback to model name lookup\n */\nexport function getProfileLimits(input: BaseLanguageModel): number | undefined {\n // Access maxInputTokens on the model profile directly if available\n if (\n \"profile\" in input &&\n typeof input.profile === \"object\" &&\n input.profile &&\n \"maxInputTokens\" in input.profile &&\n (typeof input.profile.maxInputTokens === \"number\" ||\n input.profile.maxInputTokens == null)\n ) {\n return input.profile.maxInputTokens ?? undefined;\n }\n\n // Fallback to using model name if available\n if (\"model\" in input && typeof input.model === \"string\") {\n return getModelContextSize(input.model);\n }\n if (\"modelName\" in input && typeof input.modelName === \"string\") {\n return getModelContextSize(input.modelName);\n }\n\n return undefined;\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\";\n * import { createAgent } from \"langchain\";\n *\n * // Single condition: trigger if tokens >= 4000 AND messages >= 10\n * const agent1 = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * trigger: { tokens: 4000, messages: 10 },\n * keep: { messages: 20 },\n * })\n * ],\n * });\n *\n * // Multiple conditions: trigger if (tokens >= 5000 AND messages >= 3) OR (tokens >= 3000 AND messages >= 6)\n * const agent2 = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * trigger: [\n * { tokens: 5000, messages: 3 },\n * { tokens: 3000, messages: 6 },\n * ],\n * keep: { messages: 20 },\n * })\n * ],\n * });\n *\n * ```\n */\nexport function summarizationMiddleware(\n options: SummarizationMiddlewareConfig\n) {\n /**\n * Parse user options to get their explicit values\n */\n const { data: userOptions, error } = interopSafeParse(contextSchema, options);\n if (error) {\n throw new Error(\n `Invalid summarization middleware options: ${z4.prettifyError(error)}`\n );\n }\n\n return createMiddleware({\n name: \"SummarizationMiddleware\",\n contextSchema: contextSchema.extend({\n /**\n * `model` should be required when initializing the middleware,\n * but can be omitted within context when invoking the middleware.\n */\n model: z.custom<BaseLanguageModel>().optional(),\n }),\n beforeModel: async (state, runtime) => {\n let trigger: ContextSize | ContextSize[] | undefined =\n userOptions.trigger;\n let keep: ContextSize = userOptions.keep as InferInteropZodOutput<\n typeof keepSchema\n >;\n\n /**\n * Handle deprecated parameters\n */\n if (userOptions.maxTokensBeforeSummary !== undefined) {\n console.warn(\n \"maxTokensBeforeSummary is deprecated. Use `trigger: { tokens: value }` instead.\"\n );\n if (trigger === undefined) {\n trigger = { tokens: userOptions.maxTokensBeforeSummary };\n }\n }\n\n /**\n * Handle deprecated parameters\n */\n if (userOptions.messagesToKeep !== undefined) {\n console.warn(\n \"messagesToKeep is deprecated. Use `keep: { messages: value }` instead.\"\n );\n if (\n !keep ||\n (keep &&\n \"messages\" in keep &&\n keep.messages === DEFAULT_MESSAGES_TO_KEEP)\n ) {\n keep = { messages: userOptions.messagesToKeep };\n }\n }\n\n /**\n * Merge context with user options\n */\n const resolvedTrigger =\n runtime.context?.trigger !== undefined\n ? runtime.context.trigger\n : trigger;\n const resolvedKeep =\n runtime.context?.keep !== undefined\n ? runtime.context.keep\n : (keep ?? { messages: DEFAULT_MESSAGES_TO_KEEP });\n\n const validatedKeep = keepSchema.parse(resolvedKeep);\n\n /**\n * Validate trigger conditions\n */\n let triggerConditions: ContextSize[] = [];\n if (resolvedTrigger === undefined) {\n triggerConditions = [];\n } else if (Array.isArray(resolvedTrigger)) {\n /**\n * It's an array of ContextSize objects\n */\n triggerConditions = (resolvedTrigger as ContextSize[]).map((t) =>\n contextSizeSchema.parse(t)\n );\n } else {\n /**\n * Single ContextSize object - all properties must be satisfied (AND logic)\n */\n triggerConditions = [contextSizeSchema.parse(resolvedTrigger)];\n }\n\n /**\n * Check if profile is required\n */\n const requiresProfile =\n triggerConditions.some((c) => \"fraction\" in c) ||\n \"fraction\" in validatedKeep;\n\n const model =\n typeof userOptions.model === \"string\"\n ? await initChatModel(userOptions.model)\n : userOptions.model;\n\n if (requiresProfile && !getProfileLimits(model)) {\n throw new Error(\n \"Model profile information is required to use fractional token limits. \" +\n \"Use absolute token counts instead.\"\n );\n }\n\n const summaryPrompt =\n runtime.context?.summaryPrompt === DEFAULT_SUMMARY_PROMPT\n ? (userOptions.summaryPrompt ?? DEFAULT_SUMMARY_PROMPT)\n : (runtime.context?.summaryPrompt ??\n userOptions.summaryPrompt ??\n DEFAULT_SUMMARY_PROMPT);\n const summaryPrefix =\n runtime.context.summaryPrefix ??\n userOptions.summaryPrefix ??\n DEFAULT_SUMMARY_PREFIX;\n const trimTokensToSummarize =\n runtime.context?.trimTokensToSummarize !== undefined\n ? runtime.context.trimTokensToSummarize\n : (userOptions.trimTokensToSummarize ?? DEFAULT_TRIM_TOKEN_LIMIT);\n\n /**\n * Ensure all messages have IDs\n */\n ensureMessageIds(state.messages);\n\n const tokenCounter =\n runtime.context?.tokenCounter !== undefined\n ? runtime.context.tokenCounter\n : (userOptions.tokenCounter ?? countTokensApproximately);\n const totalTokens = await tokenCounter(state.messages);\n const doSummarize = await shouldSummarize(\n state.messages,\n totalTokens,\n triggerConditions,\n model\n );\n\n if (!doSummarize) {\n return;\n }\n\n const { systemPrompt, conversationMessages } = splitSystemMessage(\n state.messages\n );\n const cutoffIndex = await determineCutoffIndex(\n conversationMessages,\n validatedKeep,\n tokenCounter,\n model\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 model,\n summaryPrompt,\n tokenCounter,\n trimTokensToSummarize,\n runtime\n );\n\n const summaryMessage = new HumanMessage({\n content: `${summaryPrefix}\\n\\n${summary}`,\n id: uuid(),\n additional_kwargs: { lc_source: \"summarization\" },\n });\n\n return {\n messages: [\n new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),\n summaryMessage,\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;\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 conversationMessages: messages,\n };\n}\n\n/**\n * Partition messages into those to summarize and those to preserve\n */\nfunction partitionMessages(\n systemPrompt: SystemMessage | undefined,\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 * Determine whether summarization should run for the current token usage\n *\n * @param messages - Current messages in the conversation\n * @param totalTokens - Total token count for all messages\n * @param triggerConditions - Array of trigger conditions. Returns true if ANY condition is satisfied (OR logic).\n * Within each condition, ALL specified properties must be satisfied (AND logic).\n * @param model - The language model being used\n * @returns true if summarization should be triggered\n */\nasync function shouldSummarize(\n messages: BaseMessage[],\n totalTokens: number,\n triggerConditions: ContextSize[],\n model: BaseLanguageModel\n): Promise<boolean> {\n if (triggerConditions.length === 0) {\n return false;\n }\n\n /**\n * Check each condition (OR logic between conditions)\n */\n for (const trigger of triggerConditions) {\n /**\n * Within a single condition, all specified properties must be satisfied (AND logic)\n */\n let conditionMet = true;\n let hasAnyProperty = false;\n\n if (trigger.messages !== undefined) {\n hasAnyProperty = true;\n if (messages.length < trigger.messages) {\n conditionMet = false;\n }\n }\n\n if (trigger.tokens !== undefined) {\n hasAnyProperty = true;\n if (totalTokens < trigger.tokens) {\n conditionMet = false;\n }\n }\n\n if (trigger.fraction !== undefined) {\n hasAnyProperty = true;\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens === \"number\") {\n const threshold = Math.floor(maxInputTokens * trigger.fraction);\n if (totalTokens < threshold) {\n conditionMet = false;\n }\n } else {\n /**\n * If fraction is specified but we can't get model limits, skip this condition\n */\n conditionMet = false;\n }\n }\n\n /**\n * If condition has at least one property and all properties are satisfied, trigger summarization\n */\n if (hasAnyProperty && conditionMet) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Determine cutoff index respecting retention configuration\n */\nasync function determineCutoffIndex(\n messages: BaseMessage[],\n keep: ContextSize,\n tokenCounter: TokenCounter,\n model: BaseLanguageModel\n): Promise<number> {\n if (\"tokens\" in keep || \"fraction\" in keep) {\n const tokenBasedCutoff = await findTokenBasedCutoff(\n messages,\n keep,\n tokenCounter,\n model\n );\n if (typeof tokenBasedCutoff === \"number\") {\n return tokenBasedCutoff;\n }\n /**\n * Fallback to message count if token-based fails\n */\n return findSafeCutoff(messages, DEFAULT_MESSAGES_TO_KEEP);\n }\n /**\n * find cutoff index based on message count\n */\n return findSafeCutoff(messages, keep.messages ?? DEFAULT_MESSAGES_TO_KEEP);\n}\n\n/**\n * Find cutoff index based on target token retention\n */\nasync function findTokenBasedCutoff(\n messages: BaseMessage[],\n keep: ContextSize,\n tokenCounter: TokenCounter,\n model: BaseLanguageModel\n): Promise<number | undefined> {\n if (messages.length === 0) {\n return 0;\n }\n\n let targetTokenCount: number;\n\n if (\"fraction\" in keep && keep.fraction !== undefined) {\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens !== \"number\") {\n return;\n }\n targetTokenCount = Math.floor(maxInputTokens * keep.fraction);\n } else if (\"tokens\" in keep && keep.tokens !== undefined) {\n targetTokenCount = Math.floor(keep.tokens);\n } else {\n return;\n }\n\n if (targetTokenCount <= 0) {\n targetTokenCount = 1;\n }\n\n const totalTokens = await tokenCounter(messages);\n if (totalTokens <= targetTokenCount) {\n return 0;\n }\n\n /**\n * Use binary search to identify the earliest message index that keeps the\n * suffix within the token budget.\n */\n let left = 0;\n let right = messages.length;\n let cutoffCandidate = messages.length;\n const maxIterations = Math.floor(Math.log2(messages.length)) + 1;\n\n for (let i = 0; i < maxIterations; i++) {\n if (left >= right) {\n break;\n }\n\n const mid = Math.floor((left + right) / 2);\n const suffixTokens = await tokenCounter(messages.slice(mid));\n if (suffixTokens <= targetTokenCount) {\n cutoffCandidate = mid;\n right = mid;\n } else {\n left = mid + 1;\n }\n }\n\n if (cutoffCandidate === messages.length) {\n cutoffCandidate = left;\n }\n\n if (cutoffCandidate >= messages.length) {\n if (messages.length === 1) {\n return 0;\n }\n cutoffCandidate = messages.length - 1;\n }\n\n /**\n * Find safe cutoff point that preserves AI/Tool pairs.\n * If cutoff lands on ToolMessage, move backward to include the AIMessage.\n */\n const safeCutoff = findSafeCutoffPoint(messages, cutoffCandidate);\n\n /**\n * If findSafeCutoffPoint moved forward (fallback case), verify it's safe.\n * If it moved backward, we already have a safe point.\n */\n if (safeCutoff <= cutoffCandidate) {\n return safeCutoff;\n }\n\n /**\n * Fallback: iterate backward to find a safe cutoff\n */\n for (let i = cutoffCandidate; i >= 0; i--) {\n if (isSafeCutoffPoint(messages, i)) {\n return i;\n }\n }\n\n return 0;\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 /**\n * First, try to find a safe cutoff point using findSafeCutoffPoint.\n * This handles the case where cutoff lands on a ToolMessage by moving\n * backward to include the corresponding AIMessage.\n */\n const safeCutoff = findSafeCutoffPoint(messages, targetCutoff);\n\n /**\n * If findSafeCutoffPoint moved backward (found matching AIMessage), use it.\n */\n if (safeCutoff <= targetCutoff) {\n return safeCutoff;\n }\n\n /**\n * Fallback: iterate backward to find a safe cutoff\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 /**\n * Prevent preserved messages from starting with AI message containing tool calls\n */\n if (\n cutoffIndex < messages.length &&\n AIMessage.isInstance(messages[cutoffIndex]) &&\n hasToolCalls(messages[cutoffIndex])\n ) {\n return false;\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 * 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 * Find a safe cutoff point that doesn't split AI/Tool message pairs.\n *\n * If the message at `cutoffIndex` is a `ToolMessage`, search backward for the\n * `AIMessage` containing the corresponding `tool_calls` and adjust the cutoff to\n * include it. This ensures tool call requests and responses stay together.\n *\n * Falls back to advancing forward past `ToolMessage` objects only if no matching\n * `AIMessage` is found (edge case).\n */\nfunction findSafeCutoffPoint(\n messages: BaseMessage[],\n cutoffIndex: number\n): number {\n if (\n cutoffIndex >= messages.length ||\n !ToolMessage.isInstance(messages[cutoffIndex])\n ) {\n return cutoffIndex;\n }\n\n // Collect tool_call_ids from consecutive ToolMessages at/after cutoff\n const toolCallIds = new Set<string>();\n let idx = cutoffIndex;\n while (idx < messages.length && ToolMessage.isInstance(messages[idx])) {\n const toolMsg = messages[idx] as ToolMessage;\n if (toolMsg.tool_call_id) {\n toolCallIds.add(toolMsg.tool_call_id);\n }\n idx++;\n }\n\n // Search backward for AIMessage with matching tool_calls\n for (let i = cutoffIndex - 1; i >= 0; i--) {\n const msg = messages[i];\n if (AIMessage.isInstance(msg) && hasToolCalls(msg)) {\n const aiToolCallIds = extractToolCallIds(msg as AIMessage);\n // Check if there's any overlap between the tool_call_ids\n for (const id of toolCallIds) {\n if (aiToolCallIds.has(id)) {\n // Found the AIMessage - move cutoff to include it\n return i;\n }\n }\n }\n }\n\n // Fallback: no matching AIMessage found, advance past ToolMessages to avoid\n // orphaned tool responses\n return idx;\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 *\n * @param messagesToSummarize - Messages to summarize.\n * @param model - The language model to use for summarization.\n * @param summaryPrompt - The prompt template for summarization.\n * @param tokenCounter - Function to count tokens.\n * @param trimTokensToSummarize - Optional token limit for trimming messages.\n * @param runtime - The runtime environment, used to inherit config so that\n * LangGraph's handlers can properly track and tag the summarization model call.\n */\nasync function createSummary(\n messagesToSummarize: BaseMessage[],\n model: BaseLanguageModel,\n summaryPrompt: string,\n tokenCounter: TokenCounter,\n trimTokensToSummarize: number | undefined,\n runtime: Runtime<unknown>\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 trimTokensToSummarize\n );\n\n if (!trimmedMessages.length) {\n return \"Previous conversation was too long to summarize.\";\n }\n\n /**\n * Format messages using getBufferString to avoid token inflation from metadata\n * when str() / JSON.stringify is called on message objects.\n * This produces compact output like:\n * ```\n * Human: What's the weather?\n * AI: Let me check...[tool_calls]\n * Tool: 72°F and sunny\n * ```\n */\n const formattedMessages = getBufferString(trimmedMessages);\n\n try {\n const formattedPrompt = summaryPrompt.replace(\n \"{messages}\",\n formattedMessages\n );\n /**\n * Merge parent runnable config with summarization metadata so LangGraph's\n * stream handlers (and other callback-based consumers) can properly track\n * and tag the summarization model call.\n */\n const baseConfig: RunnableConfig = pickRunnableConfigKeys(runtime) ?? {};\n const config = mergeConfigs(baseConfig, {\n metadata: { lc_source: \"summarization\" },\n });\n const response = await model.invoke(formattedPrompt, config);\n const content = response.content;\n /**\n * Handle both string content and MessageContent array\n */\n if (typeof content === \"string\") {\n return content.trim();\n } else if (Array.isArray(content)) {\n /**\n * Extract text from MessageContent array\n */\n const textContent = content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (typeof item === \"object\" && item !== null && \"text\" in item) {\n return (item as { text: string }).text;\n }\n return \"\";\n })\n .join(\"\");\n return textContent.trim();\n }\n return \"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 trimTokensToSummarize: number | undefined\n): Promise<BaseMessage[]> {\n if (trimTokensToSummarize === undefined) {\n return messages;\n }\n\n try {\n return await trimMessages(messages, {\n maxTokens: trimTokensToSummarize,\n tokenCounter: async (msgs) => tokenCounter(msgs),\n strategy: \"last\",\n allowPartial: true,\n includeSystem: true,\n });\n } catch {\n /**\n * Fallback to last N messages if trimming fails\n */\n return messages.slice(-DEFAULT_FALLBACK_MESSAGE_COUNT);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"summarization.js","names":["z","z4","uuid"],"sources":["../../../src/agents/middleware/summarization.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport { z as z4 } from \"zod/v4\";\nimport { v4 as uuid } from \"uuid\";\nimport {\n BaseMessage,\n AIMessage,\n SystemMessage,\n ToolMessage,\n RemoveMessage,\n trimMessages,\n HumanMessage,\n getBufferString,\n} from \"@langchain/core/messages\";\nimport {\n BaseLanguageModel,\n getModelContextSize,\n} from \"@langchain/core/language_models/base\";\nimport {\n interopSafeParse,\n InferInteropZodInput,\n InferInteropZodOutput,\n} from \"@langchain/core/utils/types\";\nimport {\n mergeConfigs,\n pickRunnableConfigKeys,\n type RunnableConfig,\n} from \"@langchain/core/runnables\";\nimport { REMOVE_ALL_MESSAGES } from \"@langchain/langgraph\";\nimport { createMiddleware } from \"../middleware.js\";\nimport { countTokensApproximately } from \"./utils.js\";\nimport { hasToolCalls } from \"../utils.js\";\nimport { initChatModel } from \"../../chat_models/universal.js\";\nimport type { Runtime } from \"../runtime.js\";\n\nexport const 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 DEFAULT_SUMMARY_PREFIX = \"Here is a summary of the conversation to date:\";\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\nconst tokenCounterSchema = z\n .function()\n .args(z.array(z.custom<BaseMessage>()))\n .returns(z.union([z.number(), z.promise(z.number())]));\nexport type TokenCounter = (\n messages: BaseMessage[]\n) => number | Promise<number>;\n\nexport const contextSizeSchema = z\n .object({\n /**\n * Fraction of the model's context size to use as the trigger\n */\n fraction: z\n .number()\n .gt(0, \"Fraction must be greater than 0\")\n .max(1, \"Fraction must be less than or equal to 1\")\n .optional(),\n /**\n * Number of tokens to use as the trigger\n */\n tokens: z.number().positive(\"Tokens must be greater than 0\").optional(),\n /**\n * Number of messages to use as the trigger\n */\n messages: z\n .number()\n .int(\"Messages must be an integer\")\n .positive(\"Messages must be greater than 0\")\n .optional(),\n })\n .refine(\n (data) => {\n const count = [data.fraction, data.tokens, data.messages].filter(\n (v) => v !== undefined\n ).length;\n return count >= 1;\n },\n {\n message: \"At least one of fraction, tokens, or messages must be provided\",\n }\n );\nexport type ContextSize = z.infer<typeof contextSizeSchema>;\n\nexport const keepSchema = z\n .object({\n /**\n * Fraction of the model's context size to keep\n */\n fraction: z\n .number()\n .min(0, \"Messages must be non-negative\")\n .max(1, \"Fraction must be less than or equal to 1\")\n .optional(),\n /**\n * Number of tokens to keep\n */\n tokens: z\n .number()\n .min(0, \"Tokens must be greater than or equal to 0\")\n .optional(),\n messages: z\n .number()\n .int(\"Messages must be an integer\")\n .min(0, \"Messages must be non-negative\")\n .optional(),\n })\n .refine(\n (data) => {\n const count = [data.fraction, data.tokens, data.messages].filter(\n (v) => v !== undefined\n ).length;\n return count === 1;\n },\n {\n message: \"Exactly one of fraction, tokens, or messages must be provided\",\n }\n );\nexport type KeepSize = z.infer<typeof keepSchema>;\n\nconst contextSchema = z.object({\n /**\n * Model to use for summarization\n */\n model: z.custom<string | BaseLanguageModel>(),\n /**\n * Trigger conditions for summarization.\n * Can be a single condition object (all properties must be met) or an array of conditions (any condition must be met).\n *\n * @example\n * ```ts\n * // Single condition: trigger if tokens >= 5000 AND messages >= 3\n * trigger: { tokens: 5000, messages: 3 }\n *\n * // Multiple conditions: trigger if (tokens >= 5000 AND messages >= 3) OR (tokens >= 3000 AND messages >= 6)\n * trigger: [\n * { tokens: 5000, messages: 3 },\n * { tokens: 3000, messages: 6 }\n * ]\n * ```\n */\n trigger: z.union([contextSizeSchema, z.array(contextSizeSchema)]).optional(),\n /**\n * Keep conditions for summarization\n */\n keep: keepSchema.optional(),\n /**\n * Token counter function to use for summarization\n */\n tokenCounter: tokenCounterSchema.optional(),\n /**\n * Summary prompt to use for summarization\n * @default {@link DEFAULT_SUMMARY_PROMPT}\n */\n summaryPrompt: z.string().default(DEFAULT_SUMMARY_PROMPT),\n /**\n * Number of tokens to trim to before summarizing\n */\n trimTokensToSummarize: z.number().optional(),\n /**\n * Prefix to add to the summary\n */\n summaryPrefix: z.string().optional(),\n /**\n * @deprecated Use `trigger: { tokens: value }` instead.\n */\n maxTokensBeforeSummary: z.number().optional(),\n /**\n * @deprecated Use `keep: { messages: value }` instead.\n */\n messagesToKeep: z.number().optional(),\n});\n\nexport type SummarizationMiddlewareConfig = InferInteropZodInput<\n typeof contextSchema\n>;\n\n/**\n * Get max input tokens from model profile or fallback to model name lookup\n */\nexport function getProfileLimits(input: BaseLanguageModel): number | undefined {\n // Access maxInputTokens on the model profile directly if available\n if (\n \"profile\" in input &&\n typeof input.profile === \"object\" &&\n input.profile &&\n \"maxInputTokens\" in input.profile &&\n (typeof input.profile.maxInputTokens === \"number\" ||\n input.profile.maxInputTokens == null)\n ) {\n return input.profile.maxInputTokens ?? undefined;\n }\n\n // Fallback to using model name if available\n if (\"model\" in input && typeof input.model === \"string\") {\n return getModelContextSize(input.model);\n }\n if (\"modelName\" in input && typeof input.modelName === \"string\") {\n return getModelContextSize(input.modelName);\n }\n\n return undefined;\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\";\n * import { createAgent } from \"langchain\";\n *\n * // Single condition: trigger if tokens >= 4000 AND messages >= 10\n * const agent1 = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * trigger: { tokens: 4000, messages: 10 },\n * keep: { messages: 20 },\n * })\n * ],\n * });\n *\n * // Multiple conditions: trigger if (tokens >= 5000 AND messages >= 3) OR (tokens >= 3000 AND messages >= 6)\n * const agent2 = createAgent({\n * llm: model,\n * tools: [getWeather],\n * middleware: [\n * summarizationMiddleware({\n * model: new ChatOpenAI({ model: \"gpt-4o\" }),\n * trigger: [\n * { tokens: 5000, messages: 3 },\n * { tokens: 3000, messages: 6 },\n * ],\n * keep: { messages: 20 },\n * })\n * ],\n * });\n *\n * ```\n */\nexport function summarizationMiddleware(\n options: SummarizationMiddlewareConfig\n) {\n /**\n * Parse user options to get their explicit values\n */\n const { data: userOptions, error } = interopSafeParse(contextSchema, options);\n if (error) {\n throw new Error(\n `Invalid summarization middleware options: ${z4.prettifyError(error)}`\n );\n }\n\n return createMiddleware({\n name: \"SummarizationMiddleware\",\n contextSchema: contextSchema.extend({\n /**\n * `model` should be required when initializing the middleware,\n * but can be omitted within context when invoking the middleware.\n */\n model: z.custom<BaseLanguageModel>().optional(),\n }),\n beforeModel: async (state, runtime) => {\n let trigger: ContextSize | ContextSize[] | undefined =\n userOptions.trigger;\n let keep: ContextSize = userOptions.keep as InferInteropZodOutput<\n typeof keepSchema\n >;\n\n /**\n * Handle deprecated parameters\n */\n if (userOptions.maxTokensBeforeSummary !== undefined) {\n console.warn(\n \"maxTokensBeforeSummary is deprecated. Use `trigger: { tokens: value }` instead.\"\n );\n if (trigger === undefined) {\n trigger = { tokens: userOptions.maxTokensBeforeSummary };\n }\n }\n\n /**\n * Handle deprecated parameters\n */\n if (userOptions.messagesToKeep !== undefined) {\n console.warn(\n \"messagesToKeep is deprecated. Use `keep: { messages: value }` instead.\"\n );\n if (\n !keep ||\n (keep &&\n \"messages\" in keep &&\n keep.messages === DEFAULT_MESSAGES_TO_KEEP)\n ) {\n keep = { messages: userOptions.messagesToKeep };\n }\n }\n\n /**\n * Merge context with user options\n */\n const resolvedTrigger =\n runtime.context?.trigger !== undefined\n ? runtime.context.trigger\n : trigger;\n const resolvedKeep =\n runtime.context?.keep !== undefined\n ? runtime.context.keep\n : (keep ?? { messages: DEFAULT_MESSAGES_TO_KEEP });\n\n const validatedKeep = keepSchema.parse(resolvedKeep);\n\n /**\n * Validate trigger conditions\n */\n let triggerConditions: ContextSize[] = [];\n if (resolvedTrigger === undefined) {\n triggerConditions = [];\n } else if (Array.isArray(resolvedTrigger)) {\n /**\n * It's an array of ContextSize objects\n */\n triggerConditions = (resolvedTrigger as ContextSize[]).map((t) =>\n contextSizeSchema.parse(t)\n );\n } else {\n /**\n * Single ContextSize object - all properties must be satisfied (AND logic)\n */\n triggerConditions = [contextSizeSchema.parse(resolvedTrigger)];\n }\n\n /**\n * Check if profile is required\n */\n const requiresProfile =\n triggerConditions.some((c) => \"fraction\" in c) ||\n \"fraction\" in validatedKeep;\n\n const model =\n typeof userOptions.model === \"string\"\n ? await initChatModel(userOptions.model)\n : userOptions.model;\n\n if (requiresProfile && !getProfileLimits(model)) {\n throw new Error(\n \"Model profile information is required to use fractional token limits. \" +\n \"Use absolute token counts instead.\"\n );\n }\n\n const summaryPrompt =\n runtime.context?.summaryPrompt === DEFAULT_SUMMARY_PROMPT\n ? (userOptions.summaryPrompt ?? DEFAULT_SUMMARY_PROMPT)\n : (runtime.context?.summaryPrompt ??\n userOptions.summaryPrompt ??\n DEFAULT_SUMMARY_PROMPT);\n const summaryPrefix =\n runtime.context.summaryPrefix ??\n userOptions.summaryPrefix ??\n DEFAULT_SUMMARY_PREFIX;\n const trimTokensToSummarize =\n runtime.context?.trimTokensToSummarize !== undefined\n ? runtime.context.trimTokensToSummarize\n : (userOptions.trimTokensToSummarize ?? DEFAULT_TRIM_TOKEN_LIMIT);\n\n /**\n * Ensure all messages have IDs\n */\n ensureMessageIds(state.messages);\n\n const tokenCounter =\n runtime.context?.tokenCounter !== undefined\n ? runtime.context.tokenCounter\n : (userOptions.tokenCounter ?? countTokensApproximately);\n const totalTokens = await tokenCounter(state.messages);\n const doSummarize = await shouldSummarize(\n state.messages,\n totalTokens,\n triggerConditions,\n model\n );\n\n if (!doSummarize) {\n return;\n }\n\n const { systemPrompt, conversationMessages } = splitSystemMessage(\n state.messages\n );\n const cutoffIndex = await determineCutoffIndex(\n conversationMessages,\n validatedKeep,\n tokenCounter,\n model\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 model,\n summaryPrompt,\n tokenCounter,\n trimTokensToSummarize,\n runtime\n );\n\n const summaryMessage = new HumanMessage({\n content: `${summaryPrefix}\\n\\n${summary}`,\n id: uuid(),\n additional_kwargs: { lc_source: \"summarization\" },\n });\n\n return {\n messages: [\n new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),\n summaryMessage,\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;\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 conversationMessages: messages,\n };\n}\n\n/**\n * Partition messages into those to summarize and those to preserve\n */\nfunction partitionMessages(\n systemPrompt: SystemMessage | undefined,\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 * Determine whether summarization should run for the current token usage\n *\n * @param messages - Current messages in the conversation\n * @param totalTokens - Total token count for all messages\n * @param triggerConditions - Array of trigger conditions. Returns true if ANY condition is satisfied (OR logic).\n * Within each condition, ALL specified properties must be satisfied (AND logic).\n * @param model - The language model being used\n * @returns true if summarization should be triggered\n */\nasync function shouldSummarize(\n messages: BaseMessage[],\n totalTokens: number,\n triggerConditions: ContextSize[],\n model: BaseLanguageModel\n): Promise<boolean> {\n if (triggerConditions.length === 0) {\n return false;\n }\n\n /**\n * Check each condition (OR logic between conditions)\n */\n for (const trigger of triggerConditions) {\n /**\n * Within a single condition, all specified properties must be satisfied (AND logic)\n */\n let conditionMet = true;\n let hasAnyProperty = false;\n\n if (trigger.messages !== undefined) {\n hasAnyProperty = true;\n if (messages.length < trigger.messages) {\n conditionMet = false;\n }\n }\n\n if (trigger.tokens !== undefined) {\n hasAnyProperty = true;\n if (totalTokens < trigger.tokens) {\n conditionMet = false;\n }\n }\n\n if (trigger.fraction !== undefined) {\n hasAnyProperty = true;\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens === \"number\") {\n const threshold = Math.floor(maxInputTokens * trigger.fraction);\n if (totalTokens < threshold) {\n conditionMet = false;\n }\n } else {\n /**\n * If fraction is specified but we can't get model limits, skip this condition\n */\n conditionMet = false;\n }\n }\n\n /**\n * If condition has at least one property and all properties are satisfied, trigger summarization\n */\n if (hasAnyProperty && conditionMet) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Determine cutoff index respecting retention configuration\n */\nasync function determineCutoffIndex(\n messages: BaseMessage[],\n keep: ContextSize,\n tokenCounter: TokenCounter,\n model: BaseLanguageModel\n): Promise<number> {\n if (\"tokens\" in keep || \"fraction\" in keep) {\n const tokenBasedCutoff = await findTokenBasedCutoff(\n messages,\n keep,\n tokenCounter,\n model\n );\n if (typeof tokenBasedCutoff === \"number\") {\n return tokenBasedCutoff;\n }\n /**\n * Fallback to message count if token-based fails\n */\n return findSafeCutoff(messages, DEFAULT_MESSAGES_TO_KEEP);\n }\n /**\n * find cutoff index based on message count\n */\n return findSafeCutoff(messages, keep.messages ?? DEFAULT_MESSAGES_TO_KEEP);\n}\n\n/**\n * Find cutoff index based on target token retention\n */\nasync function findTokenBasedCutoff(\n messages: BaseMessage[],\n keep: ContextSize,\n tokenCounter: TokenCounter,\n model: BaseLanguageModel\n): Promise<number | undefined> {\n if (messages.length === 0) {\n return 0;\n }\n\n let targetTokenCount: number;\n\n if (\"fraction\" in keep && keep.fraction !== undefined) {\n const maxInputTokens = getProfileLimits(model);\n if (typeof maxInputTokens !== \"number\") {\n return;\n }\n targetTokenCount = Math.floor(maxInputTokens * keep.fraction);\n } else if (\"tokens\" in keep && keep.tokens !== undefined) {\n targetTokenCount = Math.floor(keep.tokens);\n } else {\n return;\n }\n\n if (targetTokenCount <= 0) {\n targetTokenCount = 1;\n }\n\n const totalTokens = await tokenCounter(messages);\n if (totalTokens <= targetTokenCount) {\n return 0;\n }\n\n /**\n * Use binary search to identify the earliest message index that keeps the\n * suffix within the token budget.\n */\n let left = 0;\n let right = messages.length;\n let cutoffCandidate = messages.length;\n const maxIterations = Math.floor(Math.log2(messages.length)) + 1;\n\n for (let i = 0; i < maxIterations; i++) {\n if (left >= right) {\n break;\n }\n\n const mid = Math.floor((left + right) / 2);\n const suffixTokens = await tokenCounter(messages.slice(mid));\n if (suffixTokens <= targetTokenCount) {\n cutoffCandidate = mid;\n right = mid;\n } else {\n left = mid + 1;\n }\n }\n\n if (cutoffCandidate === messages.length) {\n cutoffCandidate = left;\n }\n\n if (cutoffCandidate >= messages.length) {\n if (messages.length === 1) {\n return 0;\n }\n cutoffCandidate = messages.length - 1;\n }\n\n /**\n * Find safe cutoff point that preserves AI/Tool pairs.\n * If cutoff lands on ToolMessage, move backward to include the AIMessage.\n */\n const safeCutoff = findSafeCutoffPoint(messages, cutoffCandidate);\n\n /**\n * If findSafeCutoffPoint moved forward (fallback case), verify it's safe.\n * If it moved backward, we already have a safe point.\n */\n if (safeCutoff <= cutoffCandidate) {\n return safeCutoff;\n }\n\n /**\n * Fallback: iterate backward to find a safe cutoff\n */\n for (let i = cutoffCandidate; i >= 0; i--) {\n if (isSafeCutoffPoint(messages, i)) {\n return i;\n }\n }\n\n return 0;\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 /**\n * First, try to find a safe cutoff point using findSafeCutoffPoint.\n * This handles the case where cutoff lands on a ToolMessage by moving\n * backward to include the corresponding AIMessage.\n */\n const safeCutoff = findSafeCutoffPoint(messages, targetCutoff);\n\n /**\n * If findSafeCutoffPoint moved backward (found matching AIMessage), use it.\n */\n if (safeCutoff <= targetCutoff) {\n return safeCutoff;\n }\n\n /**\n * Fallback: iterate backward to find a safe cutoff\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 /**\n * Prevent preserved messages from starting with AI message containing tool calls\n */\n if (\n cutoffIndex < messages.length &&\n AIMessage.isInstance(messages[cutoffIndex]) &&\n hasToolCalls(messages[cutoffIndex])\n ) {\n return false;\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 * 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 * Find a safe cutoff point that doesn't split AI/Tool message pairs.\n *\n * If the message at `cutoffIndex` is a `ToolMessage`, search backward for the\n * `AIMessage` containing the corresponding `tool_calls` and adjust the cutoff to\n * include it. This ensures tool call requests and responses stay together.\n *\n * Falls back to advancing forward past `ToolMessage` objects only if no matching\n * `AIMessage` is found (edge case).\n */\nfunction findSafeCutoffPoint(\n messages: BaseMessage[],\n cutoffIndex: number\n): number {\n if (\n cutoffIndex >= messages.length ||\n !ToolMessage.isInstance(messages[cutoffIndex])\n ) {\n return cutoffIndex;\n }\n\n // Collect tool_call_ids from consecutive ToolMessages at/after cutoff\n const toolCallIds = new Set<string>();\n let idx = cutoffIndex;\n while (idx < messages.length && ToolMessage.isInstance(messages[idx])) {\n const toolMsg = messages[idx] as ToolMessage;\n if (toolMsg.tool_call_id) {\n toolCallIds.add(toolMsg.tool_call_id);\n }\n idx++;\n }\n\n // Search backward for AIMessage with matching tool_calls\n for (let i = cutoffIndex - 1; i >= 0; i--) {\n const msg = messages[i];\n if (AIMessage.isInstance(msg) && hasToolCalls(msg)) {\n const aiToolCallIds = extractToolCallIds(msg as AIMessage);\n // Check if there's any overlap between the tool_call_ids\n for (const id of toolCallIds) {\n if (aiToolCallIds.has(id)) {\n // Found the AIMessage - move cutoff to include it\n return i;\n }\n }\n }\n }\n\n // Fallback: no matching AIMessage found, advance past ToolMessages to avoid\n // orphaned tool responses\n return idx;\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 *\n * @param messagesToSummarize - Messages to summarize.\n * @param model - The language model to use for summarization.\n * @param summaryPrompt - The prompt template for summarization.\n * @param tokenCounter - Function to count tokens.\n * @param trimTokensToSummarize - Optional token limit for trimming messages.\n * @param runtime - The runtime environment, used to inherit config so that\n * LangGraph's handlers can properly track and tag the summarization model call.\n */\nasync function createSummary(\n messagesToSummarize: BaseMessage[],\n model: BaseLanguageModel,\n summaryPrompt: string,\n tokenCounter: TokenCounter,\n trimTokensToSummarize: number | undefined,\n runtime: Runtime<unknown>\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 trimTokensToSummarize\n );\n\n if (!trimmedMessages.length) {\n return \"Previous conversation was too long to summarize.\";\n }\n\n /**\n * Format messages using getBufferString to avoid token inflation from metadata\n * when str() / JSON.stringify is called on message objects.\n * This produces compact output like:\n * ```\n * Human: What's the weather?\n * AI: Let me check...[tool_calls]\n * Tool: 72°F and sunny\n * ```\n */\n const formattedMessages = getBufferString(trimmedMessages);\n\n try {\n const formattedPrompt = summaryPrompt.replace(\n \"{messages}\",\n formattedMessages\n );\n /**\n * Merge parent runnable config with summarization metadata so LangGraph's\n * stream handlers (and other callback-based consumers) can properly track\n * and tag the summarization model call.\n */\n const baseConfig: RunnableConfig = pickRunnableConfigKeys(runtime) ?? {};\n const config = mergeConfigs(baseConfig, {\n metadata: { lc_source: \"summarization\" },\n });\n const response = await model.invoke(formattedPrompt, config);\n const content = response.content;\n /**\n * Handle both string content and MessageContent array\n */\n if (typeof content === \"string\") {\n return content.trim();\n } else if (Array.isArray(content)) {\n /**\n * Extract text from MessageContent array\n */\n const textContent = content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (typeof item === \"object\" && item !== null && \"text\" in item) {\n return (item as { text: string }).text;\n }\n return \"\";\n })\n .join(\"\");\n return textContent.trim();\n }\n return \"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 trimTokensToSummarize: number | undefined\n): Promise<BaseMessage[]> {\n if (trimTokensToSummarize === undefined) {\n return messages;\n }\n\n try {\n return await trimMessages(messages, {\n maxTokens: trimTokensToSummarize,\n tokenCounter: async (msgs) => tokenCounter(msgs),\n strategy: \"last\",\n allowPartial: true,\n includeSystem: true,\n });\n } catch {\n /**\n * Fallback to last N messages if trimming fails\n */\n return messages.slice(-DEFAULT_FALLBACK_MESSAGE_COUNT);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require("../../_virtual/_rolldown/runtime.cjs");
|
|
2
2
|
const require_middleware = require("../middleware.cjs");
|
|
3
3
|
let _langchain_core_messages = require("@langchain/core/messages");
|
|
4
|
-
let zod_v3 = require("zod/v3");
|
|
5
4
|
let zod_v4 = require("zod/v4");
|
|
5
|
+
let zod_v3 = require("zod/v3");
|
|
6
6
|
//#region src/agents/middleware/toolCallLimit.ts
|
|
7
7
|
/**
|
|
8
8
|
* Build the error message content for ToolMessage when limit is exceeded.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createMiddleware } from "../middleware.js";
|
|
2
2
|
import { AIMessage, ToolMessage } from "@langchain/core/messages";
|
|
3
|
-
import { z } from "zod/
|
|
4
|
-
import { z as z$1 } from "zod/
|
|
3
|
+
import { z } from "zod/v4";
|
|
4
|
+
import { z as z$1 } from "zod/v3";
|
|
5
5
|
//#region src/agents/middleware/toolCallLimit.ts
|
|
6
6
|
/**
|
|
7
7
|
* Build the error message content for ToolMessage when limit is exceeded.
|
|
@@ -45,7 +45,7 @@ function buildFinalAIMessageContent(threadCount, runCount, threadLimit, runLimit
|
|
|
45
45
|
/**
|
|
46
46
|
* Schema for the exit behavior.
|
|
47
47
|
*/
|
|
48
|
-
const exitBehaviorSchema = z.enum(VALID_EXIT_BEHAVIORS).default(DEFAULT_EXIT_BEHAVIOR);
|
|
48
|
+
const exitBehaviorSchema = z$1.enum(VALID_EXIT_BEHAVIORS).default(DEFAULT_EXIT_BEHAVIOR);
|
|
49
49
|
/**
|
|
50
50
|
* Exception raised when tool call limits are exceeded.
|
|
51
51
|
*
|
|
@@ -84,18 +84,18 @@ var ToolCallLimitExceededError = class extends Error {
|
|
|
84
84
|
this.toolName = toolName;
|
|
85
85
|
}
|
|
86
86
|
};
|
|
87
|
-
z.object({
|
|
88
|
-
toolName: z.string().optional(),
|
|
89
|
-
threadLimit: z.number().optional(),
|
|
90
|
-
runLimit: z.number().optional(),
|
|
87
|
+
z$1.object({
|
|
88
|
+
toolName: z$1.string().optional(),
|
|
89
|
+
threadLimit: z$1.number().optional(),
|
|
90
|
+
runLimit: z$1.number().optional(),
|
|
91
91
|
exitBehavior: exitBehaviorSchema
|
|
92
92
|
});
|
|
93
93
|
/**
|
|
94
94
|
* Middleware state schema to track the number of model calls made at the thread and run level.
|
|
95
95
|
*/
|
|
96
|
-
const stateSchema = z.object({
|
|
97
|
-
threadToolCallCount: z.record(z.string(), z.number()).default({}),
|
|
98
|
-
runToolCallCount: z.record(z.string(), z.number()).default({})
|
|
96
|
+
const stateSchema = z$1.object({
|
|
97
|
+
threadToolCallCount: z$1.record(z$1.string(), z$1.number()).default({}),
|
|
98
|
+
runToolCallCount: z$1.record(z$1.string(), z$1.number()).default({})
|
|
99
99
|
});
|
|
100
100
|
const DEFAULT_TOOL_COUNT_KEY = "__all__";
|
|
101
101
|
/**
|
|
@@ -188,7 +188,7 @@ function toolCallLimitMiddleware(options) {
|
|
|
188
188
|
*/
|
|
189
189
|
const exitBehavior = options.exitBehavior ?? DEFAULT_EXIT_BEHAVIOR;
|
|
190
190
|
const parseResult = exitBehaviorSchema.safeParse(exitBehavior);
|
|
191
|
-
if (!parseResult.success) throw new Error(z
|
|
191
|
+
if (!parseResult.success) throw new Error(z.prettifyError(parseResult.error).slice(2));
|
|
192
192
|
/**
|
|
193
193
|
* Validate that runLimit does not exceed threadLimit
|
|
194
194
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolCallLimit.js","names":["z4"],"sources":["../../../src/agents/middleware/toolCallLimit.ts"],"sourcesContent":["import { AIMessage, ToolMessage } from \"@langchain/core/messages\";\nimport { z as z4 } from \"zod/v4\";\nimport { z } from \"zod/v3\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\n\nimport { createMiddleware } from \"../middleware.js\";\n\n/**\n * Build the error message content for ToolMessage when limit is exceeded.\n *\n * This message is sent to the model, so it should not reference thread/run concepts\n * that the model has no notion of.\n *\n * @param toolName - Tool name being limited (if specific tool), or undefined for all tools.\n * @returns A concise message instructing the model not to call the tool again.\n */\nfunction buildToolMessageContent(toolName: string | undefined): string {\n // Always instruct the model not to call again, regardless of which limit was hit\n if (toolName) {\n return `Tool call limit exceeded. Do not call '${toolName}' again.`;\n }\n return \"Tool call limit exceeded. Do not make additional tool calls.\";\n}\n\nconst VALID_EXIT_BEHAVIORS = [\"continue\", \"error\", \"end\"] as const;\nconst DEFAULT_EXIT_BEHAVIOR = \"continue\";\n\n/**\n * Build the final AI message content for 'end' behavior.\n *\n * This message is displayed to the user, so it should include detailed information\n * about which limits were exceeded.\n *\n * @param threadCount - Current thread tool call count.\n * @param runCount - Current run tool call count.\n * @param threadLimit - Thread tool call limit (if set).\n * @param runLimit - Run tool call limit (if set).\n * @param toolName - Tool name being limited (if specific tool), or undefined for all tools.\n * @returns A formatted message describing which limits were exceeded.\n */\nfunction buildFinalAIMessageContent(\n threadCount: number,\n runCount: number,\n threadLimit: number | undefined,\n runLimit: number | undefined,\n toolName: string | undefined\n): string {\n const toolDesc = toolName ? `'${toolName}' tool` : \"Tool\";\n const exceededLimits: string[] = [];\n\n if (threadLimit !== undefined && threadCount > threadLimit) {\n exceededLimits.push(\n `thread limit exceeded (${threadCount}/${threadLimit} calls)`\n );\n }\n if (runLimit !== undefined && runCount > runLimit) {\n exceededLimits.push(`run limit exceeded (${runCount}/${runLimit} calls)`);\n }\n\n const limitsText = exceededLimits.join(\" and \");\n return `${toolDesc} call limit reached: ${limitsText}.`;\n}\n\n/**\n * Schema for the exit behavior.\n */\nconst exitBehaviorSchema = z\n .enum(VALID_EXIT_BEHAVIORS)\n .default(DEFAULT_EXIT_BEHAVIOR);\n\n/**\n * Exception raised when tool call limits are exceeded.\n *\n * This exception is raised when the configured exit behavior is 'error'\n * and either the thread or run tool call limit has been exceeded.\n */\nexport class ToolCallLimitExceededError extends Error {\n /**\n * Current thread tool call count.\n */\n threadCount: number;\n /**\n * Current run tool call count.\n */\n runCount: number;\n /**\n * Thread tool call limit (if set).\n */\n threadLimit: number | undefined;\n /**\n * Run tool call limit (if set).\n */\n runLimit: number | undefined;\n /**\n * Tool name being limited (if specific tool), or undefined for all tools.\n */\n toolName: string | undefined;\n\n constructor(\n threadCount: number,\n runCount: number,\n threadLimit: number | undefined,\n runLimit: number | undefined,\n toolName: string | undefined = undefined\n ) {\n const message = buildFinalAIMessageContent(\n threadCount,\n runCount,\n threadLimit,\n runLimit,\n toolName\n );\n super(message);\n\n this.name = \"ToolCallLimitExceededError\";\n this.threadCount = threadCount;\n this.runCount = runCount;\n this.threadLimit = threadLimit;\n this.runLimit = runLimit;\n this.toolName = toolName;\n }\n}\n\n/**\n * Options for configuring the Tool Call Limit middleware.\n */\nexport const ToolCallLimitOptionsSchema = z.object({\n /**\n * Name of the specific tool to limit. If undefined, limits apply to all tools.\n */\n toolName: z.string().optional(),\n /**\n * Maximum number of tool calls allowed per thread.\n * undefined means no limit.\n */\n threadLimit: z.number().optional(),\n /**\n * Maximum number of tool calls allowed per run.\n * undefined means no limit.\n */\n runLimit: z.number().optional(),\n /**\n * What to do when limits are exceeded.\n * - \"continue\": Block exceeded tools with error messages, let other tools continue (default)\n * - \"error\": Raise a ToolCallLimitExceededError exception\n * - \"end\": Stop execution immediately, injecting a ToolMessage and an AI message\n * for the single tool call that exceeded the limit. Raises NotImplementedError\n * if there are multiple tool calls.\n *\n * @default \"continue\"\n */\n exitBehavior: exitBehaviorSchema,\n});\n\nexport type ToolCallLimitConfig = InferInteropZodInput<\n typeof ToolCallLimitOptionsSchema\n>;\n\n/**\n * Middleware state schema to track the number of model calls made at the thread and run level.\n */\nconst stateSchema = z.object({\n threadToolCallCount: z.record(z.string(), z.number()).default({}),\n runToolCallCount: z.record(z.string(), z.number()).default({}),\n});\n\nconst DEFAULT_TOOL_COUNT_KEY = \"__all__\";\n\n/**\n * Middleware that tracks tool call counts and enforces limits.\n *\n * This middleware monitors the number of tool calls made during agent execution\n * and can terminate the agent when specified limits are reached. It supports\n * both thread-level and run-level call counting with configurable exit behaviors.\n *\n * Thread-level: The middleware counts all tool calls in the entire message history\n * and persists this count across multiple runs (invocations) of the agent.\n *\n * Run-level: The middleware counts tool calls made after the last HumanMessage,\n * representing the current run (invocation) of the agent.\n *\n * @param options - Configuration options for the middleware\n * @param options.toolName - Name of the specific tool to limit. If undefined, limits apply to all tools.\n * @param options.threadLimit - Maximum number of tool calls allowed per thread. undefined means no limit.\n * @param options.runLimit - Maximum number of tool calls allowed per run. undefined means no limit.\n * @param options.exitBehavior - What to do when limits are exceeded.\n * - \"continue\": Block exceeded tools with error messages, let other tools continue. Model decides when to end. (default)\n * - \"error\": Raise a ToolCallLimitExceededError exception\n * - \"end\": Stop execution immediately with a ToolMessage + AI message for the single tool call that exceeded the limit. Raises NotImplementedError if there are multiple tool calls.\n *\n * @throws {Error} If both limits are undefined, if exitBehavior is invalid, or if runLimit exceeds threadLimit.\n * @throws {NotImplementedError} If exitBehavior is \"end\" and there are multiple tool calls.\n *\n * @example Continue execution with blocked tools (default)\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * // Block exceeded tools but let other tools and model continue\n * const limiter = toolCallLimitMiddleware({\n * threadLimit: 20,\n * runLimit: 10,\n * exitBehavior: \"continue\", // default\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n * ```\n *\n * @example Stop immediately when limit exceeded\n * ```ts\n * // End execution immediately with an AI message\n * const limiter = toolCallLimitMiddleware({\n * runLimit: 5,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n * ```\n *\n * @example Raise exception on limit\n * ```ts\n * // Strict limit with exception handling\n * const limiter = toolCallLimitMiddleware({\n * toolName: \"search\",\n * threadLimit: 5,\n * exitBehavior: \"error\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n *\n * try {\n * const result = await agent.invoke({ messages: [new HumanMessage(\"Task\")] });\n * } catch (error) {\n * if (error instanceof ToolCallLimitExceededError) {\n * console.log(`Search limit exceeded: ${error}`);\n * }\n * }\n * ```\n */\nexport function toolCallLimitMiddleware(options: ToolCallLimitConfig) {\n /**\n * Validate that at least one limit is specified\n */\n if (options.threadLimit === undefined && options.runLimit === undefined) {\n throw new Error(\n \"At least one limit must be specified (threadLimit or runLimit)\"\n );\n }\n\n /**\n * Validate exitBehavior (Zod schema already validates, but provide helpful error)\n */\n const exitBehavior = options.exitBehavior ?? DEFAULT_EXIT_BEHAVIOR;\n const parseResult = exitBehaviorSchema.safeParse(exitBehavior);\n if (!parseResult.success) {\n throw new Error(z4.prettifyError(parseResult.error).slice(2));\n }\n\n /**\n * Validate that runLimit does not exceed threadLimit\n */\n if (\n options.threadLimit !== undefined &&\n options.runLimit !== undefined &&\n options.runLimit > options.threadLimit\n ) {\n throw new Error(\n `runLimit (${options.runLimit}) cannot exceed threadLimit (${options.threadLimit}). ` +\n \"The run limit should be less than or equal to the thread limit.\"\n );\n }\n\n /**\n * Generate the middleware name based on the tool name\n */\n const middlewareName = options.toolName\n ? `ToolCallLimitMiddleware[${options.toolName}]`\n : \"ToolCallLimitMiddleware\";\n\n return createMiddleware({\n name: middlewareName,\n stateSchema,\n afterModel: {\n canJumpTo: [\"end\"],\n hook: (state) => {\n /**\n * Get the last AI message to check for tool calls\n */\n const lastAIMessage = [...state.messages]\n .reverse()\n .find(AIMessage.isInstance);\n\n if (!lastAIMessage || !lastAIMessage.tool_calls) {\n return undefined;\n }\n\n /**\n * Helper to check if limit would be exceeded by one more call\n */\n const wouldExceedLimit = (\n threadCount: number,\n runCount: number\n ): boolean => {\n return (\n (options.threadLimit !== undefined &&\n threadCount + 1 > options.threadLimit) ||\n (options.runLimit !== undefined && runCount + 1 > options.runLimit)\n );\n };\n\n /**\n * Helper to check if a tool call matches our filter\n */\n const matchesToolFilter = (toolCall: { name?: string }): boolean => {\n return (\n options.toolName === undefined || toolCall.name === options.toolName\n );\n };\n\n /**\n * Separate tool calls into allowed and blocked based on limits\n */\n const separateToolCalls = (\n toolCalls: ToolCall[],\n threadCount: number,\n runCount: number\n ): {\n allowed: ToolCall[];\n blocked: ToolCall[];\n finalThreadCount: number;\n finalRunCount: number;\n } => {\n const allowed: ToolCall[] = [];\n const blocked: ToolCall[] = [];\n let tempThreadCount = threadCount;\n let tempRunCount = runCount;\n\n for (const toolCall of toolCalls) {\n if (!matchesToolFilter(toolCall)) {\n // Tool call doesn't match our filter, skip it\n continue;\n }\n\n if (wouldExceedLimit(tempThreadCount, tempRunCount)) {\n blocked.push(toolCall);\n } else {\n allowed.push(toolCall);\n tempThreadCount += 1;\n tempRunCount += 1;\n }\n }\n\n return {\n allowed,\n blocked,\n finalThreadCount: tempThreadCount,\n finalRunCount: tempRunCount + blocked.length,\n };\n };\n\n /**\n * Get the count key for this middleware instance\n */\n const countKey = options.toolName ?? DEFAULT_TOOL_COUNT_KEY;\n\n /**\n * Get current counts\n */\n const threadCounts = { ...(state.threadToolCallCount ?? {}) };\n const runCounts = { ...(state.runToolCallCount ?? {}) };\n const currentThreadCount = threadCounts[countKey] ?? 0;\n const currentRunCount = runCounts[countKey] ?? 0;\n\n /**\n * Separate tool calls into allowed and blocked\n */\n const { allowed, blocked, finalThreadCount, finalRunCount } =\n separateToolCalls(\n lastAIMessage.tool_calls,\n currentThreadCount,\n currentRunCount\n );\n\n /**\n * Update counts:\n * - Thread count includes only allowed calls (blocked calls don't count towards thread-level tracking)\n * - Run count includes blocked calls since they were attempted in this run\n */\n threadCounts[countKey] = finalThreadCount;\n runCounts[countKey] = finalRunCount;\n\n /**\n * If no tool calls are blocked, just update counts\n */\n if (blocked.length === 0) {\n if (allowed.length > 0) {\n return {\n threadToolCallCount: threadCounts,\n runToolCallCount: runCounts,\n };\n }\n return undefined;\n }\n\n /**\n * Handle different exit behaviors\n */\n if (exitBehavior === \"error\") {\n // Use hypothetical thread count to show which limit was exceeded\n const hypotheticalThreadCount = finalThreadCount + blocked.length;\n throw new ToolCallLimitExceededError(\n hypotheticalThreadCount,\n finalRunCount,\n options.threadLimit,\n options.runLimit,\n options.toolName\n );\n }\n\n /**\n * Build tool message content (sent to model - no thread/run details)\n */\n const toolMsgContent = buildToolMessageContent(options.toolName);\n\n /**\n * Inject artificial error ToolMessages for blocked tool calls\n */\n const artificialMessages: Array<ToolMessage | AIMessage> = blocked.map(\n (toolCall) =>\n new ToolMessage({\n content: toolMsgContent,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n status: \"error\",\n })\n );\n\n if (exitBehavior === \"end\") {\n /**\n * Check if there are tool calls to other tools that would continue executing\n * For tool-specific limiters: check for calls to other tools\n * For global limiters: check if there are multiple different tool types\n */\n let otherTools: ToolCall[] = [];\n if (options.toolName !== undefined) {\n /**\n * Tool-specific limiter: check for calls to other tools\n */\n otherTools = lastAIMessage.tool_calls.filter(\n (tc) => tc.name !== options.toolName\n );\n } else {\n /**\n * Global limiter: check if there are multiple different tool types\n * If there are allowed calls, those would execute\n * But even if all are blocked, we can't handle multiple tool types with \"end\"\n */\n const uniqueToolNames = new Set(\n lastAIMessage.tool_calls.map((tc) => tc.name).filter(Boolean)\n );\n if (uniqueToolNames.size > 1) {\n /**\n * Multiple different tool types - use allowed calls to show which ones\n */\n otherTools =\n allowed.length > 0 ? allowed : lastAIMessage.tool_calls;\n }\n }\n\n if (otherTools.length > 0) {\n const toolNames = Array.from(\n new Set(otherTools.map((tc) => tc.name).filter(Boolean))\n ).join(\", \");\n throw new Error(\n `Cannot end execution with other tool calls pending. Found calls to: ${toolNames}. Use 'continue' or 'error' behavior instead.`\n );\n }\n\n /**\n * Build final AI message content (displayed to user - includes thread/run details)\n * Use hypothetical thread count (what it would have been if call wasn't blocked)\n * to show which limit was actually exceeded\n */\n const hypotheticalThreadCount = finalThreadCount + blocked.length;\n const finalMsgContent = buildFinalAIMessageContent(\n hypotheticalThreadCount,\n finalRunCount,\n options.threadLimit,\n options.runLimit,\n options.toolName\n );\n artificialMessages.push(new AIMessage(finalMsgContent));\n\n return {\n threadToolCallCount: threadCounts,\n runToolCallCount: runCounts,\n jumpTo: \"end\" as const,\n messages: artificialMessages,\n };\n }\n\n /**\n * For exit_behavior=\"continue\", return error messages to block exceeded tools\n */\n return {\n threadToolCallCount: threadCounts,\n runToolCallCount: runCounts,\n messages: artificialMessages,\n };\n },\n },\n /**\n * reset the run tool call count after the agent execution completes\n */\n afterAgent: () => ({\n runToolCallCount: {},\n }),\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toolCallLimit.js","names":["z","z4"],"sources":["../../../src/agents/middleware/toolCallLimit.ts"],"sourcesContent":["import { AIMessage, ToolMessage } from \"@langchain/core/messages\";\nimport { z as z4 } from \"zod/v4\";\nimport { z } from \"zod/v3\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\n\nimport { createMiddleware } from \"../middleware.js\";\n\n/**\n * Build the error message content for ToolMessage when limit is exceeded.\n *\n * This message is sent to the model, so it should not reference thread/run concepts\n * that the model has no notion of.\n *\n * @param toolName - Tool name being limited (if specific tool), or undefined for all tools.\n * @returns A concise message instructing the model not to call the tool again.\n */\nfunction buildToolMessageContent(toolName: string | undefined): string {\n // Always instruct the model not to call again, regardless of which limit was hit\n if (toolName) {\n return `Tool call limit exceeded. Do not call '${toolName}' again.`;\n }\n return \"Tool call limit exceeded. Do not make additional tool calls.\";\n}\n\nconst VALID_EXIT_BEHAVIORS = [\"continue\", \"error\", \"end\"] as const;\nconst DEFAULT_EXIT_BEHAVIOR = \"continue\";\n\n/**\n * Build the final AI message content for 'end' behavior.\n *\n * This message is displayed to the user, so it should include detailed information\n * about which limits were exceeded.\n *\n * @param threadCount - Current thread tool call count.\n * @param runCount - Current run tool call count.\n * @param threadLimit - Thread tool call limit (if set).\n * @param runLimit - Run tool call limit (if set).\n * @param toolName - Tool name being limited (if specific tool), or undefined for all tools.\n * @returns A formatted message describing which limits were exceeded.\n */\nfunction buildFinalAIMessageContent(\n threadCount: number,\n runCount: number,\n threadLimit: number | undefined,\n runLimit: number | undefined,\n toolName: string | undefined\n): string {\n const toolDesc = toolName ? `'${toolName}' tool` : \"Tool\";\n const exceededLimits: string[] = [];\n\n if (threadLimit !== undefined && threadCount > threadLimit) {\n exceededLimits.push(\n `thread limit exceeded (${threadCount}/${threadLimit} calls)`\n );\n }\n if (runLimit !== undefined && runCount > runLimit) {\n exceededLimits.push(`run limit exceeded (${runCount}/${runLimit} calls)`);\n }\n\n const limitsText = exceededLimits.join(\" and \");\n return `${toolDesc} call limit reached: ${limitsText}.`;\n}\n\n/**\n * Schema for the exit behavior.\n */\nconst exitBehaviorSchema = z\n .enum(VALID_EXIT_BEHAVIORS)\n .default(DEFAULT_EXIT_BEHAVIOR);\n\n/**\n * Exception raised when tool call limits are exceeded.\n *\n * This exception is raised when the configured exit behavior is 'error'\n * and either the thread or run tool call limit has been exceeded.\n */\nexport class ToolCallLimitExceededError extends Error {\n /**\n * Current thread tool call count.\n */\n threadCount: number;\n /**\n * Current run tool call count.\n */\n runCount: number;\n /**\n * Thread tool call limit (if set).\n */\n threadLimit: number | undefined;\n /**\n * Run tool call limit (if set).\n */\n runLimit: number | undefined;\n /**\n * Tool name being limited (if specific tool), or undefined for all tools.\n */\n toolName: string | undefined;\n\n constructor(\n threadCount: number,\n runCount: number,\n threadLimit: number | undefined,\n runLimit: number | undefined,\n toolName: string | undefined = undefined\n ) {\n const message = buildFinalAIMessageContent(\n threadCount,\n runCount,\n threadLimit,\n runLimit,\n toolName\n );\n super(message);\n\n this.name = \"ToolCallLimitExceededError\";\n this.threadCount = threadCount;\n this.runCount = runCount;\n this.threadLimit = threadLimit;\n this.runLimit = runLimit;\n this.toolName = toolName;\n }\n}\n\n/**\n * Options for configuring the Tool Call Limit middleware.\n */\nexport const ToolCallLimitOptionsSchema = z.object({\n /**\n * Name of the specific tool to limit. If undefined, limits apply to all tools.\n */\n toolName: z.string().optional(),\n /**\n * Maximum number of tool calls allowed per thread.\n * undefined means no limit.\n */\n threadLimit: z.number().optional(),\n /**\n * Maximum number of tool calls allowed per run.\n * undefined means no limit.\n */\n runLimit: z.number().optional(),\n /**\n * What to do when limits are exceeded.\n * - \"continue\": Block exceeded tools with error messages, let other tools continue (default)\n * - \"error\": Raise a ToolCallLimitExceededError exception\n * - \"end\": Stop execution immediately, injecting a ToolMessage and an AI message\n * for the single tool call that exceeded the limit. Raises NotImplementedError\n * if there are multiple tool calls.\n *\n * @default \"continue\"\n */\n exitBehavior: exitBehaviorSchema,\n});\n\nexport type ToolCallLimitConfig = InferInteropZodInput<\n typeof ToolCallLimitOptionsSchema\n>;\n\n/**\n * Middleware state schema to track the number of model calls made at the thread and run level.\n */\nconst stateSchema = z.object({\n threadToolCallCount: z.record(z.string(), z.number()).default({}),\n runToolCallCount: z.record(z.string(), z.number()).default({}),\n});\n\nconst DEFAULT_TOOL_COUNT_KEY = \"__all__\";\n\n/**\n * Middleware that tracks tool call counts and enforces limits.\n *\n * This middleware monitors the number of tool calls made during agent execution\n * and can terminate the agent when specified limits are reached. It supports\n * both thread-level and run-level call counting with configurable exit behaviors.\n *\n * Thread-level: The middleware counts all tool calls in the entire message history\n * and persists this count across multiple runs (invocations) of the agent.\n *\n * Run-level: The middleware counts tool calls made after the last HumanMessage,\n * representing the current run (invocation) of the agent.\n *\n * @param options - Configuration options for the middleware\n * @param options.toolName - Name of the specific tool to limit. If undefined, limits apply to all tools.\n * @param options.threadLimit - Maximum number of tool calls allowed per thread. undefined means no limit.\n * @param options.runLimit - Maximum number of tool calls allowed per run. undefined means no limit.\n * @param options.exitBehavior - What to do when limits are exceeded.\n * - \"continue\": Block exceeded tools with error messages, let other tools continue. Model decides when to end. (default)\n * - \"error\": Raise a ToolCallLimitExceededError exception\n * - \"end\": Stop execution immediately with a ToolMessage + AI message for the single tool call that exceeded the limit. Raises NotImplementedError if there are multiple tool calls.\n *\n * @throws {Error} If both limits are undefined, if exitBehavior is invalid, or if runLimit exceeds threadLimit.\n * @throws {NotImplementedError} If exitBehavior is \"end\" and there are multiple tool calls.\n *\n * @example Continue execution with blocked tools (default)\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * // Block exceeded tools but let other tools and model continue\n * const limiter = toolCallLimitMiddleware({\n * threadLimit: 20,\n * runLimit: 10,\n * exitBehavior: \"continue\", // default\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n * ```\n *\n * @example Stop immediately when limit exceeded\n * ```ts\n * // End execution immediately with an AI message\n * const limiter = toolCallLimitMiddleware({\n * runLimit: 5,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n * ```\n *\n * @example Raise exception on limit\n * ```ts\n * // Strict limit with exception handling\n * const limiter = toolCallLimitMiddleware({\n * toolName: \"search\",\n * threadLimit: 5,\n * exitBehavior: \"error\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [limiter]\n * });\n *\n * try {\n * const result = await agent.invoke({ messages: [new HumanMessage(\"Task\")] });\n * } catch (error) {\n * if (error instanceof ToolCallLimitExceededError) {\n * console.log(`Search limit exceeded: ${error}`);\n * }\n * }\n * ```\n */\nexport function toolCallLimitMiddleware(options: ToolCallLimitConfig) {\n /**\n * Validate that at least one limit is specified\n */\n if (options.threadLimit === undefined && options.runLimit === undefined) {\n throw new Error(\n \"At least one limit must be specified (threadLimit or runLimit)\"\n );\n }\n\n /**\n * Validate exitBehavior (Zod schema already validates, but provide helpful error)\n */\n const exitBehavior = options.exitBehavior ?? DEFAULT_EXIT_BEHAVIOR;\n const parseResult = exitBehaviorSchema.safeParse(exitBehavior);\n if (!parseResult.success) {\n throw new Error(z4.prettifyError(parseResult.error).slice(2));\n }\n\n /**\n * Validate that runLimit does not exceed threadLimit\n */\n if (\n options.threadLimit !== undefined &&\n options.runLimit !== undefined &&\n options.runLimit > options.threadLimit\n ) {\n throw new Error(\n `runLimit (${options.runLimit}) cannot exceed threadLimit (${options.threadLimit}). ` +\n \"The run limit should be less than or equal to the thread limit.\"\n );\n }\n\n /**\n * Generate the middleware name based on the tool name\n */\n const middlewareName = options.toolName\n ? `ToolCallLimitMiddleware[${options.toolName}]`\n : \"ToolCallLimitMiddleware\";\n\n return createMiddleware({\n name: middlewareName,\n stateSchema,\n afterModel: {\n canJumpTo: [\"end\"],\n hook: (state) => {\n /**\n * Get the last AI message to check for tool calls\n */\n const lastAIMessage = [...state.messages]\n .reverse()\n .find(AIMessage.isInstance);\n\n if (!lastAIMessage || !lastAIMessage.tool_calls) {\n return undefined;\n }\n\n /**\n * Helper to check if limit would be exceeded by one more call\n */\n const wouldExceedLimit = (\n threadCount: number,\n runCount: number\n ): boolean => {\n return (\n (options.threadLimit !== undefined &&\n threadCount + 1 > options.threadLimit) ||\n (options.runLimit !== undefined && runCount + 1 > options.runLimit)\n );\n };\n\n /**\n * Helper to check if a tool call matches our filter\n */\n const matchesToolFilter = (toolCall: { name?: string }): boolean => {\n return (\n options.toolName === undefined || toolCall.name === options.toolName\n );\n };\n\n /**\n * Separate tool calls into allowed and blocked based on limits\n */\n const separateToolCalls = (\n toolCalls: ToolCall[],\n threadCount: number,\n runCount: number\n ): {\n allowed: ToolCall[];\n blocked: ToolCall[];\n finalThreadCount: number;\n finalRunCount: number;\n } => {\n const allowed: ToolCall[] = [];\n const blocked: ToolCall[] = [];\n let tempThreadCount = threadCount;\n let tempRunCount = runCount;\n\n for (const toolCall of toolCalls) {\n if (!matchesToolFilter(toolCall)) {\n // Tool call doesn't match our filter, skip it\n continue;\n }\n\n if (wouldExceedLimit(tempThreadCount, tempRunCount)) {\n blocked.push(toolCall);\n } else {\n allowed.push(toolCall);\n tempThreadCount += 1;\n tempRunCount += 1;\n }\n }\n\n return {\n allowed,\n blocked,\n finalThreadCount: tempThreadCount,\n finalRunCount: tempRunCount + blocked.length,\n };\n };\n\n /**\n * Get the count key for this middleware instance\n */\n const countKey = options.toolName ?? DEFAULT_TOOL_COUNT_KEY;\n\n /**\n * Get current counts\n */\n const threadCounts = { ...(state.threadToolCallCount ?? {}) };\n const runCounts = { ...(state.runToolCallCount ?? {}) };\n const currentThreadCount = threadCounts[countKey] ?? 0;\n const currentRunCount = runCounts[countKey] ?? 0;\n\n /**\n * Separate tool calls into allowed and blocked\n */\n const { allowed, blocked, finalThreadCount, finalRunCount } =\n separateToolCalls(\n lastAIMessage.tool_calls,\n currentThreadCount,\n currentRunCount\n );\n\n /**\n * Update counts:\n * - Thread count includes only allowed calls (blocked calls don't count towards thread-level tracking)\n * - Run count includes blocked calls since they were attempted in this run\n */\n threadCounts[countKey] = finalThreadCount;\n runCounts[countKey] = finalRunCount;\n\n /**\n * If no tool calls are blocked, just update counts\n */\n if (blocked.length === 0) {\n if (allowed.length > 0) {\n return {\n threadToolCallCount: threadCounts,\n runToolCallCount: runCounts,\n };\n }\n return undefined;\n }\n\n /**\n * Handle different exit behaviors\n */\n if (exitBehavior === \"error\") {\n // Use hypothetical thread count to show which limit was exceeded\n const hypotheticalThreadCount = finalThreadCount + blocked.length;\n throw new ToolCallLimitExceededError(\n hypotheticalThreadCount,\n finalRunCount,\n options.threadLimit,\n options.runLimit,\n options.toolName\n );\n }\n\n /**\n * Build tool message content (sent to model - no thread/run details)\n */\n const toolMsgContent = buildToolMessageContent(options.toolName);\n\n /**\n * Inject artificial error ToolMessages for blocked tool calls\n */\n const artificialMessages: Array<ToolMessage | AIMessage> = blocked.map(\n (toolCall) =>\n new ToolMessage({\n content: toolMsgContent,\n tool_call_id: toolCall.id!,\n name: toolCall.name,\n status: \"error\",\n })\n );\n\n if (exitBehavior === \"end\") {\n /**\n * Check if there are tool calls to other tools that would continue executing\n * For tool-specific limiters: check for calls to other tools\n * For global limiters: check if there are multiple different tool types\n */\n let otherTools: ToolCall[] = [];\n if (options.toolName !== undefined) {\n /**\n * Tool-specific limiter: check for calls to other tools\n */\n otherTools = lastAIMessage.tool_calls.filter(\n (tc) => tc.name !== options.toolName\n );\n } else {\n /**\n * Global limiter: check if there are multiple different tool types\n * If there are allowed calls, those would execute\n * But even if all are blocked, we can't handle multiple tool types with \"end\"\n */\n const uniqueToolNames = new Set(\n lastAIMessage.tool_calls.map((tc) => tc.name).filter(Boolean)\n );\n if (uniqueToolNames.size > 1) {\n /**\n * Multiple different tool types - use allowed calls to show which ones\n */\n otherTools =\n allowed.length > 0 ? allowed : lastAIMessage.tool_calls;\n }\n }\n\n if (otherTools.length > 0) {\n const toolNames = Array.from(\n new Set(otherTools.map((tc) => tc.name).filter(Boolean))\n ).join(\", \");\n throw new Error(\n `Cannot end execution with other tool calls pending. Found calls to: ${toolNames}. Use 'continue' or 'error' behavior instead.`\n );\n }\n\n /**\n * Build final AI message content (displayed to user - includes thread/run details)\n * Use hypothetical thread count (what it would have been if call wasn't blocked)\n * to show which limit was actually exceeded\n */\n const hypotheticalThreadCount = finalThreadCount + blocked.length;\n const finalMsgContent = buildFinalAIMessageContent(\n hypotheticalThreadCount,\n finalRunCount,\n options.threadLimit,\n options.runLimit,\n options.toolName\n );\n artificialMessages.push(new AIMessage(finalMsgContent));\n\n return {\n threadToolCallCount: threadCounts,\n runToolCallCount: runCounts,\n jumpTo: \"end\" as const,\n messages: artificialMessages,\n };\n }\n\n /**\n * For exit_behavior=\"continue\", return error messages to block exceeded tools\n */\n return {\n threadToolCallCount: threadCounts,\n runToolCallCount: runCounts,\n messages: artificialMessages,\n };\n },\n },\n /**\n * reset the run tool call count after the agent execution completes\n */\n afterAgent: () => ({\n runToolCallCount: {},\n }),\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require("../../_virtual/_rolldown/runtime.cjs");
|
|
2
2
|
let _langchain_langgraph = require("@langchain/langgraph");
|
|
3
3
|
let _langchain_core_utils_types = require("@langchain/core/utils/types");
|
|
4
|
-
let
|
|
4
|
+
let zod_v4 = require("zod/v4");
|
|
5
5
|
//#region src/agents/nodes/utils.ts
|
|
6
6
|
/**
|
|
7
7
|
* Helper function to initialize middleware state defaults.
|
|
@@ -22,7 +22,7 @@ async function initializeMiddlewareStates(middlewareList, state) {
|
|
|
22
22
|
const zodShape = {};
|
|
23
23
|
for (const [key, field] of Object.entries(middleware.stateSchema.fields)) if (_langchain_langgraph.ReducedValue.isInstance(field)) zodShape[key] = field.inputSchema || field.valueSchema;
|
|
24
24
|
else zodShape[key] = field;
|
|
25
|
-
zodSchema =
|
|
25
|
+
zodSchema = zod_v4.z.object(zodShape);
|
|
26
26
|
}
|
|
27
27
|
const parseResult = await (0, _langchain_core_utils_types.interopSafeParseAsync)((0, _langchain_core_utils_types.interopZodObjectMakeFieldsOptional)(zodSchema, (key) => key.startsWith("_")), state);
|
|
28
28
|
if (parseResult.success) {
|
|
@@ -46,20 +46,20 @@ async function initializeMiddlewareStates(middlewareList, state) {
|
|
|
46
46
|
*/
|
|
47
47
|
function derivePrivateState(stateSchema) {
|
|
48
48
|
const builtInStateSchema = {
|
|
49
|
-
messages:
|
|
50
|
-
structuredResponse:
|
|
49
|
+
messages: zod_v4.z.custom(() => []),
|
|
50
|
+
structuredResponse: zod_v4.z.any().optional()
|
|
51
51
|
};
|
|
52
|
-
if (!stateSchema) return
|
|
52
|
+
if (!stateSchema) return zod_v4.z.object(builtInStateSchema);
|
|
53
53
|
let shape;
|
|
54
54
|
if (_langchain_langgraph.StateSchema.isInstance(stateSchema)) {
|
|
55
55
|
shape = {};
|
|
56
56
|
for (const [key, field] of Object.entries(stateSchema.fields)) if (_langchain_langgraph.ReducedValue.isInstance(field)) shape[key] = field.inputSchema || field.valueSchema;
|
|
57
57
|
else shape[key] = field;
|
|
58
|
-
} else shape = stateSchema
|
|
58
|
+
} else shape = (0, _langchain_core_utils_types.getInteropZodObjectShape)(stateSchema);
|
|
59
59
|
const privateShape = { ...builtInStateSchema };
|
|
60
60
|
for (const [key, value] of Object.entries(shape)) if (key.startsWith("_")) privateShape[key] = value.optional();
|
|
61
61
|
else privateShape[key] = value;
|
|
62
|
-
return
|
|
62
|
+
return zod_v4.z.object(privateShape);
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
65
|
* Converts any supported schema type (ZodObject, StateSchema, AnnotationRoot) to a partial Zod object.
|
|
@@ -76,11 +76,11 @@ function toPartialZodObject(schema) {
|
|
|
76
76
|
let fieldSchema;
|
|
77
77
|
if (_langchain_langgraph.ReducedValue.isInstance(field)) fieldSchema = field.inputSchema || field.valueSchema;
|
|
78
78
|
else fieldSchema = field;
|
|
79
|
-
partialShape[key] = (0, _langchain_core_utils_types.isZodSchemaV4)(fieldSchema) ? fieldSchema.optional() :
|
|
79
|
+
partialShape[key] = (0, _langchain_core_utils_types.isZodSchemaV4)(fieldSchema) ? fieldSchema.optional() : zod_v4.z.any().optional();
|
|
80
80
|
}
|
|
81
|
-
return
|
|
81
|
+
return zod_v4.z.object(partialShape);
|
|
82
82
|
}
|
|
83
|
-
return
|
|
83
|
+
return zod_v4.z.object({});
|
|
84
84
|
}
|
|
85
85
|
function parseJumpToTarget(target) {
|
|
86
86
|
if (!target) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.cjs","names":["StateSchema","ReducedValue","z","END"],"sources":["../../../src/agents/nodes/utils.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { z } from \"zod\";\nimport { type BaseMessage } from \"@langchain/core/messages\";\nimport {\n interopSafeParseAsync,\n interopZodObjectMakeFieldsOptional,\n interopZodObjectPartial,\n isInteropZodObject,\n isZodSchemaV4,\n type InteropZodObject,\n} from \"@langchain/core/utils/types\";\nimport type { StateDefinitionInit } from \"@langchain/langgraph\";\nimport { END, StateSchema, ReducedValue } from \"@langchain/langgraph\";\n\nimport type { JumpTo } from \"../types.js\";\nimport type { AgentMiddleware } from \"../middleware/types.js\";\n\n/**\n * Helper function to initialize middleware state defaults.\n * This is used to ensure all middleware state properties are initialized.\n *\n * Private properties (starting with _) are automatically made optional since\n * users cannot provide them when invoking the agent.\n */\nexport async function initializeMiddlewareStates(\n middlewareList: readonly AgentMiddleware[],\n state: unknown\n): Promise<Record<string, any>> {\n const middlewareStates: Record<string, any> = {};\n\n for (const middleware of middlewareList) {\n /**\n * skip middleware if it doesn't have a state schema\n */\n if (!middleware.stateSchema) {\n continue;\n }\n\n // Convert StateSchema to Zod object if needed\n let zodSchema = middleware.stateSchema;\n if (StateSchema.isInstance(middleware.stateSchema)) {\n const zodShape: Record<string, any> = {};\n for (const [key, field] of Object.entries(\n middleware.stateSchema.fields\n )) {\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n zodShape[key] = field.inputSchema || field.valueSchema;\n } else {\n zodShape[key] = field;\n }\n }\n zodSchema = z.object(zodShape);\n }\n\n // Create a modified schema where private properties are optional\n const modifiedSchema = interopZodObjectMakeFieldsOptional(\n zodSchema,\n (key) => key.startsWith(\"_\")\n );\n\n // Use safeParse with the modified schema\n const parseResult = await interopSafeParseAsync(modifiedSchema, state);\n if (parseResult.success) {\n Object.assign(middlewareStates, parseResult.data);\n continue;\n }\n\n /**\n * If safeParse fails, there are required public fields missing.\n * Note: Zod v3 uses message \"Required\", Zod v4 uses \"Invalid input: expected X, received undefined\"\n */\n const requiredFields = parseResult.error.issues\n .filter((issue) => issue.code === \"invalid_type\")\n .map((issue) => ` - ${issue.path.join(\".\")}: Required`)\n .join(\"\\n\");\n\n throw new Error(\n `Middleware \"${middleware.name}\" has required state fields that must be initialized:\\n` +\n `${requiredFields}\\n\\n` +\n `To fix this, either:\\n` +\n `1. Provide default values in your middleware's state schema using .default():\\n` +\n ` stateSchema: z.object({\\n` +\n ` myField: z.string().default(\"default value\")\\n` +\n ` })\\n\\n` +\n `2. Or make the fields optional using .optional():\\n` +\n ` stateSchema: z.object({\\n` +\n ` myField: z.string().optional()\\n` +\n ` })\\n\\n` +\n `3. Or ensure you pass these values when invoking the agent:\\n` +\n ` agent.invoke({\\n` +\n ` messages: [...],\\n` +\n ` ${parseResult.error.issues[0]?.path.join(\".\")}: \"value\"\\n` +\n ` })`\n );\n }\n\n return middlewareStates;\n}\n\n/**\n * Users can define private and public state for a middleware. Private state properties start with an underscore.\n * This function will return the private state properties from the state schema, making all of them optional.\n * @param stateSchema - The middleware state schema\n * @returns A new schema containing only the private properties (underscore-prefixed), all made optional\n */\nexport function derivePrivateState(\n stateSchema?: z.ZodObject<z.ZodRawShape> | StateSchema<any>\n): z.ZodObject<z.ZodRawShape> {\n const builtInStateSchema = {\n messages: z.custom<BaseMessage[]>(() => []),\n // Include optional structuredResponse so after_agent hooks can access/modify it\n structuredResponse: z.any().optional(),\n };\n\n if (!stateSchema) {\n return z.object(builtInStateSchema);\n }\n\n // Extract shape from either StateSchema or Zod object\n let shape: Record<string, any>;\n if (StateSchema.isInstance(stateSchema)) {\n // For StateSchema, extract Zod schemas from fields\n shape = {};\n for (const [key, field] of Object.entries(stateSchema.fields)) {\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n shape[key] = field.inputSchema || field.valueSchema;\n } else {\n shape[key] = field;\n }\n }\n } else {\n shape = stateSchema.shape;\n }\n\n const privateShape: Record<string, any> = { ...builtInStateSchema };\n\n // Filter properties that start with underscore and make them optional\n for (const [key, value] of Object.entries(shape)) {\n if (key.startsWith(\"_\")) {\n // Make the private property optional\n privateShape[key] = value.optional();\n } else {\n privateShape[key] = value;\n }\n }\n\n // Return a new schema with only private properties (all optional)\n return z.object(privateShape);\n}\n\n/**\n * Converts any supported schema type (ZodObject, StateSchema, AnnotationRoot) to a partial Zod object.\n * This is useful for parsing state loosely where all fields are optional.\n *\n * @param schema - The schema to convert (InteropZodObject, StateSchema, or AnnotationRoot)\n * @returns A partial Zod object schema where all fields are optional\n */\nexport function toPartialZodObject(\n schema: StateDefinitionInit\n): InteropZodObject {\n // Handle ZodObject directly\n if (isInteropZodObject(schema)) {\n return interopZodObjectPartial(schema);\n }\n\n // Handle StateSchema: convert fields to Zod shape, then make partial\n if (StateSchema.isInstance(schema)) {\n const partialShape: Record<string, any> = {};\n for (const [key, field] of Object.entries(schema.fields)) {\n let fieldSchema: unknown;\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n fieldSchema = field.inputSchema || field.valueSchema;\n } else {\n fieldSchema = field;\n }\n // Only call .optional() on Zod v4 schemas, otherwise use z.any()\n partialShape[key] = isZodSchemaV4(fieldSchema)\n ? (fieldSchema as any).optional()\n : z.any().optional();\n }\n return z.object(partialShape);\n }\n\n // Fallback: return empty object schema\n return z.object({});\n}\n\n/**\n * Parse `jumpTo` target from user facing labels to a LangGraph node names\n */\nexport function parseJumpToTarget(target: string): JumpTo;\nexport function parseJumpToTarget(target?: string): JumpTo | undefined {\n if (!target) {\n return undefined;\n }\n\n /**\n * if target is already a valid jump target, return it\n */\n if ([\"model_request\", \"tools\", END].includes(target)) {\n return target as JumpTo;\n }\n\n if (target === \"model\") {\n return \"model_request\";\n }\n if (target === \"tools\") {\n return \"tools\";\n }\n if (target === \"end\") {\n return END;\n }\n\n throw new Error(\n `Invalid jump target: ${target}, must be \"model\", \"tools\" or \"end\".`\n );\n}\n\n/**\n * TypeScript currently doesn't support types for `AbortSignal.any`\n * @see https://github.com/microsoft/TypeScript/issues/60695\n */\ndeclare const AbortSignal: {\n any(signals: AbortSignal[]): AbortSignal;\n};\n\n/**\n * `config` always contains a signal from LangGraphs Pregel class.\n * To ensure we acknowledge the abort signal from the user, we merge it\n * with the signal from the ToolNode.\n *\n * @param signals - The signals to merge.\n * @returns The merged signal.\n */\nexport function mergeAbortSignals(\n ...signals: (AbortSignal | undefined)[]\n): AbortSignal {\n return AbortSignal.any(\n signals.filter(\n (maybeSignal): maybeSignal is AbortSignal =>\n maybeSignal !== null &&\n maybeSignal !== undefined &&\n typeof maybeSignal === \"object\" &&\n \"aborted\" in maybeSignal &&\n typeof maybeSignal.aborted === \"boolean\"\n )\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.cjs","names":["StateSchema","ReducedValue","z","END"],"sources":["../../../src/agents/nodes/utils.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { z } from \"zod/v4\";\nimport { type BaseMessage } from \"@langchain/core/messages\";\nimport {\n getInteropZodObjectShape,\n interopSafeParseAsync,\n interopZodObjectMakeFieldsOptional,\n interopZodObjectPartial,\n isInteropZodObject,\n isZodSchemaV4,\n type InteropZodObject,\n} from \"@langchain/core/utils/types\";\nimport type { StateDefinitionInit } from \"@langchain/langgraph\";\nimport { END, StateSchema, ReducedValue } from \"@langchain/langgraph\";\n\nimport type { JumpTo } from \"../types.js\";\nimport type { AgentMiddleware } from \"../middleware/types.js\";\n\n/**\n * Helper function to initialize middleware state defaults.\n * This is used to ensure all middleware state properties are initialized.\n *\n * Private properties (starting with _) are automatically made optional since\n * users cannot provide them when invoking the agent.\n */\nexport async function initializeMiddlewareStates(\n middlewareList: readonly AgentMiddleware[],\n state: unknown\n): Promise<Record<string, any>> {\n const middlewareStates: Record<string, any> = {};\n\n for (const middleware of middlewareList) {\n /**\n * skip middleware if it doesn't have a state schema\n */\n if (!middleware.stateSchema) {\n continue;\n }\n\n // Convert StateSchema to Zod object if needed\n let zodSchema = middleware.stateSchema;\n if (StateSchema.isInstance(middleware.stateSchema)) {\n const zodShape: Record<string, any> = {};\n for (const [key, field] of Object.entries(\n middleware.stateSchema.fields\n )) {\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n zodShape[key] = field.inputSchema || field.valueSchema;\n } else {\n zodShape[key] = field;\n }\n }\n zodSchema = z.object(zodShape);\n }\n\n // Create a modified schema where private properties are optional\n const modifiedSchema = interopZodObjectMakeFieldsOptional(\n zodSchema,\n (key) => key.startsWith(\"_\")\n );\n\n // Use safeParse with the modified schema\n const parseResult = await interopSafeParseAsync(modifiedSchema, state);\n if (parseResult.success) {\n Object.assign(middlewareStates, parseResult.data);\n continue;\n }\n\n /**\n * If safeParse fails, there are required public fields missing.\n * Note: Zod v3 uses message \"Required\", Zod v4 uses \"Invalid input: expected X, received undefined\"\n */\n const requiredFields = parseResult.error.issues\n .filter((issue) => issue.code === \"invalid_type\")\n .map((issue) => ` - ${issue.path.join(\".\")}: Required`)\n .join(\"\\n\");\n\n throw new Error(\n `Middleware \"${middleware.name}\" has required state fields that must be initialized:\\n` +\n `${requiredFields}\\n\\n` +\n `To fix this, either:\\n` +\n `1. Provide default values in your middleware's state schema using .default():\\n` +\n ` stateSchema: z.object({\\n` +\n ` myField: z.string().default(\"default value\")\\n` +\n ` })\\n\\n` +\n `2. Or make the fields optional using .optional():\\n` +\n ` stateSchema: z.object({\\n` +\n ` myField: z.string().optional()\\n` +\n ` })\\n\\n` +\n `3. Or ensure you pass these values when invoking the agent:\\n` +\n ` agent.invoke({\\n` +\n ` messages: [...],\\n` +\n ` ${parseResult.error.issues[0]?.path.join(\".\")}: \"value\"\\n` +\n ` })`\n );\n }\n\n return middlewareStates;\n}\n\n/**\n * Users can define private and public state for a middleware. Private state properties start with an underscore.\n * This function will return the private state properties from the state schema, making all of them optional.\n * @param stateSchema - The middleware state schema\n * @returns A new schema containing only the private properties (underscore-prefixed), all made optional\n */\nexport function derivePrivateState(\n stateSchema?: InteropZodObject | StateSchema<any>\n): InteropZodObject {\n const builtInStateSchema = {\n messages: z.custom<BaseMessage[]>(() => []),\n // Include optional structuredResponse so after_agent hooks can access/modify it\n structuredResponse: z.any().optional(),\n };\n\n if (!stateSchema) {\n return z.object(builtInStateSchema);\n }\n\n // Extract shape from either StateSchema or Zod object\n let shape: Record<string, any>;\n if (StateSchema.isInstance(stateSchema)) {\n // For StateSchema, extract Zod schemas from fields\n shape = {};\n for (const [key, field] of Object.entries(stateSchema.fields)) {\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n shape[key] = field.inputSchema || field.valueSchema;\n } else {\n shape[key] = field;\n }\n }\n } else {\n shape = getInteropZodObjectShape(stateSchema);\n }\n\n const privateShape: Record<string, any> = { ...builtInStateSchema };\n\n // Filter properties that start with underscore and make them optional\n for (const [key, value] of Object.entries(shape)) {\n if (key.startsWith(\"_\")) {\n // Make the private property optional\n privateShape[key] = value.optional();\n } else {\n privateShape[key] = value;\n }\n }\n\n // Return a new schema with only private properties (all optional)\n return z.object(privateShape);\n}\n\n/**\n * Converts any supported schema type (ZodObject, StateSchema, AnnotationRoot) to a partial Zod object.\n * This is useful for parsing state loosely where all fields are optional.\n *\n * @param schema - The schema to convert (InteropZodObject, StateSchema, or AnnotationRoot)\n * @returns A partial Zod object schema where all fields are optional\n */\nexport function toPartialZodObject(\n schema: StateDefinitionInit\n): InteropZodObject {\n // Handle ZodObject directly\n if (isInteropZodObject(schema)) {\n return interopZodObjectPartial(schema);\n }\n\n // Handle StateSchema: convert fields to Zod shape, then make partial\n if (StateSchema.isInstance(schema)) {\n const partialShape: Record<string, any> = {};\n for (const [key, field] of Object.entries(schema.fields)) {\n let fieldSchema: unknown;\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n fieldSchema = field.inputSchema || field.valueSchema;\n } else {\n fieldSchema = field;\n }\n // Only call .optional() on Zod v4 schemas, otherwise use z.any()\n partialShape[key] = isZodSchemaV4(fieldSchema)\n ? (fieldSchema as any).optional()\n : z.any().optional();\n }\n return z.object(partialShape);\n }\n\n // Fallback: return empty object schema\n return z.object({});\n}\n\n/**\n * Parse `jumpTo` target from user facing labels to a LangGraph node names\n */\nexport function parseJumpToTarget(target: string): JumpTo;\nexport function parseJumpToTarget(target?: string): JumpTo | undefined {\n if (!target) {\n return undefined;\n }\n\n /**\n * if target is already a valid jump target, return it\n */\n if ([\"model_request\", \"tools\", END].includes(target)) {\n return target as JumpTo;\n }\n\n if (target === \"model\") {\n return \"model_request\";\n }\n if (target === \"tools\") {\n return \"tools\";\n }\n if (target === \"end\") {\n return END;\n }\n\n throw new Error(\n `Invalid jump target: ${target}, must be \"model\", \"tools\" or \"end\".`\n );\n}\n\n/**\n * TypeScript currently doesn't support types for `AbortSignal.any`\n * @see https://github.com/microsoft/TypeScript/issues/60695\n */\ndeclare const AbortSignal: {\n any(signals: AbortSignal[]): AbortSignal;\n};\n\n/**\n * `config` always contains a signal from LangGraphs Pregel class.\n * To ensure we acknowledge the abort signal from the user, we merge it\n * with the signal from the ToolNode.\n *\n * @param signals - The signals to merge.\n * @returns The merged signal.\n */\nexport function mergeAbortSignals(\n ...signals: (AbortSignal | undefined)[]\n): AbortSignal {\n return AbortSignal.any(\n signals.filter(\n (maybeSignal): maybeSignal is AbortSignal =>\n maybeSignal !== null &&\n maybeSignal !== undefined &&\n typeof maybeSignal === \"object\" &&\n \"aborted\" in maybeSignal &&\n typeof maybeSignal.aborted === \"boolean\"\n )\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { END, ReducedValue, StateSchema } from "@langchain/langgraph";
|
|
2
|
-
import { interopSafeParseAsync, interopZodObjectMakeFieldsOptional, interopZodObjectPartial, isInteropZodObject, isZodSchemaV4 } from "@langchain/core/utils/types";
|
|
3
|
-
import { z } from "zod";
|
|
2
|
+
import { getInteropZodObjectShape, interopSafeParseAsync, interopZodObjectMakeFieldsOptional, interopZodObjectPartial, isInteropZodObject, isZodSchemaV4 } from "@langchain/core/utils/types";
|
|
3
|
+
import { z } from "zod/v4";
|
|
4
4
|
//#region src/agents/nodes/utils.ts
|
|
5
5
|
/**
|
|
6
6
|
* Helper function to initialize middleware state defaults.
|
|
@@ -54,7 +54,7 @@ function derivePrivateState(stateSchema) {
|
|
|
54
54
|
shape = {};
|
|
55
55
|
for (const [key, field] of Object.entries(stateSchema.fields)) if (ReducedValue.isInstance(field)) shape[key] = field.inputSchema || field.valueSchema;
|
|
56
56
|
else shape[key] = field;
|
|
57
|
-
} else shape = stateSchema
|
|
57
|
+
} else shape = getInteropZodObjectShape(stateSchema);
|
|
58
58
|
const privateShape = { ...builtInStateSchema };
|
|
59
59
|
for (const [key, value] of Object.entries(shape)) if (key.startsWith("_")) privateShape[key] = value.optional();
|
|
60
60
|
else privateShape[key] = value;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../../src/agents/nodes/utils.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { z } from \"zod\";\nimport { type BaseMessage } from \"@langchain/core/messages\";\nimport {\n interopSafeParseAsync,\n interopZodObjectMakeFieldsOptional,\n interopZodObjectPartial,\n isInteropZodObject,\n isZodSchemaV4,\n type InteropZodObject,\n} from \"@langchain/core/utils/types\";\nimport type { StateDefinitionInit } from \"@langchain/langgraph\";\nimport { END, StateSchema, ReducedValue } from \"@langchain/langgraph\";\n\nimport type { JumpTo } from \"../types.js\";\nimport type { AgentMiddleware } from \"../middleware/types.js\";\n\n/**\n * Helper function to initialize middleware state defaults.\n * This is used to ensure all middleware state properties are initialized.\n *\n * Private properties (starting with _) are automatically made optional since\n * users cannot provide them when invoking the agent.\n */\nexport async function initializeMiddlewareStates(\n middlewareList: readonly AgentMiddleware[],\n state: unknown\n): Promise<Record<string, any>> {\n const middlewareStates: Record<string, any> = {};\n\n for (const middleware of middlewareList) {\n /**\n * skip middleware if it doesn't have a state schema\n */\n if (!middleware.stateSchema) {\n continue;\n }\n\n // Convert StateSchema to Zod object if needed\n let zodSchema = middleware.stateSchema;\n if (StateSchema.isInstance(middleware.stateSchema)) {\n const zodShape: Record<string, any> = {};\n for (const [key, field] of Object.entries(\n middleware.stateSchema.fields\n )) {\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n zodShape[key] = field.inputSchema || field.valueSchema;\n } else {\n zodShape[key] = field;\n }\n }\n zodSchema = z.object(zodShape);\n }\n\n // Create a modified schema where private properties are optional\n const modifiedSchema = interopZodObjectMakeFieldsOptional(\n zodSchema,\n (key) => key.startsWith(\"_\")\n );\n\n // Use safeParse with the modified schema\n const parseResult = await interopSafeParseAsync(modifiedSchema, state);\n if (parseResult.success) {\n Object.assign(middlewareStates, parseResult.data);\n continue;\n }\n\n /**\n * If safeParse fails, there are required public fields missing.\n * Note: Zod v3 uses message \"Required\", Zod v4 uses \"Invalid input: expected X, received undefined\"\n */\n const requiredFields = parseResult.error.issues\n .filter((issue) => issue.code === \"invalid_type\")\n .map((issue) => ` - ${issue.path.join(\".\")}: Required`)\n .join(\"\\n\");\n\n throw new Error(\n `Middleware \"${middleware.name}\" has required state fields that must be initialized:\\n` +\n `${requiredFields}\\n\\n` +\n `To fix this, either:\\n` +\n `1. Provide default values in your middleware's state schema using .default():\\n` +\n ` stateSchema: z.object({\\n` +\n ` myField: z.string().default(\"default value\")\\n` +\n ` })\\n\\n` +\n `2. Or make the fields optional using .optional():\\n` +\n ` stateSchema: z.object({\\n` +\n ` myField: z.string().optional()\\n` +\n ` })\\n\\n` +\n `3. Or ensure you pass these values when invoking the agent:\\n` +\n ` agent.invoke({\\n` +\n ` messages: [...],\\n` +\n ` ${parseResult.error.issues[0]?.path.join(\".\")}: \"value\"\\n` +\n ` })`\n );\n }\n\n return middlewareStates;\n}\n\n/**\n * Users can define private and public state for a middleware. Private state properties start with an underscore.\n * This function will return the private state properties from the state schema, making all of them optional.\n * @param stateSchema - The middleware state schema\n * @returns A new schema containing only the private properties (underscore-prefixed), all made optional\n */\nexport function derivePrivateState(\n stateSchema?: z.ZodObject<z.ZodRawShape> | StateSchema<any>\n): z.ZodObject<z.ZodRawShape> {\n const builtInStateSchema = {\n messages: z.custom<BaseMessage[]>(() => []),\n // Include optional structuredResponse so after_agent hooks can access/modify it\n structuredResponse: z.any().optional(),\n };\n\n if (!stateSchema) {\n return z.object(builtInStateSchema);\n }\n\n // Extract shape from either StateSchema or Zod object\n let shape: Record<string, any>;\n if (StateSchema.isInstance(stateSchema)) {\n // For StateSchema, extract Zod schemas from fields\n shape = {};\n for (const [key, field] of Object.entries(stateSchema.fields)) {\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n shape[key] = field.inputSchema || field.valueSchema;\n } else {\n shape[key] = field;\n }\n }\n } else {\n shape = stateSchema.shape;\n }\n\n const privateShape: Record<string, any> = { ...builtInStateSchema };\n\n // Filter properties that start with underscore and make them optional\n for (const [key, value] of Object.entries(shape)) {\n if (key.startsWith(\"_\")) {\n // Make the private property optional\n privateShape[key] = value.optional();\n } else {\n privateShape[key] = value;\n }\n }\n\n // Return a new schema with only private properties (all optional)\n return z.object(privateShape);\n}\n\n/**\n * Converts any supported schema type (ZodObject, StateSchema, AnnotationRoot) to a partial Zod object.\n * This is useful for parsing state loosely where all fields are optional.\n *\n * @param schema - The schema to convert (InteropZodObject, StateSchema, or AnnotationRoot)\n * @returns A partial Zod object schema where all fields are optional\n */\nexport function toPartialZodObject(\n schema: StateDefinitionInit\n): InteropZodObject {\n // Handle ZodObject directly\n if (isInteropZodObject(schema)) {\n return interopZodObjectPartial(schema);\n }\n\n // Handle StateSchema: convert fields to Zod shape, then make partial\n if (StateSchema.isInstance(schema)) {\n const partialShape: Record<string, any> = {};\n for (const [key, field] of Object.entries(schema.fields)) {\n let fieldSchema: unknown;\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n fieldSchema = field.inputSchema || field.valueSchema;\n } else {\n fieldSchema = field;\n }\n // Only call .optional() on Zod v4 schemas, otherwise use z.any()\n partialShape[key] = isZodSchemaV4(fieldSchema)\n ? (fieldSchema as any).optional()\n : z.any().optional();\n }\n return z.object(partialShape);\n }\n\n // Fallback: return empty object schema\n return z.object({});\n}\n\n/**\n * Parse `jumpTo` target from user facing labels to a LangGraph node names\n */\nexport function parseJumpToTarget(target: string): JumpTo;\nexport function parseJumpToTarget(target?: string): JumpTo | undefined {\n if (!target) {\n return undefined;\n }\n\n /**\n * if target is already a valid jump target, return it\n */\n if ([\"model_request\", \"tools\", END].includes(target)) {\n return target as JumpTo;\n }\n\n if (target === \"model\") {\n return \"model_request\";\n }\n if (target === \"tools\") {\n return \"tools\";\n }\n if (target === \"end\") {\n return END;\n }\n\n throw new Error(\n `Invalid jump target: ${target}, must be \"model\", \"tools\" or \"end\".`\n );\n}\n\n/**\n * TypeScript currently doesn't support types for `AbortSignal.any`\n * @see https://github.com/microsoft/TypeScript/issues/60695\n */\ndeclare const AbortSignal: {\n any(signals: AbortSignal[]): AbortSignal;\n};\n\n/**\n * `config` always contains a signal from LangGraphs Pregel class.\n * To ensure we acknowledge the abort signal from the user, we merge it\n * with the signal from the ToolNode.\n *\n * @param signals - The signals to merge.\n * @returns The merged signal.\n */\nexport function mergeAbortSignals(\n ...signals: (AbortSignal | undefined)[]\n): AbortSignal {\n return AbortSignal.any(\n signals.filter(\n (maybeSignal): maybeSignal is AbortSignal =>\n maybeSignal !== null &&\n maybeSignal !== undefined &&\n typeof maybeSignal === \"object\" &&\n \"aborted\" in maybeSignal &&\n typeof maybeSignal.aborted === \"boolean\"\n )\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../../../src/agents/nodes/utils.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { z } from \"zod/v4\";\nimport { type BaseMessage } from \"@langchain/core/messages\";\nimport {\n getInteropZodObjectShape,\n interopSafeParseAsync,\n interopZodObjectMakeFieldsOptional,\n interopZodObjectPartial,\n isInteropZodObject,\n isZodSchemaV4,\n type InteropZodObject,\n} from \"@langchain/core/utils/types\";\nimport type { StateDefinitionInit } from \"@langchain/langgraph\";\nimport { END, StateSchema, ReducedValue } from \"@langchain/langgraph\";\n\nimport type { JumpTo } from \"../types.js\";\nimport type { AgentMiddleware } from \"../middleware/types.js\";\n\n/**\n * Helper function to initialize middleware state defaults.\n * This is used to ensure all middleware state properties are initialized.\n *\n * Private properties (starting with _) are automatically made optional since\n * users cannot provide them when invoking the agent.\n */\nexport async function initializeMiddlewareStates(\n middlewareList: readonly AgentMiddleware[],\n state: unknown\n): Promise<Record<string, any>> {\n const middlewareStates: Record<string, any> = {};\n\n for (const middleware of middlewareList) {\n /**\n * skip middleware if it doesn't have a state schema\n */\n if (!middleware.stateSchema) {\n continue;\n }\n\n // Convert StateSchema to Zod object if needed\n let zodSchema = middleware.stateSchema;\n if (StateSchema.isInstance(middleware.stateSchema)) {\n const zodShape: Record<string, any> = {};\n for (const [key, field] of Object.entries(\n middleware.stateSchema.fields\n )) {\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n zodShape[key] = field.inputSchema || field.valueSchema;\n } else {\n zodShape[key] = field;\n }\n }\n zodSchema = z.object(zodShape);\n }\n\n // Create a modified schema where private properties are optional\n const modifiedSchema = interopZodObjectMakeFieldsOptional(\n zodSchema,\n (key) => key.startsWith(\"_\")\n );\n\n // Use safeParse with the modified schema\n const parseResult = await interopSafeParseAsync(modifiedSchema, state);\n if (parseResult.success) {\n Object.assign(middlewareStates, parseResult.data);\n continue;\n }\n\n /**\n * If safeParse fails, there are required public fields missing.\n * Note: Zod v3 uses message \"Required\", Zod v4 uses \"Invalid input: expected X, received undefined\"\n */\n const requiredFields = parseResult.error.issues\n .filter((issue) => issue.code === \"invalid_type\")\n .map((issue) => ` - ${issue.path.join(\".\")}: Required`)\n .join(\"\\n\");\n\n throw new Error(\n `Middleware \"${middleware.name}\" has required state fields that must be initialized:\\n` +\n `${requiredFields}\\n\\n` +\n `To fix this, either:\\n` +\n `1. Provide default values in your middleware's state schema using .default():\\n` +\n ` stateSchema: z.object({\\n` +\n ` myField: z.string().default(\"default value\")\\n` +\n ` })\\n\\n` +\n `2. Or make the fields optional using .optional():\\n` +\n ` stateSchema: z.object({\\n` +\n ` myField: z.string().optional()\\n` +\n ` })\\n\\n` +\n `3. Or ensure you pass these values when invoking the agent:\\n` +\n ` agent.invoke({\\n` +\n ` messages: [...],\\n` +\n ` ${parseResult.error.issues[0]?.path.join(\".\")}: \"value\"\\n` +\n ` })`\n );\n }\n\n return middlewareStates;\n}\n\n/**\n * Users can define private and public state for a middleware. Private state properties start with an underscore.\n * This function will return the private state properties from the state schema, making all of them optional.\n * @param stateSchema - The middleware state schema\n * @returns A new schema containing only the private properties (underscore-prefixed), all made optional\n */\nexport function derivePrivateState(\n stateSchema?: InteropZodObject | StateSchema<any>\n): InteropZodObject {\n const builtInStateSchema = {\n messages: z.custom<BaseMessage[]>(() => []),\n // Include optional structuredResponse so after_agent hooks can access/modify it\n structuredResponse: z.any().optional(),\n };\n\n if (!stateSchema) {\n return z.object(builtInStateSchema);\n }\n\n // Extract shape from either StateSchema or Zod object\n let shape: Record<string, any>;\n if (StateSchema.isInstance(stateSchema)) {\n // For StateSchema, extract Zod schemas from fields\n shape = {};\n for (const [key, field] of Object.entries(stateSchema.fields)) {\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n shape[key] = field.inputSchema || field.valueSchema;\n } else {\n shape[key] = field;\n }\n }\n } else {\n shape = getInteropZodObjectShape(stateSchema);\n }\n\n const privateShape: Record<string, any> = { ...builtInStateSchema };\n\n // Filter properties that start with underscore and make them optional\n for (const [key, value] of Object.entries(shape)) {\n if (key.startsWith(\"_\")) {\n // Make the private property optional\n privateShape[key] = value.optional();\n } else {\n privateShape[key] = value;\n }\n }\n\n // Return a new schema with only private properties (all optional)\n return z.object(privateShape);\n}\n\n/**\n * Converts any supported schema type (ZodObject, StateSchema, AnnotationRoot) to a partial Zod object.\n * This is useful for parsing state loosely where all fields are optional.\n *\n * @param schema - The schema to convert (InteropZodObject, StateSchema, or AnnotationRoot)\n * @returns A partial Zod object schema where all fields are optional\n */\nexport function toPartialZodObject(\n schema: StateDefinitionInit\n): InteropZodObject {\n // Handle ZodObject directly\n if (isInteropZodObject(schema)) {\n return interopZodObjectPartial(schema);\n }\n\n // Handle StateSchema: convert fields to Zod shape, then make partial\n if (StateSchema.isInstance(schema)) {\n const partialShape: Record<string, any> = {};\n for (const [key, field] of Object.entries(schema.fields)) {\n let fieldSchema: unknown;\n if (ReducedValue.isInstance(field)) {\n // For ReducedValue, use inputSchema if available, otherwise valueSchema\n fieldSchema = field.inputSchema || field.valueSchema;\n } else {\n fieldSchema = field;\n }\n // Only call .optional() on Zod v4 schemas, otherwise use z.any()\n partialShape[key] = isZodSchemaV4(fieldSchema)\n ? (fieldSchema as any).optional()\n : z.any().optional();\n }\n return z.object(partialShape);\n }\n\n // Fallback: return empty object schema\n return z.object({});\n}\n\n/**\n * Parse `jumpTo` target from user facing labels to a LangGraph node names\n */\nexport function parseJumpToTarget(target: string): JumpTo;\nexport function parseJumpToTarget(target?: string): JumpTo | undefined {\n if (!target) {\n return undefined;\n }\n\n /**\n * if target is already a valid jump target, return it\n */\n if ([\"model_request\", \"tools\", END].includes(target)) {\n return target as JumpTo;\n }\n\n if (target === \"model\") {\n return \"model_request\";\n }\n if (target === \"tools\") {\n return \"tools\";\n }\n if (target === \"end\") {\n return END;\n }\n\n throw new Error(\n `Invalid jump target: ${target}, must be \"model\", \"tools\" or \"end\".`\n );\n}\n\n/**\n * TypeScript currently doesn't support types for `AbortSignal.any`\n * @see https://github.com/microsoft/TypeScript/issues/60695\n */\ndeclare const AbortSignal: {\n any(signals: AbortSignal[]): AbortSignal;\n};\n\n/**\n * `config` always contains a signal from LangGraphs Pregel class.\n * To ensure we acknowledge the abort signal from the user, we merge it\n * with the signal from the ToolNode.\n *\n * @param signals - The signals to merge.\n * @returns The merged signal.\n */\nexport function mergeAbortSignals(\n ...signals: (AbortSignal | undefined)[]\n): AbortSignal {\n return AbortSignal.any(\n signals.filter(\n (maybeSignal): maybeSignal is AbortSignal =>\n maybeSignal !== null &&\n maybeSignal !== undefined &&\n typeof maybeSignal === \"object\" &&\n \"aborted\" in maybeSignal &&\n typeof maybeSignal.aborted === \"boolean\"\n )\n );\n}\n"],"mappings":"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"}
|
package/dist/browser.cjs
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
|
|
3
3
|
const require_chat_models_universal = require("./chat_models/universal.cjs");
|
|
4
|
+
const require_errors = require("./agents/errors.cjs");
|
|
5
|
+
const require_responses = require("./agents/responses.cjs");
|
|
6
|
+
const require_utils = require("./agents/middleware/utils.cjs");
|
|
7
|
+
const require_types = require("./agents/middleware/types.cjs");
|
|
8
|
+
const require_middleware = require("./agents/middleware.cjs");
|
|
9
|
+
const require_utils$1 = require("./agents/tests/utils.cjs");
|
|
10
|
+
const require_index = require("./agents/index.cjs");
|
|
11
|
+
const require_hitl = require("./agents/middleware/hitl.cjs");
|
|
12
|
+
const require_summarization = require("./agents/middleware/summarization.cjs");
|
|
13
|
+
const require_dynamicSystemPrompt = require("./agents/middleware/dynamicSystemPrompt.cjs");
|
|
14
|
+
const require_llmToolSelector = require("./agents/middleware/llmToolSelector.cjs");
|
|
15
|
+
const require_pii = require("./agents/middleware/pii.cjs");
|
|
16
|
+
const require_piiRedaction = require("./agents/middleware/piiRedaction.cjs");
|
|
17
|
+
const require_contextEditing = require("./agents/middleware/contextEditing.cjs");
|
|
18
|
+
const require_toolCallLimit = require("./agents/middleware/toolCallLimit.cjs");
|
|
19
|
+
const require_todoListMiddleware = require("./agents/middleware/todoListMiddleware.cjs");
|
|
20
|
+
const require_modelCallLimit = require("./agents/middleware/modelCallLimit.cjs");
|
|
21
|
+
const require_modelFallback = require("./agents/middleware/modelFallback.cjs");
|
|
22
|
+
const require_modelRetry = require("./agents/middleware/modelRetry.cjs");
|
|
23
|
+
const require_toolRetry = require("./agents/middleware/toolRetry.cjs");
|
|
24
|
+
const require_toolEmulator = require("./agents/middleware/toolEmulator.cjs");
|
|
25
|
+
const require_moderation = require("./agents/middleware/provider/openai/moderation.cjs");
|
|
26
|
+
const require_promptCaching = require("./agents/middleware/provider/anthropic/promptCaching.cjs");
|
|
27
|
+
require("./agents/middleware/index.cjs");
|
|
4
28
|
let _langchain_core_messages = require("@langchain/core/messages");
|
|
5
29
|
let _langchain_core_tools = require("@langchain/core/tools");
|
|
6
30
|
let _langchain_core_utils_context = require("@langchain/core/utils/context");
|
|
@@ -13,24 +37,65 @@ var browser_exports = /* @__PURE__ */ require_runtime.__exportAll({
|
|
|
13
37
|
AIMessageChunk: () => _langchain_core_messages.AIMessageChunk,
|
|
14
38
|
BaseMessage: () => _langchain_core_messages.BaseMessage,
|
|
15
39
|
BaseMessageChunk: () => _langchain_core_messages.BaseMessageChunk,
|
|
40
|
+
ClearToolUsesEdit: () => require_contextEditing.ClearToolUsesEdit,
|
|
16
41
|
Document: () => _langchain_core_documents.Document,
|
|
17
42
|
DynamicStructuredTool: () => _langchain_core_tools.DynamicStructuredTool,
|
|
18
43
|
DynamicTool: () => _langchain_core_tools.DynamicTool,
|
|
44
|
+
FakeToolCallingModel: () => require_utils$1.FakeToolCallingModel,
|
|
19
45
|
HumanMessage: () => _langchain_core_messages.HumanMessage,
|
|
20
46
|
HumanMessageChunk: () => _langchain_core_messages.HumanMessageChunk,
|
|
21
47
|
InMemoryStore: () => _langchain_core_stores.InMemoryStore,
|
|
48
|
+
MIDDLEWARE_BRAND: () => require_types.MIDDLEWARE_BRAND,
|
|
49
|
+
MiddlewareError: () => require_errors.MiddlewareError,
|
|
50
|
+
MultipleStructuredOutputsError: () => require_errors.MultipleStructuredOutputsError,
|
|
51
|
+
MultipleToolsBoundError: () => require_errors.MultipleToolsBoundError,
|
|
52
|
+
PIIDetectionError: () => require_pii.PIIDetectionError,
|
|
53
|
+
ProviderStrategy: () => require_responses.ProviderStrategy,
|
|
54
|
+
StructuredOutputParsingError: () => require_errors.StructuredOutputParsingError,
|
|
22
55
|
StructuredTool: () => _langchain_core_tools.StructuredTool,
|
|
23
56
|
SystemMessage: () => _langchain_core_messages.SystemMessage,
|
|
24
57
|
SystemMessageChunk: () => _langchain_core_messages.SystemMessageChunk,
|
|
58
|
+
TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT: () => require_todoListMiddleware.TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT,
|
|
25
59
|
Tool: () => _langchain_core_tools.Tool,
|
|
60
|
+
ToolCallLimitExceededError: () => require_toolCallLimit.ToolCallLimitExceededError,
|
|
61
|
+
ToolInvocationError: () => require_errors.ToolInvocationError,
|
|
26
62
|
ToolMessage: () => _langchain_core_messages.ToolMessage,
|
|
27
63
|
ToolMessageChunk: () => _langchain_core_messages.ToolMessageChunk,
|
|
64
|
+
ToolStrategy: () => require_responses.ToolStrategy,
|
|
65
|
+
anthropicPromptCachingMiddleware: () => require_promptCaching.anthropicPromptCachingMiddleware,
|
|
66
|
+
applyStrategy: () => require_pii.applyStrategy,
|
|
28
67
|
context: () => _langchain_core_utils_context.context,
|
|
68
|
+
contextEditingMiddleware: () => require_contextEditing.contextEditingMiddleware,
|
|
69
|
+
countTokensApproximately: () => require_utils.countTokensApproximately,
|
|
70
|
+
createAgent: () => require_index.createAgent,
|
|
71
|
+
createMiddleware: () => require_middleware.createMiddleware,
|
|
72
|
+
detectCreditCard: () => require_pii.detectCreditCard,
|
|
73
|
+
detectEmail: () => require_pii.detectEmail,
|
|
74
|
+
detectIP: () => require_pii.detectIP,
|
|
75
|
+
detectMacAddress: () => require_pii.detectMacAddress,
|
|
76
|
+
detectUrl: () => require_pii.detectUrl,
|
|
77
|
+
dynamicSystemPromptMiddleware: () => require_dynamicSystemPrompt.dynamicSystemPromptMiddleware,
|
|
29
78
|
fakeModel: () => _langchain_core_testing.fakeModel,
|
|
30
79
|
filterMessages: () => _langchain_core_messages.filterMessages,
|
|
80
|
+
humanInTheLoopMiddleware: () => require_hitl.humanInTheLoopMiddleware,
|
|
31
81
|
initChatModel: () => require_chat_models_universal.initChatModel,
|
|
32
82
|
langchainMatchers: () => _langchain_core_testing.langchainMatchers,
|
|
83
|
+
llmToolSelectorMiddleware: () => require_llmToolSelector.llmToolSelectorMiddleware,
|
|
84
|
+
modelCallLimitMiddleware: () => require_modelCallLimit.modelCallLimitMiddleware,
|
|
85
|
+
modelFallbackMiddleware: () => require_modelFallback.modelFallbackMiddleware,
|
|
86
|
+
modelRetryMiddleware: () => require_modelRetry.modelRetryMiddleware,
|
|
87
|
+
openAIModerationMiddleware: () => require_moderation.openAIModerationMiddleware,
|
|
88
|
+
piiMiddleware: () => require_pii.piiMiddleware,
|
|
89
|
+
piiRedactionMiddleware: () => require_piiRedaction.piiRedactionMiddleware,
|
|
90
|
+
providerStrategy: () => require_responses.providerStrategy,
|
|
91
|
+
resolveRedactionRule: () => require_pii.resolveRedactionRule,
|
|
92
|
+
summarizationMiddleware: () => require_summarization.summarizationMiddleware,
|
|
93
|
+
todoListMiddleware: () => require_todoListMiddleware.todoListMiddleware,
|
|
33
94
|
tool: () => _langchain_core_tools.tool,
|
|
95
|
+
toolCallLimitMiddleware: () => require_toolCallLimit.toolCallLimitMiddleware,
|
|
96
|
+
toolEmulatorMiddleware: () => require_toolEmulator.toolEmulatorMiddleware,
|
|
97
|
+
toolRetryMiddleware: () => require_toolRetry.toolRetryMiddleware,
|
|
98
|
+
toolStrategy: () => require_responses.toolStrategy,
|
|
34
99
|
trimMessages: () => _langchain_core_messages.trimMessages
|
|
35
100
|
});
|
|
36
101
|
//#endregion
|
|
@@ -58,6 +123,7 @@ Object.defineProperty(exports, "BaseMessageChunk", {
|
|
|
58
123
|
return _langchain_core_messages.BaseMessageChunk;
|
|
59
124
|
}
|
|
60
125
|
});
|
|
126
|
+
exports.ClearToolUsesEdit = require_contextEditing.ClearToolUsesEdit;
|
|
61
127
|
Object.defineProperty(exports, "Document", {
|
|
62
128
|
enumerable: true,
|
|
63
129
|
get: function() {
|
|
@@ -76,6 +142,7 @@ Object.defineProperty(exports, "DynamicTool", {
|
|
|
76
142
|
return _langchain_core_tools.DynamicTool;
|
|
77
143
|
}
|
|
78
144
|
});
|
|
145
|
+
exports.FakeToolCallingModel = require_utils$1.FakeToolCallingModel;
|
|
79
146
|
Object.defineProperty(exports, "HumanMessage", {
|
|
80
147
|
enumerable: true,
|
|
81
148
|
get: function() {
|
|
@@ -94,6 +161,13 @@ Object.defineProperty(exports, "InMemoryStore", {
|
|
|
94
161
|
return _langchain_core_stores.InMemoryStore;
|
|
95
162
|
}
|
|
96
163
|
});
|
|
164
|
+
exports.MIDDLEWARE_BRAND = require_types.MIDDLEWARE_BRAND;
|
|
165
|
+
exports.MiddlewareError = require_errors.MiddlewareError;
|
|
166
|
+
exports.MultipleStructuredOutputsError = require_errors.MultipleStructuredOutputsError;
|
|
167
|
+
exports.MultipleToolsBoundError = require_errors.MultipleToolsBoundError;
|
|
168
|
+
exports.PIIDetectionError = require_pii.PIIDetectionError;
|
|
169
|
+
exports.ProviderStrategy = require_responses.ProviderStrategy;
|
|
170
|
+
exports.StructuredOutputParsingError = require_errors.StructuredOutputParsingError;
|
|
97
171
|
Object.defineProperty(exports, "StructuredTool", {
|
|
98
172
|
enumerable: true,
|
|
99
173
|
get: function() {
|
|
@@ -112,12 +186,15 @@ Object.defineProperty(exports, "SystemMessageChunk", {
|
|
|
112
186
|
return _langchain_core_messages.SystemMessageChunk;
|
|
113
187
|
}
|
|
114
188
|
});
|
|
189
|
+
exports.TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT = require_todoListMiddleware.TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT;
|
|
115
190
|
Object.defineProperty(exports, "Tool", {
|
|
116
191
|
enumerable: true,
|
|
117
192
|
get: function() {
|
|
118
193
|
return _langchain_core_tools.Tool;
|
|
119
194
|
}
|
|
120
195
|
});
|
|
196
|
+
exports.ToolCallLimitExceededError = require_toolCallLimit.ToolCallLimitExceededError;
|
|
197
|
+
exports.ToolInvocationError = require_errors.ToolInvocationError;
|
|
121
198
|
Object.defineProperty(exports, "ToolMessage", {
|
|
122
199
|
enumerable: true,
|
|
123
200
|
get: function() {
|
|
@@ -130,6 +207,9 @@ Object.defineProperty(exports, "ToolMessageChunk", {
|
|
|
130
207
|
return _langchain_core_messages.ToolMessageChunk;
|
|
131
208
|
}
|
|
132
209
|
});
|
|
210
|
+
exports.ToolStrategy = require_responses.ToolStrategy;
|
|
211
|
+
exports.anthropicPromptCachingMiddleware = require_promptCaching.anthropicPromptCachingMiddleware;
|
|
212
|
+
exports.applyStrategy = require_pii.applyStrategy;
|
|
133
213
|
Object.defineProperty(exports, "browser_exports", {
|
|
134
214
|
enumerable: true,
|
|
135
215
|
get: function() {
|
|
@@ -142,6 +222,16 @@ Object.defineProperty(exports, "context", {
|
|
|
142
222
|
return _langchain_core_utils_context.context;
|
|
143
223
|
}
|
|
144
224
|
});
|
|
225
|
+
exports.contextEditingMiddleware = require_contextEditing.contextEditingMiddleware;
|
|
226
|
+
exports.countTokensApproximately = require_utils.countTokensApproximately;
|
|
227
|
+
exports.createAgent = require_index.createAgent;
|
|
228
|
+
exports.createMiddleware = require_middleware.createMiddleware;
|
|
229
|
+
exports.detectCreditCard = require_pii.detectCreditCard;
|
|
230
|
+
exports.detectEmail = require_pii.detectEmail;
|
|
231
|
+
exports.detectIP = require_pii.detectIP;
|
|
232
|
+
exports.detectMacAddress = require_pii.detectMacAddress;
|
|
233
|
+
exports.detectUrl = require_pii.detectUrl;
|
|
234
|
+
exports.dynamicSystemPromptMiddleware = require_dynamicSystemPrompt.dynamicSystemPromptMiddleware;
|
|
145
235
|
Object.defineProperty(exports, "fakeModel", {
|
|
146
236
|
enumerable: true,
|
|
147
237
|
get: function() {
|
|
@@ -154,6 +244,7 @@ Object.defineProperty(exports, "filterMessages", {
|
|
|
154
244
|
return _langchain_core_messages.filterMessages;
|
|
155
245
|
}
|
|
156
246
|
});
|
|
247
|
+
exports.humanInTheLoopMiddleware = require_hitl.humanInTheLoopMiddleware;
|
|
157
248
|
exports.initChatModel = require_chat_models_universal.initChatModel;
|
|
158
249
|
Object.defineProperty(exports, "langchainMatchers", {
|
|
159
250
|
enumerable: true,
|
|
@@ -161,12 +252,27 @@ Object.defineProperty(exports, "langchainMatchers", {
|
|
|
161
252
|
return _langchain_core_testing.langchainMatchers;
|
|
162
253
|
}
|
|
163
254
|
});
|
|
255
|
+
exports.llmToolSelectorMiddleware = require_llmToolSelector.llmToolSelectorMiddleware;
|
|
256
|
+
exports.modelCallLimitMiddleware = require_modelCallLimit.modelCallLimitMiddleware;
|
|
257
|
+
exports.modelFallbackMiddleware = require_modelFallback.modelFallbackMiddleware;
|
|
258
|
+
exports.modelRetryMiddleware = require_modelRetry.modelRetryMiddleware;
|
|
259
|
+
exports.openAIModerationMiddleware = require_moderation.openAIModerationMiddleware;
|
|
260
|
+
exports.piiMiddleware = require_pii.piiMiddleware;
|
|
261
|
+
exports.piiRedactionMiddleware = require_piiRedaction.piiRedactionMiddleware;
|
|
262
|
+
exports.providerStrategy = require_responses.providerStrategy;
|
|
263
|
+
exports.resolveRedactionRule = require_pii.resolveRedactionRule;
|
|
264
|
+
exports.summarizationMiddleware = require_summarization.summarizationMiddleware;
|
|
265
|
+
exports.todoListMiddleware = require_todoListMiddleware.todoListMiddleware;
|
|
164
266
|
Object.defineProperty(exports, "tool", {
|
|
165
267
|
enumerable: true,
|
|
166
268
|
get: function() {
|
|
167
269
|
return _langchain_core_tools.tool;
|
|
168
270
|
}
|
|
169
271
|
});
|
|
272
|
+
exports.toolCallLimitMiddleware = require_toolCallLimit.toolCallLimitMiddleware;
|
|
273
|
+
exports.toolEmulatorMiddleware = require_toolEmulator.toolEmulatorMiddleware;
|
|
274
|
+
exports.toolRetryMiddleware = require_toolRetry.toolRetryMiddleware;
|
|
275
|
+
exports.toolStrategy = require_responses.toolStrategy;
|
|
170
276
|
Object.defineProperty(exports, "trimMessages", {
|
|
171
277
|
enumerable: true,
|
|
172
278
|
get: function() {
|
package/dist/browser.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.cjs","names":[],"sources":["../src/browser.ts"],"sourcesContent":["/**\n * LangChain browser exports\n */\n\n/**\n * LangChain Messages\n */\nexport {\n BaseMessage,\n BaseMessageChunk,\n AIMessage,\n AIMessageChunk,\n SystemMessage,\n SystemMessageChunk,\n HumanMessage,\n HumanMessageChunk,\n ToolMessage,\n ToolMessageChunk,\n type ContentBlock,\n filterMessages,\n trimMessages,\n} from \"@langchain/core/messages\";\n\n/**\n * Universal Chat Model\n */\nexport { initChatModel } from \"./chat_models/universal.js\";\n\n/**\n * LangChain Tools\n */\nexport {\n tool,\n Tool,\n type ToolRuntime,\n DynamicTool,\n StructuredTool,\n DynamicStructuredTool,\n} from \"@langchain/core/tools\";\n\n/**\n * LangChain utilities\n */\nexport { context } from \"@langchain/core/utils/context\";\n\n/**\n * LangChain Stores\n */\nexport { InMemoryStore } from \"@langchain/core/stores\";\n\n/**\n * LangChain Documents\n */\nexport { type DocumentInput, Document } from \"@langchain/core/documents\";\n\n/**\n * LangChain Testing Utilities\n */\nexport {\n langchainMatchers,\n type LangChainMatchers,\n fakeModel,\n} from \"@langchain/core/testing\";\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"browser.cjs","names":[],"sources":["../src/browser.ts"],"sourcesContent":["/**\n * LangChain browser exports\n */\n\n/**\n * LangChain Messages\n */\nexport {\n BaseMessage,\n BaseMessageChunk,\n AIMessage,\n AIMessageChunk,\n SystemMessage,\n SystemMessageChunk,\n HumanMessage,\n HumanMessageChunk,\n ToolMessage,\n ToolMessageChunk,\n type ContentBlock,\n filterMessages,\n trimMessages,\n} from \"@langchain/core/messages\";\n\n/**\n * Universal Chat Model\n */\nexport { initChatModel } from \"./chat_models/universal.js\";\n\n/**\n * LangChain Tools\n */\nexport {\n tool,\n Tool,\n type ToolRuntime,\n DynamicTool,\n StructuredTool,\n DynamicStructuredTool,\n} from \"@langchain/core/tools\";\n\n/**\n * LangChain utilities\n */\nexport { context } from \"@langchain/core/utils/context\";\n\n/**\n * LangChain Agents\n */\nexport * from \"./agents/index.js\";\n\n/**\n * `createAgent` pre-built middleware\n */\nexport * from \"./agents/middleware/index.js\";\n\n/**\n * LangChain Stores\n */\nexport { InMemoryStore } from \"@langchain/core/stores\";\n\n/**\n * LangChain Documents\n */\nexport { type DocumentInput, Document } from \"@langchain/core/documents\";\n\n/**\n * LangChain Testing Utilities\n */\nexport {\n langchainMatchers,\n type LangChainMatchers,\n fakeModel,\n} from \"@langchain/core/testing\";\n"],"mappings":""}
|
package/dist/browser.d.cts
CHANGED
|
@@ -1,8 +1,36 @@
|
|
|
1
1
|
import { initChatModel } from "./chat_models/universal.cjs";
|
|
2
|
+
import { MiddlewareError, MultipleStructuredOutputsError, MultipleToolsBoundError, StructuredOutputParsingError, ToolInvocationError } from "./agents/errors.cjs";
|
|
3
|
+
import { ProviderStrategy, ResponseFormat, ResponseFormatUndefined, ToolStrategy, TypedToolStrategy, providerStrategy, toolStrategy } from "./agents/responses.cjs";
|
|
4
|
+
import { JumpToTarget } from "./agents/constants.cjs";
|
|
5
|
+
import { Runtime } from "./agents/runtime.cjs";
|
|
6
|
+
import { ModelRequest } from "./agents/nodes/types.cjs";
|
|
7
|
+
import { AfterAgentHook, AfterModelHook, AgentMiddleware, AnyAnnotationRoot, BeforeAgentHook, BeforeModelHook, DefaultMiddlewareTypeConfig, InferChannelType, InferContextInput, InferMergedInputState, InferMergedState, InferMiddlewareContext, InferMiddlewareContextInput, InferMiddlewareContextInputs, InferMiddlewareContextSchema, InferMiddlewareContexts, InferMiddlewareFullContext, InferMiddlewareInputState, InferMiddlewareInputStates, InferMiddlewareSchema, InferMiddlewareState, InferMiddlewareStates, InferMiddlewareToolsFromConfig, InferMiddlewareType, InferSchemaInput, InferSchemaUpdateType, InferSchemaValue, InferSchemaValueType, MIDDLEWARE_BRAND, MiddlewareResult, MiddlewareTypeConfig, NormalizedSchemaInput, NormalizedSchemaUpdate, ResolveMiddlewareTypeConfig, ToAnnotationRoot, ToolCallHandler, ToolCallRequest, WrapModelCallHandler, WrapModelCallHook, WrapToolCallHook } from "./agents/middleware/types.cjs";
|
|
8
|
+
import { AgentTypeConfig, BuiltInState, CombineTools, CreateAgentParams, DefaultAgentTypeConfig, ExecutedToolCall, ExtractZodArrayTypes, InferAgentContext, InferAgentContextSchema, InferAgentMiddleware, InferAgentResponse, InferAgentState, InferAgentStateSchema, InferAgentTools, InferAgentType, InferMiddlewareTools, InferMiddlewareToolsArray, Interrupt, JumpTo, N, ResolveAgentTypeConfig, ToolCall, ToolResult, ToolsToMessageToolSet, UserInput, WithStateGraphNodes } from "./agents/types.cjs";
|
|
9
|
+
import { ReactAgent } from "./agents/ReactAgent.cjs";
|
|
10
|
+
import { createMiddleware } from "./agents/middleware.cjs";
|
|
11
|
+
import { FakeToolCallingModel } from "./agents/tests/utils.cjs";
|
|
12
|
+
import { createAgent } from "./agents/index.cjs";
|
|
13
|
+
import { Action, ActionRequest, ApproveDecision, Decision, DecisionType, DescriptionFactory, EditDecision, HITLRequest, HITLResponse, HumanInTheLoopMiddlewareConfig, InterruptOnConfig, RejectDecision, ReviewConfig, humanInTheLoopMiddleware } from "./agents/middleware/hitl.cjs";
|
|
14
|
+
import { SummarizationMiddlewareConfig, TokenCounter, summarizationMiddleware } from "./agents/middleware/summarization.cjs";
|
|
15
|
+
import { DynamicSystemPromptMiddlewareConfig, dynamicSystemPromptMiddleware } from "./agents/middleware/dynamicSystemPrompt.cjs";
|
|
16
|
+
import { LLMToolSelectorConfig, llmToolSelectorMiddleware } from "./agents/middleware/llmToolSelector.cjs";
|
|
17
|
+
import { BuiltInPIIType, PIIDetectionError, PIIDetector, PIIMatch, PIIMiddlewareConfig, PIIStrategy, RedactionRuleConfig, ResolvedRedactionRule, applyStrategy, detectCreditCard, detectEmail, detectIP, detectMacAddress, detectUrl, piiMiddleware, resolveRedactionRule } from "./agents/middleware/pii.cjs";
|
|
18
|
+
import { PIIRedactionMiddlewareConfig, piiRedactionMiddleware } from "./agents/middleware/piiRedaction.cjs";
|
|
19
|
+
import { ClearToolUsesEdit, ClearToolUsesEditConfig, ContextEdit, ContextEditingMiddlewareConfig, contextEditingMiddleware } from "./agents/middleware/contextEditing.cjs";
|
|
20
|
+
import { ToolCallLimitConfig, ToolCallLimitExceededError, toolCallLimitMiddleware } from "./agents/middleware/toolCallLimit.cjs";
|
|
21
|
+
import { TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT, Todo, TodoListMiddlewareOptions, todoListMiddleware } from "./agents/middleware/todoListMiddleware.cjs";
|
|
22
|
+
import { ModelCallLimitMiddlewareConfig, modelCallLimitMiddleware } from "./agents/middleware/modelCallLimit.cjs";
|
|
23
|
+
import { modelFallbackMiddleware } from "./agents/middleware/modelFallback.cjs";
|
|
24
|
+
import { ModelRetryMiddlewareConfig, modelRetryMiddleware } from "./agents/middleware/modelRetry.cjs";
|
|
25
|
+
import { ToolRetryMiddlewareConfig, toolRetryMiddleware } from "./agents/middleware/toolRetry.cjs";
|
|
26
|
+
import { ToolEmulatorOptions, toolEmulatorMiddleware } from "./agents/middleware/toolEmulator.cjs";
|
|
27
|
+
import { OpenAIModerationMiddlewareOptions, openAIModerationMiddleware } from "./agents/middleware/provider/openai/moderation.cjs";
|
|
28
|
+
import { PromptCachingMiddlewareConfig, anthropicPromptCachingMiddleware } from "./agents/middleware/provider/anthropic/promptCaching.cjs";
|
|
29
|
+
import { countTokensApproximately } from "./agents/middleware/utils.cjs";
|
|
2
30
|
import { AIMessage, AIMessageChunk, BaseMessage, BaseMessageChunk, ContentBlock, HumanMessage, HumanMessageChunk, SystemMessage, SystemMessageChunk, ToolMessage, ToolMessageChunk, filterMessages, trimMessages } from "@langchain/core/messages";
|
|
3
31
|
import { DynamicStructuredTool, DynamicTool, StructuredTool, Tool, ToolRuntime, tool } from "@langchain/core/tools";
|
|
4
32
|
import { context } from "@langchain/core/utils/context";
|
|
5
33
|
import { InMemoryStore } from "@langchain/core/stores";
|
|
6
34
|
import { Document, DocumentInput } from "@langchain/core/documents";
|
|
7
35
|
import { LangChainMatchers, fakeModel, langchainMatchers } from "@langchain/core/testing";
|
|
8
|
-
export { AIMessage, AIMessageChunk, BaseMessage, BaseMessageChunk, type ContentBlock, Document, type DocumentInput, DynamicStructuredTool, DynamicTool, HumanMessage, HumanMessageChunk, InMemoryStore, type LangChainMatchers, StructuredTool, SystemMessage, SystemMessageChunk, Tool, ToolMessage, ToolMessageChunk, type ToolRuntime, context, fakeModel, filterMessages, initChatModel, langchainMatchers, tool, trimMessages };
|
|
36
|
+
export { AIMessage, AIMessageChunk, Action, ActionRequest, AfterAgentHook, AfterModelHook, AgentMiddleware, AgentTypeConfig, AnyAnnotationRoot, ApproveDecision, BaseMessage, BaseMessageChunk, BeforeAgentHook, BeforeModelHook, BuiltInPIIType, BuiltInState, ClearToolUsesEdit, ClearToolUsesEditConfig, CombineTools, type ContentBlock, ContextEdit, ContextEditingMiddlewareConfig, CreateAgentParams, Decision, DecisionType, DefaultAgentTypeConfig, DefaultMiddlewareTypeConfig, DescriptionFactory, Document, type DocumentInput, DynamicStructuredTool, DynamicSystemPromptMiddlewareConfig, DynamicTool, EditDecision, ExecutedToolCall, ExtractZodArrayTypes, FakeToolCallingModel, HITLRequest, HITLResponse, HumanInTheLoopMiddlewareConfig, HumanMessage, HumanMessageChunk, InMemoryStore, InferAgentContext, InferAgentContextSchema, InferAgentMiddleware, InferAgentResponse, InferAgentState, InferAgentStateSchema, InferAgentTools, InferAgentType, InferChannelType, InferContextInput, InferMergedInputState, InferMergedState, InferMiddlewareContext, InferMiddlewareContextInput, InferMiddlewareContextInputs, InferMiddlewareContextSchema, InferMiddlewareContexts, InferMiddlewareFullContext, InferMiddlewareInputState, InferMiddlewareInputStates, InferMiddlewareSchema, InferMiddlewareState, InferMiddlewareStates, InferMiddlewareTools, InferMiddlewareToolsArray, InferMiddlewareToolsFromConfig, InferMiddlewareType, InferSchemaInput, InferSchemaUpdateType, InferSchemaValue, InferSchemaValueType, Interrupt, InterruptOnConfig, JumpTo, JumpToTarget, LLMToolSelectorConfig, type LangChainMatchers, MIDDLEWARE_BRAND, MiddlewareError, MiddlewareResult, MiddlewareTypeConfig, ModelCallLimitMiddlewareConfig, ModelRequest, ModelRetryMiddlewareConfig, MultipleStructuredOutputsError, MultipleToolsBoundError, N, NormalizedSchemaInput, NormalizedSchemaUpdate, OpenAIModerationMiddlewareOptions, PIIDetectionError, PIIDetector, PIIMatch, PIIMiddlewareConfig, PIIRedactionMiddlewareConfig, PIIStrategy, PromptCachingMiddlewareConfig, ProviderStrategy, ReactAgent, RedactionRuleConfig, RejectDecision, ResolveAgentTypeConfig, ResolveMiddlewareTypeConfig, ResolvedRedactionRule, ResponseFormat, ResponseFormatUndefined, ReviewConfig, Runtime, StructuredOutputParsingError, StructuredTool, SummarizationMiddlewareConfig, SystemMessage, SystemMessageChunk, TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT, ToAnnotationRoot, Todo, TodoListMiddlewareOptions, TokenCounter, Tool, ToolCall, ToolCallHandler, ToolCallLimitConfig, ToolCallLimitExceededError, ToolCallRequest, ToolEmulatorOptions, ToolInvocationError, ToolMessage, ToolMessageChunk, ToolResult, ToolRetryMiddlewareConfig, type ToolRuntime, ToolStrategy, ToolsToMessageToolSet, TypedToolStrategy, UserInput, WithStateGraphNodes, WrapModelCallHandler, WrapModelCallHook, WrapToolCallHook, anthropicPromptCachingMiddleware, applyStrategy, context, contextEditingMiddleware, countTokensApproximately, createAgent, createMiddleware, detectCreditCard, detectEmail, detectIP, detectMacAddress, detectUrl, dynamicSystemPromptMiddleware, fakeModel, filterMessages, humanInTheLoopMiddleware, initChatModel, langchainMatchers, llmToolSelectorMiddleware, modelCallLimitMiddleware, modelFallbackMiddleware, modelRetryMiddleware, openAIModerationMiddleware, piiMiddleware, piiRedactionMiddleware, providerStrategy, resolveRedactionRule, summarizationMiddleware, todoListMiddleware, tool, toolCallLimitMiddleware, toolEmulatorMiddleware, toolRetryMiddleware, toolStrategy, trimMessages };
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,8 +1,36 @@
|
|
|
1
1
|
import { initChatModel } from "./chat_models/universal.js";
|
|
2
|
+
import { MiddlewareError, MultipleStructuredOutputsError, MultipleToolsBoundError, StructuredOutputParsingError, ToolInvocationError } from "./agents/errors.js";
|
|
3
|
+
import { ProviderStrategy, ResponseFormat, ResponseFormatUndefined, ToolStrategy, TypedToolStrategy, providerStrategy, toolStrategy } from "./agents/responses.js";
|
|
4
|
+
import { JumpToTarget } from "./agents/constants.js";
|
|
5
|
+
import { Runtime } from "./agents/runtime.js";
|
|
6
|
+
import { ModelRequest } from "./agents/nodes/types.js";
|
|
7
|
+
import { AfterAgentHook, AfterModelHook, AgentMiddleware, AnyAnnotationRoot, BeforeAgentHook, BeforeModelHook, DefaultMiddlewareTypeConfig, InferChannelType, InferContextInput, InferMergedInputState, InferMergedState, InferMiddlewareContext, InferMiddlewareContextInput, InferMiddlewareContextInputs, InferMiddlewareContextSchema, InferMiddlewareContexts, InferMiddlewareFullContext, InferMiddlewareInputState, InferMiddlewareInputStates, InferMiddlewareSchema, InferMiddlewareState, InferMiddlewareStates, InferMiddlewareToolsFromConfig, InferMiddlewareType, InferSchemaInput, InferSchemaUpdateType, InferSchemaValue, InferSchemaValueType, MIDDLEWARE_BRAND, MiddlewareResult, MiddlewareTypeConfig, NormalizedSchemaInput, NormalizedSchemaUpdate, ResolveMiddlewareTypeConfig, ToAnnotationRoot, ToolCallHandler, ToolCallRequest, WrapModelCallHandler, WrapModelCallHook, WrapToolCallHook } from "./agents/middleware/types.js";
|
|
8
|
+
import { AgentTypeConfig, BuiltInState, CombineTools, CreateAgentParams, DefaultAgentTypeConfig, ExecutedToolCall, ExtractZodArrayTypes, InferAgentContext, InferAgentContextSchema, InferAgentMiddleware, InferAgentResponse, InferAgentState, InferAgentStateSchema, InferAgentTools, InferAgentType, InferMiddlewareTools, InferMiddlewareToolsArray, Interrupt, JumpTo, N, ResolveAgentTypeConfig, ToolCall, ToolResult, ToolsToMessageToolSet, UserInput, WithStateGraphNodes } from "./agents/types.js";
|
|
9
|
+
import { ReactAgent } from "./agents/ReactAgent.js";
|
|
10
|
+
import { createMiddleware } from "./agents/middleware.js";
|
|
11
|
+
import { FakeToolCallingModel } from "./agents/tests/utils.js";
|
|
12
|
+
import { createAgent } from "./agents/index.js";
|
|
13
|
+
import { Action, ActionRequest, ApproveDecision, Decision, DecisionType, DescriptionFactory, EditDecision, HITLRequest, HITLResponse, HumanInTheLoopMiddlewareConfig, InterruptOnConfig, RejectDecision, ReviewConfig, humanInTheLoopMiddleware } from "./agents/middleware/hitl.js";
|
|
14
|
+
import { SummarizationMiddlewareConfig, TokenCounter, summarizationMiddleware } from "./agents/middleware/summarization.js";
|
|
15
|
+
import { DynamicSystemPromptMiddlewareConfig, dynamicSystemPromptMiddleware } from "./agents/middleware/dynamicSystemPrompt.js";
|
|
16
|
+
import { LLMToolSelectorConfig, llmToolSelectorMiddleware } from "./agents/middleware/llmToolSelector.js";
|
|
17
|
+
import { BuiltInPIIType, PIIDetectionError, PIIDetector, PIIMatch, PIIMiddlewareConfig, PIIStrategy, RedactionRuleConfig, ResolvedRedactionRule, applyStrategy, detectCreditCard, detectEmail, detectIP, detectMacAddress, detectUrl, piiMiddleware, resolveRedactionRule } from "./agents/middleware/pii.js";
|
|
18
|
+
import { PIIRedactionMiddlewareConfig, piiRedactionMiddleware } from "./agents/middleware/piiRedaction.js";
|
|
19
|
+
import { ClearToolUsesEdit, ClearToolUsesEditConfig, ContextEdit, ContextEditingMiddlewareConfig, contextEditingMiddleware } from "./agents/middleware/contextEditing.js";
|
|
20
|
+
import { ToolCallLimitConfig, ToolCallLimitExceededError, toolCallLimitMiddleware } from "./agents/middleware/toolCallLimit.js";
|
|
21
|
+
import { TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT, Todo, TodoListMiddlewareOptions, todoListMiddleware } from "./agents/middleware/todoListMiddleware.js";
|
|
22
|
+
import { ModelCallLimitMiddlewareConfig, modelCallLimitMiddleware } from "./agents/middleware/modelCallLimit.js";
|
|
23
|
+
import { modelFallbackMiddleware } from "./agents/middleware/modelFallback.js";
|
|
24
|
+
import { ModelRetryMiddlewareConfig, modelRetryMiddleware } from "./agents/middleware/modelRetry.js";
|
|
25
|
+
import { ToolRetryMiddlewareConfig, toolRetryMiddleware } from "./agents/middleware/toolRetry.js";
|
|
26
|
+
import { ToolEmulatorOptions, toolEmulatorMiddleware } from "./agents/middleware/toolEmulator.js";
|
|
27
|
+
import { OpenAIModerationMiddlewareOptions, openAIModerationMiddleware } from "./agents/middleware/provider/openai/moderation.js";
|
|
28
|
+
import { PromptCachingMiddlewareConfig, anthropicPromptCachingMiddleware } from "./agents/middleware/provider/anthropic/promptCaching.js";
|
|
29
|
+
import { countTokensApproximately } from "./agents/middleware/utils.js";
|
|
2
30
|
import { AIMessage, AIMessageChunk, BaseMessage, BaseMessageChunk, ContentBlock, HumanMessage, HumanMessageChunk, SystemMessage, SystemMessageChunk, ToolMessage, ToolMessageChunk, filterMessages, trimMessages } from "@langchain/core/messages";
|
|
3
31
|
import { DynamicStructuredTool, DynamicTool, StructuredTool, Tool, ToolRuntime, tool } from "@langchain/core/tools";
|
|
4
32
|
import { context } from "@langchain/core/utils/context";
|
|
5
33
|
import { InMemoryStore } from "@langchain/core/stores";
|
|
6
34
|
import { Document, DocumentInput } from "@langchain/core/documents";
|
|
7
35
|
import { LangChainMatchers, fakeModel, langchainMatchers } from "@langchain/core/testing";
|
|
8
|
-
export { AIMessage, AIMessageChunk, BaseMessage, BaseMessageChunk, type ContentBlock, Document, type DocumentInput, DynamicStructuredTool, DynamicTool, HumanMessage, HumanMessageChunk, InMemoryStore, type LangChainMatchers, StructuredTool, SystemMessage, SystemMessageChunk, Tool, ToolMessage, ToolMessageChunk, type ToolRuntime, context, fakeModel, filterMessages, initChatModel, langchainMatchers, tool, trimMessages };
|
|
36
|
+
export { AIMessage, AIMessageChunk, Action, ActionRequest, AfterAgentHook, AfterModelHook, AgentMiddleware, AgentTypeConfig, AnyAnnotationRoot, ApproveDecision, BaseMessage, BaseMessageChunk, BeforeAgentHook, BeforeModelHook, BuiltInPIIType, BuiltInState, ClearToolUsesEdit, ClearToolUsesEditConfig, CombineTools, type ContentBlock, ContextEdit, ContextEditingMiddlewareConfig, CreateAgentParams, Decision, DecisionType, DefaultAgentTypeConfig, DefaultMiddlewareTypeConfig, DescriptionFactory, Document, type DocumentInput, DynamicStructuredTool, DynamicSystemPromptMiddlewareConfig, DynamicTool, EditDecision, ExecutedToolCall, ExtractZodArrayTypes, FakeToolCallingModel, HITLRequest, HITLResponse, HumanInTheLoopMiddlewareConfig, HumanMessage, HumanMessageChunk, InMemoryStore, InferAgentContext, InferAgentContextSchema, InferAgentMiddleware, InferAgentResponse, InferAgentState, InferAgentStateSchema, InferAgentTools, InferAgentType, InferChannelType, InferContextInput, InferMergedInputState, InferMergedState, InferMiddlewareContext, InferMiddlewareContextInput, InferMiddlewareContextInputs, InferMiddlewareContextSchema, InferMiddlewareContexts, InferMiddlewareFullContext, InferMiddlewareInputState, InferMiddlewareInputStates, InferMiddlewareSchema, InferMiddlewareState, InferMiddlewareStates, InferMiddlewareTools, InferMiddlewareToolsArray, InferMiddlewareToolsFromConfig, InferMiddlewareType, InferSchemaInput, InferSchemaUpdateType, InferSchemaValue, InferSchemaValueType, Interrupt, InterruptOnConfig, JumpTo, JumpToTarget, LLMToolSelectorConfig, type LangChainMatchers, MIDDLEWARE_BRAND, MiddlewareError, MiddlewareResult, MiddlewareTypeConfig, ModelCallLimitMiddlewareConfig, ModelRequest, ModelRetryMiddlewareConfig, MultipleStructuredOutputsError, MultipleToolsBoundError, N, NormalizedSchemaInput, NormalizedSchemaUpdate, OpenAIModerationMiddlewareOptions, PIIDetectionError, PIIDetector, PIIMatch, PIIMiddlewareConfig, PIIRedactionMiddlewareConfig, PIIStrategy, PromptCachingMiddlewareConfig, ProviderStrategy, ReactAgent, RedactionRuleConfig, RejectDecision, ResolveAgentTypeConfig, ResolveMiddlewareTypeConfig, ResolvedRedactionRule, ResponseFormat, ResponseFormatUndefined, ReviewConfig, Runtime, StructuredOutputParsingError, StructuredTool, SummarizationMiddlewareConfig, SystemMessage, SystemMessageChunk, TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT, ToAnnotationRoot, Todo, TodoListMiddlewareOptions, TokenCounter, Tool, ToolCall, ToolCallHandler, ToolCallLimitConfig, ToolCallLimitExceededError, ToolCallRequest, ToolEmulatorOptions, ToolInvocationError, ToolMessage, ToolMessageChunk, ToolResult, ToolRetryMiddlewareConfig, type ToolRuntime, ToolStrategy, ToolsToMessageToolSet, TypedToolStrategy, UserInput, WithStateGraphNodes, WrapModelCallHandler, WrapModelCallHook, WrapToolCallHook, anthropicPromptCachingMiddleware, applyStrategy, context, contextEditingMiddleware, countTokensApproximately, createAgent, createMiddleware, detectCreditCard, detectEmail, detectIP, detectMacAddress, detectUrl, dynamicSystemPromptMiddleware, fakeModel, filterMessages, humanInTheLoopMiddleware, initChatModel, langchainMatchers, llmToolSelectorMiddleware, modelCallLimitMiddleware, modelFallbackMiddleware, modelRetryMiddleware, openAIModerationMiddleware, piiMiddleware, piiRedactionMiddleware, providerStrategy, resolveRedactionRule, summarizationMiddleware, todoListMiddleware, tool, toolCallLimitMiddleware, toolEmulatorMiddleware, toolRetryMiddleware, toolStrategy, trimMessages };
|
package/dist/browser.js
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { initChatModel } from "./chat_models/universal.js";
|
|
3
|
+
import { MiddlewareError, MultipleStructuredOutputsError, MultipleToolsBoundError, StructuredOutputParsingError, ToolInvocationError } from "./agents/errors.js";
|
|
4
|
+
import { ProviderStrategy, ToolStrategy, providerStrategy, toolStrategy } from "./agents/responses.js";
|
|
5
|
+
import { countTokensApproximately } from "./agents/middleware/utils.js";
|
|
6
|
+
import { MIDDLEWARE_BRAND } from "./agents/middleware/types.js";
|
|
7
|
+
import { createMiddleware } from "./agents/middleware.js";
|
|
8
|
+
import { FakeToolCallingModel } from "./agents/tests/utils.js";
|
|
9
|
+
import { createAgent } from "./agents/index.js";
|
|
10
|
+
import { humanInTheLoopMiddleware } from "./agents/middleware/hitl.js";
|
|
11
|
+
import { summarizationMiddleware } from "./agents/middleware/summarization.js";
|
|
12
|
+
import { dynamicSystemPromptMiddleware } from "./agents/middleware/dynamicSystemPrompt.js";
|
|
13
|
+
import { llmToolSelectorMiddleware } from "./agents/middleware/llmToolSelector.js";
|
|
14
|
+
import { PIIDetectionError, applyStrategy, detectCreditCard, detectEmail, detectIP, detectMacAddress, detectUrl, piiMiddleware, resolveRedactionRule } from "./agents/middleware/pii.js";
|
|
15
|
+
import { piiRedactionMiddleware } from "./agents/middleware/piiRedaction.js";
|
|
16
|
+
import { ClearToolUsesEdit, contextEditingMiddleware } from "./agents/middleware/contextEditing.js";
|
|
17
|
+
import { ToolCallLimitExceededError, toolCallLimitMiddleware } from "./agents/middleware/toolCallLimit.js";
|
|
18
|
+
import { TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT, todoListMiddleware } from "./agents/middleware/todoListMiddleware.js";
|
|
19
|
+
import { modelCallLimitMiddleware } from "./agents/middleware/modelCallLimit.js";
|
|
20
|
+
import { modelFallbackMiddleware } from "./agents/middleware/modelFallback.js";
|
|
21
|
+
import { modelRetryMiddleware } from "./agents/middleware/modelRetry.js";
|
|
22
|
+
import { toolRetryMiddleware } from "./agents/middleware/toolRetry.js";
|
|
23
|
+
import { toolEmulatorMiddleware } from "./agents/middleware/toolEmulator.js";
|
|
24
|
+
import { openAIModerationMiddleware } from "./agents/middleware/provider/openai/moderation.js";
|
|
25
|
+
import { anthropicPromptCachingMiddleware } from "./agents/middleware/provider/anthropic/promptCaching.js";
|
|
26
|
+
import "./agents/middleware/index.js";
|
|
3
27
|
import { AIMessage, AIMessageChunk, BaseMessage, BaseMessageChunk, HumanMessage, HumanMessageChunk, SystemMessage, SystemMessageChunk, ToolMessage, ToolMessageChunk, filterMessages, trimMessages } from "@langchain/core/messages";
|
|
4
28
|
import { DynamicStructuredTool, DynamicTool, StructuredTool, Tool, tool } from "@langchain/core/tools";
|
|
5
29
|
import { context } from "@langchain/core/utils/context";
|
|
@@ -12,27 +36,68 @@ var browser_exports = /* @__PURE__ */ __exportAll({
|
|
|
12
36
|
AIMessageChunk: () => AIMessageChunk,
|
|
13
37
|
BaseMessage: () => BaseMessage,
|
|
14
38
|
BaseMessageChunk: () => BaseMessageChunk,
|
|
39
|
+
ClearToolUsesEdit: () => ClearToolUsesEdit,
|
|
15
40
|
Document: () => Document,
|
|
16
41
|
DynamicStructuredTool: () => DynamicStructuredTool,
|
|
17
42
|
DynamicTool: () => DynamicTool,
|
|
43
|
+
FakeToolCallingModel: () => FakeToolCallingModel,
|
|
18
44
|
HumanMessage: () => HumanMessage,
|
|
19
45
|
HumanMessageChunk: () => HumanMessageChunk,
|
|
20
46
|
InMemoryStore: () => InMemoryStore,
|
|
47
|
+
MIDDLEWARE_BRAND: () => MIDDLEWARE_BRAND,
|
|
48
|
+
MiddlewareError: () => MiddlewareError,
|
|
49
|
+
MultipleStructuredOutputsError: () => MultipleStructuredOutputsError,
|
|
50
|
+
MultipleToolsBoundError: () => MultipleToolsBoundError,
|
|
51
|
+
PIIDetectionError: () => PIIDetectionError,
|
|
52
|
+
ProviderStrategy: () => ProviderStrategy,
|
|
53
|
+
StructuredOutputParsingError: () => StructuredOutputParsingError,
|
|
21
54
|
StructuredTool: () => StructuredTool,
|
|
22
55
|
SystemMessage: () => SystemMessage,
|
|
23
56
|
SystemMessageChunk: () => SystemMessageChunk,
|
|
57
|
+
TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT: () => TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT,
|
|
24
58
|
Tool: () => Tool,
|
|
59
|
+
ToolCallLimitExceededError: () => ToolCallLimitExceededError,
|
|
60
|
+
ToolInvocationError: () => ToolInvocationError,
|
|
25
61
|
ToolMessage: () => ToolMessage,
|
|
26
62
|
ToolMessageChunk: () => ToolMessageChunk,
|
|
63
|
+
ToolStrategy: () => ToolStrategy,
|
|
64
|
+
anthropicPromptCachingMiddleware: () => anthropicPromptCachingMiddleware,
|
|
65
|
+
applyStrategy: () => applyStrategy,
|
|
27
66
|
context: () => context,
|
|
67
|
+
contextEditingMiddleware: () => contextEditingMiddleware,
|
|
68
|
+
countTokensApproximately: () => countTokensApproximately,
|
|
69
|
+
createAgent: () => createAgent,
|
|
70
|
+
createMiddleware: () => createMiddleware,
|
|
71
|
+
detectCreditCard: () => detectCreditCard,
|
|
72
|
+
detectEmail: () => detectEmail,
|
|
73
|
+
detectIP: () => detectIP,
|
|
74
|
+
detectMacAddress: () => detectMacAddress,
|
|
75
|
+
detectUrl: () => detectUrl,
|
|
76
|
+
dynamicSystemPromptMiddleware: () => dynamicSystemPromptMiddleware,
|
|
28
77
|
fakeModel: () => fakeModel,
|
|
29
78
|
filterMessages: () => filterMessages,
|
|
79
|
+
humanInTheLoopMiddleware: () => humanInTheLoopMiddleware,
|
|
30
80
|
initChatModel: () => initChatModel,
|
|
31
81
|
langchainMatchers: () => langchainMatchers,
|
|
82
|
+
llmToolSelectorMiddleware: () => llmToolSelectorMiddleware,
|
|
83
|
+
modelCallLimitMiddleware: () => modelCallLimitMiddleware,
|
|
84
|
+
modelFallbackMiddleware: () => modelFallbackMiddleware,
|
|
85
|
+
modelRetryMiddleware: () => modelRetryMiddleware,
|
|
86
|
+
openAIModerationMiddleware: () => openAIModerationMiddleware,
|
|
87
|
+
piiMiddleware: () => piiMiddleware,
|
|
88
|
+
piiRedactionMiddleware: () => piiRedactionMiddleware,
|
|
89
|
+
providerStrategy: () => providerStrategy,
|
|
90
|
+
resolveRedactionRule: () => resolveRedactionRule,
|
|
91
|
+
summarizationMiddleware: () => summarizationMiddleware,
|
|
92
|
+
todoListMiddleware: () => todoListMiddleware,
|
|
32
93
|
tool: () => tool,
|
|
94
|
+
toolCallLimitMiddleware: () => toolCallLimitMiddleware,
|
|
95
|
+
toolEmulatorMiddleware: () => toolEmulatorMiddleware,
|
|
96
|
+
toolRetryMiddleware: () => toolRetryMiddleware,
|
|
97
|
+
toolStrategy: () => toolStrategy,
|
|
33
98
|
trimMessages: () => trimMessages
|
|
34
99
|
});
|
|
35
100
|
//#endregion
|
|
36
|
-
export { AIMessage, AIMessageChunk, BaseMessage, BaseMessageChunk, Document, DynamicStructuredTool, DynamicTool, HumanMessage, HumanMessageChunk, InMemoryStore, StructuredTool, SystemMessage, SystemMessageChunk, Tool, ToolMessage, ToolMessageChunk, browser_exports, context, fakeModel, filterMessages, initChatModel, langchainMatchers, tool, trimMessages };
|
|
101
|
+
export { AIMessage, AIMessageChunk, BaseMessage, BaseMessageChunk, ClearToolUsesEdit, Document, DynamicStructuredTool, DynamicTool, FakeToolCallingModel, HumanMessage, HumanMessageChunk, InMemoryStore, MIDDLEWARE_BRAND, MiddlewareError, MultipleStructuredOutputsError, MultipleToolsBoundError, PIIDetectionError, ProviderStrategy, StructuredOutputParsingError, StructuredTool, SystemMessage, SystemMessageChunk, TODO_LIST_MIDDLEWARE_SYSTEM_PROMPT, Tool, ToolCallLimitExceededError, ToolInvocationError, ToolMessage, ToolMessageChunk, ToolStrategy, anthropicPromptCachingMiddleware, applyStrategy, browser_exports, context, contextEditingMiddleware, countTokensApproximately, createAgent, createMiddleware, detectCreditCard, detectEmail, detectIP, detectMacAddress, detectUrl, dynamicSystemPromptMiddleware, fakeModel, filterMessages, humanInTheLoopMiddleware, initChatModel, langchainMatchers, llmToolSelectorMiddleware, modelCallLimitMiddleware, modelFallbackMiddleware, modelRetryMiddleware, openAIModerationMiddleware, piiMiddleware, piiRedactionMiddleware, providerStrategy, resolveRedactionRule, summarizationMiddleware, todoListMiddleware, tool, toolCallLimitMiddleware, toolEmulatorMiddleware, toolRetryMiddleware, toolStrategy, trimMessages };
|
|
37
102
|
|
|
38
103
|
//# sourceMappingURL=browser.js.map
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","names":[],"sources":["../src/browser.ts"],"sourcesContent":["/**\n * LangChain browser exports\n */\n\n/**\n * LangChain Messages\n */\nexport {\n BaseMessage,\n BaseMessageChunk,\n AIMessage,\n AIMessageChunk,\n SystemMessage,\n SystemMessageChunk,\n HumanMessage,\n HumanMessageChunk,\n ToolMessage,\n ToolMessageChunk,\n type ContentBlock,\n filterMessages,\n trimMessages,\n} from \"@langchain/core/messages\";\n\n/**\n * Universal Chat Model\n */\nexport { initChatModel } from \"./chat_models/universal.js\";\n\n/**\n * LangChain Tools\n */\nexport {\n tool,\n Tool,\n type ToolRuntime,\n DynamicTool,\n StructuredTool,\n DynamicStructuredTool,\n} from \"@langchain/core/tools\";\n\n/**\n * LangChain utilities\n */\nexport { context } from \"@langchain/core/utils/context\";\n\n/**\n * LangChain Stores\n */\nexport { InMemoryStore } from \"@langchain/core/stores\";\n\n/**\n * LangChain Documents\n */\nexport { type DocumentInput, Document } from \"@langchain/core/documents\";\n\n/**\n * LangChain Testing Utilities\n */\nexport {\n langchainMatchers,\n type LangChainMatchers,\n fakeModel,\n} from \"@langchain/core/testing\";\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"browser.js","names":[],"sources":["../src/browser.ts"],"sourcesContent":["/**\n * LangChain browser exports\n */\n\n/**\n * LangChain Messages\n */\nexport {\n BaseMessage,\n BaseMessageChunk,\n AIMessage,\n AIMessageChunk,\n SystemMessage,\n SystemMessageChunk,\n HumanMessage,\n HumanMessageChunk,\n ToolMessage,\n ToolMessageChunk,\n type ContentBlock,\n filterMessages,\n trimMessages,\n} from \"@langchain/core/messages\";\n\n/**\n * Universal Chat Model\n */\nexport { initChatModel } from \"./chat_models/universal.js\";\n\n/**\n * LangChain Tools\n */\nexport {\n tool,\n Tool,\n type ToolRuntime,\n DynamicTool,\n StructuredTool,\n DynamicStructuredTool,\n} from \"@langchain/core/tools\";\n\n/**\n * LangChain utilities\n */\nexport { context } from \"@langchain/core/utils/context\";\n\n/**\n * LangChain Agents\n */\nexport * from \"./agents/index.js\";\n\n/**\n * `createAgent` pre-built middleware\n */\nexport * from \"./agents/middleware/index.js\";\n\n/**\n * LangChain Stores\n */\nexport { InMemoryStore } from \"@langchain/core/stores\";\n\n/**\n * LangChain Documents\n */\nexport { type DocumentInput, Document } from \"@langchain/core/documents\";\n\n/**\n * LangChain Testing Utilities\n */\nexport {\n langchainMatchers,\n type LangChainMatchers,\n fakeModel,\n} from \"@langchain/core/testing\";\n"],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "langchain",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.38",
|
|
4
4
|
"description": "Typescript bindings for langchain",
|
|
5
5
|
"author": "LangChain",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,16 +51,16 @@
|
|
|
51
51
|
"typeorm": "^0.3.28",
|
|
52
52
|
"typescript": "~5.8.3",
|
|
53
53
|
"vitest": "^3.2.4",
|
|
54
|
-
"yaml": "^2.8.
|
|
54
|
+
"yaml": "^2.8.3",
|
|
55
55
|
"@langchain/anthropic": "1.3.25",
|
|
56
56
|
"@langchain/cohere": "1.0.4",
|
|
57
|
-
"@langchain/core": "^1.1.
|
|
57
|
+
"@langchain/core": "^1.1.37",
|
|
58
58
|
"@langchain/eslint": "0.1.1",
|
|
59
|
-
"@langchain/openai": "1.
|
|
59
|
+
"@langchain/openai": "1.4.0",
|
|
60
60
|
"@langchain/tsconfig": "0.0.1"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@langchain/core": "^1.1.
|
|
63
|
+
"@langchain/core": "^1.1.37"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@langchain/langgraph": "^1.1.2",
|