@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
package/src/tools/ToolNode.ts
CHANGED
|
@@ -20,6 +20,10 @@ import type { BaseMessage, AIMessage } from '@langchain/core/messages';
|
|
|
20
20
|
import type { StructuredToolInterface } from '@langchain/core/tools';
|
|
21
21
|
import type * as t from '@/types';
|
|
22
22
|
import { RunnableCallable } from '@/utils';
|
|
23
|
+
import {
|
|
24
|
+
calculateMaxToolResultChars,
|
|
25
|
+
truncateToolResultContent,
|
|
26
|
+
} from '@/utils/truncation';
|
|
23
27
|
import { safeDispatchCustomEvent } from '@/utils/events';
|
|
24
28
|
import { Constants, GraphEvents } from '@/common';
|
|
25
29
|
|
|
@@ -53,6 +57,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
53
57
|
private agentId?: string;
|
|
54
58
|
/** Tool names that bypass event dispatch and execute directly (e.g., graph-managed handoff tools) */
|
|
55
59
|
private directToolNames?: Set<string>;
|
|
60
|
+
/** Maximum characters allowed in a single tool result before truncation. */
|
|
61
|
+
private maxToolResultChars: number;
|
|
56
62
|
|
|
57
63
|
constructor({
|
|
58
64
|
tools,
|
|
@@ -68,6 +74,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
68
74
|
eventDrivenMode,
|
|
69
75
|
agentId,
|
|
70
76
|
directToolNames,
|
|
77
|
+
maxContextTokens,
|
|
78
|
+
maxToolResultChars,
|
|
71
79
|
}: t.ToolNodeConstructorParams) {
|
|
72
80
|
super({ name, tags, func: (input, config) => this.run(input, config) });
|
|
73
81
|
this.toolMap = toolMap ?? new Map(tools.map((tool) => [tool.name, tool]));
|
|
@@ -81,6 +89,8 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
81
89
|
this.eventDrivenMode = eventDrivenMode ?? false;
|
|
82
90
|
this.agentId = agentId;
|
|
83
91
|
this.directToolNames = directToolNames;
|
|
92
|
+
this.maxToolResultChars =
|
|
93
|
+
maxToolResultChars ?? calculateMaxToolResultChars(maxContextTokens);
|
|
84
94
|
}
|
|
85
95
|
|
|
86
96
|
/**
|
|
@@ -201,10 +211,15 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
201
211
|
) {
|
|
202
212
|
return output;
|
|
203
213
|
} else {
|
|
214
|
+
const rawContent =
|
|
215
|
+
typeof output === 'string' ? output : JSON.stringify(output);
|
|
204
216
|
return new ToolMessage({
|
|
205
217
|
status: 'success',
|
|
206
218
|
name: tool.name,
|
|
207
|
-
content:
|
|
219
|
+
content: truncateToolResultContent(
|
|
220
|
+
rawContent,
|
|
221
|
+
this.maxToolResultChars
|
|
222
|
+
),
|
|
208
223
|
tool_call_id: call.id!,
|
|
209
224
|
});
|
|
210
225
|
}
|
|
@@ -539,10 +554,14 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
539
554
|
tool_call_id: result.toolCallId,
|
|
540
555
|
});
|
|
541
556
|
} else {
|
|
542
|
-
|
|
557
|
+
const rawContent =
|
|
543
558
|
typeof result.content === 'string'
|
|
544
559
|
? result.content
|
|
545
560
|
: JSON.stringify(result.content);
|
|
561
|
+
contentString = truncateToolResultContent(
|
|
562
|
+
rawContent,
|
|
563
|
+
this.maxToolResultChars
|
|
564
|
+
);
|
|
546
565
|
toolMessage = new ToolMessage({
|
|
547
566
|
status: 'success',
|
|
548
567
|
name: toolName,
|
|
@@ -658,7 +677,10 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
658
677
|
*/
|
|
659
678
|
return (
|
|
660
679
|
(call.id == null || !toolMessageIds.has(call.id)) &&
|
|
661
|
-
!(
|
|
680
|
+
!(
|
|
681
|
+
call.id?.startsWith(Constants.ANTHROPIC_SERVER_TOOL_PREFIX) ??
|
|
682
|
+
false
|
|
683
|
+
)
|
|
662
684
|
);
|
|
663
685
|
}) ?? [];
|
|
664
686
|
|
package/src/types/graph.ts
CHANGED
|
@@ -22,6 +22,13 @@ import type { ToolMap, ToolEndEvent, GenericTool, LCTool } from '@/types/tools';
|
|
|
22
22
|
import type { Providers, Callback, GraphNodeKeys } from '@/common';
|
|
23
23
|
import type { StandardGraph, MultiAgentGraph } from '@/graphs';
|
|
24
24
|
import type { ClientOptions } from '@/types/llm';
|
|
25
|
+
import type {
|
|
26
|
+
SummarizationNodeInput,
|
|
27
|
+
SummarizeCompleteEvent,
|
|
28
|
+
SummarizationConfig,
|
|
29
|
+
SummarizeStartEvent,
|
|
30
|
+
SummarizeDeltaEvent,
|
|
31
|
+
} from '@/types/summarize';
|
|
25
32
|
import type {
|
|
26
33
|
RunStep,
|
|
27
34
|
RunStepDeltaEvent,
|
|
@@ -66,12 +73,25 @@ export type BaseGraphState = {
|
|
|
66
73
|
messages: BaseMessage[];
|
|
67
74
|
};
|
|
68
75
|
|
|
76
|
+
export type AgentSubgraphState = BaseGraphState & {
|
|
77
|
+
summarizationRequest?: SummarizationNodeInput;
|
|
78
|
+
};
|
|
79
|
+
|
|
69
80
|
export type MultiAgentGraphState = BaseGraphState & {
|
|
70
81
|
agentMessages?: BaseMessage[];
|
|
71
82
|
};
|
|
72
83
|
|
|
73
84
|
export type IState = BaseGraphState;
|
|
74
85
|
|
|
86
|
+
export interface AgentLogEvent {
|
|
87
|
+
level: 'debug' | 'info' | 'warn' | 'error';
|
|
88
|
+
scope: 'prune' | 'summarize' | 'graph' | 'sanitize' | (string & {});
|
|
89
|
+
message: string;
|
|
90
|
+
data?: Record<string, unknown>;
|
|
91
|
+
runId?: string;
|
|
92
|
+
agentId?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
75
95
|
export interface EventHandler {
|
|
76
96
|
handle(
|
|
77
97
|
event: string,
|
|
@@ -82,6 +102,10 @@ export interface EventHandler {
|
|
|
82
102
|
| RunStepDeltaEvent
|
|
83
103
|
| MessageDeltaEvent
|
|
84
104
|
| ReasoningDeltaEvent
|
|
105
|
+
| SummarizeStartEvent
|
|
106
|
+
| SummarizeDeltaEvent
|
|
107
|
+
| SummarizeCompleteEvent
|
|
108
|
+
| AgentLogEvent
|
|
85
109
|
| { result: ToolEndEvent },
|
|
86
110
|
metadata?: Record<string, unknown>,
|
|
87
111
|
graph?: StandardGraph | MultiAgentGraph
|
|
@@ -142,24 +166,30 @@ export type CompiledMultiAgentWorkflow = CompiledStateGraph<
|
|
|
142
166
|
>;
|
|
143
167
|
|
|
144
168
|
export type CompiledAgentWorfklow = CompiledStateGraph<
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
{
|
|
149
|
-
messages?: BaseMessage[] | undefined;
|
|
150
|
-
},
|
|
151
|
-
'__start__' | `agent=${string}` | `tools=${string}`,
|
|
169
|
+
AgentSubgraphState,
|
|
170
|
+
Partial<AgentSubgraphState>,
|
|
171
|
+
'__start__' | `agent=${string}` | `tools=${string}` | `summarize=${string}`,
|
|
152
172
|
{
|
|
153
173
|
messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
174
|
+
summarizationRequest: BinaryOperatorAggregate<
|
|
175
|
+
SummarizationNodeInput | undefined,
|
|
176
|
+
SummarizationNodeInput | undefined
|
|
177
|
+
>;
|
|
154
178
|
},
|
|
155
179
|
{
|
|
156
180
|
messages: BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
|
|
181
|
+
summarizationRequest: BinaryOperatorAggregate<
|
|
182
|
+
SummarizationNodeInput | undefined,
|
|
183
|
+
SummarizationNodeInput | undefined
|
|
184
|
+
>;
|
|
157
185
|
},
|
|
158
186
|
StateDefinition,
|
|
159
187
|
{
|
|
160
188
|
[x: `agent=${string}`]: Partial<BaseGraphState>;
|
|
161
189
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
162
190
|
[x: `tools=${string}`]: any;
|
|
191
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
192
|
+
[x: `summarize=${string}`]: any;
|
|
163
193
|
}
|
|
164
194
|
>;
|
|
165
195
|
|
|
@@ -314,6 +344,7 @@ export type StandardGraphInput = {
|
|
|
314
344
|
agents: AgentInputs[];
|
|
315
345
|
tokenCounter?: TokenCounter;
|
|
316
346
|
indexTokenCountMap?: Record<string, number>;
|
|
347
|
+
calibrationRatio?: number;
|
|
317
348
|
};
|
|
318
349
|
|
|
319
350
|
export type GraphEdge = {
|
|
@@ -391,4 +422,28 @@ export interface AgentInputs {
|
|
|
391
422
|
* in tool binding without requiring tool_search.
|
|
392
423
|
*/
|
|
393
424
|
discoveredTools?: string[];
|
|
425
|
+
summarizationEnabled?: boolean;
|
|
426
|
+
summarizationConfig?: SummarizationConfig;
|
|
427
|
+
/** Cross-run summary from a previous run, forwarded from formatAgentMessages.
|
|
428
|
+
* Injected into the system message via AgentContext.buildInstructionsString(). */
|
|
429
|
+
initialSummary?: { text: string; tokenCount: number };
|
|
430
|
+
contextPruningConfig?: ContextPruningConfig;
|
|
431
|
+
maxToolResultChars?: number;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export interface ContextPruningConfig {
|
|
435
|
+
enabled?: boolean;
|
|
436
|
+
keepLastAssistants?: number;
|
|
437
|
+
softTrimRatio?: number;
|
|
438
|
+
hardClearRatio?: number;
|
|
439
|
+
minPrunableToolChars?: number;
|
|
440
|
+
softTrim?: {
|
|
441
|
+
maxChars?: number;
|
|
442
|
+
headChars?: number;
|
|
443
|
+
tailChars?: number;
|
|
444
|
+
};
|
|
445
|
+
hardClear?: {
|
|
446
|
+
enabled?: boolean;
|
|
447
|
+
placeholder?: string;
|
|
448
|
+
};
|
|
394
449
|
}
|
package/src/types/index.ts
CHANGED
package/src/types/run.ts
CHANGED
|
@@ -115,6 +115,15 @@ export type RunConfig = {
|
|
|
115
115
|
returnContent?: boolean;
|
|
116
116
|
tokenCounter?: TokenCounter;
|
|
117
117
|
indexTokenCountMap?: Record<string, number>;
|
|
118
|
+
/**
|
|
119
|
+
* Calibration ratio from a previous run's contextMeta.
|
|
120
|
+
* Seeds the pruner's EMA so new messages are scaled immediately.
|
|
121
|
+
*
|
|
122
|
+
* Hosts should persist the value returned by `Run.getCalibrationRatio()`
|
|
123
|
+
* after each run and pass it back here on subsequent runs for the same
|
|
124
|
+
* conversation. Without this, the EMA resets to 1 on every new Run instance.
|
|
125
|
+
*/
|
|
126
|
+
calibrationRatio?: number;
|
|
118
127
|
/** Skip post-stream cleanup (clearHeavyState) — useful for tests that inspect graph state after processStream */
|
|
119
128
|
skipCleanup?: boolean;
|
|
120
129
|
};
|
|
@@ -124,6 +133,29 @@ export type ProvidedCallbacks =
|
|
|
124
133
|
| undefined;
|
|
125
134
|
|
|
126
135
|
export type TokenCounter = (message: BaseMessage) => number;
|
|
136
|
+
|
|
137
|
+
/** Structured breakdown of how context token budget is consumed. */
|
|
138
|
+
export type TokenBudgetBreakdown = {
|
|
139
|
+
/** Total context window budget (maxContextTokens). */
|
|
140
|
+
maxContextTokens: number;
|
|
141
|
+
/** Total instruction tokens (system + tools + summary). */
|
|
142
|
+
instructionTokens: number;
|
|
143
|
+
/** Tokens from the system message text alone. */
|
|
144
|
+
systemMessageTokens: number;
|
|
145
|
+
/** Tokens from tool schema definitions. */
|
|
146
|
+
toolSchemaTokens: number;
|
|
147
|
+
/** Tokens from the conversation summary. */
|
|
148
|
+
summaryTokens: number;
|
|
149
|
+
/** Number of registered tools. */
|
|
150
|
+
toolCount: number;
|
|
151
|
+
/** Number of messages in the conversation. */
|
|
152
|
+
messageCount: number;
|
|
153
|
+
/** Total tokens consumed by messages (excluding system). */
|
|
154
|
+
messageTokens: number;
|
|
155
|
+
/** Tokens available for messages after instructions. */
|
|
156
|
+
availableForMessages: number;
|
|
157
|
+
};
|
|
158
|
+
|
|
127
159
|
export type EventStreamOptions = {
|
|
128
160
|
callbacks?: g.ClientCallbacks;
|
|
129
161
|
keepContent?: boolean;
|
package/src/types/stream.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
|
|
|
10
10
|
import type { LLMResult, Generation } from '@langchain/core/outputs';
|
|
11
11
|
import type { AnthropicContentBlock } from '@/llm/anthropic/types';
|
|
12
12
|
import type { Command } from '@langchain/langgraph';
|
|
13
|
+
import type { SummarizeCompleteEvent } from '@/types/summarize';
|
|
13
14
|
import type { ToolEndEvent } from '@/types/tools';
|
|
14
15
|
import { StepTypes, ContentTypes, GraphEvents } from '@/common/enum';
|
|
15
16
|
|
|
@@ -80,6 +81,7 @@ export type RunStep = {
|
|
|
80
81
|
index: number; // #new
|
|
81
82
|
stepIndex?: number; // #new
|
|
82
83
|
stepDetails: StepDetails;
|
|
84
|
+
summary?: SummaryContentBlock;
|
|
83
85
|
usage?: null | object;
|
|
84
86
|
// {
|
|
85
87
|
// Define usage structure if it's ever non-null
|
|
@@ -106,7 +108,12 @@ export interface RunStepDeltaEvent {
|
|
|
106
108
|
|
|
107
109
|
export type StepDetails = MessageCreationDetails | ToolCallsDetails;
|
|
108
110
|
|
|
109
|
-
export type
|
|
111
|
+
export type SummaryCompleted = {
|
|
112
|
+
type: 'summary';
|
|
113
|
+
summary: SummaryContentBlock;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export type StepCompleted = ToolCallCompleted | SummaryCompleted;
|
|
110
117
|
|
|
111
118
|
export type MessageCreationDetails = {
|
|
112
119
|
type: StepTypes.MESSAGE_CREATION;
|
|
@@ -164,6 +171,7 @@ export type ToolCallsDetails = {
|
|
|
164
171
|
export type ToolCallDelta = {
|
|
165
172
|
type: StepTypes;
|
|
166
173
|
tool_calls?: ToolCallChunk[]; // #new
|
|
174
|
+
summary?: SummaryContentBlock;
|
|
167
175
|
auth?: string;
|
|
168
176
|
expires_at?: number;
|
|
169
177
|
};
|
|
@@ -260,13 +268,35 @@ export type MessageDeltaUpdate = {
|
|
|
260
268
|
};
|
|
261
269
|
export type ReasoningDeltaUpdate = { type: ContentTypes.THINK; think: string };
|
|
262
270
|
|
|
263
|
-
export type ContentType =
|
|
271
|
+
export type ContentType =
|
|
272
|
+
| 'text'
|
|
273
|
+
| 'image_url'
|
|
274
|
+
| 'tool_call'
|
|
275
|
+
| 'think'
|
|
276
|
+
| 'summary'
|
|
277
|
+
| string;
|
|
264
278
|
|
|
265
279
|
export type ReasoningContentText = {
|
|
266
280
|
type: ContentTypes.THINK;
|
|
267
281
|
think: string;
|
|
268
282
|
};
|
|
269
283
|
|
|
284
|
+
export type SummaryBoundary = {
|
|
285
|
+
messageId: string;
|
|
286
|
+
contentIndex: number;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
export type SummaryContentBlock = {
|
|
290
|
+
type: ContentTypes.SUMMARY;
|
|
291
|
+
content?: MessageContentComplex[];
|
|
292
|
+
tokenCount?: number;
|
|
293
|
+
boundary?: SummaryBoundary;
|
|
294
|
+
summaryVersion?: number;
|
|
295
|
+
model?: string;
|
|
296
|
+
provider?: string;
|
|
297
|
+
createdAt?: string;
|
|
298
|
+
};
|
|
299
|
+
|
|
270
300
|
/** Vertex AI / Google Common - Reasoning Content Block Format */
|
|
271
301
|
export type GoogleReasoningContentText = {
|
|
272
302
|
type: ContentTypes.REASONING;
|
|
@@ -330,6 +360,7 @@ export type ToolResultContent = {
|
|
|
330
360
|
export type MessageContentComplex = (
|
|
331
361
|
| ToolResultContent
|
|
332
362
|
| ThinkingContentText
|
|
363
|
+
| SummaryContentBlock
|
|
333
364
|
| AgentUpdate
|
|
334
365
|
| ToolCallContent
|
|
335
366
|
| ReasoningContentText
|
|
@@ -399,6 +430,13 @@ export type SplitStreamHandlers = Partial<{
|
|
|
399
430
|
}) => void;
|
|
400
431
|
}>;
|
|
401
432
|
|
|
433
|
+
export type SummarizeDeltaData = {
|
|
434
|
+
id: string;
|
|
435
|
+
delta: {
|
|
436
|
+
summary: SummaryContentBlock;
|
|
437
|
+
};
|
|
438
|
+
};
|
|
439
|
+
|
|
402
440
|
export type ContentAggregator = ({
|
|
403
441
|
event,
|
|
404
442
|
data,
|
|
@@ -406,11 +444,13 @@ export type ContentAggregator = ({
|
|
|
406
444
|
event: GraphEvents;
|
|
407
445
|
data:
|
|
408
446
|
| RunStep
|
|
447
|
+
| AgentUpdate
|
|
409
448
|
| MessageDeltaEvent
|
|
449
|
+
| ReasoningDeltaEvent
|
|
410
450
|
| RunStepDeltaEvent
|
|
411
|
-
|
|
|
412
|
-
|
|
413
|
-
|
|
451
|
+
| SummarizeDeltaData
|
|
452
|
+
| SummarizeCompleteEvent
|
|
453
|
+
| { result: ToolEndEvent };
|
|
414
454
|
}) => void;
|
|
415
455
|
export type ContentAggregatorResult = {
|
|
416
456
|
stepMap: Map<string, RunStep | undefined>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { SummaryContentBlock } from '@/types/stream';
|
|
2
|
+
import type { Providers } from '@/common';
|
|
3
|
+
|
|
4
|
+
export type SummarizationTrigger = {
|
|
5
|
+
type:
|
|
6
|
+
| 'token_ratio'
|
|
7
|
+
| 'remaining_tokens'
|
|
8
|
+
| 'messages_to_refine'
|
|
9
|
+
| (string & {});
|
|
10
|
+
value: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type SummarizationConfig = {
|
|
14
|
+
provider?: Providers;
|
|
15
|
+
model?: string;
|
|
16
|
+
parameters?: Record<string, unknown>;
|
|
17
|
+
prompt?: string;
|
|
18
|
+
updatePrompt?: string;
|
|
19
|
+
trigger?: SummarizationTrigger;
|
|
20
|
+
maxSummaryTokens?: number;
|
|
21
|
+
/** Fraction of the token budget reserved as headroom (0–1). Defaults to 0.05. */
|
|
22
|
+
reserveRatio?: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export interface SummarizeResult {
|
|
26
|
+
text: string;
|
|
27
|
+
tokenCount: number;
|
|
28
|
+
model?: string;
|
|
29
|
+
provider?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface SummarizationNodeInput {
|
|
33
|
+
remainingContextTokens: number;
|
|
34
|
+
agentId: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface SummarizeStartEvent {
|
|
38
|
+
agentId: string;
|
|
39
|
+
provider: string;
|
|
40
|
+
model?: string;
|
|
41
|
+
messagesToRefineCount: number;
|
|
42
|
+
/** Which summarization cycle this is (1-based, increments each time summarization fires) */
|
|
43
|
+
summaryVersion: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface SummarizeDeltaEvent {
|
|
47
|
+
id: string;
|
|
48
|
+
delta: {
|
|
49
|
+
summary: SummaryContentBlock;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface SummarizeCompleteEvent {
|
|
54
|
+
id: string;
|
|
55
|
+
agentId: string;
|
|
56
|
+
summary?: SummaryContentBlock;
|
|
57
|
+
error?: string;
|
|
58
|
+
}
|
package/src/types/tools.ts
CHANGED
|
@@ -49,6 +49,13 @@ export type ToolNodeOptions = {
|
|
|
49
49
|
agentId?: string;
|
|
50
50
|
/** Tool names that must be executed directly (via runTool) even in event-driven mode (e.g., graph-managed handoff tools) */
|
|
51
51
|
directToolNames?: Set<string>;
|
|
52
|
+
/** Max context tokens for the agent — used to compute tool result truncation limits. */
|
|
53
|
+
maxContextTokens?: number;
|
|
54
|
+
/**
|
|
55
|
+
* Maximum characters allowed in a single tool result before truncation.
|
|
56
|
+
* When provided, takes precedence over the value computed from maxContextTokens.
|
|
57
|
+
*/
|
|
58
|
+
maxToolResultChars?: number;
|
|
52
59
|
};
|
|
53
60
|
|
|
54
61
|
export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context overflow error detection utilities.
|
|
3
|
+
*
|
|
4
|
+
* Identifies provider-specific error messages that indicate the request
|
|
5
|
+
* exceeded the model's context window. Used by the overflow recovery loop
|
|
6
|
+
* to decide whether to retry with truncation/compaction vs. propagating
|
|
7
|
+
* the error.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Exact phrases that definitively indicate a context overflow error.
|
|
12
|
+
* These are returned by various LLM providers when the prompt is too large.
|
|
13
|
+
*/
|
|
14
|
+
const CONTEXT_OVERFLOW_PHRASES = [
|
|
15
|
+
'request_too_large',
|
|
16
|
+
'context length exceeded',
|
|
17
|
+
'maximum context length',
|
|
18
|
+
'prompt is too long',
|
|
19
|
+
'exceeds model context window',
|
|
20
|
+
'exceeds the model',
|
|
21
|
+
'too large for model',
|
|
22
|
+
'context_length_exceeded',
|
|
23
|
+
'max_tokens',
|
|
24
|
+
'token limit',
|
|
25
|
+
'input too long',
|
|
26
|
+
'payload too large',
|
|
27
|
+
'content_too_large',
|
|
28
|
+
] as const;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* HTTP status codes and broader hints that suggest context overflow.
|
|
32
|
+
* Used by the less-strict `isLikelyContextOverflowError`.
|
|
33
|
+
*/
|
|
34
|
+
const CONTEXT_OVERFLOW_HINT_RE =
|
|
35
|
+
/413|too large|too long|context.*exceed|exceed.*context|token.*limit|limit.*token|prompt.*size|size.*limit|maximum.*length|length.*maximum/i;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Patterns that should NOT be treated as context overflow even if they
|
|
39
|
+
* contain words like "limit" or "too large".
|
|
40
|
+
*/
|
|
41
|
+
const FALSE_POSITIVE_RE =
|
|
42
|
+
/rate.?limit|too many requests|quota|billing|auth|permission|forbidden/i;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Extracts a human-readable error message from an unknown error value.
|
|
46
|
+
*/
|
|
47
|
+
export function extractErrorMessage(error: unknown): string {
|
|
48
|
+
if (error == null) {
|
|
49
|
+
return '';
|
|
50
|
+
}
|
|
51
|
+
if (typeof error === 'string') {
|
|
52
|
+
return error;
|
|
53
|
+
}
|
|
54
|
+
if (error instanceof Error) {
|
|
55
|
+
return error.message;
|
|
56
|
+
}
|
|
57
|
+
if (typeof error === 'object') {
|
|
58
|
+
const record = error as Record<string, unknown>;
|
|
59
|
+
if (typeof record.message === 'string') {
|
|
60
|
+
return record.message;
|
|
61
|
+
}
|
|
62
|
+
if (typeof record.error === 'string') {
|
|
63
|
+
return record.error;
|
|
64
|
+
}
|
|
65
|
+
if (
|
|
66
|
+
typeof record.error === 'object' &&
|
|
67
|
+
record.error != null &&
|
|
68
|
+
typeof (record.error as Record<string, unknown>).message === 'string'
|
|
69
|
+
) {
|
|
70
|
+
return (record.error as Record<string, unknown>).message as string;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
return JSON.stringify(error);
|
|
75
|
+
} catch {
|
|
76
|
+
return String(error);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Returns true if the error message definitively indicates a context
|
|
82
|
+
* overflow / prompt-too-large error from the provider.
|
|
83
|
+
*
|
|
84
|
+
* This is the strict check: only matches known, unambiguous phrases.
|
|
85
|
+
* Use this when you want high confidence before taking recovery action.
|
|
86
|
+
*/
|
|
87
|
+
export function isContextOverflowError(errorMessage?: string): boolean {
|
|
88
|
+
if (!errorMessage) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
const lower = errorMessage.toLowerCase();
|
|
92
|
+
if (FALSE_POSITIVE_RE.test(lower)) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
return CONTEXT_OVERFLOW_PHRASES.some((phrase) => lower.includes(phrase));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Returns true if the error message likely indicates a context overflow.
|
|
100
|
+
* Uses broader heuristic matching (regex) in addition to exact phrases.
|
|
101
|
+
*
|
|
102
|
+
* May produce false positives for unusual error messages. Use this when
|
|
103
|
+
* the cost of a false positive (one extra retry) is acceptable.
|
|
104
|
+
*/
|
|
105
|
+
export function isLikelyContextOverflowError(errorMessage?: string): boolean {
|
|
106
|
+
if (!errorMessage) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if (isContextOverflowError(errorMessage)) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
const lower = errorMessage.toLowerCase();
|
|
113
|
+
if (FALSE_POSITIVE_RE.test(lower)) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
return CONTEXT_OVERFLOW_HINT_RE.test(lower);
|
|
117
|
+
}
|
package/src/utils/events.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// src/utils/events.ts
|
|
3
3
|
import { dispatchCustomEvent } from '@langchain/core/callbacks/dispatch';
|
|
4
4
|
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
5
|
+
import type { AgentLogEvent } from '@/types/graph';
|
|
6
|
+
import { GraphEvents } from '@/common';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Safely dispatches a custom event and properly awaits it to avoid
|
|
@@ -30,3 +32,32 @@ export async function safeDispatchCustomEvent(
|
|
|
30
32
|
console.error('Error dispatching custom event:', e);
|
|
31
33
|
}
|
|
32
34
|
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Fire-and-forget diagnostic log event.
|
|
38
|
+
* Debug-level logs are gated behind AGENT_DEBUG_LOGGING=true to avoid
|
|
39
|
+
* overhead in production. Info/warn/error always flow through.
|
|
40
|
+
* Pass `force: true` to bypass the env-var gate (e.g. invoke timing).
|
|
41
|
+
*/
|
|
42
|
+
export function emitAgentLog(
|
|
43
|
+
config: RunnableConfig | undefined,
|
|
44
|
+
level: AgentLogEvent['level'],
|
|
45
|
+
scope: AgentLogEvent['scope'],
|
|
46
|
+
message: string,
|
|
47
|
+
data?: Record<string, unknown>,
|
|
48
|
+
meta?: { runId?: string; agentId?: string },
|
|
49
|
+
options?: { force?: boolean }
|
|
50
|
+
): void {
|
|
51
|
+
if (!config) return;
|
|
52
|
+
if (
|
|
53
|
+
level === 'debug' &&
|
|
54
|
+
!(options?.force ?? false) &&
|
|
55
|
+
process.env.AGENT_DEBUG_LOGGING !== 'true'
|
|
56
|
+
)
|
|
57
|
+
return;
|
|
58
|
+
void safeDispatchCustomEvent(
|
|
59
|
+
GraphEvents.ON_AGENT_LOG,
|
|
60
|
+
{ level, scope, message, data, ...meta } satisfies AgentLogEvent,
|
|
61
|
+
config
|
|
62
|
+
);
|
|
63
|
+
}
|
package/src/utils/handlers.ts
CHANGED
|
@@ -97,6 +97,24 @@ export function createHandlers(callbacks?: HandlerCallbacks): {
|
|
|
97
97
|
callbacks?.onMessageDelta?.(event, data);
|
|
98
98
|
},
|
|
99
99
|
},
|
|
100
|
+
|
|
101
|
+
[GraphEvents.ON_SUMMARIZE_DELTA]: {
|
|
102
|
+
handle: (event: string, data: t.StreamEventData): void => {
|
|
103
|
+
aggregateContent({
|
|
104
|
+
event: event as GraphEvents,
|
|
105
|
+
data: data as t.SummarizeDeltaData,
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
[GraphEvents.ON_SUMMARIZE_COMPLETE]: {
|
|
111
|
+
handle: (event: string, data: t.StreamEventData): void => {
|
|
112
|
+
aggregateContent({
|
|
113
|
+
event: event as GraphEvents,
|
|
114
|
+
data: data as t.SummarizeCompleteEvent,
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
},
|
|
100
118
|
};
|
|
101
119
|
|
|
102
120
|
return {
|
package/src/utils/index.ts
CHANGED
package/src/utils/llm.ts
CHANGED
|
@@ -24,3 +24,15 @@ export function isGoogleLike(provider?: string | Providers): boolean {
|
|
|
24
24
|
provider
|
|
25
25
|
);
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
/** Returns true for native Anthropic or Bedrock running a Claude model. */
|
|
29
|
+
export function isAnthropicLike(
|
|
30
|
+
provider?: string | Providers,
|
|
31
|
+
clientOptions?: { model?: string }
|
|
32
|
+
): boolean {
|
|
33
|
+
if (provider === Providers.ANTHROPIC) return true;
|
|
34
|
+
if (provider === Providers.BEDROCK) {
|
|
35
|
+
return /claude/i.test(String(clientOptions?.model ?? ''));
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|