@librechat/agents 3.0.18 ā 3.0.19
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/graphs/Graph.cjs +6 -4
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/main.cjs +1 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +179 -6
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +6 -4
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/main.mjs +1 -1
- package/dist/esm/messages/format.mjs +179 -7
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/types/messages/format.d.ts +14 -0
- package/package.json +2 -1
- package/src/graphs/Graph.ts +8 -4
- package/src/messages/format.ts +231 -6
- package/src/messages/labelContentByAgent.test.ts +887 -0
- package/src/scripts/test-multi-agent-list-handoff.ts +116 -10
- package/src/scripts/test-parallel-agent-labeling.ts +325 -0
|
@@ -4,11 +4,12 @@ import { config } from 'dotenv';
|
|
|
4
4
|
config();
|
|
5
5
|
|
|
6
6
|
import { HumanMessage, BaseMessage } from '@langchain/core/messages';
|
|
7
|
-
import
|
|
7
|
+
import type * as t from '@/types';
|
|
8
|
+
import { labelContentByAgent, formatAgentMessages } from '@/messages/format';
|
|
8
9
|
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
9
10
|
import { Providers, GraphEvents, Constants, StepTypes } from '@/common';
|
|
10
11
|
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
11
|
-
import
|
|
12
|
+
import { Run } from '@/run';
|
|
12
13
|
|
|
13
14
|
const conversationHistory: BaseMessage[] = [];
|
|
14
15
|
|
|
@@ -188,10 +189,6 @@ async function testSupervisorListHandoff() {
|
|
|
188
189
|
try {
|
|
189
190
|
// Test with different queries
|
|
190
191
|
const testQueries = [
|
|
191
|
-
// 'How can we analyze user engagement metrics to improve our product?',
|
|
192
|
-
// 'What security measures should we implement for our new API?',
|
|
193
|
-
// 'Can you help design a better onboarding flow for our mobile app?',
|
|
194
|
-
// 'We need to set up a CI/CD pipeline for our microservices.',
|
|
195
192
|
'What are the legal implications of using GPL-licensed code in our product?',
|
|
196
193
|
];
|
|
197
194
|
|
|
@@ -204,9 +201,9 @@ async function testSupervisorListHandoff() {
|
|
|
204
201
|
};
|
|
205
202
|
|
|
206
203
|
for (const query of testQueries) {
|
|
207
|
-
console.log(`\n${'='.repeat(
|
|
208
|
-
console.log(`USER QUERY: "${query}"`);
|
|
209
|
-
console.log('='.repeat(
|
|
204
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
205
|
+
console.log(`FIRST RUN - USER QUERY: "${query}"`);
|
|
206
|
+
console.log('='.repeat(80));
|
|
210
207
|
|
|
211
208
|
// Reset conversation
|
|
212
209
|
conversationHistory.length = 0;
|
|
@@ -216,7 +213,7 @@ async function testSupervisorListHandoff() {
|
|
|
216
213
|
const runConfig = createSupervisorGraphWithListEdge();
|
|
217
214
|
const run = await Run.create(runConfig);
|
|
218
215
|
|
|
219
|
-
console.log('Processing request...');
|
|
216
|
+
console.log('Processing first request...');
|
|
220
217
|
|
|
221
218
|
// Process with streaming
|
|
222
219
|
const inputs = {
|
|
@@ -292,6 +289,115 @@ async function testSupervisorListHandoff() {
|
|
|
292
289
|
`- Result: Supervisor has 5 handoff tools from a single edge`
|
|
293
290
|
);
|
|
294
291
|
console.log('ā'.repeat(60));
|
|
292
|
+
|
|
293
|
+
// =============================================================
|
|
294
|
+
// SECOND RUN: Demonstrate agent-labeled history
|
|
295
|
+
// =============================================================
|
|
296
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
297
|
+
console.log(`SECOND RUN - Simulating DB Load with Agent-Labeled History`);
|
|
298
|
+
console.log('='.repeat(80));
|
|
299
|
+
|
|
300
|
+
// Simulate what happens in the main app:
|
|
301
|
+
// 1. Store contentParts + agentIdMap to "DB" (in-memory here)
|
|
302
|
+
const dbStoredContentParts = [...contentParts];
|
|
303
|
+
const dbStoredAgentIdMap = Object.fromEntries(
|
|
304
|
+
run.Graph!.getContentPartAgentMap()
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
console.log('\nš¦ Simulating DB storage:');
|
|
308
|
+
console.log(` - Stored ${dbStoredContentParts.length} content parts`);
|
|
309
|
+
console.log(
|
|
310
|
+
` - Stored agent mappings for ${Object.keys(dbStoredAgentIdMap).length} parts`
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
// 2. On next run, load from "DB" and label by agent
|
|
314
|
+
console.log('\nš„ Loading from DB and labeling by agent...');
|
|
315
|
+
|
|
316
|
+
const agentNames = {
|
|
317
|
+
supervisor: 'Supervisor',
|
|
318
|
+
legal_advisor: 'Legal Advisor',
|
|
319
|
+
data_analyst: 'Data Analyst',
|
|
320
|
+
security_expert: 'Security Expert',
|
|
321
|
+
product_designer: 'Product Designer',
|
|
322
|
+
devops_engineer: 'DevOps Engineer',
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const labeledContentParts = labelContentByAgent(
|
|
326
|
+
dbStoredContentParts.filter(
|
|
327
|
+
(p): p is t.MessageContentComplex => p != null
|
|
328
|
+
),
|
|
329
|
+
dbStoredAgentIdMap,
|
|
330
|
+
agentNames
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
console.log(
|
|
334
|
+
` - Labeled ${labeledContentParts.length} content parts by agent`
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
// 3. Convert labeled content parts to payload format
|
|
338
|
+
const payload: t.TPayload = [
|
|
339
|
+
{
|
|
340
|
+
role: 'user',
|
|
341
|
+
content: query,
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
role: 'assistant',
|
|
345
|
+
content: labeledContentParts,
|
|
346
|
+
},
|
|
347
|
+
];
|
|
348
|
+
|
|
349
|
+
// 4. Format using formatAgentMessages (simulates what main app does)
|
|
350
|
+
console.log('\nš§ Calling formatAgentMessages...');
|
|
351
|
+
const { messages: formattedMessages } = formatAgentMessages(payload);
|
|
352
|
+
|
|
353
|
+
console.log(
|
|
354
|
+
` - Formatted into ${formattedMessages.length} BaseMessages`
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
// Show a preview of what the supervisor will see
|
|
358
|
+
console.log('\nšļø Preview of formatted history for supervisor:');
|
|
359
|
+
console.log('ā'.repeat(80));
|
|
360
|
+
for (let i = 0; i < formattedMessages.length; i++) {
|
|
361
|
+
const msg = formattedMessages[i];
|
|
362
|
+
const role = msg._getType();
|
|
363
|
+
const preview =
|
|
364
|
+
typeof msg.content === 'string'
|
|
365
|
+
? msg.content.slice(0, 200)
|
|
366
|
+
: JSON.stringify(msg.content).slice(0, 200);
|
|
367
|
+
console.log(
|
|
368
|
+
`[${i}] ${role}: ${preview}${preview.length >= 200 ? '...' : ''}`
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
console.log('ā'.repeat(80));
|
|
372
|
+
|
|
373
|
+
// 5. Create a new run with the formatted history + a followup question
|
|
374
|
+
console.log(
|
|
375
|
+
'\nš Starting second run with agent-labeled history + followup question...'
|
|
376
|
+
);
|
|
377
|
+
const followupQuery =
|
|
378
|
+
'Can you summarize the key legal points from your previous response?';
|
|
379
|
+
console.log(` Followup: "${followupQuery}"`);
|
|
380
|
+
|
|
381
|
+
// Reset for second run
|
|
382
|
+
const secondRunHistory: BaseMessage[] = [
|
|
383
|
+
...formattedMessages,
|
|
384
|
+
new HumanMessage(followupQuery),
|
|
385
|
+
];
|
|
386
|
+
|
|
387
|
+
const runConfig2 = createSupervisorGraphWithListEdge();
|
|
388
|
+
const run2 = await Run.create(runConfig2);
|
|
389
|
+
|
|
390
|
+
const inputs2 = {
|
|
391
|
+
messages: secondRunHistory,
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
await run2.processStream(inputs2, config);
|
|
395
|
+
|
|
396
|
+
console.log('\nā
Second run completed successfully!');
|
|
397
|
+
console.log(
|
|
398
|
+
' The supervisor correctly understood that the legal_advisor handled'
|
|
399
|
+
);
|
|
400
|
+
console.log(' the previous query, avoiding identity confusion.');
|
|
295
401
|
}
|
|
296
402
|
|
|
297
403
|
// Final summary
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { config } from 'dotenv';
|
|
4
|
+
config();
|
|
5
|
+
|
|
6
|
+
import { HumanMessage, BaseMessage } from '@langchain/core/messages';
|
|
7
|
+
import type * as t from '@/types';
|
|
8
|
+
import { labelContentByAgent, formatAgentMessages } from '@/messages/format';
|
|
9
|
+
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
10
|
+
import { Providers, GraphEvents, StepTypes } from '@/common';
|
|
11
|
+
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
12
|
+
import { Run } from '@/run';
|
|
13
|
+
|
|
14
|
+
const conversationHistory: BaseMessage[] = [];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Test parallel multi-agent system with agent labeling on subsequent runs
|
|
18
|
+
*
|
|
19
|
+
* Graph structure:
|
|
20
|
+
* START -> researcher
|
|
21
|
+
* researcher -> [analyst1, analyst2, analyst3] (fan-out)
|
|
22
|
+
* [analyst1, analyst2, analyst3] -> summarizer (fan-in)
|
|
23
|
+
* summarizer -> END
|
|
24
|
+
*/
|
|
25
|
+
async function testParallelWithAgentLabeling() {
|
|
26
|
+
console.log('Testing Parallel Multi-Agent with Agent Labeling...\n');
|
|
27
|
+
|
|
28
|
+
// Set up content aggregator
|
|
29
|
+
const { contentParts, aggregateContent } = createContentAggregator();
|
|
30
|
+
|
|
31
|
+
// Define specialized agents
|
|
32
|
+
const agents: t.AgentInputs[] = [
|
|
33
|
+
{
|
|
34
|
+
agentId: 'researcher',
|
|
35
|
+
provider: Providers.ANTHROPIC,
|
|
36
|
+
clientOptions: {
|
|
37
|
+
modelName: 'claude-haiku-4-5',
|
|
38
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
39
|
+
},
|
|
40
|
+
instructions: `You are a research coordinator. Analyze the request and provide 2-3 sentence coordination brief.`,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
agentId: 'analyst1',
|
|
44
|
+
provider: Providers.ANTHROPIC,
|
|
45
|
+
clientOptions: {
|
|
46
|
+
modelName: 'claude-haiku-4-5',
|
|
47
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
48
|
+
},
|
|
49
|
+
instructions: `You are FINANCIAL ANALYST. Provide 2-3 sentence financial analysis. Start with "FINANCIAL ANALYSIS:"`,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
agentId: 'analyst2',
|
|
53
|
+
provider: Providers.ANTHROPIC,
|
|
54
|
+
clientOptions: {
|
|
55
|
+
modelName: 'claude-haiku-4-5',
|
|
56
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
57
|
+
},
|
|
58
|
+
instructions: `You are TECHNICAL ANALYST. Provide 2-3 sentence technical analysis. Start with "TECHNICAL ANALYSIS:"`,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
agentId: 'analyst3',
|
|
62
|
+
provider: Providers.ANTHROPIC,
|
|
63
|
+
clientOptions: {
|
|
64
|
+
modelName: 'claude-haiku-4-5',
|
|
65
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
66
|
+
},
|
|
67
|
+
instructions: `You are MARKET ANALYST. Provide 2-3 sentence market analysis. Start with "MARKET ANALYSIS:"`,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
agentId: 'summarizer',
|
|
71
|
+
provider: Providers.ANTHROPIC,
|
|
72
|
+
clientOptions: {
|
|
73
|
+
modelName: 'claude-haiku-4-5',
|
|
74
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
75
|
+
},
|
|
76
|
+
instructions: `You are SYNTHESIS EXPERT. Review all analyses and provide 2-3 sentence integrated summary.`,
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
// Define direct edges (fan-out and fan-in)
|
|
81
|
+
const edges: t.GraphEdge[] = [
|
|
82
|
+
{
|
|
83
|
+
from: 'researcher',
|
|
84
|
+
to: ['analyst1', 'analyst2', 'analyst3'],
|
|
85
|
+
description: 'Distribute research to specialist analysts',
|
|
86
|
+
edgeType: 'direct',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
from: ['analyst1', 'analyst2', 'analyst3'],
|
|
90
|
+
to: 'summarizer',
|
|
91
|
+
description: 'Aggregate analysis results',
|
|
92
|
+
edgeType: 'direct',
|
|
93
|
+
prompt:
|
|
94
|
+
'Based on the analyses below, provide an integrated summary:\n\n{results}',
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
// Create custom handlers
|
|
99
|
+
const customHandlers = {
|
|
100
|
+
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
101
|
+
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
|
|
102
|
+
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
103
|
+
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
104
|
+
handle: (
|
|
105
|
+
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
106
|
+
data: t.StreamEventData
|
|
107
|
+
): void => {
|
|
108
|
+
aggregateContent({
|
|
109
|
+
event,
|
|
110
|
+
data: data as unknown as { result: t.ToolEndEvent },
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
[GraphEvents.ON_RUN_STEP]: {
|
|
115
|
+
handle: (
|
|
116
|
+
event: GraphEvents.ON_RUN_STEP,
|
|
117
|
+
data: t.StreamEventData
|
|
118
|
+
): void => {
|
|
119
|
+
aggregateContent({ event, data: data as t.RunStep });
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
[GraphEvents.ON_MESSAGE_DELTA]: {
|
|
123
|
+
handle: (
|
|
124
|
+
event: GraphEvents.ON_MESSAGE_DELTA,
|
|
125
|
+
data: t.StreamEventData
|
|
126
|
+
): void => {
|
|
127
|
+
aggregateContent({ event, data: data as t.MessageDeltaEvent });
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const query = 'What are the implications of widespread AI adoption?';
|
|
134
|
+
|
|
135
|
+
console.log(`${'='.repeat(80)}`);
|
|
136
|
+
console.log(`FIRST RUN - USER QUERY: "${query}"`);
|
|
137
|
+
console.log('='.repeat(80));
|
|
138
|
+
|
|
139
|
+
// Reset conversation
|
|
140
|
+
conversationHistory.length = 0;
|
|
141
|
+
conversationHistory.push(new HumanMessage(query));
|
|
142
|
+
|
|
143
|
+
// Create graph
|
|
144
|
+
const runConfig: t.RunConfig = {
|
|
145
|
+
runId: `parallel-test-${Date.now()}`,
|
|
146
|
+
graphConfig: {
|
|
147
|
+
type: 'multi-agent',
|
|
148
|
+
agents,
|
|
149
|
+
edges,
|
|
150
|
+
},
|
|
151
|
+
customHandlers,
|
|
152
|
+
returnContent: true,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const run = await Run.create(runConfig);
|
|
156
|
+
|
|
157
|
+
console.log('\nProcessing first run with parallel agents...\n');
|
|
158
|
+
|
|
159
|
+
const config = {
|
|
160
|
+
configurable: {
|
|
161
|
+
thread_id: 'parallel-agent-labeling-1',
|
|
162
|
+
},
|
|
163
|
+
streamMode: 'values',
|
|
164
|
+
version: 'v2' as const,
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const inputs = {
|
|
168
|
+
messages: conversationHistory,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
await run.processStream(inputs, config);
|
|
172
|
+
const finalMessages = run.getRunMessages();
|
|
173
|
+
|
|
174
|
+
if (finalMessages) {
|
|
175
|
+
conversationHistory.push(...finalMessages);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Show agent participation
|
|
179
|
+
console.log(`\n${'ā'.repeat(80)}`);
|
|
180
|
+
console.log('FIRST RUN - AGENT PARTICIPATION:');
|
|
181
|
+
console.log('ā'.repeat(80));
|
|
182
|
+
|
|
183
|
+
if (run.Graph) {
|
|
184
|
+
const activeAgents = run.Graph.getActiveAgentIds();
|
|
185
|
+
console.log(`\nActive agents (${activeAgents.length}):`, activeAgents);
|
|
186
|
+
|
|
187
|
+
const stepsByAgent = run.Graph.getRunStepsByAgent();
|
|
188
|
+
stepsByAgent.forEach((steps, agentId) => {
|
|
189
|
+
console.log(` ${agentId}: ${steps.length} steps`);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
console.log(`\nTotal content parts: ${contentParts.length}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// =============================================================
|
|
196
|
+
// SECOND RUN: Test with agent-labeled history
|
|
197
|
+
// =============================================================
|
|
198
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
199
|
+
console.log(`SECOND RUN - Simulating DB Load with Parallel Agent Labeling`);
|
|
200
|
+
console.log('='.repeat(80));
|
|
201
|
+
|
|
202
|
+
// Simulate DB storage
|
|
203
|
+
const dbStoredContentParts = [...contentParts];
|
|
204
|
+
const dbStoredAgentIdMap = Object.fromEntries(
|
|
205
|
+
run.Graph!.getContentPartAgentMap()
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
console.log('\nš¦ Simulating DB storage:');
|
|
209
|
+
console.log(` - Stored ${dbStoredContentParts.length} content parts`);
|
|
210
|
+
console.log(
|
|
211
|
+
` - Stored agent mappings for ${Object.keys(dbStoredAgentIdMap).length} parts`
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
// Load and label by agent with labelNonTransferContent option
|
|
215
|
+
console.log('\nš„ Loading from DB and labeling ALL agent content...');
|
|
216
|
+
|
|
217
|
+
const agentNames = {
|
|
218
|
+
researcher: 'Researcher',
|
|
219
|
+
analyst1: 'Financial Analyst',
|
|
220
|
+
analyst2: 'Technical Analyst',
|
|
221
|
+
analyst3: 'Market Analyst',
|
|
222
|
+
summarizer: 'Synthesizer',
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const labeledContentParts = labelContentByAgent(
|
|
226
|
+
dbStoredContentParts.filter(
|
|
227
|
+
(p): p is t.MessageContentComplex => p != null
|
|
228
|
+
),
|
|
229
|
+
dbStoredAgentIdMap,
|
|
230
|
+
agentNames,
|
|
231
|
+
{ labelNonTransferContent: true } // NEW: Label all content
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
console.log(
|
|
235
|
+
` - Labeled ${labeledContentParts.length} content groups by agent`
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
// Convert to payload
|
|
239
|
+
const payload: t.TPayload = [
|
|
240
|
+
{
|
|
241
|
+
role: 'user',
|
|
242
|
+
content: query,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
role: 'assistant',
|
|
246
|
+
content: labeledContentParts,
|
|
247
|
+
},
|
|
248
|
+
];
|
|
249
|
+
|
|
250
|
+
// Format using formatAgentMessages
|
|
251
|
+
console.log('\nš§ Calling formatAgentMessages...');
|
|
252
|
+
const { messages: formattedMessages } = formatAgentMessages(payload);
|
|
253
|
+
|
|
254
|
+
console.log(` - Formatted into ${formattedMessages.length} BaseMessages`);
|
|
255
|
+
|
|
256
|
+
// Show preview
|
|
257
|
+
console.log('\nšļø Preview of formatted history:');
|
|
258
|
+
console.log('ā'.repeat(80));
|
|
259
|
+
for (let i = 0; i < formattedMessages.length; i++) {
|
|
260
|
+
const msg = formattedMessages[i];
|
|
261
|
+
const role = msg._getType();
|
|
262
|
+
const preview =
|
|
263
|
+
typeof msg.content === 'string'
|
|
264
|
+
? msg.content.slice(0, 300)
|
|
265
|
+
: JSON.stringify(msg.content).slice(0, 300);
|
|
266
|
+
console.log(
|
|
267
|
+
`[${i}] ${role}: ${preview}${preview.length >= 300 ? '...' : ''}`
|
|
268
|
+
);
|
|
269
|
+
console.log('');
|
|
270
|
+
}
|
|
271
|
+
console.log('ā'.repeat(80));
|
|
272
|
+
|
|
273
|
+
// Create a second run with labeled history
|
|
274
|
+
console.log(
|
|
275
|
+
'\nš Starting second run with agent-labeled parallel history...'
|
|
276
|
+
);
|
|
277
|
+
const followupQuery = 'Which analyst identified the most significant risk?';
|
|
278
|
+
console.log(` Followup: "${followupQuery}"`);
|
|
279
|
+
|
|
280
|
+
const secondRunHistory: BaseMessage[] = [
|
|
281
|
+
...formattedMessages,
|
|
282
|
+
new HumanMessage(followupQuery),
|
|
283
|
+
];
|
|
284
|
+
|
|
285
|
+
const runConfig2: t.RunConfig = {
|
|
286
|
+
runId: `parallel-test-2-${Date.now()}`,
|
|
287
|
+
graphConfig: {
|
|
288
|
+
type: 'multi-agent',
|
|
289
|
+
agents,
|
|
290
|
+
edges,
|
|
291
|
+
},
|
|
292
|
+
customHandlers,
|
|
293
|
+
returnContent: true,
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const run2 = await Run.create(runConfig2);
|
|
297
|
+
|
|
298
|
+
const inputs2 = {
|
|
299
|
+
messages: secondRunHistory,
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
await run2.processStream(inputs2, config);
|
|
303
|
+
|
|
304
|
+
console.log('\nā
Second run completed successfully!');
|
|
305
|
+
console.log(
|
|
306
|
+
' The researcher correctly understood that parallel analysts handled'
|
|
307
|
+
);
|
|
308
|
+
console.log(' the previous analysis, with clear attribution per agent.');
|
|
309
|
+
|
|
310
|
+
console.log(`\n${'='.repeat(80)}`);
|
|
311
|
+
console.log('TEST COMPLETE');
|
|
312
|
+
console.log('='.repeat(80));
|
|
313
|
+
console.log(
|
|
314
|
+
'\nThis demonstrates that parallel multi-agent patterns work correctly'
|
|
315
|
+
);
|
|
316
|
+
console.log(
|
|
317
|
+
'with agent labeling, preventing confusion about who said what.'
|
|
318
|
+
);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
console.error('Error in parallel agent labeling test:', error);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Run the test
|
|
325
|
+
testParallelWithAgentLabeling();
|