@librechat/agents 3.1.56 → 3.1.60
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 +326 -62
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/enum.cjs +13 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/events.cjs +7 -27
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +303 -222
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +4 -4
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +6 -2
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +60 -0
- package/dist/cjs/llm/init.cjs.map +1 -0
- package/dist/cjs/llm/invoke.cjs +90 -0
- package/dist/cjs/llm/invoke.cjs.map +1 -0
- package/dist/cjs/llm/openai/index.cjs +2 -0
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/request.cjs +41 -0
- package/dist/cjs/llm/request.cjs.map +1 -0
- package/dist/cjs/main.cjs +40 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/cache.cjs +76 -89
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/messages/contextPruning.cjs +156 -0
- package/dist/cjs/messages/contextPruning.cjs.map +1 -0
- package/dist/cjs/messages/contextPruningSettings.cjs +53 -0
- package/dist/cjs/messages/contextPruningSettings.cjs.map +1 -0
- package/dist/cjs/messages/core.cjs +23 -37
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +156 -11
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/prune.cjs +1161 -49
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/messages/reducer.cjs +87 -0
- package/dist/cjs/messages/reducer.cjs.map +1 -0
- package/dist/cjs/run.cjs +81 -42
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +54 -7
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/index.cjs +75 -0
- package/dist/cjs/summarization/index.cjs.map +1 -0
- package/dist/cjs/summarization/node.cjs +663 -0
- package/dist/cjs/summarization/node.cjs.map +1 -0
- package/dist/cjs/tools/ToolNode.cjs +16 -8
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/handlers.cjs +2 -0
- package/dist/cjs/tools/handlers.cjs.map +1 -1
- package/dist/cjs/utils/errors.cjs +115 -0
- package/dist/cjs/utils/errors.cjs.map +1 -0
- package/dist/cjs/utils/events.cjs +17 -0
- package/dist/cjs/utils/events.cjs.map +1 -1
- package/dist/cjs/utils/handlers.cjs +16 -0
- package/dist/cjs/utils/handlers.cjs.map +1 -1
- package/dist/cjs/utils/llm.cjs +10 -0
- package/dist/cjs/utils/llm.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +247 -14
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/cjs/utils/truncation.cjs +107 -0
- package/dist/cjs/utils/truncation.cjs.map +1 -0
- package/dist/esm/agents/AgentContext.mjs +325 -61
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/enum.mjs +13 -0
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +8 -28
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +307 -226
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +4 -4
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +6 -2
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +58 -0
- package/dist/esm/llm/init.mjs.map +1 -0
- package/dist/esm/llm/invoke.mjs +87 -0
- package/dist/esm/llm/invoke.mjs.map +1 -0
- package/dist/esm/llm/openai/index.mjs +2 -0
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/request.mjs +38 -0
- package/dist/esm/llm/request.mjs.map +1 -0
- package/dist/esm/main.mjs +13 -3
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/messages/cache.mjs +76 -89
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/messages/contextPruning.mjs +154 -0
- package/dist/esm/messages/contextPruning.mjs.map +1 -0
- package/dist/esm/messages/contextPruningSettings.mjs +50 -0
- package/dist/esm/messages/contextPruningSettings.mjs.map +1 -0
- package/dist/esm/messages/core.mjs +23 -37
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +156 -11
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/prune.mjs +1158 -52
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/messages/reducer.mjs +83 -0
- package/dist/esm/messages/reducer.mjs.map +1 -0
- package/dist/esm/run.mjs +82 -43
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +54 -7
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/index.mjs +73 -0
- package/dist/esm/summarization/index.mjs.map +1 -0
- package/dist/esm/summarization/node.mjs +659 -0
- package/dist/esm/summarization/node.mjs.map +1 -0
- package/dist/esm/tools/ToolNode.mjs +16 -8
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/handlers.mjs +2 -0
- package/dist/esm/tools/handlers.mjs.map +1 -1
- package/dist/esm/utils/errors.mjs +111 -0
- package/dist/esm/utils/errors.mjs.map +1 -0
- package/dist/esm/utils/events.mjs +17 -1
- package/dist/esm/utils/events.mjs.map +1 -1
- package/dist/esm/utils/handlers.mjs +16 -0
- package/dist/esm/utils/handlers.mjs.map +1 -1
- package/dist/esm/utils/llm.mjs +10 -1
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +245 -15
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/esm/utils/truncation.mjs +102 -0
- package/dist/esm/utils/truncation.mjs.map +1 -0
- package/dist/types/agents/AgentContext.d.ts +124 -6
- package/dist/types/common/enum.d.ts +14 -1
- package/dist/types/graphs/Graph.d.ts +22 -27
- package/dist/types/index.d.ts +5 -0
- package/dist/types/llm/init.d.ts +18 -0
- package/dist/types/llm/invoke.d.ts +48 -0
- package/dist/types/llm/request.d.ts +14 -0
- package/dist/types/messages/contextPruning.d.ts +42 -0
- package/dist/types/messages/contextPruningSettings.d.ts +44 -0
- package/dist/types/messages/core.d.ts +1 -1
- package/dist/types/messages/format.d.ts +17 -1
- package/dist/types/messages/index.d.ts +3 -0
- package/dist/types/messages/prune.d.ts +162 -1
- package/dist/types/messages/reducer.d.ts +18 -0
- package/dist/types/run.d.ts +12 -1
- package/dist/types/summarization/index.d.ts +20 -0
- package/dist/types/summarization/node.d.ts +29 -0
- package/dist/types/tools/ToolNode.d.ts +3 -1
- package/dist/types/types/graph.d.ts +44 -6
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/run.d.ts +30 -0
- package/dist/types/types/stream.d.ts +31 -4
- package/dist/types/types/summarize.d.ts +47 -0
- package/dist/types/types/tools.d.ts +7 -0
- package/dist/types/utils/errors.d.ts +28 -0
- package/dist/types/utils/events.d.ts +13 -0
- package/dist/types/utils/index.d.ts +2 -0
- package/dist/types/utils/llm.d.ts +4 -0
- package/dist/types/utils/tokens.d.ts +14 -1
- package/dist/types/utils/truncation.d.ts +49 -0
- package/package.json +2 -2
- package/src/agents/AgentContext.ts +388 -58
- package/src/agents/__tests__/AgentContext.test.ts +265 -5
- package/src/common/enum.ts +13 -0
- package/src/events.ts +9 -39
- package/src/graphs/Graph.ts +468 -331
- package/src/index.ts +7 -0
- package/src/llm/anthropic/llm.spec.ts +3 -3
- package/src/llm/anthropic/utils/message_inputs.ts +6 -4
- package/src/llm/bedrock/llm.spec.ts +1 -1
- package/src/llm/bedrock/utils/message_inputs.ts +6 -2
- package/src/llm/init.ts +63 -0
- package/src/llm/invoke.ts +144 -0
- package/src/llm/request.ts +55 -0
- package/src/messages/__tests__/observationMasking.test.ts +221 -0
- package/src/messages/cache.ts +77 -102
- package/src/messages/contextPruning.ts +191 -0
- package/src/messages/contextPruningSettings.ts +90 -0
- package/src/messages/core.ts +32 -53
- package/src/messages/ensureThinkingBlock.test.ts +39 -39
- package/src/messages/format.ts +227 -15
- package/src/messages/formatAgentMessages.test.ts +511 -1
- package/src/messages/index.ts +3 -0
- package/src/messages/prune.ts +1548 -62
- package/src/messages/reducer.ts +22 -0
- package/src/run.ts +104 -51
- package/src/scripts/bedrock-merge-test.ts +1 -1
- package/src/scripts/test-thinking-handoff-bedrock.ts +1 -1
- package/src/scripts/test-thinking-handoff.ts +1 -1
- package/src/scripts/thinking-bedrock.ts +1 -1
- package/src/scripts/thinking.ts +1 -1
- package/src/specs/anthropic.simple.test.ts +1 -1
- package/src/specs/multi-agent-summarization.test.ts +396 -0
- package/src/specs/prune.test.ts +1196 -23
- package/src/specs/summarization-unit.test.ts +868 -0
- package/src/specs/summarization.test.ts +3810 -0
- package/src/specs/summarize-prune.test.ts +376 -0
- package/src/specs/thinking-handoff.test.ts +10 -10
- package/src/specs/thinking-prune.test.ts +7 -4
- package/src/specs/token-accounting-e2e.test.ts +1034 -0
- package/src/specs/token-accounting-pipeline.test.ts +882 -0
- package/src/specs/token-distribution-edge-case.test.ts +25 -26
- package/src/splitStream.test.ts +42 -33
- package/src/stream.ts +64 -11
- package/src/summarization/__tests__/aggregator.test.ts +153 -0
- package/src/summarization/__tests__/node.test.ts +708 -0
- package/src/summarization/__tests__/trigger.test.ts +50 -0
- package/src/summarization/index.ts +102 -0
- package/src/summarization/node.ts +982 -0
- package/src/tools/ToolNode.ts +25 -3
- package/src/types/graph.ts +62 -7
- package/src/types/index.ts +1 -0
- package/src/types/run.ts +32 -0
- package/src/types/stream.ts +45 -5
- package/src/types/summarize.ts +58 -0
- package/src/types/tools.ts +7 -0
- package/src/utils/errors.ts +117 -0
- package/src/utils/events.ts +31 -0
- package/src/utils/handlers.ts +18 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/llm.ts +12 -0
- package/src/utils/tokens.ts +336 -18
- package/src/utils/truncation.ts +124 -0
- package/src/scripts/image.ts +0 -180
|
@@ -105,45 +105,6 @@ describe('ensureThinkingBlockInMessages', () => {
|
|
|
105
105
|
);
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
-
test('should not modify AI message when reasoning_content is not the first block (Bedrock whitespace artifact)', () => {
|
|
109
|
-
// Bedrock emits a "\n\n" text chunk before the thinking block,
|
|
110
|
-
// pushing reasoning_content to content[1] instead of content[0].
|
|
111
|
-
const messages = [
|
|
112
|
-
new HumanMessage({ content: 'Do something' }),
|
|
113
|
-
new AIMessage({
|
|
114
|
-
content: [
|
|
115
|
-
{ type: 'text', text: '\n\n' },
|
|
116
|
-
{
|
|
117
|
-
type: ContentTypes.REASONING_CONTENT,
|
|
118
|
-
reasoningText: { text: 'Let me think about this' },
|
|
119
|
-
},
|
|
120
|
-
{ type: 'text', text: 'Let me help!' },
|
|
121
|
-
],
|
|
122
|
-
tool_calls: [
|
|
123
|
-
{
|
|
124
|
-
id: 'call_bedrock',
|
|
125
|
-
name: 'some_tool',
|
|
126
|
-
args: { x: 1 },
|
|
127
|
-
type: 'tool_call' as const,
|
|
128
|
-
},
|
|
129
|
-
],
|
|
130
|
-
}),
|
|
131
|
-
new ToolMessage({
|
|
132
|
-
content: 'tool result',
|
|
133
|
-
tool_call_id: 'call_bedrock',
|
|
134
|
-
}),
|
|
135
|
-
];
|
|
136
|
-
|
|
137
|
-
const result = ensureThinkingBlockInMessages(messages, Providers.BEDROCK);
|
|
138
|
-
|
|
139
|
-
expect(result).toHaveLength(3);
|
|
140
|
-
expect(result[0]).toBeInstanceOf(HumanMessage);
|
|
141
|
-
expect(result[1]).toBeInstanceOf(AIMessage);
|
|
142
|
-
expect(result[2]).toBeInstanceOf(ToolMessage);
|
|
143
|
-
// The AI message should be preserved, not converted to a HumanMessage
|
|
144
|
-
expect(result[1].content).toEqual(messages[1].content);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
108
|
test('should not convert follow-up tool calls in a thinking-enabled chain (Bedrock multi-step)', () => {
|
|
148
109
|
// Bedrock reasoning models produce reasoning on the first AI response,
|
|
149
110
|
// then subsequent tool calls in the same chain have content: "" with no
|
|
@@ -312,6 +273,45 @@ describe('ensureThinkingBlockInMessages', () => {
|
|
|
312
273
|
expect(result[3]).toBeInstanceOf(AIMessage);
|
|
313
274
|
});
|
|
314
275
|
|
|
276
|
+
test('should not modify AI message when reasoning_content is not the first block (Bedrock whitespace artifact)', () => {
|
|
277
|
+
// Bedrock emits a "\n\n" text chunk before the thinking block,
|
|
278
|
+
// pushing reasoning_content to content[1] instead of content[0].
|
|
279
|
+
const messages = [
|
|
280
|
+
new HumanMessage({ content: 'Do something' }),
|
|
281
|
+
new AIMessage({
|
|
282
|
+
content: [
|
|
283
|
+
{ type: 'text', text: '\n\n' },
|
|
284
|
+
{
|
|
285
|
+
type: ContentTypes.REASONING_CONTENT,
|
|
286
|
+
reasoningText: { text: 'Let me think about this' },
|
|
287
|
+
},
|
|
288
|
+
{ type: 'text', text: 'Let me help!' },
|
|
289
|
+
],
|
|
290
|
+
tool_calls: [
|
|
291
|
+
{
|
|
292
|
+
id: 'call_bedrock',
|
|
293
|
+
name: 'some_tool',
|
|
294
|
+
args: { x: 1 },
|
|
295
|
+
type: 'tool_call' as const,
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
}),
|
|
299
|
+
new ToolMessage({
|
|
300
|
+
content: 'tool result',
|
|
301
|
+
tool_call_id: 'call_bedrock',
|
|
302
|
+
}),
|
|
303
|
+
];
|
|
304
|
+
|
|
305
|
+
const result = ensureThinkingBlockInMessages(messages, Providers.BEDROCK);
|
|
306
|
+
|
|
307
|
+
expect(result).toHaveLength(3);
|
|
308
|
+
expect(result[0]).toBeInstanceOf(HumanMessage);
|
|
309
|
+
expect(result[1]).toBeInstanceOf(AIMessage);
|
|
310
|
+
expect(result[2]).toBeInstanceOf(ToolMessage);
|
|
311
|
+
// The AI message should be preserved, not converted to a HumanMessage
|
|
312
|
+
expect(result[1].content).toEqual(messages[1].content);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
315
|
test('should not modify AI message with reasoning block and tool calls', () => {
|
|
316
316
|
const messages = [
|
|
317
317
|
new HumanMessage({ content: 'Calculate something' }),
|
package/src/messages/format.ts
CHANGED
|
@@ -13,11 +13,14 @@ import type {
|
|
|
13
13
|
ExtendedMessageContent,
|
|
14
14
|
MessageContentComplex,
|
|
15
15
|
ReasoningContentText,
|
|
16
|
+
SummaryContentBlock,
|
|
16
17
|
ToolCallContent,
|
|
17
18
|
ToolCallPart,
|
|
18
19
|
TPayload,
|
|
19
20
|
TMessage,
|
|
20
21
|
} from '@/types';
|
|
22
|
+
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
23
|
+
import { emitAgentLog } from '@/utils/events';
|
|
21
24
|
import { Providers, ContentTypes, Constants } from '@/common';
|
|
22
25
|
|
|
23
26
|
interface MediaMessageParams {
|
|
@@ -380,7 +383,8 @@ function formatAssistantMessage(
|
|
|
380
383
|
continue;
|
|
381
384
|
} else if (
|
|
382
385
|
part.type === ContentTypes.ERROR ||
|
|
383
|
-
part.type === ContentTypes.AGENT_UPDATE
|
|
386
|
+
part.type === ContentTypes.AGENT_UPDATE ||
|
|
387
|
+
part.type === ContentTypes.SUMMARY
|
|
384
388
|
) {
|
|
385
389
|
continue;
|
|
386
390
|
} else {
|
|
@@ -415,6 +419,17 @@ function formatAssistantMessage(
|
|
|
415
419
|
return formattedMessages;
|
|
416
420
|
}
|
|
417
421
|
|
|
422
|
+
function getSourceMessageId(message: Partial<TMessage>): string | undefined {
|
|
423
|
+
const candidate =
|
|
424
|
+
(message as { messageId?: string }).messageId ??
|
|
425
|
+
(message as { id?: string }).id;
|
|
426
|
+
if (typeof candidate !== 'string') {
|
|
427
|
+
return undefined;
|
|
428
|
+
}
|
|
429
|
+
const normalized = candidate.trim();
|
|
430
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
431
|
+
}
|
|
432
|
+
|
|
418
433
|
/**
|
|
419
434
|
* Labels all agent content for parallel patterns (fan-out/fan-in)
|
|
420
435
|
* Groups consecutive content by agent and wraps with clear labels
|
|
@@ -677,6 +692,111 @@ function extractToolNamesFromSearchOutput(output: string): string[] {
|
|
|
677
692
|
return [];
|
|
678
693
|
}
|
|
679
694
|
|
|
695
|
+
type SummaryBoundary = {
|
|
696
|
+
messageIndex: number;
|
|
697
|
+
contentIndex: number;
|
|
698
|
+
text: string;
|
|
699
|
+
tokenCount: number;
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
function getLatestSummaryBoundary(
|
|
703
|
+
payload: TPayload
|
|
704
|
+
): SummaryBoundary | undefined {
|
|
705
|
+
let summaryBoundary: SummaryBoundary | undefined;
|
|
706
|
+
|
|
707
|
+
for (let i = 0; i < payload.length; i++) {
|
|
708
|
+
const message = payload[i];
|
|
709
|
+
if (!Array.isArray(message.content)) {
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
for (let j = 0; j < message.content.length; j++) {
|
|
714
|
+
const part = message.content[j] as MessageContentComplex | undefined;
|
|
715
|
+
if (part == null || part.type !== ContentTypes.SUMMARY) {
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
const summaryPart = part as Partial<SummaryContentBlock> & {
|
|
720
|
+
text?: string;
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
// Try content array first (new format), then direct text (legacy format)
|
|
724
|
+
let summaryText = (summaryPart.content ?? [])
|
|
725
|
+
.map((block) =>
|
|
726
|
+
'text' in block ? (block as { text: string }).text : ''
|
|
727
|
+
)
|
|
728
|
+
.join('')
|
|
729
|
+
.trim();
|
|
730
|
+
|
|
731
|
+
// Fallback: legacy format where text was a direct field on the block
|
|
732
|
+
if (summaryText.length === 0 && typeof summaryPart.text === 'string') {
|
|
733
|
+
summaryText = summaryPart.text.trim();
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
if (summaryText.length === 0) {
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
summaryBoundary = {
|
|
741
|
+
messageIndex: i,
|
|
742
|
+
contentIndex: j,
|
|
743
|
+
text: summaryText,
|
|
744
|
+
tokenCount:
|
|
745
|
+
typeof summaryPart.tokenCount === 'number' &&
|
|
746
|
+
Number.isFinite(summaryPart.tokenCount)
|
|
747
|
+
? summaryPart.tokenCount
|
|
748
|
+
: 0,
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
return summaryBoundary;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
function applySummaryBoundary(
|
|
757
|
+
message: Partial<TMessage>,
|
|
758
|
+
messageIndex: number,
|
|
759
|
+
summaryBoundary?: SummaryBoundary
|
|
760
|
+
): Partial<TMessage> | null {
|
|
761
|
+
if (!summaryBoundary) {
|
|
762
|
+
return message;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (messageIndex < summaryBoundary.messageIndex) {
|
|
766
|
+
return null;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (
|
|
770
|
+
messageIndex !== summaryBoundary.messageIndex ||
|
|
771
|
+
!Array.isArray(message.content)
|
|
772
|
+
) {
|
|
773
|
+
return message;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
return {
|
|
777
|
+
...message,
|
|
778
|
+
content: message.content.slice(summaryBoundary.contentIndex + 1),
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
function contentPartCharLength(part: MessageContentComplex): number {
|
|
783
|
+
const record = part as Record<string, unknown>;
|
|
784
|
+
let len = 0;
|
|
785
|
+
if (typeof record.text === 'string') {
|
|
786
|
+
len += record.text.length;
|
|
787
|
+
}
|
|
788
|
+
if (typeof record.thinking === 'string') {
|
|
789
|
+
len += record.thinking.length;
|
|
790
|
+
}
|
|
791
|
+
const { input } = record;
|
|
792
|
+
if (typeof input === 'string') {
|
|
793
|
+
len += input.length;
|
|
794
|
+
} else if (input != null && typeof input === 'object') {
|
|
795
|
+
len += JSON.stringify(input).length;
|
|
796
|
+
}
|
|
797
|
+
return len;
|
|
798
|
+
}
|
|
799
|
+
|
|
680
800
|
/**
|
|
681
801
|
* Formats an array of messages for LangChain, handling tool calls and creating ToolMessage instances.
|
|
682
802
|
*
|
|
@@ -692,14 +812,39 @@ export const formatAgentMessages = (
|
|
|
692
812
|
): {
|
|
693
813
|
messages: Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>;
|
|
694
814
|
indexTokenCountMap?: Record<number, number>;
|
|
815
|
+
/** Cross-run summary extracted from the payload. Should be forwarded to the
|
|
816
|
+
* agent run so it can be included in the system message via AgentContext. */
|
|
817
|
+
summary?: { text: string; tokenCount: number };
|
|
818
|
+
/** When a summary boundary sliced content from a message, the token count
|
|
819
|
+
* was proportionally reduced. Returned so the caller can log it. */
|
|
820
|
+
boundaryTokenAdjustment?: {
|
|
821
|
+
original: number;
|
|
822
|
+
adjusted: number;
|
|
823
|
+
remainingChars: number;
|
|
824
|
+
totalChars: number;
|
|
825
|
+
};
|
|
695
826
|
} => {
|
|
696
827
|
const messages: Array<
|
|
697
828
|
HumanMessage | AIMessage | SystemMessage | ToolMessage
|
|
698
829
|
> = [];
|
|
699
830
|
// If indexTokenCountMap is provided, create a new map to track the updated indices
|
|
700
831
|
const updatedIndexTokenCountMap: Record<number, number> = {};
|
|
832
|
+
let boundaryTokenAdjustment:
|
|
833
|
+
| {
|
|
834
|
+
original: number;
|
|
835
|
+
adjusted: number;
|
|
836
|
+
remainingChars: number;
|
|
837
|
+
totalChars: number;
|
|
838
|
+
}
|
|
839
|
+
| undefined;
|
|
701
840
|
// Keep track of the mapping from original payload indices to result indices
|
|
702
841
|
const indexMapping: Record<number, number[] | undefined> = {};
|
|
842
|
+
const summaryBoundary = getLatestSummaryBoundary(payload);
|
|
843
|
+
|
|
844
|
+
// Summary metadata is returned to the caller so it can be forwarded to the
|
|
845
|
+
// agent run and included in the single system message via AgentContext.
|
|
846
|
+
// We intentionally do NOT create a SystemMessage here — that would conflict
|
|
847
|
+
// with the agent's own system message (instructions + summary combined).
|
|
703
848
|
|
|
704
849
|
/**
|
|
705
850
|
* Create a mutable copy of the tools set that can be expanded dynamically.
|
|
@@ -710,21 +855,37 @@ export const formatAgentMessages = (
|
|
|
710
855
|
|
|
711
856
|
// Process messages with tool conversion if tools set is provided
|
|
712
857
|
for (let i = 0; i < payload.length; i++) {
|
|
713
|
-
const
|
|
858
|
+
const rawMessage = payload[i];
|
|
859
|
+
const sourceMessageId = getSourceMessageId(rawMessage);
|
|
860
|
+
let message = applySummaryBoundary(rawMessage, i, summaryBoundary);
|
|
861
|
+
if (!message) {
|
|
862
|
+
indexMapping[i] = [];
|
|
863
|
+
continue;
|
|
864
|
+
}
|
|
865
|
+
|
|
714
866
|
// Q: Store the current length of messages to track where this payload message starts in the result?
|
|
715
867
|
// const startIndex = messages.length;
|
|
716
868
|
if (typeof message.content === 'string') {
|
|
717
|
-
message
|
|
718
|
-
|
|
719
|
-
|
|
869
|
+
message = {
|
|
870
|
+
...message,
|
|
871
|
+
content: [
|
|
872
|
+
{ type: ContentTypes.TEXT, [ContentTypes.TEXT]: message.content },
|
|
873
|
+
],
|
|
874
|
+
};
|
|
875
|
+
} else if (Array.isArray(message.content) && message.content.length === 0) {
|
|
876
|
+
indexMapping[i] = [];
|
|
877
|
+
continue;
|
|
720
878
|
}
|
|
879
|
+
|
|
721
880
|
if (message.role !== 'assistant') {
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
881
|
+
const formattedMessage = formatMessage({
|
|
882
|
+
message: message as MessageInput,
|
|
883
|
+
langChain: true,
|
|
884
|
+
}) as HumanMessage | AIMessage | SystemMessage;
|
|
885
|
+
if (sourceMessageId != null && sourceMessageId !== '') {
|
|
886
|
+
formattedMessage.id = sourceMessageId;
|
|
887
|
+
}
|
|
888
|
+
messages.push(formattedMessage);
|
|
728
889
|
|
|
729
890
|
// Update the index mapping for this message
|
|
730
891
|
indexMapping[i] = [messages.length - 1];
|
|
@@ -743,7 +904,7 @@ export const formatAgentMessages = (
|
|
|
743
904
|
let processedMessage = message;
|
|
744
905
|
if (discoveredTools) {
|
|
745
906
|
const content = message.content;
|
|
746
|
-
if (content && Array.isArray(content)) {
|
|
907
|
+
if (content != null && Array.isArray(content)) {
|
|
747
908
|
const filteredContent: typeof content = [];
|
|
748
909
|
const invalidToolCallIds = new Set<string>();
|
|
749
910
|
const invalidToolStrings: string[] = [];
|
|
@@ -866,8 +1027,12 @@ export const formatAgentMessages = (
|
|
|
866
1027
|
}
|
|
867
1028
|
}
|
|
868
1029
|
|
|
869
|
-
// Process the assistant message using the helper function
|
|
870
1030
|
const formattedMessages = formatAssistantMessage(processedMessage);
|
|
1031
|
+
if (sourceMessageId != null && sourceMessageId !== '') {
|
|
1032
|
+
for (const formattedMessage of formattedMessages) {
|
|
1033
|
+
formattedMessage.id = sourceMessageId;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
871
1036
|
messages.push(...formattedMessages);
|
|
872
1037
|
|
|
873
1038
|
// Update the index mapping for this assistant message
|
|
@@ -887,12 +1052,46 @@ export const formatAgentMessages = (
|
|
|
887
1052
|
originalIndex++
|
|
888
1053
|
) {
|
|
889
1054
|
const resultIndices = indexMapping[originalIndex] || [];
|
|
890
|
-
|
|
1055
|
+
let tokenCount = indexTokenCountMap[originalIndex];
|
|
891
1056
|
|
|
892
1057
|
if (tokenCount === undefined) {
|
|
893
1058
|
continue;
|
|
894
1059
|
}
|
|
895
1060
|
|
|
1061
|
+
if (
|
|
1062
|
+
summaryBoundary &&
|
|
1063
|
+
originalIndex === summaryBoundary.messageIndex &&
|
|
1064
|
+
Array.isArray(payload[originalIndex].content)
|
|
1065
|
+
) {
|
|
1066
|
+
const content = payload[originalIndex]
|
|
1067
|
+
.content as MessageContentComplex[];
|
|
1068
|
+
const { contentIndex } = summaryBoundary;
|
|
1069
|
+
if (contentIndex >= 0 && contentIndex < content.length - 1) {
|
|
1070
|
+
let totalCharLen = 0;
|
|
1071
|
+
let remainingCharLen = 0;
|
|
1072
|
+
for (let p = 0; p < content.length; p++) {
|
|
1073
|
+
const charLen = contentPartCharLength(content[p]);
|
|
1074
|
+
totalCharLen += charLen;
|
|
1075
|
+
if (p > contentIndex) {
|
|
1076
|
+
remainingCharLen += charLen;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
if (totalCharLen > 0) {
|
|
1080
|
+
const original = tokenCount;
|
|
1081
|
+
tokenCount = Math.max(
|
|
1082
|
+
1,
|
|
1083
|
+
Math.round(tokenCount * (remainingCharLen / totalCharLen))
|
|
1084
|
+
);
|
|
1085
|
+
boundaryTokenAdjustment = {
|
|
1086
|
+
original,
|
|
1087
|
+
adjusted: tokenCount,
|
|
1088
|
+
remainingChars: remainingCharLen,
|
|
1089
|
+
totalChars: totalCharLen,
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
896
1095
|
const msgCount = resultIndices.length;
|
|
897
1096
|
if (msgCount === 1) {
|
|
898
1097
|
updatedIndexTokenCountMap[resultIndices[0]] = tokenCount;
|
|
@@ -969,6 +1168,10 @@ export const formatAgentMessages = (
|
|
|
969
1168
|
indexTokenCountMap: indexTokenCountMap
|
|
970
1169
|
? updatedIndexTokenCountMap
|
|
971
1170
|
: undefined,
|
|
1171
|
+
summary: summaryBoundary
|
|
1172
|
+
? { text: summaryBoundary.text, tokenCount: summaryBoundary.tokenCount }
|
|
1173
|
+
: undefined,
|
|
1174
|
+
boundaryTokenAdjustment,
|
|
972
1175
|
};
|
|
973
1176
|
};
|
|
974
1177
|
|
|
@@ -1117,11 +1320,13 @@ function appendToolCalls(
|
|
|
1117
1320
|
*
|
|
1118
1321
|
* @param messages - Array of messages to process
|
|
1119
1322
|
* @param provider - The provider being used (unused but kept for future compatibility)
|
|
1323
|
+
* @param config - Optional RunnableConfig for structured agent logging
|
|
1120
1324
|
* @returns The messages array with tool sequences converted to buffer strings if necessary
|
|
1121
1325
|
*/
|
|
1122
1326
|
export function ensureThinkingBlockInMessages(
|
|
1123
1327
|
messages: BaseMessage[],
|
|
1124
|
-
_provider: Providers
|
|
1328
|
+
_provider: Providers,
|
|
1329
|
+
config?: RunnableConfig
|
|
1125
1330
|
): BaseMessage[] {
|
|
1126
1331
|
if (messages.length === 0) {
|
|
1127
1332
|
return messages;
|
|
@@ -1232,6 +1437,13 @@ export function ensureThinkingBlockInMessages(
|
|
|
1232
1437
|
}
|
|
1233
1438
|
|
|
1234
1439
|
flushTextChunks(textChunks, parts);
|
|
1440
|
+
emitAgentLog(
|
|
1441
|
+
config,
|
|
1442
|
+
'warn',
|
|
1443
|
+
'format',
|
|
1444
|
+
'ensureThinkingBlockInMessages: injecting [Previous agent context] HumanMessage' +
|
|
1445
|
+
` (${parts.length} msgs at index ${i}, no thinking block in chain)`
|
|
1446
|
+
);
|
|
1235
1447
|
result.push(new HumanMessage({ content: parts }));
|
|
1236
1448
|
i = j;
|
|
1237
1449
|
} else {
|