langchain 1.2.19 → 1.2.20

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.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","names":["messages: BaseMessage[]","textContent: string","AIMessage","ToolMessage","hook:\n | BeforeAgentHook\n | BeforeModelHook\n | AfterAgentHook\n | AfterModelHook\n | undefined","arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook","ms: number","config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n }","retryNumber: number","delay: number"],"sources":["../../../src/agents/middleware/utils.ts"],"sourcesContent":["import {\n AIMessage,\n ToolMessage,\n type BaseMessage,\n} from \"@langchain/core/messages\";\nimport {\n AfterModelHook,\n AfterAgentHook,\n BeforeAgentHook,\n BeforeModelHook,\n} from \"./types.js\";\nimport { JumpToTarget } from \"../constants.js\";\n\n/**\n * Default token counter that approximates based on character count\n * @param messages Messages to count tokens for\n * @returns Approximate token count\n */\nexport function countTokensApproximately(messages: BaseMessage[]): number {\n let totalChars = 0;\n for (const msg of messages) {\n let textContent: string;\n if (typeof msg.content === \"string\") {\n textContent = msg.content;\n } else if (Array.isArray(msg.content)) {\n textContent = msg.content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (item.type === \"text\" && \"text\" in item) return item.text;\n return \"\";\n })\n .join(\"\");\n } else {\n textContent = \"\";\n }\n\n if (\n AIMessage.isInstance(msg) &&\n Array.isArray(msg.tool_calls) &&\n msg.tool_calls.length > 0\n ) {\n textContent += JSON.stringify(msg.tool_calls);\n }\n\n if (ToolMessage.isInstance(msg)) {\n textContent += msg.tool_call_id ?? \"\";\n }\n\n totalChars += textContent.length;\n }\n // Approximate 1 token = 4 characters\n return Math.ceil(totalChars / 4);\n}\n\nexport function getHookConstraint(\n hook:\n | BeforeAgentHook\n | BeforeModelHook\n | AfterAgentHook\n | AfterModelHook\n | undefined\n): JumpToTarget[] | undefined {\n if (!hook || typeof hook === \"function\") {\n return undefined;\n }\n return hook.canJumpTo;\n}\n\nexport function getHookFunction(\n arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook\n) {\n if (typeof arg === \"function\") {\n return arg;\n }\n return arg.hook;\n}\n\n/**\n * Sleep for the specified number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay for a retry attempt with exponential backoff and jitter.\n *\n * @param retryNumber - The retry attempt number (0-indexed)\n * @param config - Configuration for backoff calculation\n * @returns Delay in milliseconds before next retry\n *\n * @internal Exported for testing purposes\n */\nexport function calculateRetryDelay(\n config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n },\n retryNumber: number\n): number {\n const { backoffFactor, initialDelayMs, maxDelayMs, jitter } = config;\n\n let delay: number;\n if (backoffFactor === 0.0) {\n delay = initialDelayMs;\n } else {\n delay = initialDelayMs * backoffFactor ** retryNumber;\n }\n\n // Cap at maxDelayMs\n delay = Math.min(delay, maxDelayMs);\n\n if (jitter && delay > 0) {\n const jitterAmount = delay * 0.25;\n delay = delay + (Math.random() * 2 - 1) * jitterAmount;\n // Ensure delay is not negative after jitter\n delay = Math.max(0, delay);\n }\n\n return delay;\n}\n"],"mappings":";;;;;;;;;AAkBA,SAAgB,yBAAyBA,UAAiC;CACxE,IAAI,aAAa;AACjB,MAAK,MAAM,OAAO,UAAU;EAC1B,IAAIC;AACJ,MAAI,OAAO,IAAI,YAAY,UACzB,cAAc,IAAI;WACT,MAAM,QAAQ,IAAI,QAAQ,EACnC,cAAc,IAAI,QACf,IAAI,CAAC,SAAS;AACb,OAAI,OAAO,SAAS,SAAU,QAAO;AACrC,OAAI,KAAK,SAAS,UAAU,UAAU,KAAM,QAAO,KAAK;AACxD,UAAO;EACR,EAAC,CACD,KAAK,GAAG;OAEX,cAAc;AAGhB,MACEC,oCAAU,WAAW,IAAI,IACzB,MAAM,QAAQ,IAAI,WAAW,IAC7B,IAAI,WAAW,SAAS,GAExB,eAAe,KAAK,UAAU,IAAI,WAAW;AAG/C,MAAIC,sCAAY,WAAW,IAAI,EAC7B,eAAe,IAAI,gBAAgB;EAGrC,cAAc,YAAY;CAC3B;AAED,QAAO,KAAK,KAAK,aAAa,EAAE;AACjC;AAED,SAAgB,kBACdC,MAM4B;AAC5B,KAAI,CAAC,QAAQ,OAAO,SAAS,WAC3B,QAAO;AAET,QAAO,KAAK;AACb;AAED,SAAgB,gBACdC,KACA;AACA,KAAI,OAAO,QAAQ,WACjB,QAAO;AAET,QAAO,IAAI;AACZ;;;;AAKD,SAAgB,MAAMC,IAA2B;AAC/C,QAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG;AACxD;;;;;;;;;;AAWD,SAAgB,oBACdC,QAMAC,aACQ;CACR,MAAM,EAAE,eAAe,gBAAgB,YAAY,QAAQ,GAAG;CAE9D,IAAIC;AACJ,KAAI,kBAAkB,GACpB,QAAQ;MAER,QAAQ,iBAAiB,iBAAiB;CAI5C,QAAQ,KAAK,IAAI,OAAO,WAAW;AAEnC,KAAI,UAAU,QAAQ,GAAG;EACvB,MAAM,eAAe,QAAQ;EAC7B,QAAQ,SAAS,KAAK,QAAQ,GAAG,IAAI,KAAK;EAE1C,QAAQ,KAAK,IAAI,GAAG,MAAM;CAC3B;AAED,QAAO;AACR"}
1
+ {"version":3,"file":"utils.cjs","names":["messages: BaseMessage[]","tools?: Array<Record<string, any>> | null","textContent: string","AIMessage","ToolMessage","hook:\n | BeforeAgentHook\n | BeforeModelHook\n | AfterAgentHook\n | AfterModelHook\n | undefined","arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook","ms: number","config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n }","retryNumber: number","delay: number"],"sources":["../../../src/agents/middleware/utils.ts"],"sourcesContent":["import {\n AIMessage,\n ToolMessage,\n type BaseMessage,\n} from \"@langchain/core/messages\";\nimport { isLangChainTool } from \"@langchain/core/tools\";\nimport { convertToOpenAITool } from \"@langchain/core/utils/function_calling\";\nimport {\n AfterModelHook,\n AfterAgentHook,\n BeforeAgentHook,\n BeforeModelHook,\n} from \"./types.js\";\nimport { JumpToTarget } from \"../constants.js\";\n\n/**\n * Default token counter that approximates based on character count.\n *\n * If tools are provided, the token count also includes stringified tool schemas.\n *\n * @param messages Messages to count tokens for\n * @param tools Optional list of tools to include in the token count. Each tool\n * can be either a LangChain tool instance or a dict representing a tool schema.\n * LangChain tool instances are converted to OpenAI tool format before counting.\n * @returns Approximate token count\n */\nexport function countTokensApproximately(\n messages: BaseMessage[],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n tools?: Array<Record<string, any>> | null\n): number {\n const charsPerToken = 4;\n let totalChars = 0;\n\n // Count tokens for tools if provided\n if (tools && tools.length > 0) {\n let toolsChars = 0;\n for (const tool of tools) {\n const toolDict = isLangChainTool(tool) ? convertToOpenAITool(tool) : tool;\n toolsChars += JSON.stringify(toolDict).length;\n }\n totalChars += toolsChars;\n }\n\n for (const msg of messages) {\n let textContent: string;\n if (typeof msg.content === \"string\") {\n textContent = msg.content;\n } else if (Array.isArray(msg.content)) {\n textContent = msg.content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (item.type === \"text\" && \"text\" in item) return item.text;\n return \"\";\n })\n .join(\"\");\n } else {\n textContent = \"\";\n }\n\n if (\n AIMessage.isInstance(msg) &&\n Array.isArray(msg.tool_calls) &&\n msg.tool_calls.length > 0\n ) {\n textContent += JSON.stringify(msg.tool_calls);\n }\n\n if (ToolMessage.isInstance(msg)) {\n textContent += msg.tool_call_id ?? \"\";\n }\n\n totalChars += textContent.length;\n }\n // Approximate 1 token = 4 characters\n return Math.ceil(totalChars / charsPerToken);\n}\n\nexport function getHookConstraint(\n hook:\n | BeforeAgentHook\n | BeforeModelHook\n | AfterAgentHook\n | AfterModelHook\n | undefined\n): JumpToTarget[] | undefined {\n if (!hook || typeof hook === \"function\") {\n return undefined;\n }\n return hook.canJumpTo;\n}\n\nexport function getHookFunction(\n arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook\n) {\n if (typeof arg === \"function\") {\n return arg;\n }\n return arg.hook;\n}\n\n/**\n * Sleep for the specified number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay for a retry attempt with exponential backoff and jitter.\n *\n * @param retryNumber - The retry attempt number (0-indexed)\n * @param config - Configuration for backoff calculation\n * @returns Delay in milliseconds before next retry\n *\n * @internal Exported for testing purposes\n */\nexport function calculateRetryDelay(\n config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n },\n retryNumber: number\n): number {\n const { backoffFactor, initialDelayMs, maxDelayMs, jitter } = config;\n\n let delay: number;\n if (backoffFactor === 0.0) {\n delay = initialDelayMs;\n } else {\n delay = initialDelayMs * backoffFactor ** retryNumber;\n }\n\n // Cap at maxDelayMs\n delay = Math.min(delay, maxDelayMs);\n\n if (jitter && delay > 0) {\n const jitterAmount = delay * 0.25;\n delay = delay + (Math.random() * 2 - 1) * jitterAmount;\n // Ensure delay is not negative after jitter\n delay = Math.max(0, delay);\n }\n\n return delay;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA0BA,SAAgB,yBACdA,UAEAC,OACQ;CACR,MAAM,gBAAgB;CACtB,IAAI,aAAa;AAGjB,KAAI,SAAS,MAAM,SAAS,GAAG;EAC7B,IAAI,aAAa;AACjB,OAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,uDAA2B,KAAK,oEAAuB,KAAK,GAAG;GACrE,cAAc,KAAK,UAAU,SAAS,CAAC;EACxC;EACD,cAAc;CACf;AAED,MAAK,MAAM,OAAO,UAAU;EAC1B,IAAIC;AACJ,MAAI,OAAO,IAAI,YAAY,UACzB,cAAc,IAAI;WACT,MAAM,QAAQ,IAAI,QAAQ,EACnC,cAAc,IAAI,QACf,IAAI,CAAC,SAAS;AACb,OAAI,OAAO,SAAS,SAAU,QAAO;AACrC,OAAI,KAAK,SAAS,UAAU,UAAU,KAAM,QAAO,KAAK;AACxD,UAAO;EACR,EAAC,CACD,KAAK,GAAG;OAEX,cAAc;AAGhB,MACEC,oCAAU,WAAW,IAAI,IACzB,MAAM,QAAQ,IAAI,WAAW,IAC7B,IAAI,WAAW,SAAS,GAExB,eAAe,KAAK,UAAU,IAAI,WAAW;AAG/C,MAAIC,sCAAY,WAAW,IAAI,EAC7B,eAAe,IAAI,gBAAgB;EAGrC,cAAc,YAAY;CAC3B;AAED,QAAO,KAAK,KAAK,aAAa,cAAc;AAC7C;AAED,SAAgB,kBACdC,MAM4B;AAC5B,KAAI,CAAC,QAAQ,OAAO,SAAS,WAC3B,QAAO;AAET,QAAO,KAAK;AACb;AAED,SAAgB,gBACdC,KACA;AACA,KAAI,OAAO,QAAQ,WACjB,QAAO;AAET,QAAO,IAAI;AACZ;;;;AAKD,SAAgB,MAAMC,IAA2B;AAC/C,QAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG;AACxD;;;;;;;;;;AAWD,SAAgB,oBACdC,QAMAC,aACQ;CACR,MAAM,EAAE,eAAe,gBAAgB,YAAY,QAAQ,GAAG;CAE9D,IAAIC;AACJ,KAAI,kBAAkB,GACpB,QAAQ;MAER,QAAQ,iBAAiB,iBAAiB;CAI5C,QAAQ,KAAK,IAAI,OAAO,WAAW;AAEnC,KAAI,UAAU,QAAQ,GAAG;EACvB,MAAM,eAAe,QAAQ;EAC7B,QAAQ,SAAS,KAAK,QAAQ,GAAG,IAAI,KAAK;EAE1C,QAAQ,KAAK,IAAI,GAAG,MAAM;CAC3B;AAED,QAAO;AACR"}
@@ -3,11 +3,17 @@ import { BaseMessage } from "@langchain/core/messages";
3
3
  //#region src/agents/middleware/utils.d.ts
4
4
 
5
5
  /**
6
- * Default token counter that approximates based on character count
6
+ * Default token counter that approximates based on character count.
7
+ *
8
+ * If tools are provided, the token count also includes stringified tool schemas.
9
+ *
7
10
  * @param messages Messages to count tokens for
11
+ * @param tools Optional list of tools to include in the token count. Each tool
12
+ * can be either a LangChain tool instance or a dict representing a tool schema.
13
+ * LangChain tool instances are converted to OpenAI tool format before counting.
8
14
  * @returns Approximate token count
9
15
  */
10
- declare function countTokensApproximately(messages: BaseMessage[]): number;
16
+ declare function countTokensApproximately(messages: BaseMessage[], tools?: Array<Record<string, any>> | null): number;
11
17
  //#endregion
12
18
  export { countTokensApproximately };
13
19
  //# sourceMappingURL=utils.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.cts","names":["__types_js0","BaseMessage","AfterModelHook","AfterAgentHook","BeforeAgentHook","BeforeModelHook","JumpToTarget","countTokensApproximately","getHookConstraint","getHookFunction","___runtime_js0","AgentBuiltInState","Runtime","Partial","MiddlewareResult","Promise","sleep","calculateRetryDelay"],"sources":["../../../src/agents/middleware/utils.d.ts"],"sourcesContent":["import { type BaseMessage } from \"@langchain/core/messages\";\nimport { AfterModelHook, AfterAgentHook, BeforeAgentHook, BeforeModelHook } from \"./types.js\";\nimport { JumpToTarget } from \"../constants.js\";\n/**\n * Default token counter that approximates based on character count\n * @param messages Messages to count tokens for\n * @returns Approximate token count\n */\nexport declare function countTokensApproximately(messages: BaseMessage[]): number;\nexport declare function getHookConstraint(hook: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook | undefined): JumpToTarget[] | undefined;\nexport declare function getHookFunction(arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook): ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>);\n/**\n * Sleep for the specified number of milliseconds.\n */\nexport declare function sleep(ms: number): Promise<void>;\n/**\n * Calculate delay for a retry attempt with exponential backoff and jitter.\n *\n * @param retryNumber - The retry attempt number (0-indexed)\n * @param config - Configuration for backoff calculation\n * @returns Delay in milliseconds before next retry\n *\n * @internal Exported for testing purposes\n */\nexport declare function calculateRetryDelay(config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n}, retryNumber: number): number;\n//# sourceMappingURL=utils.d.ts.map"],"mappings":";;;;AAQA;;;;;iBAAwBO,wBAAAA,WAAmCN"}
1
+ {"version":3,"file":"utils.d.cts","names":["__types_js0","BaseMessage","AfterModelHook","AfterAgentHook","BeforeAgentHook","BeforeModelHook","JumpToTarget","countTokensApproximately","Record","Array","getHookConstraint","getHookFunction","___runtime_js0","AgentBuiltInState","Runtime","Partial","MiddlewareResult","Promise","sleep","calculateRetryDelay"],"sources":["../../../src/agents/middleware/utils.d.ts"],"sourcesContent":["import { type BaseMessage } from \"@langchain/core/messages\";\nimport { AfterModelHook, AfterAgentHook, BeforeAgentHook, BeforeModelHook } from \"./types.js\";\nimport { JumpToTarget } from \"../constants.js\";\n/**\n * Default token counter that approximates based on character count.\n *\n * If tools are provided, the token count also includes stringified tool schemas.\n *\n * @param messages Messages to count tokens for\n * @param tools Optional list of tools to include in the token count. Each tool\n * can be either a LangChain tool instance or a dict representing a tool schema.\n * LangChain tool instances are converted to OpenAI tool format before counting.\n * @returns Approximate token count\n */\nexport declare function countTokensApproximately(messages: BaseMessage[], tools?: Array<Record<string, any>> | null): number;\nexport declare function getHookConstraint(hook: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook | undefined): JumpToTarget[] | undefined;\nexport declare function getHookFunction(arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook): ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>);\n/**\n * Sleep for the specified number of milliseconds.\n */\nexport declare function sleep(ms: number): Promise<void>;\n/**\n * Calculate delay for a retry attempt with exponential backoff and jitter.\n *\n * @param retryNumber - The retry attempt number (0-indexed)\n * @param config - Configuration for backoff calculation\n * @returns Delay in milliseconds before next retry\n *\n * @internal Exported for testing purposes\n */\nexport declare function calculateRetryDelay(config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n}, retryNumber: number): number;\n//# sourceMappingURL=utils.d.ts.map"],"mappings":";;;;AAcA;;;;AAAuF;;;;;;;iBAA/DO,wBAAAA,WAAmCN,uBAAuBQ,MAAMD"}
@@ -5,11 +5,17 @@ import { BaseMessage } from "@langchain/core/messages";
5
5
  //#region src/agents/middleware/utils.d.ts
6
6
 
7
7
  /**
8
- * Default token counter that approximates based on character count
8
+ * Default token counter that approximates based on character count.
9
+ *
10
+ * If tools are provided, the token count also includes stringified tool schemas.
11
+ *
9
12
  * @param messages Messages to count tokens for
13
+ * @param tools Optional list of tools to include in the token count. Each tool
14
+ * can be either a LangChain tool instance or a dict representing a tool schema.
15
+ * LangChain tool instances are converted to OpenAI tool format before counting.
10
16
  * @returns Approximate token count
11
17
  */
12
- declare function countTokensApproximately(messages: BaseMessage[]): number;
18
+ declare function countTokensApproximately(messages: BaseMessage[], tools?: Array<Record<string, any>> | null): number;
13
19
  //#endregion
14
20
  export { countTokensApproximately };
15
21
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","names":["__types_js0","BaseMessage","AfterModelHook","AfterAgentHook","BeforeAgentHook","BeforeModelHook","JumpToTarget","countTokensApproximately","getHookConstraint","getHookFunction","___runtime_js0","AgentBuiltInState","Runtime","Partial","MiddlewareResult","Promise","sleep","calculateRetryDelay"],"sources":["../../../src/agents/middleware/utils.d.ts"],"sourcesContent":["import { type BaseMessage } from \"@langchain/core/messages\";\nimport { AfterModelHook, AfterAgentHook, BeforeAgentHook, BeforeModelHook } from \"./types.js\";\nimport { JumpToTarget } from \"../constants.js\";\n/**\n * Default token counter that approximates based on character count\n * @param messages Messages to count tokens for\n * @returns Approximate token count\n */\nexport declare function countTokensApproximately(messages: BaseMessage[]): number;\nexport declare function getHookConstraint(hook: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook | undefined): JumpToTarget[] | undefined;\nexport declare function getHookFunction(arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook): ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>);\n/**\n * Sleep for the specified number of milliseconds.\n */\nexport declare function sleep(ms: number): Promise<void>;\n/**\n * Calculate delay for a retry attempt with exponential backoff and jitter.\n *\n * @param retryNumber - The retry attempt number (0-indexed)\n * @param config - Configuration for backoff calculation\n * @returns Delay in milliseconds before next retry\n *\n * @internal Exported for testing purposes\n */\nexport declare function calculateRetryDelay(config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n}, retryNumber: number): number;\n//# sourceMappingURL=utils.d.ts.map"],"mappings":";;;;;;;;AAQA;;;iBAAwBO,wBAAAA,WAAmCN"}
1
+ {"version":3,"file":"utils.d.ts","names":["__types_js0","BaseMessage","AfterModelHook","AfterAgentHook","BeforeAgentHook","BeforeModelHook","JumpToTarget","countTokensApproximately","Record","Array","getHookConstraint","getHookFunction","___runtime_js0","AgentBuiltInState","Runtime","Partial","MiddlewareResult","Promise","sleep","calculateRetryDelay"],"sources":["../../../src/agents/middleware/utils.d.ts"],"sourcesContent":["import { type BaseMessage } from \"@langchain/core/messages\";\nimport { AfterModelHook, AfterAgentHook, BeforeAgentHook, BeforeModelHook } from \"./types.js\";\nimport { JumpToTarget } from \"../constants.js\";\n/**\n * Default token counter that approximates based on character count.\n *\n * If tools are provided, the token count also includes stringified tool schemas.\n *\n * @param messages Messages to count tokens for\n * @param tools Optional list of tools to include in the token count. Each tool\n * can be either a LangChain tool instance or a dict representing a tool schema.\n * LangChain tool instances are converted to OpenAI tool format before counting.\n * @returns Approximate token count\n */\nexport declare function countTokensApproximately(messages: BaseMessage[], tools?: Array<Record<string, any>> | null): number;\nexport declare function getHookConstraint(hook: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook | undefined): JumpToTarget[] | undefined;\nexport declare function getHookFunction(arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook): ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>) | ((state: import(\"../runtime.js\").AgentBuiltInState, runtime: import(\"../runtime.js\").Runtime<unknown>) => Promise<import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>> | import(\"./types.js\").MiddlewareResult<Partial<import(\"../runtime.js\").AgentBuiltInState>>);\n/**\n * Sleep for the specified number of milliseconds.\n */\nexport declare function sleep(ms: number): Promise<void>;\n/**\n * Calculate delay for a retry attempt with exponential backoff and jitter.\n *\n * @param retryNumber - The retry attempt number (0-indexed)\n * @param config - Configuration for backoff calculation\n * @returns Delay in milliseconds before next retry\n *\n * @internal Exported for testing purposes\n */\nexport declare function calculateRetryDelay(config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n}, retryNumber: number): number;\n//# sourceMappingURL=utils.d.ts.map"],"mappings":";;;;;;;;AAcA;;;;AAAuF;;;;;iBAA/DO,wBAAAA,WAAmCN,uBAAuBQ,MAAMD"}
@@ -1,13 +1,30 @@
1
1
  import { AIMessage, ToolMessage } from "@langchain/core/messages";
2
+ import { isLangChainTool } from "@langchain/core/tools";
3
+ import { convertToOpenAITool } from "@langchain/core/utils/function_calling";
2
4
 
3
5
  //#region src/agents/middleware/utils.ts
4
6
  /**
5
- * Default token counter that approximates based on character count
7
+ * Default token counter that approximates based on character count.
8
+ *
9
+ * If tools are provided, the token count also includes stringified tool schemas.
10
+ *
6
11
  * @param messages Messages to count tokens for
12
+ * @param tools Optional list of tools to include in the token count. Each tool
13
+ * can be either a LangChain tool instance or a dict representing a tool schema.
14
+ * LangChain tool instances are converted to OpenAI tool format before counting.
7
15
  * @returns Approximate token count
8
16
  */
9
- function countTokensApproximately(messages) {
17
+ function countTokensApproximately(messages, tools) {
18
+ const charsPerToken = 4;
10
19
  let totalChars = 0;
20
+ if (tools && tools.length > 0) {
21
+ let toolsChars = 0;
22
+ for (const tool$1 of tools) {
23
+ const toolDict = isLangChainTool(tool$1) ? convertToOpenAITool(tool$1) : tool$1;
24
+ toolsChars += JSON.stringify(toolDict).length;
25
+ }
26
+ totalChars += toolsChars;
27
+ }
11
28
  for (const msg of messages) {
12
29
  let textContent;
13
30
  if (typeof msg.content === "string") textContent = msg.content;
@@ -21,7 +38,7 @@ function countTokensApproximately(messages) {
21
38
  if (ToolMessage.isInstance(msg)) textContent += msg.tool_call_id ?? "";
22
39
  totalChars += textContent.length;
23
40
  }
24
- return Math.ceil(totalChars / 4);
41
+ return Math.ceil(totalChars / charsPerToken);
25
42
  }
26
43
  function getHookConstraint(hook) {
27
44
  if (!hook || typeof hook === "function") return void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":["messages: BaseMessage[]","textContent: string","hook:\n | BeforeAgentHook\n | BeforeModelHook\n | AfterAgentHook\n | AfterModelHook\n | undefined","arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook","ms: number","config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n }","retryNumber: number","delay: number"],"sources":["../../../src/agents/middleware/utils.ts"],"sourcesContent":["import {\n AIMessage,\n ToolMessage,\n type BaseMessage,\n} from \"@langchain/core/messages\";\nimport {\n AfterModelHook,\n AfterAgentHook,\n BeforeAgentHook,\n BeforeModelHook,\n} from \"./types.js\";\nimport { JumpToTarget } from \"../constants.js\";\n\n/**\n * Default token counter that approximates based on character count\n * @param messages Messages to count tokens for\n * @returns Approximate token count\n */\nexport function countTokensApproximately(messages: BaseMessage[]): number {\n let totalChars = 0;\n for (const msg of messages) {\n let textContent: string;\n if (typeof msg.content === \"string\") {\n textContent = msg.content;\n } else if (Array.isArray(msg.content)) {\n textContent = msg.content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (item.type === \"text\" && \"text\" in item) return item.text;\n return \"\";\n })\n .join(\"\");\n } else {\n textContent = \"\";\n }\n\n if (\n AIMessage.isInstance(msg) &&\n Array.isArray(msg.tool_calls) &&\n msg.tool_calls.length > 0\n ) {\n textContent += JSON.stringify(msg.tool_calls);\n }\n\n if (ToolMessage.isInstance(msg)) {\n textContent += msg.tool_call_id ?? \"\";\n }\n\n totalChars += textContent.length;\n }\n // Approximate 1 token = 4 characters\n return Math.ceil(totalChars / 4);\n}\n\nexport function getHookConstraint(\n hook:\n | BeforeAgentHook\n | BeforeModelHook\n | AfterAgentHook\n | AfterModelHook\n | undefined\n): JumpToTarget[] | undefined {\n if (!hook || typeof hook === \"function\") {\n return undefined;\n }\n return hook.canJumpTo;\n}\n\nexport function getHookFunction(\n arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook\n) {\n if (typeof arg === \"function\") {\n return arg;\n }\n return arg.hook;\n}\n\n/**\n * Sleep for the specified number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay for a retry attempt with exponential backoff and jitter.\n *\n * @param retryNumber - The retry attempt number (0-indexed)\n * @param config - Configuration for backoff calculation\n * @returns Delay in milliseconds before next retry\n *\n * @internal Exported for testing purposes\n */\nexport function calculateRetryDelay(\n config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n },\n retryNumber: number\n): number {\n const { backoffFactor, initialDelayMs, maxDelayMs, jitter } = config;\n\n let delay: number;\n if (backoffFactor === 0.0) {\n delay = initialDelayMs;\n } else {\n delay = initialDelayMs * backoffFactor ** retryNumber;\n }\n\n // Cap at maxDelayMs\n delay = Math.min(delay, maxDelayMs);\n\n if (jitter && delay > 0) {\n const jitterAmount = delay * 0.25;\n delay = delay + (Math.random() * 2 - 1) * jitterAmount;\n // Ensure delay is not negative after jitter\n delay = Math.max(0, delay);\n }\n\n return delay;\n}\n"],"mappings":";;;;;;;;AAkBA,SAAgB,yBAAyBA,UAAiC;CACxE,IAAI,aAAa;AACjB,MAAK,MAAM,OAAO,UAAU;EAC1B,IAAIC;AACJ,MAAI,OAAO,IAAI,YAAY,UACzB,cAAc,IAAI;WACT,MAAM,QAAQ,IAAI,QAAQ,EACnC,cAAc,IAAI,QACf,IAAI,CAAC,SAAS;AACb,OAAI,OAAO,SAAS,SAAU,QAAO;AACrC,OAAI,KAAK,SAAS,UAAU,UAAU,KAAM,QAAO,KAAK;AACxD,UAAO;EACR,EAAC,CACD,KAAK,GAAG;OAEX,cAAc;AAGhB,MACE,UAAU,WAAW,IAAI,IACzB,MAAM,QAAQ,IAAI,WAAW,IAC7B,IAAI,WAAW,SAAS,GAExB,eAAe,KAAK,UAAU,IAAI,WAAW;AAG/C,MAAI,YAAY,WAAW,IAAI,EAC7B,eAAe,IAAI,gBAAgB;EAGrC,cAAc,YAAY;CAC3B;AAED,QAAO,KAAK,KAAK,aAAa,EAAE;AACjC;AAED,SAAgB,kBACdC,MAM4B;AAC5B,KAAI,CAAC,QAAQ,OAAO,SAAS,WAC3B,QAAO;AAET,QAAO,KAAK;AACb;AAED,SAAgB,gBACdC,KACA;AACA,KAAI,OAAO,QAAQ,WACjB,QAAO;AAET,QAAO,IAAI;AACZ;;;;AAKD,SAAgB,MAAMC,IAA2B;AAC/C,QAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG;AACxD;;;;;;;;;;AAWD,SAAgB,oBACdC,QAMAC,aACQ;CACR,MAAM,EAAE,eAAe,gBAAgB,YAAY,QAAQ,GAAG;CAE9D,IAAIC;AACJ,KAAI,kBAAkB,GACpB,QAAQ;MAER,QAAQ,iBAAiB,iBAAiB;CAI5C,QAAQ,KAAK,IAAI,OAAO,WAAW;AAEnC,KAAI,UAAU,QAAQ,GAAG;EACvB,MAAM,eAAe,QAAQ;EAC7B,QAAQ,SAAS,KAAK,QAAQ,GAAG,IAAI,KAAK;EAE1C,QAAQ,KAAK,IAAI,GAAG,MAAM;CAC3B;AAED,QAAO;AACR"}
1
+ {"version":3,"file":"utils.js","names":["messages: BaseMessage[]","tools?: Array<Record<string, any>> | null","tool","textContent: string","hook:\n | BeforeAgentHook\n | BeforeModelHook\n | AfterAgentHook\n | AfterModelHook\n | undefined","arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook","ms: number","config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n }","retryNumber: number","delay: number"],"sources":["../../../src/agents/middleware/utils.ts"],"sourcesContent":["import {\n AIMessage,\n ToolMessage,\n type BaseMessage,\n} from \"@langchain/core/messages\";\nimport { isLangChainTool } from \"@langchain/core/tools\";\nimport { convertToOpenAITool } from \"@langchain/core/utils/function_calling\";\nimport {\n AfterModelHook,\n AfterAgentHook,\n BeforeAgentHook,\n BeforeModelHook,\n} from \"./types.js\";\nimport { JumpToTarget } from \"../constants.js\";\n\n/**\n * Default token counter that approximates based on character count.\n *\n * If tools are provided, the token count also includes stringified tool schemas.\n *\n * @param messages Messages to count tokens for\n * @param tools Optional list of tools to include in the token count. Each tool\n * can be either a LangChain tool instance or a dict representing a tool schema.\n * LangChain tool instances are converted to OpenAI tool format before counting.\n * @returns Approximate token count\n */\nexport function countTokensApproximately(\n messages: BaseMessage[],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n tools?: Array<Record<string, any>> | null\n): number {\n const charsPerToken = 4;\n let totalChars = 0;\n\n // Count tokens for tools if provided\n if (tools && tools.length > 0) {\n let toolsChars = 0;\n for (const tool of tools) {\n const toolDict = isLangChainTool(tool) ? convertToOpenAITool(tool) : tool;\n toolsChars += JSON.stringify(toolDict).length;\n }\n totalChars += toolsChars;\n }\n\n for (const msg of messages) {\n let textContent: string;\n if (typeof msg.content === \"string\") {\n textContent = msg.content;\n } else if (Array.isArray(msg.content)) {\n textContent = msg.content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (item.type === \"text\" && \"text\" in item) return item.text;\n return \"\";\n })\n .join(\"\");\n } else {\n textContent = \"\";\n }\n\n if (\n AIMessage.isInstance(msg) &&\n Array.isArray(msg.tool_calls) &&\n msg.tool_calls.length > 0\n ) {\n textContent += JSON.stringify(msg.tool_calls);\n }\n\n if (ToolMessage.isInstance(msg)) {\n textContent += msg.tool_call_id ?? \"\";\n }\n\n totalChars += textContent.length;\n }\n // Approximate 1 token = 4 characters\n return Math.ceil(totalChars / charsPerToken);\n}\n\nexport function getHookConstraint(\n hook:\n | BeforeAgentHook\n | BeforeModelHook\n | AfterAgentHook\n | AfterModelHook\n | undefined\n): JumpToTarget[] | undefined {\n if (!hook || typeof hook === \"function\") {\n return undefined;\n }\n return hook.canJumpTo;\n}\n\nexport function getHookFunction(\n arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook\n) {\n if (typeof arg === \"function\") {\n return arg;\n }\n return arg.hook;\n}\n\n/**\n * Sleep for the specified number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay for a retry attempt with exponential backoff and jitter.\n *\n * @param retryNumber - The retry attempt number (0-indexed)\n * @param config - Configuration for backoff calculation\n * @returns Delay in milliseconds before next retry\n *\n * @internal Exported for testing purposes\n */\nexport function calculateRetryDelay(\n config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n },\n retryNumber: number\n): number {\n const { backoffFactor, initialDelayMs, maxDelayMs, jitter } = config;\n\n let delay: number;\n if (backoffFactor === 0.0) {\n delay = initialDelayMs;\n } else {\n delay = initialDelayMs * backoffFactor ** retryNumber;\n }\n\n // Cap at maxDelayMs\n delay = Math.min(delay, maxDelayMs);\n\n if (jitter && delay > 0) {\n const jitterAmount = delay * 0.25;\n delay = delay + (Math.random() * 2 - 1) * jitterAmount;\n // Ensure delay is not negative after jitter\n delay = Math.max(0, delay);\n }\n\n return delay;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA0BA,SAAgB,yBACdA,UAEAC,OACQ;CACR,MAAM,gBAAgB;CACtB,IAAI,aAAa;AAGjB,KAAI,SAAS,MAAM,SAAS,GAAG;EAC7B,IAAI,aAAa;AACjB,OAAK,MAAMC,UAAQ,OAAO;GACxB,MAAM,WAAW,gBAAgBA,OAAK,GAAG,oBAAoBA,OAAK,GAAGA;GACrE,cAAc,KAAK,UAAU,SAAS,CAAC;EACxC;EACD,cAAc;CACf;AAED,MAAK,MAAM,OAAO,UAAU;EAC1B,IAAIC;AACJ,MAAI,OAAO,IAAI,YAAY,UACzB,cAAc,IAAI;WACT,MAAM,QAAQ,IAAI,QAAQ,EACnC,cAAc,IAAI,QACf,IAAI,CAAC,SAAS;AACb,OAAI,OAAO,SAAS,SAAU,QAAO;AACrC,OAAI,KAAK,SAAS,UAAU,UAAU,KAAM,QAAO,KAAK;AACxD,UAAO;EACR,EAAC,CACD,KAAK,GAAG;OAEX,cAAc;AAGhB,MACE,UAAU,WAAW,IAAI,IACzB,MAAM,QAAQ,IAAI,WAAW,IAC7B,IAAI,WAAW,SAAS,GAExB,eAAe,KAAK,UAAU,IAAI,WAAW;AAG/C,MAAI,YAAY,WAAW,IAAI,EAC7B,eAAe,IAAI,gBAAgB;EAGrC,cAAc,YAAY;CAC3B;AAED,QAAO,KAAK,KAAK,aAAa,cAAc;AAC7C;AAED,SAAgB,kBACdC,MAM4B;AAC5B,KAAI,CAAC,QAAQ,OAAO,SAAS,WAC3B,QAAO;AAET,QAAO,KAAK;AACb;AAED,SAAgB,gBACdC,KACA;AACA,KAAI,OAAO,QAAQ,WACjB,QAAO;AAET,QAAO,IAAI;AACZ;;;;AAKD,SAAgB,MAAMC,IAA2B;AAC/C,QAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG;AACxD;;;;;;;;;;AAWD,SAAgB,oBACdC,QAMAC,aACQ;CACR,MAAM,EAAE,eAAe,gBAAgB,YAAY,QAAQ,GAAG;CAE9D,IAAIC;AACJ,KAAI,kBAAkB,GACpB,QAAQ;MAER,QAAQ,iBAAiB,iBAAiB;CAI5C,QAAQ,KAAK,IAAI,OAAO,WAAW;AAEnC,KAAI,UAAU,QAAQ,GAAG;EACvB,MAAM,eAAe,QAAQ;EAC7B,QAAQ,SAAS,KAAK,QAAQ,GAAG,IAAI,KAAK;EAE1C,QAAQ,KAAK,IAAI,GAAG,MAAM;CAC3B;AAED,QAAO;AACR"}
@@ -18,7 +18,7 @@ const __langchain_core_utils_types = require_rolldown_runtime.__toESM(require("@
18
18
  * @returns True if the response is an internal model response, false otherwise.
19
19
  */
20
20
  function isInternalModelResponse(response) {
21
- return __langchain_core_messages.AIMessage.isInstance(response) || typeof response === "object" && response !== null && "structuredResponse" in response && "messages" in response;
21
+ return __langchain_core_messages.AIMessage.isInstance(response) || (0, __langchain_langgraph.isCommand)(response) || typeof response === "object" && response !== null && "structuredResponse" in response && "messages" in response;
22
22
  }
23
23
  /**
24
24
  * The name of the agent node in the state graph.
@@ -27,7 +27,6 @@ const AGENT_NODE_NAME = "model_request";
27
27
  var AgentNode = class extends require_RunnableCallable.RunnableCallable {
28
28
  #options;
29
29
  #systemMessage;
30
- #currentSystemMessage;
31
30
  constructor(options) {
32
31
  super({
33
32
  name: options.name ?? "model",
@@ -76,31 +75,35 @@ var AgentNode = class extends require_RunnableCallable.RunnableCallable {
76
75
  * If so, we should generate structured response (if needed) and stop
77
76
  */
78
77
  const lastMessage = state.messages.at(-1);
79
- if (lastMessage && __langchain_core_messages.ToolMessage.isInstance(lastMessage) && lastMessage.name && this.#options.shouldReturnDirect.has(lastMessage.name))
80
- /**
81
- * return directly without invoking the model again
82
- */
83
- return { messages: [] };
84
- const response = await this.#invokeModel(state, config);
78
+ if (lastMessage && __langchain_core_messages.ToolMessage.isInstance(lastMessage) && lastMessage.name && this.#options.shouldReturnDirect.has(lastMessage.name)) return [new __langchain_langgraph.Command({ update: { messages: [] } })];
79
+ const { response, lastAiMessage, collectedCommands } = await this.#invokeModel(state, config);
85
80
  /**
86
- * if we were able to generate a structured response, return it
81
+ * structuredResponse return as a plain state update dict (not a Command)
82
+ * because the structuredResponse channel uses UntrackedValue(guard=true)
83
+ * which only allows a single write per step.
87
84
  */
88
- if ("structuredResponse" in response) return {
89
- messages: [...state.messages, ...response.messages || []],
90
- structuredResponse: response.structuredResponse
91
- };
92
- /**
93
- * if we need to direct the agent to the model, return the update
94
- */
95
- if (response instanceof __langchain_langgraph.Command) return response;
96
- response.name = this.name;
97
- response.lc_kwargs.name = this.name;
98
- if (this.#areMoreStepsNeeded(state, response)) return { messages: [new __langchain_core_messages.AIMessage({
99
- content: "Sorry, need more steps to process this request.",
100
- name: this.name,
101
- id: response.id
102
- })] };
103
- return { messages: [response] };
85
+ if (typeof response === "object" && response !== null && "structuredResponse" in response && "messages" in response) {
86
+ const { structuredResponse, messages } = response;
87
+ return {
88
+ messages: [...state.messages, ...messages],
89
+ structuredResponse
90
+ };
91
+ }
92
+ const commands = [];
93
+ const aiMessage = __langchain_core_messages.AIMessage.isInstance(response) ? response : lastAiMessage;
94
+ if (aiMessage) {
95
+ aiMessage.name = this.name;
96
+ aiMessage.lc_kwargs.name = this.name;
97
+ if (this.#areMoreStepsNeeded(state, aiMessage)) commands.push(new __langchain_langgraph.Command({ update: { messages: [new __langchain_core_messages.AIMessage({
98
+ content: "Sorry, need more steps to process this request.",
99
+ name: this.name,
100
+ id: aiMessage.id
101
+ })] } }));
102
+ else commands.push(new __langchain_langgraph.Command({ update: { messages: [aiMessage] } }));
103
+ }
104
+ if ((0, __langchain_langgraph.isCommand)(response) && !collectedCommands.includes(response)) commands.push(response);
105
+ commands.push(...collectedCommands);
106
+ return commands;
104
107
  }
105
108
  /**
106
109
  * Derive the model from the options.
@@ -117,6 +120,18 @@ var AgentNode = class extends require_RunnableCallable.RunnableCallable {
117
120
  const model = await this.#deriveModel();
118
121
  const lgConfig = config;
119
122
  /**
123
+ * Create a local variable for current system message to avoid concurrency issues
124
+ * Each invocation gets its own copy
125
+ */
126
+ let currentSystemMessage = this.#systemMessage;
127
+ /**
128
+ * Shared tracking state for AIMessage and Command collection.
129
+ * lastAiMessage tracks the effective AIMessage through the middleware chain.
130
+ * collectedCommands accumulates Commands returned by middleware (not base handler).
131
+ */
132
+ let lastAiMessage = null;
133
+ const collectedCommands = [];
134
+ /**
120
135
  * Create the base handler that performs the actual model invocation
121
136
  */
122
137
  const baseHandler = async (request) => {
@@ -129,38 +144,39 @@ var AgentNode = class extends require_RunnableCallable.RunnableCallable {
129
144
  /**
130
145
  * prepend the system message to the messages if it is not empty
131
146
  */
132
- const messages = [...this.#currentSystemMessage.text === "" ? [] : [this.#currentSystemMessage], ...request.messages];
147
+ const messages = [...currentSystemMessage.text === "" ? [] : [currentSystemMessage], ...request.messages];
133
148
  const signal = require_utils$1.mergeAbortSignals(this.#options.signal, config.signal);
134
- const response = await (0, __langchain_core_runnables.raceWithSignal)(modelWithTools.invoke(messages, {
149
+ const response$1 = await (0, __langchain_core_runnables.raceWithSignal)(modelWithTools.invoke(messages, {
135
150
  ...config,
136
151
  signal
137
152
  }), signal);
153
+ lastAiMessage = response$1;
138
154
  /**
139
155
  * if the user requests a native schema output, try to parse the response
140
156
  * and return the structured response if it is valid
141
157
  */
142
158
  if (structuredResponseFormat?.type === "native") {
143
- const structuredResponse = structuredResponseFormat.strategy.parse(response);
159
+ const structuredResponse = structuredResponseFormat.strategy.parse(response$1);
144
160
  if (structuredResponse) return {
145
161
  structuredResponse,
146
- messages: [response]
162
+ messages: [response$1]
147
163
  };
148
- return response;
164
+ return response$1;
149
165
  }
150
- if (!structuredResponseFormat || !response.tool_calls) return response;
151
- const toolCalls = response.tool_calls.filter((call) => call.name in structuredResponseFormat.tools);
166
+ if (!structuredResponseFormat || !response$1.tool_calls) return response$1;
167
+ const toolCalls = response$1.tool_calls.filter((call) => call.name in structuredResponseFormat.tools);
152
168
  /**
153
169
  * if there were not structured tool calls, we can return the response
154
170
  */
155
- if (toolCalls.length === 0) return response;
171
+ if (toolCalls.length === 0) return response$1;
156
172
  /**
157
173
  * if there were multiple structured tool calls, we should throw an error as this
158
174
  * scenario is not defined/supported.
159
175
  */
160
- if (toolCalls.length > 1) return this.#handleMultipleStructuredOutputs(response, toolCalls, structuredResponseFormat);
176
+ if (toolCalls.length > 1) return this.#handleMultipleStructuredOutputs(response$1, toolCalls, structuredResponseFormat);
161
177
  const toolStrategy = structuredResponseFormat.tools[toolCalls[0].name];
162
178
  const toolMessageContent = toolStrategy?.options?.toolMessageContent;
163
- return this.#handleSingleStructuredOutput(response, toolCalls[0], structuredResponseFormat, toolMessageContent ?? options.lastMessage);
179
+ return this.#handleSingleStructuredOutput(response$1, toolCalls[0], structuredResponseFormat, toolMessageContent ?? options.lastMessage);
164
180
  };
165
181
  const wrapperMiddleware = this.#options.wrapModelCallHookMiddleware ?? [];
166
182
  let wrappedHandler = baseHandler;
@@ -217,43 +233,53 @@ var AgentNode = class extends require_RunnableCallable.RunnableCallable {
217
233
  const invalidTools = modifiedTools.filter((tool) => require_utils.isClientTool(tool) && this.#options.toolClasses.every((t) => t !== tool));
218
234
  if (invalidTools.length > 0) throw new Error(`You have modified a tool in "wrapModelCall" hook of middleware "${currentMiddleware.name}": ${invalidTools.map((tool) => tool.name).join(", ")}. This is not supported.`);
219
235
  let normalizedReq = req;
220
- const hasSystemPromptChanged = req.systemPrompt !== this.#currentSystemMessage.text;
221
- const hasSystemMessageChanged = req.systemMessage !== this.#currentSystemMessage;
236
+ const hasSystemPromptChanged = req.systemPrompt !== currentSystemMessage.text;
237
+ const hasSystemMessageChanged = req.systemMessage !== currentSystemMessage;
222
238
  if (hasSystemPromptChanged && hasSystemMessageChanged) throw new Error("Cannot change both systemPrompt and systemMessage in the same request.");
223
239
  /**
224
240
  * Check if systemPrompt is a string was changed, if so create a new SystemMessage
225
241
  */
226
242
  if (hasSystemPromptChanged) {
227
- this.#currentSystemMessage = new __langchain_core_messages.SystemMessage({ content: [{
243
+ currentSystemMessage = new __langchain_core_messages.SystemMessage({ content: [{
228
244
  type: "text",
229
245
  text: req.systemPrompt
230
246
  }] });
231
247
  normalizedReq = {
232
248
  ...req,
233
- systemPrompt: this.#currentSystemMessage.text,
234
- systemMessage: this.#currentSystemMessage
249
+ systemPrompt: currentSystemMessage.text,
250
+ systemMessage: currentSystemMessage
235
251
  };
236
252
  }
237
253
  /**
238
254
  * If the systemMessage was changed, update the current system message
239
255
  */
240
256
  if (hasSystemMessageChanged) {
241
- this.#currentSystemMessage = new __langchain_core_messages.SystemMessage({ ...req.systemMessage });
257
+ currentSystemMessage = new __langchain_core_messages.SystemMessage({ ...req.systemMessage });
242
258
  normalizedReq = {
243
259
  ...req,
244
- systemPrompt: this.#currentSystemMessage.text,
245
- systemMessage: this.#currentSystemMessage
260
+ systemPrompt: currentSystemMessage.text,
261
+ systemMessage: currentSystemMessage
246
262
  };
247
263
  }
248
- return innerHandler(normalizedReq);
264
+ const innerHandlerResult = await innerHandler(normalizedReq);
265
+ /**
266
+ * Normalize Commands so middleware always sees AIMessage from handler().
267
+ * When an inner middleware returns a Command, substitute the tracked
268
+ * lastAiMessage. The raw Command is still captured in innerHandlerResult
269
+ * for the framework's Command collection.
270
+ */
271
+ if ((0, __langchain_langgraph.isCommand)(innerHandlerResult) && lastAiMessage) return lastAiMessage;
272
+ return innerHandlerResult;
249
273
  };
250
274
  if (!currentMiddleware.wrapModelCall) return handlerWithValidation(requestWithStateAndRuntime);
251
275
  try {
252
276
  const middlewareResponse = await currentMiddleware.wrapModelCall(requestWithStateAndRuntime, handlerWithValidation);
253
277
  /**
254
- * Validate that this specific middleware returned a valid AIMessage
278
+ * Validate that this specific middleware returned a valid response
255
279
  */
256
- if (!isInternalModelResponse(middlewareResponse)) throw new Error(`Invalid response from "wrapModelCall" in middleware "${currentMiddleware.name}": expected AIMessage, got ${typeof middlewareResponse}`);
280
+ if (!isInternalModelResponse(middlewareResponse)) throw new Error(`Invalid response from "wrapModelCall" in middleware "${currentMiddleware.name}": expected AIMessage or Command, got ${typeof middlewareResponse}`);
281
+ if (__langchain_core_messages.AIMessage.isInstance(middlewareResponse)) lastAiMessage = middlewareResponse;
282
+ else if ((0, __langchain_langgraph.isCommand)(middlewareResponse)) collectedCommands.push(middlewareResponse);
257
283
  return middlewareResponse;
258
284
  } catch (error) {
259
285
  throw require_errors.MiddlewareError.wrap(error, currentMiddleware.name);
@@ -266,11 +292,11 @@ var AgentNode = class extends require_RunnableCallable.RunnableCallable {
266
292
  * Reset current system prompt to initial state and convert to string using .text getter
267
293
  * for backwards compatibility with ModelRequest
268
294
  */
269
- this.#currentSystemMessage = this.#systemMessage;
295
+ currentSystemMessage = this.#systemMessage;
270
296
  const initialRequest = {
271
297
  model,
272
- systemPrompt: this.#currentSystemMessage?.text,
273
- systemMessage: this.#currentSystemMessage,
298
+ systemPrompt: currentSystemMessage?.text,
299
+ systemMessage: currentSystemMessage,
274
300
  messages: state.messages,
275
301
  tools: this.#options.toolClasses,
276
302
  state,
@@ -281,7 +307,12 @@ var AgentNode = class extends require_RunnableCallable.RunnableCallable {
281
307
  signal: lgConfig.signal
282
308
  })
283
309
  };
284
- return wrappedHandler(initialRequest);
310
+ const response = await wrappedHandler(initialRequest);
311
+ return {
312
+ response,
313
+ lastAiMessage,
314
+ collectedCommands
315
+ };
285
316
  }
286
317
  /**
287
318
  * If the model returns multiple structured outputs, we need to handle it.
@@ -439,9 +470,13 @@ var AgentNode = class extends require_RunnableCallable.RunnableCallable {
439
470
  const modelRunnable = this.#options.includeAgentName === "inline" ? require_withAgentName.withAgentName(modelWithTools, this.#options.includeAgentName) : modelWithTools;
440
471
  return modelRunnable;
441
472
  }
473
+ /**
474
+ * Returns internal bookkeeping state for StateManager, not graph output.
475
+ * The return shape differs from the node's output type (Command).
476
+ */
442
477
  getState() {
443
478
  const state = super.getState();
444
- const origState = state && !(state instanceof __langchain_langgraph.Command) ? state : {};
479
+ const origState = state && !(0, __langchain_langgraph.isCommand)(state) ? state : {};
445
480
  return {
446
481
  messages: [],
447
482
  ...origState