@librechat/agents 3.3.8 → 3.3.10
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 +4 -0
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +66 -13
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +35 -2
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/hitl/askUserQuestion.cjs +3 -2
- package/dist/cjs/hitl/askUserQuestion.cjs.map +1 -1
- package/dist/cjs/instrumentation.cjs +18 -48
- package/dist/cjs/instrumentation.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +174 -29
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/langfuseConfig.cjs +12 -0
- package/dist/cjs/langfuseConfig.cjs.map +1 -1
- package/dist/cjs/langfuseRuntimeContext.cjs +23 -2
- package/dist/cjs/langfuseRuntimeContext.cjs.map +1 -1
- package/dist/cjs/langfuseRuntimeScope.cjs +39 -8
- package/dist/cjs/langfuseRuntimeScope.cjs.map +1 -1
- package/dist/cjs/langfuseSpanRegistry.cjs +95 -0
- package/dist/cjs/langfuseSpanRegistry.cjs.map +1 -0
- package/dist/cjs/langfuseTraceShaping.cjs +121 -4
- package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +39 -15
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +25 -5
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +3 -3
- package/dist/cjs/llm/invoke.cjs +5 -5
- package/dist/cjs/llm/openai/index.cjs +1 -1
- package/dist/cjs/main.cjs +10 -10
- package/dist/cjs/messages/prune.cjs +13 -1
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/prompts/activityLabel.cjs +24 -12
- package/dist/cjs/prompts/activityLabel.cjs.map +1 -1
- package/dist/cjs/run.cjs +57 -22
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/messageSerialization.cjs +6 -0
- package/dist/cjs/session/messageSerialization.cjs.map +1 -1
- package/dist/cjs/stream.cjs +21 -10
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +5 -0
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +253 -24
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/handlers.cjs +1 -1
- package/dist/cjs/tools/search/tool.cjs +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1 -1
- package/dist/cjs/utils/index.cjs +2 -2
- package/dist/esm/agents/AgentContext.mjs +4 -0
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +67 -14
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +35 -2
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/hitl/askUserQuestion.mjs +3 -2
- package/dist/esm/hitl/askUserQuestion.mjs.map +1 -1
- package/dist/esm/instrumentation.mjs +18 -48
- package/dist/esm/instrumentation.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +176 -28
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/langfuseConfig.mjs +10 -1
- package/dist/esm/langfuseConfig.mjs.map +1 -1
- package/dist/esm/langfuseRuntimeContext.mjs +21 -3
- package/dist/esm/langfuseRuntimeContext.mjs.map +1 -1
- package/dist/esm/langfuseRuntimeScope.mjs +39 -10
- package/dist/esm/langfuseRuntimeScope.mjs.map +1 -1
- package/dist/esm/langfuseSpanRegistry.mjs +91 -0
- package/dist/esm/langfuseSpanRegistry.mjs.map +1 -0
- package/dist/esm/langfuseTraceShaping.mjs +121 -4
- package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +39 -15
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +25 -5
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +2 -2
- package/dist/esm/llm/invoke.mjs +5 -5
- package/dist/esm/llm/openai/index.mjs +1 -1
- package/dist/esm/main.mjs +8 -8
- package/dist/esm/messages/prune.mjs +13 -1
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/prompts/activityLabel.mjs +24 -12
- package/dist/esm/prompts/activityLabel.mjs.map +1 -1
- package/dist/esm/run.mjs +57 -22
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/messageSerialization.mjs +6 -0
- package/dist/esm/session/messageSerialization.mjs.map +1 -1
- package/dist/esm/stream.mjs +21 -10
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +5 -0
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +254 -25
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/handlers.mjs +1 -1
- package/dist/esm/tools/search/tool.mjs +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +1 -1
- package/dist/esm/utils/index.mjs +2 -2
- package/dist/types/agents/AgentContext.d.ts +2 -0
- package/dist/types/graphs/Graph.d.ts +24 -0
- package/dist/types/hitl/askUserQuestion.d.ts +11 -1
- package/dist/types/langfuse.d.ts +16 -8
- package/dist/types/langfuseConfig.d.ts +6 -0
- package/dist/types/langfuseRuntimeContext.d.ts +27 -1
- package/dist/types/langfuseRuntimeScope.d.ts +17 -2
- package/dist/types/langfuseSpanRegistry.d.ts +17 -0
- package/dist/types/langfuseTraceShaping.d.ts +2 -1
- package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -0
- package/dist/types/run.d.ts +7 -0
- package/dist/types/session/types.d.ts +1 -0
- package/dist/types/tools/ToolNode.d.ts +7 -1
- package/dist/types/types/hitl.d.ts +8 -0
- package/dist/types/types/tools.d.ts +30 -0
- package/package.json +7 -4
- package/src/__tests__/stream.eagerArgsDivergence.test.ts +753 -0
- package/src/agents/AgentContext.ts +5 -0
- package/src/graphs/Graph.ts +108 -20
- package/src/graphs/MultiAgentGraph.ts +56 -2
- package/src/graphs/__tests__/composition.smoke.test.ts +4 -0
- package/src/hitl/askUserQuestion.ts +14 -1
- package/src/instrumentation.ts +35 -77
- package/src/langfuse.ts +320 -43
- package/src/langfuseConfig.ts +24 -0
- package/src/langfuseRuntimeContext.ts +43 -1
- package/src/langfuseRuntimeScope.ts +94 -21
- package/src/langfuseSpanRegistry.ts +131 -0
- package/src/langfuseTraceShaping.ts +194 -7
- package/src/llm/anthropic/utils/message_inputs.ts +70 -19
- package/src/llm/anthropic/utils/streaming-tool-input.test.ts +186 -11
- package/src/llm/bedrock/utils/message_inputs.test.ts +120 -4
- package/src/llm/bedrock/utils/message_inputs.ts +32 -7
- package/src/messages/prune.ts +12 -1
- package/src/prompts/activityLabel.ts +23 -6
- package/src/run.ts +91 -45
- package/src/scripts/activity-labels/captured.json +56 -0
- package/src/scripts/activity-labels/checks.cjs +205 -0
- package/src/scripts/activity-labels/corpus.cjs +473 -0
- package/src/scripts/activity-labels/report.cjs +203 -0
- package/src/scripts/activity-labels/rescore.cjs +102 -0
- package/src/scripts/activity-labels/run.ts +705 -0
- package/src/scripts/activity-labels/variants.ts +71 -0
- package/src/session/messageSerialization.ts +12 -1
- package/src/session/types.ts +1 -0
- package/src/specs/activity-label-prompt.test.ts +26 -10
- package/src/specs/agent-handoffs.test.ts +306 -0
- package/src/specs/discovered-tools.test.ts +217 -0
- package/src/specs/langfuse-callbacks.test.ts +456 -0
- package/src/specs/langfuse-routing.integration.test.ts +138 -1
- package/src/specs/langfuse-span-registry.test.ts +70 -0
- package/src/specs/langfuse-trace-shaping.test.ts +294 -0
- package/src/specs/prune.test.ts +38 -1
- package/src/stream.ts +70 -6
- package/src/summarization/node.ts +5 -0
- package/src/tools/ToolNode.ts +400 -9
- package/src/tools/__tests__/ToolNode.invalidToolCalls.test.ts +757 -0
- package/src/tools/__tests__/hitl.test.ts +58 -0
- package/src/types/hitl.ts +8 -0
- package/src/types/tools.ts +35 -1
package/src/stream.ts
CHANGED
|
@@ -162,6 +162,13 @@ function isEagerExecutionExcludedTool(
|
|
|
162
162
|
if (excluded != null && excluded.includes(name)) {
|
|
163
163
|
return true;
|
|
164
164
|
}
|
|
165
|
+
// Run-scoped circuit breaker: once a prestart for this tool diverged from
|
|
166
|
+
// the final request ("changed after eager execution started"), stop
|
|
167
|
+
// prestarting it so the model's retry executes normally instead of
|
|
168
|
+
// re-diverging in a loop (LibreChat#14371).
|
|
169
|
+
if (graph.eagerEventToolSuppressions?.has(name) === true) {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
165
172
|
// A code-session participant writes to the shared sandbox, so it is
|
|
166
173
|
// side-effecting: never prestart it speculatively (a revised/superseded turn
|
|
167
174
|
// would leave the write applied). Implies exclusion without the host having
|
|
@@ -1006,8 +1013,9 @@ function recordEagerToolCallChunks(args: {
|
|
|
1006
1013
|
graph: StandardGraph;
|
|
1007
1014
|
stepKey: string;
|
|
1008
1015
|
toolCallChunks?: ToolCallChunk[];
|
|
1016
|
+
seal?: StreamedToolCallSeal;
|
|
1009
1017
|
}): void {
|
|
1010
|
-
const { graph, stepKey, toolCallChunks } = args;
|
|
1018
|
+
const { graph, stepKey, toolCallChunks, seal } = args;
|
|
1011
1019
|
if (toolCallChunks == null || toolCallChunks.length === 0) {
|
|
1012
1020
|
return;
|
|
1013
1021
|
}
|
|
@@ -1054,13 +1062,33 @@ function recordEagerToolCallChunks(args: {
|
|
|
1054
1062
|
const argsText = isRepeatedObservedFragment
|
|
1055
1063
|
? existing.argsText
|
|
1056
1064
|
: mergeToolCallArgsText(existing.argsText, incomingArgs);
|
|
1065
|
+
const index = getEagerToolChunkIndex(toolCallChunk) ?? existing.index;
|
|
1066
|
+
// Only a chunk whose explicit adapter seal covers THIS call may supply a
|
|
1067
|
+
// full-args restatement (OpenAI Responses `arguments.done`). Pure-signal
|
|
1068
|
+
// seals carry empty args and never set this.
|
|
1069
|
+
const sealCoversChunk =
|
|
1070
|
+
seal != null &&
|
|
1071
|
+
(seal.kind === 'all' ||
|
|
1072
|
+
(seal.kind === 'single' &&
|
|
1073
|
+
((seal.id != null && seal.id === id) ||
|
|
1074
|
+
(seal.index != null && seal.index === index))));
|
|
1057
1075
|
const next = {
|
|
1058
1076
|
id,
|
|
1059
1077
|
name,
|
|
1060
1078
|
argsText,
|
|
1061
|
-
|
|
1079
|
+
// Canonical accumulation length: LangChain concats fragments verbatim
|
|
1080
|
+
// to build the final request, and every reconciliation branch above
|
|
1081
|
+
// yields text no longer than that concat — equal exactly when every
|
|
1082
|
+
// merge was a pure append. Tracking the length (not the text) keeps
|
|
1083
|
+
// cumulative/restating streams from retaining every prefix.
|
|
1084
|
+
rawArgsLength: (existing.rawArgsLength ?? 0) + incomingArgs.length,
|
|
1085
|
+
index,
|
|
1062
1086
|
lastArgsFragment:
|
|
1063
1087
|
incomingArgs !== '' ? incomingArgs : existing.lastArgsFragment,
|
|
1088
|
+
sealedArgsFragment:
|
|
1089
|
+
sealCoversChunk && incomingArgs !== ''
|
|
1090
|
+
? incomingArgs
|
|
1091
|
+
: existing.sealedArgsFragment,
|
|
1064
1092
|
};
|
|
1065
1093
|
graph.eagerEventToolCallChunks.set(key, next);
|
|
1066
1094
|
}
|
|
@@ -1095,6 +1123,7 @@ function getStreamedReadyToolCalls(args: {
|
|
|
1095
1123
|
const readyEntries: Array<{
|
|
1096
1124
|
key: string;
|
|
1097
1125
|
state: t.EagerEventToolCallChunkState;
|
|
1126
|
+
sealedByAdapter: boolean;
|
|
1098
1127
|
}> = [];
|
|
1099
1128
|
|
|
1100
1129
|
for (const [key, state] of graph.eagerEventToolCallChunks) {
|
|
@@ -1124,7 +1153,11 @@ function getStreamedReadyToolCalls(args: {
|
|
|
1124
1153
|
isSealedByLaterChunk ||
|
|
1125
1154
|
isSealedExplicitly
|
|
1126
1155
|
) {
|
|
1127
|
-
readyEntries.push({
|
|
1156
|
+
readyEntries.push({
|
|
1157
|
+
key,
|
|
1158
|
+
state,
|
|
1159
|
+
sealedByAdapter: isSealedExplicitly || seal?.kind === 'all',
|
|
1160
|
+
});
|
|
1128
1161
|
}
|
|
1129
1162
|
}
|
|
1130
1163
|
|
|
@@ -1143,11 +1176,37 @@ function getStreamedReadyToolCalls(args: {
|
|
|
1143
1176
|
|
|
1144
1177
|
return readyEntries
|
|
1145
1178
|
.sort((left, right) => (left.state.index ?? 0) - (right.state.index ?? 0))
|
|
1146
|
-
.flatMap(({ state }) => {
|
|
1179
|
+
.flatMap(({ state, sealedByAdapter }) => {
|
|
1147
1180
|
const args = coerceRecordArgs(state.argsText);
|
|
1148
1181
|
if (args == null) {
|
|
1149
1182
|
return [];
|
|
1150
1183
|
}
|
|
1184
|
+
// The final request's args come from LangChain's canonical verbatim
|
|
1185
|
+
// concatenation of fragments, while `argsText` reconciles provider
|
|
1186
|
+
// quirks with lossy heuristics that can also swallow legitimately
|
|
1187
|
+
// repetitive payload fragments (LibreChat#14371). `argsText` can never
|
|
1188
|
+
// be LONGER than the plain concat, so length equality proves it IS the
|
|
1189
|
+
// canonical accumulation.
|
|
1190
|
+
const isCanonicalAccumulation =
|
|
1191
|
+
state.rawArgsLength != null &&
|
|
1192
|
+
state.argsText.length === state.rawArgsLength;
|
|
1193
|
+
// Adapter seals may instead restate the finished call's full args on
|
|
1194
|
+
// the seal chunk itself (OpenAI Responses
|
|
1195
|
+
// `function_call_arguments.done`). Only when the seal-carrying chunk
|
|
1196
|
+
// supplied that fragment AND the accumulated text IS that restatement
|
|
1197
|
+
// has the adapter vouched for it — plain concatenation intentionally
|
|
1198
|
+
// differs there. Pure-signal seals (Bedrock contentBlockStop,
|
|
1199
|
+
// `args: ''`) never qualify.
|
|
1200
|
+
const isAuthoritativeRestatement =
|
|
1201
|
+
sealedByAdapter &&
|
|
1202
|
+
state.sealedArgsFragment != null &&
|
|
1203
|
+
state.sealedArgsFragment === state.argsText;
|
|
1204
|
+
// Prestarting an unconfirmed snapshot trips the "changed after eager
|
|
1205
|
+
// execution started" guard and burns a retry loop — leave unconfirmed
|
|
1206
|
+
// calls to normal ToolNode execution with final args.
|
|
1207
|
+
if (!isCanonicalAccumulation && !isAuthoritativeRestatement) {
|
|
1208
|
+
return [];
|
|
1209
|
+
}
|
|
1151
1210
|
return [
|
|
1152
1211
|
{
|
|
1153
1212
|
id: state.id,
|
|
@@ -1586,6 +1645,7 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
1586
1645
|
graph,
|
|
1587
1646
|
stepKey,
|
|
1588
1647
|
toolCallChunks: chunk.tool_call_chunks,
|
|
1648
|
+
seal: streamedToolCallSeal,
|
|
1589
1649
|
});
|
|
1590
1650
|
}
|
|
1591
1651
|
await handleToolCallChunks({
|
|
@@ -2325,7 +2385,9 @@ export function createContentAggregator(): t.ContentAggregatorResult {
|
|
|
2325
2385
|
return;
|
|
2326
2386
|
}
|
|
2327
2387
|
|
|
2328
|
-
for (const contentPart of getDeltaContentParts(
|
|
2388
|
+
for (const contentPart of getDeltaContentParts(
|
|
2389
|
+
messageDelta.delta.content
|
|
2390
|
+
)) {
|
|
2329
2391
|
updateContent(runStep.index, contentPart);
|
|
2330
2392
|
}
|
|
2331
2393
|
} else if (
|
|
@@ -2354,7 +2416,9 @@ export function createContentAggregator(): t.ContentAggregatorResult {
|
|
|
2354
2416
|
return;
|
|
2355
2417
|
}
|
|
2356
2418
|
|
|
2357
|
-
for (const contentPart of getDeltaContentParts(
|
|
2419
|
+
for (const contentPart of getDeltaContentParts(
|
|
2420
|
+
reasoningDelta.delta.content
|
|
2421
|
+
)) {
|
|
2358
2422
|
updateContent(runStep.index, contentPart);
|
|
2359
2423
|
}
|
|
2360
2424
|
} else if (event === GraphEvents.ON_RUN_STEP_DELTA) {
|
|
@@ -1091,6 +1091,11 @@ export function createSummarizeNode({
|
|
|
1091
1091
|
metadata: {
|
|
1092
1092
|
...config.metadata,
|
|
1093
1093
|
agent_id: request.agentId,
|
|
1094
|
+
/** Canonical agent-identity key, overwritten by every component
|
|
1095
|
+
* that stamps identity (graph model path, ToolNode, here) so the
|
|
1096
|
+
* closest stamper always wins via spread order — Langfuse scope
|
|
1097
|
+
* trust relies on it (see `isForeignScope`). */
|
|
1098
|
+
agentId: request.agentId,
|
|
1094
1099
|
summarization_provider: clientConfig.provider,
|
|
1095
1100
|
summarization_model: clientConfig.modelName,
|
|
1096
1101
|
/**
|