@librechat/agents 3.2.44 → 3.2.46
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/graphs/Graph.cjs +17 -8
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/instrumentation.cjs +20 -21
- package/dist/cjs/instrumentation.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +65 -13
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/langfuseConfig.cjs +106 -0
- package/dist/cjs/langfuseConfig.cjs.map +1 -0
- package/dist/cjs/langfuseRuntimeContext.cjs +48 -0
- package/dist/cjs/langfuseRuntimeContext.cjs.map +1 -0
- package/dist/cjs/langfuseRuntimeScope.cjs +57 -0
- package/dist/cjs/langfuseRuntimeScope.cjs.map +1 -0
- package/dist/cjs/langfuseToolOutputTracing.cjs +14 -119
- package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
- package/dist/cjs/main.cjs +1 -0
- package/dist/cjs/messages/format.cjs +1 -1
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/run.cjs +25 -12
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +5 -2
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/utils/misc.cjs +17 -0
- package/dist/cjs/utils/misc.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +16 -7
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/instrumentation.mjs +22 -22
- package/dist/esm/instrumentation.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +65 -14
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/langfuseConfig.mjs +102 -0
- package/dist/esm/langfuseConfig.mjs.map +1 -0
- package/dist/esm/langfuseRuntimeContext.mjs +44 -0
- package/dist/esm/langfuseRuntimeContext.mjs.map +1 -0
- package/dist/esm/langfuseRuntimeScope.mjs +53 -0
- package/dist/esm/langfuseRuntimeScope.mjs.map +1 -0
- package/dist/esm/langfuseToolOutputTracing.mjs +13 -115
- package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
- package/dist/esm/main.mjs +2 -2
- package/dist/esm/messages/format.mjs +1 -1
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/run.mjs +21 -8
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +5 -2
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/utils/misc.mjs +17 -1
- package/dist/esm/utils/misc.mjs.map +1 -1
- package/dist/types/instrumentation.d.ts +0 -1
- package/dist/types/langfuse.d.ts +5 -1
- package/dist/types/langfuseConfig.d.ts +7 -0
- package/dist/types/langfuseRuntimeContext.d.ts +26 -0
- package/dist/types/langfuseRuntimeScope.d.ts +17 -0
- package/dist/types/langfuseToolOutputTracing.d.ts +4 -11
- package/dist/types/messages/format.d.ts +4 -0
- package/dist/types/types/graph.d.ts +6 -0
- package/dist/types/utils/misc.d.ts +1 -0
- package/package.json +1 -1
- package/src/graphs/Graph.ts +20 -13
- package/src/instrumentation.ts +33 -29
- package/src/langfuse.ts +114 -7
- package/src/langfuseConfig.ts +214 -0
- package/src/langfuseRuntimeContext.ts +93 -0
- package/src/langfuseRuntimeScope.ts +135 -0
- package/src/langfuseToolOutputTracing.ts +25 -263
- package/src/messages/format.ts +6 -1
- package/src/messages/formatAgentMessages.test.ts +76 -0
- package/src/run.ts +44 -34
- package/src/specs/deterministic-trace-id.test.ts +4 -11
- package/src/specs/langfuse-callbacks.test.ts +278 -22
- package/src/specs/langfuse-config.test.ts +10 -3
- package/src/specs/langfuse-instrumentation.test.ts +32 -12
- package/src/specs/langfuse-routing.integration.test.ts +543 -0
- package/src/specs/langfuse-runtime-context.test.ts +92 -0
- package/src/specs/langfuse-tool-output-tracing.test.ts +353 -5
- package/src/tools/ToolNode.ts +10 -5
- package/src/tools/__tests__/ToolNode.langfuse.test.ts +21 -11
- package/src/types/graph.ts +9 -0
- package/src/utils/misc.ts +18 -0
package/dist/esm/utils/misc.mjs
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
function isPresent(value) {
|
|
3
3
|
return value != null && value !== "";
|
|
4
4
|
}
|
|
5
|
+
function parseBooleanEnv(value) {
|
|
6
|
+
if (value == null) return;
|
|
7
|
+
const normalized = value.trim().toLowerCase();
|
|
8
|
+
if ([
|
|
9
|
+
"1",
|
|
10
|
+
"true",
|
|
11
|
+
"yes",
|
|
12
|
+
"on"
|
|
13
|
+
].includes(normalized)) return true;
|
|
14
|
+
if ([
|
|
15
|
+
"0",
|
|
16
|
+
"false",
|
|
17
|
+
"no",
|
|
18
|
+
"off"
|
|
19
|
+
].includes(normalized)) return false;
|
|
20
|
+
}
|
|
5
21
|
/**
|
|
6
22
|
* Unescapes a c-escaped string
|
|
7
23
|
* @param str The string to unescape
|
|
@@ -34,6 +50,6 @@ function unescapeObject(obj, key) {
|
|
|
34
50
|
return obj;
|
|
35
51
|
}
|
|
36
52
|
//#endregion
|
|
37
|
-
export { isPresent, unescapeObject };
|
|
53
|
+
export { isPresent, parseBooleanEnv, unescapeObject };
|
|
38
54
|
|
|
39
55
|
//# sourceMappingURL=misc.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"misc.mjs","names":[],"sources":["../../../src/utils/misc.ts"],"sourcesContent":["export function isPresent(value: string | null | undefined): value is string {\n return value != null && value !== '';\n}\n\n/**\n * Unescapes a c-escaped string\n * @param str The string to unescape\n * @returns The unescaped string\n */\nconst unescapeString = (string: string): string =>\n string.replace(/\\\\(.)/g, (_, char) => {\n switch (char) {\n case 'n':\n return '\\n';\n case 't':\n return '\\t';\n case 'r':\n return '\\r';\n case '\"':\n return '\"';\n case '\\'':\n return '\\'';\n case '\\\\':\n return '\\\\';\n default:\n return char;\n }\n });\n\n/**\n * Recursively unescapes all string values in an object\n * @param obj The object to unescape\n * @returns The unescaped object\n */\nexport function unescapeObject(obj: unknown, key?: string): unknown {\n if (typeof obj === 'string') {\n let unescaped = unescapeString(obj);\n if (key === 'filePath' && unescaped.match(/^\"(.+)\"$/)) {\n unescaped = unescaped.substring(1, unescaped.length - 1);\n }\n return unescaped;\n }\n if (Array.isArray(obj)) {\n return obj.map((value) =>\n unescapeObject(value, key === 'contextPaths' ? 'filePath' : '')\n );\n }\n if (typeof obj === 'object' && obj !== null) {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => [\n key,\n unescapeObject(value, key),\n ])\n );\n }\n return obj;\n}\n"],"mappings":";AAAA,SAAgB,UAAU,OAAmD;CAC3E,OAAO,SAAS,QAAQ,UAAU;AACpC;;;;;;AAOA,MAAM,kBAAkB,WACtB,OAAO,QAAQ,WAAW,GAAG,SAAS;CACpC,QAAQ,MAAR;EACA,KAAK,KACH,OAAO;EACT,KAAK,KACH,OAAO;EACT,KAAK,KACH,OAAO;EACT,KAAK,MACH,OAAO;EACT,KAAK,KACH,OAAO;EACT,KAAK,MACH,OAAO;EACT,SACE,OAAO;CACT;AACF,CAAC;;;;;;AAOH,SAAgB,eAAe,KAAc,KAAuB;CAClE,IAAI,OAAO,QAAQ,UAAU;EAC3B,IAAI,YAAY,eAAe,GAAG;EAClC,IAAI,QAAQ,cAAc,UAAU,MAAM,UAAU,GAClD,YAAY,UAAU,UAAU,GAAG,UAAU,SAAS,CAAC;EAEzD,OAAO;CACT;CACA,IAAI,MAAM,QAAQ,GAAG,GACnB,OAAO,IAAI,KAAK,UACd,eAAe,OAAO,QAAQ,iBAAiB,aAAa,EAAE,CAChE;CAEF,IAAI,OAAO,QAAQ,YAAY,QAAQ,MACrC,OAAO,OAAO,YACZ,OAAO,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,CACxC,KACA,eAAe,OAAO,GAAG,CAC3B,CAAC,CACH;CAEF,OAAO;AACT"}
|
|
1
|
+
{"version":3,"file":"misc.mjs","names":[],"sources":["../../../src/utils/misc.ts"],"sourcesContent":["export function isPresent(value: string | null | undefined): value is string {\n return value != null && value !== '';\n}\n\nexport function parseBooleanEnv(\n value: string | undefined\n): boolean | undefined {\n if (value == null) {\n return undefined;\n }\n\n const normalized = value.trim().toLowerCase();\n if (['1', 'true', 'yes', 'on'].includes(normalized)) {\n return true;\n }\n if (['0', 'false', 'no', 'off'].includes(normalized)) {\n return false;\n }\n\n return undefined;\n}\n\n/**\n * Unescapes a c-escaped string\n * @param str The string to unescape\n * @returns The unescaped string\n */\nconst unescapeString = (string: string): string =>\n string.replace(/\\\\(.)/g, (_, char) => {\n switch (char) {\n case 'n':\n return '\\n';\n case 't':\n return '\\t';\n case 'r':\n return '\\r';\n case '\"':\n return '\"';\n case '\\'':\n return '\\'';\n case '\\\\':\n return '\\\\';\n default:\n return char;\n }\n });\n\n/**\n * Recursively unescapes all string values in an object\n * @param obj The object to unescape\n * @returns The unescaped object\n */\nexport function unescapeObject(obj: unknown, key?: string): unknown {\n if (typeof obj === 'string') {\n let unescaped = unescapeString(obj);\n if (key === 'filePath' && unescaped.match(/^\"(.+)\"$/)) {\n unescaped = unescaped.substring(1, unescaped.length - 1);\n }\n return unescaped;\n }\n if (Array.isArray(obj)) {\n return obj.map((value) =>\n unescapeObject(value, key === 'contextPaths' ? 'filePath' : '')\n );\n }\n if (typeof obj === 'object' && obj !== null) {\n return Object.fromEntries(\n Object.entries(obj).map(([key, value]) => [\n key,\n unescapeObject(value, key),\n ])\n );\n }\n return obj;\n}\n"],"mappings":";AAAA,SAAgB,UAAU,OAAmD;CAC3E,OAAO,SAAS,QAAQ,UAAU;AACpC;AAEA,SAAgB,gBACd,OACqB;CACrB,IAAI,SAAS,MACX;CAGF,MAAM,aAAa,MAAM,KAAK,CAAC,CAAC,YAAY;CAC5C,IAAI;EAAC;EAAK;EAAQ;EAAO;CAAI,CAAC,CAAC,SAAS,UAAU,GAChD,OAAO;CAET,IAAI;EAAC;EAAK;EAAS;EAAM;CAAK,CAAC,CAAC,SAAS,UAAU,GACjD,OAAO;AAIX;;;;;;AAOA,MAAM,kBAAkB,WACtB,OAAO,QAAQ,WAAW,GAAG,SAAS;CACpC,QAAQ,MAAR;EACA,KAAK,KACH,OAAO;EACT,KAAK,KACH,OAAO;EACT,KAAK,KACH,OAAO;EACT,KAAK,MACH,OAAO;EACT,KAAK,KACH,OAAO;EACT,KAAK,MACH,OAAO;EACT,SACE,OAAO;CACT;AACF,CAAC;;;;;;AAOH,SAAgB,eAAe,KAAc,KAAuB;CAClE,IAAI,OAAO,QAAQ,UAAU;EAC3B,IAAI,YAAY,eAAe,GAAG;EAClC,IAAI,QAAQ,cAAc,UAAU,MAAM,UAAU,GAClD,YAAY,UAAU,UAAU,GAAG,UAAU,SAAS,CAAC;EAEzD,OAAO;CACT;CACA,IAAI,MAAM,QAAQ,GAAG,GACnB,OAAO,IAAI,KAAK,UACd,eAAe,OAAO,QAAQ,iBAAiB,aAAa,EAAE,CAChE;CAEF,IAAI,OAAO,QAAQ,YAAY,QAAQ,MACrC,OAAO,OAAO,YACZ,OAAO,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,WAAW,CACxC,KACA,eAAe,OAAO,GAAG,CAC3B,CAAC,CACH;CAEF,OAAO;AACT"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
|
|
2
2
|
import type * as t from '@/types';
|
|
3
|
-
export declare function runWithTraceIdSeed<T>(seed: string | undefined, fn: () => T): T;
|
|
4
3
|
export declare function ensureOpenTelemetryContextManager(): void;
|
|
5
4
|
export declare function initializeLangfuseTracing(langfuse?: t.LangfuseConfig): BasicTracerProvider | undefined;
|
|
6
5
|
export declare function initializeLangfuseTracingFromEnv(): BasicTracerProvider | undefined;
|
package/dist/types/langfuse.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { CallbackHandler } from '@langfuse/langchain';
|
|
2
2
|
import type * as t from '@/types';
|
|
3
3
|
export type LangfuseTraceMetadata = Record<string, string>;
|
|
4
|
+
export type LangfuseTraceAttributes = Record<string, string | number | boolean>;
|
|
5
|
+
type LangfuseConfigTraceAttributes = NonNullable<t.LangfuseConfig['librechatTraceAttributes']>;
|
|
4
6
|
type LangfuseHandlerParams = {
|
|
5
7
|
userId?: string;
|
|
6
8
|
sessionId?: string;
|
|
7
9
|
traceMetadata?: LangfuseTraceMetadata;
|
|
8
10
|
tags?: string[];
|
|
11
|
+
traceIdSeed?: string;
|
|
9
12
|
};
|
|
10
13
|
type AgentLangfuseHandlerParams = LangfuseHandlerParams & {
|
|
11
14
|
langfuse?: t.LangfuseConfig;
|
|
@@ -18,6 +21,7 @@ export declare function hasLangfuseConfigCredentials(langfuse?: t.LangfuseConfig
|
|
|
18
21
|
secretKey: string;
|
|
19
22
|
};
|
|
20
23
|
export declare function isExplicitLangfuseConfig(langfuse?: t.LangfuseConfig): boolean;
|
|
24
|
+
export declare function createLibreChatTraceAttributes(attributes: LangfuseConfigTraceAttributes): LangfuseTraceAttributes;
|
|
21
25
|
export declare function createLangfuseTraceMetadata({ messageId, parentMessageId, agentId, agentName, }: {
|
|
22
26
|
messageId?: unknown;
|
|
23
27
|
parentMessageId?: unknown;
|
|
@@ -29,7 +33,7 @@ export declare function hasLangfuseEnvConfig(): boolean;
|
|
|
29
33
|
export declare function hasLangfuseEnvCredentials(): boolean;
|
|
30
34
|
export declare function shouldCreateLangfuseHandler(langfuse?: t.LangfuseConfig): boolean;
|
|
31
35
|
export declare function createLegacyLangfuseHandler(params: LangfuseHandlerParams): CallbackHandler;
|
|
32
|
-
export declare function createLangfuseHandler({ langfuse, userId, sessionId, traceMetadata, tags, }: AgentLangfuseHandlerParams): CallbackHandler | undefined;
|
|
36
|
+
export declare function createLangfuseHandler({ langfuse, userId, sessionId, traceMetadata, tags, traceIdSeed, }: AgentLangfuseHandlerParams): CallbackHandler | undefined;
|
|
33
37
|
export declare function withLangfuseAttributes<T>(params: LangfuseAttributeParams, action: () => T): T;
|
|
34
38
|
export declare function hasExplicitLangfuseConfig(contexts: Iterable<{
|
|
35
39
|
langfuse?: t.LangfuseConfig;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ResolvedLangfuseToolOutputTracingConfig } from '@/langfuseRuntimeContext';
|
|
2
|
+
import type * as t from '@/types';
|
|
3
|
+
export declare const LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT = "[tool output redacted]";
|
|
4
|
+
export declare function normalizeToolName(name: string): string;
|
|
5
|
+
export declare function hasToolOutputTracingConfig(runLangfuse?: t.LangfuseConfig, agentLangfuse?: t.LangfuseConfig): boolean;
|
|
6
|
+
export declare function resolveToolOutputTracingConfig(runLangfuse?: t.LangfuseConfig, agentLangfuse?: t.LangfuseConfig): ResolvedLangfuseToolOutputTracingConfig;
|
|
7
|
+
export declare function resolveLangfuseConfig(runLangfuse?: t.LangfuseConfig, agentLangfuse?: t.LangfuseConfig): t.LangfuseConfig | undefined;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type * as t from '@/types';
|
|
2
|
+
export type ResolvedLangfuseToolOutputTracingConfig = {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
redactedToolNames: Set<string>;
|
|
5
|
+
redactedToolNameMatchMode: 'exact' | 'partial';
|
|
6
|
+
redactionText: string;
|
|
7
|
+
};
|
|
8
|
+
export type LangfuseRuntimeContext = {
|
|
9
|
+
langfuse?: t.LangfuseConfig;
|
|
10
|
+
traceIdSeed?: string;
|
|
11
|
+
toolOutputTracing?: ResolvedLangfuseToolOutputTracingConfig;
|
|
12
|
+
};
|
|
13
|
+
export declare function hasLangfuseRuntimeContextValue(context: LangfuseRuntimeContext): boolean;
|
|
14
|
+
/** sha256(seed) -> first 32 hex chars; matches `@langfuse/tracing` `createTraceId`. */
|
|
15
|
+
export declare function traceIdFromSeed(seed: string): string;
|
|
16
|
+
export declare function getLangfuseRuntimeContext(): LangfuseRuntimeContext | undefined;
|
|
17
|
+
export declare function getLangfuseRuntimeConfig(): t.LangfuseConfig | undefined;
|
|
18
|
+
export declare function getTraceIdSeed(): string | undefined;
|
|
19
|
+
export declare function getLangfuseRuntimeToolOutputTracingConfig(): ResolvedLangfuseToolOutputTracingConfig | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Runs `fn` with a merged Langfuse runtime context. Undefined fields inherit
|
|
22
|
+
* from the parent scope; callers intentionally cannot clear parent values by
|
|
23
|
+
* passing `undefined`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function runWithLangfuseRuntimeContext<T>(context: LangfuseRuntimeContext, fn: () => T): T;
|
|
26
|
+
export declare function runWithTraceIdSeed<T>(seed: string | undefined, fn: () => T): T;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Context } from '@opentelemetry/api';
|
|
2
|
+
import type { LangfuseRuntimeContext, ResolvedLangfuseToolOutputTracingConfig } from '@/langfuseRuntimeContext';
|
|
3
|
+
import type * as t from '@/types';
|
|
4
|
+
export type LangfuseRuntimeScope = LangfuseRuntimeContext;
|
|
5
|
+
export type ResolveLangfuseRuntimeScopeParams = {
|
|
6
|
+
runLangfuse?: t.LangfuseConfig;
|
|
7
|
+
langfuseOverlay?: t.LangfuseConfig;
|
|
8
|
+
traceIdSeed?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function getOtelLangfuseConfig(activeContext: Context): t.LangfuseConfig | undefined;
|
|
11
|
+
export declare function getOtelTraceIdSeed(activeContext: Context): string | undefined;
|
|
12
|
+
export declare function getOtelToolOutputTracingConfig(activeContext: Context): ResolvedLangfuseToolOutputTracingConfig | undefined;
|
|
13
|
+
export declare function resolveLangfuseConfigForSpan(activeContext: Context): t.LangfuseConfig | undefined;
|
|
14
|
+
export declare function resolveTraceIdSeedForSpan(activeContext: Context): string | undefined;
|
|
15
|
+
export declare function resolveToolOutputTracingConfigForSpan(activeContext: Context): ResolvedLangfuseToolOutputTracingConfig | undefined;
|
|
16
|
+
export declare function withLangfuseRuntimeScope<T>(scope: LangfuseRuntimeScope, action: () => T): T;
|
|
17
|
+
export declare function resolveLangfuseRuntimeScope({ runLangfuse, langfuseOverlay, traceIdSeed, }: ResolveLangfuseRuntimeScopeParams): LangfuseRuntimeScope;
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
import type { ReadableSpan, SpanProcessor } from '@opentelemetry/sdk-trace-base';
|
|
2
2
|
import type { LangfuseSpanProcessorParams } from '@langfuse/otel';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ResolvedLangfuseToolOutputTracingConfig } from '@/langfuseRuntimeContext';
|
|
4
4
|
import type * as t from '@/types';
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
redactedToolNames: Set<string>;
|
|
9
|
-
redactedToolNameMatchMode: 'exact' | 'partial';
|
|
10
|
-
redactionText: string;
|
|
11
|
-
};
|
|
5
|
+
import { LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT, resolveLangfuseConfig } from '@/langfuseConfig';
|
|
6
|
+
export { LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT, resolveLangfuseConfig };
|
|
7
|
+
export declare function classifyLangfuseToolNodeSpan(span: ReadableSpan): void;
|
|
12
8
|
export declare function redactLangfuseSpanToolOutputs(span: ReadableSpan, config: ResolvedLangfuseToolOutputTracingConfig): void;
|
|
13
|
-
export declare function getContextLangfuseConfig(activeContext: Context): t.LangfuseConfig | undefined;
|
|
14
9
|
export declare function createLangfuseSpanProcessor(params?: LangfuseSpanProcessorParams, runLangfuse?: t.LangfuseConfig, agentLangfuse?: t.LangfuseConfig): SpanProcessor;
|
|
15
|
-
export declare function withLangfuseToolOutputTracingConfig<T>(runLangfuse: t.LangfuseConfig | undefined, action: () => T, agentLangfuse?: t.LangfuseConfig): T;
|
|
16
10
|
export declare function shouldTraceToolNodeForLangfuse({ runLangfuse, agentLangfuse, }: {
|
|
17
11
|
runLangfuse?: t.LangfuseConfig;
|
|
18
12
|
agentLangfuse?: t.LangfuseConfig;
|
|
19
13
|
}): boolean;
|
|
20
|
-
export declare function resolveLangfuseConfig(runLangfuse?: t.LangfuseConfig, agentLangfuse?: t.LangfuseConfig): t.LangfuseConfig | undefined;
|
|
@@ -91,6 +91,10 @@ interface LangChainMessage {
|
|
|
91
91
|
export declare const formatFromLangChain: (message: LangChainMessage) => Record<string, any>;
|
|
92
92
|
interface FormatAgentMessagesOptions {
|
|
93
93
|
provider?: Providers;
|
|
94
|
+
/** Reconstruct hidden `reasoning_content` from `THINK` parts onto prior
|
|
95
|
+
* tool-call messages. Explicit opt-in for OpenAI-compatible endpoints that
|
|
96
|
+
* replay reasoning across turns; defaults to on for DeepSeek thinking-mode. */
|
|
97
|
+
preserveReasoningContent?: boolean;
|
|
94
98
|
/** Skill names already primed fresh this turn (manual/always-apply). Their
|
|
95
99
|
* historical `skill` tool_calls are not reconstructed into a HumanMessage,
|
|
96
100
|
* so the same SKILL.md body is not injected twice in one request. */
|
|
@@ -408,6 +408,12 @@ export interface LangfuseConfig {
|
|
|
408
408
|
secretKey?: string;
|
|
409
409
|
baseUrl?: string;
|
|
410
410
|
metadata?: Record<string, string | number | boolean | null | undefined>;
|
|
411
|
+
/**
|
|
412
|
+
* Internal OTLP span attributes to attach to Langfuse observations before
|
|
413
|
+
* export. Intended for collector-side routing/filtering; strip these in the
|
|
414
|
+
* collector before forwarding spans to Langfuse.
|
|
415
|
+
*/
|
|
416
|
+
librechatTraceAttributes?: Record<string, string | number | boolean | null | undefined>;
|
|
411
417
|
tags?: string[];
|
|
412
418
|
toolNodeTracing?: LangfuseToolNodeTracingConfig;
|
|
413
419
|
toolOutputTracing?: LangfuseToolOutputTracingConfig;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare function isPresent(value: string | null | undefined): value is string;
|
|
2
|
+
export declare function parseBooleanEnv(value: string | undefined): boolean | undefined;
|
|
2
3
|
/**
|
|
3
4
|
* Recursively unescapes all string values in an object
|
|
4
5
|
* @param obj The object to unescape
|
package/package.json
CHANGED
package/src/graphs/Graph.ts
CHANGED
|
@@ -34,11 +34,6 @@ import {
|
|
|
34
34
|
makeIsDeferred,
|
|
35
35
|
partitionAndMarkAnthropicToolCache,
|
|
36
36
|
} from '@/messages';
|
|
37
|
-
import {
|
|
38
|
-
resolveLangfuseConfig,
|
|
39
|
-
shouldTraceToolNodeForLangfuse,
|
|
40
|
-
withLangfuseToolOutputTracingConfig,
|
|
41
|
-
} from '@/langfuseToolOutputTracing';
|
|
42
37
|
import {
|
|
43
38
|
createLangfuseHandler,
|
|
44
39
|
createLangfuseTraceMetadata,
|
|
@@ -54,6 +49,10 @@ import {
|
|
|
54
49
|
joinKeys,
|
|
55
50
|
sleep,
|
|
56
51
|
} from '@/utils';
|
|
52
|
+
import {
|
|
53
|
+
resolveLangfuseRuntimeScope,
|
|
54
|
+
withLangfuseRuntimeScope,
|
|
55
|
+
} from '@/langfuseRuntimeScope';
|
|
57
56
|
import {
|
|
58
57
|
GraphNodeKeys,
|
|
59
58
|
ContentTypes,
|
|
@@ -67,6 +66,7 @@ import {
|
|
|
67
66
|
type CallbackEntry,
|
|
68
67
|
} from '@/utils/callbacks';
|
|
69
68
|
import { partitionAndMarkOpenRouterToolCache } from '@/llm/openrouter/toolCache';
|
|
69
|
+
import { shouldTraceToolNodeForLangfuse } from '@/langfuseToolOutputTracing';
|
|
70
70
|
import { ToolNode as CustomToolNode, toolsCondition } from '@/tools/ToolNode';
|
|
71
71
|
import { createLocalCodingToolBundle } from '@/tools/local/LocalCodingTools';
|
|
72
72
|
import { SubagentExecutor, resolveSubagentConfigs } from '@/tools/subagent';
|
|
@@ -81,6 +81,7 @@ import { shouldTriggerSummarization } from '@/summarization';
|
|
|
81
81
|
import { resolveLocalToolsForBinding } from '@/tools/local';
|
|
82
82
|
import { createSummarizeNode } from '@/summarization/node';
|
|
83
83
|
import { messagesStateReducer } from '@/messages/reducer';
|
|
84
|
+
import { resolveLangfuseConfig } from '@/langfuseConfig';
|
|
84
85
|
import { createSchemaOnlyTools } from '@/tools/schema';
|
|
85
86
|
import { AgentContext } from '@/agents/AgentContext';
|
|
86
87
|
import { createFakeStreamingLLM } from '@/llm/fake';
|
|
@@ -2079,6 +2080,8 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2079
2080
|
sessionId: config.configurable?.thread_id as string | undefined,
|
|
2080
2081
|
traceMetadata,
|
|
2081
2082
|
tags: ['librechat', 'agent'],
|
|
2083
|
+
traceIdSeed:
|
|
2084
|
+
langfuse?.deterministicTraceId === true ? this.runId : undefined,
|
|
2082
2085
|
});
|
|
2083
2086
|
if (langfuseHandler != null) {
|
|
2084
2087
|
invokeConfig = {
|
|
@@ -2092,8 +2095,11 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2092
2095
|
const metadata = config.metadata as Record<string, unknown>;
|
|
2093
2096
|
|
|
2094
2097
|
try {
|
|
2095
|
-
result = await
|
|
2096
|
-
|
|
2098
|
+
result = await withLangfuseRuntimeScope(
|
|
2099
|
+
resolveLangfuseRuntimeScope({
|
|
2100
|
+
runLangfuse: this.langfuse,
|
|
2101
|
+
langfuseOverlay: agentContext.langfuse,
|
|
2102
|
+
}),
|
|
2097
2103
|
() =>
|
|
2098
2104
|
attemptInvoke(
|
|
2099
2105
|
{
|
|
@@ -2103,16 +2109,18 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2103
2109
|
context: this,
|
|
2104
2110
|
},
|
|
2105
2111
|
invokeConfig
|
|
2106
|
-
)
|
|
2107
|
-
agentContext.langfuse
|
|
2112
|
+
)
|
|
2108
2113
|
);
|
|
2109
2114
|
} catch (primaryError) {
|
|
2110
2115
|
clearCurrentDeltaStepMarkers({
|
|
2111
2116
|
graph: this,
|
|
2112
2117
|
metadata,
|
|
2113
2118
|
});
|
|
2114
|
-
result = await
|
|
2115
|
-
|
|
2119
|
+
result = await withLangfuseRuntimeScope(
|
|
2120
|
+
resolveLangfuseRuntimeScope({
|
|
2121
|
+
runLangfuse: this.langfuse,
|
|
2122
|
+
langfuseOverlay: agentContext.langfuse,
|
|
2123
|
+
}),
|
|
2116
2124
|
() =>
|
|
2117
2125
|
tryFallbackProviders({
|
|
2118
2126
|
fallbacks,
|
|
@@ -2121,8 +2129,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2121
2129
|
config: invokeConfig,
|
|
2122
2130
|
primaryError,
|
|
2123
2131
|
context: this,
|
|
2124
|
-
})
|
|
2125
|
-
agentContext.langfuse
|
|
2132
|
+
})
|
|
2126
2133
|
);
|
|
2127
2134
|
} finally {
|
|
2128
2135
|
await disposeLangfuseHandler(langfuseHandler);
|
package/src/instrumentation.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
1
|
import { createHash, randomBytes } from 'node:crypto';
|
|
3
2
|
import { setLangfuseTracerProvider } from '@langfuse/tracing';
|
|
4
3
|
import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
|
|
@@ -14,43 +13,33 @@ import type { LangfuseSpanProcessorParams } from '@langfuse/otel';
|
|
|
14
13
|
import type { Context } from '@opentelemetry/api';
|
|
15
14
|
import type * as t from '@/types';
|
|
16
15
|
import {
|
|
16
|
+
createLibreChatTraceAttributes,
|
|
17
17
|
hasLangfuseConfigCredentials,
|
|
18
18
|
hasLangfuseEnvCredentials,
|
|
19
19
|
hasLangfuseEnvConfig,
|
|
20
20
|
} from '@/langfuse';
|
|
21
21
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
} from '@/
|
|
22
|
+
resolveLangfuseConfigForSpan,
|
|
23
|
+
resolveTraceIdSeedForSpan,
|
|
24
|
+
} from '@/langfuseRuntimeScope';
|
|
25
|
+
import { createLangfuseSpanProcessor } from '@/langfuseToolOutputTracing';
|
|
26
|
+
import { traceIdFromSeed } from '@/langfuseRuntimeContext';
|
|
25
27
|
import { isPresent } from '@/utils/misc';
|
|
26
28
|
|
|
27
29
|
/**
|
|
28
30
|
* Per-run seed for deterministic Langfuse trace ids. When a run opts in
|
|
29
31
|
* (`LangfuseConfig.deterministicTraceId`), it executes its stream inside
|
|
30
|
-
* `runWithTraceIdSeed(runId,
|
|
31
|
-
* trace id from that seed instead of a
|
|
32
|
-
* (e.g. a host app recording user
|
|
33
|
-
*
|
|
34
|
-
* id
|
|
35
|
-
* ids, so default behavior is
|
|
32
|
+
* `runWithTraceIdSeed(runId, ...)` from `./langfuseRuntimeContext`, and the
|
|
33
|
+
* IdGenerator below derives the root trace id from that seed instead of a
|
|
34
|
+
* random one. This lets external systems (e.g. a host app recording user
|
|
35
|
+
* feedback after the fact) attach scores or observations to the trace by
|
|
36
|
+
* regenerating the same id from the run/message id; no trace lookup required.
|
|
37
|
+
* With no active seed it falls back to random ids, so default behavior is
|
|
38
|
+
* unchanged.
|
|
36
39
|
*/
|
|
37
|
-
const traceIdSeedStore = new AsyncLocalStorage<string>();
|
|
38
|
-
|
|
39
|
-
export function runWithTraceIdSeed<T>(
|
|
40
|
-
seed: string | undefined,
|
|
41
|
-
fn: () => T
|
|
42
|
-
): T {
|
|
43
|
-
return isPresent(seed) ? traceIdSeedStore.run(seed, fn) : fn();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** sha256(seed) → first 32 hex chars; matches `@langfuse/tracing` `createTraceId`. */
|
|
47
|
-
function traceIdFromSeed(seed: string): string {
|
|
48
|
-
return createHash('sha256').update(seed, 'utf8').digest('hex').slice(0, 32);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
40
|
class SeededTraceIdGenerator implements IdGenerator {
|
|
52
41
|
generateTraceId(): string {
|
|
53
|
-
const seed =
|
|
42
|
+
const seed = resolveTraceIdSeedForSpan(context.active());
|
|
54
43
|
return isPresent(seed)
|
|
55
44
|
? traceIdFromSeed(seed)
|
|
56
45
|
: randomBytes(16).toString('hex');
|
|
@@ -120,13 +109,19 @@ function getLangfuseSpanProcessorParams(
|
|
|
120
109
|
return undefined;
|
|
121
110
|
}
|
|
122
111
|
|
|
112
|
+
function hashCacheKeyValue(value: string | undefined): string | undefined {
|
|
113
|
+
return isPresent(value)
|
|
114
|
+
? createHash('sha256').update(value, 'utf8').digest('hex')
|
|
115
|
+
: undefined;
|
|
116
|
+
}
|
|
117
|
+
|
|
123
118
|
function getLangfuseTracerProviderKey(
|
|
124
119
|
params: LangfuseSpanProcessorParams,
|
|
125
120
|
langfuse?: t.LangfuseConfig
|
|
126
121
|
): string {
|
|
127
122
|
return JSON.stringify({
|
|
128
123
|
publicKey: params.publicKey,
|
|
129
|
-
|
|
124
|
+
secretKeyHash: hashCacheKeyValue(params.secretKey),
|
|
130
125
|
baseUrl: params.baseUrl,
|
|
131
126
|
environment: params.environment,
|
|
132
127
|
toolOutputTracing: langfuse?.toolOutputTracing,
|
|
@@ -134,6 +129,9 @@ function getLangfuseTracerProviderKey(
|
|
|
134
129
|
}
|
|
135
130
|
|
|
136
131
|
class RoutingLangfuseSpanProcessor implements SpanProcessor {
|
|
132
|
+
// Processors live for the process lifetime. LibreChat tenant Langfuse
|
|
133
|
+
// destinations are expected to be a bounded admin-managed set, and shutdown
|
|
134
|
+
// drains every cached processor when the provider is disposed.
|
|
137
135
|
private readonly processors = new Map<string, SpanProcessor>();
|
|
138
136
|
private readonly spanProcessors = new WeakMap<object, SpanProcessor>();
|
|
139
137
|
|
|
@@ -155,13 +153,19 @@ class RoutingLangfuseSpanProcessor implements SpanProcessor {
|
|
|
155
153
|
}
|
|
156
154
|
|
|
157
155
|
onStart(span: Span, parentContext: Context): void {
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
);
|
|
156
|
+
const langfuse = resolveLangfuseConfigForSpan(parentContext);
|
|
157
|
+
const processor = this.ensureProcessor(langfuse);
|
|
161
158
|
if (processor == null) {
|
|
162
159
|
return;
|
|
163
160
|
}
|
|
164
161
|
|
|
162
|
+
const librechatTraceAttributes = createLibreChatTraceAttributes(
|
|
163
|
+
langfuse?.librechatTraceAttributes ?? {}
|
|
164
|
+
);
|
|
165
|
+
if (Object.keys(librechatTraceAttributes).length > 0) {
|
|
166
|
+
span.setAttributes(librechatTraceAttributes);
|
|
167
|
+
}
|
|
168
|
+
|
|
165
169
|
this.spanProcessors.set(span, processor);
|
|
166
170
|
processor.onStart(span, parentContext);
|
|
167
171
|
}
|
package/src/langfuse.ts
CHANGED
|
@@ -1,23 +1,34 @@
|
|
|
1
1
|
import { CallbackHandler } from '@langfuse/langchain';
|
|
2
|
+
import { context as otelContext } from '@opentelemetry/api';
|
|
2
3
|
import {
|
|
3
4
|
getLangfuseTracerProvider,
|
|
4
5
|
propagateAttributes,
|
|
5
6
|
} from '@langfuse/tracing';
|
|
6
7
|
import type { PropagateAttributesParams } from '@langfuse/tracing';
|
|
7
8
|
import type * as t from '@/types';
|
|
8
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
resolveLangfuseConfigForSpan,
|
|
11
|
+
resolveTraceIdSeedForSpan,
|
|
12
|
+
withLangfuseRuntimeScope,
|
|
13
|
+
} from '@/langfuseRuntimeScope';
|
|
14
|
+
import { isPresent, parseBooleanEnv } from '@/utils/misc';
|
|
9
15
|
|
|
10
16
|
const TRACE_METADATA_MAX_LENGTH = 200;
|
|
11
17
|
const LANGFUSE_FORCE_FLUSH_ON_DISPOSE = 'LANGFUSE_FORCE_FLUSH_ON_DISPOSE';
|
|
12
18
|
|
|
13
19
|
export type LangfuseTraceMetadata = Record<string, string>;
|
|
20
|
+
export type LangfuseTraceAttributes = Record<string, string | number | boolean>;
|
|
14
21
|
type LangfuseMetadata = NonNullable<t.LangfuseConfig['metadata']>;
|
|
22
|
+
type LangfuseConfigTraceAttributes = NonNullable<
|
|
23
|
+
t.LangfuseConfig['librechatTraceAttributes']
|
|
24
|
+
>;
|
|
15
25
|
|
|
16
26
|
type LangfuseHandlerParams = {
|
|
17
27
|
userId?: string;
|
|
18
28
|
sessionId?: string;
|
|
19
29
|
traceMetadata?: LangfuseTraceMetadata;
|
|
20
30
|
tags?: string[];
|
|
31
|
+
traceIdSeed?: string;
|
|
21
32
|
};
|
|
22
33
|
|
|
23
34
|
type AgentLangfuseHandlerParams = LangfuseHandlerParams & {
|
|
@@ -32,11 +43,81 @@ type FlushableTracerProvider = {
|
|
|
32
43
|
forceFlush?: () => Promise<void> | void;
|
|
33
44
|
};
|
|
34
45
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
46
|
+
class ScopedLangfuseCallbackHandler extends CallbackHandler {
|
|
47
|
+
private readonly langfuse?: t.LangfuseConfig;
|
|
48
|
+
private readonly traceIdSeed?: string;
|
|
49
|
+
|
|
50
|
+
constructor(params?: AgentLangfuseHandlerParams) {
|
|
51
|
+
const { langfuse, traceIdSeed, ...handlerParams } = params ?? {};
|
|
52
|
+
super(handlerParams);
|
|
53
|
+
this.langfuse = langfuse;
|
|
54
|
+
this.traceIdSeed = traceIdSeed;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private getDeterministicTraceSeed(): string | undefined {
|
|
58
|
+
return this.langfuse?.deterministicTraceId === true
|
|
59
|
+
? this.traceIdSeed
|
|
60
|
+
: undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private withRuntimeContext<T>(action: () => T): T {
|
|
64
|
+
const activeContext = otelContext.active();
|
|
65
|
+
const langfuse =
|
|
66
|
+
resolveLangfuseConfigForSpan(activeContext) ?? this.langfuse;
|
|
67
|
+
const seed = this.getDeterministicTraceSeed();
|
|
68
|
+
return withLangfuseRuntimeScope(
|
|
69
|
+
{
|
|
70
|
+
langfuse,
|
|
71
|
+
traceIdSeed: resolveTraceIdSeedForSpan(activeContext) ?? seed,
|
|
72
|
+
},
|
|
73
|
+
action
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// LangChain may invoke callback handlers outside the caller's OTEL context.
|
|
78
|
+
// Re-enter tenant scope only for callbacks that start Langfuse observations;
|
|
79
|
+
// end/error/token callbacks use spans already bound to a processor at start.
|
|
80
|
+
override handleChainStart(
|
|
81
|
+
...args: Parameters<CallbackHandler['handleChainStart']>
|
|
82
|
+
): ReturnType<CallbackHandler['handleChainStart']> {
|
|
83
|
+
return this.withRuntimeContext(() => super.handleChainStart(...args));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
override handleAgentAction(
|
|
87
|
+
...args: Parameters<CallbackHandler['handleAgentAction']>
|
|
88
|
+
): ReturnType<CallbackHandler['handleAgentAction']> {
|
|
89
|
+
return this.withRuntimeContext(() => super.handleAgentAction(...args));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
override handleGenerationStart(
|
|
93
|
+
...args: Parameters<CallbackHandler['handleGenerationStart']>
|
|
94
|
+
): ReturnType<CallbackHandler['handleGenerationStart']> {
|
|
95
|
+
return this.withRuntimeContext(() => super.handleGenerationStart(...args));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
override handleChatModelStart(
|
|
99
|
+
...args: Parameters<CallbackHandler['handleChatModelStart']>
|
|
100
|
+
): ReturnType<CallbackHandler['handleChatModelStart']> {
|
|
101
|
+
return this.withRuntimeContext(() => super.handleChatModelStart(...args));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
override handleLLMStart(
|
|
105
|
+
...args: Parameters<CallbackHandler['handleLLMStart']>
|
|
106
|
+
): ReturnType<CallbackHandler['handleLLMStart']> {
|
|
107
|
+
return this.withRuntimeContext(() => super.handleLLMStart(...args));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
override handleToolStart(
|
|
111
|
+
...args: Parameters<CallbackHandler['handleToolStart']>
|
|
112
|
+
): ReturnType<CallbackHandler['handleToolStart']> {
|
|
113
|
+
return this.withRuntimeContext(() => super.handleToolStart(...args));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
override handleRetrieverStart(
|
|
117
|
+
...args: Parameters<CallbackHandler['handleRetrieverStart']>
|
|
118
|
+
): ReturnType<CallbackHandler['handleRetrieverStart']> {
|
|
119
|
+
return this.withRuntimeContext(() => super.handleRetrieverStart(...args));
|
|
38
120
|
}
|
|
39
|
-
return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());
|
|
40
121
|
}
|
|
41
122
|
|
|
42
123
|
function hasLangfuseTracingConfig(langfuse?: t.LangfuseConfig): boolean {
|
|
@@ -48,6 +129,9 @@ function hasLangfuseTracingConfig(langfuse?: t.LangfuseConfig): boolean {
|
|
|
48
129
|
function hasLangfuseTraceAttributes(langfuse?: t.LangfuseConfig): boolean {
|
|
49
130
|
return (
|
|
50
131
|
Object.keys(createTraceMetadata(langfuse?.metadata ?? {})).length > 0 ||
|
|
132
|
+
Object.keys(
|
|
133
|
+
createLibreChatTraceAttributes(langfuse?.librechatTraceAttributes ?? {})
|
|
134
|
+
).length > 0 ||
|
|
51
135
|
(mergeLangfuseTags(undefined, langfuse?.tags)?.length ?? 0) > 0
|
|
52
136
|
);
|
|
53
137
|
}
|
|
@@ -100,6 +184,26 @@ function createTraceMetadata(
|
|
|
100
184
|
return traceMetadata;
|
|
101
185
|
}
|
|
102
186
|
|
|
187
|
+
export function createLibreChatTraceAttributes(
|
|
188
|
+
attributes: LangfuseConfigTraceAttributes
|
|
189
|
+
): LangfuseTraceAttributes {
|
|
190
|
+
const librechatTraceAttributes: LangfuseTraceAttributes = {};
|
|
191
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
192
|
+
if (value == null || key.trim() === '') {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (typeof value === 'string') {
|
|
196
|
+
if (value.trim() === '' || value.length > TRACE_METADATA_MAX_LENGTH) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
librechatTraceAttributes[key] = value;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
librechatTraceAttributes[key] = value;
|
|
203
|
+
}
|
|
204
|
+
return librechatTraceAttributes;
|
|
205
|
+
}
|
|
206
|
+
|
|
103
207
|
export function createLangfuseTraceMetadata({
|
|
104
208
|
messageId,
|
|
105
209
|
parentMessageId,
|
|
@@ -175,7 +279,7 @@ export function shouldCreateLangfuseHandler(
|
|
|
175
279
|
export function createLegacyLangfuseHandler(
|
|
176
280
|
params: LangfuseHandlerParams
|
|
177
281
|
): CallbackHandler {
|
|
178
|
-
return new
|
|
282
|
+
return new ScopedLangfuseCallbackHandler(params);
|
|
179
283
|
}
|
|
180
284
|
|
|
181
285
|
export function createLangfuseHandler({
|
|
@@ -184,11 +288,12 @@ export function createLangfuseHandler({
|
|
|
184
288
|
sessionId,
|
|
185
289
|
traceMetadata,
|
|
186
290
|
tags,
|
|
291
|
+
traceIdSeed,
|
|
187
292
|
}: AgentLangfuseHandlerParams): CallbackHandler | undefined {
|
|
188
293
|
if (!shouldCreateLangfuseHandler(langfuse)) {
|
|
189
294
|
return undefined;
|
|
190
295
|
}
|
|
191
|
-
return new
|
|
296
|
+
return new ScopedLangfuseCallbackHandler({
|
|
192
297
|
userId,
|
|
193
298
|
sessionId,
|
|
194
299
|
traceMetadata: mergeLangfuseTraceMetadata(
|
|
@@ -196,6 +301,8 @@ export function createLangfuseHandler({
|
|
|
196
301
|
langfuse?.metadata
|
|
197
302
|
),
|
|
198
303
|
tags: mergeLangfuseTags(tags, langfuse?.tags),
|
|
304
|
+
langfuse,
|
|
305
|
+
traceIdSeed,
|
|
199
306
|
});
|
|
200
307
|
}
|
|
201
308
|
|