@librechat/agents 3.0.776 → 3.1.1
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 +2 -5
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +20 -5
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +26 -17
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +98 -25
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +1 -0
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +3 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +1 -1
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/stream.cjs +4 -2
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +37 -27
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +21 -17
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +10 -5
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +37 -30
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
- package/dist/cjs/tools/search/schema.cjs +25 -23
- package/dist/cjs/tools/search/schema.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +9 -33
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/utils/schema.cjs +27 -0
- package/dist/cjs/utils/schema.cjs.map +1 -0
- package/dist/cjs/utils/title.cjs +28 -14
- package/dist/cjs/utils/title.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +2 -5
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +20 -5
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +26 -17
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +97 -24
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +1 -0
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +1 -0
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +1 -1
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/stream.mjs +4 -2
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +37 -27
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +21 -17
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +10 -5
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +37 -30
- package/dist/esm/tools/ToolSearch.mjs.map +1 -1
- package/dist/esm/tools/search/schema.mjs +25 -23
- package/dist/esm/tools/search/schema.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +10 -34
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/utils/schema.mjs +24 -0
- package/dist/esm/utils/schema.mjs.map +1 -0
- package/dist/esm/utils/title.mjs +28 -14
- package/dist/esm/utils/title.mjs.map +1 -1
- package/dist/types/llm/bedrock/index.d.ts +86 -7
- package/dist/types/llm/bedrock/types.d.ts +27 -0
- package/dist/types/llm/bedrock/utils/index.d.ts +5 -0
- package/dist/types/llm/bedrock/utils/message_inputs.d.ts +31 -0
- package/dist/types/llm/bedrock/utils/message_outputs.d.ts +33 -0
- package/dist/types/tools/CodeExecutor.d.ts +1 -15
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +1 -13
- package/dist/types/tools/ToolSearch.d.ts +1 -15
- package/dist/types/tools/search/schema.d.ts +25 -7
- package/dist/types/tools/search/tool.d.ts +1 -52
- package/dist/types/tools/search/types.d.ts +5 -23
- package/dist/types/types/tools.d.ts +2 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/schema.d.ts +8 -0
- package/package.json +5 -2
- package/src/agents/AgentContext.ts +5 -11
- package/src/graphs/Graph.ts +23 -5
- package/src/graphs/MultiAgentGraph.ts +26 -17
- package/src/llm/bedrock/index.ts +180 -43
- package/src/llm/bedrock/llm.spec.ts +616 -0
- package/src/llm/bedrock/types.ts +51 -0
- package/src/llm/bedrock/utils/index.ts +18 -0
- package/src/llm/bedrock/utils/message_inputs.ts +563 -0
- package/src/llm/bedrock/utils/message_outputs.ts +310 -0
- package/src/messages/core.ts +1 -1
- package/src/scripts/code_exec_multi_session.ts +241 -0
- package/src/scripts/thinking-bedrock.ts +159 -0
- package/src/scripts/thinking.ts +39 -18
- package/src/scripts/tools.ts +7 -3
- package/src/specs/agent-handoffs.test.ts +1 -2
- package/src/specs/tool-error.test.ts +7 -2
- package/src/stream.ts +4 -2
- package/src/test/mockTools.ts +34 -14
- package/src/tools/CodeExecutor.ts +48 -31
- package/src/tools/ProgrammaticToolCalling.ts +24 -23
- package/src/tools/ToolNode.ts +9 -5
- package/src/tools/ToolSearch.ts +54 -43
- package/src/tools/search/schema.ts +30 -25
- package/src/tools/search/tool.ts +23 -16
- package/src/tools/search/types.ts +5 -29
- package/src/types/tools.ts +2 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/schema.ts +35 -0
- package/src/utils/title.ts +31 -19
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// src/scripts/thinking-bedrock.ts
|
|
2
|
+
import { config } from 'dotenv';
|
|
3
|
+
config();
|
|
4
|
+
import { HumanMessage, BaseMessage } from '@langchain/core/messages';
|
|
5
|
+
import type { UsageMetadata } from '@langchain/core/messages';
|
|
6
|
+
import * as t from '@/types';
|
|
7
|
+
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
8
|
+
import { createCodeExecutionTool } from '@/tools/CodeExecutor';
|
|
9
|
+
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
10
|
+
import { GraphEvents, Providers } from '@/common';
|
|
11
|
+
import { getLLMConfig } from '@/utils/llmConfig';
|
|
12
|
+
import { getArgs } from '@/scripts/args';
|
|
13
|
+
import { Run } from '@/run';
|
|
14
|
+
|
|
15
|
+
const conversationHistory: BaseMessage[] = [];
|
|
16
|
+
let _contentParts: t.MessageContentComplex[] = [];
|
|
17
|
+
const collectedUsage: UsageMetadata[] = [];
|
|
18
|
+
|
|
19
|
+
async function testBedrockThinking(): Promise<void> {
|
|
20
|
+
const { userName } = await getArgs();
|
|
21
|
+
const instructions = `You are a helpful AI assistant for ${userName}. When answering questions, be thorough in your reasoning.`;
|
|
22
|
+
const { contentParts, aggregateContent } = createContentAggregator();
|
|
23
|
+
_contentParts = contentParts as t.MessageContentComplex[];
|
|
24
|
+
|
|
25
|
+
// Set up event handlers
|
|
26
|
+
const customHandlers = {
|
|
27
|
+
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
28
|
+
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
29
|
+
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
30
|
+
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
31
|
+
handle: (
|
|
32
|
+
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
33
|
+
data: t.StreamEventData
|
|
34
|
+
): void => {
|
|
35
|
+
console.log('====== ON_RUN_STEP_COMPLETED ======');
|
|
36
|
+
aggregateContent({
|
|
37
|
+
event,
|
|
38
|
+
data: data as unknown as { result: t.ToolEndEvent },
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
[GraphEvents.ON_RUN_STEP]: {
|
|
43
|
+
handle: (event: GraphEvents.ON_RUN_STEP, data: t.RunStep) => {
|
|
44
|
+
aggregateContent({ event, data });
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
[GraphEvents.ON_RUN_STEP_DELTA]: {
|
|
48
|
+
handle: (
|
|
49
|
+
event: GraphEvents.ON_RUN_STEP_DELTA,
|
|
50
|
+
data: t.RunStepDeltaEvent
|
|
51
|
+
) => {
|
|
52
|
+
aggregateContent({ event, data });
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
[GraphEvents.ON_MESSAGE_DELTA]: {
|
|
56
|
+
handle: (
|
|
57
|
+
event: GraphEvents.ON_MESSAGE_DELTA,
|
|
58
|
+
data: t.MessageDeltaEvent
|
|
59
|
+
) => {
|
|
60
|
+
aggregateContent({ event, data });
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
[GraphEvents.ON_REASONING_DELTA]: {
|
|
64
|
+
handle: (
|
|
65
|
+
event: GraphEvents.ON_REASONING_DELTA,
|
|
66
|
+
data: t.ReasoningDeltaEvent
|
|
67
|
+
) => {
|
|
68
|
+
aggregateContent({ event, data });
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const baseLlmConfig = getLLMConfig(Providers.BEDROCK);
|
|
74
|
+
|
|
75
|
+
// Enable thinking with token budget for Bedrock
|
|
76
|
+
const llmConfig = {
|
|
77
|
+
...baseLlmConfig,
|
|
78
|
+
model: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',
|
|
79
|
+
maxTokens: 5000,
|
|
80
|
+
additionalModelRequestFields: {
|
|
81
|
+
thinking: { type: 'enabled', budget_tokens: 2000 },
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const run = await Run.create<t.IState>({
|
|
86
|
+
runId: 'test-bedrock-thinking-id',
|
|
87
|
+
graphConfig: {
|
|
88
|
+
instructions,
|
|
89
|
+
type: 'standard',
|
|
90
|
+
tools: [createCodeExecutionTool()],
|
|
91
|
+
llmConfig,
|
|
92
|
+
},
|
|
93
|
+
returnContent: true,
|
|
94
|
+
customHandlers: customHandlers as t.RunConfig['customHandlers'],
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const config = {
|
|
98
|
+
configurable: {
|
|
99
|
+
thread_id: 'bedrock-thinking-test-thread',
|
|
100
|
+
},
|
|
101
|
+
streamMode: 'values',
|
|
102
|
+
version: 'v2' as const,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Test 1: Regular thinking mode
|
|
106
|
+
console.log('\n\nTest 1: Bedrock Regular thinking mode');
|
|
107
|
+
const userMessage1 = `Please print 'hello world' in python`;
|
|
108
|
+
conversationHistory.push(new HumanMessage(userMessage1));
|
|
109
|
+
|
|
110
|
+
console.log('Running first query with Bedrock thinking enabled...');
|
|
111
|
+
const firstInputs = { messages: [...conversationHistory] };
|
|
112
|
+
await run.processStream(firstInputs, config);
|
|
113
|
+
|
|
114
|
+
// Extract and display thinking blocks
|
|
115
|
+
const finalMessages = run.getRunMessages();
|
|
116
|
+
console.log('\n\nFinal messages after Test 1:');
|
|
117
|
+
console.dir(finalMessages, { depth: null });
|
|
118
|
+
|
|
119
|
+
// Test 2: Try multi-turn conversation
|
|
120
|
+
console.log(
|
|
121
|
+
'\n\nTest 2: Multi-turn conversation with Bedrock thinking enabled'
|
|
122
|
+
);
|
|
123
|
+
const userMessage2 = `Given your previous analysis, what would be the most significant technical challenges in making this transition?`;
|
|
124
|
+
conversationHistory.push(new HumanMessage(userMessage2));
|
|
125
|
+
|
|
126
|
+
console.log('Running second query with Bedrock thinking enabled...');
|
|
127
|
+
const secondInputs = { messages: [...conversationHistory] };
|
|
128
|
+
await run.processStream(secondInputs, config);
|
|
129
|
+
|
|
130
|
+
// Display thinking blocks for second response
|
|
131
|
+
const finalMessages2 = run.getRunMessages();
|
|
132
|
+
console.log('\n\nBedrock thinking feature test completed!');
|
|
133
|
+
console.dir(finalMessages2, { depth: null });
|
|
134
|
+
|
|
135
|
+
console.log('\n\nContent parts:');
|
|
136
|
+
console.dir(_contentParts, { depth: null });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
140
|
+
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
141
|
+
console.log('Conversation history:');
|
|
142
|
+
console.dir(conversationHistory, { depth: null });
|
|
143
|
+
console.log('Content parts:');
|
|
144
|
+
console.dir(_contentParts, { depth: null });
|
|
145
|
+
process.exit(1);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
process.on('uncaughtException', (err) => {
|
|
149
|
+
console.error('Uncaught Exception:', err);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
testBedrockThinking().catch((err) => {
|
|
153
|
+
console.error(err);
|
|
154
|
+
console.log('Conversation history:');
|
|
155
|
+
console.dir(conversationHistory, { depth: null });
|
|
156
|
+
console.log('Content parts:');
|
|
157
|
+
console.dir(_contentParts, { depth: null });
|
|
158
|
+
process.exit(1);
|
|
159
|
+
});
|
package/src/scripts/thinking.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
// src/scripts/test-thinking.ts
|
|
2
2
|
import { config } from 'dotenv';
|
|
3
3
|
config();
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
HumanMessage,
|
|
6
|
+
SystemMessage,
|
|
7
|
+
BaseMessage,
|
|
8
|
+
} from '@langchain/core/messages';
|
|
5
9
|
import type { UsageMetadata } from '@langchain/core/messages';
|
|
6
10
|
import * as t from '@/types';
|
|
7
11
|
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
@@ -21,17 +25,23 @@ async function testThinking(): Promise<void> {
|
|
|
21
25
|
const instructions = `You are a helpful AI assistant for ${userName}. When answering questions, be thorough in your reasoning.`;
|
|
22
26
|
const { contentParts, aggregateContent } = createContentAggregator();
|
|
23
27
|
_contentParts = contentParts as t.MessageContentComplex[];
|
|
24
|
-
|
|
28
|
+
|
|
25
29
|
// Set up event handlers
|
|
26
30
|
const customHandlers = {
|
|
27
31
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
28
32
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
29
33
|
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
30
34
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
31
|
-
handle: (
|
|
35
|
+
handle: (
|
|
36
|
+
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
37
|
+
data: t.StreamEventData
|
|
38
|
+
): void => {
|
|
32
39
|
console.log('====== ON_RUN_STEP_COMPLETED ======');
|
|
33
|
-
aggregateContent({
|
|
34
|
-
|
|
40
|
+
aggregateContent({
|
|
41
|
+
event,
|
|
42
|
+
data: data as unknown as { result: t.ToolEndEvent },
|
|
43
|
+
});
|
|
44
|
+
},
|
|
35
45
|
},
|
|
36
46
|
[GraphEvents.ON_RUN_STEP]: {
|
|
37
47
|
handle: (event: GraphEvents.ON_RUN_STEP, data: t.RunStep) => {
|
|
@@ -39,29 +49,38 @@ async function testThinking(): Promise<void> {
|
|
|
39
49
|
},
|
|
40
50
|
},
|
|
41
51
|
[GraphEvents.ON_RUN_STEP_DELTA]: {
|
|
42
|
-
handle: (
|
|
52
|
+
handle: (
|
|
53
|
+
event: GraphEvents.ON_RUN_STEP_DELTA,
|
|
54
|
+
data: t.RunStepDeltaEvent
|
|
55
|
+
) => {
|
|
43
56
|
aggregateContent({ event, data });
|
|
44
57
|
},
|
|
45
58
|
},
|
|
46
59
|
[GraphEvents.ON_MESSAGE_DELTA]: {
|
|
47
|
-
handle: (
|
|
60
|
+
handle: (
|
|
61
|
+
event: GraphEvents.ON_MESSAGE_DELTA,
|
|
62
|
+
data: t.MessageDeltaEvent
|
|
63
|
+
) => {
|
|
48
64
|
aggregateContent({ event, data });
|
|
49
65
|
},
|
|
50
66
|
},
|
|
51
67
|
[GraphEvents.ON_REASONING_DELTA]: {
|
|
52
|
-
handle: (
|
|
68
|
+
handle: (
|
|
69
|
+
event: GraphEvents.ON_REASONING_DELTA,
|
|
70
|
+
data: t.ReasoningDeltaEvent
|
|
71
|
+
) => {
|
|
53
72
|
aggregateContent({ event, data });
|
|
54
73
|
},
|
|
55
74
|
},
|
|
56
75
|
};
|
|
57
76
|
|
|
58
77
|
const baseLlmConfig: t.LLMConfig = getLLMConfig(Providers.ANTHROPIC);
|
|
59
|
-
|
|
78
|
+
|
|
60
79
|
// Enable thinking with token budget
|
|
61
80
|
const llmConfig = {
|
|
62
81
|
...baseLlmConfig,
|
|
63
82
|
model: 'claude-3-7-sonnet-latest',
|
|
64
|
-
thinking: { type:
|
|
83
|
+
thinking: { type: 'enabled', budget_tokens: 2000 },
|
|
65
84
|
};
|
|
66
85
|
|
|
67
86
|
const run = await Run.create<t.IState>({
|
|
@@ -93,7 +112,7 @@ async function testThinking(): Promise<void> {
|
|
|
93
112
|
console.log('Running first query with thinking enabled...');
|
|
94
113
|
const firstInputs = { messages: [...conversationHistory] };
|
|
95
114
|
await run.processStream(firstInputs, config);
|
|
96
|
-
|
|
115
|
+
|
|
97
116
|
// Extract and display thinking blocks
|
|
98
117
|
const finalMessages = run.getRunMessages();
|
|
99
118
|
|
|
@@ -101,30 +120,32 @@ async function testThinking(): Promise<void> {
|
|
|
101
120
|
console.log('\n\nTest 2: Multi-turn conversation with thinking enabled');
|
|
102
121
|
const userMessage2 = `Given your previous analysis, what would be the most significant technical challenges in making this transition?`;
|
|
103
122
|
conversationHistory.push(new HumanMessage(userMessage2));
|
|
104
|
-
|
|
123
|
+
|
|
105
124
|
console.log('Running second query with thinking enabled...');
|
|
106
125
|
const secondInputs = { messages: [...conversationHistory] };
|
|
107
126
|
await run.processStream(secondInputs, config);
|
|
108
|
-
|
|
127
|
+
|
|
109
128
|
// Display thinking blocks for second response
|
|
110
129
|
const finalMessages2 = run.getRunMessages();
|
|
111
130
|
|
|
112
131
|
// Test 3: Redacted thinking mode
|
|
113
132
|
console.log('\n\nTest 3: Redacted thinking mode');
|
|
114
|
-
const magicString =
|
|
133
|
+
const magicString =
|
|
134
|
+
'ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432ECCCE4C1253D5E2D82641AC0E52CC2876CB';
|
|
115
135
|
const userMessage3 = `${magicString}\n\nExplain how quantum computing works in simple terms.`;
|
|
116
|
-
|
|
136
|
+
|
|
117
137
|
// Reset conversation for clean test
|
|
118
138
|
conversationHistory.length = 0;
|
|
119
139
|
conversationHistory.push(new HumanMessage(userMessage3));
|
|
120
|
-
|
|
140
|
+
|
|
121
141
|
console.log('Running query with redacted thinking...');
|
|
122
142
|
const thirdInputs = { messages: [...conversationHistory] };
|
|
123
143
|
await run.processStream(thirdInputs, config);
|
|
124
|
-
|
|
144
|
+
|
|
125
145
|
// Display redacted thinking blocks
|
|
126
146
|
const finalMessages3 = run.getRunMessages();
|
|
127
147
|
console.log('\n\nThinking feature test completed!');
|
|
148
|
+
console.dir(finalMessages3, { depth: null });
|
|
128
149
|
}
|
|
129
150
|
|
|
130
151
|
process.on('unhandledRejection', (reason, promise) => {
|
|
@@ -147,4 +168,4 @@ testThinking().catch((err) => {
|
|
|
147
168
|
console.log('Content parts:');
|
|
148
169
|
console.dir(_contentParts, { depth: null });
|
|
149
170
|
process.exit(1);
|
|
150
|
-
});
|
|
171
|
+
});
|
package/src/scripts/tools.ts
CHANGED
|
@@ -18,9 +18,13 @@ async function testStandardStreaming(): Promise<void> {
|
|
|
18
18
|
const { userName, location, provider, currentDate } = await getArgs();
|
|
19
19
|
const { contentParts, aggregateContent } = createContentAggregator();
|
|
20
20
|
const customHandlers = {
|
|
21
|
-
[GraphEvents.TOOL_END]: new ToolEndHandler(
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
[GraphEvents.TOOL_END]: new ToolEndHandler(
|
|
22
|
+
undefined,
|
|
23
|
+
undefined,
|
|
24
|
+
(name?: string) => {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
),
|
|
24
28
|
[GraphEvents.CHAT_MODEL_END]: {
|
|
25
29
|
handle: (
|
|
26
30
|
_event: string,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// src/specs/agent-handoffs.test.ts
|
|
2
|
-
import { z } from 'zod';
|
|
3
2
|
import { DynamicStructuredTool } from '@langchain/core/tools';
|
|
4
3
|
import { HumanMessage, ToolMessage } from '@langchain/core/messages';
|
|
5
4
|
import type { ToolCall } from '@langchain/core/messages/tool';
|
|
@@ -708,7 +707,7 @@ describe('Agent Handoffs Tests', () => {
|
|
|
708
707
|
const customTool = new DynamicStructuredTool({
|
|
709
708
|
name: 'custom_tool',
|
|
710
709
|
description: 'A custom tool',
|
|
711
|
-
schema:
|
|
710
|
+
schema: { type: 'object', properties: {}, required: [] },
|
|
712
711
|
func: async (): Promise<string> => 'Tool result',
|
|
713
712
|
});
|
|
714
713
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
1
|
import { config } from 'dotenv';
|
|
3
2
|
config();
|
|
4
3
|
import { tool } from '@langchain/core/tools';
|
|
@@ -21,7 +20,13 @@ const errorTool = tool(
|
|
|
21
20
|
{
|
|
22
21
|
name: 'errorTool',
|
|
23
22
|
description: 'A tool that always throws an error',
|
|
24
|
-
schema:
|
|
23
|
+
schema: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: {
|
|
26
|
+
input: { type: 'string' },
|
|
27
|
+
},
|
|
28
|
+
required: [],
|
|
29
|
+
},
|
|
25
30
|
}
|
|
26
31
|
);
|
|
27
32
|
|
package/src/stream.ts
CHANGED
|
@@ -339,7 +339,8 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
339
339
|
(c) =>
|
|
340
340
|
(c.type?.startsWith(ContentTypes.THINKING) ?? false) ||
|
|
341
341
|
(c.type?.startsWith(ContentTypes.REASONING) ?? false) ||
|
|
342
|
-
(c.type?.startsWith(ContentTypes.REASONING_CONTENT) ?? false)
|
|
342
|
+
(c.type?.startsWith(ContentTypes.REASONING_CONTENT) ?? false) ||
|
|
343
|
+
c.type === 'redacted_thinking'
|
|
343
344
|
)
|
|
344
345
|
) {
|
|
345
346
|
await graph.dispatchReasoningDelta(stepId, {
|
|
@@ -365,7 +366,8 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
365
366
|
Array.isArray(chunk.content) &&
|
|
366
367
|
(chunk.content[0]?.type === ContentTypes.THINKING ||
|
|
367
368
|
chunk.content[0]?.type === ContentTypes.REASONING ||
|
|
368
|
-
chunk.content[0]?.type === ContentTypes.REASONING_CONTENT
|
|
369
|
+
chunk.content[0]?.type === ContentTypes.REASONING_CONTENT ||
|
|
370
|
+
chunk.content[0]?.type === 'redacted_thinking')
|
|
369
371
|
) {
|
|
370
372
|
reasoning_content = 'valid';
|
|
371
373
|
} else if (
|
package/src/test/mockTools.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Shared mock tools for testing across all test scripts.
|
|
4
4
|
* Centralizes tool definitions to follow DRY principles.
|
|
5
5
|
*/
|
|
6
|
-
import { z } from 'zod';
|
|
7
6
|
import { tool } from '@langchain/core/tools';
|
|
8
7
|
import type { StructuredToolInterface } from '@langchain/core/tools';
|
|
9
8
|
import type { LCTool, LCToolRegistry } from '@/types';
|
|
@@ -29,7 +28,7 @@ export function createGetTeamMembersTool(): StructuredToolInterface {
|
|
|
29
28
|
name: 'get_team_members',
|
|
30
29
|
description:
|
|
31
30
|
'Get list of team members. Returns array of objects with id, name, and department fields.',
|
|
32
|
-
schema:
|
|
31
|
+
schema: { type: 'object', properties: {}, required: [] },
|
|
33
32
|
}
|
|
34
33
|
);
|
|
35
34
|
}
|
|
@@ -59,7 +58,8 @@ export function createGetExpensesTool(): StructuredToolInterface {
|
|
|
59
58
|
};
|
|
60
59
|
|
|
61
60
|
return tool(
|
|
62
|
-
async (
|
|
61
|
+
async (input) => {
|
|
62
|
+
const { user_id } = input as { user_id: string };
|
|
63
63
|
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
64
64
|
return expenseData[user_id] ?? [];
|
|
65
65
|
},
|
|
@@ -67,9 +67,16 @@ export function createGetExpensesTool(): StructuredToolInterface {
|
|
|
67
67
|
name: 'get_expenses',
|
|
68
68
|
description:
|
|
69
69
|
'Get expense records for a user. Returns array of objects with amount and category fields.',
|
|
70
|
-
schema:
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
schema: {
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
user_id: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
description: 'The user ID to fetch expenses for',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
required: ['user_id'],
|
|
79
|
+
},
|
|
73
80
|
}
|
|
74
81
|
);
|
|
75
82
|
}
|
|
@@ -91,7 +98,8 @@ export function createGetWeatherTool(): StructuredToolInterface {
|
|
|
91
98
|
};
|
|
92
99
|
|
|
93
100
|
return tool(
|
|
94
|
-
async (
|
|
101
|
+
async (input) => {
|
|
102
|
+
const { city } = input as { city: string };
|
|
95
103
|
await new Promise((resolve) => setTimeout(resolve, 40));
|
|
96
104
|
const weather = weatherData[city];
|
|
97
105
|
if (!weather) {
|
|
@@ -103,9 +111,13 @@ export function createGetWeatherTool(): StructuredToolInterface {
|
|
|
103
111
|
name: 'get_weather',
|
|
104
112
|
description:
|
|
105
113
|
'Get current weather for a city. Returns object with temperature (number) and condition (string) fields.',
|
|
106
|
-
schema:
|
|
107
|
-
|
|
108
|
-
|
|
114
|
+
schema: {
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: {
|
|
117
|
+
city: { type: 'string', description: 'City name' },
|
|
118
|
+
},
|
|
119
|
+
required: ['city'],
|
|
120
|
+
},
|
|
109
121
|
}
|
|
110
122
|
);
|
|
111
123
|
}
|
|
@@ -115,7 +127,8 @@ export function createGetWeatherTool(): StructuredToolInterface {
|
|
|
115
127
|
*/
|
|
116
128
|
export function createCalculatorTool(): StructuredToolInterface {
|
|
117
129
|
return tool(
|
|
118
|
-
async (
|
|
130
|
+
async (input) => {
|
|
131
|
+
const { expression } = input as { expression: string };
|
|
119
132
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
120
133
|
// Simple eval for demo (in production, use a proper math parser)
|
|
121
134
|
|
|
@@ -125,9 +138,16 @@ export function createCalculatorTool(): StructuredToolInterface {
|
|
|
125
138
|
{
|
|
126
139
|
name: 'calculator',
|
|
127
140
|
description: 'Evaluate a mathematical expression',
|
|
128
|
-
schema:
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
schema: {
|
|
142
|
+
type: 'object',
|
|
143
|
+
properties: {
|
|
144
|
+
expression: {
|
|
145
|
+
type: 'string',
|
|
146
|
+
description: 'Mathematical expression to evaluate',
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
required: ['expression'],
|
|
150
|
+
},
|
|
131
151
|
}
|
|
132
152
|
);
|
|
133
153
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
1
|
import { config } from 'dotenv';
|
|
3
2
|
import fetch, { RequestInit } from 'node-fetch';
|
|
4
3
|
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
@@ -21,25 +20,33 @@ const accessMessage =
|
|
|
21
20
|
const emptyOutputMessage =
|
|
22
21
|
'stdout: Empty. Ensure you\'re writing output explicitly.\n';
|
|
23
22
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
23
|
+
const SUPPORTED_LANGUAGES = [
|
|
24
|
+
'py',
|
|
25
|
+
'js',
|
|
26
|
+
'ts',
|
|
27
|
+
'c',
|
|
28
|
+
'cpp',
|
|
29
|
+
'java',
|
|
30
|
+
'php',
|
|
31
|
+
'rs',
|
|
32
|
+
'go',
|
|
33
|
+
'd',
|
|
34
|
+
'f90',
|
|
35
|
+
'r',
|
|
36
|
+
] as const;
|
|
37
|
+
|
|
38
|
+
const CodeExecutionToolSchema = {
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: {
|
|
41
|
+
lang: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
enum: SUPPORTED_LANGUAGES,
|
|
44
|
+
description:
|
|
45
|
+
'The programming language or runtime to execute the code in.',
|
|
46
|
+
},
|
|
47
|
+
code: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: `The complete, self-contained code to execute, without any truncation or minimization.
|
|
43
50
|
- The environment is stateless; variables and imports don't persist between executions.
|
|
44
51
|
- Generated files from previous executions are automatically available in "/mnt/data/".
|
|
45
52
|
- Files from previous executions are automatically available and can be modified in place.
|
|
@@ -50,21 +57,26 @@ const CodeExecutionToolSchema = z.object({
|
|
|
50
57
|
- py: Matplotlib: Use \`plt.savefig()\` to save plots as files.
|
|
51
58
|
- js: use the \`console\` or \`process\` methods for all outputs.
|
|
52
59
|
- r: IMPORTANT: No X11 display available. ALL graphics MUST use Cairo library (library(Cairo)).
|
|
53
|
-
- Other languages: use appropriate output functions
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
60
|
+
- Other languages: use appropriate output functions.`,
|
|
61
|
+
},
|
|
62
|
+
args: {
|
|
63
|
+
type: 'array',
|
|
64
|
+
items: { type: 'string' },
|
|
65
|
+
description:
|
|
66
|
+
'Additional arguments to execute the code with. This should only be used if the input code requires additional arguments to run.',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
required: ['lang', 'code'],
|
|
70
|
+
} as const;
|
|
61
71
|
|
|
62
72
|
const baseEndpoint = getCodeBaseURL();
|
|
63
73
|
const EXEC_ENDPOINT = `${baseEndpoint}/exec`;
|
|
64
74
|
|
|
75
|
+
type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number];
|
|
76
|
+
|
|
65
77
|
function createCodeExecutionTool(
|
|
66
78
|
params: t.CodeExecutionToolParams = {}
|
|
67
|
-
): DynamicStructuredTool
|
|
79
|
+
): DynamicStructuredTool {
|
|
68
80
|
const apiKey =
|
|
69
81
|
params[EnvVar.CODE_API_KEY] ??
|
|
70
82
|
params.apiKey ??
|
|
@@ -83,8 +95,13 @@ Usage:
|
|
|
83
95
|
- NEVER use this tool to execute malicious code.
|
|
84
96
|
`.trim();
|
|
85
97
|
|
|
86
|
-
return tool
|
|
87
|
-
async (
|
|
98
|
+
return tool(
|
|
99
|
+
async (rawInput, config) => {
|
|
100
|
+
const { lang, code, ...rest } = rawInput as {
|
|
101
|
+
lang: SupportedLanguage;
|
|
102
|
+
code: string;
|
|
103
|
+
args?: string[];
|
|
104
|
+
};
|
|
88
105
|
/**
|
|
89
106
|
* Extract session context from config.toolCall (injected by ToolNode).
|
|
90
107
|
* - session_id: For API to associate with previous session
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// src/tools/ProgrammaticToolCalling.ts
|
|
2
|
-
import { z } from 'zod';
|
|
3
2
|
import { config } from 'dotenv';
|
|
4
3
|
import fetch, { RequestInit } from 'node-fetch';
|
|
5
4
|
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
@@ -33,12 +32,13 @@ const DEFAULT_TIMEOUT = 60000;
|
|
|
33
32
|
// Schema
|
|
34
33
|
// ============================================================================
|
|
35
34
|
|
|
36
|
-
const ProgrammaticToolCallingSchema =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
const ProgrammaticToolCallingSchema = {
|
|
36
|
+
type: 'object',
|
|
37
|
+
properties: {
|
|
38
|
+
code: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
minLength: 1,
|
|
41
|
+
description: `Python code that calls tools programmatically. Tools are available as async functions.
|
|
42
42
|
|
|
43
43
|
CRITICAL - STATELESS EXECUTION:
|
|
44
44
|
Each call is a fresh Python interpreter. Variables, imports, and data do NOT persist between calls.
|
|
@@ -66,19 +66,19 @@ Rules:
|
|
|
66
66
|
- Just write code with await—auto-wrapped in async context
|
|
67
67
|
- DO NOT define async def main() or call asyncio.run()
|
|
68
68
|
- Tools are pre-defined—DO NOT write function definitions
|
|
69
|
-
- Only print() output returns to the model
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
69
|
+
- Only print() output returns to the model`,
|
|
70
|
+
},
|
|
71
|
+
timeout: {
|
|
72
|
+
type: 'integer',
|
|
73
|
+
minimum: 1000,
|
|
74
|
+
maximum: 300000,
|
|
75
|
+
default: DEFAULT_TIMEOUT,
|
|
76
|
+
description:
|
|
77
|
+
'Maximum execution time in milliseconds. Default: 60 seconds. Max: 5 minutes.',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
required: ['code'],
|
|
81
|
+
} as const;
|
|
82
82
|
|
|
83
83
|
// ============================================================================
|
|
84
84
|
// Helper Functions
|
|
@@ -576,7 +576,7 @@ export function formatCompletedResponse(
|
|
|
576
576
|
*/
|
|
577
577
|
export function createProgrammaticToolCallingTool(
|
|
578
578
|
initParams: t.ProgrammaticToolCallingParams = {}
|
|
579
|
-
): DynamicStructuredTool
|
|
579
|
+
): DynamicStructuredTool {
|
|
580
580
|
const apiKey =
|
|
581
581
|
(initParams[EnvVar.CODE_API_KEY] as string | undefined) ??
|
|
582
582
|
initParams.apiKey ??
|
|
@@ -616,8 +616,9 @@ Example (complete pipeline):
|
|
|
616
616
|
data = await query_db(sql="..."); df = process(data); await save_to_sheet(data=df); print("Done")
|
|
617
617
|
`.trim();
|
|
618
618
|
|
|
619
|
-
return tool
|
|
620
|
-
async (
|
|
619
|
+
return tool(
|
|
620
|
+
async (rawParams, config) => {
|
|
621
|
+
const params = rawParams as { code: string; timeout?: number };
|
|
621
622
|
const { code, timeout = DEFAULT_TIMEOUT } = params;
|
|
622
623
|
|
|
623
624
|
// Extra params injected by ToolNode (follows web_search pattern)
|