@librechat/agents 2.3.93 → 2.3.95
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 +64 -31
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +36 -16
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/run.cjs +42 -18
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +64 -31
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +36 -16
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/run.mjs +42 -18
- package/dist/esm/run.mjs.map +1 -1
- package/dist/types/graphs/Graph.d.ts +1 -1
- package/dist/types/messages/format.d.ts +3 -3
- package/dist/types/run.d.ts +1 -8
- package/dist/types/types/run.d.ts +10 -0
- package/package.json +5 -4
- package/src/graphs/Graph.ts +229 -98
- package/src/messages/format.ts +97 -30
- package/src/messages/formatAgentMessages.test.ts +337 -49
- package/src/messages/formatAgentMessages.tools.test.ts +61 -10
- package/src/run.ts +117 -48
- package/src/scripts/simple.ts +71 -28
- package/src/types/run.ts +23 -4
package/src/messages/format.ts
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AIMessage,
|
|
4
|
+
ToolMessage,
|
|
5
|
+
BaseMessage,
|
|
6
|
+
HumanMessage,
|
|
7
|
+
SystemMessage,
|
|
8
|
+
getBufferString,
|
|
9
|
+
} from '@langchain/core/messages';
|
|
3
10
|
import type { MessageContentImageUrl } from '@langchain/core/messages';
|
|
4
11
|
import type { ToolCall } from '@langchain/core/messages/tool';
|
|
5
|
-
import type {
|
|
12
|
+
import type {
|
|
13
|
+
MessageContentComplex,
|
|
14
|
+
ToolCallPart,
|
|
15
|
+
TPayload,
|
|
16
|
+
TMessage,
|
|
17
|
+
} from '@/types';
|
|
6
18
|
import { Providers, ContentTypes } from '@/common';
|
|
7
19
|
|
|
8
20
|
interface VisionMessageParams {
|
|
@@ -22,7 +34,11 @@ interface VisionMessageParams {
|
|
|
22
34
|
* @param {VisionMessageParams} params - The parameters for formatting.
|
|
23
35
|
* @returns {Object} - The formatted message.
|
|
24
36
|
*/
|
|
25
|
-
export const formatVisionMessage = ({
|
|
37
|
+
export const formatVisionMessage = ({
|
|
38
|
+
message,
|
|
39
|
+
image_urls,
|
|
40
|
+
endpoint,
|
|
41
|
+
}: VisionMessageParams): {
|
|
26
42
|
role: string;
|
|
27
43
|
content: MessageContentComplex[];
|
|
28
44
|
name?: string;
|
|
@@ -36,20 +52,20 @@ export const formatVisionMessage = ({ message, image_urls, endpoint }: VisionMes
|
|
|
36
52
|
[key: string]: any;
|
|
37
53
|
} = {
|
|
38
54
|
...message,
|
|
39
|
-
content: [] as MessageContentComplex[]
|
|
55
|
+
content: [] as MessageContentComplex[],
|
|
40
56
|
};
|
|
41
57
|
|
|
42
58
|
if (endpoint === Providers.ANTHROPIC) {
|
|
43
59
|
result.content = [
|
|
44
60
|
...image_urls,
|
|
45
|
-
{ type: ContentTypes.TEXT, text: message.content }
|
|
61
|
+
{ type: ContentTypes.TEXT, text: message.content },
|
|
46
62
|
] as MessageContentComplex[];
|
|
47
63
|
return result;
|
|
48
64
|
}
|
|
49
65
|
|
|
50
66
|
result.content = [
|
|
51
67
|
{ type: ContentTypes.TEXT, text: message.content },
|
|
52
|
-
...image_urls
|
|
68
|
+
...image_urls,
|
|
53
69
|
] as MessageContentComplex[];
|
|
54
70
|
|
|
55
71
|
return result;
|
|
@@ -92,8 +108,12 @@ export const formatMessage = ({
|
|
|
92
108
|
userName,
|
|
93
109
|
assistantName,
|
|
94
110
|
endpoint,
|
|
95
|
-
langChain = false
|
|
96
|
-
}: FormatMessageParams):
|
|
111
|
+
langChain = false,
|
|
112
|
+
}: FormatMessageParams):
|
|
113
|
+
| FormattedMessage
|
|
114
|
+
| HumanMessage
|
|
115
|
+
| AIMessage
|
|
116
|
+
| SystemMessage => {
|
|
97
117
|
// eslint-disable-next-line prefer-const
|
|
98
118
|
let { role: _role, _name, sender, text, content: _content, lc_id } = message;
|
|
99
119
|
if (lc_id && lc_id[2] && !langChain) {
|
|
@@ -104,7 +124,11 @@ export const formatMessage = ({
|
|
|
104
124
|
};
|
|
105
125
|
_role = roleMapping[lc_id[2]] || _role;
|
|
106
126
|
}
|
|
107
|
-
const role =
|
|
127
|
+
const role =
|
|
128
|
+
_role ??
|
|
129
|
+
(sender != null && sender && sender.toLowerCase() === 'user'
|
|
130
|
+
? 'user'
|
|
131
|
+
: 'assistant');
|
|
108
132
|
const content = _content ?? text ?? '';
|
|
109
133
|
const formattedMessage: FormattedMessage = {
|
|
110
134
|
role,
|
|
@@ -116,7 +140,10 @@ export const formatMessage = ({
|
|
|
116
140
|
return formatVisionMessage({
|
|
117
141
|
message: {
|
|
118
142
|
...formattedMessage,
|
|
119
|
-
content:
|
|
143
|
+
content:
|
|
144
|
+
typeof formattedMessage.content === 'string'
|
|
145
|
+
? formattedMessage.content
|
|
146
|
+
: '',
|
|
120
147
|
},
|
|
121
148
|
image_urls,
|
|
122
149
|
endpoint,
|
|
@@ -131,14 +158,21 @@ export const formatMessage = ({
|
|
|
131
158
|
formattedMessage.name = userName;
|
|
132
159
|
}
|
|
133
160
|
|
|
134
|
-
if (
|
|
161
|
+
if (
|
|
162
|
+
assistantName != null &&
|
|
163
|
+
assistantName &&
|
|
164
|
+
formattedMessage.role === 'assistant'
|
|
165
|
+
) {
|
|
135
166
|
formattedMessage.name = assistantName;
|
|
136
167
|
}
|
|
137
168
|
|
|
138
169
|
if (formattedMessage.name != null && formattedMessage.name) {
|
|
139
170
|
// Conform to API regex: ^[a-zA-Z0-9_-]{1,64}$
|
|
140
171
|
// https://community.openai.com/t/the-format-of-the-name-field-in-the-documentation-is-incorrect/175684/2
|
|
141
|
-
formattedMessage.name = formattedMessage.name.replace(
|
|
172
|
+
formattedMessage.name = formattedMessage.name.replace(
|
|
173
|
+
/[^a-zA-Z0-9_-]/g,
|
|
174
|
+
'_'
|
|
175
|
+
);
|
|
142
176
|
|
|
143
177
|
if (formattedMessage.name.length > 64) {
|
|
144
178
|
formattedMessage.name = formattedMessage.name.substring(0, 64);
|
|
@@ -170,7 +204,11 @@ export const formatLangChainMessages = (
|
|
|
170
204
|
formatOptions: Omit<FormatMessageParams, 'message' | 'langChain'>
|
|
171
205
|
): Array<HumanMessage | AIMessage | SystemMessage> => {
|
|
172
206
|
return messages.map((msg) => {
|
|
173
|
-
const formatted = formatMessage({
|
|
207
|
+
const formatted = formatMessage({
|
|
208
|
+
...formatOptions,
|
|
209
|
+
message: msg,
|
|
210
|
+
langChain: true,
|
|
211
|
+
});
|
|
174
212
|
return formatted as HumanMessage | AIMessage | SystemMessage;
|
|
175
213
|
});
|
|
176
214
|
};
|
|
@@ -193,7 +231,9 @@ interface LangChainMessage {
|
|
|
193
231
|
* @param {LangChainMessage} message - The message object to format.
|
|
194
232
|
* @returns {Record<string, any>} The formatted LangChain message.
|
|
195
233
|
*/
|
|
196
|
-
export const formatFromLangChain = (
|
|
234
|
+
export const formatFromLangChain = (
|
|
235
|
+
message: LangChainMessage
|
|
236
|
+
): Record<string, any> => {
|
|
197
237
|
const kwargs = message.lc_kwargs ?? message.kwargs ?? {};
|
|
198
238
|
const { additional_kwargs = {}, ...message_kwargs } = kwargs;
|
|
199
239
|
return {
|
|
@@ -207,7 +247,9 @@ export const formatFromLangChain = (message: LangChainMessage): Record<string, a
|
|
|
207
247
|
* @param message The message to format
|
|
208
248
|
* @returns Array of formatted messages
|
|
209
249
|
*/
|
|
210
|
-
function formatAssistantMessage(
|
|
250
|
+
function formatAssistantMessage(
|
|
251
|
+
message: Partial<TMessage>
|
|
252
|
+
): Array<AIMessage | ToolMessage> {
|
|
211
253
|
const formattedMessages: Array<AIMessage | ToolMessage> = [];
|
|
212
254
|
let currentContent: MessageContentComplex[] = [];
|
|
213
255
|
let lastAIMessage: AIMessage | null = null;
|
|
@@ -227,7 +269,8 @@ function formatAssistantMessage(message: Partial<TMessage>): Array<AIMessage | T
|
|
|
227
269
|
}
|
|
228
270
|
return acc;
|
|
229
271
|
}, '');
|
|
230
|
-
content =
|
|
272
|
+
content =
|
|
273
|
+
`${content}\n${part[ContentTypes.TEXT] ?? part.text ?? ''}`.trim();
|
|
231
274
|
lastAIMessage = new AIMessage({ content });
|
|
232
275
|
formattedMessages.push(lastAIMessage);
|
|
233
276
|
currentContent = [];
|
|
@@ -240,11 +283,17 @@ function formatAssistantMessage(message: Partial<TMessage>): Array<AIMessage | T
|
|
|
240
283
|
formattedMessages.push(lastAIMessage);
|
|
241
284
|
} else if (part.type === ContentTypes.TOOL_CALL) {
|
|
242
285
|
if (!lastAIMessage) {
|
|
243
|
-
|
|
286
|
+
// "Heal" the payload by creating an AIMessage to precede the tool call
|
|
287
|
+
lastAIMessage = new AIMessage({ content: '' });
|
|
288
|
+
formattedMessages.push(lastAIMessage);
|
|
244
289
|
}
|
|
245
290
|
|
|
246
291
|
// Note: `tool_calls` list is defined when constructed by `AIMessage` class, and outputs should be excluded from it
|
|
247
|
-
const {
|
|
292
|
+
const {
|
|
293
|
+
output,
|
|
294
|
+
args: _args,
|
|
295
|
+
..._tool_call
|
|
296
|
+
} = part.tool_call as ToolCallPart;
|
|
248
297
|
const tool_call: ToolCallPart = _tool_call;
|
|
249
298
|
// TODO: investigate; args as dictionary may need to be providers-or-tool-specific
|
|
250
299
|
let args: any = _args;
|
|
@@ -269,12 +318,15 @@ function formatAssistantMessage(message: Partial<TMessage>): Array<AIMessage | T
|
|
|
269
318
|
tool_call_id: tool_call.id ?? '',
|
|
270
319
|
name: tool_call.name,
|
|
271
320
|
content: output || '',
|
|
272
|
-
})
|
|
321
|
+
})
|
|
273
322
|
);
|
|
274
323
|
} else if (part.type === ContentTypes.THINK) {
|
|
275
324
|
hasReasoning = true;
|
|
276
325
|
continue;
|
|
277
|
-
} else if (
|
|
326
|
+
} else if (
|
|
327
|
+
part.type === ContentTypes.ERROR ||
|
|
328
|
+
part.type === ContentTypes.AGENT_UPDATE
|
|
329
|
+
) {
|
|
278
330
|
continue;
|
|
279
331
|
} else {
|
|
280
332
|
currentContent.push(part);
|
|
@@ -318,7 +370,9 @@ export const formatAgentMessages = (
|
|
|
318
370
|
messages: Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>;
|
|
319
371
|
indexTokenCountMap?: Record<number, number>;
|
|
320
372
|
} => {
|
|
321
|
-
const messages: Array<
|
|
373
|
+
const messages: Array<
|
|
374
|
+
HumanMessage | AIMessage | SystemMessage | ToolMessage
|
|
375
|
+
> = [];
|
|
322
376
|
// If indexTokenCountMap is provided, create a new map to track the updated indices
|
|
323
377
|
const updatedIndexTokenCountMap: Record<number, number> = {};
|
|
324
378
|
// Keep track of the mapping from original payload indices to result indices
|
|
@@ -330,13 +384,17 @@ export const formatAgentMessages = (
|
|
|
330
384
|
// Q: Store the current length of messages to track where this payload message starts in the result?
|
|
331
385
|
// const startIndex = messages.length;
|
|
332
386
|
if (typeof message.content === 'string') {
|
|
333
|
-
message.content = [
|
|
387
|
+
message.content = [
|
|
388
|
+
{ type: ContentTypes.TEXT, [ContentTypes.TEXT]: message.content },
|
|
389
|
+
];
|
|
334
390
|
}
|
|
335
391
|
if (message.role !== 'assistant') {
|
|
336
|
-
messages.push(
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
392
|
+
messages.push(
|
|
393
|
+
formatMessage({
|
|
394
|
+
message: message as MessageInput,
|
|
395
|
+
langChain: true,
|
|
396
|
+
}) as HumanMessage | AIMessage | SystemMessage
|
|
397
|
+
);
|
|
340
398
|
|
|
341
399
|
// Update the index mapping for this message
|
|
342
400
|
indexMapping[i] = [messages.length - 1];
|
|
@@ -441,7 +499,11 @@ export const formatAgentMessages = (
|
|
|
441
499
|
|
|
442
500
|
// Update the token count map if it was provided
|
|
443
501
|
if (indexTokenCountMap) {
|
|
444
|
-
for (
|
|
502
|
+
for (
|
|
503
|
+
let originalIndex = 0;
|
|
504
|
+
originalIndex < payload.length;
|
|
505
|
+
originalIndex++
|
|
506
|
+
) {
|
|
445
507
|
const resultIndices = indexMapping[originalIndex] || [];
|
|
446
508
|
const tokenCount = indexTokenCountMap[originalIndex];
|
|
447
509
|
|
|
@@ -456,7 +518,8 @@ export const formatAgentMessages = (
|
|
|
456
518
|
resultIndices.forEach((resultIndex, idx) => {
|
|
457
519
|
if (idx === resultIndices.length - 1) {
|
|
458
520
|
// Give any remainder to the last message
|
|
459
|
-
updatedIndexTokenCountMap[resultIndex] =
|
|
521
|
+
updatedIndexTokenCountMap[resultIndex] =
|
|
522
|
+
tokenCount - countPerMessage * (resultIndices.length - 1);
|
|
460
523
|
} else {
|
|
461
524
|
updatedIndexTokenCountMap[resultIndex] = countPerMessage;
|
|
462
525
|
}
|
|
@@ -468,7 +531,9 @@ export const formatAgentMessages = (
|
|
|
468
531
|
|
|
469
532
|
return {
|
|
470
533
|
messages,
|
|
471
|
-
indexTokenCountMap: indexTokenCountMap
|
|
534
|
+
indexTokenCountMap: indexTokenCountMap
|
|
535
|
+
? updatedIndexTokenCountMap
|
|
536
|
+
: undefined,
|
|
472
537
|
};
|
|
473
538
|
};
|
|
474
539
|
|
|
@@ -477,7 +542,9 @@ export const formatAgentMessages = (
|
|
|
477
542
|
* @param {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} payload - The array of messages to format.
|
|
478
543
|
* @returns {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} - The array of formatted LangChain messages, including ToolMessages for tool calls.
|
|
479
544
|
*/
|
|
480
|
-
export const formatContentStrings = (
|
|
545
|
+
export const formatContentStrings = (
|
|
546
|
+
payload: Array<BaseMessage>
|
|
547
|
+
): Array<BaseMessage> => {
|
|
481
548
|
// Create a copy of the payload to avoid modifying the original
|
|
482
549
|
const result = [...payload];
|
|
483
550
|
|