@librechat/agents 2.4.41 → 2.4.43
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/common/enum.cjs +4 -2
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +5 -6
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/google/index.cjs +73 -1
- package/dist/cjs/llm/google/index.cjs.map +1 -1
- package/dist/cjs/llm/google/utils/common.cjs +469 -0
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -0
- package/dist/cjs/run.cjs +4 -3
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +5 -2
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/utils/title.cjs +25 -20
- package/dist/cjs/utils/title.cjs.map +1 -1
- package/dist/esm/common/enum.mjs +4 -2
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +5 -6
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/google/index.mjs +73 -1
- package/dist/esm/llm/google/index.mjs.map +1 -1
- package/dist/esm/llm/google/utils/common.mjs +463 -0
- package/dist/esm/llm/google/utils/common.mjs.map +1 -0
- package/dist/esm/run.mjs +4 -3
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +5 -2
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/utils/title.mjs +25 -20
- package/dist/esm/utils/title.mjs.map +1 -1
- package/dist/types/common/enum.d.ts +5 -3
- package/dist/types/graphs/Graph.d.ts +3 -2
- package/dist/types/llm/google/index.d.ts +10 -5
- 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/run.d.ts +1 -1
- package/dist/types/scripts/args.d.ts +2 -1
- package/dist/types/types/llm.d.ts +2 -0
- package/dist/types/types/run.d.ts +1 -0
- package/dist/types/types/stream.d.ts +5 -0
- package/package.json +1 -1
- package/src/common/enum.ts +4 -2
- package/src/graphs/Graph.ts +16 -11
- package/src/llm/google/index.ts +118 -8
- package/src/llm/google/types.ts +43 -0
- package/src/llm/google/utils/common.ts +632 -0
- package/src/llm/google/utils/tools.ts +160 -0
- package/src/llm/google/utils/zod_to_genai_parameters.ts +88 -0
- package/src/run.ts +4 -2
- package/src/scripts/args.ts +12 -8
- package/src/scripts/code_exec.ts +49 -18
- package/src/scripts/code_exec_files.ts +48 -17
- package/src/scripts/image.ts +52 -20
- package/src/scripts/simple.ts +1 -0
- package/src/specs/anthropic.simple.test.ts +88 -31
- package/src/specs/openai.simple.test.ts +88 -31
- package/src/stream.ts +5 -2
- package/src/types/llm.ts +2 -0
- package/src/types/run.ts +1 -0
- package/src/types/stream.ts +6 -0
- package/src/utils/llmConfig.ts +2 -2
- package/src/utils/title.ts +44 -27
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
|
+
});
|
package/src/scripts/simple.ts
CHANGED
|
@@ -160,6 +160,7 @@ async function testStandardStreaming(): Promise<void> {
|
|
|
160
160
|
console.dir(contentParts, { depth: null });
|
|
161
161
|
const { handleLLMEnd, collected } = createMetadataAggregator();
|
|
162
162
|
const titleOptions: t.RunTitleOptions = {
|
|
163
|
+
provider,
|
|
163
164
|
inputText: userMessage,
|
|
164
165
|
contentParts,
|
|
165
166
|
chainOptions: {
|
|
@@ -4,10 +4,18 @@
|
|
|
4
4
|
import { config } from 'dotenv';
|
|
5
5
|
config();
|
|
6
6
|
import { Calculator } from '@langchain/community/tools/calculator';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
HumanMessage,
|
|
9
|
+
BaseMessage,
|
|
10
|
+
UsageMetadata,
|
|
11
|
+
} from '@langchain/core/messages';
|
|
8
12
|
import type { StandardGraph } from '@/graphs';
|
|
9
13
|
import type * as t from '@/types';
|
|
10
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
ToolEndHandler,
|
|
16
|
+
ModelEndHandler,
|
|
17
|
+
createMetadataAggregator,
|
|
18
|
+
} from '@/events';
|
|
11
19
|
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
12
20
|
import { ContentTypes, GraphEvents, Providers } from '@/common';
|
|
13
21
|
import { capitalizeFirstLetter } from './spec.utils';
|
|
@@ -36,7 +44,8 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
36
44
|
beforeEach(async () => {
|
|
37
45
|
conversationHistory = [];
|
|
38
46
|
collectedUsage = [];
|
|
39
|
-
const { contentParts: cp, aggregateContent: ac } =
|
|
47
|
+
const { contentParts: cp, aggregateContent: ac } =
|
|
48
|
+
createContentAggregator();
|
|
40
49
|
contentParts = cp as t.MessageContentComplex[];
|
|
41
50
|
aggregateContent = ac;
|
|
42
51
|
});
|
|
@@ -49,36 +58,62 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
49
58
|
onRunStepSpy.mockReset();
|
|
50
59
|
});
|
|
51
60
|
|
|
52
|
-
const setupCustomHandlers = (): Record<
|
|
61
|
+
const setupCustomHandlers = (): Record<
|
|
62
|
+
string | GraphEvents,
|
|
63
|
+
t.EventHandler
|
|
64
|
+
> => ({
|
|
53
65
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
54
66
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
55
67
|
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
56
68
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
57
|
-
handle: (
|
|
58
|
-
|
|
59
|
-
|
|
69
|
+
handle: (
|
|
70
|
+
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
71
|
+
data: t.StreamEventData
|
|
72
|
+
): void => {
|
|
73
|
+
aggregateContent({
|
|
74
|
+
event,
|
|
75
|
+
data: data as unknown as { result: t.ToolEndEvent },
|
|
76
|
+
});
|
|
77
|
+
},
|
|
60
78
|
},
|
|
61
79
|
[GraphEvents.ON_RUN_STEP]: {
|
|
62
|
-
handle: (
|
|
80
|
+
handle: (
|
|
81
|
+
event: GraphEvents.ON_RUN_STEP,
|
|
82
|
+
data: t.StreamEventData,
|
|
83
|
+
metadata,
|
|
84
|
+
graph
|
|
85
|
+
): void => {
|
|
63
86
|
onRunStepSpy(event, data, metadata, graph);
|
|
64
87
|
aggregateContent({ event, data: data as t.RunStep });
|
|
65
|
-
}
|
|
88
|
+
},
|
|
66
89
|
},
|
|
67
90
|
[GraphEvents.ON_RUN_STEP_DELTA]: {
|
|
68
|
-
handle: (
|
|
91
|
+
handle: (
|
|
92
|
+
event: GraphEvents.ON_RUN_STEP_DELTA,
|
|
93
|
+
data: t.StreamEventData
|
|
94
|
+
): void => {
|
|
69
95
|
aggregateContent({ event, data: data as t.RunStepDeltaEvent });
|
|
70
|
-
}
|
|
96
|
+
},
|
|
71
97
|
},
|
|
72
98
|
[GraphEvents.ON_MESSAGE_DELTA]: {
|
|
73
|
-
handle: (
|
|
99
|
+
handle: (
|
|
100
|
+
event: GraphEvents.ON_MESSAGE_DELTA,
|
|
101
|
+
data: t.StreamEventData,
|
|
102
|
+
metadata,
|
|
103
|
+
graph
|
|
104
|
+
): void => {
|
|
74
105
|
onMessageDeltaSpy(event, data, metadata, graph);
|
|
75
106
|
aggregateContent({ event, data: data as t.MessageDeltaEvent });
|
|
76
|
-
}
|
|
107
|
+
},
|
|
77
108
|
},
|
|
78
109
|
[GraphEvents.TOOL_START]: {
|
|
79
|
-
handle: (
|
|
110
|
+
handle: (
|
|
111
|
+
_event: string,
|
|
112
|
+
_data: t.StreamEventData,
|
|
113
|
+
_metadata?: Record<string, unknown>
|
|
114
|
+
): void => {
|
|
80
115
|
// Handle tool start
|
|
81
|
-
}
|
|
116
|
+
},
|
|
82
117
|
},
|
|
83
118
|
});
|
|
84
119
|
|
|
@@ -93,7 +128,8 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
93
128
|
type: 'standard',
|
|
94
129
|
llmConfig,
|
|
95
130
|
tools: [new Calculator()],
|
|
96
|
-
instructions:
|
|
131
|
+
instructions:
|
|
132
|
+
'You are a friendly AI assistant. Always address the user by their name.',
|
|
97
133
|
additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
|
|
98
134
|
},
|
|
99
135
|
returnContent: true,
|
|
@@ -109,7 +145,9 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
109
145
|
|
|
110
146
|
const finalContentParts = await run.processStream(inputs, config);
|
|
111
147
|
expect(finalContentParts).toBeDefined();
|
|
112
|
-
const allTextParts = finalContentParts?.every(
|
|
148
|
+
const allTextParts = finalContentParts?.every(
|
|
149
|
+
(part) => part.type === ContentTypes.TEXT
|
|
150
|
+
);
|
|
113
151
|
expect(allTextParts).toBe(true);
|
|
114
152
|
expect(collectedUsage.length).toBeGreaterThan(0);
|
|
115
153
|
expect(collectedUsage[0].input_tokens).toBeGreaterThan(0);
|
|
@@ -117,26 +155,33 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
117
155
|
|
|
118
156
|
const finalMessages = run.getRunMessages();
|
|
119
157
|
expect(finalMessages).toBeDefined();
|
|
120
|
-
conversationHistory.push(...finalMessages ?? []);
|
|
158
|
+
conversationHistory.push(...(finalMessages ?? []));
|
|
121
159
|
expect(conversationHistory.length).toBeGreaterThan(1);
|
|
122
160
|
runningHistory = conversationHistory.slice();
|
|
123
161
|
|
|
124
162
|
expect(onMessageDeltaSpy).toHaveBeenCalled();
|
|
125
163
|
expect(onMessageDeltaSpy.mock.calls.length).toBeGreaterThan(1);
|
|
126
|
-
expect(
|
|
164
|
+
expect(
|
|
165
|
+
(onMessageDeltaSpy.mock.calls[0][3] as StandardGraph).provider
|
|
166
|
+
).toBeDefined();
|
|
127
167
|
|
|
128
168
|
expect(onRunStepSpy).toHaveBeenCalled();
|
|
129
169
|
expect(onRunStepSpy.mock.calls.length).toBeGreaterThan(0);
|
|
130
|
-
expect(
|
|
170
|
+
expect(
|
|
171
|
+
(onRunStepSpy.mock.calls[0][3] as StandardGraph).provider
|
|
172
|
+
).toBeDefined();
|
|
131
173
|
|
|
132
174
|
const { handleLLMEnd, collected } = createMetadataAggregator();
|
|
133
175
|
const titleResult = await run.generateTitle({
|
|
176
|
+
provider,
|
|
134
177
|
inputText: userMessage,
|
|
135
178
|
contentParts,
|
|
136
179
|
chainOptions: {
|
|
137
|
-
callbacks: [
|
|
138
|
-
|
|
139
|
-
|
|
180
|
+
callbacks: [
|
|
181
|
+
{
|
|
182
|
+
handleLLMEnd,
|
|
183
|
+
},
|
|
184
|
+
],
|
|
140
185
|
},
|
|
141
186
|
});
|
|
142
187
|
|
|
@@ -148,7 +193,10 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
148
193
|
|
|
149
194
|
test(`${capitalizeFirstLetter(provider)}: should follow-up`, async () => {
|
|
150
195
|
console.log('Previous conversation length:', runningHistory.length);
|
|
151
|
-
console.log(
|
|
196
|
+
console.log(
|
|
197
|
+
'Last message:',
|
|
198
|
+
runningHistory[runningHistory.length - 1].content
|
|
199
|
+
);
|
|
152
200
|
const { userName, location } = await getArgs();
|
|
153
201
|
const llmConfig = getLLMConfig(provider);
|
|
154
202
|
const customHandlers = setupCustomHandlers();
|
|
@@ -159,7 +207,8 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
159
207
|
type: 'standard',
|
|
160
208
|
llmConfig,
|
|
161
209
|
tools: [new Calculator()],
|
|
162
|
-
instructions:
|
|
210
|
+
instructions:
|
|
211
|
+
'You are a friendly AI assistant. Always address the user by their name.',
|
|
163
212
|
additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
|
|
164
213
|
},
|
|
165
214
|
returnContent: true,
|
|
@@ -175,7 +224,9 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
175
224
|
|
|
176
225
|
const finalContentParts = await run.processStream(inputs, config);
|
|
177
226
|
expect(finalContentParts).toBeDefined();
|
|
178
|
-
const allTextParts = finalContentParts?.every(
|
|
227
|
+
const allTextParts = finalContentParts?.every(
|
|
228
|
+
(part) => part.type === ContentTypes.TEXT
|
|
229
|
+
);
|
|
179
230
|
expect(allTextParts).toBe(true);
|
|
180
231
|
expect(collectedUsage.length).toBeGreaterThan(0);
|
|
181
232
|
expect(collectedUsage[0].input_tokens).toBeGreaterThan(0);
|
|
@@ -184,7 +235,10 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
184
235
|
const finalMessages = run.getRunMessages();
|
|
185
236
|
expect(finalMessages).toBeDefined();
|
|
186
237
|
expect(finalMessages?.length).toBeGreaterThan(0);
|
|
187
|
-
console.log(
|
|
238
|
+
console.log(
|
|
239
|
+
`${capitalizeFirstLetter(provider)} follow-up message:`,
|
|
240
|
+
finalMessages?.[finalMessages.length - 1]?.content
|
|
241
|
+
);
|
|
188
242
|
|
|
189
243
|
expect(onMessageDeltaSpy).toHaveBeenCalled();
|
|
190
244
|
expect(onMessageDeltaSpy.mock.calls.length).toBeGreaterThan(1);
|
|
@@ -196,9 +250,12 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
196
250
|
test('should handle errors appropriately', async () => {
|
|
197
251
|
// Test error scenarios
|
|
198
252
|
await expect(async () => {
|
|
199
|
-
await run.processStream(
|
|
200
|
-
|
|
201
|
-
|
|
253
|
+
await run.processStream(
|
|
254
|
+
{
|
|
255
|
+
messages: [],
|
|
256
|
+
},
|
|
257
|
+
{} as any
|
|
258
|
+
);
|
|
202
259
|
}).rejects.toThrow();
|
|
203
260
|
});
|
|
204
|
-
});
|
|
261
|
+
});
|
|
@@ -4,10 +4,18 @@
|
|
|
4
4
|
import { config } from 'dotenv';
|
|
5
5
|
config();
|
|
6
6
|
import { Calculator } from '@langchain/community/tools/calculator';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
HumanMessage,
|
|
9
|
+
BaseMessage,
|
|
10
|
+
UsageMetadata,
|
|
11
|
+
} from '@langchain/core/messages';
|
|
8
12
|
import type { StandardGraph } from '@/graphs';
|
|
9
13
|
import type * as t from '@/types';
|
|
10
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
ToolEndHandler,
|
|
16
|
+
ModelEndHandler,
|
|
17
|
+
createMetadataAggregator,
|
|
18
|
+
} from '@/events';
|
|
11
19
|
import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
|
|
12
20
|
import { ContentTypes, GraphEvents, Providers } from '@/common';
|
|
13
21
|
import { capitalizeFirstLetter } from './spec.utils';
|
|
@@ -36,7 +44,8 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
36
44
|
beforeEach(async () => {
|
|
37
45
|
conversationHistory = [];
|
|
38
46
|
collectedUsage = [];
|
|
39
|
-
const { contentParts: cp, aggregateContent: ac } =
|
|
47
|
+
const { contentParts: cp, aggregateContent: ac } =
|
|
48
|
+
createContentAggregator();
|
|
40
49
|
contentParts = cp as t.MessageContentComplex[];
|
|
41
50
|
aggregateContent = ac;
|
|
42
51
|
});
|
|
@@ -49,36 +58,62 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
49
58
|
onRunStepSpy.mockReset();
|
|
50
59
|
});
|
|
51
60
|
|
|
52
|
-
const setupCustomHandlers = (): Record<
|
|
61
|
+
const setupCustomHandlers = (): Record<
|
|
62
|
+
string | GraphEvents,
|
|
63
|
+
t.EventHandler
|
|
64
|
+
> => ({
|
|
53
65
|
[GraphEvents.TOOL_END]: new ToolEndHandler(),
|
|
54
66
|
[GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(collectedUsage),
|
|
55
67
|
[GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
|
|
56
68
|
[GraphEvents.ON_RUN_STEP_COMPLETED]: {
|
|
57
|
-
handle: (
|
|
58
|
-
|
|
59
|
-
|
|
69
|
+
handle: (
|
|
70
|
+
event: GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
71
|
+
data: t.StreamEventData
|
|
72
|
+
): void => {
|
|
73
|
+
aggregateContent({
|
|
74
|
+
event,
|
|
75
|
+
data: data as unknown as { result: t.ToolEndEvent },
|
|
76
|
+
});
|
|
77
|
+
},
|
|
60
78
|
},
|
|
61
79
|
[GraphEvents.ON_RUN_STEP]: {
|
|
62
|
-
handle: (
|
|
80
|
+
handle: (
|
|
81
|
+
event: GraphEvents.ON_RUN_STEP,
|
|
82
|
+
data: t.StreamEventData,
|
|
83
|
+
metadata,
|
|
84
|
+
graph
|
|
85
|
+
): void => {
|
|
63
86
|
onRunStepSpy(event, data, metadata, graph);
|
|
64
87
|
aggregateContent({ event, data: data as t.RunStep });
|
|
65
|
-
}
|
|
88
|
+
},
|
|
66
89
|
},
|
|
67
90
|
[GraphEvents.ON_RUN_STEP_DELTA]: {
|
|
68
|
-
handle: (
|
|
91
|
+
handle: (
|
|
92
|
+
event: GraphEvents.ON_RUN_STEP_DELTA,
|
|
93
|
+
data: t.StreamEventData
|
|
94
|
+
): void => {
|
|
69
95
|
aggregateContent({ event, data: data as t.RunStepDeltaEvent });
|
|
70
|
-
}
|
|
96
|
+
},
|
|
71
97
|
},
|
|
72
98
|
[GraphEvents.ON_MESSAGE_DELTA]: {
|
|
73
|
-
handle: (
|
|
99
|
+
handle: (
|
|
100
|
+
event: GraphEvents.ON_MESSAGE_DELTA,
|
|
101
|
+
data: t.StreamEventData,
|
|
102
|
+
metadata,
|
|
103
|
+
graph
|
|
104
|
+
): void => {
|
|
74
105
|
onMessageDeltaSpy(event, data, metadata, graph);
|
|
75
106
|
aggregateContent({ event, data: data as t.MessageDeltaEvent });
|
|
76
|
-
}
|
|
107
|
+
},
|
|
77
108
|
},
|
|
78
109
|
[GraphEvents.TOOL_START]: {
|
|
79
|
-
handle: (
|
|
110
|
+
handle: (
|
|
111
|
+
_event: string,
|
|
112
|
+
_data: t.StreamEventData,
|
|
113
|
+
_metadata?: Record<string, unknown>
|
|
114
|
+
): void => {
|
|
80
115
|
// Handle tool start
|
|
81
|
-
}
|
|
116
|
+
},
|
|
82
117
|
},
|
|
83
118
|
});
|
|
84
119
|
|
|
@@ -93,7 +128,8 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
93
128
|
type: 'standard',
|
|
94
129
|
llmConfig,
|
|
95
130
|
tools: [new Calculator()],
|
|
96
|
-
instructions:
|
|
131
|
+
instructions:
|
|
132
|
+
'You are a friendly AI assistant. Always address the user by their name.',
|
|
97
133
|
additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
|
|
98
134
|
},
|
|
99
135
|
returnContent: true,
|
|
@@ -109,7 +145,9 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
109
145
|
|
|
110
146
|
const finalContentParts = await run.processStream(inputs, config);
|
|
111
147
|
expect(finalContentParts).toBeDefined();
|
|
112
|
-
const allTextParts = finalContentParts?.every(
|
|
148
|
+
const allTextParts = finalContentParts?.every(
|
|
149
|
+
(part) => part.type === ContentTypes.TEXT
|
|
150
|
+
);
|
|
113
151
|
expect(allTextParts).toBe(true);
|
|
114
152
|
expect(collectedUsage.length).toBeGreaterThan(0);
|
|
115
153
|
expect(collectedUsage[0].input_tokens).toBeGreaterThan(0);
|
|
@@ -117,26 +155,33 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
117
155
|
|
|
118
156
|
const finalMessages = run.getRunMessages();
|
|
119
157
|
expect(finalMessages).toBeDefined();
|
|
120
|
-
conversationHistory.push(...finalMessages ?? []);
|
|
158
|
+
conversationHistory.push(...(finalMessages ?? []));
|
|
121
159
|
expect(conversationHistory.length).toBeGreaterThan(1);
|
|
122
160
|
runningHistory = conversationHistory.slice();
|
|
123
161
|
|
|
124
162
|
expect(onMessageDeltaSpy).toHaveBeenCalled();
|
|
125
163
|
expect(onMessageDeltaSpy.mock.calls.length).toBeGreaterThan(1);
|
|
126
|
-
expect(
|
|
164
|
+
expect(
|
|
165
|
+
(onMessageDeltaSpy.mock.calls[0][3] as StandardGraph).provider
|
|
166
|
+
).toBeDefined();
|
|
127
167
|
|
|
128
168
|
expect(onRunStepSpy).toHaveBeenCalled();
|
|
129
169
|
expect(onRunStepSpy.mock.calls.length).toBeGreaterThan(0);
|
|
130
|
-
expect(
|
|
170
|
+
expect(
|
|
171
|
+
(onRunStepSpy.mock.calls[0][3] as StandardGraph).provider
|
|
172
|
+
).toBeDefined();
|
|
131
173
|
|
|
132
174
|
const { handleLLMEnd, collected } = createMetadataAggregator();
|
|
133
175
|
const titleResult = await run.generateTitle({
|
|
176
|
+
provider,
|
|
134
177
|
inputText: userMessage,
|
|
135
178
|
contentParts,
|
|
136
179
|
chainOptions: {
|
|
137
|
-
callbacks: [
|
|
138
|
-
|
|
139
|
-
|
|
180
|
+
callbacks: [
|
|
181
|
+
{
|
|
182
|
+
handleLLMEnd,
|
|
183
|
+
},
|
|
184
|
+
],
|
|
140
185
|
},
|
|
141
186
|
});
|
|
142
187
|
|
|
@@ -148,7 +193,10 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
148
193
|
|
|
149
194
|
test(`${capitalizeFirstLetter(provider)}: should follow-up`, async () => {
|
|
150
195
|
console.log('Previous conversation length:', runningHistory.length);
|
|
151
|
-
console.log(
|
|
196
|
+
console.log(
|
|
197
|
+
'Last message:',
|
|
198
|
+
runningHistory[runningHistory.length - 1].content
|
|
199
|
+
);
|
|
152
200
|
const { userName, location } = await getArgs();
|
|
153
201
|
const llmConfig = getLLMConfig(provider);
|
|
154
202
|
const customHandlers = setupCustomHandlers();
|
|
@@ -159,7 +207,8 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
159
207
|
type: 'standard',
|
|
160
208
|
llmConfig,
|
|
161
209
|
tools: [new Calculator()],
|
|
162
|
-
instructions:
|
|
210
|
+
instructions:
|
|
211
|
+
'You are a friendly AI assistant. Always address the user by their name.',
|
|
163
212
|
additional_instructions: `The user's name is ${userName} and they are located in ${location}.`,
|
|
164
213
|
},
|
|
165
214
|
returnContent: true,
|
|
@@ -175,7 +224,9 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
175
224
|
|
|
176
225
|
const finalContentParts = await run.processStream(inputs, config);
|
|
177
226
|
expect(finalContentParts).toBeDefined();
|
|
178
|
-
const allTextParts = finalContentParts?.every(
|
|
227
|
+
const allTextParts = finalContentParts?.every(
|
|
228
|
+
(part) => part.type === ContentTypes.TEXT
|
|
229
|
+
);
|
|
179
230
|
expect(allTextParts).toBe(true);
|
|
180
231
|
expect(collectedUsage.length).toBeGreaterThan(0);
|
|
181
232
|
expect(collectedUsage[0].input_tokens).toBeGreaterThan(0);
|
|
@@ -184,7 +235,10 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
184
235
|
const finalMessages = run.getRunMessages();
|
|
185
236
|
expect(finalMessages).toBeDefined();
|
|
186
237
|
expect(finalMessages?.length).toBeGreaterThan(0);
|
|
187
|
-
console.log(
|
|
238
|
+
console.log(
|
|
239
|
+
`${capitalizeFirstLetter(provider)} follow-up message:`,
|
|
240
|
+
finalMessages?.[finalMessages.length - 1]?.content
|
|
241
|
+
);
|
|
188
242
|
|
|
189
243
|
expect(onMessageDeltaSpy).toHaveBeenCalled();
|
|
190
244
|
expect(onMessageDeltaSpy.mock.calls.length).toBeGreaterThan(1);
|
|
@@ -196,9 +250,12 @@ describe(`${capitalizeFirstLetter(provider)} Streaming Tests`, () => {
|
|
|
196
250
|
test('should handle errors appropriately', async () => {
|
|
197
251
|
// Test error scenarios
|
|
198
252
|
await expect(async () => {
|
|
199
|
-
await run.processStream(
|
|
200
|
-
|
|
201
|
-
|
|
253
|
+
await run.processStream(
|
|
254
|
+
{
|
|
255
|
+
messages: [],
|
|
256
|
+
},
|
|
257
|
+
{} as any
|
|
258
|
+
);
|
|
202
259
|
}).rejects.toThrow();
|
|
203
260
|
});
|
|
204
|
-
});
|
|
261
|
+
});
|
package/src/stream.ts
CHANGED
|
@@ -244,6 +244,7 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
244
244
|
content.every(
|
|
245
245
|
(c) =>
|
|
246
246
|
(c.type?.startsWith(ContentTypes.THINKING) ?? false) ||
|
|
247
|
+
(c.type?.startsWith(ContentTypes.REASONING) ?? false) ||
|
|
247
248
|
(c.type?.startsWith(ContentTypes.REASONING_CONTENT) ?? false)
|
|
248
249
|
)
|
|
249
250
|
) {
|
|
@@ -252,6 +253,7 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
252
253
|
type: ContentTypes.THINK,
|
|
253
254
|
think:
|
|
254
255
|
(c as t.ThinkingContentText).thinking ??
|
|
256
|
+
(c as Partial<t.GoogleReasoningContentText>).reasoning ??
|
|
255
257
|
(c as Partial<t.BedrockReasoningContentText>).reasoningText?.text ??
|
|
256
258
|
'',
|
|
257
259
|
})),
|
|
@@ -264,8 +266,9 @@ hasToolCallChunks: ${hasToolCallChunks}
|
|
|
264
266
|
| undefined;
|
|
265
267
|
if (
|
|
266
268
|
Array.isArray(chunk.content) &&
|
|
267
|
-
(chunk.content[0]?.type ===
|
|
268
|
-
chunk.content[0]?.type ===
|
|
269
|
+
(chunk.content[0]?.type === ContentTypes.THINKING ||
|
|
270
|
+
chunk.content[0]?.type === ContentTypes.REASONING ||
|
|
271
|
+
chunk.content[0]?.type === ContentTypes.REASONING_CONTENT)
|
|
269
272
|
) {
|
|
270
273
|
reasoning_content = 'valid';
|
|
271
274
|
}
|
package/src/types/llm.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
} from '@langchain/openai';
|
|
18
18
|
import type { BedrockChatFields } from '@langchain/community/chat_models/bedrock/web';
|
|
19
19
|
import type { GoogleGenerativeAIChatInput } from '@langchain/google-genai';
|
|
20
|
+
import type { GeminiGenerationConfig } from '@langchain/google-common';
|
|
20
21
|
import type { ChatVertexAIInput } from '@langchain/google-vertexai';
|
|
21
22
|
import type { ChatDeepSeekCallOptions } from '@langchain/deepseek';
|
|
22
23
|
import type { ChatOpenRouterCallOptions } from '@/llm/openrouter';
|
|
@@ -70,6 +71,7 @@ export type BedrockAnthropicInput = ChatBedrockConverseInput & {
|
|
|
70
71
|
export type BedrockConverseClientOptions = ChatBedrockConverseInput;
|
|
71
72
|
export type GoogleClientOptions = GoogleGenerativeAIChatInput & {
|
|
72
73
|
customHeaders?: RequestOptions['customHeaders'];
|
|
74
|
+
thinkingConfig?: GeminiGenerationConfig['thinkingConfig'];
|
|
73
75
|
};
|
|
74
76
|
export type DeepSeekClientOptions = ChatDeepSeekCallOptions;
|
|
75
77
|
export type XAIClientOptions = ChatXAIInput;
|
package/src/types/run.ts
CHANGED
package/src/types/stream.ts
CHANGED
|
@@ -251,6 +251,12 @@ export type ReasoningContentText = {
|
|
|
251
251
|
think: string;
|
|
252
252
|
};
|
|
253
253
|
|
|
254
|
+
/** Vertex AI / Google Common - Reasoning Content Block Format */
|
|
255
|
+
export type GoogleReasoningContentText = {
|
|
256
|
+
type: ContentTypes.REASONING;
|
|
257
|
+
reasoning: string;
|
|
258
|
+
};
|
|
259
|
+
|
|
254
260
|
/** Anthropic's Reasoning Content Block Format */
|
|
255
261
|
export type ThinkingContentText = {
|
|
256
262
|
type: ContentTypes.THINKING;
|