langchain 1.0.0-alpha.2 → 1.0.0-alpha.3

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.
Files changed (44) hide show
  1. package/dist/agents/ReactAgent.cjs +1 -1
  2. package/dist/agents/ReactAgent.cjs.map +1 -1
  3. package/dist/agents/ReactAgent.d.cts.map +1 -1
  4. package/dist/agents/ReactAgent.d.ts.map +1 -1
  5. package/dist/agents/ReactAgent.js +2 -2
  6. package/dist/agents/ReactAgent.js.map +1 -1
  7. package/dist/agents/annotation.cjs +120 -0
  8. package/dist/agents/annotation.cjs.map +1 -1
  9. package/dist/agents/annotation.d.cts +15 -11
  10. package/dist/agents/annotation.d.cts.map +1 -1
  11. package/dist/agents/annotation.d.ts +15 -11
  12. package/dist/agents/annotation.d.ts.map +1 -1
  13. package/dist/agents/annotation.js +120 -1
  14. package/dist/agents/annotation.js.map +1 -1
  15. package/dist/agents/index.d.cts +1 -1
  16. package/dist/agents/index.d.ts +1 -1
  17. package/dist/agents/nodes/AgentNode.cjs +8 -3
  18. package/dist/agents/nodes/AgentNode.cjs.map +1 -1
  19. package/dist/agents/nodes/AgentNode.js +8 -3
  20. package/dist/agents/nodes/AgentNode.js.map +1 -1
  21. package/dist/agents/nodes/ToolNode.cjs +1 -1
  22. package/dist/agents/nodes/ToolNode.cjs.map +1 -1
  23. package/dist/agents/nodes/ToolNode.js +1 -1
  24. package/dist/agents/nodes/ToolNode.js.map +1 -1
  25. package/dist/agents/responses.cjs +1 -2
  26. package/dist/agents/responses.cjs.map +1 -1
  27. package/dist/agents/responses.d.cts +5 -0
  28. package/dist/agents/responses.d.cts.map +1 -1
  29. package/dist/agents/responses.d.ts +5 -0
  30. package/dist/agents/responses.d.ts.map +1 -1
  31. package/dist/agents/responses.js +1 -2
  32. package/dist/agents/responses.js.map +1 -1
  33. package/dist/agents/types.d.cts +21 -3
  34. package/dist/agents/types.d.cts.map +1 -1
  35. package/dist/agents/types.d.ts +21 -3
  36. package/dist/agents/types.d.ts.map +1 -1
  37. package/dist/evaluation/agents/trajectory.d.cts.map +1 -1
  38. package/dist/index.cjs +50 -1
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +3 -3
  41. package/dist/index.d.ts +3 -3
  42. package/dist/index.js +10 -3
  43. package/dist/index.js.map +1 -1
  44. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"annotation.d.ts","names":["BaseMessage","Messages","AnnotationRoot","InteropZodToStateDefinition","InteropZodObject","ResponseFormatUndefined","PreHookAnnotation","_langchain_langgraph0","BinaryOperatorAggregate","createReactAgentBaseAnnotation","createReactAgentAnnotation","Record","T","LastValue","SingleReducer","StateDefinition","S","createReactAgentAnnotationConditional","ReactAgentAnnotation","ReturnType","ToAnnotationRoot","AnyAnnotationRoot","A"],"sources":["../../src/agents/annotation.d.ts"],"sourcesContent":["import { BaseMessage } from \"@langchain/core/messages\";\nimport { Messages, AnnotationRoot } from \"@langchain/langgraph\";\nimport type { InteropZodToStateDefinition } from \"@langchain/langgraph/zod\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport type { ResponseFormatUndefined } from \"./responses.js\";\nexport declare const PreHookAnnotation: AnnotationRoot<{\n llmInputMessages: import(\"@langchain/langgraph\").BinaryOperatorAggregate<BaseMessage[], Messages>;\n messages: import(\"@langchain/langgraph\").BinaryOperatorAggregate<BaseMessage[], Messages>;\n}>;\nexport type PreHookAnnotation = typeof PreHookAnnotation;\n// Base annotation without structuredResponse (for ResponseFormatUndefined)\nexport declare const createReactAgentBaseAnnotation: () => AnnotationRoot<{\n messages: import(\"@langchain/langgraph\").BinaryOperatorAggregate<BaseMessage[], Messages>;\n}>;\n// Full annotation with structuredResponse (for regular cases)\ndeclare const createReactAgentAnnotation: <\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nT extends Record<string, any> = Record<string, any>>() => AnnotationRoot<{\n messages: import(\"@langchain/langgraph\").BinaryOperatorAggregate<BaseMessage[], Messages>;\n structuredResponse: {\n (): import(\"@langchain/langgraph\").LastValue<T>;\n (annotation: import(\"@langchain/langgraph\").SingleReducer<T, T>): import(\"@langchain/langgraph\").BinaryOperatorAggregate<T, T>;\n Root: <S extends import(\"@langchain/langgraph\").StateDefinition>(sd: S) => AnnotationRoot<S>;\n };\n}>;\n// Create annotation conditionally - for ResponseFormatUndefined, don't include structuredResponse\nexport declare function createReactAgentAnnotationConditional<T extends Record<string, any> | ResponseFormatUndefined>(hasStructuredResponse?: boolean): AnnotationRoot<{\n messages: import(\"@langchain/langgraph\").BinaryOperatorAggregate<BaseMessage[], Messages>;\n}> | AnnotationRoot<{\n messages: import(\"@langchain/langgraph\").BinaryOperatorAggregate<BaseMessage[], Messages>;\n structuredResponse: import(\"@langchain/langgraph\").LastValue<T extends ResponseFormatUndefined ? never : T>;\n}>;\n// Helper type to select the right annotation based on the response format type\nexport type ReactAgentAnnotation<T extends Record<string, any> | ResponseFormatUndefined> = T extends ResponseFormatUndefined ? ReturnType<typeof createReactAgentBaseAnnotation> : T extends Record<string, any> ? ReturnType<typeof createReactAgentAnnotation<T>> : never;\nexport type ToAnnotationRoot<A extends AnyAnnotationRoot | InteropZodObject> = A extends AnyAnnotationRoot ? A : A extends InteropZodObject ? AnnotationRoot<InteropZodToStateDefinition<A>> : never;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyAnnotationRoot = AnnotationRoot<any>;\nexport {};\n"],"mappings":";;;;;;;;cAKqBM,mBAAmBJ;oBAC4DK,qBAAAA,CAA/CC,wBAAwBR,eAAeC;YACAM,qBAAAA,CAA/CC,wBAAwBR,eAAeC;AAFpF,CAAA,CAAA;AAGE,KACUK,iBAAAA,GADV,OACqCA,iBADrC;;AAF0FL,cAKvEQ,8BALuER,EAAAA,GAAAA,GAKjCC,cALiCD,CAAAA;EAAQ,QAAAM,EAMRA,qBAAAA,CAA/CC,uBANQA,CAMgBR,WANhBQ,EAAAA,EAM+BP,QAN/BO,CAAAA;CAAuB,CAAA;;cAS9DE,0BAR+BF,EAAAA;;AAFS,UAY5CG,MAZ4C,CAAA,MAAA,EAAA,GAAA,CAAA,GAYtBA,MAZsB,CAAA,MAAA,EAAA,GAAA,CAAA,CAAA,GAAA,GAYIT,cAZJ,CAAA;EAI1CI,QAAAA,EASgFC,qBAAAA,CAA/CC,uBATW,CASaR,WATb,EAAA,EAS4BC,QAT5B,CAAA;EAEnCQ,kBAAAA,EAAAA;IAEnB,EAAA,EAOoDF,qBAAAA,CAAXM,SAPzC,CAOmDD,CAPnD,CAAA;IADmEZ,CAAAA,UAAAA,EASCO,qBAAAA,CAAlBO,aATiBd,CASHY,CATGZ,EASAY,CATAZ,CAAAA,CAAAA,EASgEO,qBAAAA,CAA5BC,uBATpCR,CAS4DY,CAT5DZ,EAS+DY,CAT/DZ,CAAAA;IAAeC,IAAAA,EAAAA,CAAAA,UAS4CM,qBAAAA,CACxEQ,eAV4Bd,CAAAA,CAAAA,EAAAA,EAUPe,CAVOf,EAAAA,GAUDC,cAVCD,CAUce,CAVdf,CAAAA;EAAQ,CAAA;CAAxB,CAAA;AADK;;;AASpBW,KAazCM,oBAbyCN,CAAAA,UAaVD,MAbUC,CAAAA,MAAAA,EAAAA,GAAAA,CAAAA,GAaYP,uBAbZO,CAAAA,GAauCA,CAbvCA,SAaiDP,uBAbjDO,GAa2EO,UAb3EP,CAAAA,OAa6FH,8BAb7FG,CAAAA,GAa+HA,CAb/HA,SAayID,MAbzIC,CAAAA,MAAAA,EAAAA,GAAAA,CAAAA,GAa+JO,UAb/JP,CAAAA,OAaiLF,0BAbjLE,CAa4MA,CAb5MA,CAAAA,CAAAA,GAAAA,KAAAA;AAACL,KAc1Ca,gBAd0Cb,CAAXM,UAcJQ,iBAdIR,GAcgBT,gBAdhBS,CAAAA,GAcoCS,CAdpCT,SAc8CQ,iBAd9CR,GAckES,CAdlET,GAcsES,CAdtET,SAcgFT,gBAdhFS,GAcmGX,cAdnGW,CAckHV,2BAdlHU,CAc8IS,CAd9IT,CAAAA,CAAAA,GAAAA,KAAAA;;AAC0BD,KAezDS,iBAAAA,GAAoBnB,cAfqCU,CAAAA,GAAAA,CAAAA"}
1
+ {"version":3,"file":"annotation.d.ts","names":["BaseMessage","Messages","AnnotationRoot","BinaryOperatorAggregate","LastValue","InteropZodToStateDefinition","InteropZodObject","ResponseFormatUndefined","PreHookAnnotation","createReactAgentBaseAnnotation","createReactAgentAnnotation","Record","T","createReactAgentAnnotationConditional","ReactAgentAnnotation","ReturnType","ToAnnotationRoot","AnyAnnotationRoot","A","enhanceStateSchemaWithMessageReducer"],"sources":["../../src/agents/annotation.d.ts"],"sourcesContent":["import { BaseMessage } from \"@langchain/core/messages\";\nimport { Messages, AnnotationRoot, type BinaryOperatorAggregate, type LastValue } from \"@langchain/langgraph\";\nimport type { InteropZodToStateDefinition } from \"@langchain/langgraph/zod\";\nimport { type InteropZodObject } from \"@langchain/core/utils/types\";\nimport type { ResponseFormatUndefined } from \"./responses.js\";\nexport declare const PreHookAnnotation: AnnotationRoot<{\n llmInputMessages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n messages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n}>;\nexport type PreHookAnnotation = typeof PreHookAnnotation;\n// Base annotation without structuredResponse (for ResponseFormatUndefined)\nexport declare const createReactAgentBaseAnnotation: () => AnnotationRoot<{\n messages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n}>;\n// Full annotation with structuredResponse (for regular cases)\ndeclare const createReactAgentAnnotation: <\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nT extends Record<string, any> = Record<string, any>>() => AnnotationRoot<{\n structuredResponse: LastValue<T>;\n messages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n}>;\n// Create annotation conditionally - for ResponseFormatUndefined, don't include structuredResponse\nexport declare function createReactAgentAnnotationConditional<T extends Record<string, any> | ResponseFormatUndefined>(hasStructuredResponse?: boolean): AnnotationRoot<{\n structuredResponse: LastValue<T extends ResponseFormatUndefined ? never : T>;\n messages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n}>;\n// Helper type to select the right annotation based on the response format type\nexport type ReactAgentAnnotation<T extends Record<string, any> | ResponseFormatUndefined> = T extends ResponseFormatUndefined ? ReturnType<typeof createReactAgentBaseAnnotation> : T extends Record<string, any> ? ReturnType<typeof createReactAgentAnnotation<T>> : never;\nexport type ToAnnotationRoot<A extends AnyAnnotationRoot | InteropZodObject> = A extends AnyAnnotationRoot ? A : A extends InteropZodObject ? AnnotationRoot<InteropZodToStateDefinition<A>> : never;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyAnnotationRoot = AnnotationRoot<any>;\n/**\n * Enhances a state schema to ensure proper message handling.\n * If a Zod schema is provided, it creates an annotation that includes the messagesStateReducer\n * and infers appropriate reducers for all other fields.\n *\n * @param stateSchema - The state schema to enhance.\n * @returns The enhanced state schema.\n */\nexport declare function enhanceStateSchemaWithMessageReducer(stateSchema: AnyAnnotationRoot | InteropZodObject): AnnotationRoot<{\n messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;\n}> | AnyAnnotationRoot;\nexport {};\n"],"mappings":";;;;;;;cAKqBQ,mBAAmBN;oBAClBC,wBAAwBH,eAAeC;EADxCO,QAAAA,EAEPL,uBACZ,CADoCH,WACpC,EAAA,EADmDC,QACnD,CAAA;CAAA,CAAA;AAF4CD,KAGlCQ,iBAAAA,GAHkCR,OAGPQ,iBAHOR;;AAAxBG,cAKDM,8BALCN,EAAAA,GAAAA,GAKqCD,cALrCC,CAAAA;EAAuB,QACPH,EAKxBG,uBALwBH,CAKAA,WALAA,EAAAA,EAKeC,QALfD,CAAAA;CAAW,CAAA;;cAQnCU,0BAV0BR,EAAAA;AAAc;AAItD,UAQUS,MAREH,CAAAA,MAAAA,EAAiB,GAAA,CAAA,GAQGG,MAROH,CAAAA,MAAAA,EAAAA,GAAAA,CAAAA,CAAAA,GAAiB,GAQEN,cARF,CAAA;EAEnCO,kBAAAA,EAOGL,SAPHK,CAOaG,CAPbH,CAAAA;EAEnB,QAAA,EAMYN,uBANZ,CAMoCH,WANpC,EAAA,EAMmDC,QANnD,CAAA;CAAA,CAAA;;;;AAIQU,KAUEG,oBAVFH,CAAAA,UAUiCA,MAVjCA,CAAAA,MAAAA,EAAAA,GAAAA,CAAAA,GAUuDJ,uBAVvDI,CAAAA,GAUkFC,CAVlFD,SAU4FJ,uBAV5FI,GAUsHI,UAVtHJ,CAAAA,OAUwIF,8BAVxIE,CAAAA,GAU0KC,CAV1KD,SAUoLA,MAVpLA,CAAAA,MAAAA,EAAAA,GAAAA,CAAAA,GAU0MI,UAV1MJ,CAAAA,OAU4ND,0BAV5NC,CAUuPC,CAVvPD,CAAAA,CAAAA,GAAAA,KAAAA;AAAsBA,KAWpBK,gBAXoBL,CAAAA,UAWOM,iBAXPN,GAW2BL,gBAX3BK,CAAAA,GAW+CO,CAX/CP,SAWyDM,iBAXzDN,GAW6EO,CAX7EP,GAWiFO,CAXjFP,SAW2FL,gBAX3FK,GAW8GT,cAX9GS,CAW6HN,2BAX7HM,CAWyJO,CAXzJP,CAAAA,CAAAA,GAAAA,KAAAA;;AACRP,KAYZa,iBAAAA,GAAoBf,cAZRE,CAAAA,GAAAA,CAAAA;;;;;AADgD;AAUxE"}
@@ -1,4 +1,5 @@
1
1
  import { Annotation, messagesStateReducer } from "@langchain/langgraph";
2
+ import { getInteropZodDefaultGetter, getInteropZodObjectShape, isInteropZodSchema } from "@langchain/core/utils/types";
2
3
 
3
4
  //#region src/agents/annotation.ts
4
5
  const PreHookAnnotation = Annotation.Root({
@@ -22,7 +23,125 @@ function createReactAgentAnnotationConditional(hasStructuredResponse = true) {
22
23
  structuredResponse: Annotation()
23
24
  });
24
25
  }
26
+ /**
27
+ * Enhances a state schema to ensure proper message handling.
28
+ * If a Zod schema is provided, it creates an annotation that includes the messagesStateReducer
29
+ * and infers appropriate reducers for all other fields.
30
+ *
31
+ * @param stateSchema - The state schema to enhance.
32
+ * @returns The enhanced state schema.
33
+ */
34
+ function enhanceStateSchemaWithMessageReducer(stateSchema) {
35
+ /**
36
+ * If it's already an annotation, return as-is
37
+ */
38
+ if (typeof stateSchema === "object" && "State" in stateSchema) return stateSchema;
39
+ /**
40
+ * If it's a Zod schema, create annotations for all fields
41
+ */
42
+ if (isInteropZodSchema(stateSchema)) {
43
+ const shape = getInteropZodObjectShape(stateSchema);
44
+ const annotationFields = {};
45
+ /**
46
+ * Process each field in the Zod schema
47
+ */
48
+ for (const [key, zodType] of Object.entries(shape)) annotationFields[key] = key === "messages" ? Annotation({
49
+ reducer: messagesStateReducer,
50
+ default: () => []
51
+ }) : createAnnotationForZodType(zodType);
52
+ /**
53
+ * Ensure messages field exists even if not in the Zod schema
54
+ */
55
+ if (!annotationFields.messages) annotationFields.messages = Annotation({
56
+ reducer: messagesStateReducer,
57
+ default: () => []
58
+ });
59
+ return Annotation.Root(annotationFields);
60
+ }
61
+ /**
62
+ * Fallback: create a base annotation with message reducer only
63
+ */
64
+ return Annotation.Root({ messages: Annotation({
65
+ reducer: messagesStateReducer,
66
+ default: () => []
67
+ }) });
68
+ }
69
+ /**
70
+ * Type configuration for different Zod types
71
+ */
72
+ const ZOD_TYPE_CONFIGS = {
73
+ ZodString: {
74
+ reducer: (_, update) => update,
75
+ fallbackDefault: ""
76
+ },
77
+ ZodNumber: {
78
+ reducer: (_, update) => update,
79
+ fallbackDefault: 0
80
+ },
81
+ ZodBoolean: {
82
+ reducer: (_, update) => update,
83
+ fallbackDefault: false
84
+ },
85
+ ZodArray: {
86
+ reducer: (_, update) => update,
87
+ fallbackDefault: []
88
+ },
89
+ ZodRecord: {
90
+ reducer: (current, update) => ({
91
+ ...current,
92
+ ...update
93
+ }),
94
+ fallbackDefault: {}
95
+ },
96
+ ZodObject: {
97
+ reducer: (current, update) => ({
98
+ ...current,
99
+ ...update
100
+ }),
101
+ fallbackDefault: {}
102
+ }
103
+ };
104
+ /**
105
+ * Creates an annotation based on type configuration and default value
106
+ */
107
+ function createAnnotationFromConfig(config, defaultValueFn) {
108
+ return Annotation({
109
+ reducer: config.reducer,
110
+ default: defaultValueFn
111
+ });
112
+ }
113
+ /**
114
+ * Creates an appropriate annotation for a given Zod type.
115
+ */
116
+ function createAnnotationForZodType(zodType) {
117
+ const typeName = zodType._def?.typeName;
118
+ const defaultGetter = getInteropZodDefaultGetter(zodType);
119
+ const isOptional = typeName === "ZodOptional";
120
+ /**
121
+ * Handle Zod wrapper first
122
+ */
123
+ if (typeName === "ZodDefault" || typeName === "ZodOptional" || typeName === "ZodNullable") {
124
+ const innerTypeName = zodType._def.innerType._def?.typeName;
125
+ const config$1 = ZOD_TYPE_CONFIGS[innerTypeName];
126
+ return config$1 ? createAnnotationFromConfig(config$1, () => defaultGetter?.() || (isOptional ? void 0 : config$1?.fallbackDefault)) : Annotation({
127
+ reducer: (_, update) => update,
128
+ default: () => defaultGetter?.()
129
+ });
130
+ }
131
+ /**
132
+ * Handle regular types
133
+ */
134
+ const config = ZOD_TYPE_CONFIGS[typeName];
135
+ if (config) return createAnnotationFromConfig(config, () => defaultGetter?.() || config?.fallbackDefault);
136
+ /**
137
+ * Fallback for unknown types
138
+ */
139
+ return Annotation({
140
+ reducer: (_, update) => update,
141
+ default: () => defaultGetter?.()
142
+ });
143
+ }
25
144
 
26
145
  //#endregion
27
- export { createReactAgentAnnotationConditional };
146
+ export { createReactAgentAnnotationConditional, enhanceStateSchemaWithMessageReducer };
28
147
  //# sourceMappingURL=annotation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"annotation.js","names":[],"sources":["../../src/agents/annotation.ts"],"sourcesContent":["import { BaseMessage } from \"@langchain/core/messages\";\nimport {\n Annotation,\n Messages,\n AnnotationRoot,\n messagesStateReducer,\n} from \"@langchain/langgraph\";\nimport type { InteropZodToStateDefinition } from \"@langchain/langgraph/zod\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport type { ResponseFormatUndefined } from \"./responses.js\";\n\nexport const PreHookAnnotation = Annotation.Root({\n llmInputMessages: Annotation<BaseMessage[], Messages>({\n reducer: (_, update) => messagesStateReducer([], update),\n default: () => [],\n }),\n messages: Annotation<BaseMessage[], Messages>({\n reducer: messagesStateReducer,\n default: () => [],\n }),\n});\nexport type PreHookAnnotation = typeof PreHookAnnotation;\n\n// Base annotation without structuredResponse (for ResponseFormatUndefined)\nexport const createReactAgentBaseAnnotation = () =>\n Annotation.Root({\n messages: Annotation<BaseMessage[], Messages>({\n reducer: messagesStateReducer,\n default: () => [],\n }),\n });\n\n// Full annotation with structuredResponse (for regular cases)\nconst createReactAgentAnnotation = <\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends Record<string, any> = Record<string, any>\n>() =>\n Annotation.Root({\n messages: Annotation<BaseMessage[], Messages>({\n reducer: messagesStateReducer,\n default: () => [],\n }),\n structuredResponse: Annotation<T>,\n });\n\n// Create annotation conditionally - for ResponseFormatUndefined, don't include structuredResponse\nexport function createReactAgentAnnotationConditional<\n T extends Record<string, any> | ResponseFormatUndefined\n>(hasStructuredResponse = true) {\n const baseAnnotation = {\n messages: Annotation<BaseMessage[], Messages>({\n reducer: messagesStateReducer,\n default: () => [],\n }),\n };\n\n if (!hasStructuredResponse) {\n return Annotation.Root(baseAnnotation);\n }\n\n return Annotation.Root({\n ...baseAnnotation,\n structuredResponse:\n Annotation<T extends ResponseFormatUndefined ? never : T>(),\n });\n}\n\n// Helper type to select the right annotation based on the response format type\nexport type ReactAgentAnnotation<\n T extends Record<string, any> | ResponseFormatUndefined\n> = T extends ResponseFormatUndefined\n ? ReturnType<typeof createReactAgentBaseAnnotation>\n : T extends Record<string, any>\n ? ReturnType<typeof createReactAgentAnnotation<T>>\n : never;\n\nexport type ToAnnotationRoot<A extends AnyAnnotationRoot | InteropZodObject> =\n A extends AnyAnnotationRoot\n ? A\n : A extends InteropZodObject\n ? AnnotationRoot<InteropZodToStateDefinition<A>>\n : never;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyAnnotationRoot = AnnotationRoot<any>;\n"],"mappings":";;;AAWA,MAAa,oBAAoB,WAAW,KAAK;CAC/C,kBAAkB,WAAoC;EACpD,SAAS,CAAC,GAAG,WAAW,qBAAqB,CAAE,GAAE,OAAO;EACxD,SAAS,MAAM,CAAE;CAClB,EAAC;CACF,UAAU,WAAoC;EAC5C,SAAS;EACT,SAAS,MAAM,CAAE;CAClB,EAAC;AACH,EAAC;AA0BF,SAAgB,sCAEd,wBAAwB,MAAM;CAC9B,MAAM,iBAAiB,EACrB,UAAU,WAAoC;EAC5C,SAAS;EACT,SAAS,MAAM,CAAE;CAClB,EAAC,CACH;AAED,KAAI,CAAC,sBACH,QAAO,WAAW,KAAK,eAAe;AAGxC,QAAO,WAAW,KAAK;EACrB,GAAG;EACH,oBACE,YAA2D;CAC9D,EAAC;AACH"}
1
+ {"version":3,"file":"annotation.js","names":["PreHookAnnotation: AnnotationRoot<{\n llmInputMessages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n messages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n}>","stateSchema: AnyAnnotationRoot | InteropZodObject","annotationFields: Record<string, any>","_: unknown","update: unknown","current: unknown[]","update: unknown[]","config: (typeof ZOD_TYPE_CONFIGS)[keyof typeof ZOD_TYPE_CONFIGS]","defaultValueFn: () => unknown","zodType: any","config"],"sources":["../../src/agents/annotation.ts"],"sourcesContent":["import { BaseMessage } from \"@langchain/core/messages\";\nimport {\n Annotation,\n Messages,\n AnnotationRoot,\n messagesStateReducer,\n type BinaryOperatorAggregate,\n type LastValue,\n} from \"@langchain/langgraph\";\nimport type { InteropZodToStateDefinition } from \"@langchain/langgraph/zod\";\nimport {\n isInteropZodSchema,\n getInteropZodObjectShape,\n getInteropZodDefaultGetter,\n type InteropZodObject,\n} from \"@langchain/core/utils/types\";\nimport type { ResponseFormatUndefined } from \"./responses.js\";\n\nexport const PreHookAnnotation: AnnotationRoot<{\n llmInputMessages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n messages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n}> = Annotation.Root({\n llmInputMessages: Annotation<BaseMessage[], Messages>({\n reducer: (_, update) => messagesStateReducer([], update),\n default: () => [],\n }),\n messages: Annotation<BaseMessage[], Messages>({\n reducer: messagesStateReducer,\n default: () => [],\n }),\n});\nexport type PreHookAnnotation = typeof PreHookAnnotation;\n\n// Base annotation without structuredResponse (for ResponseFormatUndefined)\nexport const createReactAgentBaseAnnotation = () =>\n Annotation.Root({\n messages: Annotation<BaseMessage[], Messages>({\n reducer: messagesStateReducer,\n default: () => [],\n }),\n });\n\n// Full annotation with structuredResponse (for regular cases)\nconst createReactAgentAnnotation = <\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends Record<string, any> = Record<string, any>\n>(): AnnotationRoot<{\n structuredResponse: LastValue<T>;\n messages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n}> =>\n Annotation.Root({\n messages: Annotation<BaseMessage[], Messages>({\n reducer: messagesStateReducer,\n default: () => [],\n }),\n structuredResponse: Annotation<T>(),\n });\n\n// Create annotation conditionally - for ResponseFormatUndefined, don't include structuredResponse\nexport function createReactAgentAnnotationConditional<\n T extends Record<string, any> | ResponseFormatUndefined\n>(\n hasStructuredResponse = true\n): AnnotationRoot<{\n structuredResponse: LastValue<T extends ResponseFormatUndefined ? never : T>;\n messages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n}> {\n const baseAnnotation = {\n messages: Annotation<BaseMessage[], Messages>({\n reducer: messagesStateReducer,\n default: () => [],\n }),\n };\n\n if (!hasStructuredResponse) {\n return Annotation.Root(baseAnnotation) as AnnotationRoot<{\n structuredResponse: LastValue<\n T extends ResponseFormatUndefined ? never : T\n >;\n messages: BinaryOperatorAggregate<BaseMessage[], Messages>;\n }>;\n }\n\n return Annotation.Root({\n ...baseAnnotation,\n structuredResponse:\n Annotation<T extends ResponseFormatUndefined ? never : T>(),\n });\n}\n\n// Helper type to select the right annotation based on the response format type\nexport type ReactAgentAnnotation<\n T extends Record<string, any> | ResponseFormatUndefined\n> = T extends ResponseFormatUndefined\n ? ReturnType<typeof createReactAgentBaseAnnotation>\n : T extends Record<string, any>\n ? ReturnType<typeof createReactAgentAnnotation<T>>\n : never;\n\nexport type ToAnnotationRoot<A extends AnyAnnotationRoot | InteropZodObject> =\n A extends AnyAnnotationRoot\n ? A\n : A extends InteropZodObject\n ? AnnotationRoot<InteropZodToStateDefinition<A>>\n : never;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyAnnotationRoot = AnnotationRoot<any>;\n\n/**\n * Enhances a state schema to ensure proper message handling.\n * If a Zod schema is provided, it creates an annotation that includes the messagesStateReducer\n * and infers appropriate reducers for all other fields.\n *\n * @param stateSchema - The state schema to enhance.\n * @returns The enhanced state schema.\n */\nexport function enhanceStateSchemaWithMessageReducer(\n stateSchema: AnyAnnotationRoot | InteropZodObject\n) {\n /**\n * If it's already an annotation, return as-is\n */\n if (typeof stateSchema === \"object\" && \"State\" in stateSchema) {\n return stateSchema;\n }\n\n /**\n * If it's a Zod schema, create annotations for all fields\n */\n if (isInteropZodSchema(stateSchema)) {\n const shape = getInteropZodObjectShape(stateSchema);\n const annotationFields: Record<string, any> = {};\n\n /**\n * Process each field in the Zod schema\n */\n for (const [key, zodType] of Object.entries(shape)) {\n annotationFields[key] =\n key === \"messages\"\n ? /**\n * Special handling for messages field - always use messagesStateReducer\n */\n Annotation<BaseMessage[]>({\n reducer: messagesStateReducer,\n default: () => [],\n })\n : /**\n * For other fields, create appropriate annotations based on type\n */\n createAnnotationForZodType(zodType);\n }\n\n /**\n * Ensure messages field exists even if not in the Zod schema\n */\n if (!annotationFields.messages) {\n annotationFields.messages = Annotation<BaseMessage[]>({\n reducer: messagesStateReducer,\n default: () => [],\n });\n }\n\n return Annotation.Root(annotationFields);\n }\n\n /**\n * Fallback: create a base annotation with message reducer only\n */\n return Annotation.Root({\n messages: Annotation<BaseMessage[]>({\n reducer: messagesStateReducer,\n default: () => [],\n }),\n });\n}\n\n/**\n * Type configuration for different Zod types\n */\nconst ZOD_TYPE_CONFIGS = {\n ZodString: {\n reducer: (_: unknown, update: unknown) => update,\n fallbackDefault: \"\",\n },\n ZodNumber: {\n reducer: (_: unknown, update: unknown) => update,\n fallbackDefault: 0,\n },\n ZodBoolean: {\n reducer: (_: unknown, update: unknown) => update,\n fallbackDefault: false,\n },\n ZodArray: {\n reducer: (_: unknown, update: unknown) => update,\n fallbackDefault: [] as unknown[],\n },\n ZodRecord: {\n reducer: (current: unknown[], update: unknown[]) => ({\n ...current,\n ...update,\n }),\n fallbackDefault: {} as Record<string, unknown>,\n },\n ZodObject: {\n reducer: (current: unknown[], update: unknown[]) => ({\n ...current,\n ...update,\n }),\n fallbackDefault: {} as Record<string, unknown>,\n },\n} as const;\n\n/**\n * Creates an annotation based on type configuration and default value\n */\nfunction createAnnotationFromConfig(\n config: (typeof ZOD_TYPE_CONFIGS)[keyof typeof ZOD_TYPE_CONFIGS],\n defaultValueFn: () => unknown\n) {\n return Annotation<any>({\n reducer: config.reducer,\n default: defaultValueFn,\n });\n}\n\n/**\n * Creates an appropriate annotation for a given Zod type.\n */\nfunction createAnnotationForZodType(zodType: any): any {\n const typeName = zodType._def?.typeName;\n const defaultGetter = getInteropZodDefaultGetter(zodType);\n const isOptional = typeName === \"ZodOptional\";\n\n /**\n * Handle Zod wrapper first\n */\n if (\n typeName === \"ZodDefault\" ||\n typeName === \"ZodOptional\" ||\n typeName === \"ZodNullable\"\n ) {\n const innerTypeName = zodType._def.innerType._def?.typeName;\n const config =\n ZOD_TYPE_CONFIGS[innerTypeName as keyof typeof ZOD_TYPE_CONFIGS];\n return config\n ? createAnnotationFromConfig(\n config,\n () =>\n defaultGetter?.() ||\n (isOptional ? undefined : config?.fallbackDefault)\n )\n : Annotation<unknown>({\n reducer: (_: unknown, update: unknown) => update,\n default: () => defaultGetter?.(),\n });\n }\n\n /**\n * Handle regular types\n */\n const config = ZOD_TYPE_CONFIGS[typeName as keyof typeof ZOD_TYPE_CONFIGS];\n if (config) {\n return createAnnotationFromConfig(\n config,\n () => defaultGetter?.() || config?.fallbackDefault\n );\n }\n\n /**\n * Fallback for unknown types\n */\n return Annotation<unknown>({\n reducer: (_: unknown, update: unknown) => update,\n default: () => defaultGetter?.(),\n });\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { MultipleStructuredOutputsError, StructuredOutputParsingError } from "./
2
2
  import { JsonSchemaFormat, ProviderStrategy, ResponseFormat, ResponseFormatUndefined, ToolStrategy, TypedToolStrategy, providerStrategy, toolStrategy } from "./responses.cjs";
3
3
  import { AnyAnnotationRoot } from "./annotation.cjs";
4
4
  import { ToolNode } from "./nodes/ToolNode.cjs";
5
- import { AgentState, ClientTool, CreateReactAgentParams, ExtractZodArrayTypes, N, Prompt, ServerTool } from "./types.cjs";
5
+ import { AgentRuntime, AgentState, ClientTool, CreateReactAgentParams, ExtractZodArrayTypes, N, Prompt, ServerTool } from "./types.cjs";
6
6
  import { ReactAgent } from "./ReactAgent.cjs";
7
7
  import { ActionRequest, HumanInterrupt, HumanInterruptConfig, HumanResponse } from "./interrupt.cjs";
8
8
  import { InteropZodObject, InteropZodType } from "@langchain/core/utils/types";
@@ -2,7 +2,7 @@ import { MultipleStructuredOutputsError, StructuredOutputParsingError } from "./
2
2
  import { JsonSchemaFormat, ProviderStrategy, ResponseFormat, ResponseFormatUndefined, ToolStrategy, TypedToolStrategy, providerStrategy, toolStrategy } from "./responses.js";
3
3
  import { AnyAnnotationRoot } from "./annotation.js";
4
4
  import { ToolNode } from "./nodes/ToolNode.js";
5
- import { AgentState, ClientTool, CreateReactAgentParams, ExtractZodArrayTypes, N, Prompt, ServerTool } from "./types.js";
5
+ import { AgentRuntime, AgentState, ClientTool, CreateReactAgentParams, ExtractZodArrayTypes, N, Prompt, ServerTool } from "./types.js";
6
6
  import { ReactAgent } from "./ReactAgent.js";
7
7
  import { ActionRequest, HumanInterrupt, HumanInterruptConfig, HumanResponse } from "./interrupt.js";
8
8
  import { MessagesAnnotation } from "@langchain/langgraph";
@@ -43,7 +43,10 @@ var AgentNode = class extends require_RunnableCallable.RunnableCallable {
43
43
  /**
44
44
  * if we were able to generate a structured response, return it
45
45
  */
46
- if ("structuredResponse" in response) return response;
46
+ if ("structuredResponse" in response) return {
47
+ messages: [...state.messages, ...response.messages || []],
48
+ structuredResponse: response.structuredResponse
49
+ };
47
50
  /**
48
51
  * if we need to direct the agent to the model, return the update
49
52
  */
@@ -112,7 +115,9 @@ var AgentNode = class extends require_RunnableCallable.RunnableCallable {
112
115
  * scenario is not defined/supported.
113
116
  */
114
117
  if (toolCalls.length > 1) return this.#handleMultipleStructuredOutputs(response, toolCalls);
115
- return this.#handleSingleStructuredOutput(response, toolCalls[0], options.lastMessage);
118
+ const toolStrategy = this.#structuredToolInfo[toolCalls[0].name];
119
+ const toolMessageContent = toolStrategy?.options?.toolMessageContent;
120
+ return this.#handleSingleStructuredOutput(response, toolCalls[0], toolMessageContent ?? options.lastMessage);
116
121
  }
117
122
  /**
118
123
  * If the model returns multiple structured outputs, we need to handle it.
@@ -139,7 +144,7 @@ var AgentNode = class extends require_RunnableCallable.RunnableCallable {
139
144
  const structuredResponse = tool.parse(toolCall.args);
140
145
  return {
141
146
  structuredResponse,
142
- message: new __langchain_core_messages.AIMessage(lastMessage ?? `Returning structured response: ${JSON.stringify(structuredResponse)}`)
147
+ messages: [response, new __langchain_core_messages.AIMessage(lastMessage ?? `Returning structured response: ${JSON.stringify(structuredResponse)}`)]
143
148
  };
144
149
  } catch (error) {
145
150
  return this.#handleToolStrategyError(error, response, toolCall);
@@ -1 +1 @@
1
- {"version":3,"file":"AgentNode.cjs","names":["RunnableCallable","options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >","#run","#options","#structuredToolInfo","transformResponseFormat","ToolStrategy","state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"]","config: RunnableConfig","ToolMessage","response:\n | AIMessage\n | Command\n | { structuredResponse: StructuredResponseFormat }","#invokeModel","Command","#areMoreStepsNeeded","AIMessage","initChatModel","options: {\n lastMessage?: string;\n }","#deriveModel","validateLLMHasNoBoundTools","#bindTools","#getModelInputState","mergeAbortSignals","ProviderStrategy","#handleMultipleStructuredOutputs","#handleSingleStructuredOutput","response: AIMessage","toolCalls: ToolCall[]","MultipleStructuredOutputsError","#handleToolStrategyError","toolCall: ToolCall","lastMessage?: string","error: ToolStrategyError","response: BaseMessage","hasToolCalls","model: LanguageModelLike","options: Partial<BaseChatModelCallOptions>","hasSupportForJsonSchemaOutput","bindTools","getPromptRunnable","withAgentName"],"sources":["../../../src/agents/nodes/AgentNode.ts"],"sourcesContent":["/* eslint-disable no-instanceof/no-instanceof */\nimport { Runnable, RunnableConfig } from \"@langchain/core/runnables\";\nimport { BaseMessage, AIMessage, ToolMessage } from \"@langchain/core/messages\";\nimport { Command } from \"@langchain/langgraph\";\nimport { type LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport { type BaseChatModelCallOptions } from \"@langchain/core/language_models/chat_models\";\nimport {\n InteropZodObject,\n getSchemaDescription,\n} from \"@langchain/core/utils/types\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\n\nimport { initChatModel } from \"../../chat_models/universal.js\";\nimport { MultipleStructuredOutputsError } from \"../errors.js\";\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { PreHookAnnotation, AnyAnnotationRoot } from \"../annotation.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport {\n bindTools,\n getPromptRunnable,\n validateLLMHasNoBoundTools,\n hasToolCalls,\n hasSupportForJsonSchemaOutput,\n} from \"../utils.js\";\nimport {\n InternalAgentState,\n ClientTool,\n ServerTool,\n CreateReactAgentParams,\n} from \"../types.js\";\nimport { withAgentName } from \"../withAgentName.js\";\nimport {\n ToolStrategy,\n ProviderStrategy,\n transformResponseFormat,\n ToolStrategyError,\n} from \"../responses.js\";\n\ntype ResponseHandlerResult<StructuredResponseFormat> =\n | {\n structuredResponse: StructuredResponseFormat;\n message: AIMessage;\n }\n | Promise<Command>;\n\nexport interface AgentNodeOptions<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot,\n StructuredResponseFormat extends Record<string, unknown> = Record<\n string,\n unknown\n >,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot\n> extends Pick<\n CreateReactAgentParams<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >,\n \"llm\" | \"model\" | \"prompt\" | \"includeAgentName\" | \"name\" | \"responseFormat\"\n > {\n toolClasses: (ClientTool | ServerTool)[];\n shouldReturnDirect: Set<string>;\n signal?: AbortSignal;\n}\n\nexport class AgentNode<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot,\n StructuredResponseFormat extends Record<string, unknown> = Record<\n string,\n unknown\n >,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot\n> extends RunnableCallable<\n InternalAgentState<StructuredResponseFormat> & PreHookAnnotation[\"State\"],\n { messages: BaseMessage[] } | { structuredResponse: StructuredResponseFormat }\n> {\n #options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >;\n\n #structuredToolInfo: Record<string, ToolStrategy> = {};\n\n constructor(\n options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >\n ) {\n super({\n name: options.name ?? \"model\",\n func: (input, config) =>\n this.#run(input, config as RunnableConfig) as any,\n });\n\n this.#options = options;\n\n /**\n * Populate a list of structured tool info.\n */\n this.#structuredToolInfo = (\n transformResponseFormat(this.#options.responseFormat).filter(\n (format) => format instanceof ToolStrategy\n ) as ToolStrategy[]\n ).reduce((acc, format) => {\n acc[format.name] = format;\n return acc;\n }, {} as Record<string, ToolStrategy>);\n }\n\n async #run(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ) {\n /**\n * Check if we just executed a returnDirect tool\n * If so, we should generate structured response (if needed) and stop\n */\n const lastMessage = state.messages[state.messages.length - 1];\n if (\n lastMessage instanceof ToolMessage &&\n lastMessage.name &&\n this.#options.shouldReturnDirect.has(lastMessage.name)\n ) {\n /**\n * return directly without invoking the model again\n */\n return { messages: [] };\n }\n\n const response:\n | AIMessage\n | Command\n | { structuredResponse: StructuredResponseFormat } =\n await this.#invokeModel(state, config);\n\n /**\n * if we were able to generate a structured response, return it\n */\n if (\"structuredResponse\" in response) {\n return response;\n }\n\n /**\n * if we need to direct the agent to the model, return the update\n */\n if (response instanceof Command) {\n return response;\n }\n\n response.name = this.name;\n response.lc_kwargs.name = this.name;\n\n if (this.#areMoreStepsNeeded(state, response)) {\n return {\n messages: [\n new AIMessage(\"Sorry, need more steps to process this request.\", {\n name: this.name,\n lc_kwargs: { name: this.name },\n id: response.id,\n }),\n ],\n };\n }\n\n return { messages: [response] };\n }\n\n /**\n * Derive the model from the options.\n * @param state - The state of the agent.\n * @param config - The config of the agent.\n * @returns The model.\n */\n #deriveModel(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ) {\n if (this.#options.model) {\n if (typeof this.#options.model === \"string\") {\n return initChatModel(this.#options.model);\n }\n\n throw new Error(\"`model` option must be a string.\");\n }\n\n const model = this.#options.llm;\n\n /**\n * If the model is a function, call it to get the model.\n */\n if (typeof model === \"function\") {\n return model(state, config);\n }\n\n if (model) {\n return model;\n }\n\n throw new Error(\n \"No model option was provided, either via `model` or via `llm` option.\"\n );\n }\n\n async #invokeModel(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig,\n options: {\n lastMessage?: string;\n } = {}\n ): Promise<\n | AIMessage\n | Command\n | { structuredResponse: StructuredResponseFormat; messages?: BaseMessage[] }\n > {\n const model = await this.#deriveModel(state, config);\n\n /**\n * Check if the LLM already has bound tools and throw if it does.\n */\n validateLLMHasNoBoundTools(model);\n\n const modelWithTools = await this.#bindTools(model);\n const modelInput = this.#getModelInputState(state);\n const signal = mergeAbortSignals(this.#options.signal, config.signal);\n const invokeConfig = {\n ...config,\n signal,\n };\n\n const response = (await modelWithTools.invoke(\n modelInput,\n invokeConfig\n )) as AIMessage;\n\n /**\n * if the user requests a native schema output, try to parse the response\n * and return the structured response if it is valid\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n const structuredResponse = this.#options.responseFormat.parse(response);\n if (structuredResponse) {\n return { structuredResponse, messages: [response] };\n }\n }\n\n if (!response.tool_calls) {\n return response;\n }\n\n const toolCalls = response.tool_calls.filter(\n (call) => call.name in this.#structuredToolInfo\n );\n\n /**\n * if there were not structured tool calls, we can return the response\n */\n if (toolCalls.length === 0) {\n return response;\n }\n\n /**\n * if there were multiple structured tool calls, we should throw an error as this\n * scenario is not defined/supported.\n */\n if (toolCalls.length > 1) {\n return this.#handleMultipleStructuredOutputs(response, toolCalls);\n }\n\n return this.#handleSingleStructuredOutput(\n response,\n toolCalls[0],\n options.lastMessage\n );\n }\n\n /**\n * If the model returns multiple structured outputs, we need to handle it.\n * @param response - The response from the model\n * @param toolCalls - The tool calls that were made\n * @returns The response from the model\n */\n #handleMultipleStructuredOutputs(\n response: AIMessage,\n toolCalls: ToolCall[]\n ): Promise<Command> {\n /**\n * the following should never happen, let's throw an error if it does\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n throw new Error(\n \"Multiple structured outputs should not apply to native structured output responses\"\n );\n }\n\n const multipleStructuredOutputsError = new MultipleStructuredOutputsError(\n toolCalls.map((call) => call.name)\n );\n\n return this.#handleToolStrategyError(\n multipleStructuredOutputsError,\n response,\n toolCalls[0]\n );\n }\n\n /**\n * If the model returns a single structured output, we need to handle it.\n * @param toolCall - The tool call that was made\n * @returns The structured response and a message to the LLM if needed\n */\n #handleSingleStructuredOutput(\n response: AIMessage,\n toolCall: ToolCall,\n lastMessage?: string\n ): ResponseHandlerResult<StructuredResponseFormat> {\n const tool = this.#structuredToolInfo[toolCall.name];\n\n try {\n const structuredResponse = tool.parse(\n toolCall.args\n ) as StructuredResponseFormat;\n\n return {\n structuredResponse,\n message: new AIMessage(\n lastMessage ??\n `Returning structured response: ${JSON.stringify(\n structuredResponse\n )}`\n ),\n };\n } catch (error) {\n return this.#handleToolStrategyError(\n error as ToolStrategyError,\n response,\n toolCall\n );\n }\n }\n\n async #handleToolStrategyError(\n error: ToolStrategyError,\n response: AIMessage,\n toolCall: ToolCall\n ): Promise<Command> {\n /**\n * Using the `errorHandler` option of the first `ToolStrategy` entry is sufficient here.\n * There is technically only one `ToolStrategy` entry in `structuredToolInfo` if the user\n * uses `toolStrategy` to define the response format. If the user applies a list of json\n * schema objects, these will be transformed into multiple `ToolStrategy` entries but all\n * with the same `handleError` option.\n */\n const errorHandler = Object.values(this.#structuredToolInfo).at(0)?.options\n ?.handleError;\n\n const toolCallId = toolCall.id;\n if (!toolCallId) {\n throw new Error(\n \"Tool call ID is required to handle tool output errors. Please provide a tool call ID.\"\n );\n }\n\n /**\n * retry if:\n */\n if (\n /**\n * if the user has provided `true` as the `errorHandler` option, return a new AIMessage\n * with the error message and retry the tool call.\n */\n (typeof errorHandler === \"boolean\" && errorHandler) ||\n /**\n * if `errorHandler` is an array and contains MultipleStructuredOutputsError\n */\n (Array.isArray(errorHandler) &&\n errorHandler.some((h) => h instanceof MultipleStructuredOutputsError))\n ) {\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content: error.message,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * if `errorHandler` is a string, retry the tool call with given string\n */\n if (typeof errorHandler === \"string\") {\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content: errorHandler,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * if `errorHandler` is a function, retry the tool call with the function\n */\n if (typeof errorHandler === \"function\") {\n const content = await errorHandler(error);\n if (typeof content !== \"string\") {\n throw new Error(\"Error handler must return a string.\");\n }\n\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * throw otherwise, e.g. if `errorHandler` is not defined or set to `false`\n */\n throw error;\n }\n\n #areMoreStepsNeeded(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n response: BaseMessage\n ): boolean {\n const allToolsReturnDirect =\n response instanceof AIMessage &&\n response.tool_calls?.every((call) =>\n this.#options.shouldReturnDirect.has(call.name)\n );\n const remainingSteps =\n \"remainingSteps\" in state ? (state.remainingSteps as number) : undefined;\n return Boolean(\n remainingSteps &&\n ((remainingSteps < 1 && allToolsReturnDirect) ||\n (remainingSteps < 2 && hasToolCalls(state.messages)))\n );\n }\n\n #getModelInputState(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"]\n ): Omit<InternalAgentState<StructuredResponseFormat>, \"llmInputMessages\"> {\n const { messages, llmInputMessages, ...rest } = state;\n if (llmInputMessages && llmInputMessages.length > 0) {\n return { messages: llmInputMessages, ...rest } as Omit<\n InternalAgentState<StructuredResponseFormat>,\n \"llmInputMessages\"\n >;\n }\n return { messages, ...rest } as Omit<\n InternalAgentState<StructuredResponseFormat>,\n \"llmInputMessages\"\n >;\n }\n\n async #bindTools(model: LanguageModelLike): Promise<Runnable> {\n const options: Partial<BaseChatModelCallOptions> = {};\n const structuredTools = Object.values(this.#structuredToolInfo);\n const allTools = this.#options.toolClasses.concat(\n ...structuredTools.map((toolStrategy) => toolStrategy.tool)\n );\n\n /**\n * If there are structured tools, we need to set the tool choice to \"any\"\n * so that the model can choose to use a structured tool or not.\n */\n const toolChoice = structuredTools.length > 0 ? \"any\" : undefined;\n\n /**\n * check if the user requests a native schema output\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n /**\n * if the model does not support JSON schema output, throw an error\n */\n if (!hasSupportForJsonSchemaOutput(model)) {\n throw new Error(\n \"Model does not support native structured output responses. Please use a model that supports native structured output responses or use a tool output.\"\n );\n }\n\n const jsonSchemaParams = {\n name: this.#options.responseFormat.schema?.name ?? \"extract\",\n description: getSchemaDescription(this.#options.responseFormat.schema),\n schema: this.#options.responseFormat.schema,\n strict: true,\n };\n\n Object.assign(options, {\n response_format: {\n type: \"json_schema\",\n json_schema: jsonSchemaParams,\n },\n ls_structured_output_format: {\n kwargs: { method: \"json_schema\" },\n schema: this.#options.responseFormat.schema,\n },\n strict: true,\n });\n }\n\n /**\n * Bind tools to the model if they are not already bound.\n */\n const modelWithTools = await bindTools(model, allTools, {\n ...options,\n tool_choice: toolChoice,\n });\n\n /**\n * Create a model runnable with the prompt and agent name\n */\n const modelRunnable = getPromptRunnable(this.#options.prompt).pipe(\n this.#options.includeAgentName === \"inline\"\n ? withAgentName(modelWithTools, this.#options.includeAgentName)\n : modelWithTools\n );\n\n return modelRunnable;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentNode.cjs","names":["RunnableCallable","options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >","#run","#options","#structuredToolInfo","transformResponseFormat","ToolStrategy","state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"]","config: RunnableConfig","ToolMessage","#invokeModel","Command","#areMoreStepsNeeded","AIMessage","initChatModel","options: {\n lastMessage?: string;\n }","#deriveModel","validateLLMHasNoBoundTools","#bindTools","#getModelInputState","mergeAbortSignals","ProviderStrategy","#handleMultipleStructuredOutputs","#handleSingleStructuredOutput","response: AIMessage","toolCalls: ToolCall[]","MultipleStructuredOutputsError","#handleToolStrategyError","toolCall: ToolCall","lastMessage?: string","error: ToolStrategyError","response: BaseMessage","hasToolCalls","model: LanguageModelLike","options: Partial<BaseChatModelCallOptions>","hasSupportForJsonSchemaOutput","bindTools","getPromptRunnable","withAgentName"],"sources":["../../../src/agents/nodes/AgentNode.ts"],"sourcesContent":["/* eslint-disable no-instanceof/no-instanceof */\nimport { Runnable, RunnableConfig } from \"@langchain/core/runnables\";\nimport { BaseMessage, AIMessage, ToolMessage } from \"@langchain/core/messages\";\nimport { Command } from \"@langchain/langgraph\";\nimport { type LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport { type BaseChatModelCallOptions } from \"@langchain/core/language_models/chat_models\";\nimport {\n InteropZodObject,\n getSchemaDescription,\n} from \"@langchain/core/utils/types\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\n\nimport { initChatModel } from \"../../chat_models/universal.js\";\nimport { MultipleStructuredOutputsError } from \"../errors.js\";\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { PreHookAnnotation, AnyAnnotationRoot } from \"../annotation.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport {\n bindTools,\n getPromptRunnable,\n validateLLMHasNoBoundTools,\n hasToolCalls,\n hasSupportForJsonSchemaOutput,\n} from \"../utils.js\";\nimport {\n InternalAgentState,\n ClientTool,\n ServerTool,\n CreateReactAgentParams,\n} from \"../types.js\";\nimport { withAgentName } from \"../withAgentName.js\";\nimport {\n ToolStrategy,\n ProviderStrategy,\n transformResponseFormat,\n ToolStrategyError,\n} from \"../responses.js\";\n\ntype ResponseHandlerResult<StructuredResponseFormat> =\n | {\n structuredResponse: StructuredResponseFormat;\n messages: BaseMessage[];\n }\n | Promise<Command>;\n\nexport interface AgentNodeOptions<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot,\n StructuredResponseFormat extends Record<string, unknown> = Record<\n string,\n unknown\n >,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot\n> extends Pick<\n CreateReactAgentParams<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >,\n \"llm\" | \"model\" | \"prompt\" | \"includeAgentName\" | \"name\" | \"responseFormat\"\n > {\n toolClasses: (ClientTool | ServerTool)[];\n shouldReturnDirect: Set<string>;\n signal?: AbortSignal;\n}\n\nexport class AgentNode<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot,\n StructuredResponseFormat extends Record<string, unknown> = Record<\n string,\n unknown\n >,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot\n> extends RunnableCallable<\n InternalAgentState<StructuredResponseFormat> & PreHookAnnotation[\"State\"],\n { messages: BaseMessage[] } | { structuredResponse: StructuredResponseFormat }\n> {\n #options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >;\n\n #structuredToolInfo: Record<string, ToolStrategy> = {};\n\n constructor(\n options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >\n ) {\n super({\n name: options.name ?? \"model\",\n func: (input, config) =>\n this.#run(input, config as RunnableConfig) as any,\n });\n\n this.#options = options;\n\n /**\n * Populate a list of structured tool info.\n */\n this.#structuredToolInfo = (\n transformResponseFormat(this.#options.responseFormat).filter(\n (format) => format instanceof ToolStrategy\n ) as ToolStrategy[]\n ).reduce((acc, format) => {\n acc[format.name] = format;\n return acc;\n }, {} as Record<string, ToolStrategy>);\n }\n\n async #run(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ) {\n /**\n * Check if we just executed a returnDirect tool\n * If so, we should generate structured response (if needed) and stop\n */\n const lastMessage = state.messages[state.messages.length - 1];\n if (\n lastMessage instanceof ToolMessage &&\n lastMessage.name &&\n this.#options.shouldReturnDirect.has(lastMessage.name)\n ) {\n /**\n * return directly without invoking the model again\n */\n return { messages: [] };\n }\n\n const response = await this.#invokeModel(state, config);\n\n /**\n * if we were able to generate a structured response, return it\n */\n if (\"structuredResponse\" in response) {\n return {\n messages: [...state.messages, ...(response.messages || [])],\n structuredResponse: response.structuredResponse,\n };\n }\n\n /**\n * if we need to direct the agent to the model, return the update\n */\n if (response instanceof Command) {\n return response;\n }\n\n response.name = this.name;\n response.lc_kwargs.name = this.name;\n\n if (this.#areMoreStepsNeeded(state, response)) {\n return {\n messages: [\n new AIMessage(\"Sorry, need more steps to process this request.\", {\n name: this.name,\n lc_kwargs: { name: this.name },\n id: response.id,\n }),\n ],\n };\n }\n\n return { messages: [response] };\n }\n\n /**\n * Derive the model from the options.\n * @param state - The state of the agent.\n * @param config - The config of the agent.\n * @returns The model.\n */\n #deriveModel(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ) {\n if (this.#options.model) {\n if (typeof this.#options.model === \"string\") {\n return initChatModel(this.#options.model);\n }\n\n throw new Error(\"`model` option must be a string.\");\n }\n\n const model = this.#options.llm;\n\n /**\n * If the model is a function, call it to get the model.\n */\n if (typeof model === \"function\") {\n return model(state, config);\n }\n\n if (model) {\n return model;\n }\n\n throw new Error(\n \"No model option was provided, either via `model` or via `llm` option.\"\n );\n }\n\n async #invokeModel(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig,\n options: {\n lastMessage?: string;\n } = {}\n ): Promise<AIMessage | ResponseHandlerResult<StructuredResponseFormat>> {\n const model = await this.#deriveModel(state, config);\n\n /**\n * Check if the LLM already has bound tools and throw if it does.\n */\n validateLLMHasNoBoundTools(model);\n\n const modelWithTools = await this.#bindTools(model);\n const modelInput = this.#getModelInputState(state);\n const signal = mergeAbortSignals(this.#options.signal, config.signal);\n const invokeConfig = {\n ...config,\n signal,\n };\n\n const response = (await modelWithTools.invoke(\n modelInput,\n invokeConfig\n )) as AIMessage;\n\n /**\n * if the user requests a native schema output, try to parse the response\n * and return the structured response if it is valid\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n const structuredResponse = this.#options.responseFormat.parse(response);\n if (structuredResponse) {\n return { structuredResponse, messages: [response] };\n }\n }\n\n if (!response.tool_calls) {\n return response;\n }\n\n const toolCalls = response.tool_calls.filter(\n (call) => call.name in this.#structuredToolInfo\n );\n\n /**\n * if there were not structured tool calls, we can return the response\n */\n if (toolCalls.length === 0) {\n return response;\n }\n\n /**\n * if there were multiple structured tool calls, we should throw an error as this\n * scenario is not defined/supported.\n */\n if (toolCalls.length > 1) {\n return this.#handleMultipleStructuredOutputs(response, toolCalls);\n }\n\n const toolStrategy = this.#structuredToolInfo[toolCalls[0].name];\n const toolMessageContent = toolStrategy?.options?.toolMessageContent;\n return this.#handleSingleStructuredOutput(\n response,\n toolCalls[0],\n toolMessageContent ?? options.lastMessage\n );\n }\n\n /**\n * If the model returns multiple structured outputs, we need to handle it.\n * @param response - The response from the model\n * @param toolCalls - The tool calls that were made\n * @returns The response from the model\n */\n #handleMultipleStructuredOutputs(\n response: AIMessage,\n toolCalls: ToolCall[]\n ): Promise<Command> {\n /**\n * the following should never happen, let's throw an error if it does\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n throw new Error(\n \"Multiple structured outputs should not apply to native structured output responses\"\n );\n }\n\n const multipleStructuredOutputsError = new MultipleStructuredOutputsError(\n toolCalls.map((call) => call.name)\n );\n\n return this.#handleToolStrategyError(\n multipleStructuredOutputsError,\n response,\n toolCalls[0]\n );\n }\n\n /**\n * If the model returns a single structured output, we need to handle it.\n * @param toolCall - The tool call that was made\n * @returns The structured response and a message to the LLM if needed\n */\n #handleSingleStructuredOutput(\n response: AIMessage,\n toolCall: ToolCall,\n lastMessage?: string\n ): ResponseHandlerResult<StructuredResponseFormat> {\n const tool = this.#structuredToolInfo[toolCall.name];\n\n try {\n const structuredResponse = tool.parse(\n toolCall.args\n ) as StructuredResponseFormat;\n\n return {\n structuredResponse,\n messages: [\n response,\n new AIMessage(\n lastMessage ??\n `Returning structured response: ${JSON.stringify(\n structuredResponse\n )}`\n ),\n ],\n };\n } catch (error) {\n return this.#handleToolStrategyError(\n error as ToolStrategyError,\n response,\n toolCall\n );\n }\n }\n\n async #handleToolStrategyError(\n error: ToolStrategyError,\n response: AIMessage,\n toolCall: ToolCall\n ): Promise<Command> {\n /**\n * Using the `errorHandler` option of the first `ToolStrategy` entry is sufficient here.\n * There is technically only one `ToolStrategy` entry in `structuredToolInfo` if the user\n * uses `toolStrategy` to define the response format. If the user applies a list of json\n * schema objects, these will be transformed into multiple `ToolStrategy` entries but all\n * with the same `handleError` option.\n */\n const errorHandler = Object.values(this.#structuredToolInfo).at(0)?.options\n ?.handleError;\n\n const toolCallId = toolCall.id;\n if (!toolCallId) {\n throw new Error(\n \"Tool call ID is required to handle tool output errors. Please provide a tool call ID.\"\n );\n }\n\n /**\n * retry if:\n */\n if (\n /**\n * if the user has provided `true` as the `errorHandler` option, return a new AIMessage\n * with the error message and retry the tool call.\n */\n (typeof errorHandler === \"boolean\" && errorHandler) ||\n /**\n * if `errorHandler` is an array and contains MultipleStructuredOutputsError\n */\n (Array.isArray(errorHandler) &&\n errorHandler.some((h) => h instanceof MultipleStructuredOutputsError))\n ) {\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content: error.message,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * if `errorHandler` is a string, retry the tool call with given string\n */\n if (typeof errorHandler === \"string\") {\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content: errorHandler,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * if `errorHandler` is a function, retry the tool call with the function\n */\n if (typeof errorHandler === \"function\") {\n const content = await errorHandler(error);\n if (typeof content !== \"string\") {\n throw new Error(\"Error handler must return a string.\");\n }\n\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * throw otherwise, e.g. if `errorHandler` is not defined or set to `false`\n */\n throw error;\n }\n\n #areMoreStepsNeeded(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n response: BaseMessage\n ): boolean {\n const allToolsReturnDirect =\n response instanceof AIMessage &&\n response.tool_calls?.every((call) =>\n this.#options.shouldReturnDirect.has(call.name)\n );\n const remainingSteps =\n \"remainingSteps\" in state ? (state.remainingSteps as number) : undefined;\n return Boolean(\n remainingSteps &&\n ((remainingSteps < 1 && allToolsReturnDirect) ||\n (remainingSteps < 2 && hasToolCalls(state.messages)))\n );\n }\n\n #getModelInputState(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"]\n ): Omit<InternalAgentState<StructuredResponseFormat>, \"llmInputMessages\"> {\n const { messages, llmInputMessages, ...rest } = state;\n if (llmInputMessages && llmInputMessages.length > 0) {\n return { messages: llmInputMessages, ...rest } as Omit<\n InternalAgentState<StructuredResponseFormat>,\n \"llmInputMessages\"\n >;\n }\n return { messages, ...rest } as Omit<\n InternalAgentState<StructuredResponseFormat>,\n \"llmInputMessages\"\n >;\n }\n\n async #bindTools(model: LanguageModelLike): Promise<Runnable> {\n const options: Partial<BaseChatModelCallOptions> = {};\n const structuredTools = Object.values(this.#structuredToolInfo);\n const allTools = this.#options.toolClasses.concat(\n ...structuredTools.map((toolStrategy) => toolStrategy.tool)\n );\n\n /**\n * If there are structured tools, we need to set the tool choice to \"any\"\n * so that the model can choose to use a structured tool or not.\n */\n const toolChoice = structuredTools.length > 0 ? \"any\" : undefined;\n\n /**\n * check if the user requests a native schema output\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n /**\n * if the model does not support JSON schema output, throw an error\n */\n if (!hasSupportForJsonSchemaOutput(model)) {\n throw new Error(\n \"Model does not support native structured output responses. Please use a model that supports native structured output responses or use a tool output.\"\n );\n }\n\n const jsonSchemaParams = {\n name: this.#options.responseFormat.schema?.name ?? \"extract\",\n description: getSchemaDescription(this.#options.responseFormat.schema),\n schema: this.#options.responseFormat.schema,\n strict: true,\n };\n\n Object.assign(options, {\n response_format: {\n type: \"json_schema\",\n json_schema: jsonSchemaParams,\n },\n ls_structured_output_format: {\n kwargs: { method: \"json_schema\" },\n schema: this.#options.responseFormat.schema,\n },\n strict: true,\n });\n }\n\n /**\n * Bind tools to the model if they are not already bound.\n */\n const modelWithTools = await bindTools(model, allTools, {\n ...options,\n tool_choice: toolChoice,\n });\n\n /**\n * Create a model runnable with the prompt and agent name\n */\n const modelRunnable = getPromptRunnable(this.#options.prompt).pipe(\n this.#options.includeAgentName === \"inline\"\n ? withAgentName(modelWithTools, this.#options.includeAgentName)\n : modelWithTools\n );\n\n return modelRunnable;\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAiEA,IAAa,YAAb,cAOUA,0CAGR;CACA;CAMA,sBAAoD,CAAE;CAEtD,YACEC,SAKA;EACA,MAAM;GACJ,MAAM,QAAQ,QAAQ;GACtB,MAAM,CAAC,OAAO,WACZ,KAAKC,KAAK,OAAO,OAAyB;EAC7C,EAAC;EAEF,KAAKC,WAAW;;;;EAKhB,KAAKC,sBACHC,0CAAwB,KAAKF,SAAS,eAAe,CAAC,OACpD,CAAC,WAAW,kBAAkBG,+BAC/B,CACD,OAAO,CAAC,KAAK,WAAW;GACxB,IAAI,OAAO,QAAQ;AACnB,UAAO;EACR,GAAE,CAAE,EAAiC;CACvC;CAED,MAAMJ,KACJK,OAEAC,QACA;;;;;EAKA,MAAM,cAAc,MAAM,SAAS,MAAM,SAAS,SAAS;AAC3D,MACE,uBAAuBC,yCACvB,YAAY,QACZ,KAAKN,SAAS,mBAAmB,IAAI,YAAY,KAAK;;;;AAKtD,SAAO,EAAE,UAAU,CAAE,EAAE;EAGzB,MAAM,WAAW,MAAM,KAAKO,aAAa,OAAO,OAAO;;;;AAKvD,MAAI,wBAAwB,SAC1B,QAAO;GACL,UAAU,CAAC,GAAG,MAAM,UAAU,GAAI,SAAS,YAAY,CAAE,CAAE;GAC3D,oBAAoB,SAAS;EAC9B;;;;AAMH,MAAI,oBAAoBC,8BACtB,QAAO;EAGT,SAAS,OAAO,KAAK;EACrB,SAAS,UAAU,OAAO,KAAK;AAE/B,MAAI,KAAKC,oBAAoB,OAAO,SAAS,CAC3C,QAAO,EACL,UAAU,CACR,IAAIC,oCAAU,mDAAmD;GAC/D,MAAM,KAAK;GACX,WAAW,EAAE,MAAM,KAAK,KAAM;GAC9B,IAAI,SAAS;EACd,EACF,EACF;AAGH,SAAO,EAAE,UAAU,CAAC,QAAS,EAAE;CAChC;;;;;;;CAQD,aACEN,OAEAC,QACA;AACA,MAAI,KAAKL,SAAS,OAAO;AACvB,OAAI,OAAO,KAAKA,SAAS,UAAU,SACjC,QAAOW,4CAAc,KAAKX,SAAS,MAAM;AAG3C,SAAM,IAAI,MAAM;EACjB;EAED,MAAM,QAAQ,KAAKA,SAAS;;;;AAK5B,MAAI,OAAO,UAAU,WACnB,QAAO,MAAM,OAAO,OAAO;AAG7B,MAAI,MACF,QAAO;AAGT,QAAM,IAAI,MACR;CAEH;CAED,MAAMO,aACJH,OAEAC,QACAO,UAEI,CAAE,GACgE;EACtE,MAAM,QAAQ,MAAM,KAAKC,aAAa,OAAO,OAAO;;;;EAKpDC,yCAA2B,MAAM;EAEjC,MAAM,iBAAiB,MAAM,KAAKC,WAAW,MAAM;EACnD,MAAM,aAAa,KAAKC,oBAAoB,MAAM;EAClD,MAAM,SAASC,kCAAkB,KAAKjB,SAAS,QAAQ,OAAO,OAAO;EACrE,MAAM,eAAe;GACnB,GAAG;GACH;EACD;EAED,MAAM,WAAY,MAAM,eAAe,OACrC,YACA,aACD;;;;;AAMD,MAAI,KAAKA,SAAS,0BAA0BkB,oCAAkB;GAC5D,MAAM,qBAAqB,KAAKlB,SAAS,eAAe,MAAM,SAAS;AACvE,OAAI,mBACF,QAAO;IAAE;IAAoB,UAAU,CAAC,QAAS;GAAE;EAEtD;AAED,MAAI,CAAC,SAAS,WACZ,QAAO;EAGT,MAAM,YAAY,SAAS,WAAW,OACpC,CAAC,SAAS,KAAK,QAAQ,KAAKC,oBAC7B;;;;AAKD,MAAI,UAAU,WAAW,EACvB,QAAO;;;;;AAOT,MAAI,UAAU,SAAS,EACrB,QAAO,KAAKkB,iCAAiC,UAAU,UAAU;EAGnE,MAAM,eAAe,KAAKlB,oBAAoB,UAAU,GAAG;EAC3D,MAAM,qBAAqB,cAAc,SAAS;AAClD,SAAO,KAAKmB,8BACV,UACA,UAAU,IACV,sBAAsB,QAAQ,YAC/B;CACF;;;;;;;CAQD,iCACEC,UACAC,WACkB;;;;AAIlB,MAAI,KAAKtB,SAAS,0BAA0BkB,mCAC1C,OAAM,IAAI,MACR;EAIJ,MAAM,iCAAiC,IAAIK,8CACzC,UAAU,IAAI,CAAC,SAAS,KAAK,KAAK;AAGpC,SAAO,KAAKC,yBACV,gCACA,UACA,UAAU,GACX;CACF;;;;;;CAOD,8BACEH,UACAI,UACAC,aACiD;EACjD,MAAM,OAAO,KAAKzB,oBAAoB,SAAS;AAE/C,MAAI;GACF,MAAM,qBAAqB,KAAK,MAC9B,SAAS,KACV;AAED,UAAO;IACL;IACA,UAAU,CACR,UACA,IAAIS,oCACF,eACE,CAAC,+BAA+B,EAAE,KAAK,UACrC,mBACD,EAAE,CAER;GACF;EACF,SAAQ,OAAO;AACd,UAAO,KAAKc,yBACV,OACA,UACA,SACD;EACF;CACF;CAED,MAAMA,yBACJG,OACAN,UACAI,UACkB;;;;;;;;EAQlB,MAAM,eAAe,OAAO,OAAO,KAAKxB,oBAAoB,CAAC,GAAG,EAAE,EAAE,SAChE;EAEJ,MAAM,aAAa,SAAS;AAC5B,MAAI,CAAC,WACH,OAAM,IAAI,MACR;;;;AAOJ,MAKG,OAAO,iBAAiB,aAAa,gBAIrC,MAAM,QAAQ,aAAa,IAC1B,aAAa,KAAK,CAAC,MAAM,aAAasB,8CAA+B,CAEvE,QAAO,IAAIf,8BAAQ;GACjB,QAAQ,EACN,UAAU,CACR,UACA,IAAIF,sCAAY;IACd,SAAS,MAAM;IACf,cAAc;GACf,EACF,EACF;GACD,MAAM;EACP;;;;AAMH,MAAI,OAAO,iBAAiB,SAC1B,QAAO,IAAIE,8BAAQ;GACjB,QAAQ,EACN,UAAU,CACR,UACA,IAAIF,sCAAY;IACd,SAAS;IACT,cAAc;GACf,EACF,EACF;GACD,MAAM;EACP;;;;AAMH,MAAI,OAAO,iBAAiB,YAAY;GACtC,MAAM,UAAU,MAAM,aAAa,MAAM;AACzC,OAAI,OAAO,YAAY,SACrB,OAAM,IAAI,MAAM;AAGlB,UAAO,IAAIE,8BAAQ;IACjB,QAAQ,EACN,UAAU,CACR,UACA,IAAIF,sCAAY;KACd;KACA,cAAc;IACf,EACF,EACF;IACD,MAAM;GACP;EACF;;;;AAKD,QAAM;CACP;CAED,oBACEF,OAEAwB,UACS;EACT,MAAM,uBACJ,oBAAoBlB,uCACpB,SAAS,YAAY,MAAM,CAAC,SAC1B,KAAKV,SAAS,mBAAmB,IAAI,KAAK,KAAK,CAChD;EACH,MAAM,iBACJ,oBAAoB,QAAS,MAAM,iBAA4B;AACjE,SAAO,QACL,mBACI,iBAAiB,KAAK,wBACrB,iBAAiB,KAAK6B,2BAAa,MAAM,SAAS,EACxD;CACF;CAED,oBACEzB,OAEwE;EACxE,MAAM,EAAE,UAAU,iBAAkB,GAAG,MAAM,GAAG;AAChD,MAAI,oBAAoB,iBAAiB,SAAS,EAChD,QAAO;GAAE,UAAU;GAAkB,GAAG;EAAM;AAKhD,SAAO;GAAE;GAAU,GAAG;EAAM;CAI7B;CAED,MAAMW,WAAWe,OAA6C;EAC5D,MAAMC,UAA6C,CAAE;EACrD,MAAM,kBAAkB,OAAO,OAAO,KAAK9B,oBAAoB;EAC/D,MAAM,WAAW,KAAKD,SAAS,YAAY,OACzC,GAAG,gBAAgB,IAAI,CAAC,iBAAiB,aAAa,KAAK,CAC5D;;;;;EAMD,MAAM,aAAa,gBAAgB,SAAS,IAAI,QAAQ;;;;AAKxD,MAAI,KAAKA,SAAS,0BAA0BkB,oCAAkB;;;;AAI5D,OAAI,CAACc,4CAA8B,MAAM,CACvC,OAAM,IAAI,MACR;GAIJ,MAAM,mBAAmB;IACvB,MAAM,KAAKhC,SAAS,eAAe,QAAQ,QAAQ;IACnD,oEAAkC,KAAKA,SAAS,eAAe,OAAO;IACtE,QAAQ,KAAKA,SAAS,eAAe;IACrC,QAAQ;GACT;GAED,OAAO,OAAO,SAAS;IACrB,iBAAiB;KACf,MAAM;KACN,aAAa;IACd;IACD,6BAA6B;KAC3B,QAAQ,EAAE,QAAQ,cAAe;KACjC,QAAQ,KAAKA,SAAS,eAAe;IACtC;IACD,QAAQ;GACT,EAAC;EACH;;;;EAKD,MAAM,iBAAiB,MAAMiC,wBAAU,OAAO,UAAU;GACtD,GAAG;GACH,aAAa;EACd,EAAC;;;;EAKF,MAAM,gBAAgBC,gCAAkB,KAAKlC,SAAS,OAAO,CAAC,KAC5D,KAAKA,SAAS,qBAAqB,WAC/BmC,oCAAc,gBAAgB,KAAKnC,SAAS,iBAAiB,GAC7D,eACL;AAED,SAAO;CACR;AACF"}
@@ -42,7 +42,10 @@ var AgentNode = class extends RunnableCallable {
42
42
  /**
43
43
  * if we were able to generate a structured response, return it
44
44
  */
45
- if ("structuredResponse" in response) return response;
45
+ if ("structuredResponse" in response) return {
46
+ messages: [...state.messages, ...response.messages || []],
47
+ structuredResponse: response.structuredResponse
48
+ };
46
49
  /**
47
50
  * if we need to direct the agent to the model, return the update
48
51
  */
@@ -111,7 +114,9 @@ var AgentNode = class extends RunnableCallable {
111
114
  * scenario is not defined/supported.
112
115
  */
113
116
  if (toolCalls.length > 1) return this.#handleMultipleStructuredOutputs(response, toolCalls);
114
- return this.#handleSingleStructuredOutput(response, toolCalls[0], options.lastMessage);
117
+ const toolStrategy = this.#structuredToolInfo[toolCalls[0].name];
118
+ const toolMessageContent = toolStrategy?.options?.toolMessageContent;
119
+ return this.#handleSingleStructuredOutput(response, toolCalls[0], toolMessageContent ?? options.lastMessage);
115
120
  }
116
121
  /**
117
122
  * If the model returns multiple structured outputs, we need to handle it.
@@ -138,7 +143,7 @@ var AgentNode = class extends RunnableCallable {
138
143
  const structuredResponse = tool.parse(toolCall.args);
139
144
  return {
140
145
  structuredResponse,
141
- message: new AIMessage(lastMessage ?? `Returning structured response: ${JSON.stringify(structuredResponse)}`)
146
+ messages: [response, new AIMessage(lastMessage ?? `Returning structured response: ${JSON.stringify(structuredResponse)}`)]
142
147
  };
143
148
  } catch (error) {
144
149
  return this.#handleToolStrategyError(error, response, toolCall);
@@ -1 +1 @@
1
- {"version":3,"file":"AgentNode.js","names":["options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >","#run","#options","#structuredToolInfo","state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"]","config: RunnableConfig","response:\n | AIMessage\n | Command\n | { structuredResponse: StructuredResponseFormat }","#invokeModel","#areMoreStepsNeeded","options: {\n lastMessage?: string;\n }","#deriveModel","#bindTools","#getModelInputState","#handleMultipleStructuredOutputs","#handleSingleStructuredOutput","response: AIMessage","toolCalls: ToolCall[]","#handleToolStrategyError","toolCall: ToolCall","lastMessage?: string","error: ToolStrategyError","response: BaseMessage","model: LanguageModelLike","options: Partial<BaseChatModelCallOptions>"],"sources":["../../../src/agents/nodes/AgentNode.ts"],"sourcesContent":["/* eslint-disable no-instanceof/no-instanceof */\nimport { Runnable, RunnableConfig } from \"@langchain/core/runnables\";\nimport { BaseMessage, AIMessage, ToolMessage } from \"@langchain/core/messages\";\nimport { Command } from \"@langchain/langgraph\";\nimport { type LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport { type BaseChatModelCallOptions } from \"@langchain/core/language_models/chat_models\";\nimport {\n InteropZodObject,\n getSchemaDescription,\n} from \"@langchain/core/utils/types\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\n\nimport { initChatModel } from \"../../chat_models/universal.js\";\nimport { MultipleStructuredOutputsError } from \"../errors.js\";\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { PreHookAnnotation, AnyAnnotationRoot } from \"../annotation.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport {\n bindTools,\n getPromptRunnable,\n validateLLMHasNoBoundTools,\n hasToolCalls,\n hasSupportForJsonSchemaOutput,\n} from \"../utils.js\";\nimport {\n InternalAgentState,\n ClientTool,\n ServerTool,\n CreateReactAgentParams,\n} from \"../types.js\";\nimport { withAgentName } from \"../withAgentName.js\";\nimport {\n ToolStrategy,\n ProviderStrategy,\n transformResponseFormat,\n ToolStrategyError,\n} from \"../responses.js\";\n\ntype ResponseHandlerResult<StructuredResponseFormat> =\n | {\n structuredResponse: StructuredResponseFormat;\n message: AIMessage;\n }\n | Promise<Command>;\n\nexport interface AgentNodeOptions<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot,\n StructuredResponseFormat extends Record<string, unknown> = Record<\n string,\n unknown\n >,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot\n> extends Pick<\n CreateReactAgentParams<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >,\n \"llm\" | \"model\" | \"prompt\" | \"includeAgentName\" | \"name\" | \"responseFormat\"\n > {\n toolClasses: (ClientTool | ServerTool)[];\n shouldReturnDirect: Set<string>;\n signal?: AbortSignal;\n}\n\nexport class AgentNode<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot,\n StructuredResponseFormat extends Record<string, unknown> = Record<\n string,\n unknown\n >,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot\n> extends RunnableCallable<\n InternalAgentState<StructuredResponseFormat> & PreHookAnnotation[\"State\"],\n { messages: BaseMessage[] } | { structuredResponse: StructuredResponseFormat }\n> {\n #options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >;\n\n #structuredToolInfo: Record<string, ToolStrategy> = {};\n\n constructor(\n options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >\n ) {\n super({\n name: options.name ?? \"model\",\n func: (input, config) =>\n this.#run(input, config as RunnableConfig) as any,\n });\n\n this.#options = options;\n\n /**\n * Populate a list of structured tool info.\n */\n this.#structuredToolInfo = (\n transformResponseFormat(this.#options.responseFormat).filter(\n (format) => format instanceof ToolStrategy\n ) as ToolStrategy[]\n ).reduce((acc, format) => {\n acc[format.name] = format;\n return acc;\n }, {} as Record<string, ToolStrategy>);\n }\n\n async #run(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ) {\n /**\n * Check if we just executed a returnDirect tool\n * If so, we should generate structured response (if needed) and stop\n */\n const lastMessage = state.messages[state.messages.length - 1];\n if (\n lastMessage instanceof ToolMessage &&\n lastMessage.name &&\n this.#options.shouldReturnDirect.has(lastMessage.name)\n ) {\n /**\n * return directly without invoking the model again\n */\n return { messages: [] };\n }\n\n const response:\n | AIMessage\n | Command\n | { structuredResponse: StructuredResponseFormat } =\n await this.#invokeModel(state, config);\n\n /**\n * if we were able to generate a structured response, return it\n */\n if (\"structuredResponse\" in response) {\n return response;\n }\n\n /**\n * if we need to direct the agent to the model, return the update\n */\n if (response instanceof Command) {\n return response;\n }\n\n response.name = this.name;\n response.lc_kwargs.name = this.name;\n\n if (this.#areMoreStepsNeeded(state, response)) {\n return {\n messages: [\n new AIMessage(\"Sorry, need more steps to process this request.\", {\n name: this.name,\n lc_kwargs: { name: this.name },\n id: response.id,\n }),\n ],\n };\n }\n\n return { messages: [response] };\n }\n\n /**\n * Derive the model from the options.\n * @param state - The state of the agent.\n * @param config - The config of the agent.\n * @returns The model.\n */\n #deriveModel(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ) {\n if (this.#options.model) {\n if (typeof this.#options.model === \"string\") {\n return initChatModel(this.#options.model);\n }\n\n throw new Error(\"`model` option must be a string.\");\n }\n\n const model = this.#options.llm;\n\n /**\n * If the model is a function, call it to get the model.\n */\n if (typeof model === \"function\") {\n return model(state, config);\n }\n\n if (model) {\n return model;\n }\n\n throw new Error(\n \"No model option was provided, either via `model` or via `llm` option.\"\n );\n }\n\n async #invokeModel(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig,\n options: {\n lastMessage?: string;\n } = {}\n ): Promise<\n | AIMessage\n | Command\n | { structuredResponse: StructuredResponseFormat; messages?: BaseMessage[] }\n > {\n const model = await this.#deriveModel(state, config);\n\n /**\n * Check if the LLM already has bound tools and throw if it does.\n */\n validateLLMHasNoBoundTools(model);\n\n const modelWithTools = await this.#bindTools(model);\n const modelInput = this.#getModelInputState(state);\n const signal = mergeAbortSignals(this.#options.signal, config.signal);\n const invokeConfig = {\n ...config,\n signal,\n };\n\n const response = (await modelWithTools.invoke(\n modelInput,\n invokeConfig\n )) as AIMessage;\n\n /**\n * if the user requests a native schema output, try to parse the response\n * and return the structured response if it is valid\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n const structuredResponse = this.#options.responseFormat.parse(response);\n if (structuredResponse) {\n return { structuredResponse, messages: [response] };\n }\n }\n\n if (!response.tool_calls) {\n return response;\n }\n\n const toolCalls = response.tool_calls.filter(\n (call) => call.name in this.#structuredToolInfo\n );\n\n /**\n * if there were not structured tool calls, we can return the response\n */\n if (toolCalls.length === 0) {\n return response;\n }\n\n /**\n * if there were multiple structured tool calls, we should throw an error as this\n * scenario is not defined/supported.\n */\n if (toolCalls.length > 1) {\n return this.#handleMultipleStructuredOutputs(response, toolCalls);\n }\n\n return this.#handleSingleStructuredOutput(\n response,\n toolCalls[0],\n options.lastMessage\n );\n }\n\n /**\n * If the model returns multiple structured outputs, we need to handle it.\n * @param response - The response from the model\n * @param toolCalls - The tool calls that were made\n * @returns The response from the model\n */\n #handleMultipleStructuredOutputs(\n response: AIMessage,\n toolCalls: ToolCall[]\n ): Promise<Command> {\n /**\n * the following should never happen, let's throw an error if it does\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n throw new Error(\n \"Multiple structured outputs should not apply to native structured output responses\"\n );\n }\n\n const multipleStructuredOutputsError = new MultipleStructuredOutputsError(\n toolCalls.map((call) => call.name)\n );\n\n return this.#handleToolStrategyError(\n multipleStructuredOutputsError,\n response,\n toolCalls[0]\n );\n }\n\n /**\n * If the model returns a single structured output, we need to handle it.\n * @param toolCall - The tool call that was made\n * @returns The structured response and a message to the LLM if needed\n */\n #handleSingleStructuredOutput(\n response: AIMessage,\n toolCall: ToolCall,\n lastMessage?: string\n ): ResponseHandlerResult<StructuredResponseFormat> {\n const tool = this.#structuredToolInfo[toolCall.name];\n\n try {\n const structuredResponse = tool.parse(\n toolCall.args\n ) as StructuredResponseFormat;\n\n return {\n structuredResponse,\n message: new AIMessage(\n lastMessage ??\n `Returning structured response: ${JSON.stringify(\n structuredResponse\n )}`\n ),\n };\n } catch (error) {\n return this.#handleToolStrategyError(\n error as ToolStrategyError,\n response,\n toolCall\n );\n }\n }\n\n async #handleToolStrategyError(\n error: ToolStrategyError,\n response: AIMessage,\n toolCall: ToolCall\n ): Promise<Command> {\n /**\n * Using the `errorHandler` option of the first `ToolStrategy` entry is sufficient here.\n * There is technically only one `ToolStrategy` entry in `structuredToolInfo` if the user\n * uses `toolStrategy` to define the response format. If the user applies a list of json\n * schema objects, these will be transformed into multiple `ToolStrategy` entries but all\n * with the same `handleError` option.\n */\n const errorHandler = Object.values(this.#structuredToolInfo).at(0)?.options\n ?.handleError;\n\n const toolCallId = toolCall.id;\n if (!toolCallId) {\n throw new Error(\n \"Tool call ID is required to handle tool output errors. Please provide a tool call ID.\"\n );\n }\n\n /**\n * retry if:\n */\n if (\n /**\n * if the user has provided `true` as the `errorHandler` option, return a new AIMessage\n * with the error message and retry the tool call.\n */\n (typeof errorHandler === \"boolean\" && errorHandler) ||\n /**\n * if `errorHandler` is an array and contains MultipleStructuredOutputsError\n */\n (Array.isArray(errorHandler) &&\n errorHandler.some((h) => h instanceof MultipleStructuredOutputsError))\n ) {\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content: error.message,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * if `errorHandler` is a string, retry the tool call with given string\n */\n if (typeof errorHandler === \"string\") {\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content: errorHandler,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * if `errorHandler` is a function, retry the tool call with the function\n */\n if (typeof errorHandler === \"function\") {\n const content = await errorHandler(error);\n if (typeof content !== \"string\") {\n throw new Error(\"Error handler must return a string.\");\n }\n\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * throw otherwise, e.g. if `errorHandler` is not defined or set to `false`\n */\n throw error;\n }\n\n #areMoreStepsNeeded(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n response: BaseMessage\n ): boolean {\n const allToolsReturnDirect =\n response instanceof AIMessage &&\n response.tool_calls?.every((call) =>\n this.#options.shouldReturnDirect.has(call.name)\n );\n const remainingSteps =\n \"remainingSteps\" in state ? (state.remainingSteps as number) : undefined;\n return Boolean(\n remainingSteps &&\n ((remainingSteps < 1 && allToolsReturnDirect) ||\n (remainingSteps < 2 && hasToolCalls(state.messages)))\n );\n }\n\n #getModelInputState(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"]\n ): Omit<InternalAgentState<StructuredResponseFormat>, \"llmInputMessages\"> {\n const { messages, llmInputMessages, ...rest } = state;\n if (llmInputMessages && llmInputMessages.length > 0) {\n return { messages: llmInputMessages, ...rest } as Omit<\n InternalAgentState<StructuredResponseFormat>,\n \"llmInputMessages\"\n >;\n }\n return { messages, ...rest } as Omit<\n InternalAgentState<StructuredResponseFormat>,\n \"llmInputMessages\"\n >;\n }\n\n async #bindTools(model: LanguageModelLike): Promise<Runnable> {\n const options: Partial<BaseChatModelCallOptions> = {};\n const structuredTools = Object.values(this.#structuredToolInfo);\n const allTools = this.#options.toolClasses.concat(\n ...structuredTools.map((toolStrategy) => toolStrategy.tool)\n );\n\n /**\n * If there are structured tools, we need to set the tool choice to \"any\"\n * so that the model can choose to use a structured tool or not.\n */\n const toolChoice = structuredTools.length > 0 ? \"any\" : undefined;\n\n /**\n * check if the user requests a native schema output\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n /**\n * if the model does not support JSON schema output, throw an error\n */\n if (!hasSupportForJsonSchemaOutput(model)) {\n throw new Error(\n \"Model does not support native structured output responses. Please use a model that supports native structured output responses or use a tool output.\"\n );\n }\n\n const jsonSchemaParams = {\n name: this.#options.responseFormat.schema?.name ?? \"extract\",\n description: getSchemaDescription(this.#options.responseFormat.schema),\n schema: this.#options.responseFormat.schema,\n strict: true,\n };\n\n Object.assign(options, {\n response_format: {\n type: \"json_schema\",\n json_schema: jsonSchemaParams,\n },\n ls_structured_output_format: {\n kwargs: { method: \"json_schema\" },\n schema: this.#options.responseFormat.schema,\n },\n strict: true,\n });\n }\n\n /**\n * Bind tools to the model if they are not already bound.\n */\n const modelWithTools = await bindTools(model, allTools, {\n ...options,\n tool_choice: toolChoice,\n });\n\n /**\n * Create a model runnable with the prompt and agent name\n */\n const modelRunnable = getPromptRunnable(this.#options.prompt).pipe(\n this.#options.includeAgentName === \"inline\"\n ? withAgentName(modelWithTools, this.#options.includeAgentName)\n : modelWithTools\n );\n\n return modelRunnable;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentNode.js","names":["options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >","#run","#options","#structuredToolInfo","state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"]","config: RunnableConfig","#invokeModel","#areMoreStepsNeeded","options: {\n lastMessage?: string;\n }","#deriveModel","#bindTools","#getModelInputState","#handleMultipleStructuredOutputs","#handleSingleStructuredOutput","response: AIMessage","toolCalls: ToolCall[]","#handleToolStrategyError","toolCall: ToolCall","lastMessage?: string","error: ToolStrategyError","response: BaseMessage","model: LanguageModelLike","options: Partial<BaseChatModelCallOptions>"],"sources":["../../../src/agents/nodes/AgentNode.ts"],"sourcesContent":["/* eslint-disable no-instanceof/no-instanceof */\nimport { Runnable, RunnableConfig } from \"@langchain/core/runnables\";\nimport { BaseMessage, AIMessage, ToolMessage } from \"@langchain/core/messages\";\nimport { Command } from \"@langchain/langgraph\";\nimport { type LanguageModelLike } from \"@langchain/core/language_models/base\";\nimport { type BaseChatModelCallOptions } from \"@langchain/core/language_models/chat_models\";\nimport {\n InteropZodObject,\n getSchemaDescription,\n} from \"@langchain/core/utils/types\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\n\nimport { initChatModel } from \"../../chat_models/universal.js\";\nimport { MultipleStructuredOutputsError } from \"../errors.js\";\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport { PreHookAnnotation, AnyAnnotationRoot } from \"../annotation.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport {\n bindTools,\n getPromptRunnable,\n validateLLMHasNoBoundTools,\n hasToolCalls,\n hasSupportForJsonSchemaOutput,\n} from \"../utils.js\";\nimport {\n InternalAgentState,\n ClientTool,\n ServerTool,\n CreateReactAgentParams,\n} from \"../types.js\";\nimport { withAgentName } from \"../withAgentName.js\";\nimport {\n ToolStrategy,\n ProviderStrategy,\n transformResponseFormat,\n ToolStrategyError,\n} from \"../responses.js\";\n\ntype ResponseHandlerResult<StructuredResponseFormat> =\n | {\n structuredResponse: StructuredResponseFormat;\n messages: BaseMessage[];\n }\n | Promise<Command>;\n\nexport interface AgentNodeOptions<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot,\n StructuredResponseFormat extends Record<string, unknown> = Record<\n string,\n unknown\n >,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot\n> extends Pick<\n CreateReactAgentParams<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >,\n \"llm\" | \"model\" | \"prompt\" | \"includeAgentName\" | \"name\" | \"responseFormat\"\n > {\n toolClasses: (ClientTool | ServerTool)[];\n shouldReturnDirect: Set<string>;\n signal?: AbortSignal;\n}\n\nexport class AgentNode<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot,\n StructuredResponseFormat extends Record<string, unknown> = Record<\n string,\n unknown\n >,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = AnyAnnotationRoot\n> extends RunnableCallable<\n InternalAgentState<StructuredResponseFormat> & PreHookAnnotation[\"State\"],\n { messages: BaseMessage[] } | { structuredResponse: StructuredResponseFormat }\n> {\n #options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >;\n\n #structuredToolInfo: Record<string, ToolStrategy> = {};\n\n constructor(\n options: AgentNodeOptions<\n StateSchema,\n StructuredResponseFormat,\n ContextSchema\n >\n ) {\n super({\n name: options.name ?? \"model\",\n func: (input, config) =>\n this.#run(input, config as RunnableConfig) as any,\n });\n\n this.#options = options;\n\n /**\n * Populate a list of structured tool info.\n */\n this.#structuredToolInfo = (\n transformResponseFormat(this.#options.responseFormat).filter(\n (format) => format instanceof ToolStrategy\n ) as ToolStrategy[]\n ).reduce((acc, format) => {\n acc[format.name] = format;\n return acc;\n }, {} as Record<string, ToolStrategy>);\n }\n\n async #run(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ) {\n /**\n * Check if we just executed a returnDirect tool\n * If so, we should generate structured response (if needed) and stop\n */\n const lastMessage = state.messages[state.messages.length - 1];\n if (\n lastMessage instanceof ToolMessage &&\n lastMessage.name &&\n this.#options.shouldReturnDirect.has(lastMessage.name)\n ) {\n /**\n * return directly without invoking the model again\n */\n return { messages: [] };\n }\n\n const response = await this.#invokeModel(state, config);\n\n /**\n * if we were able to generate a structured response, return it\n */\n if (\"structuredResponse\" in response) {\n return {\n messages: [...state.messages, ...(response.messages || [])],\n structuredResponse: response.structuredResponse,\n };\n }\n\n /**\n * if we need to direct the agent to the model, return the update\n */\n if (response instanceof Command) {\n return response;\n }\n\n response.name = this.name;\n response.lc_kwargs.name = this.name;\n\n if (this.#areMoreStepsNeeded(state, response)) {\n return {\n messages: [\n new AIMessage(\"Sorry, need more steps to process this request.\", {\n name: this.name,\n lc_kwargs: { name: this.name },\n id: response.id,\n }),\n ],\n };\n }\n\n return { messages: [response] };\n }\n\n /**\n * Derive the model from the options.\n * @param state - The state of the agent.\n * @param config - The config of the agent.\n * @returns The model.\n */\n #deriveModel(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ) {\n if (this.#options.model) {\n if (typeof this.#options.model === \"string\") {\n return initChatModel(this.#options.model);\n }\n\n throw new Error(\"`model` option must be a string.\");\n }\n\n const model = this.#options.llm;\n\n /**\n * If the model is a function, call it to get the model.\n */\n if (typeof model === \"function\") {\n return model(state, config);\n }\n\n if (model) {\n return model;\n }\n\n throw new Error(\n \"No model option was provided, either via `model` or via `llm` option.\"\n );\n }\n\n async #invokeModel(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n config: RunnableConfig,\n options: {\n lastMessage?: string;\n } = {}\n ): Promise<AIMessage | ResponseHandlerResult<StructuredResponseFormat>> {\n const model = await this.#deriveModel(state, config);\n\n /**\n * Check if the LLM already has bound tools and throw if it does.\n */\n validateLLMHasNoBoundTools(model);\n\n const modelWithTools = await this.#bindTools(model);\n const modelInput = this.#getModelInputState(state);\n const signal = mergeAbortSignals(this.#options.signal, config.signal);\n const invokeConfig = {\n ...config,\n signal,\n };\n\n const response = (await modelWithTools.invoke(\n modelInput,\n invokeConfig\n )) as AIMessage;\n\n /**\n * if the user requests a native schema output, try to parse the response\n * and return the structured response if it is valid\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n const structuredResponse = this.#options.responseFormat.parse(response);\n if (structuredResponse) {\n return { structuredResponse, messages: [response] };\n }\n }\n\n if (!response.tool_calls) {\n return response;\n }\n\n const toolCalls = response.tool_calls.filter(\n (call) => call.name in this.#structuredToolInfo\n );\n\n /**\n * if there were not structured tool calls, we can return the response\n */\n if (toolCalls.length === 0) {\n return response;\n }\n\n /**\n * if there were multiple structured tool calls, we should throw an error as this\n * scenario is not defined/supported.\n */\n if (toolCalls.length > 1) {\n return this.#handleMultipleStructuredOutputs(response, toolCalls);\n }\n\n const toolStrategy = this.#structuredToolInfo[toolCalls[0].name];\n const toolMessageContent = toolStrategy?.options?.toolMessageContent;\n return this.#handleSingleStructuredOutput(\n response,\n toolCalls[0],\n toolMessageContent ?? options.lastMessage\n );\n }\n\n /**\n * If the model returns multiple structured outputs, we need to handle it.\n * @param response - The response from the model\n * @param toolCalls - The tool calls that were made\n * @returns The response from the model\n */\n #handleMultipleStructuredOutputs(\n response: AIMessage,\n toolCalls: ToolCall[]\n ): Promise<Command> {\n /**\n * the following should never happen, let's throw an error if it does\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n throw new Error(\n \"Multiple structured outputs should not apply to native structured output responses\"\n );\n }\n\n const multipleStructuredOutputsError = new MultipleStructuredOutputsError(\n toolCalls.map((call) => call.name)\n );\n\n return this.#handleToolStrategyError(\n multipleStructuredOutputsError,\n response,\n toolCalls[0]\n );\n }\n\n /**\n * If the model returns a single structured output, we need to handle it.\n * @param toolCall - The tool call that was made\n * @returns The structured response and a message to the LLM if needed\n */\n #handleSingleStructuredOutput(\n response: AIMessage,\n toolCall: ToolCall,\n lastMessage?: string\n ): ResponseHandlerResult<StructuredResponseFormat> {\n const tool = this.#structuredToolInfo[toolCall.name];\n\n try {\n const structuredResponse = tool.parse(\n toolCall.args\n ) as StructuredResponseFormat;\n\n return {\n structuredResponse,\n messages: [\n response,\n new AIMessage(\n lastMessage ??\n `Returning structured response: ${JSON.stringify(\n structuredResponse\n )}`\n ),\n ],\n };\n } catch (error) {\n return this.#handleToolStrategyError(\n error as ToolStrategyError,\n response,\n toolCall\n );\n }\n }\n\n async #handleToolStrategyError(\n error: ToolStrategyError,\n response: AIMessage,\n toolCall: ToolCall\n ): Promise<Command> {\n /**\n * Using the `errorHandler` option of the first `ToolStrategy` entry is sufficient here.\n * There is technically only one `ToolStrategy` entry in `structuredToolInfo` if the user\n * uses `toolStrategy` to define the response format. If the user applies a list of json\n * schema objects, these will be transformed into multiple `ToolStrategy` entries but all\n * with the same `handleError` option.\n */\n const errorHandler = Object.values(this.#structuredToolInfo).at(0)?.options\n ?.handleError;\n\n const toolCallId = toolCall.id;\n if (!toolCallId) {\n throw new Error(\n \"Tool call ID is required to handle tool output errors. Please provide a tool call ID.\"\n );\n }\n\n /**\n * retry if:\n */\n if (\n /**\n * if the user has provided `true` as the `errorHandler` option, return a new AIMessage\n * with the error message and retry the tool call.\n */\n (typeof errorHandler === \"boolean\" && errorHandler) ||\n /**\n * if `errorHandler` is an array and contains MultipleStructuredOutputsError\n */\n (Array.isArray(errorHandler) &&\n errorHandler.some((h) => h instanceof MultipleStructuredOutputsError))\n ) {\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content: error.message,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * if `errorHandler` is a string, retry the tool call with given string\n */\n if (typeof errorHandler === \"string\") {\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content: errorHandler,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * if `errorHandler` is a function, retry the tool call with the function\n */\n if (typeof errorHandler === \"function\") {\n const content = await errorHandler(error);\n if (typeof content !== \"string\") {\n throw new Error(\"Error handler must return a string.\");\n }\n\n return new Command({\n update: {\n messages: [\n response,\n new ToolMessage({\n content,\n tool_call_id: toolCallId,\n }),\n ],\n },\n goto: \"model\",\n });\n }\n\n /**\n * throw otherwise, e.g. if `errorHandler` is not defined or set to `false`\n */\n throw error;\n }\n\n #areMoreStepsNeeded(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"],\n response: BaseMessage\n ): boolean {\n const allToolsReturnDirect =\n response instanceof AIMessage &&\n response.tool_calls?.every((call) =>\n this.#options.shouldReturnDirect.has(call.name)\n );\n const remainingSteps =\n \"remainingSteps\" in state ? (state.remainingSteps as number) : undefined;\n return Boolean(\n remainingSteps &&\n ((remainingSteps < 1 && allToolsReturnDirect) ||\n (remainingSteps < 2 && hasToolCalls(state.messages)))\n );\n }\n\n #getModelInputState(\n state: InternalAgentState<StructuredResponseFormat> &\n PreHookAnnotation[\"State\"]\n ): Omit<InternalAgentState<StructuredResponseFormat>, \"llmInputMessages\"> {\n const { messages, llmInputMessages, ...rest } = state;\n if (llmInputMessages && llmInputMessages.length > 0) {\n return { messages: llmInputMessages, ...rest } as Omit<\n InternalAgentState<StructuredResponseFormat>,\n \"llmInputMessages\"\n >;\n }\n return { messages, ...rest } as Omit<\n InternalAgentState<StructuredResponseFormat>,\n \"llmInputMessages\"\n >;\n }\n\n async #bindTools(model: LanguageModelLike): Promise<Runnable> {\n const options: Partial<BaseChatModelCallOptions> = {};\n const structuredTools = Object.values(this.#structuredToolInfo);\n const allTools = this.#options.toolClasses.concat(\n ...structuredTools.map((toolStrategy) => toolStrategy.tool)\n );\n\n /**\n * If there are structured tools, we need to set the tool choice to \"any\"\n * so that the model can choose to use a structured tool or not.\n */\n const toolChoice = structuredTools.length > 0 ? \"any\" : undefined;\n\n /**\n * check if the user requests a native schema output\n */\n if (this.#options.responseFormat instanceof ProviderStrategy) {\n /**\n * if the model does not support JSON schema output, throw an error\n */\n if (!hasSupportForJsonSchemaOutput(model)) {\n throw new Error(\n \"Model does not support native structured output responses. Please use a model that supports native structured output responses or use a tool output.\"\n );\n }\n\n const jsonSchemaParams = {\n name: this.#options.responseFormat.schema?.name ?? \"extract\",\n description: getSchemaDescription(this.#options.responseFormat.schema),\n schema: this.#options.responseFormat.schema,\n strict: true,\n };\n\n Object.assign(options, {\n response_format: {\n type: \"json_schema\",\n json_schema: jsonSchemaParams,\n },\n ls_structured_output_format: {\n kwargs: { method: \"json_schema\" },\n schema: this.#options.responseFormat.schema,\n },\n strict: true,\n });\n }\n\n /**\n * Bind tools to the model if they are not already bound.\n */\n const modelWithTools = await bindTools(model, allTools, {\n ...options,\n tool_choice: toolChoice,\n });\n\n /**\n * Create a model runnable with the prompt and agent name\n */\n const modelRunnable = getPromptRunnable(this.#options.prompt).pipe(\n this.#options.includeAgentName === \"inline\"\n ? withAgentName(modelWithTools, this.#options.includeAgentName)\n : modelWithTools\n );\n\n return modelRunnable;\n }\n}\n"],"mappings":"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"}
@@ -117,7 +117,7 @@ var ToolNode = class extends require_RunnableCallable.RunnableCallable {
117
117
  if (result && (0, __langchain_core_messages.isToolMessage)(result)) return result;
118
118
  } else if (this.handleToolErrors) return new __langchain_core_messages.ToolMessage({
119
119
  name: call.name,
120
- content: `Error: ${e}\n Please fix your mistakes.`,
120
+ content: `${e}\n Please fix your mistakes.`,
121
121
  tool_call_id: call.id
122
122
  });
123
123
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ToolNode.cjs","names":["input: unknown","isBaseMessage","RunnableCallable","tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[]","options?: ToolNodeOptions","call: ToolCall","config: RunnableConfig","tool","mergeAbortSignals","ToolMessage","e: unknown","ToolInputParsingException","ToolInvocationError","state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"]","outputs: (ToolMessage | Command)[]","messages: BaseMessage[]","toolMessageIds: Set<string>","aiMessage: AIMessage | undefined","isCommand","combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[]","parentCommand: Command | null","Command","x: unknown","Send"],"sources":["../../../src/agents/nodes/ToolNode.ts"],"sourcesContent":["/* eslint-disable no-instanceof/no-instanceof */\nimport {\n BaseMessage,\n ToolMessage,\n AIMessage,\n isBaseMessage,\n isToolMessage,\n} from \"@langchain/core/messages\";\nimport { RunnableConfig, RunnableToolLike } from \"@langchain/core/runnables\";\nimport {\n DynamicTool,\n StructuredToolInterface,\n ToolInputParsingException,\n} from \"@langchain/core/tools\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport {\n isCommand,\n Command,\n Send,\n isGraphInterrupt,\n type NodeInterrupt,\n} from \"@langchain/langgraph\";\n\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport {\n PreHookAnnotation,\n AnyAnnotationRoot,\n ToAnnotationRoot,\n} from \"../annotation.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport { ToolInvocationError } from \"../errors.js\";\n\nexport interface ToolNodeOptions {\n /**\n * The name of the tool node.\n */\n name?: string;\n /**\n * The tags to add to the tool call.\n */\n tags?: string[];\n /**\n * The abort signal to cancel the tool call.\n */\n signal?: AbortSignal;\n /**\n * Whether to throw the error immediately if the tool fails or handle it by the `onToolError` function or via ToolMessage.\n *\n * If `true` (default):\n * - a tool message with the error will be returned to the LLM\n *\n * If `false`:\n * - the error will be thrown immediately\n *\n * If a function is provided:\n * - returns a custom {@link ToolMessage} as result\n * - throws an error otherwise\n *\n * @default true\n */\n handleToolErrors?:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined);\n}\n\nconst isBaseMessageArray = (input: unknown): input is BaseMessage[] =>\n Array.isArray(input) && input.every(isBaseMessage);\n\nconst isMessagesState = (\n input: unknown\n): input is { messages: BaseMessage[] } =>\n typeof input === \"object\" &&\n input != null &&\n \"messages\" in input &&\n isBaseMessageArray(input.messages);\n\nconst isSendInput = (input: unknown): input is { lg_tool_call: ToolCall } =>\n typeof input === \"object\" && input != null && \"lg_tool_call\" in input;\n\n/**\n * `ToolNode` is a built-in LangGraph component that handles tool calls within an agent's workflow.\n * It works seamlessly with `createReactAgent`, offering advanced tool execution control, built\n * in parallelism, and error handling.\n *\n * @example\n * ```ts\n * import { ToolNode, tool, AIMessage } from \"langchain\";\n * import { z } from \"zod\";\n *\n * const getWeather = tool((input) => {\n * if ([\"sf\", \"san francisco\"].includes(input.location.toLowerCase())) {\n * return \"It's 60 degrees and foggy.\";\n * } else {\n * return \"It's 90 degrees and sunny.\";\n * }\n * }, {\n * name: \"get_weather\",\n * description: \"Call to get the current weather.\",\n * schema: z.object({\n * location: z.string().describe(\"Location to get the weather for.\"),\n * }),\n * });\n *\n * const tools = [getWeather];\n * const toolNode = new ToolNode(tools);\n *\n * const messageWithSingleToolCall = new AIMessage({\n * content: \"\",\n * tool_calls: [\n * {\n * name: \"get_weather\",\n * args: { location: \"sf\" },\n * id: \"tool_call_id\",\n * type: \"tool_call\",\n * }\n * ]\n * })\n *\n * await toolNode.invoke({ messages: [messageWithSingleToolCall] });\n * // Returns tool invocation responses as:\n * // { messages: ToolMessage[] }\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class ToolNode<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = any,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = any\n> extends RunnableCallable<StateSchema, ContextSchema> {\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[];\n\n trace = false;\n\n signal?: AbortSignal;\n\n handleToolErrors:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined) = true;\n\n constructor(\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[],\n public options?: ToolNodeOptions\n ) {\n const { name, tags, handleToolErrors } = options ?? {};\n super({\n name,\n tags,\n func: (state, config) =>\n this.run(\n state as ToAnnotationRoot<StateSchema>[\"State\"] &\n PreHookAnnotation[\"State\"],\n config as RunnableConfig\n ),\n });\n this.tools = tools;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.signal = options?.signal;\n }\n\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig\n ): Promise<ToolMessage | Command> {\n const tool = this.tools.find((tool) => tool.name === call.name);\n try {\n if (tool === undefined) {\n throw new Error(`Tool \"${call.name}\" not found.`);\n }\n\n const output = await tool.invoke(\n { ...call, type: \"tool_call\" },\n {\n ...config,\n signal: mergeAbortSignals(this.signal, config.signal),\n }\n );\n\n if (\n (isBaseMessage(output) && output.getType() === \"tool\") ||\n isCommand(output)\n ) {\n return output as ToolMessage | Command;\n }\n\n return new ToolMessage({\n name: tool.name,\n content: typeof output === \"string\" ? output : JSON.stringify(output),\n tool_call_id: call.id!,\n });\n } catch (e: unknown) {\n /**\n * If tool invocation fails due to input parsing error, throw a {@link ToolInvocationError}\n */\n if (e instanceof ToolInputParsingException) {\n throw new ToolInvocationError(e, call);\n }\n\n /**\n * throw the error if user prefers not to handle tool errors\n */\n if (!this.handleToolErrors) {\n throw e;\n }\n\n if (isGraphInterrupt(e)) {\n /**\n * {@link NodeInterrupt} errors are a breakpoint to bring a human into the loop.\n * As such, they are not recoverable by the agent and shouldn't be fed\n * back. Instead, re-throw these errors even when `handleToolErrors = true`.\n */\n throw e;\n }\n\n /**\n * If the signal is aborted, we want to bubble up the error to the invoke caller.\n */\n if (this.signal?.aborted) {\n throw e;\n }\n\n /**\n * if the user provides a function, call it with the error and tool call\n * and return the result if it is a {@link ToolMessage}\n */\n if (typeof this.handleToolErrors === \"function\") {\n const result = this.handleToolErrors(e, call);\n if (result && isToolMessage(result)) {\n return result;\n }\n } else if (this.handleToolErrors) {\n return new ToolMessage({\n name: call.name,\n content: `Error: ${e}\\n Please fix your mistakes.`,\n tool_call_id: call.id!,\n });\n }\n\n /**\n * If the user doesn't handle the error, throw it\n */\n throw e;\n }\n }\n\n protected async run(\n state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ): Promise<ContextSchema> {\n let outputs: (ToolMessage | Command)[];\n\n if (isSendInput(state)) {\n outputs = [await this.runTool(state.lg_tool_call, config)];\n } else {\n let messages: BaseMessage[];\n if (isBaseMessageArray(state)) {\n messages = state;\n } else if (isMessagesState(state)) {\n messages = state.messages;\n } else {\n throw new Error(\n \"ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.\"\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg.getType() === \"tool\")\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (message.getType() === \"ai\") {\n aiMessage = message;\n break;\n }\n }\n\n if (aiMessage?.getType() !== \"ai\") {\n throw new Error(\"ToolNode only accepts AIMessages as input.\");\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => call.id == null || !toolMessageIds.has(call.id))\n .map((call) => this.runTool(call, config)) ?? []\n );\n }\n\n // Preserve existing behavior for non-command tool outputs for backwards compatibility\n if (!outputs.some(isCommand)) {\n return (Array.isArray(state)\n ? outputs\n : { messages: outputs }) as unknown as ContextSchema;\n }\n\n // Handle mixed Command and non-Command outputs\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send) => isSend(send))\n ) {\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else {\n combinedOutputs.push(output);\n }\n } else {\n combinedOutputs.push(\n Array.isArray(state) ? [output] : { messages: [output] }\n );\n }\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as unknown as ContextSchema;\n }\n}\n\nexport function isSend(x: unknown): x is Send {\n // eslint-disable-next-line no-instanceof/no-instanceof\n return x instanceof Send;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ToolNode.cjs","names":["input: unknown","isBaseMessage","RunnableCallable","tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[]","options?: ToolNodeOptions","call: ToolCall","config: RunnableConfig","tool","mergeAbortSignals","ToolMessage","e: unknown","ToolInputParsingException","ToolInvocationError","state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"]","outputs: (ToolMessage | Command)[]","messages: BaseMessage[]","toolMessageIds: Set<string>","aiMessage: AIMessage | undefined","isCommand","combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[]","parentCommand: Command | null","Command","x: unknown","Send"],"sources":["../../../src/agents/nodes/ToolNode.ts"],"sourcesContent":["/* eslint-disable no-instanceof/no-instanceof */\nimport {\n BaseMessage,\n ToolMessage,\n AIMessage,\n isBaseMessage,\n isToolMessage,\n} from \"@langchain/core/messages\";\nimport { RunnableConfig, RunnableToolLike } from \"@langchain/core/runnables\";\nimport {\n DynamicTool,\n StructuredToolInterface,\n ToolInputParsingException,\n} from \"@langchain/core/tools\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\nimport type { InteropZodObject } from \"@langchain/core/utils/types\";\nimport {\n isCommand,\n Command,\n Send,\n isGraphInterrupt,\n type NodeInterrupt,\n} from \"@langchain/langgraph\";\n\nimport { RunnableCallable } from \"../RunnableCallable.js\";\nimport {\n PreHookAnnotation,\n AnyAnnotationRoot,\n ToAnnotationRoot,\n} from \"../annotation.js\";\nimport { mergeAbortSignals } from \"./utils.js\";\nimport { ToolInvocationError } from \"../errors.js\";\n\nexport interface ToolNodeOptions {\n /**\n * The name of the tool node.\n */\n name?: string;\n /**\n * The tags to add to the tool call.\n */\n tags?: string[];\n /**\n * The abort signal to cancel the tool call.\n */\n signal?: AbortSignal;\n /**\n * Whether to throw the error immediately if the tool fails or handle it by the `onToolError` function or via ToolMessage.\n *\n * If `true` (default):\n * - a tool message with the error will be returned to the LLM\n *\n * If `false`:\n * - the error will be thrown immediately\n *\n * If a function is provided:\n * - returns a custom {@link ToolMessage} as result\n * - throws an error otherwise\n *\n * @default true\n */\n handleToolErrors?:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined);\n}\n\nconst isBaseMessageArray = (input: unknown): input is BaseMessage[] =>\n Array.isArray(input) && input.every(isBaseMessage);\n\nconst isMessagesState = (\n input: unknown\n): input is { messages: BaseMessage[] } =>\n typeof input === \"object\" &&\n input != null &&\n \"messages\" in input &&\n isBaseMessageArray(input.messages);\n\nconst isSendInput = (input: unknown): input is { lg_tool_call: ToolCall } =>\n typeof input === \"object\" && input != null && \"lg_tool_call\" in input;\n\n/**\n * `ToolNode` is a built-in LangGraph component that handles tool calls within an agent's workflow.\n * It works seamlessly with `createReactAgent`, offering advanced tool execution control, built\n * in parallelism, and error handling.\n *\n * @example\n * ```ts\n * import { ToolNode, tool, AIMessage } from \"langchain\";\n * import { z } from \"zod\";\n *\n * const getWeather = tool((input) => {\n * if ([\"sf\", \"san francisco\"].includes(input.location.toLowerCase())) {\n * return \"It's 60 degrees and foggy.\";\n * } else {\n * return \"It's 90 degrees and sunny.\";\n * }\n * }, {\n * name: \"get_weather\",\n * description: \"Call to get the current weather.\",\n * schema: z.object({\n * location: z.string().describe(\"Location to get the weather for.\"),\n * }),\n * });\n *\n * const tools = [getWeather];\n * const toolNode = new ToolNode(tools);\n *\n * const messageWithSingleToolCall = new AIMessage({\n * content: \"\",\n * tool_calls: [\n * {\n * name: \"get_weather\",\n * args: { location: \"sf\" },\n * id: \"tool_call_id\",\n * type: \"tool_call\",\n * }\n * ]\n * })\n *\n * await toolNode.invoke({ messages: [messageWithSingleToolCall] });\n * // Returns tool invocation responses as:\n * // { messages: ToolMessage[] }\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class ToolNode<\n StateSchema extends AnyAnnotationRoot | InteropZodObject = any,\n ContextSchema extends AnyAnnotationRoot | InteropZodObject = any\n> extends RunnableCallable<StateSchema, ContextSchema> {\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[];\n\n trace = false;\n\n signal?: AbortSignal;\n\n handleToolErrors:\n | boolean\n | ((error: unknown, toolCall: ToolCall) => ToolMessage | undefined) = true;\n\n constructor(\n tools: (StructuredToolInterface | DynamicTool | RunnableToolLike)[],\n public options?: ToolNodeOptions\n ) {\n const { name, tags, handleToolErrors } = options ?? {};\n super({\n name,\n tags,\n func: (state, config) =>\n this.run(\n state as ToAnnotationRoot<StateSchema>[\"State\"] &\n PreHookAnnotation[\"State\"],\n config as RunnableConfig\n ),\n });\n this.tools = tools;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.signal = options?.signal;\n }\n\n protected async runTool(\n call: ToolCall,\n config: RunnableConfig\n ): Promise<ToolMessage | Command> {\n const tool = this.tools.find((tool) => tool.name === call.name);\n try {\n if (tool === undefined) {\n throw new Error(`Tool \"${call.name}\" not found.`);\n }\n\n const output = await tool.invoke(\n { ...call, type: \"tool_call\" },\n {\n ...config,\n signal: mergeAbortSignals(this.signal, config.signal),\n }\n );\n\n if (\n (isBaseMessage(output) && output.getType() === \"tool\") ||\n isCommand(output)\n ) {\n return output as ToolMessage | Command;\n }\n\n return new ToolMessage({\n name: tool.name,\n content: typeof output === \"string\" ? output : JSON.stringify(output),\n tool_call_id: call.id!,\n });\n } catch (e: unknown) {\n /**\n * If tool invocation fails due to input parsing error, throw a {@link ToolInvocationError}\n */\n if (e instanceof ToolInputParsingException) {\n throw new ToolInvocationError(e, call);\n }\n\n /**\n * throw the error if user prefers not to handle tool errors\n */\n if (!this.handleToolErrors) {\n throw e;\n }\n\n if (isGraphInterrupt(e)) {\n /**\n * {@link NodeInterrupt} errors are a breakpoint to bring a human into the loop.\n * As such, they are not recoverable by the agent and shouldn't be fed\n * back. Instead, re-throw these errors even when `handleToolErrors = true`.\n */\n throw e;\n }\n\n /**\n * If the signal is aborted, we want to bubble up the error to the invoke caller.\n */\n if (this.signal?.aborted) {\n throw e;\n }\n\n /**\n * if the user provides a function, call it with the error and tool call\n * and return the result if it is a {@link ToolMessage}\n */\n if (typeof this.handleToolErrors === \"function\") {\n const result = this.handleToolErrors(e, call);\n if (result && isToolMessage(result)) {\n return result;\n }\n } else if (this.handleToolErrors) {\n return new ToolMessage({\n name: call.name,\n content: `${e}\\n Please fix your mistakes.`,\n tool_call_id: call.id!,\n });\n }\n\n /**\n * If the user doesn't handle the error, throw it\n */\n throw e;\n }\n }\n\n protected async run(\n state: ToAnnotationRoot<StateSchema>[\"State\"] & PreHookAnnotation[\"State\"],\n config: RunnableConfig\n ): Promise<ContextSchema> {\n let outputs: (ToolMessage | Command)[];\n\n if (isSendInput(state)) {\n outputs = [await this.runTool(state.lg_tool_call, config)];\n } else {\n let messages: BaseMessage[];\n if (isBaseMessageArray(state)) {\n messages = state;\n } else if (isMessagesState(state)) {\n messages = state.messages;\n } else {\n throw new Error(\n \"ToolNode only accepts BaseMessage[] or { messages: BaseMessage[] } as input.\"\n );\n }\n\n const toolMessageIds: Set<string> = new Set(\n messages\n .filter((msg) => msg.getType() === \"tool\")\n .map((msg) => (msg as ToolMessage).tool_call_id)\n );\n\n let aiMessage: AIMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i -= 1) {\n const message = messages[i];\n if (message.getType() === \"ai\") {\n aiMessage = message;\n break;\n }\n }\n\n if (aiMessage?.getType() !== \"ai\") {\n throw new Error(\"ToolNode only accepts AIMessages as input.\");\n }\n\n outputs = await Promise.all(\n aiMessage.tool_calls\n ?.filter((call) => call.id == null || !toolMessageIds.has(call.id))\n .map((call) => this.runTool(call, config)) ?? []\n );\n }\n\n // Preserve existing behavior for non-command tool outputs for backwards compatibility\n if (!outputs.some(isCommand)) {\n return (Array.isArray(state)\n ? outputs\n : { messages: outputs }) as unknown as ContextSchema;\n }\n\n // Handle mixed Command and non-Command outputs\n const combinedOutputs: (\n | { messages: BaseMessage[] }\n | BaseMessage[]\n | Command\n )[] = [];\n let parentCommand: Command | null = null;\n\n for (const output of outputs) {\n if (isCommand(output)) {\n if (\n output.graph === Command.PARENT &&\n Array.isArray(output.goto) &&\n output.goto.every((send) => isSend(send))\n ) {\n if (parentCommand) {\n (parentCommand.goto as Send[]).push(...(output.goto as Send[]));\n } else {\n parentCommand = new Command({\n graph: Command.PARENT,\n goto: output.goto,\n });\n }\n } else {\n combinedOutputs.push(output);\n }\n } else {\n combinedOutputs.push(\n Array.isArray(state) ? [output] : { messages: [output] }\n );\n }\n }\n\n if (parentCommand) {\n combinedOutputs.push(parentCommand);\n }\n\n return combinedOutputs as unknown as ContextSchema;\n }\n}\n\nexport function isSend(x: unknown): x is Send {\n // eslint-disable-next-line no-instanceof/no-instanceof\n return x instanceof Send;\n}\n"],"mappings":"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"}
@@ -116,7 +116,7 @@ var ToolNode = class extends RunnableCallable {
116
116
  if (result && isToolMessage(result)) return result;
117
117
  } else if (this.handleToolErrors) return new ToolMessage({
118
118
  name: call.name,
119
- content: `Error: ${e}\n Please fix your mistakes.`,
119
+ content: `${e}\n Please fix your mistakes.`,
120
120
  tool_call_id: call.id
121
121
  });
122
122
  /**