@librechat/agents 3.3.2 → 3.3.4
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 +2 -1
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +342 -109
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +3 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +6 -0
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +79 -6
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +37 -10
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/google/utils/common.cjs +19 -7
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +64 -3
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +41 -5
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +25 -4
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs +4 -1
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +19 -2
- package/dist/cjs/messages/cache.cjs +54 -33
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/messages/contextPruning.cjs +17 -43
- package/dist/cjs/messages/contextPruning.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +315 -23
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +218 -60
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/index.cjs +1 -1
- package/dist/cjs/messages/prune.cjs +503 -127
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/stream.cjs +7 -3
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +28 -14
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +54 -41
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/toolOutputReferences.cjs +6 -0
- package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +1 -1
- package/dist/cjs/utils/llm.cjs +1 -1
- package/dist/cjs/utils/llm.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +307 -20
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/cjs/utils/toolContent.cjs +1514 -0
- package/dist/cjs/utils/toolContent.cjs.map +1 -0
- package/dist/esm/agents/AgentContext.mjs +2 -1
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +349 -116
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +3 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +6 -0
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +79 -6
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +37 -10
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/google/utils/common.mjs +19 -7
- package/dist/esm/llm/google/utils/common.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +65 -5
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +41 -5
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +25 -4
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs +4 -1
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/main.mjs +7 -7
- package/dist/esm/messages/cache.mjs +55 -34
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/messages/contextPruning.mjs +17 -43
- package/dist/esm/messages/contextPruning.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +305 -24
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +218 -61
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/index.mjs +1 -1
- package/dist/esm/messages/prune.mjs +500 -128
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/stream.mjs +7 -3
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +28 -14
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +54 -41
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/toolOutputReferences.mjs +6 -0
- package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +1 -1
- package/dist/esm/utils/llm.mjs +1 -1
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +307 -21
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/esm/utils/toolContent.mjs +1503 -0
- package/dist/esm/utils/toolContent.mjs.map +1 -0
- package/dist/types/graphs/Graph.d.ts +1 -1
- package/dist/types/llm/invoke.d.ts +27 -1
- package/dist/types/llm/openai/index.d.ts +4 -0
- package/dist/types/llm/openai/utils/index.d.ts +2 -0
- package/dist/types/llm/openrouter/index.d.ts +5 -0
- package/dist/types/messages/contextPruning.d.ts +2 -1
- package/dist/types/messages/core.d.ts +36 -0
- package/dist/types/messages/format.d.ts +6 -0
- package/dist/types/messages/prune.d.ts +16 -12
- package/dist/types/types/stream.d.ts +1 -1
- package/dist/types/utils/tokens.d.ts +7 -0
- package/dist/types/utils/toolContent.d.ts +107 -0
- package/package.json +13 -9
- package/src/__tests__/stream.eagerEventExecution.test.ts +74 -0
- package/src/agents/AgentContext.ts +1 -0
- package/src/graphs/Graph.ts +698 -200
- package/src/graphs/MultiAgentGraph.ts +6 -1
- package/src/graphs/__tests__/Graph.contextOverflow.test.ts +1128 -4
- package/src/langfuse.ts +15 -0
- package/src/llm/anthropic/utils/message_inputs.ts +158 -12
- package/src/llm/anthropic/utils/tool-id-normalization.test.ts +109 -0
- package/src/llm/bedrock/utils/message_inputs.test.ts +49 -1
- package/src/llm/bedrock/utils/message_inputs.ts +86 -13
- package/src/llm/google/utils/common.test.ts +75 -9
- package/src/llm/google/utils/common.ts +34 -3
- package/src/llm/invoke.test.ts +488 -0
- package/src/llm/invoke.ts +196 -2
- package/src/llm/openai/index.ts +106 -6
- package/src/llm/openai/utils/index.ts +109 -53
- package/src/llm/openai/utils/messages.test.ts +330 -1
- package/src/llm/openrouter/index.ts +12 -2
- package/src/llm/openrouter/reasoning.test.ts +314 -0
- package/src/messages/__tests__/observationMasking.test.ts +93 -2
- package/src/messages/cache.tail.test.ts +193 -0
- package/src/messages/cache.test.ts +113 -0
- package/src/messages/cache.ts +92 -60
- package/src/messages/contextPruning.test.ts +184 -0
- package/src/messages/contextPruning.ts +49 -42
- package/src/messages/core.ts +653 -40
- package/src/messages/ensureThinkingBlock.test.ts +49 -1
- package/src/messages/foldToollessToolBlocks.test.ts +163 -5
- package/src/messages/format.ts +363 -91
- package/src/messages/formatAgentMessages.test.ts +604 -14
- package/src/messages/formatAgentMessages.tools.test.ts +103 -0
- package/src/messages/prune.ts +996 -183
- package/src/specs/langfuse-callbacks.test.ts +203 -1
- package/src/specs/prune.test.ts +1083 -6
- package/src/specs/summarization-unit.test.ts +105 -0
- package/src/specs/tokens.test.ts +609 -32
- package/src/stream.ts +23 -15
- package/src/summarization/__tests__/node.test.ts +77 -0
- package/src/summarization/node.ts +46 -18
- package/src/tools/ToolNode.ts +147 -68
- package/src/tools/__tests__/ToolNode.onResultCompletion.test.ts +148 -1
- package/src/tools/__tests__/ToolNode.outputReferences.test.ts +112 -3
- package/src/tools/__tests__/annotateMessagesForLLM.test.ts +32 -0
- package/src/tools/__tests__/directToolHooks.test.ts +255 -7
- package/src/tools/toolOutputReferences.ts +6 -0
- package/src/types/stream.ts +1 -1
- package/src/utils/llm.test.ts +18 -0
- package/src/utils/llm.ts +4 -1
- package/src/utils/tokens.ts +586 -31
- package/src/utils/toolContent.test.ts +1432 -0
- package/src/utils/toolContent.ts +2707 -0
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { expect, test, describe } from '@jest/globals';
|
|
2
|
-
import { AIMessageChunk } from '@langchain/core/messages';
|
|
3
|
-
import type {
|
|
2
|
+
import { AIMessage, AIMessageChunk } from '@langchain/core/messages';
|
|
3
|
+
import type {
|
|
4
|
+
Content,
|
|
5
|
+
EnhancedGenerateContentResponse,
|
|
6
|
+
} from '@google/generative-ai';
|
|
4
7
|
import {
|
|
5
8
|
STREAMED_TOOL_CALL_SEAL_METADATA_KEY,
|
|
6
9
|
STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY,
|
|
@@ -8,9 +11,53 @@ import {
|
|
|
8
11
|
} from '@/tools/streamedToolCallSeals';
|
|
9
12
|
import {
|
|
10
13
|
convertResponseContentToChatGenerationChunk,
|
|
14
|
+
convertMessageContentToParts,
|
|
11
15
|
dropUnsupportedModelTurnPrefill,
|
|
12
16
|
rejectsModelTurnPrefill,
|
|
13
17
|
} from './common';
|
|
18
|
+
import { toLangChainContent } from '@/messages/langchain';
|
|
19
|
+
|
|
20
|
+
describe('convertMessageContentToParts cross-provider tool calls', () => {
|
|
21
|
+
test('deduplicates Anthropic tool_use content mirrored in parsed tool_calls', () => {
|
|
22
|
+
const message = new AIMessage({
|
|
23
|
+
content: toLangChainContent([
|
|
24
|
+
{ type: 'text', text: 'Checking.' },
|
|
25
|
+
{
|
|
26
|
+
type: 'tool_use',
|
|
27
|
+
id: 'call_weather',
|
|
28
|
+
name: 'weather',
|
|
29
|
+
input: '',
|
|
30
|
+
},
|
|
31
|
+
{ type: 'text', index: 0, input: '{"city":"NYC"}' },
|
|
32
|
+
]),
|
|
33
|
+
tool_calls: [
|
|
34
|
+
{
|
|
35
|
+
id: 'call_weather',
|
|
36
|
+
name: 'weather',
|
|
37
|
+
args: { city: 'NYC' },
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const parts = convertMessageContentToParts(
|
|
43
|
+
message,
|
|
44
|
+
false,
|
|
45
|
+
[],
|
|
46
|
+
'gemini-3.5-flash'
|
|
47
|
+
);
|
|
48
|
+
const functionCalls = parts.filter((part) => 'functionCall' in part);
|
|
49
|
+
|
|
50
|
+
expect(functionCalls).toHaveLength(1);
|
|
51
|
+
expect(parts).not.toContainEqual({});
|
|
52
|
+
expect(functionCalls[0]).toMatchObject({
|
|
53
|
+
functionCall: {
|
|
54
|
+
id: 'call_weather',
|
|
55
|
+
name: 'weather',
|
|
56
|
+
args: { city: 'NYC' },
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
14
61
|
|
|
15
62
|
function buildResponse(
|
|
16
63
|
parts: Array<Record<string, unknown>>
|
|
@@ -72,7 +119,9 @@ describe('rejectsModelTurnPrefill', () => {
|
|
|
72
119
|
expect(rejectsModelTurnPrefill('gemini-3.6-flash')).toBe(true);
|
|
73
120
|
expect(rejectsModelTurnPrefill('gemini-3.5-flash-lite')).toBe(true);
|
|
74
121
|
expect(rejectsModelTurnPrefill('models/gemini-3.6-flash')).toBe(true);
|
|
75
|
-
expect(rejectsModelTurnPrefill('google/gemini-3.5-flash-lite-latest')).toBe(
|
|
122
|
+
expect(rejectsModelTurnPrefill('google/gemini-3.5-flash-lite-latest')).toBe(
|
|
123
|
+
true
|
|
124
|
+
);
|
|
76
125
|
});
|
|
77
126
|
|
|
78
127
|
test('is false for models that still accept prefill and for empty input', () => {
|
|
@@ -86,34 +135,51 @@ describe('rejectsModelTurnPrefill', () => {
|
|
|
86
135
|
|
|
87
136
|
describe('dropUnsupportedModelTurnPrefill', () => {
|
|
88
137
|
const userTurn: Content = { role: 'user', parts: [{ text: 'Hi' }] };
|
|
89
|
-
const modelTurn: Content = {
|
|
138
|
+
const modelTurn: Content = {
|
|
139
|
+
role: 'model',
|
|
140
|
+
parts: [{ text: 'Hello, I am' }],
|
|
141
|
+
};
|
|
90
142
|
|
|
91
143
|
test('drops a trailing model turn for no-prefill models', () => {
|
|
92
144
|
const contents: Content[] = [userTurn, modelTurn];
|
|
93
|
-
const result = dropUnsupportedModelTurnPrefill(
|
|
145
|
+
const result = dropUnsupportedModelTurnPrefill(
|
|
146
|
+
contents,
|
|
147
|
+
'gemini-3.6-flash'
|
|
148
|
+
);
|
|
94
149
|
expect(result).toEqual([userTurn]);
|
|
95
150
|
});
|
|
96
151
|
|
|
97
152
|
test('drops multiple consecutive trailing model turns but keeps one turn', () => {
|
|
98
153
|
const contents: Content[] = [userTurn, modelTurn, modelTurn];
|
|
99
|
-
const result = dropUnsupportedModelTurnPrefill(
|
|
154
|
+
const result = dropUnsupportedModelTurnPrefill(
|
|
155
|
+
contents,
|
|
156
|
+
'gemini-3.5-flash-lite'
|
|
157
|
+
);
|
|
100
158
|
expect(result).toEqual([userTurn]);
|
|
101
159
|
});
|
|
102
160
|
|
|
103
161
|
test('leaves a trailing model turn for models that accept prefill', () => {
|
|
104
162
|
const contents: Content[] = [userTurn, modelTurn];
|
|
105
|
-
const result = dropUnsupportedModelTurnPrefill(
|
|
163
|
+
const result = dropUnsupportedModelTurnPrefill(
|
|
164
|
+
contents,
|
|
165
|
+
'gemini-3.5-flash'
|
|
166
|
+
);
|
|
106
167
|
expect(result).toBe(contents);
|
|
107
168
|
});
|
|
108
169
|
|
|
109
170
|
test('is a no-op when the request already ends with a user turn', () => {
|
|
110
171
|
const contents: Content[] = [modelTurn, userTurn];
|
|
111
|
-
const result = dropUnsupportedModelTurnPrefill(
|
|
172
|
+
const result = dropUnsupportedModelTurnPrefill(
|
|
173
|
+
contents,
|
|
174
|
+
'gemini-3.6-flash'
|
|
175
|
+
);
|
|
112
176
|
expect(result).toBe(contents);
|
|
113
177
|
});
|
|
114
178
|
|
|
115
179
|
test('is a no-op for empty or undefined contents', () => {
|
|
116
180
|
expect(dropUnsupportedModelTurnPrefill([], 'gemini-3.6-flash')).toEqual([]);
|
|
117
|
-
expect(
|
|
181
|
+
expect(
|
|
182
|
+
dropUnsupportedModelTurnPrefill(undefined, 'gemini-3.6-flash')
|
|
183
|
+
).toBeUndefined();
|
|
118
184
|
});
|
|
119
185
|
});
|
|
@@ -390,7 +390,9 @@ function _convertLangChainContentToPart(
|
|
|
390
390
|
}
|
|
391
391
|
|
|
392
392
|
if (content.type === 'text') {
|
|
393
|
-
return
|
|
393
|
+
return typeof content.text === 'string' && content.text !== ''
|
|
394
|
+
? { text: content.text }
|
|
395
|
+
: undefined;
|
|
394
396
|
} else if (content.type === 'executableCode') {
|
|
395
397
|
return { executableCode: content.executableCode };
|
|
396
398
|
} else if (content.type === 'codeExecutionResult') {
|
|
@@ -429,10 +431,14 @@ function _convertLangChainContentToPart(
|
|
|
429
431
|
} else if (content.type === 'media') {
|
|
430
432
|
return messageContentMedia(content);
|
|
431
433
|
} else if (content.type === 'tool_use') {
|
|
434
|
+
const functionId = getGoogleFunctionId(
|
|
435
|
+
typeof content.id === 'string' ? content.id : undefined
|
|
436
|
+
);
|
|
432
437
|
return {
|
|
433
438
|
functionCall: {
|
|
434
439
|
name: content.name,
|
|
435
440
|
args: content.input,
|
|
441
|
+
...(functionId != null ? { id: functionId } : {}),
|
|
436
442
|
},
|
|
437
443
|
};
|
|
438
444
|
} else if (
|
|
@@ -553,7 +559,28 @@ export function convertMessageContentToParts(
|
|
|
553
559
|
});
|
|
554
560
|
}
|
|
555
561
|
|
|
556
|
-
|
|
562
|
+
const parsedFunctionCallIds = new Set(
|
|
563
|
+
functionCalls.flatMap((part) => {
|
|
564
|
+
const functionCall = part.functionCall as GoogleFunctionCallWithId;
|
|
565
|
+
return functionCall.id != null ? [functionCall.id] : [];
|
|
566
|
+
})
|
|
567
|
+
);
|
|
568
|
+
const parsedFunctionCallNames = new Set(
|
|
569
|
+
functionCalls.map((part) => part.functionCall.name)
|
|
570
|
+
);
|
|
571
|
+
const contentWithoutParsedMirrors = messageParts.filter((part) => {
|
|
572
|
+
if (!('functionCall' in part) || part.functionCall == null) {
|
|
573
|
+
return true;
|
|
574
|
+
}
|
|
575
|
+
const functionCall = part.functionCall as GoogleFunctionCallWithId;
|
|
576
|
+
return !(
|
|
577
|
+
(functionCall.id != null && parsedFunctionCallIds.has(functionCall.id)) ||
|
|
578
|
+
(functionCall.id == null &&
|
|
579
|
+
parsedFunctionCallNames.has(functionCall.name))
|
|
580
|
+
);
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
return [...contentWithoutParsedMirrors, ...functionCalls];
|
|
557
584
|
}
|
|
558
585
|
|
|
559
586
|
export function convertBaseMessagesToContent(
|
|
@@ -665,7 +692,11 @@ export function dropUnsupportedModelTurnPrefill(
|
|
|
665
692
|
contents: Content[] | undefined,
|
|
666
693
|
model?: string
|
|
667
694
|
): Content[] | undefined {
|
|
668
|
-
if (
|
|
695
|
+
if (
|
|
696
|
+
contents == null ||
|
|
697
|
+
contents.length === 0 ||
|
|
698
|
+
!rejectsModelTurnPrefill(model)
|
|
699
|
+
) {
|
|
669
700
|
return contents;
|
|
670
701
|
}
|
|
671
702
|
let end = contents.length;
|