@librechat/agents 3.2.68 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/agents/AgentContext.cjs +117 -3
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/enum.cjs +4 -0
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +243 -49
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +103 -28
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/langfuseToolOutputTracing.cjs +4 -0
- package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +11 -2
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/contextOverflowRecovery.cjs +132 -0
- package/dist/cjs/llm/contextOverflowRecovery.cjs.map +1 -0
- package/dist/cjs/llm/google/index.cjs +1 -1
- package/dist/cjs/llm/invoke.cjs +60 -3
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +1 -1
- package/dist/cjs/main.cjs +21 -7
- package/dist/cjs/messages/format.cjs +136 -4
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/prune.cjs +16 -5
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/messages/recency.cjs +2 -0
- package/dist/cjs/messages/recency.cjs.map +1 -1
- package/dist/cjs/prompts/activityLabel.cjs +101 -0
- package/dist/cjs/prompts/activityLabel.cjs.map +1 -0
- package/dist/cjs/run.cjs +177 -3
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +205 -49
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +55 -7
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +2 -2
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +2 -2
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +69 -8
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +19 -15
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +32 -3
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1 -1
- package/dist/cjs/utils/errors.cjs +317 -52
- package/dist/cjs/utils/errors.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +118 -4
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/enum.mjs +4 -0
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +242 -48
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +103 -28
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/langfuseToolOutputTracing.mjs +4 -1
- package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +11 -2
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/contextOverflowRecovery.mjs +130 -0
- package/dist/esm/llm/contextOverflowRecovery.mjs.map +1 -0
- package/dist/esm/llm/google/index.mjs +1 -1
- package/dist/esm/llm/invoke.mjs +59 -4
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +1 -1
- package/dist/esm/main.mjs +10 -10
- package/dist/esm/messages/format.mjs +136 -5
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/prune.mjs +14 -6
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/messages/recency.mjs +2 -1
- package/dist/esm/messages/recency.mjs.map +1 -1
- package/dist/esm/prompts/activityLabel.mjs +100 -0
- package/dist/esm/prompts/activityLabel.mjs.map +1 -0
- package/dist/esm/run.mjs +178 -4
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +205 -49
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +55 -7
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +3 -3
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +3 -3
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +62 -9
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +20 -16
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +32 -3
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +1 -1
- package/dist/esm/utils/errors.mjs +317 -53
- package/dist/esm/utils/errors.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +62 -3
- package/dist/types/common/enum.d.ts +5 -1
- package/dist/types/graphs/Graph.d.ts +16 -2
- package/dist/types/graphs/MultiAgentGraph.d.ts +1 -0
- package/dist/types/langfuseToolOutputTracing.d.ts +4 -0
- package/dist/types/llm/contextOverflowRecovery.d.ts +85 -0
- package/dist/types/llm/invoke.d.ts +35 -6
- package/dist/types/messages/format.d.ts +22 -0
- package/dist/types/messages/prune.d.ts +10 -2
- package/dist/types/messages/recency.d.ts +1 -0
- package/dist/types/prompts/activityLabel.d.ts +31 -0
- package/dist/types/run.d.ts +16 -0
- package/dist/types/tools/CodeExecutor.d.ts +14 -1
- package/dist/types/types/activityLabel.d.ts +53 -0
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/llm.d.ts +7 -4
- package/dist/types/types/stream.d.ts +7 -4
- package/dist/types/types/summarize.d.ts +22 -0
- package/dist/types/utils/__tests__/fixtures/contextOverflowSignatures.d.ts +40 -0
- package/dist/types/utils/errors.d.ts +65 -16
- package/dist/types/utils/redactSecrets.d.ts +3 -0
- package/package.json +7 -8
- package/src/agents/AgentContext.ts +188 -7
- package/src/agents/__tests__/AgentContext.overflow.test.ts +205 -0
- package/src/common/enum.ts +4 -0
- package/src/graphs/Graph.ts +409 -58
- package/src/graphs/MultiAgentGraph.ts +184 -46
- package/src/graphs/__tests__/Graph.contextOverflow.test.ts +631 -0
- package/src/langfuseToolOutputTracing.ts +4 -1
- package/src/llm/__tests__/contextOverflowRecovery.test.ts +401 -0
- package/src/llm/__tests__/fallbackOverflow.test.ts +287 -0
- package/src/llm/bedrock/index.ts +25 -12
- package/src/llm/contextOverflowRecovery.ts +292 -0
- package/src/llm/invoke.ts +119 -4
- package/src/messages/foldToollessToolBlocks.test.ts +438 -0
- package/src/messages/format.ts +233 -5
- package/src/messages/prune.ts +24 -11
- package/src/messages/recency.ts +3 -1
- package/src/prompts/activityLabel.ts +177 -0
- package/src/run.ts +322 -3
- package/src/scripts/context-overflow-probe.ts +997 -0
- package/src/specs/activity-label-prompt.test.ts +128 -0
- package/src/specs/activity-label-trace-seed.test.ts +47 -0
- package/src/specs/agent-handoffs.test.ts +903 -1
- package/src/specs/bedrock-toolless.live.test.ts +123 -0
- package/src/specs/context-overflow-recovery.live.test.ts +213 -0
- package/src/splitStream.test.ts +882 -0
- package/src/stream.ts +315 -51
- package/src/summarization/__tests__/aggregator.test.ts +83 -0
- package/src/summarization/__tests__/node.test.ts +139 -0
- package/src/summarization/node.ts +99 -14
- package/src/tools/BashExecutor.ts +4 -2
- package/src/tools/BashProgrammaticToolCalling.ts +4 -7
- package/src/tools/CodeExecutor.ts +119 -8
- package/src/tools/ProgrammaticToolCalling.ts +29 -27
- package/src/tools/ToolNode.ts +50 -8
- package/src/tools/__tests__/CodeApiAuthHeaders.test.ts +297 -3
- package/src/types/activityLabel.ts +55 -0
- package/src/types/index.ts +1 -0
- package/src/types/llm.ts +8 -1
- package/src/types/stream.ts +7 -4
- package/src/types/summarize.ts +22 -0
- package/src/utils/__tests__/errors.test.ts +270 -0
- package/src/utils/__tests__/fixtures/contextOverflowSignatures.ts +336 -0
- package/src/utils/__tests__/redactSecrets.test.ts +56 -0
- package/src/utils/errors.ts +484 -66
- package/src/utils/redactSecrets.ts +61 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const require_langfuseToolOutputTracing = require("../langfuseToolOutputTracing.cjs");
|
|
2
|
+
//#region src/prompts/activityLabel.ts
|
|
3
|
+
/**
|
|
4
|
+
* Default system prompt for fast-model activity labeling.
|
|
5
|
+
*
|
|
6
|
+
* Style synthesized from Claude Code's tool-use summary prompt (git-subject
|
|
7
|
+
* register, past tense, distinctive nouns) and claude.ai's observed group
|
|
8
|
+
* headers (5–9 words describing a mixed reasoning + tool block, e.g.
|
|
9
|
+
* "Synthesized version data and curated comparative framework").
|
|
10
|
+
*/
|
|
11
|
+
const ACTIVITY_LABEL_PROMPT = `Write a short label describing what this block of agent activity accomplished. It appears as the header of a collapsed activity group in a chat UI.
|
|
12
|
+
|
|
13
|
+
Rules:
|
|
14
|
+
- 5 to 9 words, past-tense verb first
|
|
15
|
+
- Name the most distinctive subject (file, API, topic); drop articles and filler
|
|
16
|
+
- Describe outcomes, not mechanics; if something failed, say so plainly
|
|
17
|
+
- Output only the label — no quotes, no punctuation at the end, no preamble
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
- Searched Node.js release notes and changelogs
|
|
21
|
+
- Compared runtime versions across official sources
|
|
22
|
+
- Fixed failing auth middleware tests
|
|
23
|
+
- Read project config and dependency manifests
|
|
24
|
+
- Attempted database migration, hit permission errors`;
|
|
25
|
+
/** Truncates a serialized value for the label prompt. */
|
|
26
|
+
function truncateForLabel(value, maxLength) {
|
|
27
|
+
if (value.length <= maxLength) return value;
|
|
28
|
+
return value.slice(0, Math.max(0, maxLength - 1)) + "…";
|
|
29
|
+
}
|
|
30
|
+
const ABORT_SERIALIZATION = Symbol("abort-label-serialization");
|
|
31
|
+
/**
|
|
32
|
+
* Serializes a tool value for the prompt WITHOUT materializing huge JSON:
|
|
33
|
+
* the output is clipped to a few hundred characters anyway, so a multi-
|
|
34
|
+
* megabyte tool result must not be stringified in full on the label path.
|
|
35
|
+
* Strings clip immediately; structured values serialize under a character
|
|
36
|
+
* budget and degrade to a shape summary once it is exhausted.
|
|
37
|
+
*/
|
|
38
|
+
function serializeForLabel(value, limit) {
|
|
39
|
+
if (value == null) return "";
|
|
40
|
+
if (typeof value === "string") return value.length > limit ? value.slice(0, limit + 1) : value;
|
|
41
|
+
let budget = limit * 4;
|
|
42
|
+
try {
|
|
43
|
+
return JSON.stringify(value, (_key, nested) => {
|
|
44
|
+
if (budget <= 0) throw ABORT_SERIALIZATION;
|
|
45
|
+
if (typeof nested === "string") {
|
|
46
|
+
const clipped = nested.length > limit ? nested.slice(0, limit) : nested;
|
|
47
|
+
budget -= clipped.length;
|
|
48
|
+
return clipped;
|
|
49
|
+
}
|
|
50
|
+
budget -= 8;
|
|
51
|
+
return nested;
|
|
52
|
+
}) ?? "";
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (error === ABORT_SERIALIZATION) return Array.isArray(value) ? `[Array(${value.length})]` : "[Object]";
|
|
55
|
+
return String(value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const INPUT_CONTEXT_LIMIT = 200;
|
|
59
|
+
const MAX_THINKING_EXCERPTS = 4;
|
|
60
|
+
/** A label is 5-9 words; no batch needs more than this many entries to
|
|
61
|
+
* produce one, and the cap keeps a 200-call programmatic batch from
|
|
62
|
+
* building an enormous prompt out of per-field-bounded pieces. */
|
|
63
|
+
const MAX_PROMPT_ENTRIES = 12;
|
|
64
|
+
/**
|
|
65
|
+
* Builds the user prompt for a fast-model activity label. Pure — exported
|
|
66
|
+
* for direct testing of redaction and truncation behavior.
|
|
67
|
+
*/
|
|
68
|
+
function buildActivityLabelPrompt({ entries, charLimit, thinkingExcerpts, lastAssistantText, redaction }) {
|
|
69
|
+
const clip = truncateForLabel;
|
|
70
|
+
/** Reasoning and intent text can quote tool output verbatim — including
|
|
71
|
+
* output from EARLIER calls to a redacted tool that this batch does not
|
|
72
|
+
* contain — so any active policy (global disable or a configured
|
|
73
|
+
* redacted-name list) drops both wholesale. There is no reliable way to
|
|
74
|
+
* scrub a quoted fragment out of free-form model prose. */
|
|
75
|
+
const excerptsRedacted = redaction != null && (redaction.enabled === false || redaction.redactedToolNames.size > 0);
|
|
76
|
+
const sections = [];
|
|
77
|
+
/** Intent text is free-form assistant prose that can quote a redacted
|
|
78
|
+
* tool result just as reasoning can, so it shares the excerpts' fate. */
|
|
79
|
+
if (!excerptsRedacted && lastAssistantText != null && lastAssistantText.length > 0) sections.push(`Intent (assistant's last message): ${clip(lastAssistantText, INPUT_CONTEXT_LIMIT)}`);
|
|
80
|
+
if (!excerptsRedacted && thinkingExcerpts != null && thinkingExcerpts.length > 0) sections.push("Reasoning excerpts:\n" + thinkingExcerpts.slice(0, MAX_THINKING_EXCERPTS).map((excerpt) => `- ${clip(excerpt, charLimit)}`).join("\n"));
|
|
81
|
+
if (entries.length > 0) {
|
|
82
|
+
const shown = entries.slice(0, MAX_PROMPT_ENTRIES);
|
|
83
|
+
const omitted = entries.length - shown.length;
|
|
84
|
+
sections.push("Tool calls:\n" + shown.map((entry) => {
|
|
85
|
+
const input = clip(serializeForLabel(entry.toolInput, charLimit), charLimit);
|
|
86
|
+
const redacted = redaction != null && require_langfuseToolOutputTracing.shouldRedactTool(entry.toolName, redaction);
|
|
87
|
+
let outcome;
|
|
88
|
+
if (redacted) outcome = redaction.redactionText;
|
|
89
|
+
else if (entry.status === "error") outcome = `ERROR: ${clip(entry.error ?? "unknown error", charLimit)}`;
|
|
90
|
+
else outcome = clip(serializeForLabel(entry.toolOutput, charLimit), charLimit);
|
|
91
|
+
return `- ${entry.toolName}(${input}) → ${outcome}`;
|
|
92
|
+
}).join("\n") + (omitted > 0 ? `\n- …and ${omitted} more tool ${omitted === 1 ? "call" : "calls"}` : ""));
|
|
93
|
+
}
|
|
94
|
+
sections.push("Label:");
|
|
95
|
+
return sections.join("\n\n");
|
|
96
|
+
}
|
|
97
|
+
//#endregion
|
|
98
|
+
exports.ACTIVITY_LABEL_PROMPT = ACTIVITY_LABEL_PROMPT;
|
|
99
|
+
exports.buildActivityLabelPrompt = buildActivityLabelPrompt;
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=activityLabel.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activityLabel.cjs","names":["shouldRedactTool"],"sources":["../../../src/prompts/activityLabel.ts"],"sourcesContent":["import type { ResolvedLangfuseToolOutputTracingConfig } from '@/langfuseRuntimeContext';\nimport type { ActivityLabelToolEntry } from '@/types/activityLabel';\nimport { shouldRedactTool } from '@/langfuseToolOutputTracing';\n\n/**\n * Default system prompt for fast-model activity labeling.\n *\n * Style synthesized from Claude Code's tool-use summary prompt (git-subject\n * register, past tense, distinctive nouns) and claude.ai's observed group\n * headers (5–9 words describing a mixed reasoning + tool block, e.g.\n * \"Synthesized version data and curated comparative framework\").\n */\nexport const ACTIVITY_LABEL_PROMPT = `Write a short label describing what this block of agent activity accomplished. It appears as the header of a collapsed activity group in a chat UI.\n\nRules:\n- 5 to 9 words, past-tense verb first\n- Name the most distinctive subject (file, API, topic); drop articles and filler\n- Describe outcomes, not mechanics; if something failed, say so plainly\n- Output only the label — no quotes, no punctuation at the end, no preamble\n\nExamples:\n- Searched Node.js release notes and changelogs\n- Compared runtime versions across official sources\n- Fixed failing auth middleware tests\n- Read project config and dependency manifests\n- Attempted database migration, hit permission errors`;\n\n/** Truncates a serialized value for the label prompt. */\nexport function truncateForLabel(value: string, maxLength: number): string {\n if (value.length <= maxLength) {\n return value;\n }\n return value.slice(0, Math.max(0, maxLength - 1)) + '…';\n}\n\nconst ABORT_SERIALIZATION = Symbol('abort-label-serialization');\n\n/**\n * Serializes a tool value for the prompt WITHOUT materializing huge JSON:\n * the output is clipped to a few hundred characters anyway, so a multi-\n * megabyte tool result must not be stringified in full on the label path.\n * Strings clip immediately; structured values serialize under a character\n * budget and degrade to a shape summary once it is exhausted.\n */\nfunction serializeForLabel(value: unknown, limit: number): string {\n if (value == null) {\n return '';\n }\n if (typeof value === 'string') {\n return value.length > limit ? value.slice(0, limit + 1) : value;\n }\n let budget = limit * 4;\n try {\n return (\n JSON.stringify(value, (_key, nested: unknown) => {\n if (budget <= 0) {\n throw ABORT_SERIALIZATION;\n }\n if (typeof nested === 'string') {\n const clipped =\n nested.length > limit ? nested.slice(0, limit) : nested;\n budget -= clipped.length;\n return clipped;\n }\n budget -= 8;\n return nested;\n }) ?? ''\n );\n } catch (error) {\n if (error === ABORT_SERIALIZATION) {\n return Array.isArray(value) ? `[Array(${value.length})]` : '[Object]';\n }\n return String(value);\n }\n}\n\nconst INPUT_CONTEXT_LIMIT = 200;\nconst MAX_THINKING_EXCERPTS = 4;\n/** A label is 5-9 words; no batch needs more than this many entries to\n * produce one, and the cap keeps a 200-call programmatic batch from\n * building an enormous prompt out of per-field-bounded pieces. */\nconst MAX_PROMPT_ENTRIES = 12;\n\nexport type BuildActivityLabelPromptParams = {\n entries: ActivityLabelToolEntry[];\n charLimit: number;\n thinkingExcerpts?: string[];\n lastAssistantText?: string;\n /**\n * Resolved tool-output tracing policy. The label prompt becomes Langfuse\n * generation input, so outputs/errors excluded from tracing (global\n * disable or `redactedToolNames`) must never appear in it — the same\n * redaction the span processor applies to structured tool observations.\n */\n redaction?: ResolvedLangfuseToolOutputTracingConfig;\n};\n\n/**\n * Builds the user prompt for a fast-model activity label. Pure — exported\n * for direct testing of redaction and truncation behavior.\n */\nexport function buildActivityLabelPrompt({\n entries,\n charLimit,\n thinkingExcerpts,\n lastAssistantText,\n redaction,\n}: BuildActivityLabelPromptParams): string {\n const clip = truncateForLabel;\n /** Reasoning and intent text can quote tool output verbatim — including\n * output from EARLIER calls to a redacted tool that this batch does not\n * contain — so any active policy (global disable or a configured\n * redacted-name list) drops both wholesale. There is no reliable way to\n * scrub a quoted fragment out of free-form model prose. */\n const excerptsRedacted =\n redaction != null &&\n (redaction.enabled === false || redaction.redactedToolNames.size > 0);\n const sections: string[] = [];\n /** Intent text is free-form assistant prose that can quote a redacted\n * tool result just as reasoning can, so it shares the excerpts' fate. */\n if (\n !excerptsRedacted &&\n lastAssistantText != null &&\n lastAssistantText.length > 0\n ) {\n sections.push(\n `Intent (assistant's last message): ${clip(lastAssistantText, INPUT_CONTEXT_LIMIT)}`\n );\n }\n if (\n !excerptsRedacted &&\n thinkingExcerpts != null &&\n thinkingExcerpts.length > 0\n ) {\n sections.push(\n 'Reasoning excerpts:\\n' +\n thinkingExcerpts\n .slice(0, MAX_THINKING_EXCERPTS)\n .map((excerpt) => `- ${clip(excerpt, charLimit)}`)\n .join('\\n')\n );\n }\n if (entries.length > 0) {\n const shown = entries.slice(0, MAX_PROMPT_ENTRIES);\n const omitted = entries.length - shown.length;\n sections.push(\n 'Tool calls:\\n' +\n shown\n .map((entry) => {\n const input = clip(\n serializeForLabel(entry.toolInput, charLimit),\n charLimit\n );\n const redacted =\n redaction != null && shouldRedactTool(entry.toolName, redaction);\n let outcome: string;\n if (redacted) {\n outcome = redaction.redactionText;\n } else if (entry.status === 'error') {\n outcome = `ERROR: ${clip(entry.error ?? 'unknown error', charLimit)}`;\n } else {\n outcome = clip(\n serializeForLabel(entry.toolOutput, charLimit),\n charLimit\n );\n }\n return `- ${entry.toolName}(${input}) → ${outcome}`;\n })\n .join('\\n') +\n (omitted > 0\n ? `\\n- …and ${omitted} more tool ${omitted === 1 ? 'call' : 'calls'}`\n : '')\n );\n }\n sections.push('Label:');\n return sections.join('\\n\\n');\n}\n"],"mappings":";;;;;;;;;;AAYA,MAAa,wBAAwB;;;;;;;;;;;;;;;AAgBrC,SAAgB,iBAAiB,OAAe,WAA2B;CACzE,IAAI,MAAM,UAAU,WAClB,OAAO;CAET,OAAO,MAAM,MAAM,GAAG,KAAK,IAAI,GAAG,YAAY,CAAC,CAAC,IAAI;AACtD;AAEA,MAAM,sBAAsB,OAAO,2BAA2B;;;;;;;;AAS9D,SAAS,kBAAkB,OAAgB,OAAuB;CAChE,IAAI,SAAS,MACX,OAAO;CAET,IAAI,OAAO,UAAU,UACnB,OAAO,MAAM,SAAS,QAAQ,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI;CAE5D,IAAI,SAAS,QAAQ;CACrB,IAAI;EACF,OACE,KAAK,UAAU,QAAQ,MAAM,WAAoB;GAC/C,IAAI,UAAU,GACZ,MAAM;GAER,IAAI,OAAO,WAAW,UAAU;IAC9B,MAAM,UACJ,OAAO,SAAS,QAAQ,OAAO,MAAM,GAAG,KAAK,IAAI;IACnD,UAAU,QAAQ;IAClB,OAAO;GACT;GACA,UAAU;GACV,OAAO;EACT,CAAC,KAAK;CAEV,SAAS,OAAO;EACd,IAAI,UAAU,qBACZ,OAAO,MAAM,QAAQ,KAAK,IAAI,UAAU,MAAM,OAAO,MAAM;EAE7D,OAAO,OAAO,KAAK;CACrB;AACF;AAEA,MAAM,sBAAsB;AAC5B,MAAM,wBAAwB;;;;AAI9B,MAAM,qBAAqB;;;;;AAoB3B,SAAgB,yBAAyB,EACvC,SACA,WACA,kBACA,mBACA,aACyC;CACzC,MAAM,OAAO;;;;;;CAMb,MAAM,mBACJ,aAAa,SACZ,UAAU,YAAY,SAAS,UAAU,kBAAkB,OAAO;CACrE,MAAM,WAAqB,CAAC;;;CAG5B,IACE,CAAC,oBACD,qBAAqB,QACrB,kBAAkB,SAAS,GAE3B,SAAS,KACP,sCAAsC,KAAK,mBAAmB,mBAAmB,GACnF;CAEF,IACE,CAAC,oBACD,oBAAoB,QACpB,iBAAiB,SAAS,GAE1B,SAAS,KACP,0BACE,iBACG,MAAM,GAAG,qBAAqB,CAAC,CAC/B,KAAK,YAAY,KAAK,KAAK,SAAS,SAAS,GAAG,CAAC,CACjD,KAAK,IAAI,CAChB;CAEF,IAAI,QAAQ,SAAS,GAAG;EACtB,MAAM,QAAQ,QAAQ,MAAM,GAAG,kBAAkB;EACjD,MAAM,UAAU,QAAQ,SAAS,MAAM;EACvC,SAAS,KACP,kBACE,MACG,KAAK,UAAU;GACd,MAAM,QAAQ,KACZ,kBAAkB,MAAM,WAAW,SAAS,GAC5C,SACF;GACA,MAAM,WACJ,aAAa,QAAQA,kCAAAA,iBAAiB,MAAM,UAAU,SAAS;GACjE,IAAI;GACJ,IAAI,UACF,UAAU,UAAU;QACf,IAAI,MAAM,WAAW,SAC1B,UAAU,UAAU,KAAK,MAAM,SAAS,iBAAiB,SAAS;QAElE,UAAU,KACR,kBAAkB,MAAM,YAAY,SAAS,GAC7C,SACF;GAEF,OAAO,KAAK,MAAM,SAAS,GAAG,MAAM,MAAM;EAC5C,CAAC,CAAC,CACD,KAAK,IAAI,KACX,UAAU,IACP,YAAY,QAAQ,aAAa,YAAY,IAAI,SAAS,YAC1D,GACR;CACF;CACA,SAAS,KAAK,QAAQ;CACtB,OAAO,SAAS,KAAK,MAAM;AAC7B"}
|
package/dist/cjs/run.cjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
const require_langfuseRuntimeContext = require("./langfuseRuntimeContext.cjs");
|
|
1
2
|
const require_langfuseConfig = require("./langfuseConfig.cjs");
|
|
2
3
|
const require_langfuseRuntimeScope = require("./langfuseRuntimeScope.cjs");
|
|
3
4
|
const require_langfuse = require("./langfuse.cjs");
|
|
5
|
+
const require_activityLabel = require("./prompts/activityLabel.cjs");
|
|
4
6
|
const require_callbacks = require("./utils/callbacks.cjs");
|
|
5
7
|
require("./common/enum.cjs");
|
|
6
8
|
require("./common/index.cjs");
|
|
@@ -9,16 +11,16 @@ const require_tokens = require("./utils/tokens.cjs");
|
|
|
9
11
|
const require_instrumentation = require("./instrumentation.cjs");
|
|
10
12
|
const require_llm = require("./utils/llm.cjs");
|
|
11
13
|
const require_events = require("./events.cjs");
|
|
14
|
+
const require_init = require("./llm/init.cjs");
|
|
12
15
|
const require_executeHooks = require("./hooks/executeHooks.cjs");
|
|
13
16
|
require("./hooks/index.cjs");
|
|
14
|
-
const require_init = require("./llm/init.cjs");
|
|
15
17
|
const require_Graph = require("./graphs/Graph.cjs");
|
|
16
18
|
const require_MultiAgentGraph = require("./graphs/MultiAgentGraph.cjs");
|
|
17
|
-
let _langchain_core_messages = require("@langchain/core/messages");
|
|
18
19
|
let _langchain_core_prompts = require("@langchain/core/prompts");
|
|
19
20
|
let _langchain_core_runnables = require("@langchain/core/runnables");
|
|
20
21
|
let _langchain_openai = require("@langchain/openai");
|
|
21
22
|
let _langchain_core_callbacks_base = require("@langchain/core/callbacks/base");
|
|
23
|
+
let _langchain_core_messages = require("@langchain/core/messages");
|
|
22
24
|
let _langchain_langgraph = require("@langchain/langgraph");
|
|
23
25
|
//#region src/run.ts
|
|
24
26
|
const defaultOmitOptions = new Set([
|
|
@@ -99,6 +101,10 @@ var Run = class Run {
|
|
|
99
101
|
* lets callers assert the type they expect.
|
|
100
102
|
*/
|
|
101
103
|
_interrupt;
|
|
104
|
+
/** Per-run sequence for batch-unique activity-label trace-seed fallbacks. */
|
|
105
|
+
activityLabelSeq = 0;
|
|
106
|
+
/** Distinguishes sibling forks started from the same explicit checkpoint. */
|
|
107
|
+
checkpointForkSeq = 0;
|
|
102
108
|
_haltedReason;
|
|
103
109
|
constructor(config) {
|
|
104
110
|
const runId = config.runId ?? "";
|
|
@@ -462,7 +468,18 @@ var Run = class Run {
|
|
|
462
468
|
* block so the sidecars survive both ends of the interrupt
|
|
463
469
|
* boundary.
|
|
464
470
|
*/
|
|
465
|
-
if (!isResume)
|
|
471
|
+
if (!isResume) {
|
|
472
|
+
const checkpointThreadId = typeof config.configurable?.thread_id === "string" ? config.configurable.thread_id : void 0;
|
|
473
|
+
const checkpointNamespace = typeof config.configurable?.checkpoint_ns === "string" ? config.configurable.checkpoint_ns : "";
|
|
474
|
+
const checkpointId = typeof config.configurable?.checkpoint_id === "string" ? config.configurable.checkpoint_id : "";
|
|
475
|
+
const checkpointScope = checkpointThreadId == null ? void 0 : JSON.stringify([
|
|
476
|
+
checkpointThreadId,
|
|
477
|
+
checkpointNamespace,
|
|
478
|
+
checkpointId,
|
|
479
|
+
checkpointId === "" ? 0 : ++this.checkpointForkSeq
|
|
480
|
+
]);
|
|
481
|
+
graph.resetValues(streamOptions?.keepContent, checkpointScope);
|
|
482
|
+
}
|
|
466
483
|
this._interrupt = void 0;
|
|
467
484
|
this._haltedReason = void 0;
|
|
468
485
|
this.hookRegistry?.clearHaltSignal(this.id);
|
|
@@ -960,6 +977,163 @@ var Run = class Run {
|
|
|
960
977
|
await require_langfuse.disposeLangfuseHandler(titleLangfuseHandler);
|
|
961
978
|
}
|
|
962
979
|
}
|
|
980
|
+
/**
|
|
981
|
+
* Generates a short activity label for a completed tool/reasoning block
|
|
982
|
+
* using a fast model. Mirrors `generateTitle`'s Langfuse wiring so the
|
|
983
|
+
* call is traced under the conversation's session (sessionId from
|
|
984
|
+
* `chainOptions.configurable.thread_id`) with its own tags — never as an
|
|
985
|
+
* orphan trace. The payload contains no human messages by design: intent
|
|
986
|
+
* comes from `lastAssistantText`, content from reasoning excerpts and
|
|
987
|
+
* tool entries.
|
|
988
|
+
*/
|
|
989
|
+
async generateActivityLabel({ provider, clientOptions, entries, thinkingExcerpts, lastAssistantText, prompt, charLimit = 600, chainOptions, traceSeed, agentId }) {
|
|
990
|
+
if (entries.length === 0 && !(thinkingExcerpts && thinkingExcerpts.length > 0)) return {};
|
|
991
|
+
const labelSeq = ++this.activityLabelSeq;
|
|
992
|
+
/** Resolve the LABELED agent's context: its Langfuse overlay carries the
|
|
993
|
+
* trace metadata and the tool-output redaction policy that must govern
|
|
994
|
+
* this label. */
|
|
995
|
+
const requestedContext = this.Graph == null || agentId == null ? void 0 : this.Graph.agentContexts.get(agentId);
|
|
996
|
+
/** Fail closed: an explicit but unknown/stale `agentId` must NOT silently
|
|
997
|
+
* fall back to the default agent, whose redaction policy may be weaker
|
|
998
|
+
* than the labeled agent's. Skip generation entirely instead. */
|
|
999
|
+
if (agentId != null && requestedContext == null) return {};
|
|
1000
|
+
const labelContext = this.Graph == null ? void 0 : requestedContext ?? this.Graph.agentContexts.get(this.Graph.defaultAgentId);
|
|
1001
|
+
const traceMetadata = require_langfuse.createLangfuseTraceMetadata({
|
|
1002
|
+
messageId: "activity-label-" + this.id,
|
|
1003
|
+
agentName: labelContext?.name
|
|
1004
|
+
});
|
|
1005
|
+
const labelRunName = require_langfuse.getLangfuseTraceName(traceMetadata, "LibreChat Activity Label");
|
|
1006
|
+
/** Shallow-cloned: activity labels run once per tool batch, and writing
|
|
1007
|
+
* the Langfuse handler back onto a host-reused `chainOptions` would
|
|
1008
|
+
* accumulate duplicate callbacks across batches. */
|
|
1009
|
+
const labelChainOptions = { ...chainOptions ?? {} };
|
|
1010
|
+
const labelUserId = typeof labelChainOptions.configurable?.user_id === "string" ? labelChainOptions.configurable.user_id : void 0;
|
|
1011
|
+
const labelSessionId = typeof labelChainOptions.configurable?.thread_id === "string" ? labelChainOptions.configurable.thread_id : void 0;
|
|
1012
|
+
const labelLangfuseConfig = require_langfuseConfig.resolveLangfuseConfig(this.langfuse, labelContext?.langfuse);
|
|
1013
|
+
require_instrumentation.initializeLangfuseTracing(labelLangfuseConfig);
|
|
1014
|
+
/** Seed policy, threading two constraints:
|
|
1015
|
+
* 1. `runWithLangfuseRuntimeContext` SPREADS the surrounding context, so
|
|
1016
|
+
* an absent seed INHERITS the parent run's and collapses every label
|
|
1017
|
+
* into that trace. When a parent seed is active we must override it
|
|
1018
|
+
* with a per-label one.
|
|
1019
|
+
* 2. Without deterministic tracing there is no parent seed, and forcing
|
|
1020
|
+
* one here would make label trace ids deterministic when neither
|
|
1021
|
+
* `processStream` nor `generateTitle` are — so leave it unset.
|
|
1022
|
+
* Seeded when determinism is opted into OR a parent seed is live;
|
|
1023
|
+
* otherwise unseeded, matching the other generation paths. */
|
|
1024
|
+
const inheritedTraceSeed = require_langfuseRuntimeContext.getTraceIdSeed();
|
|
1025
|
+
const labelTraceSeed = labelLangfuseConfig?.deterministicTraceId === true || inheritedTraceSeed != null ? traceSeed ?? `activity-label-${this.id}-${labelSeq}` : void 0;
|
|
1026
|
+
const labelRuntimeScope = require_langfuseRuntimeScope.resolveLangfuseRuntimeScope({
|
|
1027
|
+
runLangfuse: this.langfuse,
|
|
1028
|
+
langfuseOverlay: labelContext?.langfuse,
|
|
1029
|
+
traceIdSeed: labelTraceSeed
|
|
1030
|
+
});
|
|
1031
|
+
/** Handler only when a session id resolved from
|
|
1032
|
+
* `chainOptions.configurable.thread_id`: without it the label call has
|
|
1033
|
+
* no conversation identity, and tracing it would create an orphan
|
|
1034
|
+
* trace outside any session — worse than not tracing at all. */
|
|
1035
|
+
/** Declared then conditionally assigned (title precedent): a ternary
|
|
1036
|
+
* around the object literal makes eslint's indent rule and prettier
|
|
1037
|
+
* disagree, and both gate CI. */
|
|
1038
|
+
let labelLangfuseHandler;
|
|
1039
|
+
if (labelSessionId != null) labelLangfuseHandler = require_langfuse.createLangfuseHandler({
|
|
1040
|
+
langfuse: labelLangfuseConfig,
|
|
1041
|
+
userId: labelUserId,
|
|
1042
|
+
sessionId: labelSessionId,
|
|
1043
|
+
traceMetadata,
|
|
1044
|
+
tags: ["librechat", "activity-label"],
|
|
1045
|
+
traceIdSeed: labelLangfuseConfig?.deterministicTraceId === true ? labelTraceSeed : void 0
|
|
1046
|
+
});
|
|
1047
|
+
if (labelLangfuseHandler != null) labelChainOptions.callbacks = require_callbacks.appendCallbacks(labelChainOptions.callbacks, [labelLangfuseHandler]);
|
|
1048
|
+
/** The label prompt becomes Langfuse generation input, so the resolved
|
|
1049
|
+
* tool-output redaction policy (global disable / redactedToolNames)
|
|
1050
|
+
* applies to it exactly as to structured tool observations. */
|
|
1051
|
+
let redaction = require_langfuseConfig.hasToolOutputTracingConfig(this.langfuse, labelContext?.langfuse) ? require_langfuseConfig.resolveToolOutputTracingConfig(this.langfuse, labelContext?.langfuse) : void 0;
|
|
1052
|
+
/** Multi-agent graph with no `agentId`: the caller did not say WHICH
|
|
1053
|
+
* agent ran this batch, so resolving from the default agent could trace
|
|
1054
|
+
* raw output that a stricter sibling's policy forbids. Fold every
|
|
1055
|
+
* agent's policy into the strictest one instead of guessing. */
|
|
1056
|
+
const agentContexts = this.Graph?.agentContexts;
|
|
1057
|
+
if (agentId == null && agentContexts != null && agentContexts.size > 1) for (const context of agentContexts.values()) {
|
|
1058
|
+
if (!require_langfuseConfig.hasToolOutputTracingConfig(this.langfuse, context.langfuse)) continue;
|
|
1059
|
+
const candidate = require_langfuseConfig.resolveToolOutputTracingConfig(this.langfuse, context.langfuse);
|
|
1060
|
+
if (redaction == null) {
|
|
1061
|
+
redaction = candidate;
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
redaction = {
|
|
1065
|
+
enabled: redaction.enabled === false ? false : candidate.enabled,
|
|
1066
|
+
redactedToolNames: new Set([...redaction.redactedToolNames, ...candidate.redactedToolNames]),
|
|
1067
|
+
redactedToolNameMatchMode: redaction.redactedToolNameMatchMode === "partial" || candidate.redactedToolNameMatchMode === "partial" ? "partial" : "exact",
|
|
1068
|
+
redactionText: redaction.redactionText
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
/** An active redaction policy suppresses free-form reasoning/intent, so
|
|
1072
|
+
* a reasoning-only block has nothing describable left — skip the model
|
|
1073
|
+
* call rather than paying for a label built from the prompt alone. */
|
|
1074
|
+
const freeFormSuppressed = redaction != null && (redaction.enabled === false || redaction.redactedToolNames.size > 0);
|
|
1075
|
+
if (entries.length === 0 && freeFormSuppressed) return {};
|
|
1076
|
+
const userPrompt = require_activityLabel.buildActivityLabelPrompt({
|
|
1077
|
+
entries,
|
|
1078
|
+
charLimit,
|
|
1079
|
+
thinkingExcerpts,
|
|
1080
|
+
lastAssistantText,
|
|
1081
|
+
redaction
|
|
1082
|
+
});
|
|
1083
|
+
const model = require_init.initializeModel({
|
|
1084
|
+
provider,
|
|
1085
|
+
clientOptions: {
|
|
1086
|
+
...clientOptions ?? {},
|
|
1087
|
+
streaming: false
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
/** Distinct run id per label call: callback/tracing integrations key
|
|
1091
|
+
* in-flight runs by it, so reusing the parent run's id would collide
|
|
1092
|
+
* across successive (or concurrent) label batches. */
|
|
1093
|
+
const labelRunId = `${this.id}-activity-${labelSeq}`;
|
|
1094
|
+
const invokeConfig = Object.assign({}, labelChainOptions, {
|
|
1095
|
+
run_id: labelRunId,
|
|
1096
|
+
runId: labelRunId,
|
|
1097
|
+
runName: labelChainOptions.runName ?? labelRunName
|
|
1098
|
+
});
|
|
1099
|
+
const invokeLabel = (runtimeConfig) => require_langfuse.withLangfuseAttributes({
|
|
1100
|
+
langfuse: labelLangfuseConfig,
|
|
1101
|
+
userId: labelUserId,
|
|
1102
|
+
sessionId: labelSessionId,
|
|
1103
|
+
traceName: runtimeConfig.runName ?? labelRunName,
|
|
1104
|
+
traceMetadata,
|
|
1105
|
+
tags: ["librechat", "activity-label"]
|
|
1106
|
+
}, () => model.invoke([new _langchain_core_messages.SystemMessage(prompt ?? require_activityLabel.ACTIVITY_LABEL_PROMPT), new _langchain_core_messages.HumanMessage(userPrompt)], runtimeConfig));
|
|
1107
|
+
const extractLabel = (response) => {
|
|
1108
|
+
const content = response?.content;
|
|
1109
|
+
let text = "";
|
|
1110
|
+
if (typeof content === "string") text = content;
|
|
1111
|
+
else if (Array.isArray(content)) text = content.map((block) => typeof block === "string" ? block : block.text ?? "").join("");
|
|
1112
|
+
return text.trim().replace(/^["']|["']$/g, "");
|
|
1113
|
+
};
|
|
1114
|
+
try {
|
|
1115
|
+
let response;
|
|
1116
|
+
try {
|
|
1117
|
+
response = await require_langfuseRuntimeScope.withLangfuseRuntimeScope(labelRuntimeScope, () => invokeLabel(invokeConfig));
|
|
1118
|
+
} catch (error) {
|
|
1119
|
+
/** Retry ONLY recognized callback/tracer failures (the EventStream
|
|
1120
|
+
* tracer class of errors the stripped-callbacks fallback exists
|
|
1121
|
+
* for). Aborts and provider failures rethrow — retrying those
|
|
1122
|
+
* doubles traffic/cost and can restart cancelled requests. */
|
|
1123
|
+
const aborted = labelChainOptions.signal?.aborted === true || error?.name === "AbortError";
|
|
1124
|
+
const callbackFailure = /callback|tracer|event.?stream/i.test(String(error?.stack ?? error?.message ?? ""));
|
|
1125
|
+
if (aborted || !callbackFailure) throw error;
|
|
1126
|
+
const langfuseHandler = require_callbacks.findCallback(invokeConfig.callbacks, require_langfuse.isLangfuseCallbackHandler);
|
|
1127
|
+
const { callbacks: _cb, ...rest } = invokeConfig;
|
|
1128
|
+
const safeConfig = Object.assign({}, rest, { callbacks: langfuseHandler ? [langfuseHandler] : [] });
|
|
1129
|
+
response = await require_langfuseRuntimeScope.withLangfuseRuntimeScope(labelRuntimeScope, () => invokeLabel(safeConfig));
|
|
1130
|
+
}
|
|
1131
|
+
const label = extractLabel(response);
|
|
1132
|
+
return label.length > 0 ? { label } : {};
|
|
1133
|
+
} finally {
|
|
1134
|
+
await require_langfuse.disposeLangfuseHandler(labelLangfuseHandler);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
963
1137
|
};
|
|
964
1138
|
function findLastMessageOfType(messages, type) {
|
|
965
1139
|
for (let i = messages.length - 1; i >= 0; i--) if (messages[i].getType() === type) return messages[i];
|