@librechat/agents 3.7.15 → 3.7.17
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 +91 -0
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/agents/projection.cjs +2 -1
- package/dist/cjs/agents/projection.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +47 -6
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +20 -7
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/llm/preempt.cjs +1 -10
- package/dist/cjs/llm/preempt.cjs.map +1 -1
- package/dist/cjs/main.cjs +23 -3
- package/dist/cjs/messages/contextPruning.cjs +1 -1
- package/dist/cjs/messages/contextPruning.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +29 -1
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/fading.cjs +122 -0
- package/dist/cjs/messages/fading.cjs.map +1 -0
- package/dist/cjs/messages/format.cjs +1 -1
- package/dist/cjs/messages/index.cjs +1 -0
- package/dist/cjs/messages/prune.cjs +364 -236
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/run.cjs +27 -0
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +213 -8
- package/dist/cjs/session/AgentSession.cjs.map +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +41 -0
- package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
- package/dist/cjs/session/index.cjs +1 -1
- package/dist/cjs/stream.cjs +1 -1
- package/dist/cjs/summarization/node.cjs +1 -1
- package/dist/cjs/tools/ToolNode.cjs +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +2 -0
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs +2 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
- package/dist/cjs/utils/errors.cjs +3 -1
- package/dist/cjs/utils/errors.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +1 -1
- package/dist/cjs/utils/truncation.cjs +9 -0
- package/dist/cjs/utils/truncation.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +92 -1
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/agents/projection.mjs +2 -1
- package/dist/esm/agents/projection.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +47 -6
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +20 -7
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +2 -2
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/llm/preempt.mjs +1 -10
- package/dist/esm/llm/preempt.mjs.map +1 -1
- package/dist/esm/main.mjs +6 -5
- package/dist/esm/messages/contextPruning.mjs +1 -1
- package/dist/esm/messages/contextPruning.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +29 -2
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/fading.mjs +108 -0
- package/dist/esm/messages/fading.mjs.map +1 -0
- package/dist/esm/messages/format.mjs +1 -1
- package/dist/esm/messages/index.mjs +1 -0
- package/dist/esm/messages/prune.mjs +363 -235
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/run.mjs +27 -0
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +213 -8
- package/dist/esm/session/AgentSession.mjs.map +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +41 -0
- package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
- package/dist/esm/session/index.mjs +1 -1
- package/dist/esm/stream.mjs +1 -1
- package/dist/esm/summarization/node.mjs +1 -1
- package/dist/esm/tools/ToolNode.mjs +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +2 -0
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs +2 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
- package/dist/esm/utils/errors.mjs +3 -1
- package/dist/esm/utils/errors.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +1 -1
- package/dist/esm/utils/truncation.mjs +7 -1
- package/dist/esm/utils/truncation.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +32 -1
- package/dist/types/agents/projection.d.ts +3 -1
- package/dist/types/graphs/Graph.d.ts +14 -1
- package/dist/types/graphs/MultiAgentGraph.d.ts +7 -0
- package/dist/types/messages/contextPruning.d.ts +2 -0
- package/dist/types/messages/core.d.ts +2 -0
- package/dist/types/messages/fading.d.ts +81 -0
- package/dist/types/messages/index.d.ts +1 -0
- package/dist/types/messages/prune.d.ts +71 -24
- package/dist/types/run.d.ts +16 -0
- package/dist/types/session/AgentSession.d.ts +15 -0
- package/dist/types/session/JsonlSessionStore.d.ts +4 -1
- package/dist/types/session/types.d.ts +9 -0
- package/dist/types/tools/subagent/SubagentReplay.d.ts +3 -1
- package/dist/types/types/graph.d.ts +23 -0
- package/dist/types/types/run.d.ts +10 -0
- package/dist/types/utils/truncation.d.ts +9 -0
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +175 -1
- package/src/agents/projection.ts +4 -0
- package/src/graphs/Graph.ts +97 -11
- package/src/graphs/MultiAgentGraph.ts +54 -6
- package/src/llm/openai/utils/index.ts +3 -1
- package/src/llm/preempt.ts +4 -17
- package/src/messages/contextPruning.ts +7 -1
- package/src/messages/core.ts +52 -0
- package/src/messages/fading.ts +301 -0
- package/src/messages/index.ts +1 -0
- package/src/messages/prune.ts +719 -507
- package/src/run.ts +52 -0
- package/src/session/AgentSession.ts +397 -8
- package/src/session/JsonlSessionStore.ts +71 -0
- package/src/session/types.ts +10 -0
- package/src/tools/subagent/SubagentExecutor.ts +6 -0
- package/src/tools/subagent/SubagentReplay.ts +15 -2
- package/src/types/graph.ts +25 -0
- package/src/types/run.ts +10 -0
- package/src/utils/errors.ts +17 -1
- package/src/utils/truncation.ts +25 -0
package/src/graphs/Graph.ts
CHANGED
|
@@ -54,7 +54,6 @@ import {
|
|
|
54
54
|
CALIBRATION_RATIO_MAX,
|
|
55
55
|
createPruneMessages,
|
|
56
56
|
projectToolMessagesForProvider,
|
|
57
|
-
calculateMaxToolCallInputChars,
|
|
58
57
|
syncBudgetDerivedFields,
|
|
59
58
|
addTailCacheControl,
|
|
60
59
|
resolvePromptCacheTtl,
|
|
@@ -156,6 +155,7 @@ import { createContextPressureMeter } from '@/llm/contextPressureMeter';
|
|
|
156
155
|
import { safeDispatchCustomEvent, emitAgentLog } from '@/utils/events';
|
|
157
156
|
import { prepareProviderRequest } from '@/llm/prepareProviderRequest';
|
|
158
157
|
import { createCloudflareCodingToolBundle } from '@/tools/cloudflare';
|
|
158
|
+
import { calculateMaxToolCallInputChars } from '@/utils/truncation';
|
|
159
159
|
import { prepareToolsForPromptCache } from '@/llm/promptCacheTools';
|
|
160
160
|
import { providerRequiresStrictAlternation } from '@/llm/providers';
|
|
161
161
|
import { buildSubagentToolParams } from '@/tools/SubagentTool';
|
|
@@ -163,6 +163,7 @@ import { initializeLangfuseTracing } from '@/instrumentation';
|
|
|
163
163
|
import { shouldTriggerSummarization } from '@/summarization';
|
|
164
164
|
import { isRunStepResumeState } from '@/tools/runStepResume';
|
|
165
165
|
import { resolveLocalToolsForBinding } from '@/tools/local';
|
|
166
|
+
import { isFadingTier, isInformativeFadingTier } from '@/messages/fading';
|
|
166
167
|
import { createSummarizeNode } from '@/summarization/node';
|
|
167
168
|
import { getTruncationStopReason } from '@/llm/truncation';
|
|
168
169
|
import { messagesStateReducer } from '@/messages/reducer';
|
|
@@ -1070,6 +1071,13 @@ export abstract class Graph<
|
|
|
1070
1071
|
return [...threadIds];
|
|
1071
1072
|
}
|
|
1072
1073
|
|
|
1074
|
+
protected createSubagentFadingResumeState(): Pick<
|
|
1075
|
+
SubagentGraphResumeState,
|
|
1076
|
+
'fadingTier' | 'fadingTiers'
|
|
1077
|
+
> {
|
|
1078
|
+
return {};
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1073
1081
|
createSubagentResumeState(runId: string): SubagentGraphResumeState {
|
|
1074
1082
|
return {
|
|
1075
1083
|
toolCallSteps: [...this.toolCallStepIds].map(([toolCallId, stepId]) => ({
|
|
@@ -1107,6 +1115,7 @@ export abstract class Graph<
|
|
|
1107
1115
|
],
|
|
1108
1116
|
eagerToolSuppressions: [...this.eagerEventToolSuppressions],
|
|
1109
1117
|
runStepState: this.createRunStepResumeState(),
|
|
1118
|
+
...this.createSubagentFadingResumeState(),
|
|
1110
1119
|
...(this._toolOutputRegistry == null
|
|
1111
1120
|
? {}
|
|
1112
1121
|
: {
|
|
@@ -1491,6 +1500,8 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1491
1500
|
tokenCounter,
|
|
1492
1501
|
indexTokenCountMap,
|
|
1493
1502
|
calibrationRatio,
|
|
1503
|
+
fadingTier,
|
|
1504
|
+
fadingTiers,
|
|
1494
1505
|
subagentUsageSink,
|
|
1495
1506
|
subagentTasks,
|
|
1496
1507
|
subagentScope,
|
|
@@ -1539,6 +1550,21 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1539
1550
|
if (calibrationRatio != null && calibrationRatio > 0) {
|
|
1540
1551
|
agentContext.calibrationRatio = calibrationRatio;
|
|
1541
1552
|
}
|
|
1553
|
+
let restoredFadingTier: t.FadingTier | null | undefined;
|
|
1554
|
+
if (
|
|
1555
|
+
fadingTiers != null &&
|
|
1556
|
+
Object.prototype.hasOwnProperty.call(fadingTiers, agentConfig.agentId)
|
|
1557
|
+
) {
|
|
1558
|
+
restoredFadingTier = fadingTiers[agentConfig.agentId];
|
|
1559
|
+
} else if (agentConfig.agentId === agents[0].agentId) {
|
|
1560
|
+
restoredFadingTier = fadingTier;
|
|
1561
|
+
}
|
|
1562
|
+
/** A supplied tier is assumed to describe the supplied history. Hosts
|
|
1563
|
+
* must clear it when they create a new summary; this also permits tiers
|
|
1564
|
+
* learned on turns after a durable summary to survive subsequent Runs. */
|
|
1565
|
+
if (isFadingTier(restoredFadingTier)) {
|
|
1566
|
+
agentContext.fadingTier = { ...restoredFadingTier };
|
|
1567
|
+
}
|
|
1542
1568
|
|
|
1543
1569
|
this.agentContexts.set(agentConfig.agentId, agentContext);
|
|
1544
1570
|
}
|
|
@@ -2551,6 +2577,57 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2551
2577
|
return context?.calibrationRatio ?? 1;
|
|
2552
2578
|
}
|
|
2553
2579
|
|
|
2580
|
+
/**
|
|
2581
|
+
* Latched context-fading tier for the default agent, or undefined while it
|
|
2582
|
+
* is still fresh. Hosts persist it beside the calibration ratio.
|
|
2583
|
+
*/
|
|
2584
|
+
getFadingTier(): t.FadingTier | undefined {
|
|
2585
|
+
const context = this.agentContexts.get(this.defaultAgentId);
|
|
2586
|
+
const tier = context?.fadingTier;
|
|
2587
|
+
return isInformativeFadingTier(tier, context?.maxContextTokens)
|
|
2588
|
+
? { ...tier }
|
|
2589
|
+
: undefined;
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2592
|
+
/** Latched context-fading tiers keyed by agent ID. */
|
|
2593
|
+
getFadingTiers(): t.FadingTiers {
|
|
2594
|
+
const tiers: Array<[string, t.FadingTier]> = [];
|
|
2595
|
+
for (const [agentId, context] of this.agentContexts) {
|
|
2596
|
+
if (
|
|
2597
|
+
isInformativeFadingTier(context.fadingTier, context.maxContextTokens)
|
|
2598
|
+
) {
|
|
2599
|
+
tiers.push([agentId, { ...context.fadingTier }]);
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
return Object.fromEntries(tiers);
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
/** Agent IDs whose canonical history was compacted during this run. */
|
|
2606
|
+
getFadingTierResetAgentIds(): string[] {
|
|
2607
|
+
return Array.from(this.agentContexts)
|
|
2608
|
+
.filter(([, context]) => context.fadingTierReset)
|
|
2609
|
+
.map(([agentId]) => agentId);
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
/** Whether the default agent compacted canonical history during this run. */
|
|
2613
|
+
didResetFadingTier(): boolean {
|
|
2614
|
+
return (
|
|
2615
|
+
this.agentContexts.get(this.defaultAgentId)?.fadingTierReset === true
|
|
2616
|
+
);
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
protected override createSubagentFadingResumeState(): Pick<
|
|
2620
|
+
SubagentGraphResumeState,
|
|
2621
|
+
'fadingTier' | 'fadingTiers'
|
|
2622
|
+
> {
|
|
2623
|
+
const fadingTier = this.getFadingTier();
|
|
2624
|
+
const fadingTiers = this.getFadingTiers();
|
|
2625
|
+
return {
|
|
2626
|
+
...(fadingTier == null ? {} : { fadingTier }),
|
|
2627
|
+
...(Object.keys(fadingTiers).length === 0 ? {} : { fadingTiers }),
|
|
2628
|
+
};
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2554
2631
|
getResolvedInstructionOverhead(): number | undefined {
|
|
2555
2632
|
const context = this.agentContexts.get(this.defaultAgentId);
|
|
2556
2633
|
return context?.resolvedInstructionOverhead;
|
|
@@ -3059,6 +3136,12 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
3059
3136
|
* same masking record the configured trigger preserves.
|
|
3060
3137
|
*/
|
|
3061
3138
|
let prunedOriginalToolContent: Map<number, string> | undefined;
|
|
3139
|
+
const canProjectContext =
|
|
3140
|
+
agentContext.tokenCounter != null &&
|
|
3141
|
+
agentContext.maxContextTokens != null;
|
|
3142
|
+
const providerMessages = canProjectContext
|
|
3143
|
+
? agentContext.getProviderProjectedMessages(messages)
|
|
3144
|
+
: messages;
|
|
3062
3145
|
if (
|
|
3063
3146
|
!agentContext.pruneMessages &&
|
|
3064
3147
|
agentContext.tokenCounter &&
|
|
@@ -3080,6 +3163,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
3080
3163
|
summarizationEnabled: agentContext.summarizationEnabled,
|
|
3081
3164
|
reserveRatio: agentContext.summarizationConfig?.reserveRatio,
|
|
3082
3165
|
calibrationRatio: agentContext.calibrationRatio,
|
|
3166
|
+
fadingTier: agentContext.fadingTier,
|
|
3083
3167
|
getInstructionTokens: () => agentContext.instructionTokens,
|
|
3084
3168
|
log: (level, message, data) => {
|
|
3085
3169
|
emitAgentLog(config, level, 'prune', message, data, {
|
|
@@ -3098,29 +3182,28 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
3098
3182
|
remainingContextTokens,
|
|
3099
3183
|
newOriginalToolContent,
|
|
3100
3184
|
calibrationRatio,
|
|
3185
|
+
fadingTier,
|
|
3101
3186
|
resolvedInstructionOverhead,
|
|
3102
3187
|
contextBudget,
|
|
3103
3188
|
effectiveInstructionTokens,
|
|
3104
3189
|
} = agentContext.pruneMessages({
|
|
3105
|
-
messages,
|
|
3190
|
+
messages: providerMessages,
|
|
3191
|
+
canonicalMessages: messages,
|
|
3192
|
+
canonicalPrefixStable: true,
|
|
3106
3193
|
usageMetadata: agentContext.currentUsage,
|
|
3107
3194
|
lastCallUsage: agentContext.lastCallUsage,
|
|
3108
3195
|
totalTokensFresh: agentContext.totalTokensFresh,
|
|
3109
3196
|
});
|
|
3110
3197
|
prunedOriginalToolContent = newOriginalToolContent;
|
|
3111
|
-
/**
|
|
3112
|
-
*
|
|
3113
|
-
*
|
|
3114
|
-
* every prune, not just when a summary is about to be written — the
|
|
3115
|
-
* pruner closure that produced it is discarded on the next reset, and
|
|
3116
|
-
* with it any chance of a later summary restoring the real content.
|
|
3117
|
-
* AgentContext bounds what accumulates.
|
|
3118
|
-
*/
|
|
3198
|
+
/** Preserve the masking record for the existing overflow/summarization
|
|
3199
|
+
* path. The graph history itself remains canonical; only the provider
|
|
3200
|
+
* projection above is rewritten by fading. */
|
|
3119
3201
|
agentContext.preserveOriginalToolContent(newOriginalToolContent);
|
|
3120
3202
|
agentContext.indexTokenCountMap = indexTokenCountMap;
|
|
3121
3203
|
if (calibrationRatio != null && calibrationRatio > 0) {
|
|
3122
3204
|
agentContext.calibrationRatio = calibrationRatio;
|
|
3123
3205
|
}
|
|
3206
|
+
agentContext.fadingTier = fadingTier;
|
|
3124
3207
|
if (resolvedInstructionOverhead != null) {
|
|
3125
3208
|
agentContext.resolvedInstructionOverhead =
|
|
3126
3209
|
resolvedInstructionOverhead;
|
|
@@ -5031,7 +5114,10 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
5031
5114
|
|
|
5032
5115
|
const StateAnnotation = Annotation.Root({
|
|
5033
5116
|
messages: Annotation<BaseMessage[]>({
|
|
5034
|
-
reducer:
|
|
5117
|
+
reducer: (a, b) => {
|
|
5118
|
+
agentContext.invalidateProviderProjectionForMessageUpdates(b);
|
|
5119
|
+
return messagesStateReducer(a, b);
|
|
5120
|
+
},
|
|
5035
5121
|
default: () => [],
|
|
5036
5122
|
}),
|
|
5037
5123
|
summarizationRequest: Annotation<t.SummarizationNodeInput | undefined>({
|
|
@@ -30,7 +30,10 @@ import {
|
|
|
30
30
|
} from '@/messages/provenance';
|
|
31
31
|
import { serializeToolContentBounded } from '@/utils/toolContent';
|
|
32
32
|
import { Constants, MULTI_AGENT_GRAPH_RUN_NAME } from '@/common';
|
|
33
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
calculateMaxToolResultChars,
|
|
35
|
+
HARD_MAX_TOOL_RESULT_CHARS,
|
|
36
|
+
} from '@/utils/truncation';
|
|
34
37
|
import { StandardGraph } from './Graph';
|
|
35
38
|
|
|
36
39
|
/** Pattern to extract instructions from transfer ToolMessage content */
|
|
@@ -970,6 +973,29 @@ export class MultiAgentGraph extends StandardGraph {
|
|
|
970
973
|
* @param agentId - The agent ID to check for handoff reception
|
|
971
974
|
* @returns Object with filtered messages, extracted instructions, source agent, and parallel siblings
|
|
972
975
|
*/
|
|
976
|
+
/**
|
|
977
|
+
* Character cap for text injected into an agent's context as a routing or
|
|
978
|
+
* handoff prompt, derived from that agent's remaining message budget. Fading
|
|
979
|
+
* only shrinks tool content, so a prompt above this cap could overflow the
|
|
980
|
+
* agent's window or force the routing instruction out of its context.
|
|
981
|
+
*/
|
|
982
|
+
private async resolveMaxRoutingPromptChars(agentId: string): Promise<number> {
|
|
983
|
+
const agentContext = this.agentContexts.get(agentId);
|
|
984
|
+
if (agentContext?.tokenCalculationPromise != null) {
|
|
985
|
+
await agentContext.tokenCalculationPromise;
|
|
986
|
+
}
|
|
987
|
+
const availableMessageTokens =
|
|
988
|
+
agentContext?.maxContextTokens == null
|
|
989
|
+
? undefined
|
|
990
|
+
: agentContext.getTokenBudgetBreakdown().availableForMessages;
|
|
991
|
+
if (availableMessageTokens == null) {
|
|
992
|
+
return HARD_MAX_TOOL_RESULT_CHARS;
|
|
993
|
+
}
|
|
994
|
+
return availableMessageTokens <= 0
|
|
995
|
+
? 0
|
|
996
|
+
: calculateMaxToolResultChars(availableMessageTokens);
|
|
997
|
+
}
|
|
998
|
+
|
|
973
999
|
private processHandoffReception(
|
|
974
1000
|
messages: BaseMessage[],
|
|
975
1001
|
agentId: string
|
|
@@ -1358,6 +1384,12 @@ export class MultiAgentGraph extends StandardGraph {
|
|
|
1358
1384
|
*/
|
|
1359
1385
|
const hasInstructions = instructions !== null && instructions !== '';
|
|
1360
1386
|
if (hasInstructions) {
|
|
1387
|
+
/** Bounded like a direct-edge routing prompt: a HumanMessage is
|
|
1388
|
+
* not tool content, so fading could never shrink it later. */
|
|
1389
|
+
const boundedInstructions = serializeToolContentBounded(
|
|
1390
|
+
instructions,
|
|
1391
|
+
await this.resolveMaxRoutingPromptChars(agentId)
|
|
1392
|
+
);
|
|
1361
1393
|
const lastMsg =
|
|
1362
1394
|
filteredMessages.length > 0
|
|
1363
1395
|
? filteredMessages[filteredMessages.length - 1]
|
|
@@ -1371,12 +1403,12 @@ export class MultiAgentGraph extends StandardGraph {
|
|
|
1371
1403
|
`[Processed tool result and transferring to ${agentId}]`
|
|
1372
1404
|
)
|
|
1373
1405
|
),
|
|
1374
|
-
buildRoutingPrompt(
|
|
1406
|
+
buildRoutingPrompt(boundedInstructions),
|
|
1375
1407
|
];
|
|
1376
1408
|
} else {
|
|
1377
1409
|
messagesForAgent = [
|
|
1378
1410
|
...filteredMessages,
|
|
1379
|
-
buildRoutingPrompt(
|
|
1411
|
+
buildRoutingPrompt(boundedInstructions),
|
|
1380
1412
|
];
|
|
1381
1413
|
}
|
|
1382
1414
|
}
|
|
@@ -1576,18 +1608,34 @@ export class MultiAgentGraph extends StandardGraph {
|
|
|
1576
1608
|
builder.addNode(wrapperNodeId, async (state: t.BaseGraphState) => {
|
|
1577
1609
|
let promptText: string | undefined;
|
|
1578
1610
|
let effectiveExcludeResults = excludeResults;
|
|
1611
|
+
const getMaxRoutingPromptChars = (): Promise<number> =>
|
|
1612
|
+
this.resolveMaxRoutingPromptChars(destination);
|
|
1579
1613
|
|
|
1580
1614
|
if (typeof prompt === 'function') {
|
|
1581
|
-
|
|
1615
|
+
const resolvedPrompt = await prompt(state.messages, this.startIndex);
|
|
1616
|
+
promptText =
|
|
1617
|
+
resolvedPrompt == null
|
|
1618
|
+
? undefined
|
|
1619
|
+
: serializeToolContentBounded(
|
|
1620
|
+
resolvedPrompt,
|
|
1621
|
+
await getMaxRoutingPromptChars()
|
|
1622
|
+
);
|
|
1582
1623
|
} else if (prompt != null) {
|
|
1583
1624
|
if (prompt.includes('{results}')) {
|
|
1584
1625
|
const resultsMessages = state.messages.slice(this.startIndex);
|
|
1585
|
-
const
|
|
1626
|
+
const maxRoutingPromptChars = await getMaxRoutingPromptChars();
|
|
1627
|
+
const resultsString = serializeToolContentBounded(
|
|
1628
|
+
getBufferString(resultsMessages),
|
|
1629
|
+
maxRoutingPromptChars
|
|
1630
|
+
);
|
|
1586
1631
|
const promptTemplate = PromptTemplate.fromTemplate(prompt);
|
|
1587
1632
|
const result = await promptTemplate.invoke({
|
|
1588
1633
|
results: resultsString,
|
|
1589
1634
|
});
|
|
1590
|
-
promptText =
|
|
1635
|
+
promptText = serializeToolContentBounded(
|
|
1636
|
+
result.value,
|
|
1637
|
+
maxRoutingPromptChars
|
|
1638
|
+
);
|
|
1591
1639
|
effectiveExcludeResults =
|
|
1592
1640
|
excludeResults !== false && promptText !== '';
|
|
1593
1641
|
} else {
|
|
@@ -48,11 +48,13 @@ import {
|
|
|
48
48
|
OPENAI_RESPONSES_STREAMED_TOOL_CALL_ADAPTER,
|
|
49
49
|
} from '@/tools/streamedToolCallSeals';
|
|
50
50
|
import {
|
|
51
|
+
HARD_MAX_TOOL_RESULT_CHARS,
|
|
51
52
|
calculateMaxToolCallInputChars,
|
|
53
|
+
} from '@/utils/truncation';
|
|
54
|
+
import {
|
|
52
55
|
projectToolCallInputs,
|
|
53
56
|
serializeToolCallInput,
|
|
54
57
|
} from '@/messages/prune';
|
|
55
|
-
import { HARD_MAX_TOOL_RESULT_CHARS } from '@/utils/truncation';
|
|
56
58
|
import { toLangChainContent } from '@/messages/langchain';
|
|
57
59
|
|
|
58
60
|
export type { OpenAICallOptions, OpenAIChatInput };
|
package/src/llm/preempt.ts
CHANGED
|
@@ -5,7 +5,10 @@ import {
|
|
|
5
5
|
DEFAULT_MAX_SEALS,
|
|
6
6
|
DEFAULT_PREEMPT_RESTART_GRACE_MS,
|
|
7
7
|
} from '@/common';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
hasNonEmptyTextContent,
|
|
10
|
+
isReasoningContentBlock,
|
|
11
|
+
} from '@/messages/core';
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Normalizes a host-supplied seal budget.
|
|
@@ -33,22 +36,6 @@ export function resolveMaxSeals(maxSeals: number | undefined): number {
|
|
|
33
36
|
* stripped or signed on several providers and cannot stand in for the visible
|
|
34
37
|
* assistant turn a sealed sequence needs.
|
|
35
38
|
*/
|
|
36
|
-
function hasNonEmptyTextContent(content: AIMessageChunk['content']): boolean {
|
|
37
|
-
if (typeof content === 'string') {
|
|
38
|
-
return content.trim() !== '';
|
|
39
|
-
}
|
|
40
|
-
for (const block of content) {
|
|
41
|
-
if (block.type !== ContentTypes.TEXT) {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
const text = block[ContentTypes.TEXT];
|
|
45
|
-
if (typeof text === 'string' && text.trim() !== '') {
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
39
|
/**
|
|
53
40
|
* True while a Gemini server-side tool call is still awaiting its response.
|
|
54
41
|
*
|
|
@@ -60,6 +60,8 @@ export interface ContextPruningResult {
|
|
|
60
60
|
*/
|
|
61
61
|
export function applyContextPruning(params: {
|
|
62
62
|
messages: BaseMessage[];
|
|
63
|
+
/** Full graph history used only to decide whether a projected result is eligible. */
|
|
64
|
+
canonicalMessages?: BaseMessage[];
|
|
63
65
|
indexTokenCountMap: Record<string, number | undefined>;
|
|
64
66
|
tokenCounter: TokenCounter;
|
|
65
67
|
config?: ContextPruningConfig;
|
|
@@ -138,7 +140,11 @@ export function applyContextPruning(params: {
|
|
|
138
140
|
}
|
|
139
141
|
const content = message.content;
|
|
140
142
|
const contentLength = getToolContentCharLength(content);
|
|
141
|
-
|
|
143
|
+
const eligibilityContent = params.canonicalMessages?.[i]?.content ?? content;
|
|
144
|
+
if (
|
|
145
|
+
getToolContentCharLength(eligibilityContent) <
|
|
146
|
+
settings.minPrunableToolChars
|
|
147
|
+
) {
|
|
142
148
|
continue;
|
|
143
149
|
}
|
|
144
150
|
|
package/src/messages/core.ts
CHANGED
|
@@ -2793,3 +2793,55 @@ export function findLastIndex<T>(
|
|
|
2793
2793
|
}
|
|
2794
2794
|
return -1;
|
|
2795
2795
|
}
|
|
2796
|
+
|
|
2797
|
+
/** Reads an own data property without invoking accessors; `undefined` otherwise. */
|
|
2798
|
+
function readOwnDataProperty(target: object, key: PropertyKey): unknown {
|
|
2799
|
+
try {
|
|
2800
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
2801
|
+
return descriptor != null && 'value' in descriptor ? descriptor.value : undefined;
|
|
2802
|
+
} catch {
|
|
2803
|
+
return undefined;
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2807
|
+
/** Whether message content carries non-whitespace text in any text block. */
|
|
2808
|
+
export function hasNonEmptyTextContent(content: BaseMessage['content']): boolean {
|
|
2809
|
+
if (typeof content === 'string') {
|
|
2810
|
+
return content.trim() !== '';
|
|
2811
|
+
}
|
|
2812
|
+
if (!Array.isArray(content) || isProxy(content)) {
|
|
2813
|
+
return false;
|
|
2814
|
+
}
|
|
2815
|
+
/** Index reads through own data descriptors: `for...of` would invoke a
|
|
2816
|
+
* hostile `Symbol.iterator` or an accessor-backed element before any guard. */
|
|
2817
|
+
const length = readOwnDataProperty(content, 'length');
|
|
2818
|
+
const blockCount = typeof length === 'number' ? length : 0;
|
|
2819
|
+
for (let i = 0; i < blockCount; i++) {
|
|
2820
|
+
const block = readOwnDataProperty(content, i);
|
|
2821
|
+
if (typeof block !== 'object' || block == null || isProxy(block)) {
|
|
2822
|
+
continue;
|
|
2823
|
+
}
|
|
2824
|
+
try {
|
|
2825
|
+
const type = Object.getOwnPropertyDescriptor(block, 'type');
|
|
2826
|
+
if (
|
|
2827
|
+
type == null ||
|
|
2828
|
+
!('value' in type) ||
|
|
2829
|
+
(type.value !== ContentTypes.TEXT && type.value !== 'output_text')
|
|
2830
|
+
) {
|
|
2831
|
+
continue;
|
|
2832
|
+
}
|
|
2833
|
+
const text = Object.getOwnPropertyDescriptor(block, ContentTypes.TEXT);
|
|
2834
|
+
if (
|
|
2835
|
+
text != null &&
|
|
2836
|
+
'value' in text &&
|
|
2837
|
+
typeof text.value === 'string' &&
|
|
2838
|
+
text.value.trim() !== ''
|
|
2839
|
+
) {
|
|
2840
|
+
return true;
|
|
2841
|
+
}
|
|
2842
|
+
} catch {
|
|
2843
|
+
continue;
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
return false;
|
|
2847
|
+
}
|