@librechat/agents 3.0.36 → 3.0.40
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 +71 -2
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/enum.cjs +2 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/events.cjs +3 -0
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +5 -1
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/main.cjs +12 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +329 -0
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -0
- package/dist/cjs/tools/ToolNode.cjs +34 -3
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearchRegex.cjs +455 -0
- package/dist/cjs/tools/ToolSearchRegex.cjs.map +1 -0
- package/dist/esm/agents/AgentContext.mjs +71 -2
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/enum.mjs +2 -0
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +4 -1
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +5 -1
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/main.mjs +2 -0
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +324 -0
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -0
- package/dist/esm/tools/ToolNode.mjs +34 -3
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearchRegex.mjs +448 -0
- package/dist/esm/tools/ToolSearchRegex.mjs.map +1 -0
- package/dist/types/agents/AgentContext.d.ts +25 -1
- package/dist/types/common/enum.d.ts +2 -0
- package/dist/types/graphs/Graph.d.ts +2 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/test/mockTools.d.ts +28 -0
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +86 -0
- package/dist/types/tools/ToolNode.d.ts +7 -1
- package/dist/types/tools/ToolSearchRegex.d.ts +80 -0
- package/dist/types/types/graph.d.ts +7 -1
- package/dist/types/types/tools.d.ts +136 -0
- package/package.json +5 -1
- package/src/agents/AgentContext.ts +86 -0
- package/src/common/enum.ts +2 -0
- package/src/events.ts +5 -1
- package/src/graphs/Graph.ts +6 -0
- package/src/index.ts +2 -0
- package/src/scripts/code_exec_ptc.ts +277 -0
- package/src/scripts/programmatic_exec.ts +396 -0
- package/src/scripts/programmatic_exec_agent.ts +231 -0
- package/src/scripts/tool_search_regex.ts +162 -0
- package/src/test/mockTools.ts +366 -0
- package/src/tools/ProgrammaticToolCalling.ts +423 -0
- package/src/tools/ToolNode.ts +38 -4
- package/src/tools/ToolSearchRegex.ts +535 -0
- package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.ts +318 -0
- package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +613 -0
- package/src/tools/__tests__/ToolSearchRegex.integration.test.ts +161 -0
- package/src/tools/__tests__/ToolSearchRegex.test.ts +232 -0
- package/src/types/graph.ts +7 -1
- package/src/types/tools.ts +166 -0
|
@@ -13,6 +13,19 @@ import type * as t from '@/types';
|
|
|
13
13
|
import type { createPruneMessages } from '@/messages';
|
|
14
14
|
import { ContentTypes, Providers } from '@/common';
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Checks if a tool allows the specified caller type.
|
|
18
|
+
* Default is 'direct' only if allowed_callers is not specified.
|
|
19
|
+
*/
|
|
20
|
+
function toolAllowsCaller(
|
|
21
|
+
toolDef: t.LCTool | undefined,
|
|
22
|
+
caller: t.AllowedCaller
|
|
23
|
+
): boolean {
|
|
24
|
+
if (!toolDef) return false;
|
|
25
|
+
const allowedCallers = toolDef.allowed_callers ?? ['direct'];
|
|
26
|
+
return allowedCallers.includes(caller);
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
/**
|
|
17
30
|
* Encapsulates agent-specific state that can vary between agents in a multi-agent system
|
|
18
31
|
*/
|
|
@@ -32,6 +45,7 @@ export class AgentContext {
|
|
|
32
45
|
tools,
|
|
33
46
|
toolMap,
|
|
34
47
|
toolEnd,
|
|
48
|
+
toolRegistry,
|
|
35
49
|
instructions,
|
|
36
50
|
additional_instructions,
|
|
37
51
|
streamBuffer,
|
|
@@ -48,6 +62,7 @@ export class AgentContext {
|
|
|
48
62
|
streamBuffer,
|
|
49
63
|
tools,
|
|
50
64
|
toolMap,
|
|
65
|
+
toolRegistry,
|
|
51
66
|
instructions,
|
|
52
67
|
additionalInstructions: additional_instructions,
|
|
53
68
|
reasoningKey,
|
|
@@ -102,6 +117,11 @@ export class AgentContext {
|
|
|
102
117
|
tools?: t.GraphTools;
|
|
103
118
|
/** Tool map for this agent */
|
|
104
119
|
toolMap?: t.ToolMap;
|
|
120
|
+
/**
|
|
121
|
+
* Tool definitions registry (includes deferred and programmatic tool metadata).
|
|
122
|
+
* Used for tool search and programmatic tool calling.
|
|
123
|
+
*/
|
|
124
|
+
toolRegistry?: t.LCToolRegistry;
|
|
105
125
|
/** Instructions for this agent */
|
|
106
126
|
instructions?: string;
|
|
107
127
|
/** Additional instructions for this agent */
|
|
@@ -137,6 +157,7 @@ export class AgentContext {
|
|
|
137
157
|
tokenCounter,
|
|
138
158
|
tools,
|
|
139
159
|
toolMap,
|
|
160
|
+
toolRegistry,
|
|
140
161
|
instructions,
|
|
141
162
|
additionalInstructions,
|
|
142
163
|
reasoningKey,
|
|
@@ -152,6 +173,7 @@ export class AgentContext {
|
|
|
152
173
|
tokenCounter?: t.TokenCounter;
|
|
153
174
|
tools?: t.GraphTools;
|
|
154
175
|
toolMap?: t.ToolMap;
|
|
176
|
+
toolRegistry?: t.LCToolRegistry;
|
|
155
177
|
instructions?: string;
|
|
156
178
|
additionalInstructions?: string;
|
|
157
179
|
reasoningKey?: 'reasoning_content' | 'reasoning';
|
|
@@ -167,6 +189,7 @@ export class AgentContext {
|
|
|
167
189
|
this.tokenCounter = tokenCounter;
|
|
168
190
|
this.tools = tools;
|
|
169
191
|
this.toolMap = toolMap;
|
|
192
|
+
this.toolRegistry = toolRegistry;
|
|
170
193
|
this.instructions = instructions;
|
|
171
194
|
this.additionalInstructions = additionalInstructions;
|
|
172
195
|
if (reasoningKey) {
|
|
@@ -320,4 +343,67 @@ export class AgentContext {
|
|
|
320
343
|
// Add tool tokens to existing instruction tokens (which may already include system message tokens)
|
|
321
344
|
this.instructionTokens += toolTokens;
|
|
322
345
|
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Gets a map of tools that allow programmatic (code_execution) calling.
|
|
349
|
+
* Filters toolMap based on toolRegistry's allowed_callers settings.
|
|
350
|
+
* @returns ToolMap containing only tools that allow code_execution
|
|
351
|
+
*/
|
|
352
|
+
getProgrammaticToolMap(): t.ToolMap {
|
|
353
|
+
const programmaticMap: t.ToolMap = new Map();
|
|
354
|
+
|
|
355
|
+
if (!this.toolMap) {
|
|
356
|
+
return programmaticMap;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
for (const [name, tool] of this.toolMap) {
|
|
360
|
+
const toolDef = this.toolRegistry?.get(name);
|
|
361
|
+
if (toolAllowsCaller(toolDef, 'code_execution')) {
|
|
362
|
+
programmaticMap.set(name, tool);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return programmaticMap;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Gets tool definitions for tools that allow programmatic calling.
|
|
371
|
+
* Used to send to the Code API for stub generation.
|
|
372
|
+
* @returns Array of LCTool definitions for programmatic tools
|
|
373
|
+
*/
|
|
374
|
+
getProgrammaticToolDefs(): t.LCTool[] {
|
|
375
|
+
if (!this.toolRegistry) {
|
|
376
|
+
return [];
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const defs: t.LCTool[] = [];
|
|
380
|
+
for (const [_name, toolDef] of this.toolRegistry) {
|
|
381
|
+
if (toolAllowsCaller(toolDef, 'code_execution')) {
|
|
382
|
+
defs.push(toolDef);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return defs;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Gets the tool registry for deferred tools (for tool search).
|
|
391
|
+
* @param onlyDeferred If true, only returns tools with defer_loading=true
|
|
392
|
+
* @returns LCToolRegistry with tool definitions
|
|
393
|
+
*/
|
|
394
|
+
getDeferredToolRegistry(onlyDeferred: boolean = true): t.LCToolRegistry {
|
|
395
|
+
const registry: t.LCToolRegistry = new Map();
|
|
396
|
+
|
|
397
|
+
if (!this.toolRegistry) {
|
|
398
|
+
return registry;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
for (const [name, toolDef] of this.toolRegistry) {
|
|
402
|
+
if (!onlyDeferred || toolDef.defer_loading === true) {
|
|
403
|
+
registry.set(name, toolDef);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return registry;
|
|
408
|
+
}
|
|
323
409
|
}
|
package/src/common/enum.ts
CHANGED
|
@@ -159,6 +159,8 @@ export enum Callback {
|
|
|
159
159
|
export enum Constants {
|
|
160
160
|
OFFICIAL_CODE_BASEURL = 'https://api.librechat.ai/v1',
|
|
161
161
|
EXECUTE_CODE = 'execute_code',
|
|
162
|
+
TOOL_SEARCH_REGEX = 'tool_search_regex',
|
|
163
|
+
PROGRAMMATIC_TOOL_CALLING = 'programmatic_code_execution',
|
|
162
164
|
WEB_SEARCH = 'web_search',
|
|
163
165
|
CONTENT_AND_ARTIFACT = 'content_and_artifact',
|
|
164
166
|
LC_TRANSFER_TO_ = 'lc_transfer_to_',
|
package/src/events.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { MultiAgentGraph, StandardGraph } from '@/graphs';
|
|
|
9
9
|
import type { Logger } from 'winston';
|
|
10
10
|
import type * as t from '@/types';
|
|
11
11
|
import { handleToolCalls } from '@/tools/handlers';
|
|
12
|
-
import { Providers } from '@/common';
|
|
12
|
+
import { Constants, Providers } from '@/common';
|
|
13
13
|
|
|
14
14
|
export class HandlerRegistry {
|
|
15
15
|
private handlers: Map<string, t.EventHandler> = new Map();
|
|
@@ -112,6 +112,10 @@ export class ToolEndHandler implements t.EventHandler {
|
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
if (metadata[Constants.PROGRAMMATIC_TOOL_CALLING] === true) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
115
119
|
if (this.callback) {
|
|
116
120
|
await this.callback(toolEndData, metadata);
|
|
117
121
|
}
|
package/src/graphs/Graph.ts
CHANGED
|
@@ -443,9 +443,11 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
443
443
|
initializeTools({
|
|
444
444
|
currentTools,
|
|
445
445
|
currentToolMap,
|
|
446
|
+
agentContext,
|
|
446
447
|
}: {
|
|
447
448
|
currentTools?: t.GraphTools;
|
|
448
449
|
currentToolMap?: t.ToolMap;
|
|
450
|
+
agentContext?: AgentContext;
|
|
449
451
|
}): CustomToolNode<t.BaseGraphState> | ToolNode<t.BaseGraphState> {
|
|
450
452
|
return new CustomToolNode<t.BaseGraphState>({
|
|
451
453
|
tools: (currentTools as t.GenericTool[] | undefined) ?? [],
|
|
@@ -453,6 +455,9 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
453
455
|
toolCallStepIds: this.toolCallStepIds,
|
|
454
456
|
errorHandler: (data, metadata) =>
|
|
455
457
|
StandardGraph.handleToolCallErrorStatic(this, data, metadata),
|
|
458
|
+
toolRegistry: agentContext?.toolRegistry,
|
|
459
|
+
programmaticToolMap: agentContext?.getProgrammaticToolMap(),
|
|
460
|
+
programmaticToolDefs: agentContext?.getProgrammaticToolDefs(),
|
|
456
461
|
});
|
|
457
462
|
}
|
|
458
463
|
|
|
@@ -879,6 +884,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
879
884
|
this.initializeTools({
|
|
880
885
|
currentTools: agentContext.tools,
|
|
881
886
|
currentToolMap: agentContext.toolMap,
|
|
887
|
+
agentContext,
|
|
882
888
|
})
|
|
883
889
|
)
|
|
884
890
|
.addEdge(START, agentNode)
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,8 @@ export * from './graphs';
|
|
|
11
11
|
/* Tools */
|
|
12
12
|
export * from './tools/Calculator';
|
|
13
13
|
export * from './tools/CodeExecutor';
|
|
14
|
+
export * from './tools/ProgrammaticToolCalling';
|
|
15
|
+
export * from './tools/ToolSearchRegex';
|
|
14
16
|
export * from './tools/handlers';
|
|
15
17
|
export * from './tools/search';
|
|
16
18
|
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
// src/scripts/code_exec_ptc.ts
|
|
2
|
+
/**
|
|
3
|
+
* Live LLM test for Programmatic Tool Calling (PTC).
|
|
4
|
+
* Run with: npm run code_exec_ptc
|
|
5
|
+
*
|
|
6
|
+
* Tests PTC with a real LLM in the loop, demonstrating:
|
|
7
|
+
* 1. LLM decides when to use PTC
|
|
8
|
+
* 2. LLM writes Python code that calls tools programmatically
|
|
9
|
+
* 3. ToolNode automatically injects programmatic tools
|
|
10
|
+
* 4. Tools filtered by allowed_callers
|
|
11
|
+
*/
|
|
12
|
+
import { config } from 'dotenv';
|
|
13
|
+
config();
|
|
14
|
+
|
|
15
|
+
import { randomUUID } from 'crypto';
|
|
16
|
+
import { HumanMessage, BaseMessage } from '@langchain/core/messages';
|
|
17
|
+
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
18
|
+
import type * as t from '@/types';
|
|
19
|
+
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
20
|
+
import {
|
|
21
|
+
ToolEndHandler,
|
|
22
|
+
ModelEndHandler,
|
|
23
|
+
createMetadataAggregator,
|
|
24
|
+
} from '@/events';
|
|
25
|
+
import { getLLMConfig } from '@/utils/llmConfig';
|
|
26
|
+
import { getArgs } from '@/scripts/args';
|
|
27
|
+
import { GraphEvents } from '@/common';
|
|
28
|
+
import { Run } from '@/run';
|
|
29
|
+
import { createCodeExecutionTool } from '@/tools/CodeExecutor';
|
|
30
|
+
import { createProgrammaticToolCallingTool } from '@/tools/ProgrammaticToolCalling';
|
|
31
|
+
import {
|
|
32
|
+
createGetTeamMembersTool,
|
|
33
|
+
createGetExpensesTool,
|
|
34
|
+
createGetWeatherTool,
|
|
35
|
+
createProgrammaticToolRegistry,
|
|
36
|
+
} from '@/test/mockTools';
|
|
37
|
+
|
|
38
|
+
const conversationHistory: BaseMessage[] = [];
|
|
39
|
+
|
|
40
|
+
async function testProgrammaticToolCalling(): Promise<void> {
|
|
41
|
+
const { userName, location, provider, currentDate } = await getArgs();
|
|
42
|
+
const { contentParts, aggregateContent } = createContentAggregator();
|
|
43
|
+
|
|
44
|
+
const customHandlers = {
|
|
45
|
+
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
46
|
+
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
|
|
47
|
+
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
48
|
+
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
49
|
+
handle: (
|
|
50
|
+
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
51
|
+
data: t.StreamEventData
|
|
52
|
+
): void => {
|
|
53
|
+
console.log('====== ON_RUN_STEP_COMPLETED ======');
|
|
54
|
+
console.dir(data, { depth: null });
|
|
55
|
+
aggregateContent({
|
|
56
|
+
event,
|
|
57
|
+
data: data as unknown as { result: t.ToolEndEvent },
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
[GraphEvents.ON_RUN_STEP]: {
|
|
62
|
+
handle: (
|
|
63
|
+
event: GraphEvents.ON_RUN_STEP,
|
|
64
|
+
data: t.StreamEventData
|
|
65
|
+
): void => {
|
|
66
|
+
console.log('====== ON_RUN_STEP ======');
|
|
67
|
+
console.dir(data, { depth: null });
|
|
68
|
+
aggregateContent({ event, data: data as t.RunStep });
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
[GraphEvents.ON_RUN_STEP_DELTA]: {
|
|
72
|
+
handle: (
|
|
73
|
+
event: GraphEvents.ON_RUN_STEP_DELTA,
|
|
74
|
+
data: t.StreamEventData
|
|
75
|
+
): void => {
|
|
76
|
+
aggregateContent({ event, data: data as t.RunStepDeltaEvent });
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
[GraphEvents.ON_MESSAGE_DELTA]: {
|
|
80
|
+
handle: (
|
|
81
|
+
event: GraphEvents.ON_MESSAGE_DELTA,
|
|
82
|
+
data: t.StreamEventData
|
|
83
|
+
): void => {
|
|
84
|
+
aggregateContent({ event, data: data as t.MessageDeltaEvent });
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
[GraphEvents.TOOL_START]: {
|
|
88
|
+
handle: (
|
|
89
|
+
_event: string,
|
|
90
|
+
data: t.StreamEventData,
|
|
91
|
+
metadata?: Record<string, unknown>
|
|
92
|
+
): void => {
|
|
93
|
+
console.log('====== TOOL_START ======');
|
|
94
|
+
console.dir(data, { depth: null });
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const llmConfig = getLLMConfig(provider);
|
|
100
|
+
|
|
101
|
+
// Create mock tool instances
|
|
102
|
+
const teamTool = createGetTeamMembersTool();
|
|
103
|
+
const expensesTool = createGetExpensesTool();
|
|
104
|
+
const weatherTool = createGetWeatherTool();
|
|
105
|
+
|
|
106
|
+
// Create special tools
|
|
107
|
+
const codeExecTool = createCodeExecutionTool();
|
|
108
|
+
const ptcTool = createProgrammaticToolCallingTool();
|
|
109
|
+
|
|
110
|
+
// Build complete tool list and map
|
|
111
|
+
const allTools = [teamTool, expensesTool, weatherTool, codeExecTool, ptcTool];
|
|
112
|
+
const toolMap = new Map(allTools.map((t) => [t.name, t]));
|
|
113
|
+
|
|
114
|
+
// Create tool registry with allowed_callers configuration
|
|
115
|
+
// Only includes business logic tools (not special tools)
|
|
116
|
+
// Special tools (execute_code, PTC) are always bound directly to LLM
|
|
117
|
+
const toolRegistry = createProgrammaticToolRegistry();
|
|
118
|
+
|
|
119
|
+
console.log('\n' + '='.repeat(70));
|
|
120
|
+
console.log('Tool Configuration Summary:');
|
|
121
|
+
console.log('='.repeat(70));
|
|
122
|
+
console.log('Total tools:', allTools.length);
|
|
123
|
+
console.log(
|
|
124
|
+
'Programmatic-allowed:',
|
|
125
|
+
Array.from(toolRegistry.values())
|
|
126
|
+
.filter((t) => t.allowed_callers?.includes('code_execution'))
|
|
127
|
+
.map((t) => t.name)
|
|
128
|
+
.join(', ')
|
|
129
|
+
);
|
|
130
|
+
console.log(
|
|
131
|
+
'Direct-callable:',
|
|
132
|
+
Array.from(toolRegistry.values())
|
|
133
|
+
.filter((t) => !t.allowed_callers || t.allowed_callers.includes('direct'))
|
|
134
|
+
.map((t) => t.name)
|
|
135
|
+
.join(', ')
|
|
136
|
+
);
|
|
137
|
+
console.log('='.repeat(70) + '\n');
|
|
138
|
+
|
|
139
|
+
const run = await Run.create<t.IState>({
|
|
140
|
+
runId: randomUUID(),
|
|
141
|
+
graphConfig: {
|
|
142
|
+
type: 'standard',
|
|
143
|
+
llmConfig,
|
|
144
|
+
agents: [
|
|
145
|
+
{
|
|
146
|
+
agentId: 'default',
|
|
147
|
+
provider: llmConfig.provider,
|
|
148
|
+
clientOptions: llmConfig,
|
|
149
|
+
tools: allTools,
|
|
150
|
+
toolMap,
|
|
151
|
+
toolRegistry,
|
|
152
|
+
instructions:
|
|
153
|
+
'You are a friendly AI assistant with advanced coding capabilities. ' +
|
|
154
|
+
'You have access to team and expense management tools, but ONLY through programmatic code execution. ' +
|
|
155
|
+
'When you need to analyze expenses or process team data, use the programmatic_code_execution tool ' +
|
|
156
|
+
'to write Python code that calls get_team_members(), get_expenses(), and get_weather() functions. ' +
|
|
157
|
+
'These functions are async - use await. Use asyncio.gather() for parallel execution.',
|
|
158
|
+
additional_instructions: `The user's name is ${userName} and they are located in ${location}. Today is ${currentDate}.`,
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
returnContent: true,
|
|
163
|
+
customHandlers,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const config: Partial<RunnableConfig> & {
|
|
167
|
+
version: 'v1' | 'v2';
|
|
168
|
+
run_id?: string;
|
|
169
|
+
streamMode: string;
|
|
170
|
+
} = {
|
|
171
|
+
configurable: {
|
|
172
|
+
provider,
|
|
173
|
+
thread_id: 'ptc-conversation-1',
|
|
174
|
+
},
|
|
175
|
+
streamMode: 'values',
|
|
176
|
+
version: 'v2' as const,
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
console.log('Test 1: Team Expense Analysis with PTC');
|
|
180
|
+
console.log('='.repeat(70) + '\n');
|
|
181
|
+
|
|
182
|
+
const userMessage1 = `Hi ${userName}! I need you to analyze our team's expenses. Please:
|
|
183
|
+
|
|
184
|
+
1. Get the list of all team members
|
|
185
|
+
2. For each member, fetch their expense records
|
|
186
|
+
3. Calculate the total expenses per member
|
|
187
|
+
4. Identify anyone who spent more than $500
|
|
188
|
+
5. Show me a summary report
|
|
189
|
+
|
|
190
|
+
IMPORTANT: Use the programmatic_code_execution tool to do this efficiently.
|
|
191
|
+
Don't call each tool separately - write Python code that orchestrates all the calls!`;
|
|
192
|
+
|
|
193
|
+
conversationHistory.push(new HumanMessage(userMessage1));
|
|
194
|
+
|
|
195
|
+
let inputs = {
|
|
196
|
+
messages: conversationHistory,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const finalContentParts1 = await run.processStream(inputs, config);
|
|
200
|
+
const finalMessages1 = run.getRunMessages();
|
|
201
|
+
if (finalMessages1) {
|
|
202
|
+
conversationHistory.push(...finalMessages1);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
console.log('\n\n====================\n\n');
|
|
206
|
+
console.log('Content Parts:');
|
|
207
|
+
console.dir(contentParts, { depth: null });
|
|
208
|
+
|
|
209
|
+
console.log('\n\n' + '='.repeat(70));
|
|
210
|
+
console.log('Test 2: Conditional Logic and Parallel Execution');
|
|
211
|
+
console.log('='.repeat(70) + '\n');
|
|
212
|
+
|
|
213
|
+
const userMessage2 = `Great job! Now let's test some advanced patterns. Please:
|
|
214
|
+
|
|
215
|
+
1. Check the weather in both San Francisco and New York (in parallel!)
|
|
216
|
+
2. Based on which city has better weather (warmer), fetch the team members
|
|
217
|
+
3. For the Engineering team members only, calculate their travel expenses
|
|
218
|
+
4. Show me the results
|
|
219
|
+
|
|
220
|
+
Again, use programmatic_code_execution for maximum efficiency. Use asyncio.gather()
|
|
221
|
+
to check both cities' weather at the same time!`;
|
|
222
|
+
|
|
223
|
+
conversationHistory.push(new HumanMessage(userMessage2));
|
|
224
|
+
|
|
225
|
+
inputs = {
|
|
226
|
+
messages: conversationHistory,
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const finalContentParts2 = await run.processStream(inputs, config);
|
|
230
|
+
const finalMessages2 = run.getRunMessages();
|
|
231
|
+
if (finalMessages2) {
|
|
232
|
+
conversationHistory.push(...finalMessages2);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
console.log('\n\n====================\n\n');
|
|
236
|
+
console.log('Final Content Parts:');
|
|
237
|
+
console.dir(finalContentParts2, { depth: null });
|
|
238
|
+
|
|
239
|
+
console.log('\n\n' + '='.repeat(70));
|
|
240
|
+
console.log('Generating conversation title...');
|
|
241
|
+
console.log('='.repeat(70) + '\n');
|
|
242
|
+
|
|
243
|
+
const { handleLLMEnd, collected } = createMetadataAggregator();
|
|
244
|
+
const titleResult = await run.generateTitle({
|
|
245
|
+
provider,
|
|
246
|
+
inputText: userMessage1,
|
|
247
|
+
contentParts,
|
|
248
|
+
chainOptions: {
|
|
249
|
+
callbacks: [
|
|
250
|
+
{
|
|
251
|
+
handleLLMEnd,
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
console.log('Generated Title:', titleResult);
|
|
258
|
+
console.log('Collected metadata:', collected);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
262
|
+
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
263
|
+
console.log('Conversation history:');
|
|
264
|
+
console.dir(conversationHistory, { depth: null });
|
|
265
|
+
process.exit(1);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
process.on('uncaughtException', (err) => {
|
|
269
|
+
console.error('Uncaught Exception:', err);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
testProgrammaticToolCalling().catch((err) => {
|
|
273
|
+
console.error(err);
|
|
274
|
+
console.log('Conversation history:');
|
|
275
|
+
console.dir(conversationHistory, { depth: null });
|
|
276
|
+
process.exit(1);
|
|
277
|
+
});
|