@librechat/agents 3.7.7 → 3.7.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/agents/AgentContext.cjs +26 -5
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/constants.cjs +12 -0
- package/dist/cjs/common/constants.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +56 -11
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +1 -1
- package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
- package/dist/cjs/hooks/executeHooks.cjs +8 -0
- package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
- package/dist/cjs/hooks/index.cjs +2 -0
- package/dist/cjs/hooks/index.cjs.map +1 -1
- package/dist/cjs/hooks/types.cjs +1 -0
- package/dist/cjs/hooks/types.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +43 -3
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/langfuseTraceShaping.cjs +75 -0
- package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/toolCache.cjs +1 -1
- package/dist/cjs/llm/fake.cjs +9 -5
- package/dist/cjs/llm/fake.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +3 -7
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/toolCache.cjs +1 -1
- package/dist/cjs/llm/prepareProviderRequest.cjs +2 -2
- package/dist/cjs/llm/providers.cjs +1 -1
- package/dist/cjs/llm/request.cjs +6 -0
- package/dist/cjs/llm/request.cjs.map +1 -1
- package/dist/cjs/llm/truncation.cjs +1 -0
- package/dist/cjs/main.cjs +22 -13
- package/dist/cjs/messages/format.cjs +375 -3
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/index.cjs +1 -1
- package/dist/cjs/messages/prune.cjs +1 -1
- package/dist/cjs/run.cjs +217 -52
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +1 -1
- package/dist/cjs/stream.cjs +1 -1
- package/dist/cjs/summarization/index.cjs +1 -0
- package/dist/cjs/summarization/index.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +58 -85
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/summarization/semanticIndex.cjs +366 -0
- package/dist/cjs/summarization/semanticIndex.cjs.map +1 -0
- package/dist/cjs/summarization/shared.cjs +83 -0
- package/dist/cjs/summarization/shared.cjs.map +1 -0
- package/dist/cjs/tools/ToolNode.cjs +5 -5
- package/dist/cjs/tools/local/CompileCheckTool.cjs +1 -1
- package/dist/cjs/tools/local/LocalCodingTools.cjs +1 -1
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs +1 -1
- package/dist/cjs/tools/runStepResume.cjs +1 -1
- package/dist/cjs/tools/runStepResume.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +8 -12
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/subagent/childGraphConfig.cjs +2 -1
- package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +1 -1
- package/dist/cjs/utils/tokens.cjs +8 -1
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +26 -5
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/constants.mjs +11 -1
- package/dist/esm/common/constants.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +56 -11
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +1 -1
- package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
- package/dist/esm/hooks/executeHooks.mjs +8 -1
- package/dist/esm/hooks/executeHooks.mjs.map +1 -1
- package/dist/esm/hooks/index.mjs +2 -1
- package/dist/esm/hooks/index.mjs.map +1 -1
- package/dist/esm/hooks/types.mjs +1 -0
- package/dist/esm/hooks/types.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +43 -3
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/langfuseTraceShaping.mjs +75 -0
- package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
- package/dist/esm/llm/bedrock/toolCache.mjs +1 -1
- package/dist/esm/llm/fake.mjs +9 -5
- package/dist/esm/llm/fake.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +3 -7
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openrouter/toolCache.mjs +1 -1
- package/dist/esm/llm/prepareProviderRequest.mjs +2 -2
- package/dist/esm/llm/providers.mjs +1 -1
- package/dist/esm/llm/request.mjs +6 -1
- package/dist/esm/llm/request.mjs.map +1 -1
- package/dist/esm/llm/truncation.mjs +1 -1
- package/dist/esm/main.mjs +15 -14
- package/dist/esm/messages/format.mjs +375 -3
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/index.mjs +1 -1
- package/dist/esm/messages/prune.mjs +1 -1
- package/dist/esm/run.mjs +217 -52
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +1 -1
- package/dist/esm/stream.mjs +1 -1
- package/dist/esm/summarization/index.mjs +1 -0
- package/dist/esm/summarization/index.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +57 -84
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/summarization/semanticIndex.mjs +363 -0
- package/dist/esm/summarization/semanticIndex.mjs.map +1 -0
- package/dist/esm/summarization/shared.mjs +79 -0
- package/dist/esm/summarization/shared.mjs.map +1 -0
- package/dist/esm/tools/ToolNode.mjs +5 -5
- package/dist/esm/tools/local/CompileCheckTool.mjs +1 -1
- package/dist/esm/tools/local/LocalCodingTools.mjs +1 -1
- package/dist/esm/tools/local/LocalExecutionEngine.mjs +1 -1
- package/dist/esm/tools/runStepResume.mjs +1 -1
- package/dist/esm/tools/runStepResume.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +8 -12
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/subagent/childGraphConfig.mjs +2 -1
- package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +1 -1
- package/dist/esm/utils/tokens.mjs +8 -2
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +27 -1
- package/dist/types/common/constants.d.ts +17 -0
- package/dist/types/graphs/Graph.d.ts +24 -0
- package/dist/types/hooks/executeHooks.d.ts +5 -2
- package/dist/types/hooks/index.d.ts +7 -2
- package/dist/types/hooks/types.d.ts +45 -7
- package/dist/types/langfuse.d.ts +3 -1
- package/dist/types/llm/fake.d.ts +12 -2
- package/dist/types/llm/request.d.ts +10 -0
- package/dist/types/messages/format.d.ts +17 -2
- package/dist/types/run.d.ts +19 -6
- package/dist/types/summarization/index.d.ts +6 -0
- package/dist/types/summarization/node.d.ts +0 -4
- package/dist/types/summarization/semanticIndex.d.ts +21 -0
- package/dist/types/summarization/shared.d.ts +25 -0
- package/dist/types/types/graph.d.ts +9 -1
- package/dist/types/types/run.d.ts +8 -0
- package/dist/types/types/stream.d.ts +6 -0
- package/dist/types/types/summarize.d.ts +44 -0
- package/dist/types/utils/tokens.d.ts +9 -0
- package/package.json +2 -1
- package/src/agents/AgentContext.ts +63 -6
- package/src/common/constants.ts +19 -0
- package/src/graphs/Graph.ts +86 -8
- package/src/hooks/HookRegistry.ts +3 -1
- package/src/hooks/executeHooks.ts +20 -2
- package/src/hooks/index.ts +12 -1
- package/src/hooks/types.ts +47 -4
- package/src/langfuse.ts +70 -0
- package/src/langfuseTraceShaping.ts +94 -0
- package/src/llm/fake.ts +35 -4
- package/src/llm/invoke.ts +13 -29
- package/src/llm/request.ts +24 -0
- package/src/messages/format.ts +839 -5
- package/src/run.ts +393 -187
- package/src/summarization/index.ts +11 -0
- package/src/summarization/node.ts +202 -158
- package/src/summarization/semanticIndex.ts +662 -0
- package/src/summarization/shared.ts +130 -0
- package/src/tools/runStepResume.ts +9 -0
- package/src/tools/subagent/SubagentExecutor.ts +4 -27
- package/src/tools/subagent/childGraphConfig.ts +3 -0
- package/src/types/graph.ts +9 -0
- package/src/types/run.ts +8 -0
- package/src/types/stream.ts +6 -0
- package/src/types/summarize.ts +57 -0
- package/src/utils/tokens.ts +31 -8
package/src/run.ts
CHANGED
|
@@ -3,27 +3,28 @@ import { nanoid } from 'nanoid';
|
|
|
3
3
|
import { PromptTemplate } from '@langchain/core/prompts';
|
|
4
4
|
import { RunnableLambda } from '@langchain/core/runnables';
|
|
5
5
|
import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
|
|
6
|
-
import {
|
|
7
|
-
Command,
|
|
8
|
-
INTERRUPT,
|
|
9
|
-
MemorySaver,
|
|
10
|
-
isInterrupted,
|
|
11
|
-
} from '@langchain/langgraph';
|
|
12
6
|
import {
|
|
13
7
|
AIMessage,
|
|
14
8
|
BaseMessage,
|
|
15
9
|
HumanMessage,
|
|
16
10
|
SystemMessage,
|
|
17
11
|
} from '@langchain/core/messages';
|
|
12
|
+
import {
|
|
13
|
+
Command,
|
|
14
|
+
INTERRUPT,
|
|
15
|
+
MemorySaver,
|
|
16
|
+
Overwrite,
|
|
17
|
+
isInterrupted,
|
|
18
|
+
} from '@langchain/langgraph';
|
|
18
19
|
import type {
|
|
19
20
|
MessageContentComplex,
|
|
20
21
|
UsageMetadata,
|
|
21
22
|
} from '@langchain/core/messages';
|
|
22
23
|
import type { StringPromptValue } from '@langchain/core/prompt_values';
|
|
23
24
|
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
25
|
+
import type { AggregatedHookResult, HookRegistry } from '@/hooks';
|
|
24
26
|
import type { MultiAgentGraph } from '@/graphs/MultiAgentGraph';
|
|
25
27
|
import type { StandardGraph } from '@/graphs/Graph';
|
|
26
|
-
import type { HookRegistry } from '@/hooks';
|
|
27
28
|
import type * as t from '@/types';
|
|
28
29
|
import {
|
|
29
30
|
Callback,
|
|
@@ -33,9 +34,9 @@ import {
|
|
|
33
34
|
REASONING_LABEL_RUN_NAME,
|
|
34
35
|
ACTIVITY_PHASE_RUN_NAME,
|
|
35
36
|
ACTIVITY_PHASE_LABEL_RUN_NAME,
|
|
37
|
+
DEFAULT_MAX_STOP_CONTINUATIONS,
|
|
36
38
|
DEFAULT_RECURSION_LIMIT,
|
|
37
39
|
} from '@/common';
|
|
38
|
-
import { isBuiltRuntime } from '@/lazyRequire';
|
|
39
40
|
import {
|
|
40
41
|
requireValidSubagentResumeManifest,
|
|
41
42
|
stripSubagentResumeManifest,
|
|
@@ -94,15 +95,18 @@ import { applyGraphRuntimeConfig } from '@/graphs/applyGraphRuntimeConfig';
|
|
|
94
95
|
import { LANGFUSE_OPERATION_METADATA_KEY } from '@/langfuseOperation';
|
|
95
96
|
import { createTokenCounter, encodingForModel } from '@/utils/tokens';
|
|
96
97
|
import { stampSyntheticProviderMessage } from '@/messages/provenance';
|
|
98
|
+
import { isOpenAILike, isLibreChatOpenAIModel } from '@/utils/llm';
|
|
99
|
+
import { executeHooks, mergeAggregatedHookResults } from '@/hooks';
|
|
100
|
+
import { convertInjectedMessages } from '@/messages/injected';
|
|
97
101
|
import { initializeLangfuseTracing } from './instrumentation';
|
|
98
102
|
import { seedRunInitialSessions } from '@/utils/toolSessions';
|
|
99
103
|
import { getTraceIdSeed } from '@/langfuseRuntimeContext';
|
|
104
|
+
import { resolveClientOptionsModel } from '@/llm/request';
|
|
100
105
|
import { createGraph } from '@/graphs/createGraph';
|
|
101
106
|
import { resolveMaxSeals } from '@/llm/preempt';
|
|
107
|
+
import { isBuiltRuntime } from '@/lazyRequire';
|
|
102
108
|
import { initializeModel } from '@/llm/init';
|
|
103
109
|
import { HandlerRegistry } from '@/events';
|
|
104
|
-
import { isOpenAILike, isLibreChatOpenAIModel } from '@/utils/llm';
|
|
105
|
-
import { executeHooks } from '@/hooks';
|
|
106
110
|
|
|
107
111
|
/** Source-mode runs have no dist siblings for the lazy-loading seam, so every
|
|
108
112
|
* lazily loadable module is imported through the active loader before the
|
|
@@ -130,6 +134,61 @@ export const defaultOmitOptions = new Set([
|
|
|
130
134
|
const ACTIVITY_LABEL_TRACE_NAME = 'LibreChat Activity Label';
|
|
131
135
|
const ACTIVITY_PHASE_TRACE_NAME = 'LibreChat Activity Phase';
|
|
132
136
|
const REASONING_LABEL_TRACE_NAME = 'LibreChat Reasoning Label';
|
|
137
|
+
const OUTPUT_TRUNCATED_HALT_REASON = 'output_truncated';
|
|
138
|
+
|
|
139
|
+
function resolveMaxStopContinuations(value: number | undefined): number {
|
|
140
|
+
if (value == null || !Number.isFinite(value)) {
|
|
141
|
+
return DEFAULT_MAX_STOP_CONTINUATIONS;
|
|
142
|
+
}
|
|
143
|
+
return Math.max(0, Math.floor(value));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function materializeStopContinuation(
|
|
147
|
+
result: AggregatedHookResult
|
|
148
|
+
): BaseMessage[] {
|
|
149
|
+
const messages: BaseMessage[] = [];
|
|
150
|
+
const contexts = result.additionalContexts.filter(
|
|
151
|
+
(context) => context.trim() !== ''
|
|
152
|
+
);
|
|
153
|
+
if (contexts.length > 0) {
|
|
154
|
+
messages.push(
|
|
155
|
+
stampSyntheticProviderMessage(
|
|
156
|
+
new HumanMessage({
|
|
157
|
+
content: contexts.join('\n\n'),
|
|
158
|
+
additional_kwargs: {
|
|
159
|
+
role: 'system',
|
|
160
|
+
isMeta: true,
|
|
161
|
+
source: 'hook',
|
|
162
|
+
},
|
|
163
|
+
})
|
|
164
|
+
)
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
messages.push(...convertInjectedMessages(result.injectedMessages));
|
|
168
|
+
return messages;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function advanceCheckpointCursor(
|
|
172
|
+
config: t.RunStreamConfig
|
|
173
|
+
): t.RunStreamConfig {
|
|
174
|
+
const configurable = { ...config.configurable };
|
|
175
|
+
delete configurable.checkpoint_id;
|
|
176
|
+
delete configurable.checkpoint_map;
|
|
177
|
+
return { ...config, configurable };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function assertFinalAdmissionSucceeded(result: AggregatedHookResult): void {
|
|
181
|
+
if (result.hasHookFailures !== true && result.errors.length === 0) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const detail =
|
|
185
|
+
result.errors.length > 0
|
|
186
|
+
? result.errors.join('; ')
|
|
187
|
+
: 'one or more internal finalizers failed';
|
|
188
|
+
throw new Error(
|
|
189
|
+
`StopFinalize terminal admission failed: ${detail}`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
133
192
|
|
|
134
193
|
const CUSTOM_GRAPH_EVENTS = new Set<string>([
|
|
135
194
|
GraphEvents.ON_AGENT_UPDATE,
|
|
@@ -227,7 +286,10 @@ function getInterruptHookSessionId(payload: unknown): string | undefined {
|
|
|
227
286
|
|
|
228
287
|
type InterruptStateSnapshot = {
|
|
229
288
|
config?: RunnableConfig;
|
|
230
|
-
values?: {
|
|
289
|
+
values?: {
|
|
290
|
+
messages?: BaseMessage[];
|
|
291
|
+
runStepState?: t.RunStepResumeState;
|
|
292
|
+
};
|
|
231
293
|
tasks?: Array<{
|
|
232
294
|
interrupts?: Array<{ id?: string; value?: unknown }>;
|
|
233
295
|
state?: RunnableConfig | InterruptStateSnapshot;
|
|
@@ -240,10 +302,79 @@ type WorkflowWithStateHistory = {
|
|
|
240
302
|
options?: { subgraphs?: boolean }
|
|
241
303
|
): Promise<InterruptStateSnapshot>;
|
|
242
304
|
getStateHistory?(
|
|
243
|
-
config: RunnableConfig
|
|
305
|
+
config: RunnableConfig,
|
|
306
|
+
options?: { filter?: Record<string, unknown>; limit?: number }
|
|
244
307
|
): AsyncIterableIterator<InterruptStateSnapshot>;
|
|
245
308
|
};
|
|
246
309
|
|
|
310
|
+
async function resolveCompletedSegmentConfig(
|
|
311
|
+
workflow: t.CompiledStateWorkflow,
|
|
312
|
+
config: t.RunStreamConfig,
|
|
313
|
+
executionId: string,
|
|
314
|
+
streamSegment: number
|
|
315
|
+
): Promise<t.RunStreamConfig> {
|
|
316
|
+
const stateWorkflow = workflow as t.CompiledStateWorkflow &
|
|
317
|
+
WorkflowWithStateHistory;
|
|
318
|
+
const stateHistory = stateWorkflow.getStateHistory;
|
|
319
|
+
if (typeof stateHistory !== 'function') {
|
|
320
|
+
throw new Error(
|
|
321
|
+
'Cannot continue a checkpointed run without exact state history.'
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
const lookup = advanceCheckpointCursor(config);
|
|
325
|
+
|
|
326
|
+
const resolveSnapshot = (
|
|
327
|
+
snapshot: InterruptStateSnapshot | undefined
|
|
328
|
+
): t.RunStreamConfig | undefined => {
|
|
329
|
+
if (snapshot == null) {
|
|
330
|
+
return undefined;
|
|
331
|
+
}
|
|
332
|
+
const runStepState =
|
|
333
|
+
snapshot.values?.runStepState ??
|
|
334
|
+
snapshot.tasks
|
|
335
|
+
?.flatMap((task) => task.interrupts ?? [])
|
|
336
|
+
.map((pendingInterrupt) =>
|
|
337
|
+
getRunStepResumeState(pendingInterrupt.value)
|
|
338
|
+
)
|
|
339
|
+
.find((state): state is t.RunStepResumeState => state != null);
|
|
340
|
+
if (
|
|
341
|
+
runStepState?.stopContinuationExecutionId !== executionId ||
|
|
342
|
+
runStepState.streamSegment !== streamSegment
|
|
343
|
+
) {
|
|
344
|
+
return undefined;
|
|
345
|
+
}
|
|
346
|
+
const checkpointId = snapshot.config?.configurable?.checkpoint_id;
|
|
347
|
+
if (typeof checkpointId !== 'string' || checkpointId.length === 0) {
|
|
348
|
+
return undefined;
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
...config,
|
|
352
|
+
configurable: {
|
|
353
|
+
...config.configurable,
|
|
354
|
+
...snapshot.config?.configurable,
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
if (typeof stateWorkflow.getState === 'function') {
|
|
360
|
+
const latest = await stateWorkflow.getState(lookup);
|
|
361
|
+
const latestConfig = resolveSnapshot(latest);
|
|
362
|
+
if (latestConfig != null) {
|
|
363
|
+
return latestConfig;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
for await (const snapshot of stateHistory.call(workflow, lookup)) {
|
|
368
|
+
const snapshotConfig = resolveSnapshot(snapshot);
|
|
369
|
+
if (snapshotConfig != null) {
|
|
370
|
+
return snapshotConfig;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
throw new Error(
|
|
374
|
+
'Cannot identify the checkpoint committed by the completed graph segment.'
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
|
|
247
378
|
function getFirstPersistedInterrupt(
|
|
248
379
|
snapshot: InterruptStateSnapshot
|
|
249
380
|
): { id: string; value: unknown } | undefined {
|
|
@@ -283,6 +414,27 @@ function getPersistedMessages(
|
|
|
283
414
|
|
|
284
415
|
type ResumeCommandUpdate = ConstructorParameters<typeof Command>[0]['update'];
|
|
285
416
|
|
|
417
|
+
function overwriteResumeRunStepState(
|
|
418
|
+
command: Command,
|
|
419
|
+
state: t.RunStepResumeState
|
|
420
|
+
): Command {
|
|
421
|
+
const overwrite = new Overwrite(state);
|
|
422
|
+
const update = Array.isArray(command.update)
|
|
423
|
+
? [
|
|
424
|
+
...command.update.filter(([key]) => key !== 'runStepState'),
|
|
425
|
+
['runStepState', overwrite] as [string, unknown],
|
|
426
|
+
]
|
|
427
|
+
: { ...(command.update ?? {}), runStepState: overwrite };
|
|
428
|
+
const resumed = new Command({
|
|
429
|
+
...(command.graph == null ? {} : { graph: command.graph }),
|
|
430
|
+
...(command.resume === undefined ? {} : { resume: command.resume }),
|
|
431
|
+
update,
|
|
432
|
+
...(command.goto === undefined ? {} : { goto: command.goto }),
|
|
433
|
+
});
|
|
434
|
+
resumed.lc_direct_tool_output = command.lc_direct_tool_output;
|
|
435
|
+
return resumed;
|
|
436
|
+
}
|
|
437
|
+
|
|
286
438
|
function getResumeUpdateMessages(
|
|
287
439
|
update: ResumeCommandUpdate
|
|
288
440
|
): BaseMessage[] | undefined {
|
|
@@ -315,6 +467,7 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
315
467
|
private toolExecution?: t.ToolExecutionConfig;
|
|
316
468
|
private subagentUsageSink?: t.SubagentUsageSink;
|
|
317
469
|
private preemption?: t.StreamPreemption;
|
|
470
|
+
private maxStopContinuations: number;
|
|
318
471
|
private streamLimits?: t.StreamLimits;
|
|
319
472
|
private subagentTasks?: t.SubagentTaskConfig;
|
|
320
473
|
private indexTokenCountMap?: Record<string, number>;
|
|
@@ -386,6 +539,9 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
386
539
|
this.subagentUsageSink = config.subagentUsageSink;
|
|
387
540
|
this.subagentTasks = config.subagentTasks;
|
|
388
541
|
this.preemption = config.preemption;
|
|
542
|
+
this.maxStopContinuations = resolveMaxStopContinuations(
|
|
543
|
+
config.maxStopContinuations
|
|
544
|
+
);
|
|
389
545
|
this.streamLimits = config.streamLimits;
|
|
390
546
|
|
|
391
547
|
if (!config.graphConfig) {
|
|
@@ -728,12 +884,16 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
728
884
|
config: t.RunConfig
|
|
729
885
|
): Promise<Run<T>> {
|
|
730
886
|
await ensureSourceModeProviders();
|
|
731
|
-
/** Create tokenCounter if indexTokenCountMap is provided but tokenCounter is
|
|
887
|
+
/** Create tokenCounter if indexTokenCountMap is provided but tokenCounter is
|
|
888
|
+
* not. The model is read through both option keys: `modelName` is
|
|
889
|
+
* LangChain's alias for `model`, so consulting one alone would give a
|
|
890
|
+
* Claude-backed agent an `o200k_base` counter and undercount every message
|
|
891
|
+
* it measures. */
|
|
732
892
|
if (config.indexTokenCountMap && !config.tokenCounter) {
|
|
733
893
|
const gc = config.graphConfig;
|
|
734
894
|
const clientOpts =
|
|
735
895
|
'agents' in gc ? gc.agents[0]?.clientOptions : gc.clientOptions;
|
|
736
|
-
const model = (clientOpts
|
|
896
|
+
const model = resolveClientOptionsModel(clientOpts) ?? '';
|
|
737
897
|
config.tokenCounter = await createTokenCounter(encodingForModel(model));
|
|
738
898
|
}
|
|
739
899
|
return new Run<T>(config);
|
|
@@ -794,6 +954,18 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
794
954
|
return this.Graph?.getToolCount() ?? 0;
|
|
795
955
|
}
|
|
796
956
|
|
|
957
|
+
/**
|
|
958
|
+
* True when the run's last turn ended at `END` because the provider hit
|
|
959
|
+
* its output token ceiling while producing plain text/reasoning — no tool
|
|
960
|
+
* call, so `assertNotTruncatedToolCall` never sees it and the graph reads
|
|
961
|
+
* the turn as an ordinary completion. Hosts check this alongside
|
|
962
|
+
* `getPreemptStats()` / `getHaltReason()` to decide whether to persist the
|
|
963
|
+
* response as unfinished instead of a silently truncated "complete" one.
|
|
964
|
+
*/
|
|
965
|
+
getOutputTruncated(): boolean {
|
|
966
|
+
return this.Graph?.outputTruncatedIncomplete ?? false;
|
|
967
|
+
}
|
|
968
|
+
|
|
797
969
|
/**
|
|
798
970
|
* Creates a custom event callback handler that intercepts custom events
|
|
799
971
|
* and processes them through our handler registry instead of EventStreamCallbackHandler
|
|
@@ -1042,11 +1214,16 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1042
1214
|
delete config.configurable?.[SUBAGENT_RESUME_ATTEMPT_CONFIG_KEY];
|
|
1043
1215
|
delete config.configurable?.[SUBAGENT_RESUME_MANIFEST_CONFIG_KEY];
|
|
1044
1216
|
}
|
|
1217
|
+
let overwriteLegacyResumeState = false;
|
|
1045
1218
|
if (isResume) {
|
|
1046
1219
|
await this.restoreInterruptFromCheckpoint(
|
|
1047
1220
|
config,
|
|
1048
1221
|
(inputs as Command).update
|
|
1049
1222
|
);
|
|
1223
|
+
if (graph.getStopContinuationExecutionId() === '') {
|
|
1224
|
+
graph.startStopContinuationExecution(nanoid());
|
|
1225
|
+
overwriteLegacyResumeState = this.hasCheckpointer;
|
|
1226
|
+
}
|
|
1050
1227
|
}
|
|
1051
1228
|
|
|
1052
1229
|
/**
|
|
@@ -1097,6 +1274,7 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1097
1274
|
checkpointId === '' ? 0 : ++this.checkpointForkSeq,
|
|
1098
1275
|
]);
|
|
1099
1276
|
graph.resetValues(streamOptions?.keepContent, checkpointScope);
|
|
1277
|
+
graph.startStopContinuationExecution(nanoid());
|
|
1100
1278
|
}
|
|
1101
1279
|
this._interrupt = undefined;
|
|
1102
1280
|
this._haltedReason = undefined;
|
|
@@ -1162,6 +1340,7 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1162
1340
|
: undefined,
|
|
1163
1341
|
traceAnchor: graph.langfuseTraceAnchor,
|
|
1164
1342
|
runId: graph.langfuseScopeRunId,
|
|
1343
|
+
deferRootRunId: this.id,
|
|
1165
1344
|
// The aggregate multi-agent policy from the runtime scope — the
|
|
1166
1345
|
// handler must restore THIS (not the primary agent's config-derived
|
|
1167
1346
|
// policy) when rejecting a foreign scope.
|
|
@@ -1176,6 +1355,7 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1176
1355
|
throw new Error('Run ID not provided');
|
|
1177
1356
|
}
|
|
1178
1357
|
|
|
1358
|
+
config.runId = this.id;
|
|
1179
1359
|
config.run_id = this.id;
|
|
1180
1360
|
config.configurable = Object.assign(config.configurable ?? {}, {
|
|
1181
1361
|
run_id: this.id,
|
|
@@ -1224,191 +1404,209 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1224
1404
|
let terminalAt: number | undefined;
|
|
1225
1405
|
|
|
1226
1406
|
const consumeStream = async (): Promise<void> => {
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
* Custom events are already handled via our createCustomEventCallback()
|
|
1241
|
-
* which routes them through the handlerRegistry.
|
|
1242
|
-
* Without this flag, EventStreamCallbackHandler throws errors when
|
|
1243
|
-
* custom events are dispatched for run IDs not in its internal map
|
|
1244
|
-
* (due to timing issues in parallel execution or after run cleanup).
|
|
1245
|
-
*/
|
|
1246
|
-
ignoreCustomEvent: true,
|
|
1247
|
-
}
|
|
1248
|
-
);
|
|
1407
|
+
let streamInputs: t.IState | Command = inputs;
|
|
1408
|
+
if (!isResume && this.hasCheckpointer) {
|
|
1409
|
+
streamInputs = {
|
|
1410
|
+
...(inputs as t.IState),
|
|
1411
|
+
runStepState: new Overwrite(graph.createRunStepResumeState()),
|
|
1412
|
+
} as unknown as t.IState;
|
|
1413
|
+
} else if (overwriteLegacyResumeState) {
|
|
1414
|
+
streamInputs = overwriteResumeRunStepState(
|
|
1415
|
+
inputs as Command,
|
|
1416
|
+
graph.createRunStepResumeState()
|
|
1417
|
+
);
|
|
1418
|
+
}
|
|
1419
|
+
let streamConfig = config;
|
|
1249
1420
|
|
|
1250
|
-
for
|
|
1251
|
-
|
|
1421
|
+
for (;;) {
|
|
1422
|
+
/**
|
|
1423
|
+
* `streamEvents` accepts both state inputs and `Command` (resume) at
|
|
1424
|
+
* runtime, but our `CompiledStateWorkflow` type narrows the first
|
|
1425
|
+
* arg to `BaseGraphState`. Cast on the call so the resume path
|
|
1426
|
+
* type-checks without widening the wrapper for every caller.
|
|
1427
|
+
*/
|
|
1428
|
+
const stream = graphRunnable.streamEvents(
|
|
1429
|
+
streamInputs as t.IState,
|
|
1430
|
+
{ ...streamConfig, runName: graph.runName },
|
|
1431
|
+
{
|
|
1432
|
+
raiseError: true,
|
|
1433
|
+
/** Custom events are handled by createCustomEventCallback(). */
|
|
1434
|
+
ignoreCustomEvent: true,
|
|
1435
|
+
}
|
|
1436
|
+
);
|
|
1252
1437
|
|
|
1253
|
-
const
|
|
1438
|
+
for await (const event of stream) {
|
|
1439
|
+
const { data, metadata, ...info } = event;
|
|
1440
|
+
const eventName: t.EventName = info.event;
|
|
1254
1441
|
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
}
|
|
1442
|
+
if (CUSTOM_GRAPH_EVENTS.has(eventName)) {
|
|
1443
|
+
continue;
|
|
1444
|
+
}
|
|
1259
1445
|
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
this.
|
|
1290
|
-
|
|
1291
|
-
threadId,
|
|
1292
|
-
payload: first.value,
|
|
1293
|
-
};
|
|
1446
|
+
if (
|
|
1447
|
+
this._interrupt == null &&
|
|
1448
|
+
data.chunk != null &&
|
|
1449
|
+
isInterrupted<unknown>(data.chunk)
|
|
1450
|
+
) {
|
|
1451
|
+
const interrupts = data.chunk[INTERRUPT];
|
|
1452
|
+
if (interrupts.length > 0) {
|
|
1453
|
+
const first = interrupts[0];
|
|
1454
|
+
this._interrupt = {
|
|
1455
|
+
interruptId: first.id ?? '',
|
|
1456
|
+
threadId,
|
|
1457
|
+
payload: first.value,
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
const modelEndAt =
|
|
1463
|
+
eventName === GraphEvents.CHAT_MODEL_END ? Date.now() : undefined;
|
|
1464
|
+
const handler = this.handlerRegistry?.getHandler(eventName);
|
|
1465
|
+
if (handler) {
|
|
1466
|
+
await handler.handle(eventName, data, metadata, this.Graph);
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
if (eventName === GraphEvents.CHAT_MODEL_END && this.Graph != null) {
|
|
1470
|
+
await this.Graph.closeOpenMessageStep(metadata, modelEndAt);
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
const haltSignal = this.hookRegistry?.getHaltSignal(this.id);
|
|
1474
|
+
if (haltSignal != null) {
|
|
1475
|
+
this._haltedReason = haltSignal.reason;
|
|
1476
|
+
break;
|
|
1294
1477
|
}
|
|
1295
1478
|
}
|
|
1296
1479
|
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1480
|
+
terminalAt = Date.now();
|
|
1481
|
+
|
|
1482
|
+
if (this._interrupt != null) {
|
|
1483
|
+
const interruptConfig = this.hasCheckpointer
|
|
1484
|
+
? advanceCheckpointCursor(streamConfig)
|
|
1485
|
+
: streamConfig;
|
|
1486
|
+
await this.resolveInterruptResumeConfig(interruptConfig);
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
if (this._haltedReason != null) {
|
|
1490
|
+
return;
|
|
1307
1491
|
}
|
|
1308
1492
|
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
if (eventName === GraphEvents.CHAT_MODEL_END && this.Graph != null) {
|
|
1316
|
-
await this.Graph.closeOpenMessageStep(metadata, modelEndAt);
|
|
1493
|
+
let stopReason = graph.preemptHaltReason;
|
|
1494
|
+
if (stopReason == null && graph.preemptIncomplete) {
|
|
1495
|
+
stopReason = 'preempt_incomplete';
|
|
1496
|
+
}
|
|
1497
|
+
if (stopReason == null && graph.outputTruncatedIncomplete) {
|
|
1498
|
+
stopReason = OUTPUT_TRUNCATED_HALT_REASON;
|
|
1317
1499
|
}
|
|
1318
1500
|
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
break;
|
|
1501
|
+
const stopMessages = graph.getRunMessages() ?? stateInputs?.messages ?? [];
|
|
1502
|
+
const stopContinuationCount = graph.getStopContinuationCount();
|
|
1503
|
+
const continuationBudgetRemaining = Math.max(
|
|
1504
|
+
0,
|
|
1505
|
+
this.maxStopContinuations - stopContinuationCount
|
|
1506
|
+
);
|
|
1507
|
+
let stopResult: AggregatedHookResult | undefined;
|
|
1508
|
+
if (this.hookRegistry?.hasHookFor('Stop', this.id) === true) {
|
|
1509
|
+
stopResult = await executeHooks({
|
|
1510
|
+
registry: this.hookRegistry,
|
|
1511
|
+
input: {
|
|
1512
|
+
hook_event_name: 'Stop',
|
|
1513
|
+
runId: this.id,
|
|
1514
|
+
threadId,
|
|
1515
|
+
agentId: graph.defaultAgentId,
|
|
1516
|
+
messages: stopMessages,
|
|
1517
|
+
stopReason,
|
|
1518
|
+
stopHookActive: stopContinuationCount > 0,
|
|
1519
|
+
continuationCount: stopContinuationCount,
|
|
1520
|
+
continuationBudgetRemaining,
|
|
1521
|
+
},
|
|
1522
|
+
sessionId: this.id,
|
|
1523
|
+
signal: config.signal,
|
|
1524
|
+
}).catch((): undefined => undefined);
|
|
1344
1525
|
}
|
|
1345
|
-
}
|
|
1346
1526
|
|
|
1347
|
-
|
|
1527
|
+
if (this.hookRegistry?.hasHookFor('StopFinalize', this.id) === true) {
|
|
1528
|
+
const stopInjected =
|
|
1529
|
+
stopResult == null ? [] : materializeStopContinuation(stopResult);
|
|
1530
|
+
const continuationPrevented =
|
|
1531
|
+
stopReason != null || stopResult?.preventContinuation === true;
|
|
1532
|
+
const finalized = await executeHooks({
|
|
1533
|
+
registry: this.hookRegistry,
|
|
1534
|
+
input: {
|
|
1535
|
+
hook_event_name: 'StopFinalize',
|
|
1536
|
+
runId: this.id,
|
|
1537
|
+
threadId,
|
|
1538
|
+
agentId: graph.defaultAgentId,
|
|
1539
|
+
messages: stopMessages,
|
|
1540
|
+
stopReason,
|
|
1541
|
+
stopHookActive: stopContinuationCount > 0,
|
|
1542
|
+
continuationCount: stopContinuationCount,
|
|
1543
|
+
continuationBudgetRemaining,
|
|
1544
|
+
continuationPlanned:
|
|
1545
|
+
!continuationPrevented &&
|
|
1546
|
+
stopResult?.stopDecision === 'block' &&
|
|
1547
|
+
stopInjected.length > 0 &&
|
|
1548
|
+
continuationBudgetRemaining > 0,
|
|
1549
|
+
continuationPrevented,
|
|
1550
|
+
},
|
|
1551
|
+
sessionId: this.id,
|
|
1552
|
+
signal: config.signal,
|
|
1553
|
+
});
|
|
1554
|
+
assertFinalAdmissionSucceeded(finalized);
|
|
1555
|
+
stopResult = mergeAggregatedHookResults(stopResult, finalized);
|
|
1556
|
+
}
|
|
1348
1557
|
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1558
|
+
if (stopResult?.preventContinuation === true) {
|
|
1559
|
+
this._haltedReason =
|
|
1560
|
+
stopResult.stopReason ?? stopResult.reason ?? 'preventContinuation';
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1352
1563
|
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1564
|
+
const requestsContinuation =
|
|
1565
|
+
stopReason == null && stopResult?.stopDecision === 'block';
|
|
1566
|
+
if (requestsContinuation && stopResult != null) {
|
|
1567
|
+
const injected = materializeStopContinuation(stopResult);
|
|
1568
|
+
if (injected.length > 0) {
|
|
1569
|
+
if (stopContinuationCount >= this.maxStopContinuations) {
|
|
1570
|
+
throw new Error(
|
|
1571
|
+
'Stop hook attempted to inject messages after the terminal continuation budget was exhausted.'
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1574
|
+
const completedSegmentConfig = this.hasCheckpointer
|
|
1575
|
+
? await resolveCompletedSegmentConfig(
|
|
1576
|
+
graphRunnable,
|
|
1577
|
+
streamConfig,
|
|
1578
|
+
graph.getStopContinuationExecutionId(),
|
|
1579
|
+
graph.getStreamSegment()
|
|
1580
|
+
)
|
|
1581
|
+
: streamConfig;
|
|
1582
|
+
const nextContinuationCount = stopContinuationCount + 1;
|
|
1583
|
+
graph.setStopContinuationCount(nextContinuationCount);
|
|
1584
|
+
graph.advanceStreamSegment();
|
|
1373
1585
|
/**
|
|
1374
|
-
* A
|
|
1375
|
-
*
|
|
1376
|
-
*
|
|
1377
|
-
*
|
|
1378
|
-
* is reserved for the boundary that simply had nothing to inject.
|
|
1586
|
+
* A checkpointer already owns the completed graph state, so only
|
|
1587
|
+
* the delta is submitted. Without one, each invocation starts from
|
|
1588
|
+
* empty state and must be seeded with the live full transcript.
|
|
1589
|
+
* Graph sidecars and the outer Run stay intact in both cases.
|
|
1379
1590
|
*/
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1591
|
+
streamInputs = {
|
|
1592
|
+
messages: this.hasCheckpointer
|
|
1593
|
+
? injected
|
|
1594
|
+
: [...graph.messages, ...injected],
|
|
1595
|
+
runStepState: graph.createRunStepResumeState(),
|
|
1596
|
+
};
|
|
1597
|
+
streamConfig = completedSegmentConfig;
|
|
1598
|
+
continue;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1390
1601
|
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
*
|
|
1400
|
-
* An empty boundary — sealed, but nothing to inject because the host's
|
|
1401
|
-
* queue was drained or cancelled in the meantime — cut the answer short
|
|
1402
|
-
* just as surely, only without a hook-supplied reason. It surfaces
|
|
1403
|
-
* through the same channel under the same name the `Stop` dispatch
|
|
1404
|
-
* already used for its `stopReason`, so terminal consumers
|
|
1405
|
-
* (`AgentSession` emits `run.halted`, not `run.completed`) cannot
|
|
1406
|
-
* finalize a truncated answer as a natural finish.
|
|
1407
|
-
*/
|
|
1408
|
-
if (this._haltedReason == null && graph.preemptHaltReason != null) {
|
|
1409
|
-
this._haltedReason = graph.preemptHaltReason;
|
|
1410
|
-
} else if (this._haltedReason == null && graph.preemptIncomplete) {
|
|
1411
|
-
this._haltedReason = 'preempt_incomplete';
|
|
1602
|
+
if (graph.preemptHaltReason != null) {
|
|
1603
|
+
this._haltedReason = graph.preemptHaltReason;
|
|
1604
|
+
} else if (graph.preemptIncomplete) {
|
|
1605
|
+
this._haltedReason = 'preempt_incomplete';
|
|
1606
|
+
} else if (graph.outputTruncatedIncomplete) {
|
|
1607
|
+
this._haltedReason = OUTPUT_TRUNCATED_HALT_REASON;
|
|
1608
|
+
}
|
|
1609
|
+
return;
|
|
1412
1610
|
}
|
|
1413
1611
|
};
|
|
1414
1612
|
|
|
@@ -1432,6 +1630,10 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1432
1630
|
} catch (err) {
|
|
1433
1631
|
terminalAt = Date.now();
|
|
1434
1632
|
streamThrew = true;
|
|
1633
|
+
await langfuseHandler?.handleChainError(
|
|
1634
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
1635
|
+
this.id
|
|
1636
|
+
);
|
|
1435
1637
|
/**
|
|
1436
1638
|
* Corroborate cancellation against an actually-aborted signal. A
|
|
1437
1639
|
* provider SDK or host handler can reject with an `AbortError` while
|
|
@@ -1614,13 +1816,16 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1614
1816
|
}
|
|
1615
1817
|
|
|
1616
1818
|
/**
|
|
1617
|
-
* Returns the
|
|
1618
|
-
*
|
|
1819
|
+
* Returns why the run ended without a natural completion, or `undefined`
|
|
1820
|
+
* when it completed normally. Reasons include hook- and prompt-driven
|
|
1821
|
+
* halts, `preempt_incomplete` when a cooperative seal ended the turn
|
|
1822
|
+
* without continuation content, and `output_truncated` when the provider
|
|
1823
|
+
* stopped a plain-text/reasoning response at its output-token ceiling.
|
|
1619
1824
|
*
|
|
1620
1825
|
* Hosts inspect this after `processStream` returns to distinguish a
|
|
1621
|
-
* natural completion
|
|
1622
|
-
*
|
|
1623
|
-
*
|
|
1826
|
+
* natural completion from a terminal partial response. Independent from
|
|
1827
|
+
* `getInterrupt()` — a halted run has no interrupt; an interrupted run has
|
|
1828
|
+
* no halt reason.
|
|
1624
1829
|
*/
|
|
1625
1830
|
getHaltReason(): string | undefined {
|
|
1626
1831
|
return this._haltedReason;
|
|
@@ -1833,7 +2038,8 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1833
2038
|
return;
|
|
1834
2039
|
}
|
|
1835
2040
|
this.Graph?.restoreRunStepResumeState(
|
|
1836
|
-
getRunStepResumeState(persistedInterrupt.value)
|
|
2041
|
+
getRunStepResumeState(persistedInterrupt.value) ??
|
|
2042
|
+
snapshot.values?.runStepState
|
|
1837
2043
|
);
|
|
1838
2044
|
const persistedMessages = getPersistedMessages(snapshot);
|
|
1839
2045
|
if (persistedMessages != null) {
|