@librechat/agents 3.0.0-rc7 → 3.0.0-rc9

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 (48) hide show
  1. package/dist/cjs/graphs/Graph.cjs +0 -1
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/graphs/MultiAgentGraph.cjs +103 -19
  4. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  5. package/dist/esm/graphs/Graph.mjs +0 -1
  6. package/dist/esm/graphs/Graph.mjs.map +1 -1
  7. package/dist/esm/graphs/MultiAgentGraph.mjs +103 -19
  8. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  9. package/dist/types/graphs/MultiAgentGraph.d.ts +11 -1
  10. package/package.json +5 -1
  11. package/src/graphs/Graph.ts +0 -1
  12. package/src/graphs/MultiAgentGraph.ts +120 -21
  13. package/src/scripts/multi-agent-chain.ts +278 -0
  14. package/src/scripts/multi-agent-document-review-chain.ts +197 -0
  15. package/src/scripts/multi-agent-hybrid-flow.ts +310 -0
  16. package/src/scripts/test-tools-before-handoff.ts +233 -0
  17. package/dist/types/scripts/abort.d.ts +0 -1
  18. package/dist/types/scripts/ant_web_search.d.ts +0 -1
  19. package/dist/types/scripts/args.d.ts +0 -7
  20. package/dist/types/scripts/caching.d.ts +0 -1
  21. package/dist/types/scripts/cli.d.ts +0 -1
  22. package/dist/types/scripts/cli2.d.ts +0 -1
  23. package/dist/types/scripts/cli3.d.ts +0 -1
  24. package/dist/types/scripts/cli4.d.ts +0 -1
  25. package/dist/types/scripts/cli5.d.ts +0 -1
  26. package/dist/types/scripts/code_exec.d.ts +0 -1
  27. package/dist/types/scripts/code_exec_files.d.ts +0 -1
  28. package/dist/types/scripts/code_exec_simple.d.ts +0 -1
  29. package/dist/types/scripts/content.d.ts +0 -1
  30. package/dist/types/scripts/empty_input.d.ts +0 -1
  31. package/dist/types/scripts/handoff-test.d.ts +0 -1
  32. package/dist/types/scripts/image.d.ts +0 -1
  33. package/dist/types/scripts/memory.d.ts +0 -1
  34. package/dist/types/scripts/multi-agent-conditional.d.ts +0 -1
  35. package/dist/types/scripts/multi-agent-parallel.d.ts +0 -1
  36. package/dist/types/scripts/multi-agent-sequence.d.ts +0 -1
  37. package/dist/types/scripts/multi-agent-supervisor.d.ts +0 -1
  38. package/dist/types/scripts/multi-agent-test.d.ts +0 -1
  39. package/dist/types/scripts/search.d.ts +0 -1
  40. package/dist/types/scripts/simple.d.ts +0 -1
  41. package/dist/types/scripts/stream.d.ts +0 -1
  42. package/dist/types/scripts/test-custom-prompt-key.d.ts +0 -2
  43. package/dist/types/scripts/test-handoff-input.d.ts +0 -1
  44. package/dist/types/scripts/test-multi-agent-list-handoff.d.ts +0 -2
  45. package/dist/types/scripts/thinking.d.ts +0 -1
  46. package/dist/types/scripts/tools.d.ts +0 -1
  47. package/dist/types/specs/spec.utils.d.ts +0 -1
  48. package/src/scripts/multi-agent-example-output.md +0 -110
@@ -0,0 +1,233 @@
1
+ import { config } from 'dotenv';
2
+ config();
3
+
4
+ import { TavilySearch } from '@langchain/tavily';
5
+ import { HumanMessage, BaseMessage } from '@langchain/core/messages';
6
+ import { Run } from '@/run';
7
+ import { Providers, GraphEvents } from '@/common';
8
+ import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
9
+ import { ToolEndHandler, ModelEndHandler } from '@/events';
10
+ import type * as t from '@/types';
11
+
12
+ const conversationHistory: BaseMessage[] = [];
13
+
14
+ /**
15
+ * Test edge case: Agent performs 2 web searches before handing off
16
+ *
17
+ * This tests how the system behaves when an agent with handoff capabilities
18
+ * uses tools before transferring control to another agent.
19
+ */
20
+ async function testToolsBeforeHandoff() {
21
+ console.log('Testing Tools Before Handoff Edge Case...\n');
22
+
23
+ // Set up content aggregator
24
+ const { contentParts, aggregateContent } = createContentAggregator();
25
+
26
+ // Track tool calls and handoffs
27
+ let toolCallCount = 0;
28
+ let handoffOccurred = false;
29
+
30
+ // Create custom handlers
31
+ const customHandlers = {
32
+ [GraphEvents.TOOL_END]: new ToolEndHandler(undefined, (name?: string) => {
33
+ console.log(`\n✅ Tool completed: ${name}`);
34
+ return true;
35
+ }),
36
+ [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
37
+ [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
38
+ [GraphEvents.ON_RUN_STEP]: {
39
+ handle: (
40
+ event: GraphEvents.ON_RUN_STEP,
41
+ data: t.StreamEventData
42
+ ): void => {
43
+ const runStepData = data as any;
44
+ if (runStepData?.name) {
45
+ console.log(`\n[${runStepData.name}] Processing...`);
46
+ }
47
+ aggregateContent({ event, data: data as t.RunStep });
48
+ },
49
+ },
50
+ [GraphEvents.ON_RUN_STEP_COMPLETED]: {
51
+ handle: (
52
+ event: GraphEvents.ON_RUN_STEP_COMPLETED,
53
+ data: t.StreamEventData
54
+ ): void => {
55
+ aggregateContent({
56
+ event,
57
+ data: data as unknown as { result: t.ToolEndEvent },
58
+ });
59
+ },
60
+ },
61
+ [GraphEvents.ON_MESSAGE_DELTA]: {
62
+ handle: (
63
+ event: GraphEvents.ON_MESSAGE_DELTA,
64
+ data: t.StreamEventData
65
+ ): void => {
66
+ // console.log('====== ON_MESSAGE_DELTA ======');
67
+ console.dir(data, { depth: null });
68
+ aggregateContent({ event, data: data as t.MessageDeltaEvent });
69
+ },
70
+ },
71
+ [GraphEvents.TOOL_START]: {
72
+ handle: (
73
+ _event: string,
74
+ data: t.StreamEventData,
75
+ metadata?: Record<string, unknown>
76
+ ): void => {
77
+ const toolData = data as any;
78
+ console.log(`\n🔧 Tool started:`);
79
+ console.dir({ toolData, metadata }, { depth: null });
80
+
81
+ if (toolData?.output?.name === 'tavily_search_results_json') {
82
+ toolCallCount++;
83
+ console.log(`📊 Search #${toolCallCount} initiated`);
84
+ } else if (toolData?.output?.name?.includes('transfer_to_')) {
85
+ handoffOccurred = true;
86
+ const specialist = toolData.name.replace('transfer_to_', '');
87
+ console.log(`\n🔀 Handoff initiated to: ${specialist}`);
88
+ }
89
+ },
90
+ },
91
+ };
92
+
93
+ // Create the graph with research agent and report writer
94
+ function createGraphWithToolsAndHandoff(): t.RunConfig {
95
+ const agents: t.AgentInputs[] = [
96
+ {
97
+ agentId: 'research_coordinator',
98
+ provider: Providers.OPENAI,
99
+ clientOptions: {
100
+ modelName: 'gpt-4.1-mini',
101
+ apiKey: process.env.OPENAI_API_KEY,
102
+ },
103
+ tools: [new TavilySearch({ maxResults: 3 })],
104
+ instructions: `You are a Research Coordinator with access to web search and a report writer specialist.
105
+
106
+ Your workflow MUST follow these steps IN ORDER:
107
+ 1. FIRST: Write an initial response acknowledging the request and outlining your research plan
108
+ - Explain what aspects you'll investigate
109
+ - Describe your search strategy
110
+ 2. SECOND: Conduct exactly 2 web searches to gather comprehensive information
111
+ - Search 1: Get general information about the topic
112
+ - Search 2: Get specific details, recent updates, or complementary data
113
+ - Note: Even if your searches are unsuccessful, you MUST still proceed to handoff after EXACTLY 2 searches
114
+ 3. FINALLY: After completing both searches, transfer to the report writer
115
+ - Provide the report writer with a summary of your findings
116
+
117
+ CRITICAL: You MUST write your initial response before ANY tool use. Then complete both searches before handoff.`,
118
+ maxContextTokens: 8000,
119
+ },
120
+ {
121
+ agentId: 'report_writer',
122
+ provider: Providers.OPENAI,
123
+ clientOptions: {
124
+ modelName: 'gpt-5-mini',
125
+ apiKey: process.env.OPENAI_API_KEY,
126
+ },
127
+ instructions: `You are a Report Writer specialist. Your role is to:
128
+ 1. Receive research findings from the Research Coordinator
129
+ 2. Create a well-structured, comprehensive report
130
+ 3. Include all key findings from the research
131
+ 4. Format the report with clear sections and bullet points
132
+ 5. Add a brief executive summary at the beginning
133
+
134
+ Focus on clarity, completeness, and professional presentation.`,
135
+ maxContextTokens: 8000,
136
+ },
137
+ ];
138
+
139
+ // Create edge from research coordinator to report writer
140
+ const edges: t.GraphEdge[] = [
141
+ {
142
+ from: 'research_coordinator',
143
+ to: 'report_writer',
144
+ description: 'Transfer to report writer after completing research',
145
+ edgeType: 'handoff',
146
+ },
147
+ ];
148
+
149
+ return {
150
+ runId: `tools-before-handoff-${Date.now()}`,
151
+ graphConfig: {
152
+ type: 'multi-agent',
153
+ agents,
154
+ edges,
155
+ },
156
+ customHandlers,
157
+ returnContent: true,
158
+ };
159
+ }
160
+
161
+ try {
162
+ // Single test query that requires research before report writing
163
+ const query = `Research the latest developments in quantum computing from 2025,
164
+ including major breakthroughs and commercial applications.
165
+ I need a comprehensive report with recent findings.`;
166
+
167
+ console.log('='.repeat(60));
168
+ console.log(`USER QUERY: "${query}"`);
169
+ console.log('='.repeat(60));
170
+
171
+ // Create the graph
172
+ const runConfig = createGraphWithToolsAndHandoff();
173
+ const run = await Run.create(runConfig);
174
+
175
+ console.log('\nExpected behavior:');
176
+ console.log('1. Research Coordinator writes initial response/plan');
177
+ console.log('2. Research Coordinator performs 2 web searches');
178
+ console.log('3. Research Coordinator hands off to Report Writer');
179
+ console.log('4. Report Writer creates final report\n');
180
+
181
+ // Process with streaming
182
+ conversationHistory.push(new HumanMessage(query));
183
+ const inputs = {
184
+ messages: conversationHistory,
185
+ };
186
+
187
+ const config = {
188
+ configurable: {
189
+ thread_id: 'tools-handoff-test-1',
190
+ },
191
+ streamMode: 'values',
192
+ version: 'v2' as const,
193
+ };
194
+
195
+ const finalContentParts = await run.processStream(inputs, config);
196
+ const finalMessages = run.getRunMessages();
197
+
198
+ if (finalMessages) {
199
+ conversationHistory.push(...finalMessages);
200
+ }
201
+
202
+ // Show results summary
203
+ console.log(`\n${'─'.repeat(60)}`);
204
+ console.log('EDGE CASE TEST RESULTS:');
205
+ console.log('─'.repeat(60));
206
+ console.log(`Tool calls before handoff: ${toolCallCount}`);
207
+ console.log(`Expected tool calls: 2`);
208
+ console.log(`Handoff occurred: ${handoffOccurred ? 'Yes ✅' : 'No ❌'}`);
209
+ console.log(
210
+ `Test status: ${toolCallCount === 2 && handoffOccurred ? 'PASSED ✅' : 'FAILED ❌'}`
211
+ );
212
+ console.log('─'.repeat(60));
213
+
214
+ // Display conversation history
215
+ console.log('\nConversation History:');
216
+ console.log('─'.repeat(60));
217
+ conversationHistory.forEach((msg, idx) => {
218
+ const role = msg.constructor.name.replace('Message', '');
219
+ console.log(`\n[${idx}] ${role}:`);
220
+ if (typeof msg.content === 'string') {
221
+ console.log(
222
+ msg.content.substring(0, 200) +
223
+ (msg.content.length > 200 ? '...' : '')
224
+ );
225
+ }
226
+ });
227
+ } catch (error) {
228
+ console.error('Error in tools-before-handoff test:', error);
229
+ }
230
+ }
231
+
232
+ // Run the test
233
+ testToolsBeforeHandoff();
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,7 +0,0 @@
1
- import { Providers } from '@/common';
2
- export declare function getArgs(): Promise<{
3
- userName: string;
4
- location: string;
5
- provider: Providers;
6
- currentDate: string;
7
- }>;
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env bun
2
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env bun
2
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export declare function capitalizeFirstLetter(string: string): string;
@@ -1,110 +0,0 @@
1
- # Multi-Agent Test Scripts - Example Output
2
-
3
- ## multi-agent-test.ts
4
-
5
- ```
6
- Testing Multi-Agent Handoff System...
7
-
8
- Invoking multi-agent graph...
9
-
10
- ====== ON_RUN_STEP ======
11
- { name: 'flight_assistant', type: 'agent', ... }
12
- [flight_assistant] Starting...
13
-
14
- ====== CHAT_MODEL_STREAM ======
15
- I'll help you book a flight from Boston to New York...
16
-
17
- ====== TOOL_START ======
18
- { name: 'transfer_to_hotel_assistant', ... }
19
-
20
- ====== ON_RUN_STEP_COMPLETED ======
21
- [flight_assistant] Completed
22
-
23
- ====== ON_RUN_STEP ======
24
- { name: 'hotel_assistant', type: 'agent', ... }
25
- [hotel_assistant] Starting...
26
-
27
- ====== CHAT_MODEL_STREAM ======
28
- Great! I'll help you find a hotel near Times Square...
29
-
30
- Final content parts:
31
- [
32
- { type: 'text', text: "I'll help you book a flight..." },
33
- { type: 'tool_use', name: 'transfer_to_hotel_assistant', ... },
34
- { type: 'text', text: "Great! I'll help you find a hotel..." }
35
- ]
36
- ```
37
-
38
- ## multi-agent-parallel.ts
39
-
40
- ```
41
- Testing Parallel Multi-Agent System (Fan-in/Fan-out)...
42
-
43
- Invoking parallel multi-agent graph...
44
-
45
- ====== ON_RUN_STEP ======
46
- [researcher] Starting analysis...
47
-
48
- ====== ON_RUN_STEP ======
49
- [analyst1] Starting analysis...
50
- [analyst2] Starting analysis...
51
- [analyst3] Starting analysis...
52
-
53
- ====== CHAT_MODEL_STREAM ======
54
- [analyst1] From a financial perspective...
55
- [analyst2] From a technical perspective...
56
- [analyst3] From a market perspective...
57
-
58
- ====== ON_RUN_STEP_COMPLETED ======
59
- [analyst1] Completed analysis
60
- [analyst2] Completed analysis
61
- [analyst3] Completed analysis
62
-
63
- ====== ON_RUN_STEP ======
64
- [summarizer] Starting analysis...
65
-
66
- Final content parts: 5 parts
67
- ```
68
-
69
- ## multi-agent-conditional.ts
70
-
71
- ```
72
- Testing Conditional Multi-Agent System...
73
-
74
- --- Processing: "How do I implement a binary search tree in Python?" ---
75
-
76
- ====== ON_RUN_STEP ======
77
- { name: 'classifier', type: 'agent', ... }
78
-
79
- ====== ON_RUN_STEP ======
80
- { name: 'technical_expert', type: 'agent', ... }
81
- Routing to: technical_expert
82
-
83
- ====== CHAT_MODEL_STREAM ======
84
- To implement a binary search tree in Python, you'll need to create a Node class...
85
-
86
- Expert used: technical_expert
87
- Content parts: 2
88
- ---
89
-
90
- --- Processing: "What are the key strategies for market expansion?" ---
91
-
92
- Routing to: business_expert
93
- ...
94
-
95
- --- Processing: "What is the capital of France?" ---
96
-
97
- Routing to: general_assistant
98
- ...
99
- ```
100
-
101
- ## Key Features of Updated Scripts
102
-
103
- 1. **Proper Event Handling**: All GraphEvents are properly handled with custom handlers
104
- 2. **Content Aggregation**: Using `createContentAggregator()` to collect all content parts
105
- 3. **Stream Output**: Real-time token streaming via `ChatModelStreamHandler`
106
- 4. **Debug Logging**: Comprehensive event logging for debugging multi-agent flows
107
- 5. **Conversation History**: Proper tracking of messages across agent interactions
108
- 6. **Return Content**: `returnContent: true` ensures content parts are returned
109
-
110
- The scripts now follow the same patterns as `simple.ts` and `tools.ts`, providing consistent behavior and comprehensive event handling across all multi-agent scenarios.