@librechat/agents 3.3.0 → 3.3.2
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 +116 -2
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/enum.cjs +2 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +229 -48
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +102 -27
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +11 -2
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/contextOverflowRecovery.cjs +132 -0
- package/dist/cjs/llm/contextOverflowRecovery.cjs.map +1 -0
- package/dist/cjs/llm/google/index.cjs +1 -1
- package/dist/cjs/llm/invoke.cjs +60 -3
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/main.cjs +20 -7
- package/dist/cjs/messages/prune.cjs +16 -5
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/messages/recency.cjs +2 -0
- package/dist/cjs/messages/recency.cjs.map +1 -1
- package/dist/cjs/run.cjs +15 -2
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +205 -49
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +55 -7
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +2 -2
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +2 -2
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +69 -8
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +19 -15
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +32 -3
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/utils/errors.cjs +317 -52
- package/dist/cjs/utils/errors.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +117 -3
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/enum.mjs +2 -0
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +227 -46
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +102 -27
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +11 -2
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/contextOverflowRecovery.mjs +130 -0
- package/dist/esm/llm/contextOverflowRecovery.mjs.map +1 -0
- package/dist/esm/llm/google/index.mjs +1 -1
- package/dist/esm/llm/invoke.mjs +59 -4
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/main.mjs +9 -9
- package/dist/esm/messages/prune.mjs +14 -6
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/messages/recency.mjs +2 -1
- package/dist/esm/messages/recency.mjs.map +1 -1
- package/dist/esm/run.mjs +15 -2
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +205 -49
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +55 -7
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +3 -3
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +3 -3
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +62 -9
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +20 -16
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +32 -3
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/utils/errors.mjs +317 -53
- package/dist/esm/utils/errors.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +62 -3
- package/dist/types/common/enum.d.ts +2 -0
- package/dist/types/graphs/Graph.d.ts +16 -2
- package/dist/types/graphs/MultiAgentGraph.d.ts +1 -0
- package/dist/types/llm/contextOverflowRecovery.d.ts +85 -0
- package/dist/types/llm/invoke.d.ts +35 -6
- package/dist/types/messages/prune.d.ts +10 -2
- package/dist/types/messages/recency.d.ts +1 -0
- package/dist/types/run.d.ts +2 -0
- package/dist/types/tools/CodeExecutor.d.ts +14 -1
- package/dist/types/types/llm.d.ts +7 -4
- package/dist/types/types/stream.d.ts +5 -4
- package/dist/types/types/summarize.d.ts +22 -0
- package/dist/types/utils/__tests__/fixtures/contextOverflowSignatures.d.ts +40 -0
- package/dist/types/utils/errors.d.ts +65 -16
- package/dist/types/utils/redactSecrets.d.ts +3 -0
- package/package.json +10 -11
- package/src/agents/AgentContext.ts +188 -7
- package/src/agents/__tests__/AgentContext.overflow.test.ts +205 -0
- package/src/common/enum.ts +2 -0
- package/src/graphs/Graph.ts +389 -58
- package/src/graphs/MultiAgentGraph.ts +184 -46
- package/src/graphs/__tests__/Graph.contextOverflow.test.ts +631 -0
- package/src/llm/__tests__/contextOverflowRecovery.test.ts +401 -0
- package/src/llm/__tests__/fallbackOverflow.test.ts +287 -0
- package/src/llm/anthropic/llm.spec.ts +8 -0
- package/src/llm/bedrock/index.ts +25 -12
- package/src/llm/contextOverflowRecovery.ts +292 -0
- package/src/llm/invoke.ts +119 -4
- package/src/messages/prune.ts +24 -11
- package/src/messages/recency.ts +3 -1
- package/src/run.ts +24 -1
- package/src/scripts/context-overflow-probe.ts +997 -0
- package/src/specs/agent-handoffs.test.ts +903 -1
- package/src/specs/context-overflow-recovery.live.test.ts +213 -0
- package/src/splitStream.test.ts +882 -0
- package/src/stream.ts +315 -51
- package/src/summarization/__tests__/aggregator.test.ts +83 -0
- package/src/summarization/__tests__/node.test.ts +139 -0
- package/src/summarization/node.ts +99 -14
- package/src/tools/BashExecutor.ts +4 -2
- package/src/tools/BashProgrammaticToolCalling.ts +4 -7
- package/src/tools/CodeExecutor.ts +119 -8
- package/src/tools/ProgrammaticToolCalling.ts +29 -27
- package/src/tools/ToolNode.ts +50 -8
- package/src/tools/__tests__/CodeApiAuthHeaders.test.ts +297 -3
- package/src/types/llm.ts +8 -1
- package/src/types/stream.ts +5 -4
- package/src/types/summarize.ts +22 -0
- package/src/utils/__tests__/errors.test.ts +270 -0
- package/src/utils/__tests__/fixtures/contextOverflowSignatures.ts +336 -0
- package/src/utils/__tests__/redactSecrets.test.ts +56 -0
- package/src/utils/errors.ts +484 -66
- package/src/utils/redactSecrets.ts +61 -0
|
@@ -18,6 +18,7 @@ const require_anthropicToolCache = require("../messages/anthropicToolCache.cjs")
|
|
|
18
18
|
const require_content = require("../messages/content.cjs");
|
|
19
19
|
const require_tools = require("../messages/tools.cjs");
|
|
20
20
|
const require_reducer = require("../messages/reducer.cjs");
|
|
21
|
+
const require_recency = require("../messages/recency.cjs");
|
|
21
22
|
require("../messages/index.cjs");
|
|
22
23
|
const require_graph = require("../utils/graph.cjs");
|
|
23
24
|
const require_llm = require("../utils/llm.cjs");
|
|
@@ -26,7 +27,11 @@ const require_toolOutputReferences = require("../tools/toolOutputReferences.cjs"
|
|
|
26
27
|
const require_events$1 = require("../events.cjs");
|
|
27
28
|
const require_run = require("../utils/run.cjs");
|
|
28
29
|
require("../utils/index.cjs");
|
|
29
|
-
const
|
|
30
|
+
const require_contextOverflowRecovery = require("../llm/contextOverflowRecovery.cjs");
|
|
31
|
+
const require_toolCache = require("../llm/bedrock/toolCache.cjs");
|
|
32
|
+
const require_init = require("../llm/init.cjs");
|
|
33
|
+
const require_invoke = require("../llm/invoke.cjs");
|
|
34
|
+
const require_toolCache$1 = require("../llm/openrouter/toolCache.cjs");
|
|
30
35
|
const require_LocalCodingTools = require("../tools/local/LocalCodingTools.cjs");
|
|
31
36
|
const require_CloudflareSandboxTools = require("../tools/cloudflare/CloudflareSandboxTools.cjs");
|
|
32
37
|
require("../tools/cloudflare/index.cjs");
|
|
@@ -35,9 +40,6 @@ require("../tools/local/index.cjs");
|
|
|
35
40
|
const require_ToolNode = require("../tools/ToolNode.cjs");
|
|
36
41
|
const require_SubagentExecutor = require("../tools/subagent/SubagentExecutor.cjs");
|
|
37
42
|
require("../tools/subagent/index.cjs");
|
|
38
|
-
const require_toolCache$1 = require("../llm/bedrock/toolCache.cjs");
|
|
39
|
-
const require_init = require("../llm/init.cjs");
|
|
40
|
-
const require_invoke = require("../llm/invoke.cjs");
|
|
41
43
|
const require_SubagentTool = require("../tools/SubagentTool.cjs");
|
|
42
44
|
const require_index$6 = require("../summarization/index.cjs");
|
|
43
45
|
const require_request = require("../llm/request.cjs");
|
|
@@ -161,6 +163,33 @@ function clearCurrentDeltaStepMarkers({ graph, metadata }) {
|
|
|
161
163
|
graph.reasoningStepHasDeltas.delete(stepId);
|
|
162
164
|
}
|
|
163
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* The completion allowance the caller configured, under whichever key the
|
|
168
|
+
* provider's client uses. Providers count it against the same ceiling as the
|
|
169
|
+
* prompt, so overflow recovery has to reserve it when the error did not
|
|
170
|
+
* itemize the total.
|
|
171
|
+
*/
|
|
172
|
+
function getConfiguredCompletionTokens(clientOptions) {
|
|
173
|
+
const options = clientOptions;
|
|
174
|
+
for (const value of [options?.maxTokens, options?.maxOutputTokens]) if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Our own estimate of the prompt that was actually sent, derived from the
|
|
178
|
+
* pre-invoke usage snapshot. Used to corroborate ambiguous provider errors
|
|
179
|
+
* and to measure how far our token accounting sits from the provider's.
|
|
180
|
+
*/
|
|
181
|
+
function getEstimatedPromptTokens(contextUsage) {
|
|
182
|
+
const budget = contextUsage?.contextBudget;
|
|
183
|
+
const remaining = contextUsage?.remainingContextTokens;
|
|
184
|
+
if (budget == null || remaining == null || !Number.isFinite(budget) || !Number.isFinite(remaining)) return;
|
|
185
|
+
const used = budget - remaining;
|
|
186
|
+
return used > 0 ? used : void 0;
|
|
187
|
+
}
|
|
188
|
+
function minDefined(left, right) {
|
|
189
|
+
if (left == null) return right;
|
|
190
|
+
if (right == null) return left;
|
|
191
|
+
return Math.min(left, right);
|
|
192
|
+
}
|
|
164
193
|
async function dispatchMessageCreationStep({ graph, stepKey, messageId, metadata }) {
|
|
165
194
|
await graph.dispatchRunStep(stepKey, {
|
|
166
195
|
type: "message_creation",
|
|
@@ -457,9 +486,13 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
457
486
|
overrideModel;
|
|
458
487
|
/** Optional compile options passed into workflow.compile() */
|
|
459
488
|
compileOptions;
|
|
489
|
+
/** Whether the workflow was actually compiled with a checkpointer. */
|
|
490
|
+
hasCompiledCheckpointer = false;
|
|
460
491
|
messages = [];
|
|
461
492
|
/** Cached run messages preserved before clearHeavyState() so getRunMessages() works after cleanup. */
|
|
462
493
|
cachedRunMessages;
|
|
494
|
+
/** Checkpoint scope whose messages match index-keyed tool snapshots. */
|
|
495
|
+
originalToolContentCheckpointScope;
|
|
463
496
|
runId;
|
|
464
497
|
/**
|
|
465
498
|
* Boundary between historical messages (loaded from conversation state)
|
|
@@ -498,7 +531,7 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
498
531
|
}
|
|
499
532
|
this.defaultAgentId = agents[0].agentId;
|
|
500
533
|
}
|
|
501
|
-
resetValues(keepContent) {
|
|
534
|
+
resetValues(keepContent, checkpointScope) {
|
|
502
535
|
this.messages = [];
|
|
503
536
|
this.cachedRunMessages = void 0;
|
|
504
537
|
this.config = require_graph.resetIfNotEmpty(this.config, void 0);
|
|
@@ -525,14 +558,18 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
525
558
|
this.reasoningStepHasDeltas = require_graph.resetIfNotEmpty(this.reasoningStepHasDeltas, /* @__PURE__ */ new Set());
|
|
526
559
|
this.prelimMessageIdsByStepKey = require_graph.resetIfNotEmpty(this.prelimMessageIdsByStepKey, /* @__PURE__ */ new Map());
|
|
527
560
|
this.invokedToolIds = require_graph.resetIfNotEmpty(this.invokedToolIds, void 0);
|
|
528
|
-
|
|
561
|
+
const hasScopedCheckpoint = this.hasCompiledCheckpointer && checkpointScope != null && checkpointScope !== "";
|
|
562
|
+
const preserveOriginalToolContent = hasScopedCheckpoint && this.originalToolContentCheckpointScope === checkpointScope;
|
|
563
|
+
for (const context of this.agentContexts.values()) context.reset({ preserveOriginalToolContent });
|
|
564
|
+
this.originalToolContentCheckpointScope = hasScopedCheckpoint ? checkpointScope : void 0;
|
|
529
565
|
}
|
|
530
566
|
clearHeavyState() {
|
|
531
567
|
this.cachedRunMessages = this.messages.slice(this.startIndex);
|
|
532
568
|
super.clearHeavyState();
|
|
533
569
|
this.messages = [];
|
|
534
570
|
this.overrideModel = void 0;
|
|
535
|
-
|
|
571
|
+
const preserveOriginalToolContent = this.hasCompiledCheckpointer && this.originalToolContentCheckpointScope != null;
|
|
572
|
+
for (const context of this.agentContexts.values()) context.reset({ preserveOriginalToolContent });
|
|
536
573
|
}
|
|
537
574
|
getRunStep(stepId) {
|
|
538
575
|
const index = this.contentIndexMap.get(stepId);
|
|
@@ -767,6 +804,49 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
767
804
|
this.signal.removeEventListener("abort", client.abortHandler);
|
|
768
805
|
client.abortHandler = void 0;
|
|
769
806
|
}
|
|
807
|
+
/**
|
|
808
|
+
* Applies a context-overflow recovery plan and hands control to the
|
|
809
|
+
* summarize node, which compacts and then routes straight back here for a
|
|
810
|
+
* retry against the corrected budget.
|
|
811
|
+
*
|
|
812
|
+
* Returning the detour rather than rethrowing is the whole point: the
|
|
813
|
+
* caller never sees the provider's rejection, only a slightly longer turn.
|
|
814
|
+
*/
|
|
815
|
+
beginOverflowRecovery({ recovery, agentContext, agentId, config, originalToolContent, estimatedPromptTokens }) {
|
|
816
|
+
const previousBudget = agentContext.maxContextTokens;
|
|
817
|
+
/**
|
|
818
|
+
* Deterministic compaction first. Re-pruning against the corrected budget
|
|
819
|
+
* raises context pressure, which is what drives the pruner's tool-output
|
|
820
|
+
* truncation and observation masking — no model call, no cost, and no
|
|
821
|
+
* message content lost. A summarization call is held back until that has
|
|
822
|
+
* been tried and the provider rejected the prompt again.
|
|
823
|
+
*/
|
|
824
|
+
const allowSummarization = agentContext.shouldSummarizeOverflow();
|
|
825
|
+
agentContext.preserveOriginalToolContent(originalToolContent);
|
|
826
|
+
agentContext.applyContextBudgetCorrection(recovery.budgetTokens, estimatedPromptTokens);
|
|
827
|
+
agentContext.applyObservedOverflowCalibration(recovery.info.provider, recovery.observedCalibrationRatio);
|
|
828
|
+
require_events.emitAgentLog(config, "warn", "graph", "Provider rejected the prompt as too large — compacting and retrying", {
|
|
829
|
+
kind: recovery.info.kind,
|
|
830
|
+
previousBudget,
|
|
831
|
+
recoveredBudget: recovery.budgetTokens,
|
|
832
|
+
providerReportedLimit: recovery.info.limitTokens,
|
|
833
|
+
providerReportedTokens: recovery.info.requestedTokens,
|
|
834
|
+
providerReportedPromptTokens: recovery.info.promptTokens,
|
|
835
|
+
observedCalibrationRatio: recovery.observedCalibrationRatio,
|
|
836
|
+
detectedBy: recovery.info.source,
|
|
837
|
+
attempt: agentContext.overflowRecoveryAttempts,
|
|
838
|
+
compaction: allowSummarization ? "summarize" : "compress"
|
|
839
|
+
}, {
|
|
840
|
+
runId: this.runId,
|
|
841
|
+
agentId
|
|
842
|
+
}, { force: true });
|
|
843
|
+
return { summarizationRequest: {
|
|
844
|
+
remainingContextTokens: 0,
|
|
845
|
+
agentId: agentId || agentContext.agentId,
|
|
846
|
+
reason: "overflow",
|
|
847
|
+
allowSummarization
|
|
848
|
+
} };
|
|
849
|
+
}
|
|
770
850
|
createCallModel(agentId = "default") {
|
|
771
851
|
return async (state, config) => {
|
|
772
852
|
const agentContext = this.agentContexts.get(agentId);
|
|
@@ -794,10 +874,10 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
794
874
|
*/
|
|
795
875
|
let toolsForBinding = rawToolsForBinding;
|
|
796
876
|
if (agentContext.provider === "anthropic" && agentContext.clientOptions?.promptCache === true) toolsForBinding = require_anthropicToolCache.partitionAndMarkAnthropicToolCache(rawToolsForBinding, require_anthropicToolCache.makeIsDeferred(agentContext.toolDefinitions), require_cache.resolvePromptCacheTtl(agentContext.clientOptions?.promptCacheTtl)) ?? rawToolsForBinding;
|
|
797
|
-
else if (agentContext.provider === "openrouter" && agentContext.clientOptions?.promptCache === true) toolsForBinding = require_toolCache.partitionAndMarkOpenRouterToolCache(rawToolsForBinding, require_anthropicToolCache.makeIsDeferred(agentContext.toolDefinitions), require_cache.resolvePromptCacheTtl(agentContext.clientOptions?.promptCacheTtl)) ?? rawToolsForBinding;
|
|
877
|
+
else if (agentContext.provider === "openrouter" && agentContext.clientOptions?.promptCache === true) toolsForBinding = require_toolCache$1.partitionAndMarkOpenRouterToolCache(rawToolsForBinding, require_anthropicToolCache.makeIsDeferred(agentContext.toolDefinitions), require_cache.resolvePromptCacheTtl(agentContext.clientOptions?.promptCacheTtl)) ?? rawToolsForBinding;
|
|
798
878
|
else if (agentContext.provider === "bedrock" && agentContext.clientOptions?.promptCache === true) {
|
|
799
879
|
const bedrockModel = agentContext.clientOptions?.model;
|
|
800
|
-
if (bedrockModel == null || require_cache.supportsBedrockToolCache(bedrockModel)) toolsForBinding = require_toolCache
|
|
880
|
+
if (bedrockModel == null || require_cache.supportsBedrockToolCache(bedrockModel)) toolsForBinding = require_toolCache.partitionAndMarkBedrockToolCache(rawToolsForBinding, require_anthropicToolCache.makeIsDeferred(agentContext.toolDefinitions)) ?? rawToolsForBinding;
|
|
801
881
|
}
|
|
802
882
|
let model = this.overrideModel ?? require_init.initializeModel({
|
|
803
883
|
tools: toolsForBinding,
|
|
@@ -810,6 +890,12 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
810
890
|
this.config = config;
|
|
811
891
|
let messagesToUse = messages;
|
|
812
892
|
let contextUsage = null;
|
|
893
|
+
/**
|
|
894
|
+
* Held outside the prune block so overflow recovery — which detours to
|
|
895
|
+
* the summarize node from the invoke catch below — can preserve the
|
|
896
|
+
* same masking record the configured trigger preserves.
|
|
897
|
+
*/
|
|
898
|
+
let prunedOriginalToolContent;
|
|
813
899
|
if (!agentContext.pruneMessages && agentContext.tokenCounter && agentContext.maxContextTokens != null) agentContext.pruneMessages = require_prune.createPruneMessages({
|
|
814
900
|
startIndex: agentContext.indexTokenCountMap[0] != null ? this.startIndex : 0,
|
|
815
901
|
provider: agentContext.provider,
|
|
@@ -830,12 +916,22 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
830
916
|
}
|
|
831
917
|
});
|
|
832
918
|
if (agentContext.pruneMessages) {
|
|
833
|
-
const { context, indexTokenCountMap, messagesToRefine, prePruneContextTokens, remainingContextTokens,
|
|
919
|
+
const { context, indexTokenCountMap, messagesToRefine, prePruneContextTokens, remainingContextTokens, newOriginalToolContent, calibrationRatio, resolvedInstructionOverhead, contextBudget, effectiveInstructionTokens } = agentContext.pruneMessages({
|
|
834
920
|
messages,
|
|
835
921
|
usageMetadata: agentContext.currentUsage,
|
|
836
922
|
lastCallUsage: agentContext.lastCallUsage,
|
|
837
923
|
totalTokensFresh: agentContext.totalTokensFresh
|
|
838
924
|
});
|
|
925
|
+
prunedOriginalToolContent = newOriginalToolContent;
|
|
926
|
+
/**
|
|
927
|
+
* Masking rewrites tool content in `state.messages` in place, so this
|
|
928
|
+
* map is the only surviving copy of the full output. Persist it on
|
|
929
|
+
* every prune, not just when a summary is about to be written — the
|
|
930
|
+
* pruner closure that produced it is discarded on the next reset, and
|
|
931
|
+
* with it any chance of a later summary restoring the real content.
|
|
932
|
+
* AgentContext bounds what accumulates.
|
|
933
|
+
*/
|
|
934
|
+
agentContext.preserveOriginalToolContent(newOriginalToolContent);
|
|
839
935
|
agentContext.indexTokenCountMap = indexTokenCountMap;
|
|
840
936
|
if (calibrationRatio != null && calibrationRatio > 0) agentContext.calibrationRatio = calibrationRatio;
|
|
841
937
|
if (resolvedInstructionOverhead != null) {
|
|
@@ -882,31 +978,6 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
882
978
|
remainingContextTokens,
|
|
883
979
|
messagesToRefineCount: messagesToRefine.length
|
|
884
980
|
})) {
|
|
885
|
-
if (originalToolContent != null && originalToolContent.size > 0)
|
|
886
|
-
/**
|
|
887
|
-
* Merge — never overwrite — the pruner's masking record
|
|
888
|
-
* into pendingOriginalToolContent. Carry-over entries
|
|
889
|
-
* from a prior summarize (preserved by the recency
|
|
890
|
-
* window for masked tool messages still in the tail) and
|
|
891
|
-
* the current pruner's new entries are both keyed by
|
|
892
|
-
* indices in the current `state.messages`, so a key-wise
|
|
893
|
-
* union is correct. Overwriting would discard the
|
|
894
|
-
* carry-over and reduce summary fidelity when those
|
|
895
|
-
* masked tail messages eventually move into the head.
|
|
896
|
-
*/
|
|
897
|
-
if (agentContext.pendingOriginalToolContent == null) agentContext.pendingOriginalToolContent = originalToolContent;
|
|
898
|
-
else {
|
|
899
|
-
for (const [idx, content] of originalToolContent) agentContext.pendingOriginalToolContent.set(idx, content);
|
|
900
|
-
/**
|
|
901
|
-
* Re-apply the per-store char cap after the union. The
|
|
902
|
-
* pruner enforces ORIGINAL_CONTENT_MAX_CHARS inside its
|
|
903
|
-
* own map via the onContentStored callback, but a
|
|
904
|
-
* key-wise merge with recency carry-over bypasses that
|
|
905
|
-
* accounting and could let the merged map grow without
|
|
906
|
-
* bound across long sessions.
|
|
907
|
-
*/
|
|
908
|
-
require_prune.enforceOriginalContentCap(agentContext.pendingOriginalToolContent);
|
|
909
|
-
}
|
|
910
981
|
require_events.emitAgentLog(config, "info", "graph", "Summarization triggered", void 0, {
|
|
911
982
|
runId: this.runId,
|
|
912
983
|
agentId
|
|
@@ -1137,17 +1208,115 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1137
1208
|
graph: this,
|
|
1138
1209
|
metadata
|
|
1139
1210
|
});
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1211
|
+
/**
|
|
1212
|
+
* A context overflow is a deterministic consequence of the payload,
|
|
1213
|
+
* not a provider being unavailable — so it is answered by compacting
|
|
1214
|
+
* and retrying rather than by re-sending the same oversized prompt
|
|
1215
|
+
* down the fallback chain. Fallbacks still run for every other
|
|
1216
|
+
* failure, and for an overflow whose recovery budget is spent.
|
|
1217
|
+
*/
|
|
1218
|
+
/**
|
|
1219
|
+
* Compaction has to have something to work with. Without a token
|
|
1220
|
+
* counter there is no pruner, and with summarization disabled the
|
|
1221
|
+
* summarize node deliberately no-ops — so in that combination the
|
|
1222
|
+
* retry would resend a byte-identical prompt. Skipping the detour
|
|
1223
|
+
* keeps the original error and one round trip instead of three.
|
|
1224
|
+
*/
|
|
1225
|
+
const estimatedPromptTokens = getEstimatedPromptTokens(contextUsage);
|
|
1226
|
+
/**
|
|
1227
|
+
* A previous correction that left the prompt no smaller proves this
|
|
1228
|
+
* state has nothing left to compact — an emptied message list whose
|
|
1229
|
+
* content rides along in an injected summary, for instance. Measuring
|
|
1230
|
+
* that beats trying to predict every such configuration.
|
|
1231
|
+
*/
|
|
1232
|
+
const recoveryStalled = agentContext.overflowRecoveryStalled(estimatedPromptTokens);
|
|
1233
|
+
const canSummarizeOverflow = agentContext.summarizationEnabled === true && require_recency.splitAtRecencyBoundary(messages, {
|
|
1234
|
+
turns: agentContext.summarizationConfig?.retainRecent?.turns ?? 2,
|
|
1235
|
+
tokens: agentContext.summarizationConfig?.retainRecent?.tokens,
|
|
1236
|
+
tokenCounter: agentContext.tokenCounter
|
|
1237
|
+
}).head.length > 0;
|
|
1238
|
+
const planRecovery = (error, attributedFallbackContext) => {
|
|
1239
|
+
if (recoveryStalled) return null;
|
|
1240
|
+
/**
|
|
1241
|
+
* When the rejection came from a fallback, plan against *that*
|
|
1242
|
+
* client: its window and output allowance are why it was configured
|
|
1243
|
+
* as an alternative in the first place.
|
|
1244
|
+
*/
|
|
1245
|
+
const fallbackContext = attributedFallbackContext ?? require_invoke.getFallbackErrorContext(error);
|
|
1246
|
+
const recovery = require_contextOverflowRecovery.planContextOverflowRecovery({
|
|
1247
|
+
error,
|
|
1248
|
+
provider: fallbackContext?.provider ?? agentContext.provider,
|
|
1249
|
+
maxContextTokens: fallbackContext?.maxContextTokens ?? agentContext.maxContextTokens,
|
|
1250
|
+
estimatedPromptTokens,
|
|
1251
|
+
calibrationRatio: agentContext.calibrationRatio,
|
|
1252
|
+
instructionTokens: agentContext.instructionTokens,
|
|
1253
|
+
canSummarize: agentContext.summarizationEnabled === true,
|
|
1254
|
+
configuredCompletionTokens: getConfiguredCompletionTokens(fallbackContext?.clientOptions ?? agentContext.clientOptions),
|
|
1255
|
+
attemptsSoFar: agentContext.overflowRecoveryAttempts
|
|
1256
|
+
});
|
|
1257
|
+
if (recovery == null) return null;
|
|
1258
|
+
const translatedRecovery = fallbackContext != null ? {
|
|
1259
|
+
...recovery,
|
|
1260
|
+
budgetTokens: minDefined(require_contextOverflowRecovery.getBlindRecoveryBudget(agentContext.maxContextTokens), require_contextOverflowRecovery.translateRecoveryBudget(recovery.budgetTokens, recovery.observedCalibrationRatio ?? 5, agentContext.calibrationRatio)),
|
|
1261
|
+
observedCalibrationRatio: void 0
|
|
1262
|
+
} : recovery;
|
|
1263
|
+
return canSummarizeOverflow || agentContext.tokenCounter != null && translatedRecovery.budgetTokens != null ? translatedRecovery : null;
|
|
1264
|
+
};
|
|
1265
|
+
const recovery = planRecovery(primaryError);
|
|
1266
|
+
if (recovery != null) return this.beginOverflowRecovery({
|
|
1267
|
+
recovery,
|
|
1268
|
+
agentContext,
|
|
1269
|
+
agentId,
|
|
1270
|
+
config,
|
|
1271
|
+
originalToolContent: prunedOriginalToolContent,
|
|
1272
|
+
estimatedPromptTokens
|
|
1273
|
+
});
|
|
1274
|
+
/**
|
|
1275
|
+
* A fallback can reject the same prompt as too large even when the
|
|
1276
|
+
* primary failed for an unrelated reason — a fallback with a smaller
|
|
1277
|
+
* window is the obvious case. Planning against the exhausted-chain
|
|
1278
|
+
* error keeps that path recoverable instead of surfacing it.
|
|
1279
|
+
*/
|
|
1280
|
+
try {
|
|
1281
|
+
result = await require_langfuseRuntimeScope.withLangfuseRuntimeScope(require_langfuseRuntimeScope.resolveLangfuseRuntimeScope({
|
|
1282
|
+
runLangfuse: this.langfuse,
|
|
1283
|
+
langfuseOverlay: agentContext.langfuse
|
|
1284
|
+
}), () => require_invoke.tryFallbackProviders({
|
|
1285
|
+
fallbacks,
|
|
1286
|
+
tools: agentContext.tools,
|
|
1287
|
+
messages: finalMessages,
|
|
1288
|
+
config: invokeConfig,
|
|
1289
|
+
primaryError,
|
|
1290
|
+
context: this,
|
|
1291
|
+
/**
|
|
1292
|
+
* Lets the chain recognise a fallback overflow whose signature
|
|
1293
|
+
* carries no reason of its own (Vertex AI's bare 400) and
|
|
1294
|
+
* surface it rather than a later unrelated failure.
|
|
1295
|
+
*/
|
|
1296
|
+
overflowContext: {
|
|
1297
|
+
provider: agentContext.provider,
|
|
1298
|
+
estimatedPromptTokens: getEstimatedPromptTokens(contextUsage),
|
|
1299
|
+
maxContextTokens: agentContext.maxContextTokens
|
|
1300
|
+
}
|
|
1301
|
+
}));
|
|
1302
|
+
} catch (fallbackError) {
|
|
1303
|
+
const overflowCandidates = require_invoke.getFallbackOverflowCandidates(fallbackError);
|
|
1304
|
+
let fallbackRecovery = null;
|
|
1305
|
+
for (const candidate of overflowCandidates) {
|
|
1306
|
+
fallbackRecovery = planRecovery(candidate.error, candidate.context);
|
|
1307
|
+
if (fallbackRecovery != null) break;
|
|
1308
|
+
}
|
|
1309
|
+
if (overflowCandidates.length === 0) fallbackRecovery = planRecovery(fallbackError);
|
|
1310
|
+
if (fallbackRecovery == null) throw fallbackError;
|
|
1311
|
+
return this.beginOverflowRecovery({
|
|
1312
|
+
recovery: fallbackRecovery,
|
|
1313
|
+
agentContext,
|
|
1314
|
+
agentId,
|
|
1315
|
+
config,
|
|
1316
|
+
originalToolContent: prunedOriginalToolContent,
|
|
1317
|
+
estimatedPromptTokens
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1151
1320
|
} finally {
|
|
1152
1321
|
await require_langfuse.disposeLangfuseHandler(langfuseHandler);
|
|
1153
1322
|
}
|
|
@@ -1386,9 +1555,13 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1386
1555
|
isMultiAgent: this.isMultiAgentGraph(),
|
|
1387
1556
|
hookRegistry: this.hookRegistry,
|
|
1388
1557
|
dispatchRunStep: async (runStep, nodeConfig) => {
|
|
1558
|
+
const resolvedConfig = nodeConfig ?? this.config;
|
|
1559
|
+
if (runStep.agentId != null) {
|
|
1560
|
+
const groupId = this.resolveParallelGroupId(runStep.agentId, resolvedConfig?.metadata);
|
|
1561
|
+
if (groupId != null) runStep.groupId = groupId;
|
|
1562
|
+
}
|
|
1389
1563
|
this.contentData.push(runStep);
|
|
1390
1564
|
this.contentIndexMap.set(runStep.id, runStep.index);
|
|
1391
|
-
const resolvedConfig = nodeConfig ?? this.config;
|
|
1392
1565
|
const handler = this.handlerRegistry?.getHandler("on_run_step");
|
|
1393
1566
|
if (handler) {
|
|
1394
1567
|
await handler.handle("on_run_step", runStep, resolvedConfig?.configurable, this);
|
|
@@ -1416,6 +1589,7 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1416
1589
|
})).addEdge(_langchain_langgraph.START, agentNode).addConditionalEdges(agentNode, routeMessage).addEdge(summarizeNode, agentNode).addEdge(toolNode, agentContext.toolEnd ? _langchain_langgraph.END : agentNode).compile();
|
|
1417
1590
|
}
|
|
1418
1591
|
createWorkflow() {
|
|
1592
|
+
this.hasCompiledCheckpointer = this.compileOptions?.checkpointer != null;
|
|
1419
1593
|
const agentNode = this.createAgentNode(this.defaultAgentId);
|
|
1420
1594
|
return new _langchain_langgraph.StateGraph(_langchain_langgraph.Annotation.Root({ messages: (0, _langchain_langgraph.Annotation)({
|
|
1421
1595
|
reducer: (a, b) => {
|
|
@@ -1443,6 +1617,13 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1443
1617
|
* @returns undefined for StandardGraph (no parallel groups), or group number for MultiAgentGraph
|
|
1444
1618
|
*/
|
|
1445
1619
|
getParallelGroupIdForAgent(_agentId) {}
|
|
1620
|
+
resolveParallelGroupId(agentId, metadata) {
|
|
1621
|
+
if (metadata == null || !Object.prototype.hasOwnProperty.call(metadata, "__handoff_group_id")) return this.getParallelGroupIdForAgent(agentId);
|
|
1622
|
+
const runtimeGroupId = metadata["__handoff_group_id"];
|
|
1623
|
+
if (runtimeGroupId === null) return;
|
|
1624
|
+
if (typeof runtimeGroupId === "number" && Number.isSafeInteger(runtimeGroupId) && runtimeGroupId > 0) return runtimeGroupId;
|
|
1625
|
+
return this.getParallelGroupIdForAgent(agentId);
|
|
1626
|
+
}
|
|
1446
1627
|
/**
|
|
1447
1628
|
* Dispatches a run step to the client, returns the step ID
|
|
1448
1629
|
*/
|
|
@@ -1468,7 +1649,7 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1468
1649
|
const agentContext = this.getAgentContext(metadata);
|
|
1469
1650
|
if (this.isMultiAgentGraph() && agentContext.agentId) {
|
|
1470
1651
|
runStep.agentId = agentContext.agentId;
|
|
1471
|
-
const groupId = this.
|
|
1652
|
+
const groupId = this.resolveParallelGroupId(agentContext.agentId, metadata);
|
|
1472
1653
|
if (groupId != null) runStep.groupId = groupId;
|
|
1473
1654
|
}
|
|
1474
1655
|
} catch (_e) {}
|