@librechat/agents 3.3.7 → 3.3.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.
Files changed (168) hide show
  1. package/dist/cjs/graphs/Graph.cjs +47 -13
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/graphs/MultiAgentGraph.cjs +56 -6
  4. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  5. package/dist/cjs/hitl/askUserQuestion.cjs +3 -2
  6. package/dist/cjs/hitl/askUserQuestion.cjs.map +1 -1
  7. package/dist/cjs/instrumentation.cjs +18 -48
  8. package/dist/cjs/instrumentation.cjs.map +1 -1
  9. package/dist/cjs/langfuse.cjs +174 -29
  10. package/dist/cjs/langfuse.cjs.map +1 -1
  11. package/dist/cjs/langfuseConfig.cjs +12 -0
  12. package/dist/cjs/langfuseConfig.cjs.map +1 -1
  13. package/dist/cjs/langfuseRuntimeContext.cjs +23 -2
  14. package/dist/cjs/langfuseRuntimeContext.cjs.map +1 -1
  15. package/dist/cjs/langfuseRuntimeScope.cjs +39 -8
  16. package/dist/cjs/langfuseRuntimeScope.cjs.map +1 -1
  17. package/dist/cjs/langfuseSpanRegistry.cjs +95 -0
  18. package/dist/cjs/langfuseSpanRegistry.cjs.map +1 -0
  19. package/dist/cjs/langfuseTraceShaping.cjs +121 -4
  20. package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
  21. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +39 -15
  22. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  23. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +25 -5
  24. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  25. package/dist/cjs/llm/init.cjs +3 -3
  26. package/dist/cjs/llm/invoke.cjs +5 -5
  27. package/dist/cjs/llm/openai/index.cjs +1 -1
  28. package/dist/cjs/main.cjs +10 -10
  29. package/dist/cjs/messages/format.cjs +124 -15
  30. package/dist/cjs/messages/format.cjs.map +1 -1
  31. package/dist/cjs/messages/injected.cjs +10 -1
  32. package/dist/cjs/messages/injected.cjs.map +1 -1
  33. package/dist/cjs/messages/prune.cjs +13 -1
  34. package/dist/cjs/messages/prune.cjs.map +1 -1
  35. package/dist/cjs/prompts/activityLabel.cjs +51 -11
  36. package/dist/cjs/prompts/activityLabel.cjs.map +1 -1
  37. package/dist/cjs/run.cjs +54 -24
  38. package/dist/cjs/run.cjs.map +1 -1
  39. package/dist/cjs/session/messageSerialization.cjs +6 -0
  40. package/dist/cjs/session/messageSerialization.cjs.map +1 -1
  41. package/dist/cjs/stream.cjs +21 -10
  42. package/dist/cjs/stream.cjs.map +1 -1
  43. package/dist/cjs/summarization/node.cjs +60 -0
  44. package/dist/cjs/summarization/node.cjs.map +1 -1
  45. package/dist/cjs/tools/ToolNode.cjs +253 -24
  46. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  47. package/dist/cjs/tools/handlers.cjs +1 -1
  48. package/dist/cjs/tools/search/tool.cjs +1 -1
  49. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1 -1
  50. package/dist/cjs/utils/index.cjs +2 -2
  51. package/dist/esm/graphs/Graph.mjs +48 -14
  52. package/dist/esm/graphs/Graph.mjs.map +1 -1
  53. package/dist/esm/graphs/MultiAgentGraph.mjs +56 -6
  54. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  55. package/dist/esm/hitl/askUserQuestion.mjs +3 -2
  56. package/dist/esm/hitl/askUserQuestion.mjs.map +1 -1
  57. package/dist/esm/instrumentation.mjs +18 -48
  58. package/dist/esm/instrumentation.mjs.map +1 -1
  59. package/dist/esm/langfuse.mjs +176 -28
  60. package/dist/esm/langfuse.mjs.map +1 -1
  61. package/dist/esm/langfuseConfig.mjs +10 -1
  62. package/dist/esm/langfuseConfig.mjs.map +1 -1
  63. package/dist/esm/langfuseRuntimeContext.mjs +21 -3
  64. package/dist/esm/langfuseRuntimeContext.mjs.map +1 -1
  65. package/dist/esm/langfuseRuntimeScope.mjs +39 -10
  66. package/dist/esm/langfuseRuntimeScope.mjs.map +1 -1
  67. package/dist/esm/langfuseSpanRegistry.mjs +91 -0
  68. package/dist/esm/langfuseSpanRegistry.mjs.map +1 -0
  69. package/dist/esm/langfuseTraceShaping.mjs +121 -4
  70. package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
  71. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +39 -15
  72. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  73. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +25 -5
  74. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  75. package/dist/esm/llm/init.mjs +2 -2
  76. package/dist/esm/llm/invoke.mjs +5 -5
  77. package/dist/esm/llm/openai/index.mjs +1 -1
  78. package/dist/esm/main.mjs +8 -8
  79. package/dist/esm/messages/format.mjs +124 -15
  80. package/dist/esm/messages/format.mjs.map +1 -1
  81. package/dist/esm/messages/injected.mjs +10 -1
  82. package/dist/esm/messages/injected.mjs.map +1 -1
  83. package/dist/esm/messages/prune.mjs +13 -1
  84. package/dist/esm/messages/prune.mjs.map +1 -1
  85. package/dist/esm/prompts/activityLabel.mjs +51 -11
  86. package/dist/esm/prompts/activityLabel.mjs.map +1 -1
  87. package/dist/esm/run.mjs +54 -24
  88. package/dist/esm/run.mjs.map +1 -1
  89. package/dist/esm/session/messageSerialization.mjs +6 -0
  90. package/dist/esm/session/messageSerialization.mjs.map +1 -1
  91. package/dist/esm/stream.mjs +21 -10
  92. package/dist/esm/stream.mjs.map +1 -1
  93. package/dist/esm/summarization/node.mjs +60 -0
  94. package/dist/esm/summarization/node.mjs.map +1 -1
  95. package/dist/esm/tools/ToolNode.mjs +254 -25
  96. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  97. package/dist/esm/tools/handlers.mjs +1 -1
  98. package/dist/esm/tools/search/tool.mjs +1 -1
  99. package/dist/esm/tools/subagent/SubagentExecutor.mjs +1 -1
  100. package/dist/esm/utils/index.mjs +2 -2
  101. package/dist/types/graphs/Graph.d.ts +19 -0
  102. package/dist/types/hitl/askUserQuestion.d.ts +11 -1
  103. package/dist/types/langfuse.d.ts +16 -8
  104. package/dist/types/langfuseConfig.d.ts +6 -0
  105. package/dist/types/langfuseRuntimeContext.d.ts +27 -1
  106. package/dist/types/langfuseRuntimeScope.d.ts +17 -2
  107. package/dist/types/langfuseSpanRegistry.d.ts +17 -0
  108. package/dist/types/langfuseTraceShaping.d.ts +2 -1
  109. package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -0
  110. package/dist/types/messages/format.d.ts +9 -8
  111. package/dist/types/prompts/activityLabel.d.ts +8 -1
  112. package/dist/types/run.d.ts +1 -1
  113. package/dist/types/session/types.d.ts +1 -0
  114. package/dist/types/tools/ToolNode.d.ts +7 -1
  115. package/dist/types/types/activityLabel.d.ts +8 -0
  116. package/dist/types/types/hitl.d.ts +8 -0
  117. package/dist/types/types/stream.d.ts +19 -0
  118. package/dist/types/types/tools.d.ts +30 -0
  119. package/package.json +7 -4
  120. package/src/__tests__/stream.eagerArgsDivergence.test.ts +753 -0
  121. package/src/graphs/Graph.ts +69 -20
  122. package/src/graphs/MultiAgentGraph.ts +74 -6
  123. package/src/graphs/__tests__/composition.smoke.test.ts +4 -0
  124. package/src/hitl/askUserQuestion.ts +14 -1
  125. package/src/instrumentation.ts +35 -77
  126. package/src/langfuse.ts +320 -43
  127. package/src/langfuseConfig.ts +24 -0
  128. package/src/langfuseRuntimeContext.ts +43 -1
  129. package/src/langfuseRuntimeScope.ts +94 -21
  130. package/src/langfuseSpanRegistry.ts +131 -0
  131. package/src/langfuseTraceShaping.ts +194 -7
  132. package/src/llm/anthropic/utils/message_inputs.ts +70 -19
  133. package/src/llm/anthropic/utils/streaming-tool-input.test.ts +186 -11
  134. package/src/llm/bedrock/utils/message_inputs.test.ts +120 -4
  135. package/src/llm/bedrock/utils/message_inputs.ts +32 -7
  136. package/src/messages/format.ts +222 -50
  137. package/src/messages/formatAgentMessages.test.ts +308 -6
  138. package/src/messages/injected.test.ts +18 -1
  139. package/src/messages/injected.ts +8 -1
  140. package/src/messages/prune.ts +12 -1
  141. package/src/prompts/activityLabel.ts +67 -2
  142. package/src/run.ts +86 -46
  143. package/src/scripts/activity-labels/captured.json +56 -0
  144. package/src/scripts/activity-labels/checks.cjs +205 -0
  145. package/src/scripts/activity-labels/corpus.cjs +473 -0
  146. package/src/scripts/activity-labels/report.cjs +203 -0
  147. package/src/scripts/activity-labels/rescore.cjs +102 -0
  148. package/src/scripts/activity-labels/run.ts +705 -0
  149. package/src/scripts/activity-labels/variants.ts +71 -0
  150. package/src/session/messageSerialization.ts +12 -1
  151. package/src/session/types.ts +1 -0
  152. package/src/specs/activity-label-prompt.test.ts +109 -0
  153. package/src/specs/agent-handoffs.test.ts +306 -0
  154. package/src/specs/langfuse-callbacks.test.ts +456 -0
  155. package/src/specs/langfuse-routing.integration.test.ts +138 -1
  156. package/src/specs/langfuse-span-registry.test.ts +70 -0
  157. package/src/specs/langfuse-trace-shaping.test.ts +294 -0
  158. package/src/specs/prune.test.ts +38 -1
  159. package/src/stream.ts +70 -6
  160. package/src/summarization/__tests__/node.test.ts +188 -0
  161. package/src/summarization/node.ts +72 -0
  162. package/src/tools/ToolNode.ts +400 -9
  163. package/src/tools/__tests__/ToolNode.invalidToolCalls.test.ts +757 -0
  164. package/src/tools/__tests__/hitl.test.ts +58 -0
  165. package/src/types/activityLabel.ts +8 -0
  166. package/src/types/hitl.ts +8 -0
  167. package/src/types/stream.ts +20 -0
  168. package/src/types/tools.ts +35 -1
@@ -4,8 +4,8 @@ import { getMessageId } from "../messages/ids.mjs";
4
4
  import "../messages/index.mjs";
5
5
  import { coerceAnthropicSearchResults, isAnthropicWebSearchResult } from "./search/anthropic.mjs";
6
6
  import { formatResultsForLLM } from "./search/format.mjs";
7
- import { ToolMessage } from "@langchain/core/messages";
8
7
  import { nanoid } from "nanoid";
8
+ import { ToolMessage } from "@langchain/core/messages";
9
9
  //#region src/tools/handlers.ts
10
10
  async function handleToolCallChunks({ graph, stepKey, toolCallChunks, metadata }) {
11
11
  let prevStepId;
@@ -1,8 +1,8 @@
1
1
  import "../../common/enum.mjs";
2
2
  import "../../common/index.mjs";
3
+ import { INTENT_PROPERTY } from "../intentArg.mjs";
3
4
  import { createDefaultLogger } from "./utils.mjs";
4
5
  import { formatResultsForLLM } from "./format.mjs";
5
- import { INTENT_PROPERTY } from "../intentArg.mjs";
6
6
  import { WebSearchToolDescription, WebSearchToolName, countrySchema, dateSchema, imagesSchema, newsSchema, querySchema, videosSchema } from "./schema.mjs";
7
7
  import { createSearchAPI, createSourceProcessor } from "./search.mjs";
8
8
  import { createKeenableScraper } from "./keenable-scraper.mjs";
@@ -2,9 +2,9 @@ import "../../common/enum.mjs";
2
2
  import "../../common/index.mjs";
3
3
  import { executeHooks } from "../../hooks/executeHooks.mjs";
4
4
  import "../../hooks/index.mjs";
5
+ import { nanoid } from "nanoid";
5
6
  import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
6
7
  import { HumanMessage } from "@langchain/core/messages";
7
- import { nanoid } from "nanoid";
8
8
  //#region src/tools/subagent/SubagentExecutor.ts
9
9
  const DEFAULT_MAX_TURNS = 25;
10
10
  const RECURSION_MULTIPLIER = 3;
@@ -1,10 +1,10 @@
1
1
  import "./misc.mjs";
2
2
  import "./truncation.mjs";
3
3
  import "./tokens.mjs";
4
- import "./graph.mjs";
4
+ import "./errors.mjs";
5
5
  import "./llm.mjs";
6
+ import "./graph.mjs";
6
7
  import "./handlers.mjs";
7
8
  import "./run.mjs";
8
9
  import "./schema.mjs";
9
- import "./errors.mjs";
10
10
  export {};
@@ -110,6 +110,15 @@ export declare abstract class Graph<T extends t.BaseGraphState = t.BaseGraphStat
110
110
  eagerEventToolUsageCount: Map<string, number>;
111
111
  private eagerEventToolUsageCountsByAgentId;
112
112
  eagerEventToolCallChunks: Map<string, t.EagerEventToolCallChunkState>;
113
+ /**
114
+ * Per-run eager prestart circuit breaker, shared by reference with every
115
+ * ToolNode this graph compiles. When a prestarted execution's args turn
116
+ * out to differ from the final request, ToolNode records the tool name
117
+ * here and the stream handler stops prestarting that tool for the rest of
118
+ * the run — the retry then executes normally instead of re-diverging in a
119
+ * loop (LibreChat#14371).
120
+ */
121
+ eagerEventToolSuppressions: Set<string>;
113
122
  /**
114
123
  * Run-scoped execution backend for built-in code tools. Defaults to the
115
124
  * remote Code API sandbox when unset.
@@ -197,6 +206,16 @@ export declare class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode>
197
206
  /** Checkpoint scope whose messages match index-keyed tool snapshots. */
198
207
  private originalToolContentCheckpointScope?;
199
208
  runId: string | undefined;
209
+ /**
210
+ * Identity used to stamp Langfuse runtime scopes and handlers (see
211
+ * `LangfuseRuntimeContext.runId`). Carries an opaque per-instance
212
+ * component: public run ids are unrestricted and may repeat across
213
+ * concurrently executing runs (retries, duplicate submissions,
214
+ * tenant-local message ids), and equal stamps would let those runs adopt
215
+ * each other's scopes. One graph instance = one execution's stamp, shared
216
+ * by the stream handler and every graph-level scope of that execution.
217
+ */
218
+ readonly langfuseScopeRunId: string;
200
219
  /**
201
220
  * Boundary between historical messages (loaded from conversation state)
202
221
  * and messages produced during the current run. Set once in the state
@@ -52,4 +52,14 @@ import type { AskUserQuestionRequest, AskUserQuestionResolution } from '@/types/
52
52
  * });
53
53
  * ```
54
54
  */
55
- export declare function askUserQuestion(question: AskUserQuestionRequest): AskUserQuestionResolution;
55
+ export declare function askUserQuestion(question: AskUserQuestionRequest, options?: {
56
+ /**
57
+ * The calling tool's `tool_call_id`, surfaced on the interrupt payload
58
+ * as `tool_call_id` so hosts can attribute the question (and answer) to
59
+ * the exact tool-call content part. Tool bodies created with
60
+ * `tool(fn, …)` receive it as `config.toolCall.id` — LangChain stamps
61
+ * the full ToolCall onto the config when a tool is invoked with one.
62
+ * Optional: positional hosts and custom nodes can omit it.
63
+ */
64
+ toolCallId?: string;
65
+ }): AskUserQuestionResolution;
@@ -1,5 +1,8 @@
1
1
  import { CallbackHandler } from '@langfuse/langchain';
2
+ import type { ResolvedLangfuseToolOutputTracingConfig } from '@/langfuseRuntimeContext';
2
3
  import type * as t from '@/types';
4
+ import { hasLangfuseConfigCredentials, hasLangfuseEnvCredentials, hasLangfuseEnvConfig } from '@/langfuseConfig';
5
+ export { hasLangfuseConfigCredentials, hasLangfuseEnvCredentials, hasLangfuseEnvConfig, };
3
6
  export type LangfuseTraceMetadata = Record<string, string>;
4
7
  export type LangfuseTraceAttributes = Record<string, string | number | boolean>;
5
8
  type LangfuseConfigTraceAttributes = NonNullable<t.LangfuseConfig['librechatTraceAttributes']>;
@@ -9,6 +12,18 @@ type LangfuseHandlerParams = {
9
12
  traceMetadata?: LangfuseTraceMetadata;
10
13
  tags?: string[];
11
14
  traceIdSeed?: string;
15
+ /** Identity of the run this handler traces; ambient runtime scopes are
16
+ * only adopted when stamped with the same run (see
17
+ * `LangfuseRuntimeContext.runId`). */
18
+ runId?: string;
19
+ /** The run's resolved tool-output policy — for multi-agent streams the
20
+ * conservative aggregate across agents, which `this.langfuse` (the
21
+ * primary agent's config) cannot reproduce. Applied when a foreign
22
+ * scope's policy is rejected. */
23
+ toolOutputTracing?: ResolvedLangfuseToolOutputTracingConfig;
24
+ /** The run's propagated trace name, re-propagated when a foreign scope's
25
+ * attributes are cleared. */
26
+ traceName?: string;
12
27
  };
13
28
  type AgentLangfuseHandlerParams = LangfuseHandlerParams & {
14
29
  langfuse?: t.LangfuseConfig;
@@ -16,10 +31,6 @@ type AgentLangfuseHandlerParams = LangfuseHandlerParams & {
16
31
  type LangfuseAttributeParams = AgentLangfuseHandlerParams & {
17
32
  traceName?: string;
18
33
  };
19
- export declare function hasLangfuseConfigCredentials(langfuse?: t.LangfuseConfig): langfuse is t.LangfuseConfig & {
20
- publicKey: string;
21
- secretKey: string;
22
- };
23
34
  export declare function isExplicitLangfuseConfig(langfuse?: t.LangfuseConfig): boolean;
24
35
  export declare function createLibreChatTraceAttributes(attributes: LangfuseConfigTraceAttributes): LangfuseTraceAttributes;
25
36
  export declare function createLangfuseTraceMetadata({ messageId, parentMessageId, agentId, agentName, }: {
@@ -29,15 +40,12 @@ export declare function createLangfuseTraceMetadata({ messageId, parentMessageId
29
40
  agentName?: unknown;
30
41
  }): LangfuseTraceMetadata;
31
42
  export declare function getLangfuseTraceName(traceMetadata?: LangfuseTraceMetadata, fallback?: string): string;
32
- export declare function hasLangfuseEnvConfig(): boolean;
33
- export declare function hasLangfuseEnvCredentials(): boolean;
34
43
  export declare function shouldCreateLangfuseHandler(langfuse?: t.LangfuseConfig): boolean;
35
44
  export declare function createLegacyLangfuseHandler(params: LangfuseHandlerParams): CallbackHandler;
36
- export declare function createLangfuseHandler({ langfuse, userId, sessionId, traceMetadata, tags, traceIdSeed, }: AgentLangfuseHandlerParams): CallbackHandler | undefined;
45
+ export declare function createLangfuseHandler({ langfuse, userId, sessionId, traceMetadata, tags, traceIdSeed, runId, toolOutputTracing, traceName, }: AgentLangfuseHandlerParams): CallbackHandler | undefined;
37
46
  export declare function withLangfuseAttributes<T>(params: LangfuseAttributeParams, action: () => T): T;
38
47
  export declare function hasExplicitLangfuseConfig(contexts: Iterable<{
39
48
  langfuse?: t.LangfuseConfig;
40
49
  }>): boolean;
41
50
  export declare function isLangfuseCallbackHandler(value: unknown): boolean;
42
51
  export declare function disposeLangfuseHandler(value: unknown): Promise<void>;
43
- export {};
@@ -2,6 +2,12 @@ import type { ResolvedLangfuseToolOutputTracingConfig } from '@/langfuseRuntimeC
2
2
  import type * as t from '@/types';
3
3
  export declare const LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT = "[tool output redacted]";
4
4
  export declare function normalizeToolName(name: string): string;
5
+ export declare function hasLangfuseConfigCredentials(langfuse?: t.LangfuseConfig): langfuse is t.LangfuseConfig & {
6
+ publicKey: string;
7
+ secretKey: string;
8
+ };
9
+ export declare function hasLangfuseEnvCredentials(): boolean;
10
+ export declare function hasLangfuseEnvConfig(): boolean;
5
11
  export declare function hasToolOutputTracingConfig(runLangfuse?: t.LangfuseConfig, agentLangfuse?: t.LangfuseConfig): boolean;
6
12
  export declare function resolveToolOutputTracingConfig(runLangfuse?: t.LangfuseConfig, agentLangfuse?: t.LangfuseConfig): ResolvedLangfuseToolOutputTracingConfig;
7
13
  export declare function resolveLangfuseConfig(runLangfuse?: t.LangfuseConfig, agentLangfuse?: t.LangfuseConfig): t.LangfuseConfig | undefined;
@@ -9,6 +9,22 @@ export type LangfuseRuntimeContext = {
9
9
  langfuse?: t.LangfuseConfig;
10
10
  traceIdSeed?: string;
11
11
  toolOutputTracing?: ResolvedLangfuseToolOutputTracingConfig;
12
+ /**
13
+ * Identity of the run this scope belongs to. LangChain executes
14
+ * non-awaited callbacks on a shared background queue
15
+ * (`@langchain/core` `consumeCallback`, a process-wide `p-queue` with
16
+ * concurrency 1), so a callback can run inside a DIFFERENT concurrent
17
+ * run's async context. Handlers compare this id against their own run to
18
+ * decide whether an ambient scope is theirs to adopt.
19
+ */
20
+ runId?: string;
21
+ /**
22
+ * Identity of the agent whose overlay this scope carries, for per-agent
23
+ * scopes inside a run. Fan-out agents execute concurrently with distinct
24
+ * Langfuse overlays, so handlers additionally compare this against the
25
+ * agent a callback reports via its inherited `langgraph_node` metadata.
26
+ */
27
+ agentId?: string;
12
28
  };
13
29
  export declare function hasLangfuseRuntimeContextValue(context: LangfuseRuntimeContext): boolean;
14
30
  /** sha256(seed) -> first 32 hex chars; matches `@langfuse/tracing` `createTraceId`. */
@@ -16,11 +32,21 @@ export declare function traceIdFromSeed(seed: string): string;
16
32
  export declare function getLangfuseRuntimeContext(): LangfuseRuntimeContext | undefined;
17
33
  export declare function getLangfuseRuntimeConfig(): t.LangfuseConfig | undefined;
18
34
  export declare function getTraceIdSeed(): string | undefined;
35
+ export declare function getLangfuseScopeRunId(): string | undefined;
36
+ export declare function getLangfuseScopeAgentId(): string | undefined;
19
37
  export declare function getLangfuseRuntimeToolOutputTracingConfig(): ResolvedLangfuseToolOutputTracingConfig | undefined;
20
38
  /**
21
39
  * Runs `fn` with a merged Langfuse runtime context. Undefined fields inherit
22
40
  * from the parent scope; callers intentionally cannot clear parent values by
23
- * passing `undefined`.
41
+ * passing `undefined` — use `replaceLangfuseRuntimeContext` when the parent
42
+ * scope must NOT leak through (a foreign concurrent run's scope).
24
43
  */
25
44
  export declare function runWithLangfuseRuntimeContext<T>(context: LangfuseRuntimeContext, fn: () => T): T;
45
+ /**
46
+ * Runs `fn` with EXACTLY the provided context — the surrounding scope's
47
+ * fields do not leak through. A rejected foreign run's explicit destination
48
+ * or seed must not survive via merge inheritance when this run has none of
49
+ * its own (env-credential runs, non-deterministic runs).
50
+ */
51
+ export declare function replaceLangfuseRuntimeContext<T>(context: LangfuseRuntimeContext, fn: () => T): T;
26
52
  export declare function runWithTraceIdSeed<T>(seed: string | undefined, fn: () => T): T;
@@ -6,12 +6,27 @@ export type ResolveLangfuseRuntimeScopeParams = {
6
6
  runLangfuse?: t.LangfuseConfig;
7
7
  langfuseOverlay?: t.LangfuseConfig;
8
8
  traceIdSeed?: string;
9
+ runId?: string;
10
+ agentId?: string;
11
+ };
12
+ export type LangfuseRuntimeScopeOptions = {
13
+ /** Replace the surrounding scope entirely instead of merging with it:
14
+ * fields absent from `scope` are CLEARED rather than inherited. Required
15
+ * when rejecting a foreign concurrent run's scope, whose explicit values
16
+ * must not survive merge inheritance. */
17
+ replace?: boolean;
9
18
  };
10
19
  export declare function getOtelLangfuseConfig(activeContext: Context): t.LangfuseConfig | undefined;
11
20
  export declare function getOtelTraceIdSeed(activeContext: Context): string | undefined;
12
21
  export declare function getOtelToolOutputTracingConfig(activeContext: Context): ResolvedLangfuseToolOutputTracingConfig | undefined;
13
22
  export declare function resolveLangfuseConfigForSpan(activeContext: Context): t.LangfuseConfig | undefined;
14
23
  export declare function resolveTraceIdSeedForSpan(activeContext: Context): string | undefined;
24
+ /** The run identity the active scope belongs to (see
25
+ * `LangfuseRuntimeContext.runId`), or `undefined` for unstamped scopes. */
26
+ export declare function resolveLangfuseScopeRunId(activeContext: Context): string | undefined;
27
+ /** The agent identity of a per-agent overlay scope (see
28
+ * `LangfuseRuntimeContext.agentId`), or `undefined` for run-level scopes. */
29
+ export declare function resolveLangfuseScopeAgentId(activeContext: Context): string | undefined;
15
30
  export declare function resolveToolOutputTracingConfigForSpan(activeContext: Context): ResolvedLangfuseToolOutputTracingConfig | undefined;
16
- export declare function withLangfuseRuntimeScope<T>(scope: LangfuseRuntimeScope, action: () => T): T;
17
- export declare function resolveLangfuseRuntimeScope({ runLangfuse, langfuseOverlay, traceIdSeed, }: ResolveLangfuseRuntimeScopeParams): LangfuseRuntimeScope;
31
+ export declare function withLangfuseRuntimeScope<T>(scope: LangfuseRuntimeScope, action: () => T, options?: LangfuseRuntimeScopeOptions): T;
32
+ export declare function resolveLangfuseRuntimeScope({ runLangfuse, langfuseOverlay, traceIdSeed, runId, agentId, }: ResolveLangfuseRuntimeScopeParams): LangfuseRuntimeScope;
@@ -0,0 +1,17 @@
1
+ import type { LangfuseSpanProcessorParams } from '@langfuse/otel';
2
+ import type { Span } from '@opentelemetry/api';
3
+ import type * as t from '@/types';
4
+ export declare function registerLangfuseManagedSpan(span: Span, destinationKey: string): void;
5
+ export declare function getLangfuseManagedSpanDestination(span: Span): string | undefined;
6
+ export declare function getLangfuseSpanProcessorParams(langfuse?: t.LangfuseConfig): LangfuseSpanProcessorParams | undefined;
7
+ /**
8
+ * Identity of an export destination (project credentials + endpoint +
9
+ * environment) only. Processor-level policies like `toolOutputTracing` are
10
+ * deliberately excluded: two spans exporting to the same project under
11
+ * different redaction settings still share a destination and may parent one
12
+ * another.
13
+ */
14
+ export declare function getLangfuseDestinationKey(params: LangfuseSpanProcessorParams): string;
15
+ /** The export destination a run with this config resolves to, or `undefined`
16
+ * when no Langfuse destination is configured. */
17
+ export declare function resolveLangfuseDestinationKey(langfuse?: t.LangfuseConfig): string | undefined;
@@ -11,7 +11,8 @@ export declare function shouldDropLangfuseSpan(spanName: string): boolean;
11
11
  * Reshapes spans per Langfuse-team feedback before export:
12
12
  * - `agent=<id>` / `tools=<id>` node names carry the ephemeral agent id
13
13
  * (`provider__model`) — strip it so switching models doesn't break
14
- * name-based logic (item 1).
14
+ * name-based logic (item 1). The outer workflow node is named with the
15
+ * bare agent id; ephemeral ids reduce to their stable sender name.
15
16
  * - LLM generation spans keep the provider client class name (`ChatOpenAI`,
16
17
  * `AzureChatOpenAI`, …); rename them to a provider-agnostic `llm` so the
17
18
  * name reflects the operation, not the model (the model stays on the
@@ -16,6 +16,7 @@ import { AnthropicMessageCreateParams, AnthropicToolResponse } from '../types';
16
16
  */
17
17
  export declare function normalizeAnthropicToolCallId(id: string): string;
18
18
  export declare function normalizeAnthropicToolCallId(id: string | undefined): string | undefined;
19
+ export declare function coerceAnthropicToolUseInput(input: unknown): Record<string, unknown>;
19
20
  export declare function _convertLangChainToolCallToAnthropic(toolCall: ToolCall): AnthropicToolResponse;
20
21
  /**
21
22
  * Formats messages as a prompt for the model.
@@ -114,6 +114,12 @@ interface FormatAgentMessagesOptions {
114
114
  export declare const labelContentByAgent: (contentParts: MessageContentComplex[], agentIdMap?: Record<number, string>, agentNames?: Record<string, string>, options?: {
115
115
  labelNonTransferContent?: boolean;
116
116
  }) => MessageContentComplex[];
117
+ type SummaryTokenAdjustment = {
118
+ original: number;
119
+ adjusted: number;
120
+ remainingChars: number;
121
+ totalChars: number;
122
+ };
117
123
  /**
118
124
  * Formats an array of messages for LangChain, handling tool calls and creating ToolMessage instances.
119
125
  *
@@ -133,14 +139,9 @@ export declare const formatAgentMessages: (payload: TPayload, indexTokenCountMap
133
139
  text: string;
134
140
  tokenCount: number;
135
141
  };
136
- /** When a summary boundary sliced content from a message, the token count
137
- * was proportionally reduced. Returned so the caller can log it. */
138
- boundaryTokenAdjustment?: {
139
- original: number;
140
- adjusted: number;
141
- remainingChars: number;
142
- totalChars: number;
143
- };
142
+ /** When a positional summary boundary sliced content from a message, the token
143
+ * count was proportionally reduced. Returned so the caller can log it. */
144
+ boundaryTokenAdjustment?: SummaryTokenAdjustment;
144
145
  };
145
146
  /**
146
147
  * Adds a value at key 0 for system messages and shifts all key indices by one in an indexTokenCountMap.
@@ -16,6 +16,13 @@ export type BuildActivityLabelPromptParams = {
16
16
  charLimit: number;
17
17
  thinkingExcerpts?: string[];
18
18
  lastAssistantText?: string;
19
+ /**
20
+ * Headers already committed for earlier batches in this run, in run order
21
+ * with the most recent last. Rendered ahead of the block context so the
22
+ * label continues the run's story instead of restating a line the user is
23
+ * already reading. Capped at {@link MAX_PREVIOUS_LABELS}.
24
+ */
25
+ previousLabels?: string[];
19
26
  /**
20
27
  * Resolved tool-output tracing policy. The label prompt becomes Langfuse
21
28
  * generation input, so outputs/errors excluded from tracing (global
@@ -28,4 +35,4 @@ export type BuildActivityLabelPromptParams = {
28
35
  * Builds the user prompt for a fast-model activity label. Pure — exported
29
36
  * for direct testing of redaction and truncation behavior.
30
37
  */
31
- export declare function buildActivityLabelPrompt({ entries, charLimit, thinkingExcerpts, lastAssistantText, redaction, }: BuildActivityLabelPromptParams): string;
38
+ export declare function buildActivityLabelPrompt({ entries, charLimit, thinkingExcerpts, lastAssistantText, previousLabels, redaction, }: BuildActivityLabelPromptParams): string;
@@ -227,7 +227,7 @@ export declare class Run<_T extends t.BaseGraphState> {
227
227
  * comes from `lastAssistantText`, content from reasoning excerpts and
228
228
  * tool entries.
229
229
  */
230
- generateActivityLabel({ provider, clientOptions, entries, thinkingExcerpts, lastAssistantText, prompt, charLimit, chainOptions, traceSeed, agentId, }: t.RunActivityLabelOptions): Promise<{
230
+ generateActivityLabel({ provider, clientOptions, entries, thinkingExcerpts, lastAssistantText, previousLabels, prompt, charLimit, chainOptions, traceSeed, agentId, }: t.RunActivityLabelOptions): Promise<{
231
231
  label?: string;
232
232
  }>;
233
233
  }
@@ -35,6 +35,7 @@ export interface SerializedSessionMessage {
35
35
  name?: string;
36
36
  toolCallId?: string;
37
37
  toolCalls?: JsonValue;
38
+ invalidToolCalls?: JsonValue;
38
39
  usageMetadata?: JsonObject;
39
40
  }
40
41
  export type SessionMessageEntry = SessionEntryBase<'message', {
@@ -129,6 +129,12 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
129
129
  private eagerEventToolExecutions?;
130
130
  /** Shared per-run per-tool turn counter used by eager and normal event dispatch. */
131
131
  private eagerEventToolUsageCount?;
132
+ /**
133
+ * Shared per-run eager prestart circuit breaker. Tool names added here
134
+ * (when a prestarted execution's args mismatch the final request) are no
135
+ * longer prestarted by the stream handler for the rest of the run.
136
+ */
137
+ private eagerEventToolSuppressions?;
132
138
  /** Agent ID for event-driven mode */
133
139
  private agentId?;
134
140
  /**
@@ -194,7 +200,7 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
194
200
  * other's in-flight state.
195
201
  */
196
202
  private anonBatchCounter;
197
- constructor({ tools, toolMap, name, tags, trace, runLangfuse, agentLangfuse, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, toolRegistry, sessions, eventDrivenMode, eagerEventToolExecution, eagerEventToolExecutions, eagerEventToolUsageCount, agentId, executingAgentId, directToolNames, interruptingToolNames, codeSessionToolNames, maxContextTokens, maxToolResultChars, hookRegistry, humanInTheLoop, toolOutputReferences, toolOutputRegistry, toolExecution, fileCheckpointer, }: t.ToolNodeConstructorParams);
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);
198
204
  invoke(input: any, options?: Partial<RunnableConfig>): Promise<any>;
199
205
  /**
200
206
  * Returns the run-scoped tool output registry, or `undefined` when
@@ -36,6 +36,14 @@ export type RunActivityLabelOptions = {
36
36
  thinkingExcerpts?: string[];
37
37
  /** Assistant's last text before the block (~200 chars), as intent context. */
38
38
  lastAssistantText?: string;
39
+ /**
40
+ * Headers already committed for earlier batches in this run (run order,
41
+ * most recent last). Continuity context: the prompt shows them so the new
42
+ * header extends the run's story instead of restating a line already on
43
+ * screen. Hosts should pass only COMMITTED labels — a pending slot's text
44
+ * is empty and a dropped fill never surfaced to the user.
45
+ */
46
+ previousLabels?: string[];
39
47
  /** Override for the default label system prompt. */
40
48
  prompt?: string;
41
49
  /** Per-entry serialization cap for the prompt. Default 600. */
@@ -151,6 +151,14 @@ export interface AskUserQuestionRequest {
151
151
  export interface AskUserQuestionInterruptPayload {
152
152
  type: 'ask_user_question';
153
153
  question: AskUserQuestionRequest;
154
+ /**
155
+ * The `tool_call_id` of the ask-tool call that raised this interrupt,
156
+ * when the tool body supplied it (see `askUserQuestion`'s `options`).
157
+ * Lets hosts attribute the question — and later the answer — to the
158
+ * exact tool-call content part instead of guessing by position, which
159
+ * mislabels cards when a model emits several ask calls in one turn.
160
+ */
161
+ tool_call_id?: string;
154
162
  }
155
163
  /**
156
164
  * Discriminated union of every interrupt payload the SDK raises. New
@@ -233,10 +233,29 @@ export type SummaryBoundary = {
233
233
  messageId: string;
234
234
  contentIndex: number;
235
235
  };
236
+ /**
237
+ * Semantic extent of a summary: the first source message compaction retained
238
+ * verbatim, meaning everything before it is covered. Distinct from `boundary`,
239
+ * which records where the block was emitted — a retained recency tail sits
240
+ * *before* the block's own position, so position alone cannot say what the
241
+ * summary replaced.
242
+ *
243
+ * Anchored to the retained side rather than the covered side so that a source
244
+ * message expanding into several messages (a steer splits an assistant entry
245
+ * into pre-steer, steer, and post-steer entries sharing one ID) stays whole:
246
+ * such a message is the retained anchor and survives intact.
247
+ */
248
+ export type SummaryCoverage = {
249
+ retainedFromMessageId: string;
250
+ };
236
251
  export type SummaryContentBlock = {
237
252
  type: ContentTypes.SUMMARY;
238
253
  content?: MessageContentComplex[];
254
+ /** Injection budget: provider output-token space when usage was reported, plus
255
+ * the wrapper added at injection time. Not comparable with per-message counts
256
+ * such as `indexTokenCountMap`, which are in the consumer's own tokenizer. */
239
257
  tokenCount?: number;
258
+ coverage?: SummaryCoverage;
240
259
  boundary?: SummaryBoundary;
241
260
  summaryVersion?: number;
242
261
  model?: string;
@@ -69,6 +69,28 @@ export type EagerEventToolCallChunkState = {
69
69
  argsText: string;
70
70
  index?: number;
71
71
  lastArgsFragment?: string;
72
+ /**
73
+ * Cumulative length of every observed args fragment — the length of the
74
+ * plain in-order concatenation that LangChain's `AIMessageChunk.concat`
75
+ * performs to build the final tool call. Every reconciliation branch in
76
+ * `mergeToolCallArgsText` (and the repeat-fragment dedupe) produces text no
77
+ * longer than plain concatenation, with equality exactly when every merge
78
+ * was a pure append — so `argsText.length === rawArgsLength` proves
79
+ * `argsText` IS the canonical accumulation the final request will carry.
80
+ * Tracking only the length keeps cumulative/restating streams from
81
+ * retaining every prefix (quadratic growth) while still letting seal-time
82
+ * prestart verify the snapshot.
83
+ */
84
+ rawArgsLength?: number;
85
+ /**
86
+ * The non-empty args fragment carried by a chunk whose explicit adapter
87
+ * seal covered this call. Some adapters restate the finished call's full
88
+ * args on the seal chunk (OpenAI Responses `function_call_arguments.done`);
89
+ * only such a restatement may override the canonical-accumulation check at
90
+ * seal time. Pure-signal seals (Bedrock `contentBlockStop`, `args: ''`)
91
+ * never set this.
92
+ */
93
+ sealedArgsFragment?: string;
72
94
  };
73
95
  export type ToolNodeOptions = {
74
96
  name?: string;
@@ -146,6 +168,14 @@ export type ToolNodeOptions = {
146
168
  eagerEventToolExecutions?: Map<string, EagerEventToolExecution>;
147
169
  /** Shared per-run per-tool turn counter used by eager and normal event dispatch. */
148
170
  eagerEventToolUsageCount?: Map<string, number>;
171
+ /**
172
+ * Shared per-run circuit breaker for eager prestart. When a prestarted
173
+ * execution's args turn out to differ from the final request ("changed
174
+ * after eager execution started"), the ToolNode adds the tool name here
175
+ * and the stream handler stops prestarting that tool for the remainder of
176
+ * the run, so the model's retry executes normally instead of looping.
177
+ */
178
+ eagerEventToolSuppressions?: Set<string>;
149
179
  /**
150
180
  * Hook registry for PreToolUse/PostToolUse/PostToolUseFailure/
151
181
  * PermissionDenied lifecycle hooks. Fires for **every** tool the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.3.7",
3
+ "version": "3.3.9",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -199,7 +199,9 @@
199
199
  "re": "bun run clean && bun install && rm -rf ./dist && turbo build",
200
200
  "lint": "eslint \"{,!(node_modules|venv)/**/}*.{js,jsx,ts,tsx}\" --fix",
201
201
  "format": "prettier --write .",
202
- "audit": "npm audit --omit=dev"
202
+ "audit": "npm audit --omit=dev",
203
+ "label:eval": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/activity-labels/run.ts",
204
+ "label:rescore": "node ./src/scripts/activity-labels/rescore.cjs"
203
205
  },
204
206
  "overrides": {
205
207
  "@langchain/openai": "1.5.5",
@@ -224,17 +226,17 @@
224
226
  "@langchain/google-gauth": "2.2.0",
225
227
  "@langchain/google-genai": "2.2.0",
226
228
  "@langchain/google-vertexai": "2.2.0",
227
- "@langchain/langgraph": "^1.4.6",
229
+ "@langchain/langgraph": "1.4.8",
228
230
  "@langchain/mistralai": "^1.2.0",
229
231
  "@langchain/openai": "1.5.5",
230
232
  "@langchain/textsplitters": "^1.0.1",
231
233
  "@langchain/xai": "^1.4.3",
234
+ "@langfuse/core": "^5.4.1",
232
235
  "@langfuse/langchain": "^5.4.1",
233
236
  "@langfuse/otel": "^5.4.1",
234
237
  "@langfuse/tracing": "^5.4.1",
235
238
  "@opentelemetry/context-async-hooks": "^2.9.0",
236
239
  "@opentelemetry/sdk-node": "^0.220.0",
237
- "@scarf/scarf": "^1.4.0",
238
240
  "@types/diff": "^7.0.2",
239
241
  "ai-tokenizer": "^1.0.6",
240
242
  "axios": "^1.18.1",
@@ -246,6 +248,7 @@
246
248
  "nanoid": "^3.3.7",
247
249
  "okapibm25": "^1.4.1",
248
250
  "openai": "^6.46.0",
251
+ "reo-census": "^1.2.9",
249
252
  "uuid": "^11.1.1"
250
253
  },
251
254
  "peerDependencies": {