Reputation: 28627
Here's the graph that I've constructed with LangGraphJs:
const workflow = new StateGraph(MessagesAnnotation)
.addNode('fooAgent', fooAgent)
.addNode('barAgent', barAgent)
.addEdge(START, 'fooAgent')
.addEdge('fooAgent', 'barAgent')
.addEdge('barAgent', END);
const graph = workflow.compile({
checkpointer: checkpointSaver,
});
When I run the graph
, I get the following error:
file:///Users/user/code/foobar/node_modules/@langchain/core/dist/language_models/chat_models.js:64
return chatGeneration.message;
^
TypeError: Cannot read properties of undefined (reading 'message')
at ChatOpenAI.invoke (file:///Users/user/code/foobar/node_modules/@langchain/core/dist/language_models/chat_models.js:64:31)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async RunnableSequence.invoke (file:///Users/user/code/foobar/node_modules/@langchain/core/dist/runnables/base.js:1280:27)
at async RunnableCallable.callModel [as func] (file:///Users/user/code/foobar/node_modules/@langchain/langgraph/dist/prebuilt/react_agent_executor.js:227:29)
at async RunnableCallable.invoke (file:///Users/user/code/foobar/node_modules/@langchain/langgraph/dist/utils.js:79:27)
at async RunnableSequence.invoke (file:///Users/user/code/foobar/node_modules/@langchain/core/dist/runnables/base.js:1274:33)
at async _runWithRetry (file:///Users/user/code/foobar/node_modules/@langchain/langgraph/dist/pregel/retry.js:67:22)
at async PregelRunner._executeTasksWithRetry (file:///Users/user/code/foobar/node_modules/@langchain/langgraph/dist/pregel/runner.js:208:33)
at async PregelRunner.tick (file:///Users/user/code/foobar/node_modules/@langchain/langgraph/dist/pregel/runner.js:45:40)
at async CompiledStateGraph._runLoop (file:///Users/user/code/foobar/node_modules/@langchain/langgraph/dist/pregel/index.js:1015:17) {
pregelTaskId: 'c9848e05-19d9-5587-b2b4-4728ad808c34'
}
Node.js v23.3.0
I assumed, incorrectly, that the addNode
function would accept the agent.
However:
CompiledStateGraph
(ref: @langchain/langgraph/dist/prebuilt/react_agent_executor.d.ts
), whereasaddNode
is of type RunnableLike
(ref: @langchain/core/dist/runnables/base.d.ts
)I believe that there may be 2 possible ways to solve this issue:
Are either of these possible?
more details:
The agents are initialised using createReactAgent
, like so:
const checkpointSaver = new MemorySaver();
const fooAgent = createReactAgent({
llm,
tools,
checkpointSaver,
});
/* code to modify the agent to give it specific capabilities */
const barAgent = createReactAgent({
llm,
tools,
checkpointSaver,
});
/* code to modify the agent to give it specific capabilities */
After the agents are added to graph
, they are execute like so:
const inputs = { messages: [new HumanMessage('Please do the following tasks ...')] }
const stream = await graph.stream(inputs, { streamMode: 'values' });
for await (const { messages } of stream) {
console.log(messages);
}
Upvotes: 0
Views: 28
Reputation: 28627
Agents can indeed be passed into addNode
, but both the agents themselves need to be initialised differently, and the top-level graph that is composed of those agents needs to be invoked/parsed differently.
Code details below:
(1) When initialising the agents, do not use the checkpoint saver. There should only be one of these, and it needs to be in the top-level graph - i.e. the main workflow graph.
const checkpointSaver = new MemorySaver();
const fooAgent = createReactAgent({
llm,
tools,
// checkpointSaver, // NOTE Do NOT use a checkpoint saver for each agent
});
/* code to modify the agent to give it specific capabilities */
const barAgent = createReactAgent({
llm,
tools,
// checkpointSaver, // NOTE Do NOT use a checkpoint saver for each agent
});
/* code to modify the agent to give it specific capabilities */
(2) When compiling the graph, that's when the checkpoint saver is necessary.
// NOTE define `workflow`, same as above.
const graph = workflow.compile({
checkpointer: checkpointSaver, // NOTE **only** the top level graph should use a checkpoint saver
});
(3) When invoking graph.stream
, need to set subgraphs
.
Optionally, also set recursionLimit
.
const config = {
configurable: { thread_id: '0x0002' },
subgraphs: true, // NOTE the agents are technically subgraphs
streamMode: 'values',
recursionLimit: 10, // NOTE add a limit, in case the edges between the nodes in the graph were defined incorrectly (as mine was)
};
const stream = graph.stream({ messages: [humanMsg] }, config);
(4) When using subgraphs, the structure of the events in the stream needs to be parsed differently, like so:
let eventIdx = 0;
for await (const event of await stream) {
console.log(`===AGENT=== ${event[0]}`);
const eventMessages = event[1].messages;
if (eventMessages) {
const msg = eventMessages[eventMessages.length - 1];
console.log(`===MSG=== (${++eventIdx}) type: ${msg._getType()}`);
console.log(msg.content);
}
}
Upvotes: 0