@librechat/agents 3.3.13 → 3.4.1

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 (192) hide show
  1. package/dist/cjs/graphs/Graph.cjs +121 -27
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/hooks/HookRegistry.cjs +83 -0
  4. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  5. package/dist/cjs/hooks/executeHooks.cjs +60 -14
  6. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  7. package/dist/cjs/hooks/index.cjs.map +1 -1
  8. package/dist/cjs/hooks/types.cjs +2 -0
  9. package/dist/cjs/hooks/types.cjs.map +1 -1
  10. package/dist/cjs/llm/anthropic/index.cjs +35 -206
  11. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  12. package/dist/cjs/llm/bedrock/index.cjs +121 -241
  13. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  14. package/dist/cjs/llm/google/index.cjs +19 -12
  15. package/dist/cjs/llm/google/index.cjs.map +1 -1
  16. package/dist/cjs/llm/init.cjs +3 -3
  17. package/dist/cjs/llm/invoke.cjs +2 -2
  18. package/dist/cjs/llm/mistral/index.cjs +26 -0
  19. package/dist/cjs/llm/mistral/index.cjs.map +1 -0
  20. package/dist/cjs/llm/openai/index.cjs +82 -80
  21. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  22. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  23. package/dist/cjs/llm/providers.cjs +19 -19
  24. package/dist/cjs/llm/providers.cjs.map +1 -1
  25. package/dist/cjs/llm/stream/chunkAdapters.cjs +198 -0
  26. package/dist/cjs/llm/stream/chunkAdapters.cjs.map +1 -0
  27. package/dist/cjs/llm/stream/smoother.cjs +369 -0
  28. package/dist/cjs/llm/stream/smoother.cjs.map +1 -0
  29. package/dist/cjs/llm/vertexai/index.cjs +13 -1
  30. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  31. package/dist/cjs/main.cjs +25 -16
  32. package/dist/cjs/messages/format.cjs +40 -23
  33. package/dist/cjs/messages/format.cjs.map +1 -1
  34. package/dist/cjs/run.cjs +82 -15
  35. package/dist/cjs/run.cjs.map +1 -1
  36. package/dist/cjs/session/AgentSession.cjs +37 -2
  37. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  38. package/dist/cjs/stream.cjs +1 -1
  39. package/dist/cjs/summarization/node.cjs +6 -3
  40. package/dist/cjs/summarization/node.cjs.map +1 -1
  41. package/dist/cjs/tools/BashExecutor.cjs +1 -1
  42. package/dist/cjs/tools/CodeExecutor.cjs +1 -1
  43. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +1 -1
  44. package/dist/cjs/tools/ToolNode.cjs +316 -94
  45. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  46. package/dist/cjs/tools/ToolSearch.cjs +1 -1
  47. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +664 -80
  48. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  49. package/dist/cjs/tools/subagent/SubagentReplay.cjs +175 -0
  50. package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -0
  51. package/dist/cjs/tools/toolOutputReferences.cjs +20 -0
  52. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  53. package/dist/cjs/utils/index.cjs +2 -2
  54. package/dist/cjs/utils/tokens.cjs +76 -29
  55. package/dist/cjs/utils/tokens.cjs.map +1 -1
  56. package/dist/esm/graphs/Graph.mjs +121 -27
  57. package/dist/esm/graphs/Graph.mjs.map +1 -1
  58. package/dist/esm/hooks/HookRegistry.mjs +83 -0
  59. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  60. package/dist/esm/hooks/executeHooks.mjs +60 -14
  61. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  62. package/dist/esm/hooks/index.mjs.map +1 -1
  63. package/dist/esm/hooks/types.mjs +2 -1
  64. package/dist/esm/hooks/types.mjs.map +1 -1
  65. package/dist/esm/llm/anthropic/index.mjs +34 -205
  66. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  67. package/dist/esm/llm/bedrock/index.mjs +120 -240
  68. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  69. package/dist/esm/llm/google/index.mjs +19 -12
  70. package/dist/esm/llm/google/index.mjs.map +1 -1
  71. package/dist/esm/llm/init.mjs +1 -1
  72. package/dist/esm/llm/invoke.mjs +2 -2
  73. package/dist/esm/llm/mistral/index.mjs +26 -0
  74. package/dist/esm/llm/mistral/index.mjs.map +1 -0
  75. package/dist/esm/llm/openai/index.mjs +82 -80
  76. package/dist/esm/llm/openai/index.mjs.map +1 -1
  77. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  78. package/dist/esm/llm/providers.mjs +3 -3
  79. package/dist/esm/llm/providers.mjs.map +1 -1
  80. package/dist/esm/llm/stream/chunkAdapters.mjs +195 -0
  81. package/dist/esm/llm/stream/chunkAdapters.mjs.map +1 -0
  82. package/dist/esm/llm/stream/smoother.mjs +365 -0
  83. package/dist/esm/llm/stream/smoother.mjs.map +1 -0
  84. package/dist/esm/llm/vertexai/index.mjs +13 -1
  85. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  86. package/dist/esm/main.mjs +13 -11
  87. package/dist/esm/messages/format.mjs +40 -23
  88. package/dist/esm/messages/format.mjs.map +1 -1
  89. package/dist/esm/run.mjs +83 -16
  90. package/dist/esm/run.mjs.map +1 -1
  91. package/dist/esm/session/AgentSession.mjs +37 -2
  92. package/dist/esm/session/AgentSession.mjs.map +1 -1
  93. package/dist/esm/stream.mjs +1 -1
  94. package/dist/esm/summarization/node.mjs +6 -3
  95. package/dist/esm/summarization/node.mjs.map +1 -1
  96. package/dist/esm/tools/BashExecutor.mjs +1 -1
  97. package/dist/esm/tools/CodeExecutor.mjs +1 -1
  98. package/dist/esm/tools/ProgrammaticToolCalling.mjs +1 -1
  99. package/dist/esm/tools/ToolNode.mjs +317 -95
  100. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  101. package/dist/esm/tools/ToolSearch.mjs +1 -1
  102. package/dist/esm/tools/subagent/SubagentExecutor.mjs +665 -81
  103. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  104. package/dist/esm/tools/subagent/SubagentReplay.mjs +168 -0
  105. package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -0
  106. package/dist/esm/tools/toolOutputReferences.mjs +20 -0
  107. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  108. package/dist/esm/utils/index.mjs +2 -2
  109. package/dist/esm/utils/tokens.mjs +76 -30
  110. package/dist/esm/utils/tokens.mjs.map +1 -1
  111. package/dist/types/graphs/Graph.d.ts +19 -1
  112. package/dist/types/hooks/HookRegistry.d.ts +10 -1
  113. package/dist/types/hooks/executeHooks.d.ts +5 -1
  114. package/dist/types/hooks/index.d.ts +2 -2
  115. package/dist/types/hooks/types.d.ts +12 -0
  116. package/dist/types/index.d.ts +3 -0
  117. package/dist/types/llm/google/index.d.ts +2 -0
  118. package/dist/types/llm/mistral/index.d.ts +11 -0
  119. package/dist/types/llm/openai/index.d.ts +20 -4
  120. package/dist/types/llm/openrouter/index.d.ts +4 -1
  121. package/dist/types/llm/stream/chunkAdapters.d.ts +48 -0
  122. package/dist/types/llm/stream/smoother.d.ts +95 -0
  123. package/dist/types/llm/vertexai/index.d.ts +2 -0
  124. package/dist/types/run.d.ts +4 -1
  125. package/dist/types/session/AgentSession.d.ts +1 -0
  126. package/dist/types/tools/ToolNode.d.ts +23 -15
  127. package/dist/types/tools/subagent/SubagentExecutor.d.ts +49 -7
  128. package/dist/types/tools/subagent/SubagentReplay.d.ts +81 -0
  129. package/dist/types/tools/toolOutputReferences.d.ts +12 -0
  130. package/dist/types/types/graph.d.ts +5 -5
  131. package/dist/types/types/hitl.d.ts +15 -0
  132. package/dist/types/types/llm.d.ts +21 -14
  133. package/dist/types/utils/tokens.d.ts +10 -0
  134. package/package.json +6 -2
  135. package/src/graphs/Graph.ts +257 -52
  136. package/src/graphs/__tests__/Graph.breakerLifecycle.test.ts +48 -9
  137. package/src/graphs/__tests__/Graph.contextOverflow.test.ts +1 -1
  138. package/src/graphs/__tests__/Graph.subagentResumeState.test.ts +80 -0
  139. package/src/hooks/HookRegistry.ts +151 -1
  140. package/src/hooks/__tests__/HookRegistry.test.ts +96 -0
  141. package/src/hooks/__tests__/executeHooks.test.ts +160 -0
  142. package/src/hooks/executeHooks.ts +133 -15
  143. package/src/hooks/index.ts +3 -1
  144. package/src/hooks/types.ts +16 -0
  145. package/src/index.ts +8 -0
  146. package/src/llm/anthropic/index.ts +85 -354
  147. package/src/llm/bedrock/index.ts +174 -390
  148. package/src/llm/bedrock/llm.spec.ts +2 -0
  149. package/src/llm/bedrock/streamSealDispatch.test.ts +76 -0
  150. package/src/llm/custom-chat-models.smoke.test.ts +16 -1
  151. package/src/llm/google/index.ts +17 -18
  152. package/src/llm/google/streamSmoothing.test.ts +121 -0
  153. package/src/llm/mistral/index.ts +33 -0
  154. package/src/llm/mistral/streamSmoothing.test.ts +97 -0
  155. package/src/llm/openai/deepseek.test.ts +56 -0
  156. package/src/llm/openai/index.ts +119 -126
  157. package/src/llm/openrouter/index.ts +4 -1
  158. package/src/llm/providers.ts +3 -3
  159. package/src/llm/stream/chunkAdapters.test.ts +202 -0
  160. package/src/llm/stream/chunkAdapters.ts +317 -0
  161. package/src/llm/stream/reassembly.test.ts +241 -0
  162. package/src/llm/stream/smoother.bench.test.ts +155 -0
  163. package/src/llm/stream/smoother.test.ts +519 -0
  164. package/src/llm/stream/smoother.ts +574 -0
  165. package/src/llm/vertexai/index.ts +17 -1
  166. package/src/llm/vertexai/streamSmoothing.test.ts +109 -0
  167. package/src/messages/format.ts +54 -26
  168. package/src/messages/formatAgentMessages.reducer.test.ts +162 -0
  169. package/src/messages/formatAgentMessages.steer.test.ts +16 -11
  170. package/src/messages/formatAgentMessages.test.ts +7 -2
  171. package/src/run.ts +164 -18
  172. package/src/session/AgentSession.ts +52 -2
  173. package/src/session/__tests__/JsonlSessionStore.test.ts +53 -0
  174. package/src/specs/subagent.test.ts +44 -0
  175. package/src/specs/tokens.test.ts +159 -14
  176. package/src/summarization/__tests__/node.test.ts +32 -14
  177. package/src/summarization/node.ts +15 -11
  178. package/src/tools/ToolNode.ts +631 -157
  179. package/src/tools/__tests__/SubagentExecutor.test.ts +590 -7
  180. package/src/tools/__tests__/SubagentReplay.test.ts +300 -0
  181. package/src/tools/__tests__/ToolNode.breakerSignal.test.ts +208 -2
  182. package/src/tools/__tests__/directToolHITLResumeScope.test.ts +486 -2
  183. package/src/tools/__tests__/hitl.test.ts +234 -5
  184. package/src/tools/__tests__/subagentHooks.test.ts +1040 -62
  185. package/src/tools/__tests__/toolOutputReferences.test.ts +19 -2
  186. package/src/tools/subagent/SubagentExecutor.ts +1438 -136
  187. package/src/tools/subagent/SubagentReplay.ts +575 -0
  188. package/src/tools/toolOutputReferences.ts +40 -1
  189. package/src/types/graph.ts +5 -5
  190. package/src/types/hitl.ts +16 -0
  191. package/src/types/llm.ts +53 -36
  192. package/src/utils/tokens.ts +115 -30
@@ -9,6 +9,7 @@ import type { InjectedMessage } from '@/types/tools';
9
9
  * `@librechat/agents` emission points.
10
10
  */
11
11
  export declare const HOOK_EVENTS: readonly ["RunStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "PostToolUseFailure", "PostToolBatch", "PreemptBoundary", "PermissionDenied", "SubagentStart", "SubagentStop", "Stop", "StopFailure", "PreCompact", "PostCompact"];
12
+ export declare const TOOL_APPROVAL_EXECUTION_SCOPE_CONFIG_KEY = "__librechat_tool_approval_execution_scope";
12
13
  export type HookEvent = (typeof HOOK_EVENTS)[number];
13
14
  /** Tool-gating decision; executeHooks folds with `deny > ask > allow` precedence. */
14
15
  export type ToolDecision = 'allow' | 'deny' | 'ask';
@@ -331,6 +332,17 @@ export interface PreToolUseHookOutput extends BaseHookOutput {
331
332
  */
332
333
  allowedDecisions?: ReadonlyArray<'approve' | 'reject' | 'edit' | 'respond'>;
333
334
  }
335
+ /** Stable identity for replaying a consumed one-shot tool approval. */
336
+ export interface ToolApprovalReplayKey {
337
+ executionScope: string;
338
+ agentId: string;
339
+ toolUseId: string;
340
+ }
341
+ /** Checkpoint-safe copy of a consumed one-shot approval contribution. */
342
+ export interface ToolApprovalReplaySnapshot {
343
+ key: ToolApprovalReplayKey;
344
+ result: AggregatedHookResult;
345
+ }
334
346
  export interface PostToolUseHookOutput extends BaseHookOutput {
335
347
  /**
336
348
  * Replacement tool output. Flows through the aggregated result so the
@@ -42,6 +42,9 @@ export { CustomOpenAIClient } from './llm/openai';
42
42
  export { ChatOpenRouter } from './llm/openrouter';
43
43
  export type { OpenRouterReasoning, OpenRouterReasoningEffort, ChatOpenRouterCallOptions, } from './llm/openrouter';
44
44
  export { getChatModelClass } from './llm/providers';
45
+ export { CustomChatMistralAI } from './llm/mistral';
46
+ export { smoothStream, resolveStreamDelay, DEFAULT_STREAM_DELAY, computeAdaptivePieceSize, } from './llm/stream/smoother';
47
+ export type { SmoothItem, SmoothPiece } from './llm/stream/smoother';
45
48
  export { FakeChatModel, createFakeStreamingLLM } from './llm/fake';
46
49
  export { initializeModel } from './llm/init';
47
50
  export { attemptInvoke, tryFallbackProviders } from './llm/invoke';
@@ -5,6 +5,7 @@ import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager
5
5
  import type { BaseMessage } from '@langchain/core/messages';
6
6
  import type { GoogleClientOptions, GoogleThinkingConfig } from '@/types';
7
7
  export declare class CustomChatGoogleGenerativeAI extends ChatGoogleGenerativeAI {
8
+ _lc_stream_delay: number;
8
9
  thinkingConfig?: GoogleThinkingConfig;
9
10
  includeServerSideToolInvocations?: boolean;
10
11
  /**
@@ -21,4 +22,5 @@ export declare class CustomChatGoogleGenerativeAI extends ChatGoogleGenerativeAI
21
22
  invocationParams(options?: this['ParsedCallOptions']): Omit<GenerateContentRequest, 'contents'>;
22
23
  _generate(messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): Promise<import('@langchain/core/outputs').ChatResult>;
23
24
  _streamResponseChunks(messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
25
+ private _streamProviderChunks;
24
26
  }
@@ -0,0 +1,11 @@
1
+ import { ChatMistralAI } from '@langchain/mistralai';
2
+ import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
3
+ import type { ChatGenerationChunk } from '@langchain/core/outputs';
4
+ import type { BaseMessage } from '@langchain/core/messages';
5
+ import type { MistralAIClientOptions } from '@/types';
6
+ export declare class CustomChatMistralAI extends ChatMistralAI {
7
+ _lc_stream_delay: number;
8
+ static lc_name(): 'LibreChatMistralAI';
9
+ constructor(fields?: MistralAIClientOptions);
10
+ _streamResponseChunks(messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
11
+ }
@@ -10,6 +10,7 @@ import type { BindToolsInput } from '@langchain/core/language_models/chat_models
10
10
  import type { ChatResult } from '@langchain/core/outputs';
11
11
  import type { ChatXAIInput } from '@langchain/xai';
12
12
  import type * as t from '@langchain/openai';
13
+ import type { SmoothItem } from '@/llm/stream/smoother';
13
14
  import type { HeaderValue, HeadersLike } from './types';
14
15
  import type { PromptCacheTtl } from '@/messages/cache';
15
16
  export declare function isHeaders(headers: unknown): headers is Headers;
@@ -44,6 +45,21 @@ export declare function shouldIncludeEncryptedReasoning(model: string, params: {
44
45
  export declare function getCacheWriteTokens(message: BaseMessage): number | undefined;
45
46
  export declare function attachCacheWriteUsage(message: BaseMessage): void;
46
47
  export declare function attachCacheWriteMetadata(response: OpenAIClient.Responses.Response): OpenAIClient.Responses.Response;
48
+ /**
49
+ * Classifies a generation chunk for the smoothing engine:
50
+ * - splittable: plain visible text (string content equal to `chunk.text`, no
51
+ * logprobs / finish_reason) — sliced adaptively at the pacing cadence.
52
+ * ANY logprobs value blocks splitting here (this family only attaches
53
+ * logprobs on request; the DeepSeek suite pins chunks with them staying
54
+ * intact) — deliberately stricter than `stream/chunkAdapters.ts`, where
55
+ * google-common's always-present empty logprobs must not block.
56
+ * - atomic: text- or reasoning-bearing chunks whose metadata cannot survive
57
+ * slicing — paced as one piece, never split (legacy parity: these were
58
+ * emitted whole but still paced).
59
+ * - passthrough: tool-call deltas, usage-only, finish_reason and other
60
+ * metadata chunks — strict FIFO, zero delay.
61
+ */
62
+ export declare function toSmoothItem(chunk: ChatGenerationChunk): SmoothItem<ChatGenerationChunk>;
47
63
  export declare function emitStreamChunkCallback(chunk: ChatGenerationChunk, runManager?: CallbackManagerForLLMRun): Promise<void>;
48
64
  export declare function _convertToOpenAITool(tool: BindToolsInput, fields?: {
49
65
  /**
@@ -61,7 +77,7 @@ export declare class CustomAzureOpenAIClient extends AzureOpenAIClient {
61
77
  fetchWithTimeout(url: RequestInfo, init: RequestInit | undefined, ms: number, controller: AbortController): Promise<Response>;
62
78
  }
63
79
  export declare class ChatOpenAI extends OriginalChatOpenAI<t.ChatOpenAICallOptions> {
64
- _lc_stream_delay?: number;
80
+ _lc_stream_delay: number;
65
81
  constructor(fields?: LibreChatOpenAIFields & t.OpenAIChatInput['modelKwargs']);
66
82
  get exposedClient(): CustomOpenAIClient;
67
83
  static lc_name(): string;
@@ -81,7 +97,7 @@ export declare class ChatOpenAI extends OriginalChatOpenAI<t.ChatOpenAICallOptio
81
97
  protected _streamRawResponseChunks(messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
82
98
  }
83
99
  export declare class AzureChatOpenAI extends OriginalAzureChatOpenAI {
84
- _lc_stream_delay?: number;
100
+ _lc_stream_delay: number;
85
101
  constructor(fields?: LibreChatAzureOpenAIFields);
86
102
  get exposedClient(): CustomOpenAIClient;
87
103
  static lc_name(): 'LibreChatAzureOpenAI';
@@ -95,7 +111,7 @@ export declare class AzureChatOpenAI extends OriginalAzureChatOpenAI {
95
111
  _streamResponseChunks(messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
96
112
  }
97
113
  export declare class ChatDeepSeek extends OriginalChatDeepSeek {
98
- _lc_stream_delay?: number;
114
+ _lc_stream_delay: number;
99
115
  constructor(fields?: ConstructorParameters<typeof OriginalChatDeepSeek>[0] & {
100
116
  _lc_stream_delay?: number;
101
117
  });
@@ -139,7 +155,7 @@ export declare class ChatMoonshot extends ChatOpenAI {
139
155
  static lc_name(): 'LibreChatMoonshot';
140
156
  }
141
157
  export declare class ChatXAI extends OriginalChatXAI {
142
- _lc_stream_delay?: number;
158
+ _lc_stream_delay: number;
143
159
  constructor(fields?: Partial<ChatXAIInput> & {
144
160
  configuration?: {
145
161
  baseURL?: string;
@@ -26,7 +26,10 @@ export interface ChatOpenRouterCallOptions extends Omit<ChatOpenAICallOptions, '
26
26
  */
27
27
  promptCacheTtl?: PromptCacheTtl;
28
28
  }
29
- export type ChatOpenRouterInput = Partial<ChatOpenRouterCallOptions & OpenAIChatInput>;
29
+ export type ChatOpenRouterInput = Partial<ChatOpenRouterCallOptions & OpenAIChatInput> & {
30
+ /** Minimum delay in ms between visible streamed deltas (default 25; 0 disables). */
31
+ _lc_stream_delay?: number;
32
+ };
30
33
  /** invocationParams return type extended with OpenRouter reasoning */
31
34
  export type OpenRouterInvocationParams = Omit<OpenAIClient.Chat.ChatCompletionCreateParams, 'messages'> & {
32
35
  reasoning?: OpenRouterReasoning;
@@ -0,0 +1,48 @@
1
+ import { AIMessageChunk } from '@langchain/core/messages';
2
+ import { ChatGenerationChunk } from '@langchain/core/outputs';
3
+ import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
4
+ import type { SmoothItem, SmoothPiece } from '@/llm/stream/smoother';
5
+ /**
6
+ * Rebuilds a generation chunk carrying one piece of a split plain-text chunk.
7
+ * Unsplit pieces return the original chunk untouched, so disabled smoothing is
8
+ * byte-identical to no smoothing. Usage metadata, additional kwargs and
9
+ * response metadata survive only on the first piece: the aggregator merges
10
+ * dicts by concatenating string fields, so replicating them across pieces
11
+ * would duplicate reasoning text and scalar metadata once per piece.
12
+ */
13
+ export declare function cloneGenerationChunkPiece(chunk: ChatGenerationChunk, piece: SmoothPiece): ChatGenerationChunk;
14
+ /**
15
+ * Chunks that pair visible text with reasoning payloads in
16
+ * `additional_kwargs` (Gemini thought summaries, reasoning_content deltas,
17
+ * OpenRouter reasoning_details) must pace whole: split pieces would each
18
+ * carry the same kwargs and downstream merging — the aggregator's dict merge
19
+ * or OpenRouter's reasoning_details accumulation — duplicates them once per
20
+ * piece.
21
+ */
22
+ /**
23
+ * Mixed text/tool-call deltas must never split: cloned pieces would each
24
+ * carry the same tool_call_chunks and downstream accumulation would corrupt
25
+ * the assembled tool arguments.
26
+ */
27
+ export declare function hasToolCallChunks(message: AIMessageChunk): boolean;
28
+ export declare function hasReasoningKwargs(message: AIMessageChunk): boolean;
29
+ /**
30
+ * Extracts the visible reasoning text a kwargs-borne delta contributes, so
31
+ * reasoning-only chunks (Gemini thoughts, DeepSeek reasoning_content,
32
+ * OpenAI reasoning summaries, OpenRouter reasoning_details) pace atomically
33
+ * at the cadence instead of passing through unsmoothed.
34
+ */
35
+ export declare function getReasoningKwargsText(message: AIMessageChunk): string;
36
+ export declare function toGenerationSmoothItem(chunk: ChatGenerationChunk, getAtomicText?: (message: AIMessageChunk) => string): SmoothItem<ChatGenerationChunk>;
37
+ /**
38
+ * Wraps a provider's raw chunk stream with adaptive smoothing and per-piece
39
+ * `handleLLMNewToken` dispatch. The raw stream must NOT dispatch runManager
40
+ * callbacks itself — callback-echo consumers would otherwise observe the
41
+ * unsmoothed deltas.
42
+ */
43
+ export declare function smoothGenerationChunks({ chunks, delayMs, signal, runManager, }: {
44
+ chunks: AsyncGenerator<ChatGenerationChunk>;
45
+ delayMs: number;
46
+ signal?: AbortSignal;
47
+ runManager?: CallbackManagerForLLMRun;
48
+ }): AsyncGenerator<ChatGenerationChunk>;
@@ -0,0 +1,95 @@
1
+ export declare const DEFAULT_STREAM_DELAY = 25;
2
+ export declare const SMOOTH_TARGET_LATENCY_MS = 250;
3
+ export declare const MAX_STREAM_QUEUE_CHUNKS = 256;
4
+ export declare const MAX_STREAM_QUEUE_TEXT_CHARS = 8192;
5
+ export declare const MAX_SMOOTH_ITEM_SEGMENT_CHARS = 4096;
6
+ export declare const STREAM_CHUNK_MIN_SIZE = 4;
7
+ export declare const STREAM_BOUNDARIES: ReadonlySet<string>;
8
+ export declare const STREAM_ABORT_MESSAGE = "AbortError: User aborted the request.";
9
+ export declare const STREAM_PRODUCER_FAILURE = "Stream producer failed.";
10
+ /**
11
+ * How long generator teardown waits for the background producer to observe a
12
+ * consumer close before abandoning it. Well-behaved streams settle in
13
+ * microseconds (the next enqueue throws); a stalled provider that ignores
14
+ * aborts otherwise blocks teardown — and abort propagation — indefinitely.
15
+ * An abandoned producer still self-terminates on its next enqueue attempt.
16
+ */
17
+ export declare const PRODUCER_CLOSE_GRACE_MS = 1000;
18
+ /**
19
+ * Resolves a configured stream delay to its effective value (default 25ms;
20
+ * 0 disables smoothing). Non-finite inputs (NaN from a malformed config
21
+ * value, ±Infinity) normalize to the default rather than poisoning piece
22
+ * arithmetic downstream.
23
+ */
24
+ export declare function resolveStreamDelay(delay?: number): number;
25
+ export declare function isSignalAborted(signal?: AbortSignal): boolean;
26
+ /**
27
+ * How far past the target size the word-boundary search may extend before
28
+ * hard-cutting. Natural language hits a boundary within a few characters;
29
+ * boundary-free runs (base64, minified data, long identifiers) must not
30
+ * stretch a piece — or an admission segment — arbitrarily far past its
31
+ * budget.
32
+ */
33
+ export declare const STREAM_BOUNDARY_LOOKAHEAD_CHARS = 64;
34
+ export declare function findStreamChunkBoundary(text: string, minSize: number): number;
35
+ /**
36
+ * Backlog-proportional piece sizing: emit enough per tick that the current
37
+ * backlog drains in ~`targetLatencyMs`, so render lag stays pinned near the
38
+ * target regardless of how fast the provider streams. Token-sized arrivals
39
+ * never exceed the minimum piece, matching the legacy fixed-size splitter.
40
+ */
41
+ export declare function computeAdaptivePieceSize(bufferedTextLength: number, tickMs: number, targetLatencyMs?: number): number;
42
+ /**
43
+ * A cadence, not an additive sleep: time the consumer already spent since the
44
+ * last visible emission counts against the target delay, so slow downstream
45
+ * handlers never compound latency.
46
+ */
47
+ export declare function getCadencedStreamDelay({ targetDelay, lastVisibleTextAt, now, }: {
48
+ targetDelay: number;
49
+ lastVisibleTextAt?: number;
50
+ now: number;
51
+ }): number;
52
+ /** Abort-aware sleep that resolves (never rejects) on abort; callers re-check the signal. */
53
+ export declare function waitForStreamDelay(delay: number, signal?: AbortSignal): Promise<void>;
54
+ export type SmoothPiece = {
55
+ text: string;
56
+ isFirst: boolean;
57
+ isLast: boolean;
58
+ };
59
+ /**
60
+ * One classified unit of provider stream output.
61
+ *
62
+ * - `smooth: true` — visible text, paced at the configured cadence and (unless
63
+ * `atomic`) sliced adaptively at dequeue time.
64
+ * - `atomic: true` — paced as a single piece, never split (text-bearing chunks
65
+ * whose metadata cannot survive slicing, e.g. logprobs / finish_reason).
66
+ * - `smooth: false` — passthrough: tool-call deltas, usage-only, id-only and
67
+ * seal chunks. Zero delay, strict FIFO with the text around them.
68
+ *
69
+ * `emit` builds the provider-specific output for one piece; `isFirst` lets
70
+ * providers keep usage_metadata on only the first piece of a split.
71
+ */
72
+ export type SmoothItem<TEmit> = {
73
+ text: string;
74
+ smooth: boolean;
75
+ atomic?: boolean;
76
+ emit: (piece: SmoothPiece) => TEmit;
77
+ };
78
+ /**
79
+ * Bounded producer/consumer smoothing engine.
80
+ *
81
+ * The producer drains `source` eagerly into a bounded queue (the buffer is the
82
+ * backlog measurement adaptive sizing needs); at capacity it parks, applying
83
+ * backpressure to the underlying stream. The consumer emits paced pieces,
84
+ * decrementing the text budget and waking the producer *before* each cadenced
85
+ * sleep so the provider stream keeps being read during pacing.
86
+ *
87
+ * `delayMs <= 0` disables smoothing entirely: every item passes through FIFO,
88
+ * unsplit and undelayed.
89
+ */
90
+ export declare function smoothStream<TEmit>({ source, delayMs, signal, abortUpstream, }: {
91
+ source: AsyncIterable<SmoothItem<TEmit>>;
92
+ delayMs: number;
93
+ signal?: AbortSignal;
94
+ abortUpstream?: () => void;
95
+ }): AsyncGenerator<TEmit>;
@@ -340,6 +340,7 @@ export declare function fixThoughtSignatures(contents: GeminiContent[], input: B
340
340
  */
341
341
  export declare class ChatVertexAI extends ChatGoogle {
342
342
  lc_namespace: string[];
343
+ _lc_stream_delay: number;
343
344
  dynamicThinkingBudget: boolean;
344
345
  thinkingConfig?: GoogleThinkingConfig;
345
346
  static lc_name(): 'LibreChatVertexAI';
@@ -347,5 +348,6 @@ export declare class ChatVertexAI extends ChatGoogle {
347
348
  constructor(fields?: VertexAIClientOptions);
348
349
  invocationParams(options?: this['ParsedCallOptions'] | undefined): GoogleAIModelRequestParams;
349
350
  _streamResponseChunks(messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
351
+ private _streamRepairedChunks;
350
352
  buildConnection(fields: VertexAIClientOptions | undefined, client: GoogleAbstractedClient): void;
351
353
  }
@@ -1,5 +1,6 @@
1
+ import { BaseMessage } from '@langchain/core/messages';
1
2
  import { Command } from '@langchain/langgraph';
2
- import type { MessageContentComplex, BaseMessage } from '@langchain/core/messages';
3
+ import type { MessageContentComplex } from '@langchain/core/messages';
3
4
  import type * as t from '@/types';
4
5
  import { MultiAgentGraph } from '@/graphs/MultiAgentGraph';
5
6
  import { StandardGraph } from '@/graphs/Graph';
@@ -103,6 +104,7 @@ export declare class Run<_T extends t.BaseGraphState> {
103
104
  private runPreStreamHooks;
104
105
  static create<T extends t.BaseGraphState>(config: t.RunConfig): Promise<Run<T>>;
105
106
  getRunMessages(): BaseMessage[] | undefined;
107
+ getChildCheckpointThreadIds(): string[];
106
108
  /**
107
109
  * Returns a defensive snapshot of tools discovered by the current run.
108
110
  * Pass an agent id for that context, or omit it for the ordered union across
@@ -220,6 +222,7 @@ export declare class Run<_T extends t.BaseGraphState> {
220
222
  */
221
223
  resume<TResume = t.ToolApprovalDecision[] | t.ToolApprovalDecisionMap>(resumeValue: TResume, callerConfig: t.RunStreamConfig, streamOptions?: t.EventStreamOptions, commandOptions?: Pick<ConstructorParameters<typeof Command>[0], 'update' | 'goto'>): Promise<MessageContentComplex[] | undefined>;
222
224
  private resolveInterruptResumeConfig;
225
+ private restoreInterruptFromCheckpoint;
223
226
  private createSystemCallback;
224
227
  getCallbacks(clientCallbacks: t.ClientCallbacks): t.SystemCallbacks;
225
228
  generateTitle({ provider, inputText, contentParts, titlePrompt, clientOptions, chainOptions, skipLanguage, titleMethod, titlePromptTemplate, }: t.RunTitleOptions): Promise<{
@@ -16,6 +16,7 @@ export declare class AgentSession {
16
16
  getLatestCheckpoint(options?: AgentSessionCheckpointLookupOptions): Promise<AgentSessionCheckpointReference | undefined>;
17
17
  private hasCheckpointState;
18
18
  private recordCheckpoint;
19
+ private recordChildCheckpointThreads;
19
20
  private getCheckpointThreadIds;
20
21
  private resetCheckpointThreads;
21
22
  private runInternal;
@@ -3,6 +3,7 @@ import { END, Command, MessagesAnnotation } from '@langchain/langgraph';
3
3
  import type { RunnableConfig } from '@langchain/core/runnables';
4
4
  import type { BaseMessage } from '@langchain/core/messages';
5
5
  import type { ToolOutputResolveView, ResolvedArgsByCallId } from '@/tools/toolOutputReferences';
6
+ import type { SubagentToolNodeResumeState } from '@/tools/subagent/SubagentReplay';
6
7
  import type * as t from '@/types';
7
8
  import { ToolOutputReferenceRegistry } from '@/tools/toolOutputReferences';
8
9
  import { RunnableCallable } from '@/utils';
@@ -50,6 +51,8 @@ type RunToolBatchContext<T = unknown> = {
50
51
  * contract for hosts relying on it for policy / recovery guidance.
51
52
  */
52
53
  additionalContextsSink?: string[];
54
+ /** Stable identity of the assistant tool-call batch across HITL replay. */
55
+ replayBatchKey?: string;
53
56
  /**
54
57
  * Graph state the ToolNode was invoked with, threaded from `run()`
55
58
  * so `tool.invoke` can forward it as langgraph 1.4's `runtime.state`
@@ -113,6 +116,10 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
113
116
  * the Run ends.
114
117
  */
115
118
  private directPathTurns;
119
+ /** Terminal results from interrupting siblings that must survive a
120
+ * LangGraph replay of the containing ToolNode. Includes the sidecar data
121
+ * the fresh batch needs for hook-context injection and completion events. */
122
+ private settledInterruptingResults;
116
123
  /** Tool registry for filtering (lazy computation of programmatic maps) */
117
124
  private toolRegistry?;
118
125
  /** Cached programmatic tools (computed once on first PTC call) */
@@ -240,12 +247,11 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
240
247
  private shouldHandleUnknownHandoffLocally;
241
248
  private getUnknownToolErrorMessage;
242
249
  /**
243
- * Flush the per-Run direct-path turn cache. Called by the Graph at
244
- * end-of-Run via `clearHeavyState`. The map intentionally survives
245
- * `run()` re-entry so an interrupt + resume reuses the original
246
- * slot (Codex P2 #30), but it would otherwise grow linearly with
247
- * tool calls and could collide across Runs if a provider reused
248
- * call IDs (Codex P2 #33). Hosts can also call this directly if
250
+ * Flush per-Run direct replay state. Called by the Graph at end-of-Run via
251
+ * `clearHeavyState`. The state intentionally survives `run()` re-entry so
252
+ * interrupt + resume keeps both original turn slots and terminal sibling
253
+ * outputs, but it would otherwise grow linearly and could collide across
254
+ * Runs if a provider reused call IDs. Hosts can also call this directly if
249
255
  * they reuse a ToolNode across batches outside of a Graph.
250
256
  */
251
257
  clearDirectPathTurns(): void;
@@ -259,6 +265,8 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
259
265
  * @returns A ReadonlyMap where keys are tool names and values are their usage counts.
260
266
  */
261
267
  getToolUsageCounts(): ReadonlyMap<string, number>;
268
+ createSubagentResumeState(): SubagentToolNodeResumeState;
269
+ restoreSubagentResumeState(state: SubagentToolNodeResumeState): void;
262
270
  private recordToolUsageTurn;
263
271
  private recordEventToolPlanningTurn;
264
272
  /**
@@ -296,9 +304,9 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
296
304
  * `blockDirectCall`, `respond` returns the host-supplied
297
305
  * `responseText` as a synthetic success ToolMessage,
298
306
  * `edit` re-runs with edited args. LangGraph re-enters
299
- * ToolNode.run from the start on resume; the hook fires
300
- * again and the resume value distinguishes "first ask" from
301
- * "second pass with decision".
307
+ * ToolNode.run from the start on resume. Reusable hooks fire
308
+ * again; a consumed one-shot hook replays its pending approval
309
+ * result. In both cases `interrupt()` consumes the resume value.
302
310
  * • When HITL is off: collapses to a fail-closed deny (matches
303
311
  * the rest of the SDK's HITL-disabled default). One-time
304
312
  * warning logged so hosts notice the gap.
@@ -465,16 +473,16 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
465
473
  * call throws a `GraphInterrupt`, the `await` below rejects and unwinds the
466
474
  * whole ToolNode *before* any non-interrupting sibling has started — so a
467
475
  * sibling with real side effects (send_email, billing) never executes on
468
- * the first pass. On the resume pass LangGraph re-runs the batch from the
469
- * top; the interrupting tool resolves with the host's answer instead of
470
- * throwing, and the siblings execute for the FIRST time, exactly once.
476
+ * the first pass. Terminal interrupting siblings are cached by call id, so
477
+ * LangGraph replay reuses their complete lifecycle output instead of
478
+ * repeating model calls, hooks, or side effects.
471
479
  *
472
480
  * Without this ordering, a flat `Promise.all` starts every sibling
473
481
  * concurrently, so a non-idempotent sibling can complete its side effect
474
482
  * before the interrupt unwinds and then run a SECOND time on resume — the
475
- * duplicate side effect this method exists to prevent. Interrupting tools
476
- * are expected to be side-effect-free (they only suspend), so running them
477
- * as a group and re-running them on resume is harmless.
483
+ * duplicate side effect this method exists to prevent. A tool that actually
484
+ * suspends re-enters until it reaches a terminal result; siblings that
485
+ * already settled do not re-enter.
478
486
  *
479
487
  * `batchIndices[i]` is `directCalls[i]`'s position within the parent
480
488
  * ToolNode batch (used for `{{tool<i>turn<n>}}` registration); it is
@@ -1,5 +1,8 @@
1
- import type { BaseMessage } from '@langchain/core/messages';
2
- import type { AgentInputs, StandardGraphInput, ResolvedSubagentConfig, SubagentConfig, SubagentUsageSink, TokenCounter } from '@/types';
1
+ import { BaseMessage } from '@langchain/core/messages';
2
+ import type { RunnableConfig } from '@langchain/core/runnables';
3
+ import type { ToolCall } from '@langchain/core/messages/tool';
4
+ import type { AgentInputs, HumanInTheLoopConfig, StandardGraphInput, ResolvedSubagentConfig, SubagentConfig, SubagentUsageSink, TokenCounter } from '@/types';
5
+ import type { SubagentResumeManifest, SettledSubagentToolOutput } from './SubagentReplay';
3
6
  import type { HookRegistry } from '@/hooks';
4
7
  import type { AgentContext } from '@/agents/AgentContext';
5
8
  import type { StandardGraph } from '@/graphs/Graph';
@@ -34,11 +37,12 @@ export type SubagentExecuteParams = {
34
37
  *
35
38
  * Inheritance details (verified empirically against LangGraph):
36
39
  * - host-set keys propagate as-is into the child's tool dispatches;
37
- * - `thread_id` propagates (with `childRunId` as a fallback when
38
- * parent did not supply one) — matches the "subagent is part of
39
- * the same conversation" mental model and aligns with the
40
- * `sessionId: this.parentRunId` convention this executor already
41
- * uses for `SubagentStart` / `SubagentStop` hooks;
40
+ * - with nested HITL enabled, `thread_id` is replaced with a stable
41
+ * child checkpoint id derived from the parent's durable thread id,
42
+ * checkpoint fork, parent agent id, and spawning tool call id so parent
43
+ * and child checkpoints cannot collide, sibling parent forks stay
44
+ * isolated, and reconstruction returns to the same child checkpoint;
45
+ * parent-scoped hook lookup remains keyed by the inherited `run_id`;
42
46
  * - `parent_run_id` propagates when the host put it on parent's
43
47
  * configurable;
44
48
  * - `run_id` is *overwritten by the LangGraph runtime* at child
@@ -95,6 +99,11 @@ export type SubagentExecutorOptions = {
95
99
  * revert to the defaults.
96
100
  */
97
101
  streamLimits?: StandardGraphInput['streamLimits'];
102
+ humanInTheLoop?: HumanInTheLoopConfig;
103
+ /** Shared durable saver used to recover outer tool lifecycle results before
104
+ * parent hooks re-enter after a process rebuild. Narrowed structurally at
105
+ * construction because graph compile options also permit framework flags. */
106
+ checkpointer?: unknown;
98
107
  /** Remaining nesting budget. 0 or negative blocks execution. */
99
108
  maxDepth?: number;
100
109
  /**
@@ -143,9 +152,18 @@ export declare class SubagentExecutor {
143
152
  private readonly langfuse?;
144
153
  private readonly tokenCounter?;
145
154
  private readonly streamLimits?;
155
+ private readonly humanInTheLoop?;
156
+ private readonly checkpointer?;
146
157
  private readonly maxDepth;
147
158
  private readonly createChildGraph;
148
159
  private readonly usageSink?;
160
+ private readonly checkpointThreadIds;
161
+ private readonly startedChildRuns;
162
+ private readonly completedChildRuns;
163
+ private readonly completedChildResults;
164
+ private readonly childExecutionIdentities;
165
+ private readonly activeChildRuns;
166
+ private replayCheckpointWorkflow?;
149
167
  private readonly resolveParentHandlerRegistry?;
150
168
  constructor(options: SubagentExecutorOptions);
151
169
  /** The breaker controller current for this execution — read per spawn
@@ -157,6 +175,27 @@ export declare class SubagentExecutor {
157
175
  private composeChildSignal;
158
176
  /** Snapshot of the parent's registry at the moment a subagent is dispatched. */
159
177
  private getParentHandlerRegistry;
178
+ /**
179
+ * Keeps the original child thread as an immutable resume source once a
180
+ * different parent Run reconstructs it. Each rebuilt parent gets a private
181
+ * checkpoint fork, while the persisted child run ID remains stable for
182
+ * activity and usage correlation across the interrupt boundary.
183
+ */
184
+ private resolveChildExecutionIdentity;
185
+ /** Captures one exact checkpoint head per namespace for a child thread. */
186
+ private getLatestCheckpointSnapshot;
187
+ /** Copies exact checkpoint lineages, including pending task writes. */
188
+ private forkCheckpointSnapshot;
189
+ private createResumeManifest;
190
+ getResumeManifest(parentToolCallIds?: ReadonlySet<string>): Promise<SubagentResumeManifest | undefined>;
191
+ getChildCheckpointThreadIds(): string[];
192
+ resetCheckpointThreadIds(): void;
193
+ private getGraphChildCheckpointThreadIds;
194
+ private clearChildGraph;
195
+ clearHeavyState(): void;
196
+ getSettledToolOutput(call: ToolCall, config: RunnableConfig): Promise<SettledSubagentToolOutput | undefined>;
197
+ persistSettledToolOutput(call: ToolCall, config: RunnableConfig, settled: SettledSubagentToolOutput): Promise<void>;
198
+ private persistChildCheckpointMarker;
160
199
  execute(params: SubagentExecuteParams): Promise<SubagentExecuteResult>;
161
200
  /**
162
201
  * Emits a single {@link GraphEvents.ON_SUBAGENT_UPDATE} envelope through the
@@ -192,6 +231,9 @@ export declare function summarizeEvent(eventName: string, data: unknown): string
192
231
  * pure tool_use (e.g. the subagent hit `maxTurns` mid-tool-call), the walk
193
232
  * continues to earlier AIMessages so partial progress is salvaged — this
194
233
  * matches Claude Code's behavior in `agentToolUtils.finalizeAgentTool`.
234
+ * Consecutive streamed text-delta blocks with the same provider index are
235
+ * coalesced without adding whitespace. Annotation-only text blocks are
236
+ * ignored; complete text blocks and distinct delta indexes remain separated.
195
237
  * Returns "Task completed" only when no AIMessage in the history contains
196
238
  * any text.
197
239
  */
@@ -0,0 +1,81 @@
1
+ import type { ToolCall, ToolMessage } from '@langchain/core/messages/tool';
2
+ import type { RunnableConfig } from '@langchain/core/runnables';
3
+ import type { ToolOutputReferenceState } from '@/tools/toolOutputReferences';
4
+ import type { ToolApprovalReplaySnapshot } from '@/hooks';
5
+ import type { ToolSessionContext } from '@/types';
6
+ export declare const SUBAGENT_RESUME_MANIFEST_CONFIG_KEY = "__librechat_subagent_resume_manifest";
7
+ export declare const SUBAGENT_RESUME_ATTEMPT_CONFIG_KEY = "__librechat_subagent_resume_attempt";
8
+ export declare const SUBAGENT_PARENT_BATCH_CONFIG_KEY = "__librechat_subagent_parent_batch";
9
+ export interface SubagentCheckpointReference {
10
+ threadId: string;
11
+ checkpointId: string;
12
+ checkpointNs: string;
13
+ }
14
+ export interface SubagentToolCallStepReference {
15
+ toolCallId: string;
16
+ stepId: string;
17
+ }
18
+ export interface SubagentToolSessionReference {
19
+ toolName: string;
20
+ context: ToolSessionContext;
21
+ }
22
+ export interface SubagentToolNodeResumeState {
23
+ stateKey: string;
24
+ toolUsageCounts: Array<{
25
+ toolName: string;
26
+ count: number;
27
+ }>;
28
+ directPathTurns: Array<{
29
+ toolCallId: string;
30
+ turn: number;
31
+ }>;
32
+ }
33
+ export interface SubagentEagerToolUsageState {
34
+ agentId: string;
35
+ toolUsageCounts: Array<{
36
+ toolName: string;
37
+ count: number;
38
+ }>;
39
+ }
40
+ export interface SubagentGraphResumeState {
41
+ toolCallSteps: SubagentToolCallStepReference[];
42
+ toolSessions: SubagentToolSessionReference[];
43
+ toolNodes: SubagentToolNodeResumeState[];
44
+ eagerToolUsage: SubagentEagerToolUsageState[];
45
+ eagerToolSuppressions: string[];
46
+ toolOutputReferences?: ToolOutputReferenceState;
47
+ }
48
+ /** Private checkpoint payload linking a parent pause to an exact child state. */
49
+ export interface SubagentResumeExecution {
50
+ parentToolCallId: string;
51
+ childRunId: string;
52
+ approvalExecutionScope: string;
53
+ checkpoints: SubagentCheckpointReference[];
54
+ graphState: SubagentGraphResumeState;
55
+ approvalReplays: ToolApprovalReplaySnapshot[];
56
+ descendant?: SubagentResumeManifest;
57
+ }
58
+ /** Private checkpoint payload linking a parent pause to every child state. */
59
+ export interface SubagentResumeManifest {
60
+ version: 1;
61
+ executions: SubagentResumeExecution[];
62
+ }
63
+ export declare function getSubagentResumeManifest(payload: unknown): SubagentResumeManifest | undefined;
64
+ export declare function requireValidSubagentResumeManifest(payload: unknown): SubagentResumeManifest | undefined;
65
+ export declare function attachSubagentResumeManifest(payload: unknown, manifest: SubagentResumeManifest): object;
66
+ export declare function stripSubagentResumeManifest(payload: unknown): unknown;
67
+ export declare const SUBAGENT_REPLAY_CONTROLLER: unique symbol;
68
+ export type SettledSubagentToolOutput = {
69
+ output: ToolMessage;
70
+ additionalContexts: string[];
71
+ resolvedArgs?: Record<string, unknown>;
72
+ referenceContent?: string;
73
+ };
74
+ export interface SubagentReplayController {
75
+ getResumeManifest?(parentToolCallIds?: ReadonlySet<string>): Promise<SubagentResumeManifest | undefined>;
76
+ getSettledOutput(call: ToolCall, config: RunnableConfig): Promise<SettledSubagentToolOutput | undefined>;
77
+ persistSettledOutput(call: ToolCall, config: RunnableConfig, settled: SettledSubagentToolOutput): Promise<void>;
78
+ }
79
+ export type ReplayableSubagentTool = {
80
+ [SUBAGENT_REPLAY_CONTROLLER]?: SubagentReplayController;
81
+ };
@@ -53,6 +53,14 @@ export type ToolOutputReferenceRegistryOptions = {
53
53
  */
54
54
  maxActiveRuns?: number;
55
55
  };
56
+ export interface ToolOutputReferenceState {
57
+ entries: Array<{
58
+ key: string;
59
+ value: string;
60
+ }>;
61
+ turnCounter: number;
62
+ warnedNonStringTools: string[];
63
+ }
56
64
  /**
57
65
  * Result of resolving placeholders in tool args.
58
66
  */
@@ -189,6 +197,10 @@ export declare class ToolOutputReferenceRegistry {
189
197
  * completed.
190
198
  */
191
199
  snapshot(runId: string | undefined): ToolOutputResolveView;
200
+ /** Captures the checkpoint-safe state needed to resume one run bucket. */
201
+ snapshotState(runId: string | undefined): ToolOutputReferenceState;
202
+ /** Restores a checkpointed run bucket under the current resume scope. */
203
+ restoreState(runId: string | undefined, state: ToolOutputReferenceState): void;
192
204
  private resolveAgainst;
193
205
  private transform;
194
206
  private replaceInString;