@librechat/agents 3.3.11 → 3.3.12
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/graphs/Graph.cjs +246 -25
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +13 -2
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +146 -36
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +2 -2
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/streamLimits.cjs +723 -0
- package/dist/cjs/llm/streamLimits.cjs.map +1 -0
- package/dist/cjs/main.cjs +8 -0
- package/dist/cjs/run.cjs +6 -2
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +4 -1
- package/dist/cjs/session/AgentSession.cjs.map +1 -1
- package/dist/cjs/stream.cjs +103 -12
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +157 -37
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +3 -2
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +4 -3
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +5 -3
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +76 -3
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +3 -2
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
- package/dist/cjs/tools/search/crw-scraper.cjs +7 -1
- package/dist/cjs/tools/search/crw-scraper.cjs.map +1 -1
- package/dist/cjs/tools/search/crw-search.cjs +3 -1
- package/dist/cjs/tools/search/crw-search.cjs.map +1 -1
- package/dist/cjs/tools/search/firecrawl.cjs +7 -1
- package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
- package/dist/cjs/tools/search/keenable-scraper.cjs +7 -1
- package/dist/cjs/tools/search/keenable-scraper.cjs.map +1 -1
- package/dist/cjs/tools/search/keenable-search.cjs +3 -1
- package/dist/cjs/tools/search/keenable-search.cjs.map +1 -1
- package/dist/cjs/tools/search/rerankers.cjs +26 -8
- package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
- package/dist/cjs/tools/search/search.cjs +30 -10
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/serper-scraper.cjs +7 -1
- package/dist/cjs/tools/search/serper-scraper.cjs.map +1 -1
- package/dist/cjs/tools/search/tavily-scraper.cjs +7 -1
- package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -1
- package/dist/cjs/tools/search/tavily-search.cjs +3 -1
- package/dist/cjs/tools/search/tavily-search.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +16 -2
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +54 -3
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +1 -0
- package/dist/cjs/utils/misc.cjs +12 -0
- package/dist/cjs/utils/misc.cjs.map +1 -1
- package/dist/cjs/utils/proxy.cjs +63 -0
- package/dist/cjs/utils/proxy.cjs.map +1 -0
- package/dist/esm/graphs/Graph.mjs +245 -24
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +13 -2
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +146 -36
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +2 -2
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/streamLimits.mjs +704 -0
- package/dist/esm/llm/streamLimits.mjs.map +1 -0
- package/dist/esm/main.mjs +4 -2
- package/dist/esm/run.mjs +6 -2
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +4 -1
- package/dist/esm/session/AgentSession.mjs.map +1 -1
- package/dist/esm/stream.mjs +103 -12
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +157 -37
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +3 -2
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +4 -3
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +5 -3
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +76 -3
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +3 -2
- package/dist/esm/tools/ToolSearch.mjs.map +1 -1
- package/dist/esm/tools/search/crw-scraper.mjs +7 -1
- package/dist/esm/tools/search/crw-scraper.mjs.map +1 -1
- package/dist/esm/tools/search/crw-search.mjs +3 -1
- package/dist/esm/tools/search/crw-search.mjs.map +1 -1
- package/dist/esm/tools/search/firecrawl.mjs +7 -1
- package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
- package/dist/esm/tools/search/keenable-scraper.mjs +7 -1
- package/dist/esm/tools/search/keenable-scraper.mjs.map +1 -1
- package/dist/esm/tools/search/keenable-search.mjs +3 -1
- package/dist/esm/tools/search/keenable-search.mjs.map +1 -1
- package/dist/esm/tools/search/rerankers.mjs +26 -8
- package/dist/esm/tools/search/rerankers.mjs.map +1 -1
- package/dist/esm/tools/search/search.mjs +30 -10
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/serper-scraper.mjs +7 -1
- package/dist/esm/tools/search/serper-scraper.mjs.map +1 -1
- package/dist/esm/tools/search/tavily-scraper.mjs +7 -1
- package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -1
- package/dist/esm/tools/search/tavily-search.mjs +3 -1
- package/dist/esm/tools/search/tavily-search.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +16 -2
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +54 -3
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +1 -0
- package/dist/esm/utils/misc.mjs +12 -1
- package/dist/esm/utils/misc.mjs.map +1 -1
- package/dist/esm/utils/proxy.mjs +62 -0
- package/dist/esm/utils/proxy.mjs.map +1 -0
- package/dist/types/graphs/Graph.d.ts +53 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/llm/invoke.d.ts +25 -4
- package/dist/types/llm/openai/index.d.ts +3 -0
- package/dist/types/llm/streamLimits.d.ts +314 -0
- package/dist/types/run.d.ts +1 -0
- package/dist/types/summarization/node.d.ts +27 -2
- package/dist/types/tools/BashExecutor.d.ts +2 -2
- package/dist/types/tools/CodeExecutor.d.ts +3 -3
- package/dist/types/tools/ToolNode.d.ts +11 -1
- package/dist/types/tools/search/crw-scraper.d.ts +2 -0
- package/dist/types/tools/search/firecrawl.d.ts +2 -0
- package/dist/types/tools/search/keenable-scraper.d.ts +2 -0
- package/dist/types/tools/search/rerankers.d.ts +9 -5
- package/dist/types/tools/search/serper-scraper.d.ts +2 -0
- package/dist/types/tools/search/tavily-scraper.d.ts +2 -0
- package/dist/types/tools/search/types.d.ts +28 -33
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +44 -0
- package/dist/types/types/graph.d.ts +7 -1
- package/dist/types/types/run.d.ts +46 -1
- package/dist/types/types/tools.d.ts +21 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/misc.d.ts +7 -0
- package/dist/types/utils/proxy.d.ts +31 -0
- package/package.json +2 -1
- package/src/__tests__/stream.eagerArgsDivergence.test.ts +158 -0
- package/src/__tests__/stream.eagerEventExecution.test.ts +1 -0
- package/src/__tests__/stream.streamLimits.test.ts +1982 -0
- package/src/graphs/Graph.ts +302 -27
- package/src/graphs/__tests__/Graph.breakerLifecycle.test.ts +234 -0
- package/src/index.ts +11 -0
- package/src/llm/bedrock/index.ts +22 -2
- package/src/llm/invoke.streamLimits.test.ts +142 -0
- package/src/llm/invoke.test.ts +89 -1
- package/src/llm/invoke.ts +197 -20
- package/src/llm/openai/cacheWriteTokens.test.ts +112 -0
- package/src/llm/openai/index.ts +14 -6
- package/src/llm/streamLimits.test.ts +450 -0
- package/src/llm/streamLimits.ts +1158 -0
- package/src/run.ts +4 -0
- package/src/session/AgentSession.ts +5 -0
- package/src/stream.ts +141 -6
- package/src/summarization/__tests__/node.test.ts +269 -0
- package/src/summarization/chunkHandler.test.ts +196 -0
- package/src/summarization/node.ts +203 -6
- package/src/tools/BashExecutor.ts +4 -3
- package/src/tools/CodeExecutor.ts +5 -4
- package/src/tools/ProgrammaticToolCalling.ts +7 -5
- package/src/tools/ToolNode.ts +109 -6
- package/src/tools/ToolSearch.ts +4 -3
- package/src/tools/__tests__/BashExecutor.test.ts +2 -2
- package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +2 -4
- package/src/tools/__tests__/SubagentExecutor.test.ts +126 -0
- package/src/tools/__tests__/ToolNode.breakerSignal.test.ts +389 -0
- package/src/tools/__tests__/ToolNode.streamLimits.test.ts +69 -0
- package/src/tools/search/crw-scraper.ts +6 -0
- package/src/tools/search/crw-search.ts +6 -1
- package/src/tools/search/firecrawl.ts +6 -0
- package/src/tools/search/http-agent.test.ts +133 -0
- package/src/tools/search/keenable-scraper.ts +6 -0
- package/src/tools/search/keenable-search.ts +6 -1
- package/src/tools/search/rerankers.ts +36 -10
- package/src/tools/search/search.ts +29 -11
- package/src/tools/search/serper-scraper.ts +6 -0
- package/src/tools/search/tavily-scraper.ts +6 -0
- package/src/tools/search/tavily-search.ts +2 -0
- package/src/tools/search/tool.ts +16 -0
- package/src/tools/search/types.ts +31 -33
- package/src/tools/subagent/SubagentExecutor.ts +96 -3
- package/src/types/graph.ts +7 -0
- package/src/types/run.ts +49 -1
- package/src/types/tools.ts +21 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/misc.ts +19 -0
- package/src/utils/proxy.test.ts +176 -0
- package/src/utils/proxy.ts +93 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const require_misc = require("../utils/misc.cjs");
|
|
1
2
|
const require_langfuseConfig = require("../langfuseConfig.cjs");
|
|
2
3
|
const require_langfuseRuntimeScope = require("../langfuseRuntimeScope.cjs");
|
|
3
4
|
const require_langfuse = require("../langfuse.cjs");
|
|
@@ -27,6 +28,7 @@ const require_reducer = require("../messages/reducer.cjs");
|
|
|
27
28
|
const require_recency = require("../messages/recency.cjs");
|
|
28
29
|
require("../messages/index.cjs");
|
|
29
30
|
const require_handlers = require("../tools/handlers.cjs");
|
|
31
|
+
const require_streamLimits = require("../llm/streamLimits.cjs");
|
|
30
32
|
const require_toolOutputReferences = require("../tools/toolOutputReferences.cjs");
|
|
31
33
|
const require_llm = require("../utils/llm.cjs");
|
|
32
34
|
const require_toolCache = require("../llm/bedrock/toolCache.cjs");
|
|
@@ -68,17 +70,6 @@ const EMPTY_PREEMPT_BOUNDARY = {
|
|
|
68
70
|
messages: [],
|
|
69
71
|
preventContinuation: false
|
|
70
72
|
};
|
|
71
|
-
/**
|
|
72
|
-
* One signal that fires when either input fires. `AbortSignal.any` is skipped
|
|
73
|
-
* when the inputs collapse to a single signal — the composite is a fresh
|
|
74
|
-
* object per call, and the common cases (one channel, or the host reusing the
|
|
75
|
-
* same controller for both) don't need one.
|
|
76
|
-
*/
|
|
77
|
-
function composeAbortSignals(a, b) {
|
|
78
|
-
if (a == null || a === b) return b;
|
|
79
|
-
if (b == null) return a;
|
|
80
|
-
return AbortSignal.any([a, b]);
|
|
81
|
-
}
|
|
82
73
|
/** Minimum relative variance before calibrated toolSchemaTokens overrides current value. */
|
|
83
74
|
const CALIBRATION_VARIANCE_THRESHOLD = .15;
|
|
84
75
|
function createToolHandlerRegistry(source) {
|
|
@@ -575,6 +566,62 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
575
566
|
/** See {@link t.StandardGraphInput.preemption}. */
|
|
576
567
|
preemption;
|
|
577
568
|
/**
|
|
569
|
+
* Stream circuit breakers, resolved once from
|
|
570
|
+
* {@link t.StandardGraphInput.streamLimits}. The stream handler enforces
|
|
571
|
+
* these on every streamed chunk event.
|
|
572
|
+
*/
|
|
573
|
+
streamLimits;
|
|
574
|
+
/**
|
|
575
|
+
* Cumulative streamed argument bytes per in-flight tool call, keyed by
|
|
576
|
+
* generation key + chunk index (see `resolveGenerationKey`). Per-run
|
|
577
|
+
* accumulation state, cleared by both reset paths.
|
|
578
|
+
*/
|
|
579
|
+
streamedToolCallArgTallies = /* @__PURE__ */ new Map();
|
|
580
|
+
/** Streamed chunk events per model generation, keyed by generation key. */
|
|
581
|
+
streamDeltaEventCounts = /* @__PURE__ */ new Map();
|
|
582
|
+
/** Per-chunk-object, per-generation charge balances (lazily created; see
|
|
583
|
+
* `StreamLimitState`). Reinitialized by both reset paths: a model may
|
|
584
|
+
* retain and re-yield one mutable chunk object, whose nested map would
|
|
585
|
+
* otherwise grow by one attempt-stamped entry per model call for the
|
|
586
|
+
* graph's lifetime. */
|
|
587
|
+
streamLimitChargeCredits;
|
|
588
|
+
/** Run-scoped breaker abort: composed into every model invocation and
|
|
589
|
+
* every SubagentExecutor child signal, and tripped when a stream circuit
|
|
590
|
+
* breaker fires anywhere in the run, so parallel agent nodes' in-flight
|
|
591
|
+
* provider calls and subagents stop consuming quota while the rejection
|
|
592
|
+
* propagates. Recreated by both reset paths — the abort is one-way within
|
|
593
|
+
* a run, and a reused graph must start its next run unaborted. */
|
|
594
|
+
breakerAbort = new AbortController();
|
|
595
|
+
/** Incremented whenever `breakerAbort` is replaced. Stamped into each
|
|
596
|
+
* model attempt's metadata ({@link STREAM_LIMIT_EPOCH_KEY}) so the stream
|
|
597
|
+
* handler's consumer-side trip binds to the run that produced the event
|
|
598
|
+
* rather than whichever controller is live when a straggling chunk is
|
|
599
|
+
* finally handled. */
|
|
600
|
+
breakerEpoch = 0;
|
|
601
|
+
/** Immutable snapshot of the run's breaker identity (epoch + controller),
|
|
602
|
+
* replaced as ONE object whenever `resetValues` installs a fresh
|
|
603
|
+
* controller. Sites that pause across awaits capture it at entry and
|
|
604
|
+
* revalidate by REFERENCE afterwards — a single identity comparison
|
|
605
|
+
* proves no reset happened while suspended, where separate epoch and
|
|
606
|
+
* controller reads could interleave with one. */
|
|
607
|
+
runScope = Object.freeze({
|
|
608
|
+
epoch: 0,
|
|
609
|
+
controller: this.breakerAbort
|
|
610
|
+
});
|
|
611
|
+
/** Generation keys of model attempts still in flight (see
|
|
612
|
+
* `StreamLimitState.activeStreamLimitGenerations`). Lazily created by the
|
|
613
|
+
* attempt lease; spans resets on purpose. */
|
|
614
|
+
activeStreamLimitGenerations;
|
|
615
|
+
/** The stream-limit error behind an already-fired breaker, whether this
|
|
616
|
+
* graph's own controller tripped or a parent run's breaker arrived through
|
|
617
|
+
* the composed constructor signal (child graphs own separate controllers).
|
|
618
|
+
* Providers can translate either abort into a generic error, and recovery
|
|
619
|
+
* paths must not run in that state. */
|
|
620
|
+
resolveTrippedBreakerReason(breakerSignal = this.breakerAbort.signal) {
|
|
621
|
+
if (breakerSignal.aborted && breakerSignal.reason instanceof require_streamLimits.StreamLimitExceededError) return breakerSignal.reason;
|
|
622
|
+
if (this.signal?.aborted === true && this.signal.reason instanceof require_streamLimits.StreamLimitExceededError) return this.signal.reason;
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
578
625
|
* Seals charged against `preemption.maxSeals`. Per-turn: cleared by both
|
|
579
626
|
* reset paths so a fresh turn gets a fresh budget, while a HITL resume —
|
|
580
627
|
* which skips `resetValues` — keeps what it had left.
|
|
@@ -619,7 +666,7 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
619
666
|
* another's turn.
|
|
620
667
|
*/
|
|
621
668
|
pendingPreemptReturn = /* @__PURE__ */ new Set();
|
|
622
|
-
constructor({ runId, signal, agents, langfuse, tokenCounter, indexTokenCountMap, calibrationRatio, subagentUsageSink, subagentScope, preemption }) {
|
|
669
|
+
constructor({ runId, signal, agents, langfuse, tokenCounter, indexTokenCountMap, calibrationRatio, subagentUsageSink, subagentScope, preemption, streamLimits }) {
|
|
623
670
|
super();
|
|
624
671
|
this.runId = runId;
|
|
625
672
|
this.langfuseScopeRunId = `${runId ?? "graph"}:${(0, nanoid.nanoid)()}`;
|
|
@@ -628,6 +675,7 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
628
675
|
this.subagentUsageSink = subagentUsageSink;
|
|
629
676
|
this.subagentScope = subagentScope === true;
|
|
630
677
|
this.preemption = preemption;
|
|
678
|
+
this.streamLimits = require_streamLimits.resolveStreamLimits(streamLimits);
|
|
631
679
|
if (agents.length === 0) throw new Error("At least one agent configuration is required");
|
|
632
680
|
for (const agentConfig of agents) {
|
|
633
681
|
const agentContext = require_AgentContext.AgentContext.fromConfig(agentConfig, tokenCounter, indexTokenCountMap);
|
|
@@ -658,6 +706,28 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
658
706
|
this.clearEagerEventToolUsageCounts();
|
|
659
707
|
this.eagerEventToolCallChunks.clear();
|
|
660
708
|
this.eagerEventToolSuppressions.clear();
|
|
709
|
+
/** Grace sweep instead of a clear: producer loops of straggling
|
|
710
|
+
* attempts use these maps directly and sit outside the consumer-only
|
|
711
|
+
* epoch gate — clearing would hand a cancellation-ignoring provider a
|
|
712
|
+
* fresh allowance at every run start. Entries from the epoch that is
|
|
713
|
+
* ending survive exactly one reset so those stragglers stay on their
|
|
714
|
+
* original budgets; older entries are removed. */
|
|
715
|
+
require_streamLimits.sweepStaleStreamLimitEntries(this.streamedToolCallArgTallies, this.breakerEpoch, this.activeStreamLimitGenerations);
|
|
716
|
+
require_streamLimits.sweepStaleStreamLimitEntries(this.streamDeltaEventCounts, this.breakerEpoch, this.activeStreamLimitGenerations);
|
|
717
|
+
this.streamLimitChargeCredits = void 0;
|
|
718
|
+
/** Run-start is the only safe replacement point for the breaker:
|
|
719
|
+
* end-of-run cleanup must leave it in place so straggling parallel
|
|
720
|
+
* children from the failed run cannot start on a fresh signal.
|
|
721
|
+
* Replaced UNCONDITIONALLY here — a run that failed on an ordinary
|
|
722
|
+
* error leaves the controller un-aborted, and stragglers still settling
|
|
723
|
+
* hold their entry-time capture of it; a late stream-limit trip on that
|
|
724
|
+
* old controller must not cancel the run starting now. */
|
|
725
|
+
this.breakerAbort = new AbortController();
|
|
726
|
+
this.breakerEpoch += 1;
|
|
727
|
+
this.runScope = Object.freeze({
|
|
728
|
+
epoch: this.breakerEpoch,
|
|
729
|
+
controller: this.breakerAbort
|
|
730
|
+
});
|
|
661
731
|
this.handlerDispatchedStepIds = require_graph.resetIfNotEmpty(this.handlerDispatchedStepIds, /* @__PURE__ */ new Set());
|
|
662
732
|
this.handlerDispatchedEventCounts = require_graph.resetIfNotEmpty(this.handlerDispatchedEventCounts, /* @__PURE__ */ new Map());
|
|
663
733
|
this.messageIdsByStepKey = require_graph.resetIfNotEmpty(this.messageIdsByStepKey, /* @__PURE__ */ new Map());
|
|
@@ -679,6 +749,21 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
679
749
|
super.clearHeavyState();
|
|
680
750
|
this.messages = [];
|
|
681
751
|
this.overrideModel = void 0;
|
|
752
|
+
/** Stream-limit accounting (argument tallies, event counts, charge
|
|
753
|
+
* credits) deliberately SURVIVES cleanup: this runs in `processStream`'s
|
|
754
|
+
* finally, which an ordinary parallel-branch failure reaches while
|
|
755
|
+
* sibling attempts are still unwinding on the retained breaker — a
|
|
756
|
+
* cancellation-ignoring provider's late chunks would otherwise recreate
|
|
757
|
+
* their budgets from zero and stream another full allowance. The maps
|
|
758
|
+
* are bounded by in-flight call sizes and `resetValues` clears them at
|
|
759
|
+
* the next run start, where the epoch bump already drops stamped
|
|
760
|
+
* straggler events before accounting. */
|
|
761
|
+
/** Deliberately NOT recreating a tripped breakerAbort here: this runs in
|
|
762
|
+
* `processStream`'s cleanup, which a rejected parallel batch reaches
|
|
763
|
+
* while sibling subagents can still be pre-invoke — a fresh controller
|
|
764
|
+
* would hand them an un-aborted signal and let provider requests start
|
|
765
|
+
* after the run already failed. `resetValues` recreates it when the next
|
|
766
|
+
* run begins. */
|
|
682
767
|
/**
|
|
683
768
|
* Turn state only. The reported totals must outlive cleanup — this runs
|
|
684
769
|
* in `processStream`'s `finally`, and the host reads `getPreemptStats()`
|
|
@@ -850,9 +935,13 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
850
935
|
return keyList.some((key) => key === void 0);
|
|
851
936
|
}
|
|
852
937
|
getRunMessages() {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
938
|
+
/** Runtime-honest widening: a disposed-but-cached graph (HITL
|
|
939
|
+
* resume/reconnect through a WeakRef cache) can carry null here despite
|
|
940
|
+
* the field type. */
|
|
941
|
+
const messages = this.messages;
|
|
942
|
+
if (messages == null) return this.cachedRunMessages;
|
|
943
|
+
if (messages.length === 0 && this.cachedRunMessages != null) return this.cachedRunMessages;
|
|
944
|
+
return messages.slice(this.startIndex);
|
|
856
945
|
}
|
|
857
946
|
getDiscoveredTools(agentId) {
|
|
858
947
|
if (agentId != null) {
|
|
@@ -880,8 +969,9 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
880
969
|
return typeof id === "string" && id !== "" && this.runProducedAiMessageIds.has(id);
|
|
881
970
|
}
|
|
882
971
|
getContentParts() {
|
|
883
|
-
|
|
884
|
-
|
|
972
|
+
const messages = this.messages;
|
|
973
|
+
if (messages == null) return;
|
|
974
|
+
return require_core.convertMessagesToContent(messages.slice(this.startIndex));
|
|
885
975
|
}
|
|
886
976
|
getCalibrationRatio() {
|
|
887
977
|
return this.agentContexts.get(this.defaultAgentId)?.calibrationRatio ?? 1;
|
|
@@ -897,9 +987,10 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
897
987
|
* Get all run steps, optionally filtered by agent ID
|
|
898
988
|
*/
|
|
899
989
|
getRunSteps(agentId) {
|
|
900
|
-
|
|
901
|
-
if (
|
|
902
|
-
|
|
990
|
+
const contentData = this.contentData;
|
|
991
|
+
if (contentData == null) return [];
|
|
992
|
+
if (agentId == null || agentId === "") return [...contentData];
|
|
993
|
+
return contentData.filter((step) => step.agentId === agentId);
|
|
903
994
|
}
|
|
904
995
|
/**
|
|
905
996
|
* Get run steps grouped by agent ID
|
|
@@ -979,6 +1070,8 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
979
1070
|
maxToolResultChars: agentContext?.maxToolResultChars,
|
|
980
1071
|
toolOutputRegistry: this.getOrCreateToolOutputRegistry(),
|
|
981
1072
|
fileCheckpointer: this.getOrCreateFileCheckpointer(),
|
|
1073
|
+
getBreakerSignal: () => this.breakerAbort.signal,
|
|
1074
|
+
getRunScope: () => this.runScope,
|
|
982
1075
|
errorHandler: (data, metadata) => StandardGraph.handleToolCallErrorStatic(this, data, metadata)
|
|
983
1076
|
});
|
|
984
1077
|
this.registerCompiledToolNode(node);
|
|
@@ -1006,7 +1099,9 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1006
1099
|
maxContextTokens: agentContext?.maxContextTokens,
|
|
1007
1100
|
maxToolResultChars: agentContext?.maxToolResultChars,
|
|
1008
1101
|
toolOutputRegistry: this.getOrCreateToolOutputRegistry(),
|
|
1009
|
-
fileCheckpointer: this.getOrCreateFileCheckpointer()
|
|
1102
|
+
fileCheckpointer: this.getOrCreateFileCheckpointer(),
|
|
1103
|
+
getBreakerSignal: () => this.breakerAbort.signal,
|
|
1104
|
+
getRunScope: () => this.runScope
|
|
1010
1105
|
});
|
|
1011
1106
|
this.registerCompiledToolNode(node);
|
|
1012
1107
|
return node;
|
|
@@ -1075,6 +1170,21 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1075
1170
|
}
|
|
1076
1171
|
createCallModel(agentId = "default") {
|
|
1077
1172
|
return async (state, config) => {
|
|
1173
|
+
/** Captured at node ENTRY, before any host-facing await (context-usage
|
|
1174
|
+
* dispatch, hooks): a sibling's trip can fail the run and a prompt
|
|
1175
|
+
* next run can reset the controller while this node is paused in one
|
|
1176
|
+
* of those awaits, and a later capture would bind this attempt to the
|
|
1177
|
+
* fresh controller. Trips and reason reads below stay on this
|
|
1178
|
+
* capture. */
|
|
1179
|
+
const attemptBreaker = this.breakerAbort;
|
|
1180
|
+
const attemptBreakerEpoch = this.breakerEpoch;
|
|
1181
|
+
/** Already-tripped-at-entry: a parallel sibling's breach has failed
|
|
1182
|
+
* the run before this node was scheduled. Rethrow before hooks or the
|
|
1183
|
+
* provider call — a custom provider that doesn't synchronously reject
|
|
1184
|
+
* an aborted signal would otherwise start another model request on a
|
|
1185
|
+
* failed run. */
|
|
1186
|
+
const entryTripReason = this.resolveTrippedBreakerReason(attemptBreaker.signal);
|
|
1187
|
+
if (entryTripReason != null) throw entryTripReason;
|
|
1078
1188
|
const agentContext = this.agentContexts.get(agentId);
|
|
1079
1189
|
if (!agentContext) throw new Error(`Agent context not found for agentId: ${agentId}`);
|
|
1080
1190
|
if (!config) throw new Error("No config provided");
|
|
@@ -1670,6 +1780,10 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1670
1780
|
let langfuseHandler;
|
|
1671
1781
|
let invokeConfig = {
|
|
1672
1782
|
...config,
|
|
1783
|
+
/** The run-scoped breaker composed in, so a stream-limit trip in one
|
|
1784
|
+
* parallel agent node also cancels sibling nodes' in-flight model
|
|
1785
|
+
* calls, not only their subagents. */
|
|
1786
|
+
signal: require_misc.composeAbortSignals(config.signal, attemptBreaker.signal),
|
|
1673
1787
|
metadata: {
|
|
1674
1788
|
...config.metadata ?? {},
|
|
1675
1789
|
...traceMetadata,
|
|
@@ -1677,7 +1791,8 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1677
1791
|
* filtering: `createLangfuseTraceMetadata` drops values over its
|
|
1678
1792
|
* length cap, but scope trust (`isForeignScope`) needs the id
|
|
1679
1793
|
* verbatim regardless of length. */
|
|
1680
|
-
agentId
|
|
1794
|
+
agentId,
|
|
1795
|
+
[require_streamLimits.STREAM_LIMIT_EPOCH_KEY]: attemptBreakerEpoch
|
|
1681
1796
|
}
|
|
1682
1797
|
};
|
|
1683
1798
|
require_instrumentation.initializeLangfuseTracing(langfuse);
|
|
@@ -1700,6 +1815,14 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1700
1815
|
const metadata = config.metadata;
|
|
1701
1816
|
try {
|
|
1702
1817
|
if (preInvokeContextOverflowError != null) throw preInvokeContextOverflowError;
|
|
1818
|
+
/** Rechecked after the pre-invoke awaits (context-usage dispatch,
|
|
1819
|
+
* hooks): a sibling can trip the breaker while this node is paused
|
|
1820
|
+
* in one of them, and a provider that doesn't synchronously reject
|
|
1821
|
+
* an aborted signal would still start the request. */
|
|
1822
|
+
{
|
|
1823
|
+
const preInvokeTrip = this.resolveTrippedBreakerReason(attemptBreaker.signal);
|
|
1824
|
+
if (preInvokeTrip != null) throw preInvokeTrip;
|
|
1825
|
+
}
|
|
1703
1826
|
result = await require_langfuseRuntimeScope.withLangfuseRuntimeScope(require_langfuseRuntimeScope.resolveLangfuseRuntimeScope({
|
|
1704
1827
|
runLangfuse: this.langfuse,
|
|
1705
1828
|
langfuseOverlay: agentContext.langfuse,
|
|
@@ -1717,6 +1840,28 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1717
1840
|
metadata
|
|
1718
1841
|
});
|
|
1719
1842
|
/**
|
|
1843
|
+
* A tripped stream circuit breaker is a deliberate abort, not a
|
|
1844
|
+
* provider failure: entering overflow recovery or the fallback chain
|
|
1845
|
+
* would spend more provider work after the safety limit fired, and a
|
|
1846
|
+
* succeeding fallback would resolve a run the public contract says
|
|
1847
|
+
* must reject. Rethrow before any recovery path.
|
|
1848
|
+
*/
|
|
1849
|
+
if (primaryError instanceof require_streamLimits.StreamLimitExceededError) {
|
|
1850
|
+
/** Tripped before rethrowing so parallel agent nodes' in-flight
|
|
1851
|
+
* model calls and subagents stop while the rejection propagates. */
|
|
1852
|
+
attemptBreaker.abort(primaryError);
|
|
1853
|
+
throw primaryError;
|
|
1854
|
+
}
|
|
1855
|
+
/** A sibling that tripped the shared breaker aborts this branch's
|
|
1856
|
+
* composed signal, and some providers surface that as a generic
|
|
1857
|
+
* abort error; entering overflow planning or the fallback chain
|
|
1858
|
+
* would start new provider work after the run-wide breaker fired.
|
|
1859
|
+
* Rethrow the breaker's own stream-limit reason instead. */
|
|
1860
|
+
{
|
|
1861
|
+
const trippedReason = this.resolveTrippedBreakerReason(attemptBreaker.signal);
|
|
1862
|
+
if (trippedReason != null) throw trippedReason;
|
|
1863
|
+
}
|
|
1864
|
+
/**
|
|
1720
1865
|
* A context overflow is a deterministic consequence of the payload,
|
|
1721
1866
|
* not a provider being unavailable — so it is answered by compacting
|
|
1722
1867
|
* and retrying rather than by re-sending the same oversized prompt
|
|
@@ -1848,6 +1993,18 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
1848
1993
|
}
|
|
1849
1994
|
}));
|
|
1850
1995
|
} catch (fallbackError) {
|
|
1996
|
+
if (fallbackError instanceof require_streamLimits.StreamLimitExceededError) {
|
|
1997
|
+
/** Same treatment as the primary path: a fallback stream that
|
|
1998
|
+
* trips the breaker must stop parallel agent nodes' model calls
|
|
1999
|
+
* and subagents before the rejection propagates. */
|
|
2000
|
+
attemptBreaker.abort(fallbackError);
|
|
2001
|
+
throw fallbackError;
|
|
2002
|
+
}
|
|
2003
|
+
{
|
|
2004
|
+
/** Same sibling-abort translation guard as the primary catch. */
|
|
2005
|
+
const trippedReason = this.resolveTrippedBreakerReason(attemptBreaker.signal);
|
|
2006
|
+
if (trippedReason != null) throw trippedReason;
|
|
2007
|
+
}
|
|
1851
2008
|
const overflowCandidates = require_invoke.getFallbackOverflowCandidates(fallbackError);
|
|
1852
2009
|
let fallbackRecovery = null;
|
|
1853
2010
|
let fallbackRecoveryPromptEstimate;
|
|
@@ -2083,7 +2240,7 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
2083
2240
|
* construction signal. When both exist they may be different
|
|
2084
2241
|
* controllers, and a drain must stop when EITHER fires.
|
|
2085
2242
|
*/
|
|
2086
|
-
signal: composeAbortSignals(this.signal, this.callerSignal)
|
|
2243
|
+
signal: require_misc.composeAbortSignals(this.signal, this.callerSignal)
|
|
2087
2244
|
}).catch(() => void 0);
|
|
2088
2245
|
if (result == null) return EMPTY_PREEMPT_BOUNDARY;
|
|
2089
2246
|
/**
|
|
@@ -2166,6 +2323,7 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
2166
2323
|
const executor = new require_SubagentExecutor.SubagentExecutor({
|
|
2167
2324
|
configs: new Map(resolvedConfigs.map((c) => [c.type, c])),
|
|
2168
2325
|
parentSignal: this.signal,
|
|
2326
|
+
breakerScope: { controller: () => this.breakerAbort },
|
|
2169
2327
|
hookRegistry: this.hookRegistry,
|
|
2170
2328
|
/** Lazy — Run wires the registry onto the graph AFTER
|
|
2171
2329
|
* `createWorkflow()` runs, so a direct capture here would be
|
|
@@ -2176,6 +2334,7 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
2176
2334
|
langfuse: this.langfuse,
|
|
2177
2335
|
tokenCounter: agentContext.tokenCounter,
|
|
2178
2336
|
usageSink: this.subagentUsageSink,
|
|
2337
|
+
streamLimits: this.streamLimits,
|
|
2179
2338
|
maxDepth: effectiveSubagentDepth,
|
|
2180
2339
|
createChildGraph: (input) => {
|
|
2181
2340
|
const childGraph = new StandardGraph(input);
|
|
@@ -2215,11 +2374,17 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
2215
2374
|
*/
|
|
2216
2375
|
const toolCall = config.toolCall;
|
|
2217
2376
|
const parentToolCallId = typeof toolCall?.id === "string" ? toolCall.id : void 0;
|
|
2377
|
+
/** The parent tool batch's entry-captured scope (stamped by
|
|
2378
|
+
* ToolNode before PreToolUse hooks) — binds this child to the
|
|
2379
|
+
* run that dispatched it, not to whatever controller a reset
|
|
2380
|
+
* installed while the hooks were awaited. */
|
|
2381
|
+
const batchScope = config.configurable?.[require_streamLimits.RUN_BREAKER_SCOPE_CONFIG_KEY];
|
|
2218
2382
|
return (await executor.execute({
|
|
2219
2383
|
description,
|
|
2220
2384
|
subagentType,
|
|
2221
2385
|
threadId,
|
|
2222
2386
|
parentToolCallId,
|
|
2387
|
+
breaker: batchScope?.controller,
|
|
2223
2388
|
/**
|
|
2224
2389
|
* Forward the parent's `configurable` so host-set fields
|
|
2225
2390
|
* (`requestBody`, `user`, etc.) propagate into the child
|
|
@@ -2262,7 +2427,7 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
2262
2427
|
if (state.summarizationRequest != null) return summarizeNode;
|
|
2263
2428
|
return require_ToolNode.toolsCondition(state, toolNode, this.invokedToolIds);
|
|
2264
2429
|
};
|
|
2265
|
-
|
|
2430
|
+
const StateAnnotation = _langchain_langgraph.Annotation.Root({
|
|
2266
2431
|
messages: (0, _langchain_langgraph.Annotation)({
|
|
2267
2432
|
reducer: require_reducer.messagesStateReducer,
|
|
2268
2433
|
default: () => []
|
|
@@ -2271,7 +2436,17 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
2271
2436
|
reducer: (_, b) => b,
|
|
2272
2437
|
default: () => void 0
|
|
2273
2438
|
})
|
|
2274
|
-
})
|
|
2439
|
+
});
|
|
2440
|
+
const readChargeCredits = () => this.streamLimitChargeCredits;
|
|
2441
|
+
const readBreakerEpoch = () => this.breakerEpoch;
|
|
2442
|
+
const readActiveGenerations = () => this.activeStreamLimitGenerations;
|
|
2443
|
+
const writeActiveGenerations = (value) => {
|
|
2444
|
+
this.activeStreamLimitGenerations = value;
|
|
2445
|
+
};
|
|
2446
|
+
const writeChargeCredits = (value) => {
|
|
2447
|
+
this.streamLimitChargeCredits = value;
|
|
2448
|
+
};
|
|
2449
|
+
return new _langchain_langgraph.StateGraph(StateAnnotation).addNode(agentNode, this.createCallModel(agentId)).addNode(toolNode, this.initializeTools({
|
|
2275
2450
|
currentTools: agentContext.tools,
|
|
2276
2451
|
currentToolMap: agentContext.toolMap,
|
|
2277
2452
|
agentContext
|
|
@@ -2286,6 +2461,52 @@ var StandardGraph = class StandardGraph extends Graph {
|
|
|
2286
2461
|
runId: this.runId,
|
|
2287
2462
|
isMultiAgent: this.isMultiAgentGraph(),
|
|
2288
2463
|
hookRegistry: this.hookRegistry,
|
|
2464
|
+
/**
|
|
2465
|
+
* Live references (both maps are cleared in place, never
|
|
2466
|
+
* replaced), so summarization streams share the run's event
|
|
2467
|
+
* budget accounting under their own generation key.
|
|
2468
|
+
*/
|
|
2469
|
+
streamLimits: this.streamLimits,
|
|
2470
|
+
streamDeltaEventCounts: this.streamDeltaEventCounts,
|
|
2471
|
+
streamedToolCallArgTallies: this.streamedToolCallArgTallies,
|
|
2472
|
+
/** Accessor pair, not a value copy: unlike the two maps above,
|
|
2473
|
+
* the credit map is REPLACED by graph resets rather than cleared
|
|
2474
|
+
* in place, and the guards' lazy `??=` must install onto the
|
|
2475
|
+
* graph — a copy held here would survive resets and grow one
|
|
2476
|
+
* attempt-stamped entry per compaction for a retained reused
|
|
2477
|
+
* chunk object. */
|
|
2478
|
+
get streamLimitChargeCredits() {
|
|
2479
|
+
return readChargeCredits();
|
|
2480
|
+
},
|
|
2481
|
+
set streamLimitChargeCredits(value) {
|
|
2482
|
+
writeChargeCredits(value);
|
|
2483
|
+
},
|
|
2484
|
+
/** Live epoch, so summary tallies are creation-tagged and the
|
|
2485
|
+
* resetValues grace sweep treats them like model-attempt
|
|
2486
|
+
* entries. */
|
|
2487
|
+
get breakerEpoch() {
|
|
2488
|
+
return readBreakerEpoch();
|
|
2489
|
+
},
|
|
2490
|
+
/** Accessor pair like the charge credits: summary attempts
|
|
2491
|
+
* lease their generations on the GRAPH's active set, and the
|
|
2492
|
+
* lazy `??=` in the lease helper must install there. */
|
|
2493
|
+
get activeStreamLimitGenerations() {
|
|
2494
|
+
return readActiveGenerations();
|
|
2495
|
+
},
|
|
2496
|
+
set activeStreamLimitGenerations(value) {
|
|
2497
|
+
writeActiveGenerations(value);
|
|
2498
|
+
},
|
|
2499
|
+
/** Read per attempt: a sibling branch tripping the run breaker
|
|
2500
|
+
* must also cancel in-flight summarization model calls. */
|
|
2501
|
+
getBreakerSignal: () => this.breakerAbort.signal,
|
|
2502
|
+
/** The node captures this at entry so its own chunk handler's
|
|
2503
|
+
* breach trips the run that STARTED the summarization, not a
|
|
2504
|
+
* controller installed by a later reset. */
|
|
2505
|
+
getBreakerController: () => this.breakerAbort,
|
|
2506
|
+
/** Captured at node entry and stamped into the summary attempt
|
|
2507
|
+
* metadata, so the wire consumer epoch-gates old-run summary
|
|
2508
|
+
* chunks exactly like model-attempt chunks. */
|
|
2509
|
+
getBreakerEpoch: () => this.breakerEpoch,
|
|
2289
2510
|
dispatchRunStep: async (runStep, nodeConfig) => {
|
|
2290
2511
|
const resolvedConfig = nodeConfig ?? this.config;
|
|
2291
2512
|
if (runStep.agentId != null) {
|