@librechat/agents 2.4.41 → 2.4.42
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 +5 -6
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/run.cjs +4 -3
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/utils/title.cjs +25 -20
- package/dist/cjs/utils/title.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +5 -6
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/run.mjs +4 -3
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/utils/title.mjs +25 -20
- package/dist/esm/utils/title.mjs.map +1 -1
- package/dist/types/graphs/Graph.d.ts +3 -2
- package/dist/types/run.d.ts +1 -1
- package/dist/types/scripts/args.d.ts +2 -1
- package/dist/types/types/run.d.ts +1 -0
- package/package.json +1 -1
- package/src/graphs/Graph.ts +10 -9
- 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/types/run.ts +1 -0
- package/src/utils/title.ts +44 -27
|
@@ -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/types/run.ts
CHANGED
package/src/utils/title.ts
CHANGED
|
@@ -4,48 +4,65 @@ import { RunnableLambda } from '@langchain/core/runnables';
|
|
|
4
4
|
import type { Runnable } from '@langchain/core/runnables';
|
|
5
5
|
import * as t from '@/types';
|
|
6
6
|
|
|
7
|
-
const defaultTitlePrompt = `
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const languageInstructions = 'Detect the language used in the following text. Note: words may be misspelled or cut off; use context clues to identify the language:\n{text}';
|
|
7
|
+
const defaultTitlePrompt = `Analyze this conversation and provide:
|
|
8
|
+
1. The detected language of the conversation
|
|
9
|
+
2. A concise title in the detected language (5 words or less, no punctuation or quotation)
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
{convo}`;
|
|
13
12
|
|
|
14
|
-
const
|
|
15
|
-
|
|
13
|
+
const titleSchema = z.object({
|
|
14
|
+
title: z
|
|
15
|
+
.string()
|
|
16
|
+
.describe(
|
|
17
|
+
'A concise title for the conversation in 5 words or less, without punctuation or quotation'
|
|
18
|
+
),
|
|
16
19
|
});
|
|
17
20
|
|
|
18
|
-
const
|
|
19
|
-
|
|
21
|
+
const combinedSchema = z.object({
|
|
22
|
+
language: z.string().describe('The detected language of the conversation'),
|
|
23
|
+
title: z
|
|
24
|
+
.string()
|
|
25
|
+
.describe(
|
|
26
|
+
'A concise title for the conversation in 5 words or less, without punctuation or quotation'
|
|
27
|
+
),
|
|
20
28
|
});
|
|
21
29
|
|
|
22
|
-
export const createTitleRunnable = async (
|
|
30
|
+
export const createTitleRunnable = async (
|
|
31
|
+
model: t.ChatModelInstance,
|
|
32
|
+
_titlePrompt?: string
|
|
33
|
+
): Promise<Runnable> => {
|
|
23
34
|
// Disabled since this works fine
|
|
24
35
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
25
36
|
/* @ts-ignore */
|
|
26
|
-
const
|
|
37
|
+
const titleLLM = model.withStructuredOutput(titleSchema);
|
|
27
38
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
28
39
|
/* @ts-ignore */
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
const languageChain = languagePrompt.pipe(languageLLM);
|
|
40
|
+
const combinedLLM = model.withStructuredOutput(combinedSchema);
|
|
32
41
|
|
|
33
|
-
const titlePrompt = ChatPromptTemplate.fromTemplate(
|
|
42
|
+
const titlePrompt = ChatPromptTemplate.fromTemplate(
|
|
43
|
+
_titlePrompt ?? defaultTitlePrompt
|
|
44
|
+
);
|
|
34
45
|
|
|
35
46
|
return new RunnableLambda({
|
|
36
|
-
func: async (input: {
|
|
47
|
+
func: async (input: {
|
|
48
|
+
convo: string;
|
|
49
|
+
inputText: string;
|
|
50
|
+
skipLanguage: boolean;
|
|
51
|
+
}): Promise<{ language: string; title: string } | { title: string }> => {
|
|
37
52
|
if (input.skipLanguage) {
|
|
38
|
-
return await titlePrompt.pipe(titleLLM).invoke({
|
|
39
|
-
convo: input.convo
|
|
40
|
-
}) as { title: string };
|
|
53
|
+
return (await titlePrompt.pipe(titleLLM).invoke({
|
|
54
|
+
convo: input.convo,
|
|
55
|
+
})) as { title: string };
|
|
41
56
|
}
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
|
|
58
|
+
const result = (await titlePrompt.pipe(combinedLLM).invoke({
|
|
59
|
+
convo: input.convo,
|
|
60
|
+
})) as { language: string; title: string } | undefined;
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
language: result?.language ?? 'English',
|
|
64
|
+
title: result?.title ?? '',
|
|
65
|
+
};
|
|
49
66
|
},
|
|
50
67
|
});
|
|
51
|
-
};
|
|
68
|
+
};
|