@librechat/agents 3.1.89 → 3.1.91
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 +9 -5
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +53 -14
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/hooks/executeHooks.cjs +14 -7
- package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +234 -0
- package/dist/cjs/langfuse.cjs.map +1 -0
- package/dist/cjs/llm/anthropic/index.cjs +8 -2
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +34 -0
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/main.cjs +34 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/run.cjs +44 -27
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +10 -3
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +10 -9
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +12 -8
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +35 -11
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/CodeSessionFileSummary.cjs +63 -0
- package/dist/cjs/tools/CodeSessionFileSummary.cjs.map +1 -0
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +16 -12
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +8 -5
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs +380 -0
- package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs.map +1 -0
- package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs +997 -0
- package/dist/cjs/tools/cloudflare/CloudflareProgrammaticToolCalling.cjs.map +1 -0
- package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs +575 -0
- package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs.map +1 -0
- package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs +165 -0
- package/dist/cjs/tools/cloudflare/CloudflareSandboxTools.cjs.map +1 -0
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs +17 -5
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs.map +1 -1
- package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +110 -6
- package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +319 -29
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +9 -5
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +53 -14
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/hooks/executeHooks.mjs +14 -7
- package/dist/esm/hooks/executeHooks.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +226 -0
- package/dist/esm/langfuse.mjs.map +1 -0
- package/dist/esm/llm/anthropic/index.mjs +9 -3
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +33 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/main.mjs +7 -2
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/run.mjs +44 -27
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +10 -3
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +11 -10
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +13 -9
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +29 -12
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/CodeSessionFileSummary.mjs +60 -0
- package/dist/esm/tools/CodeSessionFileSummary.mjs.map +1 -0
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +17 -13
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +8 -5
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs +378 -0
- package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs.map +1 -0
- package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs +994 -0
- package/dist/esm/tools/cloudflare/CloudflareProgrammaticToolCalling.mjs.map +1 -0
- package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs +566 -0
- package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs.map +1 -0
- package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs +155 -0
- package/dist/esm/tools/cloudflare/CloudflareSandboxTools.mjs.map +1 -0
- package/dist/esm/tools/local/LocalExecutionEngine.mjs +17 -6
- package/dist/esm/tools/local/LocalExecutionEngine.mjs.map +1 -1
- package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +111 -7
- package/dist/esm/tools/local/resolveLocalExecutionTools.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +320 -31
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +4 -1
- package/dist/types/graphs/Graph.d.ts +6 -5
- package/dist/types/index.d.ts +1 -0
- package/dist/types/langfuse.d.ts +48 -0
- package/dist/types/llm/anthropic/index.d.ts +3 -1
- package/dist/types/llm/anthropic/utils/message_inputs.d.ts +4 -0
- package/dist/types/tools/BashExecutor.d.ts +3 -3
- package/dist/types/tools/CodeExecutor.d.ts +10 -3
- package/dist/types/tools/CodeSessionFileSummary.d.ts +3 -0
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +4 -4
- package/dist/types/tools/cloudflare/CloudflareBridgeRuntime.d.ts +23 -0
- package/dist/types/tools/cloudflare/CloudflareProgrammaticToolCalling.d.ts +4 -0
- package/dist/types/tools/cloudflare/CloudflareSandboxExecutionEngine.d.ts +21 -0
- package/dist/types/tools/cloudflare/CloudflareSandboxTools.d.ts +22 -0
- package/dist/types/tools/cloudflare/index.d.ts +4 -0
- package/dist/types/tools/local/LocalExecutionEngine.d.ts +1 -0
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +8 -5
- package/dist/types/types/graph.d.ts +8 -0
- package/dist/types/types/tools.d.ts +120 -5
- package/package.json +4 -4
- package/src/__tests__/stream.eagerEventExecution.test.ts +66 -0
- package/src/agents/AgentContext.ts +13 -3
- package/src/graphs/Graph.ts +60 -16
- package/src/hooks/__tests__/executeHooks.test.ts +38 -0
- package/src/hooks/executeHooks.ts +27 -7
- package/src/index.ts +1 -0
- package/src/langfuse.ts +358 -0
- package/src/llm/anthropic/index.ts +27 -3
- package/src/llm/anthropic/llm.spec.ts +60 -1
- package/src/llm/anthropic/utils/message_inputs.ts +46 -0
- package/src/run.ts +60 -38
- package/src/specs/langfuse-config.test.ts +57 -0
- package/src/specs/langfuse-metadata.test.ts +19 -1
- package/src/stream.ts +13 -3
- package/src/tools/BashExecutor.ts +21 -10
- package/src/tools/BashProgrammaticToolCalling.ts +21 -9
- package/src/tools/CodeExecutor.ts +55 -12
- package/src/tools/CodeSessionFileSummary.ts +80 -0
- package/src/tools/ProgrammaticToolCalling.ts +25 -12
- package/src/tools/ToolNode.ts +8 -5
- package/src/tools/__tests__/BashExecutor.test.ts +9 -0
- package/src/tools/__tests__/CloudflareSandboxExecution.test.ts +537 -0
- package/src/tools/__tests__/CodeApiAuthHeaders.test.ts +43 -0
- package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +100 -16
- package/src/tools/__tests__/SubagentExecutor.test.ts +540 -6
- package/src/tools/__tests__/ToolNode.outputReferences.test.ts +52 -0
- package/src/tools/__tests__/subagentHooks.test.ts +237 -0
- package/src/tools/cloudflare/CloudflareBridgeRuntime.ts +480 -0
- package/src/tools/cloudflare/CloudflareProgrammaticToolCalling.ts +1162 -0
- package/src/tools/cloudflare/CloudflareSandboxExecutionEngine.ts +744 -0
- package/src/tools/cloudflare/CloudflareSandboxTools.ts +225 -0
- package/src/tools/cloudflare/index.ts +4 -0
- package/src/tools/local/LocalExecutionEngine.ts +20 -4
- package/src/tools/local/resolveLocalExecutionTools.ts +169 -7
- package/src/tools/subagent/SubagentExecutor.ts +514 -36
- package/src/types/graph.ts +9 -0
- package/src/types/tools.ts +143 -5
|
@@ -47,9 +47,8 @@ function makeAbortPromise(signal) {
|
|
|
47
47
|
};
|
|
48
48
|
return { promise, cleanup };
|
|
49
49
|
}
|
|
50
|
-
async function runHook(hook, input, signal, matcher) {
|
|
50
|
+
async function runHook(hook, input, signal, abortPromise, matcher) {
|
|
51
51
|
const hookPromise = Promise.resolve().then(() => hook(input, signal));
|
|
52
|
-
const { promise: abortPromise, cleanup } = makeAbortPromise(signal);
|
|
53
52
|
try {
|
|
54
53
|
const output = await Promise.race([hookPromise, abortPromise]);
|
|
55
54
|
return { matcher, output, error: null, timedOut: false };
|
|
@@ -62,8 +61,15 @@ async function runHook(hook, input, signal, matcher) {
|
|
|
62
61
|
timedOut: isTimeout(err),
|
|
63
62
|
};
|
|
64
63
|
}
|
|
64
|
+
}
|
|
65
|
+
async function runMatcherHooks(matcher, input, signal) {
|
|
66
|
+
const abortRace = makeAbortPromise(signal);
|
|
67
|
+
const tasks = matcher.hooks.map((hook) => runHook(hook, input, signal, abortRace.promise, matcher));
|
|
68
|
+
try {
|
|
69
|
+
return await Promise.all(tasks);
|
|
70
|
+
}
|
|
65
71
|
finally {
|
|
66
|
-
cleanup();
|
|
72
|
+
abortRace.cleanup();
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
function reportErrors(outcomes, event, logger) {
|
|
@@ -271,17 +277,18 @@ async function executeHooks(opts) {
|
|
|
271
277
|
if (matcher.once === true) {
|
|
272
278
|
registry.removeMatcher(event, matcher, sessionId);
|
|
273
279
|
}
|
|
280
|
+
if (matcher.hooks.length === 0) {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
274
283
|
const perHookTimeout = matcher.timeout ?? timeoutMs;
|
|
275
284
|
const matcherSignal = combineSignals(signal, perHookTimeout);
|
|
276
|
-
|
|
277
|
-
tasks.push(runHook(hook, input, matcherSignal, matcher));
|
|
278
|
-
}
|
|
285
|
+
tasks.push(runMatcherHooks(matcher, input, matcherSignal));
|
|
279
286
|
}
|
|
280
287
|
// --- END SYNC CRITICAL SECTION ---
|
|
281
288
|
if (tasks.length === 0) {
|
|
282
289
|
return freshResult();
|
|
283
290
|
}
|
|
284
|
-
const outcomes = await Promise.all(tasks);
|
|
291
|
+
const outcomes = (await Promise.all(tasks)).flat();
|
|
285
292
|
reportErrors(outcomes, event, logger);
|
|
286
293
|
const aggregated = fold(outcomes);
|
|
287
294
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executeHooks.mjs","sources":["../../../src/hooks/executeHooks.ts"],"sourcesContent":["// src/hooks/executeHooks.ts\nimport type { Logger } from 'winston';\nimport type { HookRegistry } from './HookRegistry';\nimport type {\n HookInput,\n HookEvent,\n HookOutput,\n HookMatcher,\n ToolDecision,\n StopDecision,\n HookCallback,\n AggregatedHookResult,\n} from './types';\nimport { matchesQuery } from './matchers';\n\n/** Default per-hook timeout when a matcher doesn't set its own. */\nexport const DEFAULT_HOOK_TIMEOUT_MS = 30_000;\n\n/**\n * Options for a single `executeHooks` call. The `input` drives everything —\n * the event name is read from `input.hook_event_name`, matchers are looked\n * up against that event, and each hook receives `input` directly.\n */\nexport interface ExecuteHooksOptions {\n registry: HookRegistry;\n input: HookInput;\n /** Scope lookup to this session (in addition to global matchers). */\n sessionId?: string;\n /** Query string matched against each matcher's pattern (tool name, etc.). */\n matchQuery?: string;\n /** Parent AbortSignal — combined with per-hook timeout into the hook signal. */\n signal?: AbortSignal;\n /** Default per-hook timeout; overridden by `matcher.timeout` when present. */\n timeoutMs?: number;\n /** Optional winston logger for non-internal hook errors. */\n logger?: Logger;\n}\n\ntype WideMatcher = HookMatcher<HookEvent>;\ntype WideCallback = HookCallback<HookEvent>;\n\ninterface HookOutcome {\n matcher: WideMatcher;\n output: HookOutput | null;\n error: string | null;\n timedOut: boolean;\n}\n\nfunction freshResult(): AggregatedHookResult {\n return {\n additionalContexts: [],\n errors: [],\n };\n}\n\nfunction combineSignals(\n parent: AbortSignal | undefined,\n timeoutMs: number\n): AbortSignal {\n const timeoutSignal = AbortSignal.timeout(timeoutMs);\n if (parent === undefined) {\n return timeoutSignal;\n }\n return AbortSignal.any([parent, timeoutSignal]);\n}\n\nfunction isTimeout(err: unknown): boolean {\n if (err instanceof Error) {\n return err.name === 'TimeoutError' || err.name === 'AbortError';\n }\n return false;\n}\n\nfunction describeError(err: unknown): string {\n if (err instanceof Error) {\n return err.message !== '' ? err.message : err.name;\n }\n return String(err);\n}\n\nfunction makeAbortPromise(signal: AbortSignal): {\n promise: Promise<never>;\n cleanup: () => void;\n} {\n let onAbort: (() => void) | undefined;\n const promise = new Promise<never>((_resolve, reject) => {\n if (signal.aborted) {\n reject(\n signal.reason instanceof Error ? signal.reason : new Error('aborted')\n );\n return;\n }\n onAbort = (): void => {\n reject(\n signal.reason instanceof Error ? signal.reason : new Error('aborted')\n );\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\n const cleanup = (): void => {\n if (onAbort !== undefined) {\n signal.removeEventListener('abort', onAbort);\n onAbort = undefined;\n }\n };\n return { promise, cleanup };\n}\n\nasync function runHook(\n hook: WideCallback,\n input: HookInput,\n signal: AbortSignal,\n matcher: WideMatcher\n): Promise<HookOutcome> {\n const hookPromise = Promise.resolve().then(() => hook(input, signal));\n const { promise: abortPromise, cleanup } = makeAbortPromise(signal);\n try {\n const output = await Promise.race([hookPromise, abortPromise]);\n return { matcher, output, error: null, timedOut: false };\n } catch (err) {\n return {\n matcher,\n output: null,\n error: describeError(err),\n timedOut: isTimeout(err),\n };\n } finally {\n cleanup();\n }\n}\n\nfunction reportErrors(\n outcomes: readonly HookOutcome[],\n event: HookEvent,\n logger: Logger | undefined\n): void {\n for (const outcome of outcomes) {\n if (outcome.error === null) {\n continue;\n }\n if (outcome.matcher.internal === true) {\n continue;\n }\n const label = outcome.timedOut ? 'timed out' : 'threw an error';\n const message = `Hook for ${event} ${label}: ${outcome.error}`;\n if (logger !== undefined) {\n logger.warn(message);\n continue;\n }\n // eslint-disable-next-line no-console\n console.warn(message);\n }\n}\n\nfunction applyToolDecision(\n agg: AggregatedHookResult,\n decision: ToolDecision,\n reason: string | undefined\n): void {\n if (decision === 'deny') {\n if (agg.decision === 'deny') {\n return;\n }\n agg.decision = 'deny';\n agg.reason = reason;\n return;\n }\n if (decision === 'ask') {\n if (agg.decision === 'deny' || agg.decision === 'ask') {\n return;\n }\n agg.decision = 'ask';\n agg.reason = reason;\n return;\n }\n if (agg.decision === undefined) {\n agg.decision = 'allow';\n agg.reason = reason;\n }\n}\n\nfunction applyStopDecision(\n agg: AggregatedHookResult,\n decision: StopDecision,\n reason: string | undefined\n): void {\n if (decision === 'block') {\n if (agg.stopDecision === 'block') {\n return;\n }\n agg.stopDecision = 'block';\n agg.reason = reason;\n return;\n }\n if (agg.stopDecision === undefined) {\n agg.stopDecision = 'continue';\n if (agg.reason === undefined) {\n agg.reason = reason;\n }\n }\n}\n\nfunction applyDecision(agg: AggregatedHookResult, output: HookOutput): void {\n if (!('decision' in output) || output.decision === undefined) {\n return;\n }\n const decision = output.decision;\n const reason =\n 'reason' in output && typeof output.reason === 'string'\n ? output.reason\n : undefined;\n if (decision === 'deny' || decision === 'ask' || decision === 'allow') {\n applyToolDecision(agg, decision, reason);\n return;\n }\n applyStopDecision(agg, decision, reason);\n}\n\nfunction applyContext(agg: AggregatedHookResult, output: HookOutput): void {\n if (\n typeof output.additionalContext === 'string' &&\n output.additionalContext.length > 0\n ) {\n agg.additionalContexts.push(output.additionalContext);\n }\n}\n\nfunction applyStopFlag(agg: AggregatedHookResult, output: HookOutput): void {\n if (output.preventContinuation !== true) {\n return;\n }\n agg.preventContinuation = true;\n if (typeof output.stopReason === 'string' && agg.stopReason === undefined) {\n agg.stopReason = output.stopReason;\n }\n}\n\nfunction applyUpdatedInput(\n agg: AggregatedHookResult,\n output: HookOutput\n): void {\n if (!('updatedInput' in output) || output.updatedInput === undefined) {\n return;\n }\n agg.updatedInput = output.updatedInput;\n}\n\nfunction applyUpdatedOutput(\n agg: AggregatedHookResult,\n output: HookOutput\n): void {\n if (!('updatedOutput' in output) || output.updatedOutput === undefined) {\n return;\n }\n agg.updatedOutput = output.updatedOutput;\n}\n\nfunction applyAllowedDecisions(\n agg: AggregatedHookResult,\n output: HookOutput\n): void {\n if (\n !('allowedDecisions' in output) ||\n output.allowedDecisions === undefined\n ) {\n return;\n }\n agg.allowedDecisions = output.allowedDecisions;\n}\n\nfunction fold(outcomes: readonly HookOutcome[]): AggregatedHookResult {\n const agg = freshResult();\n for (const outcome of outcomes) {\n if (outcome.error !== null) {\n if (outcome.matcher.internal !== true) {\n agg.errors.push(outcome.error);\n }\n continue;\n }\n const output = outcome.output;\n if (output === null) {\n continue;\n }\n /**\n * Skip fire-and-forget outputs entirely: the agent has already\n * moved on, so an async hook cannot influence the run. Background\n * work inside the hook body still runs (we don't cancel it), it\n * just doesn't fold into the aggregate result.\n */\n if (output.async === true) {\n continue;\n }\n applyContext(agg, output);\n applyStopFlag(agg, output);\n applyDecision(agg, output);\n applyUpdatedInput(agg, output);\n applyUpdatedOutput(agg, output);\n applyAllowedDecisions(agg, output);\n }\n return agg;\n}\n\n/**\n * Fires every matcher registered against `input.hook_event_name`, folding\n * their results per `deny > ask > allow` precedence and accumulating\n * context/errors.\n *\n * ## Parallelism and determinism\n *\n * All matching hooks fire simultaneously and are awaited via `Promise.all`,\n * which preserves input-array order in its returned results. The fold\n * therefore iterates outcomes in **registration order** — outer loop over\n * matchers as they sit in the registry (global first, then session), inner\n * loop over each matcher's `hooks` array. Last-writer-wins fields\n * (`updatedInput`, `updatedOutput`) are deterministic in that order, even\n * though hooks may complete in arbitrary wall-clock order.\n *\n * Consumers that need a single authoritative rewrite should still scope\n * `updatedInput`/`updatedOutput` to one hook per matcher to avoid subtle\n * precedence bugs when matchers are added in a different order than\n * expected.\n *\n * ## Timeouts and cancellation\n *\n * Each matcher receives **one shared `AbortSignal`** derived from the\n * caller's parent signal combined with `matcher.timeout` (falling back to\n * `opts.timeoutMs`, default {@link DEFAULT_HOOK_TIMEOUT_MS}). Sharing the\n * signal across hooks in a matcher collapses N timer allocations into\n * one, which matters on the PreToolUse hot path where a matcher with\n * several hooks fires on every tool call. Each hook call is raced\n * against the shared signal, so even a hook that ignores the signal is\n * force-unblocked when the timeout fires. Timeout/abort errors are\n * swallowed into the aggregated result's `errors` array (non-fatal by\n * default).\n *\n * ## Internal matchers\n *\n * A matcher with `internal: true` is excluded from both the `errors` array\n * and the logger output. Use it for infrastructure hooks whose failures\n * should not pollute user-visible diagnostics.\n *\n * ## Once semantics — atomic at-most-once\n *\n * A matcher with `once: true` is removed from the registry **before any\n * hook runs**, inside the synchronous prefix of `executeHooks` (between\n * `getMatchers` and the first `await`). Because Node's event loop serialises\n * sync work, two concurrent `executeHooks` calls can never both observe\n * and dispatch the same `once` matcher — whichever call runs its sync\n * prefix first consumes it, and the loser sees an empty bucket.\n *\n * Trade-off: if every hook in a `once` matcher throws, the matcher is\n * still gone. \"Once\" here means \"at most one dispatch, ever\", not \"at\n * most one successful execution with retry on failure\". Hosts that need\n * retry semantics should register a normal matcher and self-unregister\n * via the `unregister` callback returned from `registry.register`.\n */\nexport async function executeHooks(\n opts: ExecuteHooksOptions\n): Promise<AggregatedHookResult> {\n const {\n registry,\n input,\n sessionId,\n matchQuery,\n signal,\n timeoutMs = DEFAULT_HOOK_TIMEOUT_MS,\n logger,\n } = opts;\n const event = input.hook_event_name;\n const matchers = registry.getMatchers(event, sessionId);\n if (matchers.length === 0) {\n return freshResult();\n }\n\n // --- SYNC CRITICAL SECTION: once-matcher removal must complete before any await ---\n const tasks: Promise<HookOutcome>[] = [];\n for (const matcher of matchers) {\n if (!matchesQuery(matcher.pattern, matchQuery)) {\n continue;\n }\n if (matcher.once === true) {\n registry.removeMatcher(event, matcher, sessionId);\n }\n const perHookTimeout = matcher.timeout ?? timeoutMs;\n const matcherSignal = combineSignals(signal, perHookTimeout);\n for (const hook of matcher.hooks) {\n tasks.push(runHook(hook, input, matcherSignal, matcher));\n }\n }\n // --- END SYNC CRITICAL SECTION ---\n if (tasks.length === 0) {\n return freshResult();\n }\n\n const outcomes = await Promise.all(tasks);\n reportErrors(outcomes, event, logger);\n const aggregated = fold(outcomes);\n /**\n * Centralized `preventContinuation` propagation: when any hook (across\n * any callsite — RunStart, PreToolUse, PostToolBatch, SubagentStop,\n * etc.) returns `preventContinuation: true`, raise a halt signal on\n * the registry scoped to the run's `sessionId`. `Run.processStream`\n * polls the signal between stream events using its own id and exits\n * cleanly, skipping the `Stop` hook (since the run is being halted,\n * not naturally completing).\n *\n * First-write-wins per session inside the registry — a halt already\n * raised by an earlier hook in the same run is preserved so the\n * original `reason` / `source` are not clobbered. Hooks fired\n * without a `sessionId` cannot raise a halt (there's no run for the\n * loop to poll under), which is fine: every in-tree callsite passes\n * `sessionId: runId`. Pre-stream callsites in `Run.processStream`\n * still read `preventContinuation` directly off the result for an\n * early return because they have not yet entered the stream loop.\n */\n if (aggregated.preventContinuation === true && sessionId !== undefined) {\n registry.haltRun(\n sessionId,\n aggregated.stopReason ?? 'preventContinuation',\n event\n );\n }\n return aggregated;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"executeHooks.mjs","sources":["../../../src/hooks/executeHooks.ts"],"sourcesContent":["// src/hooks/executeHooks.ts\nimport type { Logger } from 'winston';\nimport type { HookRegistry } from './HookRegistry';\nimport type {\n HookInput,\n HookEvent,\n HookOutput,\n HookMatcher,\n ToolDecision,\n StopDecision,\n HookCallback,\n AggregatedHookResult,\n} from './types';\nimport { matchesQuery } from './matchers';\n\n/** Default per-hook timeout when a matcher doesn't set its own. */\nexport const DEFAULT_HOOK_TIMEOUT_MS = 30_000;\n\n/**\n * Options for a single `executeHooks` call. The `input` drives everything —\n * the event name is read from `input.hook_event_name`, matchers are looked\n * up against that event, and each hook receives `input` directly.\n */\nexport interface ExecuteHooksOptions {\n registry: HookRegistry;\n input: HookInput;\n /** Scope lookup to this session (in addition to global matchers). */\n sessionId?: string;\n /** Query string matched against each matcher's pattern (tool name, etc.). */\n matchQuery?: string;\n /** Parent AbortSignal — combined with per-hook timeout into the hook signal. */\n signal?: AbortSignal;\n /** Default per-hook timeout; overridden by `matcher.timeout` when present. */\n timeoutMs?: number;\n /** Optional winston logger for non-internal hook errors. */\n logger?: Logger;\n}\n\ntype WideMatcher = HookMatcher<HookEvent>;\ntype WideCallback = HookCallback<HookEvent>;\n\ninterface HookOutcome {\n matcher: WideMatcher;\n output: HookOutput | null;\n error: string | null;\n timedOut: boolean;\n}\n\ninterface AbortRace {\n promise: Promise<never>;\n cleanup: () => void;\n}\n\nfunction freshResult(): AggregatedHookResult {\n return {\n additionalContexts: [],\n errors: [],\n };\n}\n\nfunction combineSignals(\n parent: AbortSignal | undefined,\n timeoutMs: number\n): AbortSignal {\n const timeoutSignal = AbortSignal.timeout(timeoutMs);\n if (parent === undefined) {\n return timeoutSignal;\n }\n return AbortSignal.any([parent, timeoutSignal]);\n}\n\nfunction isTimeout(err: unknown): boolean {\n if (err instanceof Error) {\n return err.name === 'TimeoutError' || err.name === 'AbortError';\n }\n return false;\n}\n\nfunction describeError(err: unknown): string {\n if (err instanceof Error) {\n return err.message !== '' ? err.message : err.name;\n }\n return String(err);\n}\n\nfunction makeAbortPromise(signal: AbortSignal): {\n promise: Promise<never>;\n cleanup: () => void;\n} {\n let onAbort: (() => void) | undefined;\n const promise = new Promise<never>((_resolve, reject) => {\n if (signal.aborted) {\n reject(\n signal.reason instanceof Error ? signal.reason : new Error('aborted')\n );\n return;\n }\n onAbort = (): void => {\n reject(\n signal.reason instanceof Error ? signal.reason : new Error('aborted')\n );\n };\n signal.addEventListener('abort', onAbort, { once: true });\n });\n const cleanup = (): void => {\n if (onAbort !== undefined) {\n signal.removeEventListener('abort', onAbort);\n onAbort = undefined;\n }\n };\n return { promise, cleanup };\n}\n\nasync function runHook(\n hook: WideCallback,\n input: HookInput,\n signal: AbortSignal,\n abortPromise: Promise<never>,\n matcher: WideMatcher\n): Promise<HookOutcome> {\n const hookPromise = Promise.resolve().then(() => hook(input, signal));\n try {\n const output = await Promise.race([hookPromise, abortPromise]);\n return { matcher, output, error: null, timedOut: false };\n } catch (err) {\n return {\n matcher,\n output: null,\n error: describeError(err),\n timedOut: isTimeout(err),\n };\n }\n}\n\nasync function runMatcherHooks(\n matcher: WideMatcher,\n input: HookInput,\n signal: AbortSignal\n): Promise<HookOutcome[]> {\n const abortRace: AbortRace = makeAbortPromise(signal);\n const tasks = matcher.hooks.map((hook) =>\n runHook(hook, input, signal, abortRace.promise, matcher)\n );\n try {\n return await Promise.all(tasks);\n } finally {\n abortRace.cleanup();\n }\n}\n\nfunction reportErrors(\n outcomes: readonly HookOutcome[],\n event: HookEvent,\n logger: Logger | undefined\n): void {\n for (const outcome of outcomes) {\n if (outcome.error === null) {\n continue;\n }\n if (outcome.matcher.internal === true) {\n continue;\n }\n const label = outcome.timedOut ? 'timed out' : 'threw an error';\n const message = `Hook for ${event} ${label}: ${outcome.error}`;\n if (logger !== undefined) {\n logger.warn(message);\n continue;\n }\n // eslint-disable-next-line no-console\n console.warn(message);\n }\n}\n\nfunction applyToolDecision(\n agg: AggregatedHookResult,\n decision: ToolDecision,\n reason: string | undefined\n): void {\n if (decision === 'deny') {\n if (agg.decision === 'deny') {\n return;\n }\n agg.decision = 'deny';\n agg.reason = reason;\n return;\n }\n if (decision === 'ask') {\n if (agg.decision === 'deny' || agg.decision === 'ask') {\n return;\n }\n agg.decision = 'ask';\n agg.reason = reason;\n return;\n }\n if (agg.decision === undefined) {\n agg.decision = 'allow';\n agg.reason = reason;\n }\n}\n\nfunction applyStopDecision(\n agg: AggregatedHookResult,\n decision: StopDecision,\n reason: string | undefined\n): void {\n if (decision === 'block') {\n if (agg.stopDecision === 'block') {\n return;\n }\n agg.stopDecision = 'block';\n agg.reason = reason;\n return;\n }\n if (agg.stopDecision === undefined) {\n agg.stopDecision = 'continue';\n if (agg.reason === undefined) {\n agg.reason = reason;\n }\n }\n}\n\nfunction applyDecision(agg: AggregatedHookResult, output: HookOutput): void {\n if (!('decision' in output) || output.decision === undefined) {\n return;\n }\n const decision = output.decision;\n const reason =\n 'reason' in output && typeof output.reason === 'string'\n ? output.reason\n : undefined;\n if (decision === 'deny' || decision === 'ask' || decision === 'allow') {\n applyToolDecision(agg, decision, reason);\n return;\n }\n applyStopDecision(agg, decision, reason);\n}\n\nfunction applyContext(agg: AggregatedHookResult, output: HookOutput): void {\n if (\n typeof output.additionalContext === 'string' &&\n output.additionalContext.length > 0\n ) {\n agg.additionalContexts.push(output.additionalContext);\n }\n}\n\nfunction applyStopFlag(agg: AggregatedHookResult, output: HookOutput): void {\n if (output.preventContinuation !== true) {\n return;\n }\n agg.preventContinuation = true;\n if (typeof output.stopReason === 'string' && agg.stopReason === undefined) {\n agg.stopReason = output.stopReason;\n }\n}\n\nfunction applyUpdatedInput(\n agg: AggregatedHookResult,\n output: HookOutput\n): void {\n if (!('updatedInput' in output) || output.updatedInput === undefined) {\n return;\n }\n agg.updatedInput = output.updatedInput;\n}\n\nfunction applyUpdatedOutput(\n agg: AggregatedHookResult,\n output: HookOutput\n): void {\n if (!('updatedOutput' in output) || output.updatedOutput === undefined) {\n return;\n }\n agg.updatedOutput = output.updatedOutput;\n}\n\nfunction applyAllowedDecisions(\n agg: AggregatedHookResult,\n output: HookOutput\n): void {\n if (\n !('allowedDecisions' in output) ||\n output.allowedDecisions === undefined\n ) {\n return;\n }\n agg.allowedDecisions = output.allowedDecisions;\n}\n\nfunction fold(outcomes: readonly HookOutcome[]): AggregatedHookResult {\n const agg = freshResult();\n for (const outcome of outcomes) {\n if (outcome.error !== null) {\n if (outcome.matcher.internal !== true) {\n agg.errors.push(outcome.error);\n }\n continue;\n }\n const output = outcome.output;\n if (output === null) {\n continue;\n }\n /**\n * Skip fire-and-forget outputs entirely: the agent has already\n * moved on, so an async hook cannot influence the run. Background\n * work inside the hook body still runs (we don't cancel it), it\n * just doesn't fold into the aggregate result.\n */\n if (output.async === true) {\n continue;\n }\n applyContext(agg, output);\n applyStopFlag(agg, output);\n applyDecision(agg, output);\n applyUpdatedInput(agg, output);\n applyUpdatedOutput(agg, output);\n applyAllowedDecisions(agg, output);\n }\n return agg;\n}\n\n/**\n * Fires every matcher registered against `input.hook_event_name`, folding\n * their results per `deny > ask > allow` precedence and accumulating\n * context/errors.\n *\n * ## Parallelism and determinism\n *\n * All matching hooks fire simultaneously and are awaited via `Promise.all`,\n * which preserves input-array order in its returned results. The fold\n * therefore iterates outcomes in **registration order** — outer loop over\n * matchers as they sit in the registry (global first, then session), inner\n * loop over each matcher's `hooks` array. Last-writer-wins fields\n * (`updatedInput`, `updatedOutput`) are deterministic in that order, even\n * though hooks may complete in arbitrary wall-clock order.\n *\n * Consumers that need a single authoritative rewrite should still scope\n * `updatedInput`/`updatedOutput` to one hook per matcher to avoid subtle\n * precedence bugs when matchers are added in a different order than\n * expected.\n *\n * ## Timeouts and cancellation\n *\n * Each matcher receives **one shared `AbortSignal`** derived from the\n * caller's parent signal combined with `matcher.timeout` (falling back to\n * `opts.timeoutMs`, default {@link DEFAULT_HOOK_TIMEOUT_MS}). Sharing the\n * signal across hooks in a matcher collapses N timer allocations into\n * one, which matters on the PreToolUse hot path where a matcher with\n * several hooks fires on every tool call. Each hook call is raced\n * against the shared signal, so even a hook that ignores the signal is\n * force-unblocked when the timeout fires. Timeout/abort errors are\n * swallowed into the aggregated result's `errors` array (non-fatal by\n * default).\n *\n * ## Internal matchers\n *\n * A matcher with `internal: true` is excluded from both the `errors` array\n * and the logger output. Use it for infrastructure hooks whose failures\n * should not pollute user-visible diagnostics.\n *\n * ## Once semantics — atomic at-most-once\n *\n * A matcher with `once: true` is removed from the registry **before any\n * hook runs**, inside the synchronous prefix of `executeHooks` (between\n * `getMatchers` and the first `await`). Because Node's event loop serialises\n * sync work, two concurrent `executeHooks` calls can never both observe\n * and dispatch the same `once` matcher — whichever call runs its sync\n * prefix first consumes it, and the loser sees an empty bucket.\n *\n * Trade-off: if every hook in a `once` matcher throws, the matcher is\n * still gone. \"Once\" here means \"at most one dispatch, ever\", not \"at\n * most one successful execution with retry on failure\". Hosts that need\n * retry semantics should register a normal matcher and self-unregister\n * via the `unregister` callback returned from `registry.register`.\n */\nexport async function executeHooks(\n opts: ExecuteHooksOptions\n): Promise<AggregatedHookResult> {\n const {\n registry,\n input,\n sessionId,\n matchQuery,\n signal,\n timeoutMs = DEFAULT_HOOK_TIMEOUT_MS,\n logger,\n } = opts;\n const event = input.hook_event_name;\n const matchers = registry.getMatchers(event, sessionId);\n if (matchers.length === 0) {\n return freshResult();\n }\n\n // --- SYNC CRITICAL SECTION: once-matcher removal must complete before any await ---\n const tasks: Promise<HookOutcome[]>[] = [];\n for (const matcher of matchers) {\n if (!matchesQuery(matcher.pattern, matchQuery)) {\n continue;\n }\n if (matcher.once === true) {\n registry.removeMatcher(event, matcher, sessionId);\n }\n if (matcher.hooks.length === 0) {\n continue;\n }\n const perHookTimeout = matcher.timeout ?? timeoutMs;\n const matcherSignal = combineSignals(signal, perHookTimeout);\n tasks.push(runMatcherHooks(matcher, input, matcherSignal));\n }\n // --- END SYNC CRITICAL SECTION ---\n if (tasks.length === 0) {\n return freshResult();\n }\n\n const outcomes = (await Promise.all(tasks)).flat();\n reportErrors(outcomes, event, logger);\n const aggregated = fold(outcomes);\n /**\n * Centralized `preventContinuation` propagation: when any hook (across\n * any callsite — RunStart, PreToolUse, PostToolBatch, SubagentStop,\n * etc.) returns `preventContinuation: true`, raise a halt signal on\n * the registry scoped to the run's `sessionId`. `Run.processStream`\n * polls the signal between stream events using its own id and exits\n * cleanly, skipping the `Stop` hook (since the run is being halted,\n * not naturally completing).\n *\n * First-write-wins per session inside the registry — a halt already\n * raised by an earlier hook in the same run is preserved so the\n * original `reason` / `source` are not clobbered. Hooks fired\n * without a `sessionId` cannot raise a halt (there's no run for the\n * loop to poll under), which is fine: every in-tree callsite passes\n * `sessionId: runId`. Pre-stream callsites in `Run.processStream`\n * still read `preventContinuation` directly off the result for an\n * early return because they have not yet entered the stream loop.\n */\n if (aggregated.preventContinuation === true && sessionId !== undefined) {\n registry.haltRun(\n sessionId,\n aggregated.stopReason ?? 'preventContinuation',\n event\n );\n }\n return aggregated;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { CallbackHandler } from '@langfuse/langchain';
|
|
2
|
+
import { LangfuseSpanProcessor } from '@langfuse/otel';
|
|
3
|
+
import { createObservationAttributes, createTraceAttributes } from '@langfuse/tracing';
|
|
4
|
+
import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
|
|
5
|
+
import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
|
|
6
|
+
import { SpanStatusCode } from '@opentelemetry/api';
|
|
7
|
+
import { isPresent } from './utils/misc.mjs';
|
|
8
|
+
|
|
9
|
+
function getModelName(serialized) {
|
|
10
|
+
const serializedRecord = serialized;
|
|
11
|
+
const kwargs = serializedRecord.kwargs;
|
|
12
|
+
const modelName = kwargs?.model ??
|
|
13
|
+
kwargs?.model_name ??
|
|
14
|
+
kwargs?.modelName ??
|
|
15
|
+
kwargs?.model_id ??
|
|
16
|
+
kwargs?.modelId ??
|
|
17
|
+
serializedRecord.name;
|
|
18
|
+
if (typeof modelName === 'string' && modelName.trim() !== '') {
|
|
19
|
+
return modelName;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(serializedRecord.id) && serializedRecord.id.length > 0) {
|
|
22
|
+
return String(serializedRecord.id[serializedRecord.id.length - 1]);
|
|
23
|
+
}
|
|
24
|
+
return 'ChatModel';
|
|
25
|
+
}
|
|
26
|
+
function getModelParameters(extraParams) {
|
|
27
|
+
const invocationParams = extraParams?.invocation_params;
|
|
28
|
+
const params = invocationParams != null && typeof invocationParams === 'object'
|
|
29
|
+
? invocationParams
|
|
30
|
+
: (extraParams ?? {});
|
|
31
|
+
return Object.fromEntries(Object.entries(params).filter(([, value]) => {
|
|
32
|
+
return typeof value === 'string' || typeof value === 'number';
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
function getOutput(output) {
|
|
36
|
+
return output.generations.map((generation) => generation.map((item) => {
|
|
37
|
+
if ('message' in item && item.message != null) {
|
|
38
|
+
return item.message.content;
|
|
39
|
+
}
|
|
40
|
+
return item.text;
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
function getUsageDetails(output) {
|
|
44
|
+
const llmOutput = output.llmOutput;
|
|
45
|
+
const usage = llmOutput?.tokenUsage ?? llmOutput?.usage;
|
|
46
|
+
if (usage == null || typeof usage !== 'object') {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const usageEntries = Object.entries(usage).filter(([, value]) => typeof value === 'number');
|
|
50
|
+
return usageEntries.length > 0
|
|
51
|
+
? Object.fromEntries(usageEntries)
|
|
52
|
+
: undefined;
|
|
53
|
+
}
|
|
54
|
+
function getTraceName(traceMetadata) {
|
|
55
|
+
const agentName = traceMetadata?.agentName;
|
|
56
|
+
return typeof agentName === 'string' && agentName.trim() !== ''
|
|
57
|
+
? `LibreChat Agent: ${agentName}`
|
|
58
|
+
: 'LibreChat Agent';
|
|
59
|
+
}
|
|
60
|
+
class LangfuseAgentCallbackHandler extends BaseCallbackHandler {
|
|
61
|
+
name = 'librechat_langfuse_agent_handler';
|
|
62
|
+
provider;
|
|
63
|
+
processor;
|
|
64
|
+
userId;
|
|
65
|
+
sessionId;
|
|
66
|
+
traceMetadata;
|
|
67
|
+
spans = new Map();
|
|
68
|
+
constructor({ langfuse, userId, sessionId, traceMetadata, }) {
|
|
69
|
+
super();
|
|
70
|
+
this.userId = userId;
|
|
71
|
+
this.sessionId = sessionId;
|
|
72
|
+
this.traceMetadata = traceMetadata;
|
|
73
|
+
this.processor = new LangfuseSpanProcessor({
|
|
74
|
+
publicKey: langfuse.publicKey,
|
|
75
|
+
secretKey: langfuse.secretKey,
|
|
76
|
+
...(isPresent(langfuse.baseUrl) ? { baseUrl: langfuse.baseUrl } : {}),
|
|
77
|
+
environment: process.env.LANGFUSE_TRACING_ENVIRONMENT ??
|
|
78
|
+
process.env.NODE_ENV ??
|
|
79
|
+
'development',
|
|
80
|
+
exportMode: 'immediate',
|
|
81
|
+
});
|
|
82
|
+
this.provider = new BasicTracerProvider({
|
|
83
|
+
spanProcessors: [this.processor],
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
startGenerationSpan({ llm, input, runId, extraParams, metadata, name, }) {
|
|
87
|
+
if (this.spans.has(runId)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const tracer = this.provider.getTracer('librechat-agents-langfuse');
|
|
91
|
+
const spanName = typeof name === 'string' && name.trim() !== '' ? name : getModelName(llm);
|
|
92
|
+
const span = tracer.startSpan(spanName, {
|
|
93
|
+
attributes: {
|
|
94
|
+
...createTraceAttributes({
|
|
95
|
+
name: getTraceName(this.traceMetadata),
|
|
96
|
+
userId: this.userId,
|
|
97
|
+
sessionId: this.sessionId,
|
|
98
|
+
metadata: this.traceMetadata,
|
|
99
|
+
}),
|
|
100
|
+
...createObservationAttributes('generation', {
|
|
101
|
+
input,
|
|
102
|
+
model: getModelName(llm),
|
|
103
|
+
modelParameters: getModelParameters(extraParams),
|
|
104
|
+
metadata: {
|
|
105
|
+
...metadata,
|
|
106
|
+
...this.traceMetadata,
|
|
107
|
+
},
|
|
108
|
+
}),
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
this.spans.set(runId, span);
|
|
112
|
+
}
|
|
113
|
+
async handleChatModelStart(llm, messages, runId, _parentRunId, extraParams, _tags, metadata, name) {
|
|
114
|
+
this.startGenerationSpan({
|
|
115
|
+
llm,
|
|
116
|
+
input: messages,
|
|
117
|
+
runId,
|
|
118
|
+
extraParams,
|
|
119
|
+
metadata,
|
|
120
|
+
name,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
async handleLLMStart(llm, prompts, runId, _parentRunId, extraParams, _tags, metadata, name) {
|
|
124
|
+
this.startGenerationSpan({
|
|
125
|
+
llm,
|
|
126
|
+
input: prompts,
|
|
127
|
+
runId,
|
|
128
|
+
extraParams,
|
|
129
|
+
metadata,
|
|
130
|
+
name,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async handleLLMEnd(output, runId) {
|
|
134
|
+
const span = this.spans.get(runId);
|
|
135
|
+
if (!span) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
span.setAttributes(createObservationAttributes('generation', {
|
|
139
|
+
output: getOutput(output),
|
|
140
|
+
usageDetails: getUsageDetails(output),
|
|
141
|
+
}));
|
|
142
|
+
span.end();
|
|
143
|
+
this.spans.delete(runId);
|
|
144
|
+
await this.flush();
|
|
145
|
+
}
|
|
146
|
+
async handleLLMError(err, runId) {
|
|
147
|
+
const span = this.spans.get(runId);
|
|
148
|
+
if (!span) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
152
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
153
|
+
span.setAttributes(createObservationAttributes('generation', {
|
|
154
|
+
level: 'ERROR',
|
|
155
|
+
statusMessage: message,
|
|
156
|
+
}));
|
|
157
|
+
span.end();
|
|
158
|
+
this.spans.delete(runId);
|
|
159
|
+
await this.flush();
|
|
160
|
+
}
|
|
161
|
+
async flush() {
|
|
162
|
+
try {
|
|
163
|
+
await this.provider.forceFlush();
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
process.emitWarning(`[LangfuseAgentCallbackHandler] Failed to flush Langfuse spans: ${error instanceof Error ? error.message : String(error)}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async dispose() {
|
|
170
|
+
for (const span of this.spans.values()) {
|
|
171
|
+
span.end();
|
|
172
|
+
}
|
|
173
|
+
this.spans.clear();
|
|
174
|
+
await this.flush();
|
|
175
|
+
try {
|
|
176
|
+
await this.provider.shutdown();
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
process.emitWarning(`[LangfuseAgentCallbackHandler] Failed to shut down Langfuse provider: ${error instanceof Error ? error.message : String(error)}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function hasRequiredLangfuseConfig(langfuse) {
|
|
184
|
+
return (langfuse?.enabled === true &&
|
|
185
|
+
isPresent(langfuse.publicKey) &&
|
|
186
|
+
isPresent(langfuse.secretKey));
|
|
187
|
+
}
|
|
188
|
+
function createLegacyLangfuseHandler(params) {
|
|
189
|
+
return new CallbackHandler(params);
|
|
190
|
+
}
|
|
191
|
+
function createLangfuseHandler({ langfuse, userId, sessionId, traceMetadata, }) {
|
|
192
|
+
if (!hasRequiredLangfuseConfig(langfuse)) {
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
return new LangfuseAgentCallbackHandler({
|
|
196
|
+
langfuse,
|
|
197
|
+
userId,
|
|
198
|
+
sessionId,
|
|
199
|
+
traceMetadata,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
function hasExplicitLangfuseConfig(contexts) {
|
|
203
|
+
for (const context of contexts) {
|
|
204
|
+
if (context.langfuse != null) {
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
function hasLangfuseEnvConfig() {
|
|
211
|
+
return (isPresent(process.env.LANGFUSE_SECRET_KEY) &&
|
|
212
|
+
isPresent(process.env.LANGFUSE_PUBLIC_KEY) &&
|
|
213
|
+
isPresent(process.env.LANGFUSE_BASE_URL));
|
|
214
|
+
}
|
|
215
|
+
function isLangfuseCallbackHandler(value) {
|
|
216
|
+
return (value instanceof CallbackHandler ||
|
|
217
|
+
value instanceof LangfuseAgentCallbackHandler);
|
|
218
|
+
}
|
|
219
|
+
async function disposeLangfuseHandler(value) {
|
|
220
|
+
if (value instanceof LangfuseAgentCallbackHandler) {
|
|
221
|
+
await value.dispose();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export { LangfuseAgentCallbackHandler, createLangfuseHandler, createLegacyLangfuseHandler, disposeLangfuseHandler, hasExplicitLangfuseConfig, hasLangfuseEnvConfig, isLangfuseCallbackHandler };
|
|
226
|
+
//# sourceMappingURL=langfuse.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"langfuse.mjs","sources":["../../src/langfuse.ts"],"sourcesContent":["import { CallbackHandler } from '@langfuse/langchain';\nimport { LangfuseSpanProcessor } from '@langfuse/otel';\nimport {\n createObservationAttributes,\n createTraceAttributes,\n} from '@langfuse/tracing';\nimport { BaseCallbackHandler } from '@langchain/core/callbacks/base';\nimport { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport type { Serialized } from '@langchain/core/load/serializable';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport type { LLMResult } from '@langchain/core/outputs';\nimport type { Span } from '@opentelemetry/api';\nimport type * as t from '@/types';\nimport { isPresent } from '@/utils/misc';\n\ntype TraceMetadata = Record<string, unknown>;\n\ntype LangfuseHandlerParams = {\n userId?: string;\n sessionId?: string;\n traceMetadata?: TraceMetadata;\n};\n\ntype AgentLangfuseHandlerParams = LangfuseHandlerParams & {\n langfuse?: t.LangfuseConfig;\n};\n\ntype ResolvedLangfuseConfig = t.LangfuseConfig & {\n enabled: true;\n publicKey: string;\n secretKey: string;\n};\n\nfunction getModelName(serialized: Serialized): string {\n const serializedRecord = serialized as unknown as Record<string, unknown>;\n const kwargs = serializedRecord.kwargs as Record<string, unknown> | undefined;\n const modelName =\n kwargs?.model ??\n kwargs?.model_name ??\n kwargs?.modelName ??\n kwargs?.model_id ??\n kwargs?.modelId ??\n serializedRecord.name;\n\n if (typeof modelName === 'string' && modelName.trim() !== '') {\n return modelName;\n }\n\n if (Array.isArray(serializedRecord.id) && serializedRecord.id.length > 0) {\n return String(serializedRecord.id[serializedRecord.id.length - 1]);\n }\n\n return 'ChatModel';\n}\n\nfunction getModelParameters(\n extraParams?: Record<string, unknown>\n): Record<string, string | number> {\n const invocationParams = extraParams?.invocation_params;\n const params =\n invocationParams != null && typeof invocationParams === 'object'\n ? (invocationParams as Record<string, unknown>)\n : (extraParams ?? {});\n\n return Object.fromEntries(\n Object.entries(params).filter(([, value]) => {\n return typeof value === 'string' || typeof value === 'number';\n })\n ) as Record<string, string | number>;\n}\n\nfunction getOutput(output: LLMResult): unknown {\n return output.generations.map((generation) =>\n generation.map((item) => {\n if ('message' in item && item.message != null) {\n return (item.message as { content?: unknown }).content;\n }\n return item.text;\n })\n );\n}\n\nfunction getUsageDetails(\n output: LLMResult\n): Record<string, number> | undefined {\n const llmOutput = output.llmOutput as Record<string, unknown> | undefined;\n const usage = llmOutput?.tokenUsage ?? llmOutput?.usage;\n if (usage == null || typeof usage !== 'object') {\n return undefined;\n }\n\n const usageEntries = Object.entries(usage as Record<string, unknown>).filter(\n ([, value]) => typeof value === 'number'\n );\n\n return usageEntries.length > 0\n ? (Object.fromEntries(usageEntries) as Record<string, number>)\n : undefined;\n}\n\nfunction getTraceName(traceMetadata?: TraceMetadata): string {\n const agentName = traceMetadata?.agentName;\n return typeof agentName === 'string' && agentName.trim() !== ''\n ? `LibreChat Agent: ${agentName}`\n : 'LibreChat Agent';\n}\n\nexport class LangfuseAgentCallbackHandler extends BaseCallbackHandler {\n name = 'librechat_langfuse_agent_handler';\n\n private readonly provider: BasicTracerProvider;\n private readonly processor: LangfuseSpanProcessor;\n private readonly userId?: string;\n private readonly sessionId?: string;\n private readonly traceMetadata?: TraceMetadata;\n private readonly spans = new Map<string, Span>();\n\n constructor({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n }: LangfuseHandlerParams & { langfuse: ResolvedLangfuseConfig }) {\n super();\n this.userId = userId;\n this.sessionId = sessionId;\n this.traceMetadata = traceMetadata;\n this.processor = new LangfuseSpanProcessor({\n publicKey: langfuse.publicKey,\n secretKey: langfuse.secretKey,\n ...(isPresent(langfuse.baseUrl) ? { baseUrl: langfuse.baseUrl } : {}),\n environment:\n process.env.LANGFUSE_TRACING_ENVIRONMENT ??\n process.env.NODE_ENV ??\n 'development',\n exportMode: 'immediate',\n });\n this.provider = new BasicTracerProvider({\n spanProcessors: [this.processor],\n });\n }\n\n private startGenerationSpan({\n llm,\n input,\n runId,\n extraParams,\n metadata,\n name,\n }: {\n llm: Serialized;\n input: unknown;\n runId: string;\n extraParams?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n name?: string;\n }): void {\n if (this.spans.has(runId)) {\n return;\n }\n\n const tracer = this.provider.getTracer('librechat-agents-langfuse');\n const spanName =\n typeof name === 'string' && name.trim() !== '' ? name : getModelName(llm);\n const span = tracer.startSpan(spanName, {\n attributes: {\n ...createTraceAttributes({\n name: getTraceName(this.traceMetadata),\n userId: this.userId,\n sessionId: this.sessionId,\n metadata: this.traceMetadata,\n }),\n ...createObservationAttributes('generation', {\n input,\n model: getModelName(llm),\n modelParameters: getModelParameters(extraParams),\n metadata: {\n ...metadata,\n ...this.traceMetadata,\n },\n }),\n },\n });\n this.spans.set(runId, span);\n }\n\n async handleChatModelStart(\n llm: Serialized,\n messages: BaseMessage[][],\n runId: string,\n _parentRunId?: string,\n extraParams?: Record<string, unknown>,\n _tags?: string[],\n metadata?: Record<string, unknown>,\n name?: string\n ): Promise<void> {\n this.startGenerationSpan({\n llm,\n input: messages,\n runId,\n extraParams,\n metadata,\n name,\n });\n }\n\n async handleLLMStart(\n llm: Serialized,\n prompts: string[],\n runId: string,\n _parentRunId?: string,\n extraParams?: Record<string, unknown>,\n _tags?: string[],\n metadata?: Record<string, unknown>,\n name?: string\n ): Promise<void> {\n this.startGenerationSpan({\n llm,\n input: prompts,\n runId,\n extraParams,\n metadata,\n name,\n });\n }\n\n async handleLLMEnd(output: LLMResult, runId: string): Promise<void> {\n const span = this.spans.get(runId);\n if (!span) {\n return;\n }\n\n span.setAttributes(\n createObservationAttributes('generation', {\n output: getOutput(output),\n usageDetails: getUsageDetails(output),\n })\n );\n span.end();\n this.spans.delete(runId);\n await this.flush();\n }\n\n async handleLLMError(err: unknown, runId: string): Promise<void> {\n const span = this.spans.get(runId);\n if (!span) {\n return;\n }\n\n const message = err instanceof Error ? err.message : String(err);\n span.setStatus({ code: SpanStatusCode.ERROR, message });\n span.setAttributes(\n createObservationAttributes('generation', {\n level: 'ERROR',\n statusMessage: message,\n })\n );\n span.end();\n this.spans.delete(runId);\n await this.flush();\n }\n\n private async flush(): Promise<void> {\n try {\n await this.provider.forceFlush();\n } catch (error) {\n process.emitWarning(\n `[LangfuseAgentCallbackHandler] Failed to flush Langfuse spans: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n async dispose(): Promise<void> {\n for (const span of this.spans.values()) {\n span.end();\n }\n this.spans.clear();\n await this.flush();\n try {\n await this.provider.shutdown();\n } catch (error) {\n process.emitWarning(\n `[LangfuseAgentCallbackHandler] Failed to shut down Langfuse provider: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n}\n\nfunction hasRequiredLangfuseConfig(\n langfuse?: t.LangfuseConfig\n): langfuse is ResolvedLangfuseConfig {\n return (\n langfuse?.enabled === true &&\n isPresent(langfuse.publicKey) &&\n isPresent(langfuse.secretKey)\n );\n}\n\nexport function createLegacyLangfuseHandler(\n params: LangfuseHandlerParams\n): CallbackHandler {\n return new CallbackHandler(params);\n}\n\nexport function createLangfuseHandler({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n}: AgentLangfuseHandlerParams): LangfuseAgentCallbackHandler | undefined {\n if (!hasRequiredLangfuseConfig(langfuse)) {\n return undefined;\n }\n\n return new LangfuseAgentCallbackHandler({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n });\n}\n\nexport function hasExplicitLangfuseConfig(\n contexts: Iterable<{ langfuse?: t.LangfuseConfig }>\n): boolean {\n for (const context of contexts) {\n if (context.langfuse != null) {\n return true;\n }\n }\n return false;\n}\n\nexport function hasLangfuseEnvConfig(): boolean {\n return (\n isPresent(process.env.LANGFUSE_SECRET_KEY) &&\n isPresent(process.env.LANGFUSE_PUBLIC_KEY) &&\n isPresent(process.env.LANGFUSE_BASE_URL)\n );\n}\n\nexport function isLangfuseCallbackHandler(value: unknown): boolean {\n return (\n value instanceof CallbackHandler ||\n value instanceof LangfuseAgentCallbackHandler\n );\n}\n\nexport async function disposeLangfuseHandler(value: unknown): Promise<void> {\n if (value instanceof LangfuseAgentCallbackHandler) {\n await value.dispose();\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { AIMessageChunk } from '@langchain/core/messages';
|
|
|
2
2
|
import { ChatAnthropicMessages } from '@langchain/anthropic';
|
|
3
3
|
import { ChatGenerationChunk } from '@langchain/core/outputs';
|
|
4
4
|
import { _makeMessageChunkFromAnthropicEvent } from './utils/message_outputs.mjs';
|
|
5
|
-
import { _convertMessagesToAnthropicPayload } from './utils/message_inputs.mjs';
|
|
5
|
+
import { stripUnsupportedAssistantPrefill, _convertMessagesToAnthropicPayload } from './utils/message_inputs.mjs';
|
|
6
6
|
import { handleToolChoice } from './utils/tools.mjs';
|
|
7
7
|
|
|
8
8
|
const DEFAULT_STREAM_DELAY = 25;
|
|
@@ -370,15 +370,21 @@ class CustomAnthropic extends ChatAnthropicMessages {
|
|
|
370
370
|
text: token ?? '',
|
|
371
371
|
});
|
|
372
372
|
}
|
|
373
|
+
async createStreamWithRetry(request, options) {
|
|
374
|
+
return super.createStreamWithRetry(stripUnsupportedAssistantPrefill(request), options);
|
|
375
|
+
}
|
|
376
|
+
async completionWithRetry(request, options) {
|
|
377
|
+
return super.completionWithRetry(stripUnsupportedAssistantPrefill(request), options);
|
|
378
|
+
}
|
|
373
379
|
async *_streamResponseChunks(messages, options, runManager) {
|
|
374
380
|
this.resetTokenEvents();
|
|
375
381
|
const params = this.invocationParams(options);
|
|
376
382
|
const formattedMessages = _convertMessagesToAnthropicPayload(messages);
|
|
377
|
-
const payload = {
|
|
383
|
+
const payload = stripUnsupportedAssistantPrefill({
|
|
378
384
|
...params,
|
|
379
385
|
...formattedMessages,
|
|
380
386
|
stream: true,
|
|
381
|
-
};
|
|
387
|
+
});
|
|
382
388
|
const coerceContentToString = !_toolsInParams(payload) &&
|
|
383
389
|
!_documentsInParams(payload) &&
|
|
384
390
|
!_thinkingInParams(payload) &&
|