@librechat/agents 3.1.32 ā 3.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/agents/AgentContext.cjs +14 -5
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +35 -8
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +3 -4
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/index.cjs +43 -11
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +10 -7
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +32 -0
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +34 -13
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +14 -5
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +35 -8
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +3 -4
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/llm/anthropic/index.mjs +43 -11
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/anthropic/types.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +10 -7
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs +32 -0
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +34 -13
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +2 -0
- package/dist/types/llm/anthropic/index.d.ts +7 -1
- package/dist/types/llm/anthropic/types.d.ts +5 -2
- package/dist/types/llm/anthropic/utils/message_outputs.d.ts +1 -1
- package/dist/types/tools/ToolNode.d.ts +8 -3
- package/dist/types/types/tools.d.ts +2 -0
- package/package.json +4 -1
- package/src/agents/AgentContext.ts +18 -5
- package/src/graphs/Graph.ts +45 -9
- package/src/graphs/MultiAgentGraph.ts +3 -4
- package/src/llm/anthropic/index.ts +68 -15
- package/src/llm/anthropic/llm.spec.ts +402 -0
- package/src/llm/anthropic/types.ts +8 -2
- package/src/llm/anthropic/utils/message_inputs.ts +16 -33
- package/src/llm/anthropic/utils/message_outputs.ts +40 -1
- package/src/scripts/test-thinking-to-thinking-handoff-bedrock.ts +165 -0
- package/src/specs/agent-handoffs.test.ts +16 -18
- package/src/specs/thinking-handoff.test.ts +2 -2
- package/src/tools/ToolNode.ts +52 -18
- package/src/types/tools.ts +2 -0
- package/src/utils/llmConfig.ts +2 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { config } from 'dotenv';
|
|
4
|
+
config();
|
|
5
|
+
|
|
6
|
+
import { HumanMessage, BaseMessage } from '@langchain/core/messages';
|
|
7
|
+
import { Run } from '@/run';
|
|
8
|
+
import { ChatModelStreamHandler } from '@/stream';
|
|
9
|
+
import { Providers, GraphEvents } from '@/common';
|
|
10
|
+
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
11
|
+
import type * as t from '@/types';
|
|
12
|
+
|
|
13
|
+
const conversationHistory: BaseMessage[] = [];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Test edge case: switching from Bedrock supervisor (with thinking) to Bedrock specialist (with thinking)
|
|
17
|
+
* Both agents use extended thinking, validating that thinking blocks are properly
|
|
18
|
+
* handled across the handoff boundary when both sides produce them.
|
|
19
|
+
*/
|
|
20
|
+
async function testThinkingToThinkingHandoffBedrock() {
|
|
21
|
+
console.log(
|
|
22
|
+
'Testing Bedrock (with thinking) ā Bedrock (with thinking) handoff...\n'
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const customHandlers = {
|
|
26
|
+
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
27
|
+
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
|
|
28
|
+
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
29
|
+
[GraphEvents.TOOL_START]: {
|
|
30
|
+
handle: (_event: string, data: t.StreamEventData): void => {
|
|
31
|
+
const toolData = data as any;
|
|
32
|
+
if (toolData?.name) {
|
|
33
|
+
console.log(`\nš§ Tool called: ${toolData.name}`);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
[GraphEvents.ON_RUN_STEP]: {
|
|
38
|
+
handle: (_event: string, data: t.StreamEventData): void => {
|
|
39
|
+
const runStep = data as t.RunStep;
|
|
40
|
+
console.log(
|
|
41
|
+
`\nš ON_RUN_STEP: agentId=${runStep.agentId}, groupId=${runStep.groupId}`
|
|
42
|
+
);
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
function createGraphConfig(): t.RunConfig {
|
|
48
|
+
console.log(
|
|
49
|
+
'Creating graph with Bedrock supervisor (thinking) and Bedrock specialist (thinking).\n'
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const agents: t.AgentInputs[] = [
|
|
53
|
+
{
|
|
54
|
+
agentId: 'supervisor',
|
|
55
|
+
provider: Providers.BEDROCK,
|
|
56
|
+
clientOptions: {
|
|
57
|
+
region: process.env.BEDROCK_AWS_REGION || 'us-east-1',
|
|
58
|
+
model: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0',
|
|
59
|
+
credentials: {
|
|
60
|
+
accessKeyId: process.env.BEDROCK_AWS_ACCESS_KEY_ID!,
|
|
61
|
+
secretAccessKey: process.env.BEDROCK_AWS_SECRET_ACCESS_KEY!,
|
|
62
|
+
},
|
|
63
|
+
additionalModelRequestFields: {
|
|
64
|
+
thinking: {
|
|
65
|
+
type: 'enabled',
|
|
66
|
+
budget_tokens: 2000,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
instructions: `You are a task supervisor. When the user asks about code review, use transfer_to_code_reviewer to hand off to the specialist.`,
|
|
71
|
+
maxContextTokens: 8000,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
agentId: 'code_reviewer',
|
|
75
|
+
provider: Providers.BEDROCK,
|
|
76
|
+
clientOptions: {
|
|
77
|
+
region: process.env.BEDROCK_AWS_REGION || 'us-east-1',
|
|
78
|
+
model: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0',
|
|
79
|
+
credentials: {
|
|
80
|
+
accessKeyId: process.env.BEDROCK_AWS_ACCESS_KEY_ID!,
|
|
81
|
+
secretAccessKey: process.env.BEDROCK_AWS_SECRET_ACCESS_KEY!,
|
|
82
|
+
},
|
|
83
|
+
additionalModelRequestFields: {
|
|
84
|
+
thinking: {
|
|
85
|
+
type: 'enabled',
|
|
86
|
+
budget_tokens: 2000,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
instructions: `You are a code review specialist using Bedrock with extended thinking. Think carefully about the code quality, best practices, and potential issues. Provide thoughtful feedback.`,
|
|
91
|
+
maxContextTokens: 8000,
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
const edges: t.GraphEdge[] = [
|
|
96
|
+
{
|
|
97
|
+
from: 'supervisor',
|
|
98
|
+
to: ['code_reviewer'],
|
|
99
|
+
description: 'Transfer to code review specialist',
|
|
100
|
+
edgeType: 'handoff',
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
runId: `thinking-to-thinking-bedrock-test-${Date.now()}`,
|
|
106
|
+
graphConfig: {
|
|
107
|
+
type: 'multi-agent',
|
|
108
|
+
agents,
|
|
109
|
+
edges,
|
|
110
|
+
},
|
|
111
|
+
customHandlers,
|
|
112
|
+
returnContent: true,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const query =
|
|
118
|
+
'Can you review this function and tell me if there are any issues?\n\nfunction add(a, b) { return a + b; }';
|
|
119
|
+
|
|
120
|
+
console.log(`${'='.repeat(60)}`);
|
|
121
|
+
console.log(`USER QUERY: "${query}"`);
|
|
122
|
+
console.log('='.repeat(60));
|
|
123
|
+
|
|
124
|
+
conversationHistory.push(new HumanMessage(query));
|
|
125
|
+
|
|
126
|
+
const runConfig = createGraphConfig();
|
|
127
|
+
const run = await Run.create(runConfig);
|
|
128
|
+
|
|
129
|
+
const streamConfig = {
|
|
130
|
+
configurable: {
|
|
131
|
+
thread_id: 'thinking-to-thinking-bedrock-test-1',
|
|
132
|
+
},
|
|
133
|
+
streamMode: 'values',
|
|
134
|
+
version: 'v2' as const,
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
console.log('\nProcessing request...\n');
|
|
138
|
+
|
|
139
|
+
const inputs = {
|
|
140
|
+
messages: conversationHistory,
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
await run.processStream(inputs, streamConfig);
|
|
144
|
+
const finalMessages = run.getRunMessages();
|
|
145
|
+
|
|
146
|
+
if (finalMessages) {
|
|
147
|
+
conversationHistory.push(...finalMessages);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
151
|
+
console.log('ā
TEST PASSED');
|
|
152
|
+
console.log('='.repeat(60));
|
|
153
|
+
console.log('\nSuccessfully handed off from Bedrock (with thinking) to');
|
|
154
|
+
console.log('Bedrock (with thinking) without errors!');
|
|
155
|
+
console.log('\nThinking blocks were properly managed across the handoff');
|
|
156
|
+
console.log('boundary when both agents produce them.');
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error('\nā TEST FAILED');
|
|
159
|
+
console.error('='.repeat(60));
|
|
160
|
+
console.error('Error:', error);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
testThinkingToThinkingHandoffBedrock();
|
|
@@ -106,11 +106,11 @@ describe('Agent Handoffs Tests', () => {
|
|
|
106
106
|
'agent_a'
|
|
107
107
|
);
|
|
108
108
|
expect(agentAContext).toBeDefined();
|
|
109
|
-
expect(agentAContext?.
|
|
109
|
+
expect(agentAContext?.graphTools).toBeDefined();
|
|
110
110
|
|
|
111
111
|
// Check that handoff tool was created
|
|
112
112
|
const handoffTool = findToolByName(
|
|
113
|
-
agentAContext?.
|
|
113
|
+
agentAContext?.graphTools,
|
|
114
114
|
`${Constants.LC_TRANSFER_TO_}agent_b`
|
|
115
115
|
);
|
|
116
116
|
expect(handoffTool).toBeDefined();
|
|
@@ -203,7 +203,7 @@ describe('Agent Handoffs Tests', () => {
|
|
|
203
203
|
expect(agentBContext).toBeDefined();
|
|
204
204
|
|
|
205
205
|
// Agent B should not have handoff tools (no outgoing edges)
|
|
206
|
-
const handoffTools = agentBContext?.
|
|
206
|
+
const handoffTools = agentBContext?.graphTools?.filter((tool) => {
|
|
207
207
|
const name = getToolName(tool);
|
|
208
208
|
return name?.startsWith(Constants.LC_TRANSFER_TO_) ?? false;
|
|
209
209
|
});
|
|
@@ -244,14 +244,14 @@ describe('Agent Handoffs Tests', () => {
|
|
|
244
244
|
|
|
245
245
|
// Agent A should have tool to transfer to B
|
|
246
246
|
const agentAHandoffTool = findToolByName(
|
|
247
|
-
agentAContext?.
|
|
247
|
+
agentAContext?.graphTools,
|
|
248
248
|
`${Constants.LC_TRANSFER_TO_}agent_b`
|
|
249
249
|
);
|
|
250
250
|
expect(agentAHandoffTool).toBeDefined();
|
|
251
251
|
|
|
252
252
|
// Agent B should have tool to transfer to A
|
|
253
253
|
const agentBHandoffTool = findToolByName(
|
|
254
|
-
agentBContext?.
|
|
254
|
+
agentBContext?.graphTools,
|
|
255
255
|
`${Constants.LC_TRANSFER_TO_}agent_a`
|
|
256
256
|
);
|
|
257
257
|
expect(agentBHandoffTool).toBeDefined();
|
|
@@ -359,7 +359,7 @@ describe('Agent Handoffs Tests', () => {
|
|
|
359
359
|
// Agent A should have tool to transfer to B
|
|
360
360
|
expect(
|
|
361
361
|
findToolByName(
|
|
362
|
-
agentAContext?.
|
|
362
|
+
agentAContext?.graphTools,
|
|
363
363
|
`${Constants.LC_TRANSFER_TO_}agent_b`
|
|
364
364
|
)
|
|
365
365
|
).toBeDefined();
|
|
@@ -367,13 +367,13 @@ describe('Agent Handoffs Tests', () => {
|
|
|
367
367
|
// Agent B should have tool to transfer to C
|
|
368
368
|
expect(
|
|
369
369
|
findToolByName(
|
|
370
|
-
agentBContext?.
|
|
370
|
+
agentBContext?.graphTools,
|
|
371
371
|
`${Constants.LC_TRANSFER_TO_}agent_c`
|
|
372
372
|
)
|
|
373
373
|
).toBeDefined();
|
|
374
374
|
|
|
375
375
|
// Agent C should have no handoff tools
|
|
376
|
-
const agentCHandoffTools = agentCContext?.
|
|
376
|
+
const agentCHandoffTools = agentCContext?.graphTools?.filter((tool) => {
|
|
377
377
|
const name = getToolName(tool);
|
|
378
378
|
return name?.startsWith(Constants.LC_TRANSFER_TO_) ?? false;
|
|
379
379
|
});
|
|
@@ -419,7 +419,7 @@ describe('Agent Handoffs Tests', () => {
|
|
|
419
419
|
expect(routerContext).toBeDefined();
|
|
420
420
|
|
|
421
421
|
// Router should have 3 handoff tools
|
|
422
|
-
const handoffTools = routerContext?.
|
|
422
|
+
const handoffTools = routerContext?.graphTools?.filter((tool) => {
|
|
423
423
|
const name = getToolName(tool);
|
|
424
424
|
return name?.startsWith(Constants.LC_TRANSFER_TO_) ?? false;
|
|
425
425
|
});
|
|
@@ -531,7 +531,7 @@ describe('Agent Handoffs Tests', () => {
|
|
|
531
531
|
'agent_a'
|
|
532
532
|
);
|
|
533
533
|
const handoffTool = findToolByName(
|
|
534
|
-
agentAContext?.
|
|
534
|
+
agentAContext?.graphTools,
|
|
535
535
|
`${Constants.LC_TRANSFER_TO_}agent_b`
|
|
536
536
|
);
|
|
537
537
|
|
|
@@ -562,7 +562,7 @@ describe('Agent Handoffs Tests', () => {
|
|
|
562
562
|
'agent_a'
|
|
563
563
|
);
|
|
564
564
|
const handoffTool = findToolByName(
|
|
565
|
-
agentAContext?.
|
|
565
|
+
agentAContext?.graphTools,
|
|
566
566
|
`${Constants.LC_TRANSFER_TO_}agent_b`
|
|
567
567
|
);
|
|
568
568
|
|
|
@@ -664,7 +664,7 @@ describe('Agent Handoffs Tests', () => {
|
|
|
664
664
|
const agentAContext = (run.Graph as StandardGraph).agentContexts.get(
|
|
665
665
|
'agent_a'
|
|
666
666
|
);
|
|
667
|
-
const handoffTools = agentAContext?.
|
|
667
|
+
const handoffTools = agentAContext?.graphTools?.filter((tool) => {
|
|
668
668
|
const name = getToolName(tool);
|
|
669
669
|
return name?.startsWith(Constants.LC_TRANSFER_TO_) ?? false;
|
|
670
670
|
});
|
|
@@ -734,14 +734,12 @@ describe('Agent Handoffs Tests', () => {
|
|
|
734
734
|
'agent_a'
|
|
735
735
|
);
|
|
736
736
|
|
|
737
|
-
// Agent A should have
|
|
738
|
-
expect(agentAContext?.tools?.length).toBeGreaterThanOrEqual(2);
|
|
739
|
-
|
|
737
|
+
// Agent A should have custom tool in tools and handoff tool in graphTools
|
|
740
738
|
expect(findToolByName(agentAContext?.tools, 'custom_tool')).toBeDefined();
|
|
741
739
|
|
|
742
740
|
expect(
|
|
743
741
|
findToolByName(
|
|
744
|
-
agentAContext?.
|
|
742
|
+
agentAContext?.graphTools,
|
|
745
743
|
`${Constants.LC_TRANSFER_TO_}agent_b`
|
|
746
744
|
)
|
|
747
745
|
).toBeDefined();
|
|
@@ -845,7 +843,7 @@ describe('Agent Handoffs Tests', () => {
|
|
|
845
843
|
'flight_assistant'
|
|
846
844
|
);
|
|
847
845
|
const handoffTool = findToolByName(
|
|
848
|
-
flightContext?.
|
|
846
|
+
flightContext?.graphTools,
|
|
849
847
|
`${Constants.LC_TRANSFER_TO_}hotel_assistant`
|
|
850
848
|
);
|
|
851
849
|
|
|
@@ -875,7 +873,7 @@ describe('Agent Handoffs Tests', () => {
|
|
|
875
873
|
'agent_with_underscores'
|
|
876
874
|
);
|
|
877
875
|
const handoffTool = findToolByName(
|
|
878
|
-
agentContext?.
|
|
876
|
+
agentContext?.graphTools,
|
|
879
877
|
`${Constants.LC_TRANSFER_TO_}AgentWithCamelCase`
|
|
880
878
|
);
|
|
881
879
|
|
|
@@ -484,14 +484,14 @@ describe('Thinking-Enabled Agent Handoff Tests', () => {
|
|
|
484
484
|
|
|
485
485
|
// Verify handoff tools exist
|
|
486
486
|
expect(
|
|
487
|
-
routerContext?.
|
|
487
|
+
routerContext?.graphTools?.find(
|
|
488
488
|
(tool) =>
|
|
489
489
|
(tool as { name?: string }).name ===
|
|
490
490
|
`${Constants.LC_TRANSFER_TO_}processor`
|
|
491
491
|
)
|
|
492
492
|
).toBeDefined();
|
|
493
493
|
expect(
|
|
494
|
-
processorContext?.
|
|
494
|
+
processorContext?.graphTools?.find(
|
|
495
495
|
(tool) =>
|
|
496
496
|
(tool as { name?: string }).name ===
|
|
497
497
|
`${Constants.LC_TRANSFER_TO_}reviewer`
|
package/src/tools/ToolNode.ts
CHANGED
|
@@ -47,10 +47,10 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
47
47
|
private sessions?: t.ToolSessionMap;
|
|
48
48
|
/** When true, dispatches ON_TOOL_EXECUTE events instead of invoking tools directly */
|
|
49
49
|
private eventDrivenMode: boolean = false;
|
|
50
|
-
/** Tool definitions for event-driven mode */
|
|
51
|
-
private toolDefinitions?: Map<string, t.LCTool>;
|
|
52
50
|
/** Agent ID for event-driven mode */
|
|
53
51
|
private agentId?: string;
|
|
52
|
+
/** Tool names that bypass event dispatch and execute directly (e.g., graph-managed handoff tools) */
|
|
53
|
+
private directToolNames?: Set<string>;
|
|
54
54
|
|
|
55
55
|
constructor({
|
|
56
56
|
tools,
|
|
@@ -64,8 +64,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
64
64
|
toolRegistry,
|
|
65
65
|
sessions,
|
|
66
66
|
eventDrivenMode,
|
|
67
|
-
toolDefinitions,
|
|
68
67
|
agentId,
|
|
68
|
+
directToolNames,
|
|
69
69
|
}: t.ToolNodeConstructorParams) {
|
|
70
70
|
super({ name, tags, func: (input, config) => this.run(input, config) });
|
|
71
71
|
this.toolMap = toolMap ?? new Map(tools.map((tool) => [tool.name, tool]));
|
|
@@ -77,8 +77,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
77
77
|
this.toolRegistry = toolRegistry;
|
|
78
78
|
this.sessions = sessions;
|
|
79
79
|
this.eventDrivenMode = eventDrivenMode ?? false;
|
|
80
|
-
this.toolDefinitions = toolDefinitions;
|
|
81
80
|
this.agentId = agentId;
|
|
81
|
+
this.directToolNames = directToolNames;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
@@ -257,15 +257,13 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
/**
|
|
260
|
-
*
|
|
261
|
-
*
|
|
260
|
+
* Dispatches tool calls to the host via ON_TOOL_EXECUTE event and returns raw ToolMessages.
|
|
261
|
+
* Core logic for event-driven execution, separated from output shaping.
|
|
262
262
|
*/
|
|
263
|
-
private async
|
|
263
|
+
private async dispatchToolEvents(
|
|
264
264
|
toolCalls: ToolCall[],
|
|
265
|
-
config: RunnableConfig
|
|
266
|
-
|
|
267
|
-
input: any
|
|
268
|
-
): Promise<T> {
|
|
265
|
+
config: RunnableConfig
|
|
266
|
+
): Promise<ToolMessage[]> {
|
|
269
267
|
const requests: t.ToolCallRequest[] = toolCalls.map((call) => {
|
|
270
268
|
const turn = this.toolUsageCount.get(call.name) ?? 0;
|
|
271
269
|
this.toolUsageCount.set(call.name, turn + 1);
|
|
@@ -296,7 +294,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
296
294
|
}
|
|
297
295
|
);
|
|
298
296
|
|
|
299
|
-
|
|
297
|
+
return results.map((result) => {
|
|
300
298
|
const request = requests.find((r) => r.id === result.toolCallId);
|
|
301
299
|
const toolName = request?.name ?? 'unknown';
|
|
302
300
|
const stepId = this.toolCallStepIds?.get(result.toolCallId) ?? '';
|
|
@@ -354,7 +352,19 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
354
352
|
|
|
355
353
|
return toolMessage;
|
|
356
354
|
});
|
|
355
|
+
}
|
|
357
356
|
|
|
357
|
+
/**
|
|
358
|
+
* Execute all tool calls via ON_TOOL_EXECUTE event dispatch.
|
|
359
|
+
* Used in event-driven mode where the host handles actual tool execution.
|
|
360
|
+
*/
|
|
361
|
+
private async executeViaEvent(
|
|
362
|
+
toolCalls: ToolCall[],
|
|
363
|
+
config: RunnableConfig,
|
|
364
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
365
|
+
input: any
|
|
366
|
+
): Promise<T> {
|
|
367
|
+
const outputs = await this.dispatchToolEvents(toolCalls, config);
|
|
358
368
|
return (Array.isArray(input) ? outputs : { messages: outputs }) as T;
|
|
359
369
|
}
|
|
360
370
|
|
|
@@ -363,7 +373,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
363
373
|
let outputs: (BaseMessage | Command)[];
|
|
364
374
|
|
|
365
375
|
if (this.isSendInput(input)) {
|
|
366
|
-
|
|
376
|
+
const isDirectTool = this.directToolNames?.has(input.lg_tool_call.name);
|
|
377
|
+
if (this.eventDrivenMode && isDirectTool !== true) {
|
|
367
378
|
return this.executeViaEvent([input.lg_tool_call], config, input);
|
|
368
379
|
}
|
|
369
380
|
outputs = [await this.runTool(input.lg_tool_call, config)];
|
|
@@ -422,12 +433,35 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
422
433
|
}) ?? [];
|
|
423
434
|
|
|
424
435
|
if (this.eventDrivenMode && filteredCalls.length > 0) {
|
|
425
|
-
|
|
426
|
-
|
|
436
|
+
if (!this.directToolNames || this.directToolNames.size === 0) {
|
|
437
|
+
return this.executeViaEvent(filteredCalls, config, input);
|
|
438
|
+
}
|
|
427
439
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
440
|
+
const directCalls = filteredCalls.filter((c) =>
|
|
441
|
+
this.directToolNames!.has(c.name)
|
|
442
|
+
);
|
|
443
|
+
const eventCalls = filteredCalls.filter(
|
|
444
|
+
(c) => !this.directToolNames!.has(c.name)
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
const directOutputs: (BaseMessage | Command)[] =
|
|
448
|
+
directCalls.length > 0
|
|
449
|
+
? await Promise.all(
|
|
450
|
+
directCalls.map((call) => this.runTool(call, config))
|
|
451
|
+
)
|
|
452
|
+
: [];
|
|
453
|
+
|
|
454
|
+
const eventOutputs: ToolMessage[] =
|
|
455
|
+
eventCalls.length > 0
|
|
456
|
+
? await this.dispatchToolEvents(eventCalls, config)
|
|
457
|
+
: [];
|
|
458
|
+
|
|
459
|
+
outputs = [...directOutputs, ...eventOutputs];
|
|
460
|
+
} else {
|
|
461
|
+
outputs = await Promise.all(
|
|
462
|
+
filteredCalls.map((call) => this.runTool(call, config))
|
|
463
|
+
);
|
|
464
|
+
}
|
|
431
465
|
}
|
|
432
466
|
|
|
433
467
|
if (!outputs.some(isCommand)) {
|
package/src/types/tools.ts
CHANGED
|
@@ -47,6 +47,8 @@ export type ToolNodeOptions = {
|
|
|
47
47
|
toolDefinitions?: Map<string, LCTool>;
|
|
48
48
|
/** Agent ID for event-driven mode (used to identify which agent's context to use) */
|
|
49
49
|
agentId?: string;
|
|
50
|
+
/** Tool names that must be executed directly (via runTool) even in event-driven mode (e.g., graph-managed handoff tools) */
|
|
51
|
+
directToolNames?: Set<string>;
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
|
package/src/utils/llmConfig.ts
CHANGED
|
@@ -177,7 +177,8 @@ export const llmConfigs: Record<string, t.LLMConfig | undefined> = {
|
|
|
177
177
|
// model: 'anthropic.claude-3-sonnet-20240229-v1:0',
|
|
178
178
|
// model: 'us.anthropic.claude-3-5-sonnet-20241022-v2:0',
|
|
179
179
|
// model: 'us.amazon.nova-pro-v1:0',
|
|
180
|
-
model: 'us.anthropic.claude-sonnet-4-20250514-v1:0',
|
|
180
|
+
// model: 'us.anthropic.claude-sonnet-4-20250514-v1:0',
|
|
181
|
+
model: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0',
|
|
181
182
|
// additionalModelRequestFields: { thinking: { type: 'enabled', budget_tokens: 2000 } },
|
|
182
183
|
region: process.env.BEDROCK_AWS_REGION,
|
|
183
184
|
credentials: {
|