@librechat/agents 2.4.321 → 3.0.0-rc1
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 +218 -0
- package/dist/cjs/agents/AgentContext.cjs.map +1 -0
- package/dist/cjs/common/enum.cjs +14 -5
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/events.cjs +10 -6
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +309 -212
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +322 -0
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -0
- package/dist/cjs/llm/anthropic/index.cjs +54 -9
- 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 +52 -6
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +22 -2
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/tools.cjs +29 -0
- package/dist/cjs/llm/anthropic/utils/tools.cjs.map +1 -0
- package/dist/cjs/llm/google/index.cjs +144 -0
- package/dist/cjs/llm/google/index.cjs.map +1 -0
- package/dist/cjs/llm/google/utils/common.cjs +477 -0
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -0
- package/dist/cjs/llm/ollama/index.cjs +67 -0
- package/dist/cjs/llm/ollama/index.cjs.map +1 -0
- package/dist/cjs/llm/ollama/utils.cjs +158 -0
- package/dist/cjs/llm/ollama/utils.cjs.map +1 -0
- package/dist/cjs/llm/openai/index.cjs +389 -3
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +672 -0
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -0
- package/dist/cjs/llm/providers.cjs +15 -15
- package/dist/cjs/llm/providers.cjs.map +1 -1
- package/dist/cjs/llm/text.cjs +14 -3
- package/dist/cjs/llm/text.cjs.map +1 -1
- package/dist/cjs/llm/vertexai/index.cjs +330 -0
- package/dist/cjs/llm/vertexai/index.cjs.map +1 -0
- package/dist/cjs/main.cjs +11 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/run.cjs +120 -81
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +85 -51
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +10 -4
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/handlers.cjs +119 -13
- package/dist/cjs/tools/handlers.cjs.map +1 -1
- package/dist/cjs/tools/search/anthropic.cjs +40 -0
- package/dist/cjs/tools/search/anthropic.cjs.map +1 -0
- package/dist/cjs/tools/search/firecrawl.cjs +61 -13
- package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
- package/dist/cjs/tools/search/format.cjs +9 -3
- package/dist/cjs/tools/search/format.cjs.map +1 -1
- package/dist/cjs/tools/search/rerankers.cjs +35 -50
- package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
- package/dist/cjs/tools/search/schema.cjs +70 -0
- package/dist/cjs/tools/search/schema.cjs.map +1 -0
- package/dist/cjs/tools/search/search.cjs +145 -38
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +165 -48
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/search/utils.cjs +34 -5
- package/dist/cjs/tools/search/utils.cjs.map +1 -1
- package/dist/cjs/utils/events.cjs +31 -0
- package/dist/cjs/utils/events.cjs.map +1 -0
- package/dist/cjs/utils/title.cjs +57 -21
- package/dist/cjs/utils/title.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +54 -7
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +216 -0
- package/dist/esm/agents/AgentContext.mjs.map +1 -0
- package/dist/esm/common/enum.mjs +15 -6
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +10 -6
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +311 -214
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +320 -0
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -0
- package/dist/esm/llm/anthropic/index.mjs +54 -9
- 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 +52 -6
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs +22 -2
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/tools.mjs +27 -0
- package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -0
- package/dist/esm/llm/google/index.mjs +142 -0
- package/dist/esm/llm/google/index.mjs.map +1 -0
- package/dist/esm/llm/google/utils/common.mjs +471 -0
- package/dist/esm/llm/google/utils/common.mjs.map +1 -0
- package/dist/esm/llm/ollama/index.mjs +65 -0
- package/dist/esm/llm/ollama/index.mjs.map +1 -0
- package/dist/esm/llm/ollama/utils.mjs +155 -0
- package/dist/esm/llm/ollama/utils.mjs.map +1 -0
- package/dist/esm/llm/openai/index.mjs +388 -4
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +666 -0
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -0
- package/dist/esm/llm/providers.mjs +5 -5
- package/dist/esm/llm/providers.mjs.map +1 -1
- package/dist/esm/llm/text.mjs +14 -3
- package/dist/esm/llm/text.mjs.map +1 -1
- package/dist/esm/llm/vertexai/index.mjs +328 -0
- package/dist/esm/llm/vertexai/index.mjs.map +1 -0
- package/dist/esm/main.mjs +6 -5
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/run.mjs +121 -83
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +87 -54
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +10 -4
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/handlers.mjs +119 -15
- package/dist/esm/tools/handlers.mjs.map +1 -1
- package/dist/esm/tools/search/anthropic.mjs +37 -0
- package/dist/esm/tools/search/anthropic.mjs.map +1 -0
- package/dist/esm/tools/search/firecrawl.mjs +61 -13
- package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
- package/dist/esm/tools/search/format.mjs +10 -4
- package/dist/esm/tools/search/format.mjs.map +1 -1
- package/dist/esm/tools/search/rerankers.mjs +35 -50
- package/dist/esm/tools/search/rerankers.mjs.map +1 -1
- package/dist/esm/tools/search/schema.mjs +61 -0
- package/dist/esm/tools/search/schema.mjs.map +1 -0
- package/dist/esm/tools/search/search.mjs +146 -39
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +164 -47
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/search/utils.mjs +33 -6
- package/dist/esm/tools/search/utils.mjs.map +1 -1
- package/dist/esm/utils/events.mjs +29 -0
- package/dist/esm/utils/events.mjs.map +1 -0
- package/dist/esm/utils/title.mjs +57 -22
- package/dist/esm/utils/title.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +54 -8
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +91 -0
- package/dist/types/common/enum.d.ts +15 -6
- package/dist/types/events.d.ts +5 -4
- package/dist/types/graphs/Graph.d.ts +64 -67
- package/dist/types/graphs/MultiAgentGraph.d.ts +37 -0
- package/dist/types/graphs/index.d.ts +1 -0
- package/dist/types/llm/anthropic/index.d.ts +11 -0
- package/dist/types/llm/anthropic/types.d.ts +9 -3
- package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -1
- package/dist/types/llm/anthropic/utils/output_parsers.d.ts +4 -4
- package/dist/types/llm/anthropic/utils/tools.d.ts +3 -0
- package/dist/types/llm/google/index.d.ts +13 -0
- package/dist/types/llm/google/types.d.ts +32 -0
- package/dist/types/llm/google/utils/common.d.ts +19 -0
- package/dist/types/llm/google/utils/tools.d.ts +10 -0
- package/dist/types/llm/google/utils/zod_to_genai_parameters.d.ts +14 -0
- package/dist/types/llm/ollama/index.d.ts +7 -0
- package/dist/types/llm/ollama/utils.d.ts +7 -0
- package/dist/types/llm/openai/index.d.ts +72 -3
- package/dist/types/llm/openai/types.d.ts +10 -0
- package/dist/types/llm/openai/utils/index.d.ts +20 -0
- package/dist/types/llm/text.d.ts +1 -1
- package/dist/types/llm/vertexai/index.d.ts +293 -0
- package/dist/types/messages/reducer.d.ts +9 -0
- package/dist/types/run.d.ts +19 -12
- package/dist/types/scripts/ant_web_search.d.ts +1 -0
- package/dist/types/scripts/args.d.ts +2 -1
- package/dist/types/scripts/handoff-test.d.ts +1 -0
- package/dist/types/scripts/multi-agent-conditional.d.ts +1 -0
- package/dist/types/scripts/multi-agent-parallel.d.ts +1 -0
- package/dist/types/scripts/multi-agent-sequence.d.ts +1 -0
- package/dist/types/scripts/multi-agent-test.d.ts +1 -0
- package/dist/types/stream.d.ts +10 -3
- package/dist/types/tools/CodeExecutor.d.ts +2 -2
- package/dist/types/tools/ToolNode.d.ts +1 -1
- package/dist/types/tools/handlers.d.ts +17 -4
- package/dist/types/tools/search/anthropic.d.ts +16 -0
- package/dist/types/tools/search/firecrawl.d.ts +16 -0
- package/dist/types/tools/search/rerankers.d.ts +8 -5
- package/dist/types/tools/search/schema.d.ts +16 -0
- package/dist/types/tools/search/tool.d.ts +13 -0
- package/dist/types/tools/search/types.d.ts +64 -9
- package/dist/types/tools/search/utils.d.ts +9 -2
- package/dist/types/types/graph.d.ts +95 -15
- package/dist/types/types/llm.d.ts +24 -10
- package/dist/types/types/run.d.ts +46 -8
- package/dist/types/types/stream.d.ts +16 -2
- package/dist/types/types/tools.d.ts +1 -1
- package/dist/types/utils/events.d.ts +6 -0
- package/dist/types/utils/title.d.ts +2 -1
- package/dist/types/utils/tokens.d.ts +24 -0
- package/package.json +35 -18
- package/src/agents/AgentContext.ts +315 -0
- package/src/common/enum.ts +14 -5
- package/src/events.ts +24 -13
- package/src/graphs/Graph.ts +495 -312
- package/src/graphs/MultiAgentGraph.ts +381 -0
- package/src/graphs/index.ts +2 -1
- package/src/llm/anthropic/Jacob_Lee_Resume_2023.pdf +0 -0
- package/src/llm/anthropic/index.ts +78 -13
- package/src/llm/anthropic/llm.spec.ts +491 -115
- package/src/llm/anthropic/types.ts +39 -3
- package/src/llm/anthropic/utils/message_inputs.ts +67 -11
- package/src/llm/anthropic/utils/message_outputs.ts +21 -2
- package/src/llm/anthropic/utils/output_parsers.ts +25 -6
- package/src/llm/anthropic/utils/tools.ts +29 -0
- package/src/llm/google/index.ts +218 -0
- package/src/llm/google/types.ts +43 -0
- package/src/llm/google/utils/common.ts +646 -0
- package/src/llm/google/utils/tools.ts +160 -0
- package/src/llm/google/utils/zod_to_genai_parameters.ts +86 -0
- package/src/llm/ollama/index.ts +89 -0
- package/src/llm/ollama/utils.ts +193 -0
- package/src/llm/openai/index.ts +600 -14
- package/src/llm/openai/types.ts +24 -0
- package/src/llm/openai/utils/index.ts +912 -0
- package/src/llm/openai/utils/isReasoningModel.test.ts +90 -0
- package/src/llm/providers.ts +10 -9
- package/src/llm/text.ts +26 -7
- package/src/llm/vertexai/index.ts +360 -0
- package/src/messages/reducer.ts +80 -0
- package/src/run.ts +181 -112
- package/src/scripts/ant_web_search.ts +158 -0
- package/src/scripts/args.ts +12 -8
- package/src/scripts/cli4.ts +29 -21
- package/src/scripts/cli5.ts +29 -21
- package/src/scripts/code_exec.ts +54 -23
- package/src/scripts/code_exec_files.ts +48 -17
- package/src/scripts/code_exec_simple.ts +46 -27
- package/src/scripts/handoff-test.ts +135 -0
- package/src/scripts/image.ts +52 -20
- package/src/scripts/multi-agent-conditional.ts +220 -0
- package/src/scripts/multi-agent-example-output.md +110 -0
- package/src/scripts/multi-agent-parallel.ts +337 -0
- package/src/scripts/multi-agent-sequence.ts +212 -0
- package/src/scripts/multi-agent-test.ts +186 -0
- package/src/scripts/search.ts +4 -12
- package/src/scripts/simple.ts +25 -10
- package/src/scripts/tools.ts +48 -18
- package/src/specs/anthropic.simple.test.ts +150 -34
- package/src/specs/azure.simple.test.ts +325 -0
- package/src/specs/openai.simple.test.ts +140 -33
- package/src/specs/openrouter.simple.test.ts +107 -0
- package/src/specs/prune.test.ts +4 -9
- package/src/specs/reasoning.test.ts +80 -44
- package/src/specs/token-memoization.test.ts +39 -0
- package/src/stream.test.ts +94 -0
- package/src/stream.ts +139 -60
- package/src/tools/ToolNode.ts +21 -7
- package/src/tools/handlers.ts +192 -18
- package/src/tools/search/anthropic.ts +51 -0
- package/src/tools/search/firecrawl.ts +78 -24
- package/src/tools/search/format.ts +10 -5
- package/src/tools/search/rerankers.ts +50 -62
- package/src/tools/search/schema.ts +63 -0
- package/src/tools/search/search.ts +167 -34
- package/src/tools/search/tool.ts +222 -46
- package/src/tools/search/types.ts +65 -10
- package/src/tools/search/utils.ts +37 -5
- package/src/types/graph.ts +272 -103
- package/src/types/llm.ts +25 -12
- package/src/types/run.ts +51 -13
- package/src/types/stream.ts +22 -1
- package/src/types/tools.ts +16 -10
- package/src/utils/events.ts +32 -0
- package/src/utils/llmConfig.ts +20 -8
- package/src/utils/title.ts +104 -30
- package/src/utils/tokens.ts +69 -10
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { config } from 'dotenv';
|
|
2
|
+
config();
|
|
3
|
+
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { tool } from '@langchain/core/tools';
|
|
6
|
+
import { ChatAnthropic } from '@langchain/anthropic';
|
|
7
|
+
import { createReactAgent } from '@langchain/langgraph/prebuilt';
|
|
8
|
+
import {
|
|
9
|
+
StateGraph,
|
|
10
|
+
MessagesAnnotation,
|
|
11
|
+
Command,
|
|
12
|
+
START,
|
|
13
|
+
getCurrentTaskInput,
|
|
14
|
+
END,
|
|
15
|
+
} from '@langchain/langgraph';
|
|
16
|
+
import { ToolMessage } from '@langchain/core/messages';
|
|
17
|
+
|
|
18
|
+
interface CreateHandoffToolParams {
|
|
19
|
+
agentName: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const createHandoffTool = ({
|
|
24
|
+
agentName,
|
|
25
|
+
description,
|
|
26
|
+
}: CreateHandoffToolParams) => {
|
|
27
|
+
const toolName = `transfer_to_${agentName}`;
|
|
28
|
+
const toolDescription = description || `Ask agent '${agentName}' for help`;
|
|
29
|
+
|
|
30
|
+
const handoffTool = tool(
|
|
31
|
+
async (_, config) => {
|
|
32
|
+
const toolMessage = new ToolMessage({
|
|
33
|
+
content: `Successfully transferred to ${agentName}`,
|
|
34
|
+
name: toolName,
|
|
35
|
+
tool_call_id: config.toolCall.id,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// inject the current agent state
|
|
39
|
+
const state =
|
|
40
|
+
getCurrentTaskInput() as (typeof MessagesAnnotation)['State'];
|
|
41
|
+
return new Command({
|
|
42
|
+
goto: agentName,
|
|
43
|
+
update: { messages: state.messages.concat(toolMessage) },
|
|
44
|
+
graph: Command.PARENT,
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: toolName,
|
|
49
|
+
schema: z.object({}),
|
|
50
|
+
description: toolDescription,
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
return handoffTool;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const bookHotel = tool(
|
|
58
|
+
async (input: { hotel_name: string }) => {
|
|
59
|
+
return `Successfully booked a stay at ${input.hotel_name}.`;
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'book_hotel',
|
|
63
|
+
description: 'Book a hotel',
|
|
64
|
+
schema: z.object({
|
|
65
|
+
hotel_name: z.string().describe('The name of the hotel to book'),
|
|
66
|
+
}),
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const bookFlight = tool(
|
|
71
|
+
async (input: { from_airport: string; to_airport: string }) => {
|
|
72
|
+
return `Successfully booked a flight from ${input.from_airport} to ${input.to_airport}.`;
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'book_flight',
|
|
76
|
+
description: 'Book a flight',
|
|
77
|
+
schema: z.object({
|
|
78
|
+
from_airport: z.string().describe('The departure airport code'),
|
|
79
|
+
to_airport: z.string().describe('The arrival airport code'),
|
|
80
|
+
}),
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const transferToHotelAssistant = createHandoffTool({
|
|
85
|
+
agentName: 'hotel_assistant',
|
|
86
|
+
description: 'Transfer user to the hotel-booking assistant.',
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const transferToFlightAssistant = createHandoffTool({
|
|
90
|
+
agentName: 'flight_assistant',
|
|
91
|
+
description: 'Transfer user to the flight-booking assistant.',
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const llm = new ChatAnthropic({
|
|
95
|
+
modelName: 'claude-3-5-sonnet-latest',
|
|
96
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const flightAssistant = createReactAgent({
|
|
100
|
+
llm,
|
|
101
|
+
tools: [bookFlight, transferToHotelAssistant],
|
|
102
|
+
prompt: 'You are a flight booking assistant',
|
|
103
|
+
name: 'flight_assistant',
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const hotelAssistant = createReactAgent({
|
|
107
|
+
llm,
|
|
108
|
+
tools: [bookHotel, transferToFlightAssistant],
|
|
109
|
+
prompt: 'You are a hotel booking assistant',
|
|
110
|
+
name: 'hotel_assistant',
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const multiAgentGraph = new StateGraph(MessagesAnnotation)
|
|
114
|
+
.addNode('flight_assistant', flightAssistant, {
|
|
115
|
+
ends: ['hotel_assistant', END],
|
|
116
|
+
})
|
|
117
|
+
.addNode('hotel_assistant', hotelAssistant, {
|
|
118
|
+
ends: ['flight_assistant', END],
|
|
119
|
+
})
|
|
120
|
+
.addEdge(START, 'flight_assistant')
|
|
121
|
+
.compile();
|
|
122
|
+
|
|
123
|
+
const stream = await multiAgentGraph.stream({
|
|
124
|
+
messages: [
|
|
125
|
+
{
|
|
126
|
+
role: 'user',
|
|
127
|
+
content: 'book a flight from BOS to JFK and a stay at McKittrick Hotel',
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
for await (const chunk of stream) {
|
|
133
|
+
console.log(chunk);
|
|
134
|
+
console.log('\n');
|
|
135
|
+
}
|
package/src/scripts/image.ts
CHANGED
|
@@ -5,14 +5,17 @@ import { HumanMessage, AIMessage, BaseMessage } from '@langchain/core/messages';
|
|
|
5
5
|
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
6
6
|
import type * as t from '@/types';
|
|
7
7
|
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
ToolEndHandler,
|
|
10
|
+
ModelEndHandler,
|
|
11
|
+
createMetadataAggregator,
|
|
12
|
+
} from '@/events';
|
|
9
13
|
import { fetchRandomImageTool, fetchRandomImageURL } from '@/tools/example';
|
|
10
14
|
import { getLLMConfig } from '@/utils/llmConfig';
|
|
11
15
|
import { getArgs } from '@/scripts/args';
|
|
12
16
|
import { GraphEvents } from '@/common';
|
|
13
17
|
import { Run } from '@/run';
|
|
14
18
|
|
|
15
|
-
|
|
16
19
|
const conversationHistory: BaseMessage[] = [];
|
|
17
20
|
|
|
18
21
|
async function testCodeExecution(): Promise<void> {
|
|
@@ -23,38 +26,57 @@ async function testCodeExecution(): Promise<void> {
|
|
|
23
26
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
|
|
24
27
|
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
25
28
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
26
|
-
handle: (
|
|
29
|
+
handle: (
|
|
30
|
+
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
31
|
+
data: t.StreamEventData
|
|
32
|
+
): void => {
|
|
27
33
|
console.log('====== ON_RUN_STEP_COMPLETED ======');
|
|
28
34
|
console.dir(data, { depth: null });
|
|
29
|
-
aggregateContent({
|
|
30
|
-
|
|
35
|
+
aggregateContent({
|
|
36
|
+
event,
|
|
37
|
+
data: data as unknown as { result: t.ToolEndEvent },
|
|
38
|
+
});
|
|
39
|
+
},
|
|
31
40
|
},
|
|
32
41
|
[GraphEvents.ON_RUN_STEP]: {
|
|
33
|
-
handle: (
|
|
42
|
+
handle: (
|
|
43
|
+
event: GraphEvents.ON_RUN_STEP,
|
|
44
|
+
data: t.StreamEventData
|
|
45
|
+
): void => {
|
|
34
46
|
console.log('====== ON_RUN_STEP ======');
|
|
35
47
|
console.dir(data, { depth: null });
|
|
36
48
|
aggregateContent({ event, data: data as t.RunStep });
|
|
37
|
-
}
|
|
49
|
+
},
|
|
38
50
|
},
|
|
39
51
|
[GraphEvents.ON_RUN_STEP_DELTA]: {
|
|
40
|
-
handle: (
|
|
52
|
+
handle: (
|
|
53
|
+
event: GraphEvents.ON_RUN_STEP_DELTA,
|
|
54
|
+
data: t.StreamEventData
|
|
55
|
+
): void => {
|
|
41
56
|
console.log('====== ON_RUN_STEP_DELTA ======');
|
|
42
57
|
console.dir(data, { depth: null });
|
|
43
58
|
aggregateContent({ event, data: data as t.RunStepDeltaEvent });
|
|
44
|
-
}
|
|
59
|
+
},
|
|
45
60
|
},
|
|
46
61
|
[GraphEvents.ON_MESSAGE_DELTA]: {
|
|
47
|
-
handle: (
|
|
62
|
+
handle: (
|
|
63
|
+
event: GraphEvents.ON_MESSAGE_DELTA,
|
|
64
|
+
data: t.StreamEventData
|
|
65
|
+
): void => {
|
|
48
66
|
console.log('====== ON_MESSAGE_DELTA ======');
|
|
49
67
|
console.dir(data, { depth: null });
|
|
50
68
|
aggregateContent({ event, data: data as t.MessageDeltaEvent });
|
|
51
|
-
}
|
|
69
|
+
},
|
|
52
70
|
},
|
|
53
71
|
[GraphEvents.TOOL_START]: {
|
|
54
|
-
handle: (
|
|
72
|
+
handle: (
|
|
73
|
+
_event: string,
|
|
74
|
+
data: t.StreamEventData,
|
|
75
|
+
metadata?: Record<string, unknown>
|
|
76
|
+
): void => {
|
|
55
77
|
console.log('====== TOOL_START ======');
|
|
56
78
|
console.dir(data, { depth: null });
|
|
57
|
-
}
|
|
79
|
+
},
|
|
58
80
|
},
|
|
59
81
|
};
|
|
60
82
|
|
|
@@ -67,14 +89,19 @@ async function testCodeExecution(): Promise<void> {
|
|
|
67
89
|
llmConfig,
|
|
68
90
|
tools: [fetchRandomImageTool],
|
|
69
91
|
// tools: [fetchRandomImageURL],
|
|
70
|
-
instructions:
|
|
92
|
+
instructions:
|
|
93
|
+
'You are a friendly AI assistant with internet capabilities. Always address the user by their name.',
|
|
71
94
|
additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
|
|
72
95
|
},
|
|
73
96
|
returnContent: true,
|
|
74
97
|
customHandlers,
|
|
75
98
|
});
|
|
76
99
|
|
|
77
|
-
const config: Partial<RunnableConfig> & {
|
|
100
|
+
const config: Partial<RunnableConfig> & {
|
|
101
|
+
version: 'v1' | 'v2';
|
|
102
|
+
run_id?: string;
|
|
103
|
+
streamMode: string;
|
|
104
|
+
} = {
|
|
78
105
|
configurable: {
|
|
79
106
|
provider,
|
|
80
107
|
thread_id: 'conversation-num-1',
|
|
@@ -109,7 +136,9 @@ async function testCodeExecution(): Promise<void> {
|
|
|
109
136
|
inputs = {
|
|
110
137
|
messages: conversationHistory,
|
|
111
138
|
};
|
|
112
|
-
const finalContentParts2 = await run.processStream(inputs, config, {
|
|
139
|
+
const finalContentParts2 = await run.processStream(inputs, config, {
|
|
140
|
+
keepContent: true,
|
|
141
|
+
});
|
|
113
142
|
const finalMessages2 = run.getRunMessages();
|
|
114
143
|
if (finalMessages2) {
|
|
115
144
|
conversationHistory.push(...finalMessages2);
|
|
@@ -119,12 +148,15 @@ async function testCodeExecution(): Promise<void> {
|
|
|
119
148
|
|
|
120
149
|
const { handleLLMEnd, collected } = createMetadataAggregator();
|
|
121
150
|
const titleResult = await run.generateTitle({
|
|
151
|
+
provider,
|
|
122
152
|
inputText: userMessage2,
|
|
123
153
|
contentParts,
|
|
124
154
|
chainOptions: {
|
|
125
|
-
callbacks: [
|
|
126
|
-
|
|
127
|
-
|
|
155
|
+
callbacks: [
|
|
156
|
+
{
|
|
157
|
+
handleLLMEnd,
|
|
158
|
+
},
|
|
159
|
+
],
|
|
128
160
|
},
|
|
129
161
|
});
|
|
130
162
|
console.log('Generated Title:', titleResult);
|
|
@@ -143,4 +175,4 @@ testCodeExecution().catch((err) => {
|
|
|
143
175
|
console.log('Conversation history:');
|
|
144
176
|
console.dir(conversationHistory, { depth: null });
|
|
145
177
|
process.exit(1);
|
|
146
|
-
});
|
|
178
|
+
});
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { config } from 'dotenv';
|
|
2
|
+
config();
|
|
3
|
+
|
|
4
|
+
import { HumanMessage, BaseMessage } from '@langchain/core/messages';
|
|
5
|
+
import { Run } from '@/run';
|
|
6
|
+
import { Providers, GraphEvents } from '@/common';
|
|
7
|
+
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
8
|
+
import { ToolEndHandler, ModelEndHandler } from '@/events';
|
|
9
|
+
import type * as t from '@/types';
|
|
10
|
+
|
|
11
|
+
const conversationHistory: BaseMessage[] = [];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Example of conditional multi-agent system
|
|
15
|
+
*
|
|
16
|
+
* Graph structure:
|
|
17
|
+
* START -> classifier
|
|
18
|
+
* classifier -> technical_expert (if technical question)
|
|
19
|
+
* classifier -> business_expert (if business question)
|
|
20
|
+
* classifier -> general_assistant (otherwise)
|
|
21
|
+
* [all experts] -> END
|
|
22
|
+
*/
|
|
23
|
+
async function testConditionalMultiAgent() {
|
|
24
|
+
console.log('Testing Conditional Multi-Agent System...\n');
|
|
25
|
+
|
|
26
|
+
// Set up content aggregator
|
|
27
|
+
const { contentParts, aggregateContent } = createContentAggregator();
|
|
28
|
+
|
|
29
|
+
// Define specialized agents
|
|
30
|
+
const agents: t.AgentInputs[] = [
|
|
31
|
+
{
|
|
32
|
+
agentId: 'classifier',
|
|
33
|
+
provider: Providers.ANTHROPIC,
|
|
34
|
+
clientOptions: {
|
|
35
|
+
modelName: 'claude-3-5-sonnet-latest',
|
|
36
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
37
|
+
},
|
|
38
|
+
instructions:
|
|
39
|
+
'You are a query classifier. Analyze user questions and determine if they are technical, business-related, or general.',
|
|
40
|
+
maxContextTokens: 8000,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
agentId: 'technical_expert',
|
|
44
|
+
provider: Providers.ANTHROPIC,
|
|
45
|
+
clientOptions: {
|
|
46
|
+
modelName: 'claude-3-5-sonnet-latest',
|
|
47
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
48
|
+
},
|
|
49
|
+
instructions:
|
|
50
|
+
'You are a technical expert. Provide detailed technical answers about programming, systems, and technology.',
|
|
51
|
+
maxContextTokens: 8000,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
agentId: 'business_expert',
|
|
55
|
+
provider: Providers.ANTHROPIC,
|
|
56
|
+
clientOptions: {
|
|
57
|
+
modelName: 'claude-3-5-sonnet-latest',
|
|
58
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
59
|
+
},
|
|
60
|
+
instructions:
|
|
61
|
+
'You are a business expert. Provide insights on business strategy, operations, and management.',
|
|
62
|
+
maxContextTokens: 8000,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
agentId: 'general_assistant',
|
|
66
|
+
provider: Providers.ANTHROPIC,
|
|
67
|
+
clientOptions: {
|
|
68
|
+
modelName: 'claude-3-5-sonnet-latest',
|
|
69
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
70
|
+
},
|
|
71
|
+
instructions:
|
|
72
|
+
'You are a helpful general assistant. Answer questions on a wide range of topics.',
|
|
73
|
+
maxContextTokens: 8000,
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
// Define conditional edges
|
|
78
|
+
// These create handoff tools with conditional routing logic
|
|
79
|
+
const edges: t.GraphEdge[] = [
|
|
80
|
+
{
|
|
81
|
+
from: 'classifier',
|
|
82
|
+
to: ['technical_expert', 'business_expert', 'general_assistant'],
|
|
83
|
+
description: 'Route to appropriate expert based on query type',
|
|
84
|
+
condition: (state: t.BaseGraphState) => {
|
|
85
|
+
// Simple keyword-based routing for demo
|
|
86
|
+
// In a real system, this would use the classifier's analysis
|
|
87
|
+
const lastMessage = state.messages[state.messages.length - 1];
|
|
88
|
+
const content = lastMessage.content?.toString().toLowerCase() || '';
|
|
89
|
+
|
|
90
|
+
if (
|
|
91
|
+
content.includes('code') ||
|
|
92
|
+
content.includes('programming') ||
|
|
93
|
+
content.includes('technical')
|
|
94
|
+
) {
|
|
95
|
+
return 'technical_expert';
|
|
96
|
+
} else if (
|
|
97
|
+
content.includes('business') ||
|
|
98
|
+
content.includes('strategy') ||
|
|
99
|
+
content.includes('market')
|
|
100
|
+
) {
|
|
101
|
+
return 'business_expert';
|
|
102
|
+
} else {
|
|
103
|
+
return 'general_assistant';
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
// Track selected expert
|
|
110
|
+
let selectedExpert = '';
|
|
111
|
+
|
|
112
|
+
// Create custom handlers
|
|
113
|
+
const customHandlers = {
|
|
114
|
+
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
115
|
+
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
|
|
116
|
+
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
117
|
+
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
118
|
+
handle: (
|
|
119
|
+
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
120
|
+
data: t.StreamEventData
|
|
121
|
+
): void => {
|
|
122
|
+
aggregateContent({
|
|
123
|
+
event,
|
|
124
|
+
data: data as unknown as { result: t.ToolEndEvent },
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
[GraphEvents.ON_RUN_STEP]: {
|
|
129
|
+
handle: (
|
|
130
|
+
event: GraphEvents.ON_RUN_STEP,
|
|
131
|
+
data: t.StreamEventData
|
|
132
|
+
): void => {
|
|
133
|
+
const runStepData = data as any;
|
|
134
|
+
if (runStepData?.name && runStepData.name !== 'classifier') {
|
|
135
|
+
selectedExpert = runStepData.name;
|
|
136
|
+
console.log(`Routing to: ${selectedExpert}`);
|
|
137
|
+
}
|
|
138
|
+
aggregateContent({ event, data: data as t.RunStep });
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
[GraphEvents.ON_RUN_STEP_DELTA]: {
|
|
142
|
+
handle: (
|
|
143
|
+
event: GraphEvents.ON_RUN_STEP_DELTA,
|
|
144
|
+
data: t.StreamEventData
|
|
145
|
+
): void => {
|
|
146
|
+
aggregateContent({ event, data: data as t.RunStepDeltaEvent });
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
[GraphEvents.ON_MESSAGE_DELTA]: {
|
|
150
|
+
handle: (
|
|
151
|
+
event: GraphEvents.ON_MESSAGE_DELTA,
|
|
152
|
+
data: t.StreamEventData
|
|
153
|
+
): void => {
|
|
154
|
+
aggregateContent({ event, data: data as t.MessageDeltaEvent });
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Create multi-agent run configuration
|
|
160
|
+
const runConfig: t.RunConfig = {
|
|
161
|
+
runId: `conditional-multi-agent-${Date.now()}`,
|
|
162
|
+
graphConfig: {
|
|
163
|
+
type: 'multi-agent',
|
|
164
|
+
agents,
|
|
165
|
+
edges,
|
|
166
|
+
},
|
|
167
|
+
customHandlers,
|
|
168
|
+
returnContent: true,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
// Create and execute the run
|
|
173
|
+
const run = await Run.create(runConfig);
|
|
174
|
+
|
|
175
|
+
// Test with different types of questions
|
|
176
|
+
const testQuestions = [
|
|
177
|
+
'How do I implement a binary search tree in Python?',
|
|
178
|
+
'What are the key strategies for market expansion?',
|
|
179
|
+
'What is the capital of France?',
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
const config = {
|
|
183
|
+
configurable: {
|
|
184
|
+
thread_id: 'conditional-conversation-1',
|
|
185
|
+
},
|
|
186
|
+
streamMode: 'values',
|
|
187
|
+
version: 'v2' as const,
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
for (const question of testQuestions) {
|
|
191
|
+
console.log(`\n--- Processing: "${question}" ---\n`);
|
|
192
|
+
|
|
193
|
+
// Reset for each question
|
|
194
|
+
selectedExpert = '';
|
|
195
|
+
conversationHistory.length = 0;
|
|
196
|
+
conversationHistory.push(new HumanMessage(question));
|
|
197
|
+
|
|
198
|
+
// Process with streaming
|
|
199
|
+
const inputs = {
|
|
200
|
+
messages: conversationHistory,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const finalContentParts = await run.processStream(inputs, config);
|
|
204
|
+
const finalMessages = run.getRunMessages();
|
|
205
|
+
|
|
206
|
+
if (finalMessages) {
|
|
207
|
+
conversationHistory.push(...finalMessages);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
console.log(`\n\nExpert used: ${selectedExpert}`);
|
|
211
|
+
console.log('Content parts:', contentParts.length);
|
|
212
|
+
console.log('---');
|
|
213
|
+
}
|
|
214
|
+
} catch (error) {
|
|
215
|
+
console.error('Error in conditional multi-agent test:', error);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Run the test
|
|
220
|
+
testConditionalMultiAgent();
|
|
@@ -0,0 +1,110 @@
|
|
|
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.
|