@librechat/agents 3.3.10 → 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.
Files changed (211) hide show
  1. package/dist/cjs/graphs/Graph.cjs +248 -27
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/langfuseToolOutputTracing.cjs +228 -16
  4. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  5. package/dist/cjs/llm/bedrock/index.cjs +13 -2
  6. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  7. package/dist/cjs/llm/init.cjs +1 -1
  8. package/dist/cjs/llm/invoke.cjs +160 -43
  9. package/dist/cjs/llm/invoke.cjs.map +1 -1
  10. package/dist/cjs/llm/openai/index.cjs +190 -13
  11. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  12. package/dist/cjs/llm/streamLimits.cjs +723 -0
  13. package/dist/cjs/llm/streamLimits.cjs.map +1 -0
  14. package/dist/cjs/main.cjs +12 -3
  15. package/dist/cjs/messages/core.cjs +592 -27
  16. package/dist/cjs/messages/core.cjs.map +1 -1
  17. package/dist/cjs/run.cjs +7 -3
  18. package/dist/cjs/run.cjs.map +1 -1
  19. package/dist/cjs/session/AgentSession.cjs +4 -1
  20. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  21. package/dist/cjs/stream.cjs +105 -14
  22. package/dist/cjs/stream.cjs.map +1 -1
  23. package/dist/cjs/summarization/node.cjs +157 -37
  24. package/dist/cjs/summarization/node.cjs.map +1 -1
  25. package/dist/cjs/tools/BashExecutor.cjs +3 -2
  26. package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
  27. package/dist/cjs/tools/CodeExecutor.cjs +4 -3
  28. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  29. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +5 -3
  30. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  31. package/dist/cjs/tools/ToolNode.cjs +77 -4
  32. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  33. package/dist/cjs/tools/ToolSearch.cjs +3 -2
  34. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  35. package/dist/cjs/tools/search/crw-scraper.cjs +7 -1
  36. package/dist/cjs/tools/search/crw-scraper.cjs.map +1 -1
  37. package/dist/cjs/tools/search/crw-search.cjs +3 -1
  38. package/dist/cjs/tools/search/crw-search.cjs.map +1 -1
  39. package/dist/cjs/tools/search/firecrawl.cjs +7 -1
  40. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  41. package/dist/cjs/tools/search/keenable-scraper.cjs +7 -1
  42. package/dist/cjs/tools/search/keenable-scraper.cjs.map +1 -1
  43. package/dist/cjs/tools/search/keenable-search.cjs +3 -1
  44. package/dist/cjs/tools/search/keenable-search.cjs.map +1 -1
  45. package/dist/cjs/tools/search/rerankers.cjs +26 -8
  46. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  47. package/dist/cjs/tools/search/search.cjs +30 -10
  48. package/dist/cjs/tools/search/search.cjs.map +1 -1
  49. package/dist/cjs/tools/search/serper-scraper.cjs +7 -1
  50. package/dist/cjs/tools/search/serper-scraper.cjs.map +1 -1
  51. package/dist/cjs/tools/search/tavily-scraper.cjs +7 -1
  52. package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -1
  53. package/dist/cjs/tools/search/tavily-search.cjs +3 -1
  54. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -1
  55. package/dist/cjs/tools/search/tool.cjs +17 -3
  56. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  57. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +54 -3
  58. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  59. package/dist/cjs/utils/index.cjs +2 -1
  60. package/dist/cjs/utils/misc.cjs +12 -0
  61. package/dist/cjs/utils/misc.cjs.map +1 -1
  62. package/dist/cjs/utils/proxy.cjs +63 -0
  63. package/dist/cjs/utils/proxy.cjs.map +1 -0
  64. package/dist/esm/graphs/Graph.mjs +247 -26
  65. package/dist/esm/graphs/Graph.mjs.map +1 -1
  66. package/dist/esm/langfuseToolOutputTracing.mjs +228 -16
  67. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  68. package/dist/esm/llm/bedrock/index.mjs +13 -2
  69. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  70. package/dist/esm/llm/init.mjs +1 -1
  71. package/dist/esm/llm/invoke.mjs +160 -43
  72. package/dist/esm/llm/invoke.mjs.map +1 -1
  73. package/dist/esm/llm/openai/index.mjs +192 -15
  74. package/dist/esm/llm/openai/index.mjs.map +1 -1
  75. package/dist/esm/llm/streamLimits.mjs +704 -0
  76. package/dist/esm/llm/streamLimits.mjs.map +1 -0
  77. package/dist/esm/main.mjs +8 -6
  78. package/dist/esm/messages/core.mjs +592 -28
  79. package/dist/esm/messages/core.mjs.map +1 -1
  80. package/dist/esm/run.mjs +7 -3
  81. package/dist/esm/run.mjs.map +1 -1
  82. package/dist/esm/session/AgentSession.mjs +4 -1
  83. package/dist/esm/session/AgentSession.mjs.map +1 -1
  84. package/dist/esm/stream.mjs +105 -14
  85. package/dist/esm/stream.mjs.map +1 -1
  86. package/dist/esm/summarization/node.mjs +157 -37
  87. package/dist/esm/summarization/node.mjs.map +1 -1
  88. package/dist/esm/tools/BashExecutor.mjs +3 -2
  89. package/dist/esm/tools/BashExecutor.mjs.map +1 -1
  90. package/dist/esm/tools/CodeExecutor.mjs +4 -3
  91. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  92. package/dist/esm/tools/ProgrammaticToolCalling.mjs +5 -3
  93. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  94. package/dist/esm/tools/ToolNode.mjs +77 -4
  95. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  96. package/dist/esm/tools/ToolSearch.mjs +3 -2
  97. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  98. package/dist/esm/tools/search/crw-scraper.mjs +7 -1
  99. package/dist/esm/tools/search/crw-scraper.mjs.map +1 -1
  100. package/dist/esm/tools/search/crw-search.mjs +3 -1
  101. package/dist/esm/tools/search/crw-search.mjs.map +1 -1
  102. package/dist/esm/tools/search/firecrawl.mjs +7 -1
  103. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  104. package/dist/esm/tools/search/keenable-scraper.mjs +7 -1
  105. package/dist/esm/tools/search/keenable-scraper.mjs.map +1 -1
  106. package/dist/esm/tools/search/keenable-search.mjs +3 -1
  107. package/dist/esm/tools/search/keenable-search.mjs.map +1 -1
  108. package/dist/esm/tools/search/rerankers.mjs +26 -8
  109. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  110. package/dist/esm/tools/search/search.mjs +30 -10
  111. package/dist/esm/tools/search/search.mjs.map +1 -1
  112. package/dist/esm/tools/search/serper-scraper.mjs +7 -1
  113. package/dist/esm/tools/search/serper-scraper.mjs.map +1 -1
  114. package/dist/esm/tools/search/tavily-scraper.mjs +7 -1
  115. package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -1
  116. package/dist/esm/tools/search/tavily-search.mjs +3 -1
  117. package/dist/esm/tools/search/tavily-search.mjs.map +1 -1
  118. package/dist/esm/tools/search/tool.mjs +17 -3
  119. package/dist/esm/tools/search/tool.mjs.map +1 -1
  120. package/dist/esm/tools/subagent/SubagentExecutor.mjs +54 -3
  121. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  122. package/dist/esm/utils/index.mjs +2 -1
  123. package/dist/esm/utils/misc.mjs +12 -1
  124. package/dist/esm/utils/misc.mjs.map +1 -1
  125. package/dist/esm/utils/proxy.mjs +62 -0
  126. package/dist/esm/utils/proxy.mjs.map +1 -0
  127. package/dist/types/graphs/Graph.d.ts +53 -1
  128. package/dist/types/index.d.ts +2 -0
  129. package/dist/types/langfuseToolOutputTracing.d.ts +1 -0
  130. package/dist/types/llm/invoke.d.ts +26 -5
  131. package/dist/types/llm/openai/index.d.ts +3 -0
  132. package/dist/types/llm/streamLimits.d.ts +314 -0
  133. package/dist/types/messages/core.d.ts +11 -6
  134. package/dist/types/run.d.ts +1 -0
  135. package/dist/types/summarization/node.d.ts +27 -2
  136. package/dist/types/tools/BashExecutor.d.ts +2 -2
  137. package/dist/types/tools/CodeExecutor.d.ts +3 -3
  138. package/dist/types/tools/ToolNode.d.ts +11 -1
  139. package/dist/types/tools/search/crw-scraper.d.ts +2 -0
  140. package/dist/types/tools/search/firecrawl.d.ts +2 -0
  141. package/dist/types/tools/search/keenable-scraper.d.ts +2 -0
  142. package/dist/types/tools/search/rerankers.d.ts +9 -5
  143. package/dist/types/tools/search/serper-scraper.d.ts +2 -0
  144. package/dist/types/tools/search/tavily-scraper.d.ts +2 -0
  145. package/dist/types/tools/search/types.d.ts +28 -33
  146. package/dist/types/tools/subagent/SubagentExecutor.d.ts +44 -0
  147. package/dist/types/types/graph.d.ts +7 -1
  148. package/dist/types/types/run.d.ts +46 -1
  149. package/dist/types/types/tools.d.ts +21 -0
  150. package/dist/types/utils/index.d.ts +1 -0
  151. package/dist/types/utils/misc.d.ts +7 -0
  152. package/dist/types/utils/proxy.d.ts +31 -0
  153. package/package.json +2 -1
  154. package/src/__tests__/stream.eagerArgsDivergence.test.ts +158 -0
  155. package/src/__tests__/stream.eagerEventExecution.test.ts +1 -0
  156. package/src/__tests__/stream.streamLimits.test.ts +1982 -0
  157. package/src/graphs/Graph.ts +302 -27
  158. package/src/graphs/__tests__/Graph.breakerLifecycle.test.ts +234 -0
  159. package/src/index.ts +11 -0
  160. package/src/langfuseToolOutputTracing.ts +410 -14
  161. package/src/llm/bedrock/index.ts +22 -2
  162. package/src/llm/custom-chat-models.smoke.test.ts +747 -0
  163. package/src/llm/invoke.streamLimits.test.ts +142 -0
  164. package/src/llm/invoke.test.ts +187 -1
  165. package/src/llm/invoke.ts +231 -43
  166. package/src/llm/openai/cacheWriteTokens.test.ts +112 -0
  167. package/src/llm/openai/index.ts +348 -31
  168. package/src/llm/openai/llm.spec.ts +107 -6
  169. package/src/llm/streamLimits.test.ts +450 -0
  170. package/src/llm/streamLimits.ts +1158 -0
  171. package/src/messages/core.ts +1290 -42
  172. package/src/messages/formatAgentMessages.test.ts +2623 -0
  173. package/src/run.ts +4 -0
  174. package/src/session/AgentSession.ts +5 -0
  175. package/src/specs/langfuse-tool-output-tracing.test.ts +887 -0
  176. package/src/specs/preemptSeal.test.ts +374 -5
  177. package/src/stream.ts +141 -6
  178. package/src/summarization/__tests__/node.test.ts +269 -0
  179. package/src/summarization/chunkHandler.test.ts +196 -0
  180. package/src/summarization/node.ts +203 -6
  181. package/src/tools/BashExecutor.ts +4 -3
  182. package/src/tools/CodeExecutor.ts +5 -4
  183. package/src/tools/ProgrammaticToolCalling.ts +7 -5
  184. package/src/tools/ToolNode.ts +109 -6
  185. package/src/tools/ToolSearch.ts +4 -3
  186. package/src/tools/__tests__/BashExecutor.test.ts +2 -2
  187. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +2 -4
  188. package/src/tools/__tests__/SubagentExecutor.test.ts +126 -0
  189. package/src/tools/__tests__/ToolNode.breakerSignal.test.ts +389 -0
  190. package/src/tools/__tests__/ToolNode.streamLimits.test.ts +69 -0
  191. package/src/tools/search/crw-scraper.ts +6 -0
  192. package/src/tools/search/crw-search.ts +6 -1
  193. package/src/tools/search/firecrawl.ts +6 -0
  194. package/src/tools/search/http-agent.test.ts +133 -0
  195. package/src/tools/search/keenable-scraper.ts +6 -0
  196. package/src/tools/search/keenable-search.ts +6 -1
  197. package/src/tools/search/rerankers.ts +36 -10
  198. package/src/tools/search/search.ts +29 -11
  199. package/src/tools/search/serper-scraper.ts +6 -0
  200. package/src/tools/search/tavily-scraper.ts +6 -0
  201. package/src/tools/search/tavily-search.ts +2 -0
  202. package/src/tools/search/tool.ts +16 -0
  203. package/src/tools/search/types.ts +31 -33
  204. package/src/tools/subagent/SubagentExecutor.ts +96 -3
  205. package/src/types/graph.ts +7 -0
  206. package/src/types/run.ts +49 -1
  207. package/src/types/tools.ts +21 -0
  208. package/src/utils/index.ts +1 -0
  209. package/src/utils/misc.ts +19 -0
  210. package/src/utils/proxy.test.ts +176 -0
  211. package/src/utils/proxy.ts +93 -0
@@ -2,10 +2,11 @@ import { AIMessageChunk } from '@langchain/core/messages';
2
2
  import type { RunnableConfig } from '@langchain/core/runnables';
3
3
  import type { BaseMessage } from '@langchain/core/messages';
4
4
  import type { ToolOutputReferenceRegistry } from '@/tools/toolOutputReferences';
5
+ import type { StreamLimitState } from '@/llm/streamLimits';
5
6
  import type { ContextOverflowContext } from '@/utils/errors';
6
7
  import type * as t from '@/types';
7
- import { Providers } from '@/common';
8
8
  import { ChatModelStreamHandler } from '@/stream';
9
+ import { Providers } from '@/common';
9
10
  /**
10
11
  * Context passed to `attemptInvoke`. Matches the subset of Graph that
11
12
  * `ChatModelStreamHandler.handle` needs *plus* the explicit
@@ -39,8 +40,12 @@ export type InvokeContext = NonNullable<Parameters<ChatModelStreamHandler['handl
39
40
  /**
40
41
  * Per-chunk callback for custom stream processing.
41
42
  * When provided, replaces the default `ChatModelStreamHandler`.
43
+ *
44
+ * `metadata` is the attempt's callback metadata (carrying the provider and
45
+ * stream-limit attempt stamps), so consumers that count against the stream
46
+ * limits key each model attempt separately.
42
47
  */
43
- export type OnChunk = (chunk: AIMessageChunk) => void | Promise<void>;
48
+ export type OnChunk = (chunk: AIMessageChunk, metadata?: Record<string, unknown>) => void | Promise<void>;
44
49
  export declare function usesNativeOpenAIResponses(model: t.ChatModel, provider: Providers, callOptions?: unknown): boolean;
45
50
  /**
46
51
  * Produces the exact provider-facing message representation before a model
@@ -70,13 +75,25 @@ export declare function resolveServingModelId(model: unknown): string | undefine
70
75
  * Pass an `onChunk` callback to override this with custom chunk processing
71
76
  * (e.g. summarization delta events).
72
77
  */
73
- export declare function attemptInvoke({ model, messages, provider, context, onChunk, }: {
78
+ interface AttemptInvokeParams {
74
79
  model: t.ChatModel;
75
80
  messages: BaseMessage[];
76
81
  provider: Providers;
77
82
  context?: InvokeContext;
78
83
  onChunk?: OnChunk;
79
- }, config?: RunnableConfig): Promise<Partial<t.BaseGraphState>>;
84
+ /** Accounting owner for callers that deliberately pass no `context`
85
+ * (summarization) — used ONLY for the attempt's accounting lease, never
86
+ * for charge claims. */
87
+ streamLimitState?: StreamLimitState;
88
+ }
89
+ /**
90
+ * One model attempt. Stamps the attempt identity into callback metadata
91
+ * (see the generation-key notes in `streamLimits.ts`), leases the attempt's
92
+ * accounting for its LIFETIME, and releases both from `finally`: retention
93
+ * must follow the attempt — a cancellation-ignoring straggler keeps its
94
+ * original budget no matter how many runs start and reset while it drains.
95
+ */
96
+ export declare function attemptInvoke(params: AttemptInvokeParams, config?: RunnableConfig): Promise<Partial<t.BaseGraphState>>;
80
97
  /**
81
98
  * Identifies which fallback produced an error, so a caller planning a
82
99
  * recovery can reason about the client that actually failed rather than the
@@ -105,7 +122,7 @@ export declare function getFallbackOverflowCandidates(error: unknown): FallbackO
105
122
  * behind a later unrelated error would surface a dead end instead. Ordinary
106
123
  * failures still throw last-error-wins.
107
124
  */
108
- export declare function tryFallbackProviders({ fallbacks, tools, messages, config, primaryError, context, onChunk, overflowContext, prepareProviderMessages, }: {
125
+ export declare function tryFallbackProviders({ fallbacks, tools, messages, config, primaryError, context, onChunk, streamLimitState, overflowContext, prepareProviderMessages, }: {
109
126
  fallbacks: t.FallbackConfig[];
110
127
  tools?: t.GraphTools;
111
128
  messages: BaseMessage[];
@@ -113,6 +130,9 @@ export declare function tryFallbackProviders({ fallbacks, tools, messages, confi
113
130
  primaryError: unknown;
114
131
  context?: InvokeContext;
115
132
  onChunk?: OnChunk;
133
+ /** Accounting-lease owner forwarded to each fallback attempt (see
134
+ * `AttemptInvokeParams.streamLimitState`). */
135
+ streamLimitState?: StreamLimitState;
116
136
  /**
117
137
  * Prompt-size corroboration for signatures that are not self-describing.
118
138
  * Vertex AI's overflow is a bare `400` with no reason, so without this a
@@ -134,3 +154,4 @@ export declare function tryFallbackProviders({ fallbacks, tools, messages, confi
134
154
  config?: RunnableConfig;
135
155
  }) => BaseMessage[] | Promise<BaseMessage[]>;
136
156
  }): Promise<Partial<t.BaseGraphState> | undefined>;
157
+ export {};
@@ -41,6 +41,9 @@ export declare function shouldIncludeEncryptedReasoning(model: string, params: {
41
41
  store?: boolean | null;
42
42
  reasoning?: unknown;
43
43
  }): boolean;
44
+ export declare function getCacheWriteTokens(message: BaseMessage): number | undefined;
45
+ export declare function attachCacheWriteUsage(message: BaseMessage): void;
46
+ export declare function attachCacheWriteMetadata(response: OpenAIClient.Responses.Response): OpenAIClient.Responses.Response;
44
47
  export declare function emitStreamChunkCallback(chunk: ChatGenerationChunk, runManager?: CallbackManagerForLLMRun): Promise<void>;
45
48
  export declare function _convertToOpenAITool(tool: BindToolsInput, fields?: {
46
49
  /**
@@ -0,0 +1,314 @@
1
+ import type { ToolCallChunk } from '@langchain/core/messages/tool';
2
+ import type * as t from '@/types';
3
+ /**
4
+ * Circuit breakers for pathological model streams.
5
+ *
6
+ * A malformed generation can stream a single tool call's arguments for many
7
+ * minutes at the provider's full token rate while the arguments never become
8
+ * executable (observed live: one 149,923-char SQL argument streamed for 26
9
+ * minutes before the 64k output-token ceiling finally ended the run). These
10
+ * guards fail fast instead: when a limit trips, the stream handler throws
11
+ * `StreamLimitExceededError` out of the run's `streamEvents` loop, which
12
+ * tears down the in-flight provider request where it stands (see the
13
+ * mid-flight halt notes in `Run.processStream`: leaving the loop cancels the
14
+ * reader and langgraph aborts the model call).
15
+ */
16
+ /** Default cap on a single streamed tool call's cumulative argument bytes (64 KiB). */
17
+ export declare const DEFAULT_MAX_TOOL_CALL_ARG_BYTES = 65536;
18
+ /** Limits normalized by {@link resolveStreamLimits}; `0` uniformly means disabled. */
19
+ export interface ResolvedStreamLimits {
20
+ maxToolCallArgBytes: number;
21
+ /** Per-tool overrides of the byte cap, keyed by model-facing tool name. */
22
+ maxToolCallArgBytesByTool?: Readonly<Record<string, number>>;
23
+ maxDeltaEventsPerTurn: number;
24
+ /** Precomputed once: whether ANY argument byte limit can fire. False when
25
+ * the global cap is disabled and every per-tool entry is a zero-valued
26
+ * disable — accounting must not allocate for guards that judge nothing. */
27
+ hasEnforceableToolCallArgLimit: boolean;
28
+ }
29
+ /** Cumulative streamed argument bytes for one in-flight tool call. */
30
+ export interface StreamedToolCallArgTally {
31
+ bytes: number;
32
+ name?: string;
33
+ /** The graph's breaker epoch when this tally was created. Entries from
34
+ * the epoch that is ending survive one `resetValues` sweep, so producer
35
+ * loops of straggling attempts — which are not behind the consumer-only
36
+ * epoch gate — stay on their original budgets instead of receiving a
37
+ * fresh allowance at every run start. */
38
+ epoch?: number;
39
+ /** Every tally-map key this tally is registered under: its primary key
40
+ * (which can migrate through identifier transitions), the batch-position
41
+ * fallback for id-bearing chunks, and the id for chunks carrying both
42
+ * identifiers. Release deletes all of them — a call sealed through one
43
+ * identity must not leave entries behind under another. */
44
+ keys?: string[];
45
+ /**
46
+ * True when the previous chunk ended on an unpaired UTF-16 high surrogate.
47
+ * Counting each half of a split surrogate pair alone yields 3 bytes per
48
+ * half (the replacement-character encoding) versus 4 for the pair, so the
49
+ * next chunk starting with the low surrogate reconciles by subtracting 2.
50
+ */
51
+ pendingHighSurrogate?: boolean;
52
+ }
53
+ /** Immutable snapshot of one run's breaker identity. Captured at
54
+ * model/event/tool-batch entry and revalidated by REFERENCE after awaits —
55
+ * one identity comparison proves no reset interleaved. */
56
+ export interface RunBreakerScope {
57
+ readonly epoch: number;
58
+ readonly controller: AbortController;
59
+ }
60
+ /** Streamed chunk events counted against one generation's event cap. */
61
+ export interface StreamDeltaEventTally {
62
+ count: number;
63
+ /** Creation-epoch tag, same grace semantics as
64
+ * {@link StreamedToolCallArgTally.epoch}. */
65
+ epoch?: number;
66
+ }
67
+ /**
68
+ * The graph-owned state the guards read and write. Structural on purpose:
69
+ * handler-level tests stub graphs with plain objects, and the guards lazily
70
+ * create the tally maps so partial stubs need no extra setup.
71
+ */
72
+ export interface StreamLimitState {
73
+ streamLimits?: ResolvedStreamLimits;
74
+ streamedToolCallArgTallies?: Map<string, StreamedToolCallArgTally>;
75
+ streamDeltaEventCounts?: Map<string, StreamDeltaEventTally>;
76
+ /** The graph's live breaker epoch; new accounting entries are tagged with
77
+ * it so `resetValues` can sweep by age instead of clearing outright. */
78
+ breakerEpoch?: number;
79
+ /** Generation keys of model attempts still in flight. Each attempt leases
80
+ * its generation at entry and releases it (with its accounting entries)
81
+ * from its `finally`, so retention follows ATTEMPT LIFETIME — a
82
+ * cancellation-ignoring straggler keeps its original budget no matter how
83
+ * many runs start and reset while it drains. */
84
+ activeStreamLimitGenerations?: Set<string>;
85
+ /** Per-chunk-object, per-generation charge balance: producer visits
86
+ * increment, consumer (handler echo) visits decrement, and a visit only
87
+ * charges when the other side has not pre-charged the same emission.
88
+ * Count-balancing rather than a lifetime set, because a streaming model
89
+ * may mutate and re-yield the same chunk object; scoped by generation so
90
+ * parallel generations sharing one reused object cannot cancel each
91
+ * other's charges. */
92
+ streamLimitChargeCredits?: WeakMap<object, Map<string, number>>;
93
+ }
94
+ /**
95
+ * Normalizes host-supplied limits once at graph construction. `undefined`
96
+ * applies the default for each guard (the tool-argument byte cap is ON by
97
+ * default, the per-turn event cap is opt-in), `0` and negative values
98
+ * disable a guard, `Infinity` means "no limit" and also disables, and `NaN`
99
+ * falls back to the default.
100
+ */
101
+ export declare function resolveStreamLimits(limits?: t.StreamLimits): ResolvedStreamLimits;
102
+ export type StreamLimitKind = 'tool_call_args' | 'delta_events';
103
+ /**
104
+ * Raised when a {@link t.StreamLimits} guard trips. Thrown from inside the
105
+ * run's `streamEvents` loop, so the in-flight provider request is torn down
106
+ * and `processStream` rejects with this error.
107
+ */
108
+ export declare class StreamLimitExceededError extends Error {
109
+ readonly kind: StreamLimitKind;
110
+ readonly limit: number;
111
+ readonly observed: number;
112
+ readonly toolName?: string;
113
+ constructor({ kind, limit, observed, toolName, }: {
114
+ kind: StreamLimitKind;
115
+ limit: number;
116
+ observed: number;
117
+ toolName?: string;
118
+ });
119
+ }
120
+ /**
121
+ * Identity of one model generation, derived from langgraph's node-execution
122
+ * metadata. Deliberately NOT `Graph.getStepKey()`: the step key forks within
123
+ * a single generation on reasoning transitions (`'reasoning'` /
124
+ * `post-reasoning-<n>` suffixes in `getKeyList`) and on mid-turn server-tool
125
+ * results (`invokedToolIds` count), which would hand a fresh budget to each
126
+ * segment. One agent-node execution is one superstep, so
127
+ * `checkpoint_ns + node + step` stays stable for the whole generation and
128
+ * distinguishes parallel agents in the same superstep.
129
+ *
130
+ * The attempt stamp scopes attempts within one node execution:
131
+ * `attemptInvoke` is the single funnel for primary, fallback, and
132
+ * summarization model calls and stamps {@link STREAM_LIMIT_ATTEMPT_KEY}
133
+ * with a unique sequence number into each attempt's callback metadata. A
134
+ * fallback's chunks therefore key separately from the failed primary's,
135
+ * even for two fallbacks configured with the same provider and model name,
136
+ * and even when the decoupled `streamEvents` reader drains a failed
137
+ * attempt's buffered chunks late. Those late chunks land in their own
138
+ * attempt's bucket instead of polluting the next one's.
139
+ */
140
+ export declare function resolveGenerationKey(metadata: Record<string, unknown> | undefined): string;
141
+ /**
142
+ * Metadata key carrying the unique per-model-attempt sequence number that
143
+ * `attemptInvoke` stamps into every attempt's callback metadata. Part of
144
+ * the generation key so budgets never alias across attempts.
145
+ */
146
+ export declare const STREAM_LIMIT_ATTEMPT_KEY = "lc_stream_limit_attempt";
147
+ /**
148
+ * Event-metadata marker for a chunk the SDK re-dispatches inline after
149
+ * transforming it (`attemptInvoke`'s OpenRouter final-reasoning replay). The
150
+ * original wire chunk still reaches the handler through `streamEvents` and
151
+ * is counted there, so the re-dispatch must not consume a second
152
+ * event-budget slot.
153
+ */
154
+ export declare const STREAM_LIMIT_REDISPATCH_KEY = "lc_stream_limit_redispatch";
155
+ /**
156
+ * Metadata key carrying the graph's breaker epoch at the time a model
157
+ * attempt started. The stream handler trips the shared breaker only when
158
+ * the event's epoch matches the live controller's — a straggling chunk from
159
+ * a failed run that outlived `resetValues()` must fail its own (dead) run,
160
+ * not abort the controller now serving the next one. A primitive rather
161
+ * than the controller itself so attempt metadata stays serialization-safe
162
+ * for tracing.
163
+ */
164
+ export declare const STREAM_LIMIT_EPOCH_KEY = "lc_stream_limit_epoch";
165
+ /**
166
+ * Configurable key carrying the tool batch's entry-captured
167
+ * {@link RunBreakerScope} to tools that spawn their own runs (subagents).
168
+ * Captured BEFORE PreToolUse hooks, so a reset during a hook cannot rebind
169
+ * the spawned child to the new run's controller. Stripped from host-facing
170
+ * batch requests and from child-graph configurables.
171
+ */
172
+ export declare const RUN_BREAKER_SCOPE_CONFIG_KEY = "lc_run_breaker_scope";
173
+ /**
174
+ * Accumulates the UTF-8 byte size of streamed tool-call argument chunks per
175
+ * in-flight tool call and throws once a single call's cumulative bytes
176
+ * exceed `maxToolCallArgBytes`. Runs once per streamed chunk event, before
177
+ * complete tool calls are dispatched or eagerly executed and before chunks
178
+ * are recorded, so a tripped limit stops the run without dispatching the
179
+ * offending call.
180
+ *
181
+ * Calls are keyed by generation and chunk `index`, falling back to the
182
+ * chunk `id` and then to the chunk's position within the event's batch when
183
+ * a provider identifies chunks by neither (Google emits complete parallel
184
+ * calls with optional ids and no index). A `kind: 'all'` arrival seal marks
185
+ * every chunk in the event as its own complete call, so those are checked
186
+ * standalone and never share a budget; a matching `kind: 'single'` seal
187
+ * replaces the call's tally with the sealing chunk's own bytes (the OpenAI
188
+ * Responses done-chunk restates the full argument string) and releases it.
189
+ */
190
+ export declare function enforceStreamedToolCallArgLimit({ graph, metadata, toolCallChunks, responseMetadata, parsedToolCalls, }: {
191
+ graph: StreamLimitState;
192
+ metadata: Record<string, unknown> | undefined;
193
+ toolCallChunks: ToolCallChunk[];
194
+ responseMetadata?: Record<string, unknown>;
195
+ /** Complete parsed calls from the same event, used to name anonymous raw
196
+ * chunks so per-tool overrides are honored before the global cap trips. */
197
+ parsedToolCalls?: CompleteToolCallLike[];
198
+ }): void;
199
+ /** Structural subset of a complete parsed tool call. */
200
+ interface CompleteToolCallLike {
201
+ id?: string;
202
+ name?: string;
203
+ args?: unknown;
204
+ }
205
+ /**
206
+ * Standalone byte check for complete parsed tool calls that arrive without a
207
+ * raw chunk representation: a streaming custom or OpenAI-compatible
208
+ * `ChatModel` can yield fully parsed `tool_calls` with empty
209
+ * `tool_call_chunks`, which would otherwise dispatch without consuming any
210
+ * byte budget. Complete calls are self-contained, so each is judged
211
+ * standalone without tallying.
212
+ */
213
+ export declare function enforceCompleteToolCallArgLimit({ graph, metadata, toolCalls, }: {
214
+ graph: StreamLimitState;
215
+ metadata: Record<string, unknown> | undefined;
216
+ toolCalls: CompleteToolCallLike[];
217
+ }): void;
218
+ /**
219
+ * Whether a chunk needs charge accounting at all. With the event cap off
220
+ * (the default) and no tool payload on the chunk, there is nothing a claim
221
+ * could ever gate — skipping restores the documented zero-cost-disabled
222
+ * behavior by avoiding a WeakMap entry and nested Map per ordinary text
223
+ * delta. Both the producer and consumer paths use this same predicate on
224
+ * the same chunk, so claim pairing is unaffected.
225
+ */
226
+ export declare function requiresStreamLimitAccounting(graph: StreamLimitState, chunk: {
227
+ tool_call_chunks?: unknown[];
228
+ tool_calls?: unknown[];
229
+ invalid_tool_calls?: unknown[];
230
+ }): boolean;
231
+ /** True when any stream-limit guard can fire for this graph. The attempt
232
+ * lease and per-chunk claims are both gated on it — fully disabled guards
233
+ * must allocate no bookkeeping at all, per-attempt included. */
234
+ export declare function streamLimitAccountingEnabled(graph: StreamLimitState): boolean;
235
+ /** Leases a model attempt's generation: entries under it are exempt from
236
+ * the reset sweep until {@link releaseStreamLimitGeneration} runs from the
237
+ * attempt's `finally`. */
238
+ export declare function registerActiveStreamLimitGeneration(graph: StreamLimitState, generationKey: string): void;
239
+ /** Ends an attempt's lease and deletes its accounting entries — the
240
+ * authoritative retirement point for attempt-scoped state. */
241
+ export declare function releaseStreamLimitGeneration(graph: StreamLimitState, generationKey: string): void;
242
+ /**
243
+ * Deletes accounting entries older than the epoch that is ending, EXCEPT
244
+ * entries leased by a still-active attempt. Called by `resetValues` instead
245
+ * of clearing: producer loops of straggling attempts use the graph's maps
246
+ * directly and are not behind the consumer-only epoch gate, so a clear
247
+ * would hand a cancellation-ignoring provider a fresh allowance at every
248
+ * run start. Leased entries live until their attempt's `finally` releases
249
+ * them; unleased entries (direct callers with no attempt stamp) get one
250
+ * grace reset via their epoch tag.
251
+ */
252
+ export declare function sweepStaleStreamLimitEntries(entries: Map<string, {
253
+ epoch?: number;
254
+ }>, endingEpoch: number, activeGenerations?: ReadonlySet<string>): void;
255
+ export declare function linkStreamLimitCanonical(copy: object, canonical: object): void;
256
+ /**
257
+ * Claims accounting ownership of one EMISSION of a wire chunk. LangChain can
258
+ * hand the same chunk object to the decoupled `streamEvents` handler
259
+ * (`consumer`) and to the dispatch loop (`producer`) in either order, and a
260
+ * streaming model may mutate and re-yield the same object across emissions —
261
+ * so dedup is a signed credit balance per object rather than a lifetime set.
262
+ * Each producer visit adds a credit, each consumer visit removes one, and a
263
+ * visit charges only when the other side has not already charged that
264
+ * emission (positive balance = producer ahead, negative = consumer ahead).
265
+ * Paths where only one side ever observes the chunk (summarization, local
266
+ * replay-skip) charge every visit, since their balance never crosses zero
267
+ * the other way. Balances are scoped by generation identity so parallel
268
+ * generations sharing one reused chunk object cannot cancel each other's
269
+ * charges. Non-object chunks cannot be identity-tracked and are always
270
+ * claimable.
271
+ */
272
+ export declare function claimStreamLimitCharge(graph: StreamLimitState, chunk: unknown, side: 'producer' | 'consumer', metadata: Record<string, unknown> | undefined): boolean;
273
+ /**
274
+ * Synchronous producer-side accounting for wire chunks that would otherwise
275
+ * be judged only when the decoupled `streamEvents` reader catches up — or,
276
+ * on replay-skipped and summarization chunks, not at all. A lagging reader
277
+ * would let an oversized complete call return to LangGraph and reach
278
+ * `ToolNode` before the queued handler throws; charging in the producer
279
+ * loop keeps the breaker ahead of graph progression. Claim-based, so
280
+ * whichever of this path and the handler echo sees the chunk object first
281
+ * charges it and the other skips.
282
+ */
283
+ export declare function enforceStreamLimitsForWireChunk({ graph, metadata, chunk, side, }: {
284
+ graph: StreamLimitState;
285
+ metadata: Record<string, unknown> | undefined;
286
+ chunk: {
287
+ tool_call_chunks?: ToolCallChunk[];
288
+ tool_calls?: CompleteToolCallLike[];
289
+ invalid_tool_calls?: CompleteToolCallLike[];
290
+ response_metadata?: Record<string, unknown>;
291
+ };
292
+ /** Claim side for the credit balance. The local dispatch branch charges
293
+ * as `consumer` because its handler-handled and replay-skipped emissions
294
+ * of one reused object ALTERNATE — mixed sides would pair them as
295
+ * producer/echo and swallow a charge. */
296
+ side?: 'producer' | 'consumer';
297
+ }): void;
298
+ /** Combined view of a chunk's parsed and invalid complete calls, avoiding
299
+ * allocation on the common paths where one or both are absent. */
300
+ export declare function combineCompleteToolCalls(chunk: {
301
+ tool_calls?: CompleteToolCallLike[];
302
+ invalid_tool_calls?: CompleteToolCallLike[];
303
+ }): CompleteToolCallLike[] | undefined;
304
+ /**
305
+ * Counts streamed chunk events per model generation and throws once a single
306
+ * generation exceeds `maxDeltaEventsPerTurn`. Opt-in defense in depth for
307
+ * pathologies a byte cap cannot see, such as a provider stream looping on
308
+ * empty chunks. Zero cost while disabled.
309
+ */
310
+ export declare function enforceStreamDeltaEventLimit({ graph, metadata, }: {
311
+ graph: StreamLimitState;
312
+ metadata: Record<string, unknown> | undefined;
313
+ }): void;
314
+ export {};
@@ -9,12 +9,16 @@ export declare function getConverseOverrideMessage({ userMessage, lastMessageX,
9
9
  export declare function modifyDeltaProperties(provider: Providers, obj?: AIMessageChunk): AIMessageChunk | undefined;
10
10
  export declare function formatAnthropicMessage(message: AIMessageChunk): AIMessage;
11
11
  export declare function convertMessagesToContent(messages: BaseMessage[]): t.MessageContentComplex[];
12
- /**
13
- * Drops incomplete streamed text-input fragments that some providers retain
14
- * beside the assembled parsed tool call. They are neither user-visible text
15
- * nor valid content blocks for a subsequent provider.
16
- */
17
- export declare function projectToolStreamContentForProvider(messages: BaseMessage[]): BaseMessage[];
12
+ type ResponsesReplayProjection = 'fallback' | 'native';
13
+ export declare const OPENAI_RESPONSES_REPLAY_POSITIONS_KEY = "__openai_responses_replay_positions__";
14
+ export type ResponsesReplayPosition = {
15
+ contentIndex?: number;
16
+ itemId: string;
17
+ kind: 'message' | 'output' | 'reasoning' | 'text';
18
+ outputIndex: number;
19
+ };
20
+ /** Applies sealed-Responses safety and drops incomplete streamed text input. */
21
+ export declare function projectToolStreamContentForProvider(messages: BaseMessage[], responsesReplayProjection?: ResponsesReplayProjection, maxChars?: number): BaseMessage[];
18
22
  /** Projects OpenAI-compatible tool content without changing parsed call parents. */
19
23
  export declare function projectOpenAIToolMessageContent(messages: BaseMessage[], maxChars?: number): BaseMessage[];
20
24
  /** Projects an actual OpenAI-compatible Chat attempt and removes cache metadata. */
@@ -48,3 +52,4 @@ export declare function projectArtifactPayload(messages: BaseMessage[], maxChars
48
52
  */
49
53
  export declare function formatArtifactPayload(messages: BaseMessage[]): void;
50
54
  export declare function findLastIndex<T>(array: T[], predicate: (value: T) => boolean): number;
55
+ export {};
@@ -18,6 +18,7 @@ export declare class Run<_T extends t.BaseGraphState> {
18
18
  private toolExecution?;
19
19
  private subagentUsageSink?;
20
20
  private preemption?;
21
+ private streamLimits?;
21
22
  private indexTokenCountMap?;
22
23
  calibrationRatio: number;
23
24
  graphRunnable?: t.CompiledStateWorkflow;
@@ -1,8 +1,11 @@
1
1
  import type { BaseMessage } from '@langchain/core/messages';
2
2
  import type { RunnableConfig } from '@langchain/core/runnables';
3
+ import type { StreamLimitState } from '@/llm/streamLimits';
3
4
  import type { AgentContext } from '@/agents/AgentContext';
4
5
  import type { HookRegistry } from '@/hooks';
6
+ import type { OnChunk } from '@/llm/invoke';
5
7
  import type * as t from '@/types';
8
+ import { Providers } from '@/common';
6
9
  /** Structured checkpoint prompt for fresh summarization (no prior summary). */
7
10
  export declare const DEFAULT_SUMMARIZATION_PROMPT = "Hold on, before you continue I need you to write me a checkpoint of everything so far. Your context window is filling up and this checkpoint replaces the messages above, so capture everything you need to pick right back up.\n\nDon't second-guess or fact-check anything you did, your tool results reflect exactly what happened. If a tool result appears truncated, that's just a display artifact from context management: the tool executed fully. Just record what you did and what you observed. Only the checkpoint, don't respond to me or continue the conversation.\n\n## Checkpoint\n\n## Goal\nWhat I asked you to do and any sub-goals you identified.\n\n## Constraints & Preferences\nAny rules, preferences, or configuration I established.\n\n## Progress\n### Done\n- What you completed and the outcomes\n\n### In Progress\n- What you're currently working on\n\n## Key Decisions\nDecisions you made and why.\n\n## Next Steps\nConcrete task actions remaining, in priority order.\n\n## Critical Context\nExact identifiers, names, error messages, URLs, and details you need to preserve verbatim.\n\nRules:\n- Record what you did and observed, don't judge or re-evaluate it\n- For each tool call: the tool name, key inputs, and the outcome\n- Preserve exact identifiers, names, errors, and references verbatim\n- Short declarative sentences\n- Skip empty sections";
8
11
  /** Prompt for re-compaction when a prior summary exists. */
@@ -18,14 +21,36 @@ interface CreateSummarizeNodeParams {
18
21
  hookRegistry?: HookRegistry;
19
22
  dispatchRunStep: (runStep: t.RunStep, config?: RunnableConfig) => Promise<void>;
20
23
  dispatchRunStepCompleted: (stepId: string, result: t.StepCompleted, config?: RunnableConfig) => Promise<void>;
21
- };
24
+ /** The run's shared breaker signal, composed into every summarization
25
+ * model attempt so a sibling branch tripping a stream limit also
26
+ * cancels in-flight summaries. */
27
+ getBreakerSignal?: () => AbortSignal;
28
+ /** The run's shared breaker controller. Preferred over the bare signal
29
+ * accessor: the node captures it at entry so a breach detected by its
30
+ * own chunk handler trips the run that STARTED the summarization. */
31
+ getBreakerController?: () => AbortController;
32
+ /** The controller's epoch, captured at entry and stamped into summary
33
+ * attempt metadata so the wire consumer epoch-gates old-run summary
34
+ * chunks like model-attempt chunks. */
35
+ getBreakerEpoch?: () => number;
36
+ } & StreamLimitState;
22
37
  generateStepId: (stepKey: string) => [string, number];
23
38
  }
24
- export declare function createSummarizeNode({ agentContext, graph, generateStepId, }: CreateSummarizeNodeParams): (state: {
39
+ export declare function createSummarizeNode({ agentContext, graph: adapterGraph, generateStepId, }: CreateSummarizeNodeParams): (state: {
25
40
  messages: BaseMessage[];
26
41
  summarizationRequest?: t.SummarizationNodeInput;
27
42
  }, config?: RunnableConfig) => Promise<{
28
43
  summarizationRequest: undefined;
29
44
  messages?: BaseMessage[];
30
45
  }>;
46
+ /** Creates an `onChunk` callback that dispatches `ON_SUMMARIZE_DELTA` events for streaming. */
47
+ export declare function createSummarizationChunkHandler({ stepId, config, provider, reasoningKey, graph, }: {
48
+ stepId?: string;
49
+ config?: RunnableConfig;
50
+ provider?: Providers;
51
+ reasoningKey?: 'reasoning_content' | 'reasoning';
52
+ graph?: StreamLimitState & {
53
+ getBreakerController?: () => AbortController;
54
+ };
55
+ }): OnChunk | undefined;
31
56
  export {};
@@ -15,7 +15,7 @@ export declare const BashExecutionToolSchema: {
15
15
  };
16
16
  readonly command: {
17
17
  readonly type: "string";
18
- readonly description: "The bash command or script to execute.\n- The environment is stateless; variables and state don't persist between executions.\n- Prior /mnt/data files are available and can be modified in place.\n- Persist handoff artifacts in `/mnt/data` with standard extensions (.json/.txt/.csv/.tsv/.log/.parquet/.png/.jpg/.pdf/.xlsx); failed executions do not register new files; `/tmp` and odd extensions are same-call scratch only, not later-call storage.\n- Bash: multi-line files use heredoc/printf; run Python via python3 -c/heredoc, not bare Python.\n- Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.\n- Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.\n- IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.\n- Use `echo`, `printf`, or `cat` for all outputs.";
18
+ readonly description: "The bash command or script to execute.\n- The environment is stateless; variables and state don't persist between executions.\n- Prior /mnt/data files are available and can be modified in place.\n- Anything a later call needs (data, helper scripts/modules, partial results) MUST be written under `/mnt/data` in the same call that produces it; `/tmp` never survives the call. `/mnt/data` keeps files with recognized extensions, covering common source, text, data, document, image, and archive formats (.py/.sh/.sql/.md/.json/.csv/.parquet/.png/.pdf/.zip and similar); extensionless or unusual extensions are not kept. Failed executions register nothing; fix the error and rerun before relying on new files.\n- Bash: multi-line files use heredoc/printf; run Python via python3 -c/heredoc, not bare Python.\n- Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.\n- Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.\n- IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.\n- Use `echo`, `printf`, or `cat` for all outputs.";
19
19
  };
20
20
  readonly args: {
21
21
  readonly type: "array";
@@ -91,7 +91,7 @@ export declare const BashExecutionToolDefinition: {
91
91
  };
92
92
  readonly command: {
93
93
  readonly type: "string";
94
- readonly description: "The bash command or script to execute.\n- The environment is stateless; variables and state don't persist between executions.\n- Prior /mnt/data files are available and can be modified in place.\n- Persist handoff artifacts in `/mnt/data` with standard extensions (.json/.txt/.csv/.tsv/.log/.parquet/.png/.jpg/.pdf/.xlsx); failed executions do not register new files; `/tmp` and odd extensions are same-call scratch only, not later-call storage.\n- Bash: multi-line files use heredoc/printf; run Python via python3 -c/heredoc, not bare Python.\n- Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.\n- Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.\n- IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.\n- Use `echo`, `printf`, or `cat` for all outputs.";
94
+ readonly description: "The bash command or script to execute.\n- The environment is stateless; variables and state don't persist between executions.\n- Prior /mnt/data files are available and can be modified in place.\n- Anything a later call needs (data, helper scripts/modules, partial results) MUST be written under `/mnt/data` in the same call that produces it; `/tmp` never survives the call. `/mnt/data` keeps files with recognized extensions, covering common source, text, data, document, image, and archive formats (.py/.sh/.sql/.md/.json/.csv/.parquet/.png/.pdf/.zip and similar); extensionless or unusual extensions are not kept. Failed executions register nothing; fix the error and rerun before relying on new files.\n- Bash: multi-line files use heredoc/printf; run Python via python3 -c/heredoc, not bare Python.\n- Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.\n- Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.\n- IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.\n- Use `echo`, `printf`, or `cat` for all outputs.";
95
95
  };
96
96
  readonly args: {
97
97
  readonly type: "array";
@@ -4,7 +4,7 @@ import { Constants } from '@/common';
4
4
  export { appendCodeSessionFileSummary, stripCodeSessionFileSummary, } from '@/tools/CodeSessionFileSummary';
5
5
  export declare const getCodeBaseURL: () => string;
6
6
  export declare const emptyOutputMessage = "stdout: Empty. Ensure you're writing output explicitly.\n";
7
- export declare const CODE_ARTIFACT_PATH_GUIDANCE = "Persist handoff artifacts in `/mnt/data` with standard extensions (.json/.txt/.csv/.tsv/.log/.parquet/.png/.jpg/.pdf/.xlsx); failed executions do not register new files; `/tmp` and odd extensions are same-call scratch only, not later-call storage.";
7
+ export declare const CODE_ARTIFACT_PATH_GUIDANCE = "Anything a later call needs (data, helper scripts/modules, partial results) MUST be written under `/mnt/data` in the same call that produces it; `/tmp` never survives the call. `/mnt/data` keeps files with recognized extensions, covering common source, text, data, document, image, and archive formats (.py/.sh/.sql/.md/.json/.csv/.parquet/.png/.pdf/.zip and similar); extensionless or unusual extensions are not kept. Failed executions register nothing; fix the error and rerun before relying on new files.";
8
8
  export declare const BASH_SHELL_GUIDANCE = "Bash: multi-line files use heredoc/printf; run Python via python3 -c/heredoc, not bare Python.";
9
9
  export declare const TMP_SCRATCH_OUTPUT_REMINDER = "Note: /tmp files are same-call scratch only and were not persisted; use /mnt/data for files needed later.";
10
10
  export declare const FAILED_EXECUTION_FILE_REMINDER = "Note: any files written during this failed call were not registered for later calls; fix the error and rerun before relying on them.";
@@ -29,7 +29,7 @@ export declare const CodeExecutionToolSchema: {
29
29
  };
30
30
  readonly code: {
31
31
  readonly type: "string";
32
- readonly description: "The complete, self-contained code to execute, without any truncation or minimization.\n- The environment is stateless; variables and imports don't persist between executions.\n- Prior /mnt/data files are available and can be modified in place.\n- Persist handoff artifacts in `/mnt/data` with standard extensions (.json/.txt/.csv/.tsv/.log/.parquet/.png/.jpg/.pdf/.xlsx); failed executions do not register new files; `/tmp` and odd extensions are same-call scratch only, not later-call storage.\n- Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.\n- Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.\n- IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.\n- py: This is not a Jupyter notebook environment. Use `print()` for all outputs.\n- py: Matplotlib: Use `plt.savefig()` to save plots as files.\n- js: use the `console` or `process` methods for all outputs.\n- r: IMPORTANT: No X11 display available. ALL graphics MUST use Cairo library (library(Cairo)).\n- Other languages: use appropriate output functions.";
32
+ readonly description: "The complete, self-contained code to execute, without any truncation or minimization.\n- The environment is stateless; variables and imports don't persist between executions.\n- Prior /mnt/data files are available and can be modified in place.\n- Anything a later call needs (data, helper scripts/modules, partial results) MUST be written under `/mnt/data` in the same call that produces it; `/tmp` never survives the call. `/mnt/data` keeps files with recognized extensions, covering common source, text, data, document, image, and archive formats (.py/.sh/.sql/.md/.json/.csv/.parquet/.png/.pdf/.zip and similar); extensionless or unusual extensions are not kept. Failed executions register nothing; fix the error and rerun before relying on new files.\n- Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.\n- Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.\n- IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.\n- py: This is not a Jupyter notebook environment. Use `print()` for all outputs.\n- py: Matplotlib: Use `plt.savefig()` to save plots as files.\n- js: use the `console` or `process` methods for all outputs.\n- r: IMPORTANT: No X11 display available. ALL graphics MUST use Cairo library (library(Cairo)).\n- Other languages: use appropriate output functions.";
33
33
  };
34
34
  readonly args: {
35
35
  readonly type: "array";
@@ -99,7 +99,7 @@ export declare const CodeExecutionToolDefinition: {
99
99
  };
100
100
  readonly code: {
101
101
  readonly type: "string";
102
- readonly description: "The complete, self-contained code to execute, without any truncation or minimization.\n- The environment is stateless; variables and imports don't persist between executions.\n- Prior /mnt/data files are available and can be modified in place.\n- Persist handoff artifacts in `/mnt/data` with standard extensions (.json/.txt/.csv/.tsv/.log/.parquet/.png/.jpg/.pdf/.xlsx); failed executions do not register new files; `/tmp` and odd extensions are same-call scratch only, not later-call storage.\n- Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.\n- Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.\n- IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.\n- py: This is not a Jupyter notebook environment. Use `print()` for all outputs.\n- py: Matplotlib: Use `plt.savefig()` to save plots as files.\n- js: use the `console` or `process` methods for all outputs.\n- r: IMPORTANT: No X11 display available. ALL graphics MUST use Cairo library (library(Cairo)).\n- Other languages: use appropriate output functions.";
102
+ readonly description: "The complete, self-contained code to execute, without any truncation or minimization.\n- The environment is stateless; variables and imports don't persist between executions.\n- Prior /mnt/data files are available and can be modified in place.\n- Anything a later call needs (data, helper scripts/modules, partial results) MUST be written under `/mnt/data` in the same call that produces it; `/tmp` never survives the call. `/mnt/data` keeps files with recognized extensions, covering common source, text, data, document, image, and archive formats (.py/.sh/.sql/.md/.json/.csv/.parquet/.png/.pdf/.zip and similar); extensionless or unusual extensions are not kept. Failed executions register nothing; fix the error and rerun before relying on new files.\n- Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.\n- Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.\n- IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.\n- py: This is not a Jupyter notebook environment. Use `print()` for all outputs.\n- py: Matplotlib: Use `plt.savefig()` to save plots as files.\n- js: use the `console` or `process` methods for all outputs.\n- r: IMPORTANT: No X11 display available. ALL graphics MUST use Cairo library (library(Cairo)).\n- Other languages: use appropriate output functions.";
103
103
  };
104
104
  readonly args: {
105
105
  readonly type: "array";
@@ -192,6 +192,10 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
192
192
  private toolOutputRegistry?;
193
193
  /** Run-scoped selection for swapping remote code tools to local executors. */
194
194
  private toolExecution?;
195
+ /** Owning graph's run-scoped breaker signal, composed into each batch's config. */
196
+ private getBreakerSignal?;
197
+ /** Owning graph's immutable run scope; captured once per batch. */
198
+ private getRunScope?;
195
199
  /**
196
200
  * Monotonic counter used to mint a unique scope id for anonymous
197
201
  * batches (ones invoked without a `run_id` in
@@ -200,7 +204,7 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
200
204
  * other's in-flight state.
201
205
  */
202
206
  private anonBatchCounter;
203
- constructor({ tools, toolMap, name, tags, trace, runLangfuse, agentLangfuse, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, toolRegistry, sessions, eventDrivenMode, eagerEventToolExecution, eagerEventToolExecutions, eagerEventToolUsageCount, eagerEventToolSuppressions, agentId, executingAgentId, directToolNames, interruptingToolNames, codeSessionToolNames, maxContextTokens, maxToolResultChars, hookRegistry, humanInTheLoop, toolOutputReferences, toolOutputRegistry, toolExecution, fileCheckpointer, }: t.ToolNodeConstructorParams);
207
+ constructor({ tools, toolMap, name, tags, trace, runLangfuse, agentLangfuse, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, toolRegistry, sessions, eventDrivenMode, eagerEventToolExecution, eagerEventToolExecutions, eagerEventToolUsageCount, eagerEventToolSuppressions, agentId, executingAgentId, directToolNames, interruptingToolNames, codeSessionToolNames, maxContextTokens, maxToolResultChars, hookRegistry, humanInTheLoop, toolOutputReferences, toolOutputRegistry, toolExecution, fileCheckpointer, getBreakerSignal, getRunScope, }: t.ToolNodeConstructorParams);
204
208
  invoke(input: any, options?: Partial<RunnableConfig>): Promise<any>;
205
209
  /**
206
210
  * Returns the run-scoped tool output registry, or `undefined` when
@@ -399,6 +403,12 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
399
403
  * 4. Injected messages from results are collected and returned alongside
400
404
  * ToolMessages (appended AFTER to respect provider ordering).
401
405
  */
406
+ /** Rethrows a stream-limit trip carried on the batch config's composed
407
+ * signal. Rechecked at each later execution/dispatch stage because a tool
408
+ * that ignores cancellation can complete normally across the trip, and
409
+ * the next stage would otherwise start fresh side effects on a failed
410
+ * run. */
411
+ private throwIfBreakerTripped;
402
412
  private dispatchToolEvents;
403
413
  /** Run-scoped so another run's session hooks can't flip this run's gate. */
404
414
  private canConsumeEagerEventExecution;
@@ -19,6 +19,8 @@ export declare class CrwScraper implements t.BaseScraper {
19
19
  private xpath?;
20
20
  private proxy?;
21
21
  private stealth?;
22
+ private httpAgent?;
23
+ private httpsAgent?;
22
24
  constructor(config?: t.CrwScraperConfig);
23
25
  scrapeUrl(url: string, options?: t.CrwScrapeOptions): Promise<[string, t.CrwScrapeResponse]>;
24
26
  /**
@@ -25,6 +25,8 @@ export declare class FirecrawlScraper implements t.BaseScraper {
25
25
  private location?;
26
26
  private onlyMainContent?;
27
27
  private changeTrackingOptions?;
28
+ private httpAgent?;
29
+ private httpsAgent?;
28
30
  constructor(config?: t.FirecrawlScraperConfig);
29
31
  /**
30
32
  * Scrape a single URL
@@ -5,6 +5,8 @@ export declare class KeenableScraper implements t.BaseScraper {
5
5
  private timeout;
6
6
  private attributionTitle;
7
7
  private logger;
8
+ private httpAgent?;
9
+ private httpsAgent?;
8
10
  constructor(config?: t.KeenableScraperConfig);
9
11
  private buildHeaders;
10
12
  scrapeUrl(url: string, options?: t.KeenableScrapeOptions): Promise<[string, t.KeenableScrapeResponse]>;