@librechat/agents 3.2.43 → 3.2.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/cjs/graphs/Graph.cjs +17 -8
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/instrumentation.cjs +20 -21
  4. package/dist/cjs/instrumentation.cjs.map +1 -1
  5. package/dist/cjs/langfuse.cjs +65 -13
  6. package/dist/cjs/langfuse.cjs.map +1 -1
  7. package/dist/cjs/langfuseConfig.cjs +106 -0
  8. package/dist/cjs/langfuseConfig.cjs.map +1 -0
  9. package/dist/cjs/langfuseRuntimeContext.cjs +48 -0
  10. package/dist/cjs/langfuseRuntimeContext.cjs.map +1 -0
  11. package/dist/cjs/langfuseRuntimeScope.cjs +57 -0
  12. package/dist/cjs/langfuseRuntimeScope.cjs.map +1 -0
  13. package/dist/cjs/langfuseToolOutputTracing.cjs +14 -119
  14. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  15. package/dist/cjs/main.cjs +1 -0
  16. package/dist/cjs/messages/reducer.cjs +15 -2
  17. package/dist/cjs/messages/reducer.cjs.map +1 -1
  18. package/dist/cjs/run.cjs +25 -12
  19. package/dist/cjs/run.cjs.map +1 -1
  20. package/dist/cjs/tools/ToolNode.cjs +5 -2
  21. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  22. package/dist/cjs/utils/misc.cjs +17 -0
  23. package/dist/cjs/utils/misc.cjs.map +1 -1
  24. package/dist/esm/graphs/Graph.mjs +16 -7
  25. package/dist/esm/graphs/Graph.mjs.map +1 -1
  26. package/dist/esm/instrumentation.mjs +22 -22
  27. package/dist/esm/instrumentation.mjs.map +1 -1
  28. package/dist/esm/langfuse.mjs +65 -14
  29. package/dist/esm/langfuse.mjs.map +1 -1
  30. package/dist/esm/langfuseConfig.mjs +102 -0
  31. package/dist/esm/langfuseConfig.mjs.map +1 -0
  32. package/dist/esm/langfuseRuntimeContext.mjs +44 -0
  33. package/dist/esm/langfuseRuntimeContext.mjs.map +1 -0
  34. package/dist/esm/langfuseRuntimeScope.mjs +53 -0
  35. package/dist/esm/langfuseRuntimeScope.mjs.map +1 -0
  36. package/dist/esm/langfuseToolOutputTracing.mjs +13 -115
  37. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  38. package/dist/esm/main.mjs +2 -2
  39. package/dist/esm/messages/reducer.mjs +15 -2
  40. package/dist/esm/messages/reducer.mjs.map +1 -1
  41. package/dist/esm/run.mjs +21 -8
  42. package/dist/esm/run.mjs.map +1 -1
  43. package/dist/esm/tools/ToolNode.mjs +5 -2
  44. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  45. package/dist/esm/utils/misc.mjs +17 -1
  46. package/dist/esm/utils/misc.mjs.map +1 -1
  47. package/dist/types/instrumentation.d.ts +0 -1
  48. package/dist/types/langfuse.d.ts +5 -1
  49. package/dist/types/langfuseConfig.d.ts +7 -0
  50. package/dist/types/langfuseRuntimeContext.d.ts +26 -0
  51. package/dist/types/langfuseRuntimeScope.d.ts +17 -0
  52. package/dist/types/langfuseToolOutputTracing.d.ts +4 -11
  53. package/dist/types/types/graph.d.ts +6 -0
  54. package/dist/types/utils/misc.d.ts +1 -0
  55. package/package.json +1 -1
  56. package/src/graphs/Graph.ts +20 -13
  57. package/src/instrumentation.ts +33 -29
  58. package/src/langfuse.ts +114 -7
  59. package/src/langfuseConfig.ts +214 -0
  60. package/src/langfuseRuntimeContext.ts +93 -0
  61. package/src/langfuseRuntimeScope.ts +135 -0
  62. package/src/langfuseToolOutputTracing.ts +25 -263
  63. package/src/messages/reducer.spec.ts +32 -0
  64. package/src/messages/reducer.ts +23 -7
  65. package/src/run.ts +44 -34
  66. package/src/specs/deterministic-trace-id.test.ts +4 -11
  67. package/src/specs/langfuse-callbacks.test.ts +278 -22
  68. package/src/specs/langfuse-config.test.ts +10 -3
  69. package/src/specs/langfuse-instrumentation.test.ts +32 -12
  70. package/src/specs/langfuse-routing.integration.test.ts +543 -0
  71. package/src/specs/langfuse-runtime-context.test.ts +92 -0
  72. package/src/specs/langfuse-tool-output-tracing.test.ts +353 -5
  73. package/src/tools/ToolNode.ts +10 -5
  74. package/src/tools/__tests__/ToolNode.langfuse.test.ts +21 -11
  75. package/src/types/graph.ts +9 -0
  76. package/src/utils/misc.ts +18 -0
@@ -1,9 +1,10 @@
1
+ const require_langfuseRuntimeContext = require("./langfuseRuntimeContext.cjs");
1
2
  const require_misc = require("./utils/misc.cjs");
3
+ const require_langfuseRuntimeScope = require("./langfuseRuntimeScope.cjs");
2
4
  const require_langfuse = require("./langfuse.cjs");
3
5
  const require_langfuseToolOutputTracing = require("./langfuseToolOutputTracing.cjs");
4
- let _langfuse_tracing = require("@langfuse/tracing");
5
- let node_async_hooks = require("node:async_hooks");
6
6
  let _opentelemetry_api = require("@opentelemetry/api");
7
+ let _langfuse_tracing = require("@langfuse/tracing");
7
8
  let node_crypto = require("node:crypto");
8
9
  let _opentelemetry_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
9
10
  let _opentelemetry_context_async_hooks = require("@opentelemetry/context-async-hooks");
@@ -11,25 +12,18 @@ let _opentelemetry_context_async_hooks = require("@opentelemetry/context-async-h
11
12
  /**
12
13
  * Per-run seed for deterministic Langfuse trace ids. When a run opts in
13
14
  * (`LangfuseConfig.deterministicTraceId`), it executes its stream inside
14
- * `runWithTraceIdSeed(runId, )` and the IdGenerator below derives the root
15
- * trace id from that seed instead of a random one. This lets external systems
16
- * (e.g. a host app recording user feedback after the fact) attach scores or
17
- * observations to the trace by regenerating the same id from the run/message
18
- * id no trace lookup required. With no active seed it falls back to random
19
- * ids, so default behavior is unchanged.
15
+ * `runWithTraceIdSeed(runId, ...)` from `./langfuseRuntimeContext`, and the
16
+ * IdGenerator below derives the root trace id from that seed instead of a
17
+ * random one. This lets external systems (e.g. a host app recording user
18
+ * feedback after the fact) attach scores or observations to the trace by
19
+ * regenerating the same id from the run/message id; no trace lookup required.
20
+ * With no active seed it falls back to random ids, so default behavior is
21
+ * unchanged.
20
22
  */
21
- const traceIdSeedStore = new node_async_hooks.AsyncLocalStorage();
22
- function runWithTraceIdSeed(seed, fn) {
23
- return require_misc.isPresent(seed) ? traceIdSeedStore.run(seed, fn) : fn();
24
- }
25
- /** sha256(seed) → first 32 hex chars; matches `@langfuse/tracing` `createTraceId`. */
26
- function traceIdFromSeed(seed) {
27
- return (0, node_crypto.createHash)("sha256").update(seed, "utf8").digest("hex").slice(0, 32);
28
- }
29
23
  var SeededTraceIdGenerator = class {
30
24
  generateTraceId() {
31
- const seed = traceIdSeedStore.getStore();
32
- return require_misc.isPresent(seed) ? traceIdFromSeed(seed) : (0, node_crypto.randomBytes)(16).toString("hex");
25
+ const seed = require_langfuseRuntimeScope.resolveTraceIdSeedForSpan(_opentelemetry_api.context.active());
26
+ return require_misc.isPresent(seed) ? require_langfuseRuntimeContext.traceIdFromSeed(seed) : (0, node_crypto.randomBytes)(16).toString("hex");
33
27
  }
34
28
  generateSpanId() {
35
29
  return (0, node_crypto.randomBytes)(8).toString("hex");
@@ -68,10 +62,13 @@ function getLangfuseSpanProcessorParams(langfuse) {
68
62
  baseUrl: langfuse.baseUrl
69
63
  };
70
64
  }
65
+ function hashCacheKeyValue(value) {
66
+ return require_misc.isPresent(value) ? (0, node_crypto.createHash)("sha256").update(value, "utf8").digest("hex") : void 0;
67
+ }
71
68
  function getLangfuseTracerProviderKey(params, langfuse) {
72
69
  return JSON.stringify({
73
70
  publicKey: params.publicKey,
74
- secretKey: params.secretKey,
71
+ secretKeyHash: hashCacheKeyValue(params.secretKey),
75
72
  baseUrl: params.baseUrl,
76
73
  environment: params.environment,
77
74
  toolOutputTracing: langfuse?.toolOutputTracing
@@ -91,8 +88,11 @@ var RoutingLangfuseSpanProcessor = class {
91
88
  return processor;
92
89
  }
93
90
  onStart(span, parentContext) {
94
- const processor = this.ensureProcessor(require_langfuseToolOutputTracing.getContextLangfuseConfig(parentContext));
91
+ const langfuse = require_langfuseRuntimeScope.resolveLangfuseConfigForSpan(parentContext);
92
+ const processor = this.ensureProcessor(langfuse);
95
93
  if (processor == null) return;
94
+ const librechatTraceAttributes = require_langfuse.createLibreChatTraceAttributes(langfuse?.librechatTraceAttributes ?? {});
95
+ if (Object.keys(librechatTraceAttributes).length > 0) span.setAttributes(librechatTraceAttributes);
96
96
  this.spanProcessors.set(span, processor);
97
97
  processor.onStart(span, parentContext);
98
98
  }
@@ -128,6 +128,5 @@ function initializeLangfuseTracingFromEnv() {
128
128
  initializeLangfuseTracingFromEnv();
129
129
  //#endregion
130
130
  exports.initializeLangfuseTracing = initializeLangfuseTracing;
131
- exports.runWithTraceIdSeed = runWithTraceIdSeed;
132
131
 
133
132
  //# sourceMappingURL=instrumentation.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.cjs","names":["AsyncLocalStorage","isPresent","context","ROOT_CONTEXT","AsyncLocalStorageContextManager","hasLangfuseConfigCredentials","hasLangfuseEnvConfig","hasLangfuseEnvCredentials","createLangfuseSpanProcessor","getContextLangfuseConfig","BasicTracerProvider"],"sources":["../../src/instrumentation.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport { createHash, randomBytes } from 'node:crypto';\nimport { setLangfuseTracerProvider } from '@langfuse/tracing';\nimport { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';\nimport { context, ROOT_CONTEXT, createContextKey } from '@opentelemetry/api';\nimport { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';\nimport type {\n IdGenerator,\n ReadableSpan,\n Span,\n SpanProcessor,\n} from '@opentelemetry/sdk-trace-base';\nimport type { LangfuseSpanProcessorParams } from '@langfuse/otel';\nimport type { Context } from '@opentelemetry/api';\nimport type * as t from '@/types';\nimport {\n hasLangfuseConfigCredentials,\n hasLangfuseEnvCredentials,\n hasLangfuseEnvConfig,\n} from '@/langfuse';\nimport {\n createLangfuseSpanProcessor,\n getContextLangfuseConfig,\n} from '@/langfuseToolOutputTracing';\nimport { isPresent } from '@/utils/misc';\n\n/**\n * Per-run seed for deterministic Langfuse trace ids. When a run opts in\n * (`LangfuseConfig.deterministicTraceId`), it executes its stream inside\n * `runWithTraceIdSeed(runId, …)` and the IdGenerator below derives the root\n * trace id from that seed instead of a random one. This lets external systems\n * (e.g. a host app recording user feedback after the fact) attach scores or\n * observations to the trace by regenerating the same id from the run/message\n * id — no trace lookup required. With no active seed it falls back to random\n * ids, so default behavior is unchanged.\n */\nconst traceIdSeedStore = new AsyncLocalStorage<string>();\n\nexport function runWithTraceIdSeed<T>(\n seed: string | undefined,\n fn: () => T\n): T {\n return isPresent(seed) ? traceIdSeedStore.run(seed, fn) : fn();\n}\n\n/** sha256(seed) → first 32 hex chars; matches `@langfuse/tracing` `createTraceId`. */\nfunction traceIdFromSeed(seed: string): string {\n return createHash('sha256').update(seed, 'utf8').digest('hex').slice(0, 32);\n}\n\nclass SeededTraceIdGenerator implements IdGenerator {\n generateTraceId(): string {\n const seed = traceIdSeedStore.getStore();\n return isPresent(seed)\n ? traceIdFromSeed(seed)\n : randomBytes(16).toString('hex');\n }\n\n generateSpanId(): string {\n return randomBytes(8).toString('hex');\n }\n}\n\nlet langfuseTracerProvider: BasicTracerProvider | undefined;\nlet langfuseRoutingSpanProcessor: RoutingLangfuseSpanProcessor | undefined;\nconst contextManagerProbeKey = createContextKey(\n 'langfuse-context-manager-probe'\n);\n\nfunction hasActiveContextManager(): boolean {\n return context.with(\n ROOT_CONTEXT.setValue(contextManagerProbeKey, true),\n () => context.active().getValue(contextManagerProbeKey) === true\n );\n}\n\nexport function ensureOpenTelemetryContextManager(): void {\n if (hasActiveContextManager()) {\n return;\n }\n\n const contextManager = new AsyncLocalStorageContextManager();\n contextManager.enable();\n if (!context.setGlobalContextManager(contextManager)) {\n contextManager.disable();\n }\n}\n\nfunction getLangfuseSpanProcessorParams(\n langfuse?: t.LangfuseConfig\n): LangfuseSpanProcessorParams | undefined {\n if (langfuse?.enabled === false) {\n return undefined;\n }\n if (hasLangfuseConfigCredentials(langfuse)) {\n return {\n publicKey: langfuse.publicKey,\n secretKey: langfuse.secretKey,\n ...(isPresent(langfuse.baseUrl) ? { baseUrl: langfuse.baseUrl } : {}),\n };\n }\n if (hasLangfuseEnvConfig()) {\n const baseUrl =\n langfuse?.baseUrl ??\n process.env.LANGFUSE_BASE_URL ??\n process.env.LANGFUSE_BASEURL;\n return {\n publicKey: process.env.LANGFUSE_PUBLIC_KEY as string,\n secretKey: process.env.LANGFUSE_SECRET_KEY as string,\n ...(isPresent(baseUrl) ? { baseUrl } : {}),\n };\n }\n if (isPresent(langfuse?.baseUrl) && hasLangfuseEnvCredentials()) {\n return {\n publicKey: process.env.LANGFUSE_PUBLIC_KEY as string,\n secretKey: process.env.LANGFUSE_SECRET_KEY as string,\n baseUrl: langfuse.baseUrl,\n };\n }\n return undefined;\n}\n\nfunction getLangfuseTracerProviderKey(\n params: LangfuseSpanProcessorParams,\n langfuse?: t.LangfuseConfig\n): string {\n return JSON.stringify({\n publicKey: params.publicKey,\n secretKey: params.secretKey,\n baseUrl: params.baseUrl,\n environment: params.environment,\n toolOutputTracing: langfuse?.toolOutputTracing,\n });\n}\n\nclass RoutingLangfuseSpanProcessor implements SpanProcessor {\n private readonly processors = new Map<string, SpanProcessor>();\n private readonly spanProcessors = new WeakMap<object, SpanProcessor>();\n\n ensureProcessor(langfuse?: t.LangfuseConfig): SpanProcessor | undefined {\n const params = getLangfuseSpanProcessorParams(langfuse);\n if (params == null) {\n return undefined;\n }\n\n const processorKey = getLangfuseTracerProviderKey(params, langfuse);\n const existing = this.processors.get(processorKey);\n if (existing != null) {\n return existing;\n }\n\n const processor = createLangfuseSpanProcessor(params, langfuse);\n this.processors.set(processorKey, processor);\n return processor;\n }\n\n onStart(span: Span, parentContext: Context): void {\n const processor = this.ensureProcessor(\n getContextLangfuseConfig(parentContext)\n );\n if (processor == null) {\n return;\n }\n\n this.spanProcessors.set(span, processor);\n processor.onStart(span, parentContext);\n }\n\n onEnd(span: ReadableSpan): void {\n this.spanProcessors.get(span)?.onEnd(span);\n }\n\n async forceFlush(): Promise<void> {\n await Promise.all(\n Array.from(this.processors.values(), (processor) =>\n processor.forceFlush()\n )\n );\n }\n\n async shutdown(): Promise<void> {\n await Promise.all(\n Array.from(this.processors.values(), (processor) => processor.shutdown())\n );\n }\n}\n\nexport function initializeLangfuseTracing(\n langfuse?: t.LangfuseConfig\n): BasicTracerProvider | undefined {\n const params = getLangfuseSpanProcessorParams(langfuse);\n if (params == null) {\n return undefined;\n }\n\n if (langfuseTracerProvider != null) {\n langfuseRoutingSpanProcessor?.ensureProcessor(langfuse);\n return langfuseTracerProvider;\n }\n\n ensureOpenTelemetryContextManager();\n langfuseRoutingSpanProcessor = new RoutingLangfuseSpanProcessor();\n langfuseRoutingSpanProcessor.ensureProcessor(langfuse);\n langfuseTracerProvider = new BasicTracerProvider({\n spanProcessors: [langfuseRoutingSpanProcessor],\n idGenerator: new SeededTraceIdGenerator(),\n });\n\n setLangfuseTracerProvider(langfuseTracerProvider);\n return langfuseTracerProvider;\n}\n\nexport function initializeLangfuseTracingFromEnv():\n | BasicTracerProvider\n | undefined {\n return initializeLangfuseTracing();\n}\n\ninitializeLangfuseTracingFromEnv();\n"],"mappings":"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"}
1
+ {"version":3,"file":"instrumentation.cjs","names":["resolveTraceIdSeedForSpan","context","isPresent","traceIdFromSeed","ROOT_CONTEXT","AsyncLocalStorageContextManager","hasLangfuseConfigCredentials","hasLangfuseEnvConfig","hasLangfuseEnvCredentials","createLangfuseSpanProcessor","resolveLangfuseConfigForSpan","createLibreChatTraceAttributes","BasicTracerProvider"],"sources":["../../src/instrumentation.ts"],"sourcesContent":["import { createHash, randomBytes } from 'node:crypto';\nimport { setLangfuseTracerProvider } from '@langfuse/tracing';\nimport { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';\nimport { context, ROOT_CONTEXT, createContextKey } from '@opentelemetry/api';\nimport { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';\nimport type {\n IdGenerator,\n ReadableSpan,\n Span,\n SpanProcessor,\n} from '@opentelemetry/sdk-trace-base';\nimport type { LangfuseSpanProcessorParams } from '@langfuse/otel';\nimport type { Context } from '@opentelemetry/api';\nimport type * as t from '@/types';\nimport {\n createLibreChatTraceAttributes,\n hasLangfuseConfigCredentials,\n hasLangfuseEnvCredentials,\n hasLangfuseEnvConfig,\n} from '@/langfuse';\nimport {\n resolveLangfuseConfigForSpan,\n resolveTraceIdSeedForSpan,\n} from '@/langfuseRuntimeScope';\nimport { createLangfuseSpanProcessor } from '@/langfuseToolOutputTracing';\nimport { traceIdFromSeed } from '@/langfuseRuntimeContext';\nimport { isPresent } from '@/utils/misc';\n\n/**\n * Per-run seed for deterministic Langfuse trace ids. When a run opts in\n * (`LangfuseConfig.deterministicTraceId`), it executes its stream inside\n * `runWithTraceIdSeed(runId, ...)` from `./langfuseRuntimeContext`, and the\n * IdGenerator below derives the root trace id from that seed instead of a\n * random one. This lets external systems (e.g. a host app recording user\n * feedback after the fact) attach scores or observations to the trace by\n * regenerating the same id from the run/message id; no trace lookup required.\n * With no active seed it falls back to random ids, so default behavior is\n * unchanged.\n */\nclass SeededTraceIdGenerator implements IdGenerator {\n generateTraceId(): string {\n const seed = resolveTraceIdSeedForSpan(context.active());\n return isPresent(seed)\n ? traceIdFromSeed(seed)\n : randomBytes(16).toString('hex');\n }\n\n generateSpanId(): string {\n return randomBytes(8).toString('hex');\n }\n}\n\nlet langfuseTracerProvider: BasicTracerProvider | undefined;\nlet langfuseRoutingSpanProcessor: RoutingLangfuseSpanProcessor | undefined;\nconst contextManagerProbeKey = createContextKey(\n 'langfuse-context-manager-probe'\n);\n\nfunction hasActiveContextManager(): boolean {\n return context.with(\n ROOT_CONTEXT.setValue(contextManagerProbeKey, true),\n () => context.active().getValue(contextManagerProbeKey) === true\n );\n}\n\nexport function ensureOpenTelemetryContextManager(): void {\n if (hasActiveContextManager()) {\n return;\n }\n\n const contextManager = new AsyncLocalStorageContextManager();\n contextManager.enable();\n if (!context.setGlobalContextManager(contextManager)) {\n contextManager.disable();\n }\n}\n\nfunction getLangfuseSpanProcessorParams(\n langfuse?: t.LangfuseConfig\n): LangfuseSpanProcessorParams | undefined {\n if (langfuse?.enabled === false) {\n return undefined;\n }\n if (hasLangfuseConfigCredentials(langfuse)) {\n return {\n publicKey: langfuse.publicKey,\n secretKey: langfuse.secretKey,\n ...(isPresent(langfuse.baseUrl) ? { baseUrl: langfuse.baseUrl } : {}),\n };\n }\n if (hasLangfuseEnvConfig()) {\n const baseUrl =\n langfuse?.baseUrl ??\n process.env.LANGFUSE_BASE_URL ??\n process.env.LANGFUSE_BASEURL;\n return {\n publicKey: process.env.LANGFUSE_PUBLIC_KEY as string,\n secretKey: process.env.LANGFUSE_SECRET_KEY as string,\n ...(isPresent(baseUrl) ? { baseUrl } : {}),\n };\n }\n if (isPresent(langfuse?.baseUrl) && hasLangfuseEnvCredentials()) {\n return {\n publicKey: process.env.LANGFUSE_PUBLIC_KEY as string,\n secretKey: process.env.LANGFUSE_SECRET_KEY as string,\n baseUrl: langfuse.baseUrl,\n };\n }\n return undefined;\n}\n\nfunction hashCacheKeyValue(value: string | undefined): string | undefined {\n return isPresent(value)\n ? createHash('sha256').update(value, 'utf8').digest('hex')\n : undefined;\n}\n\nfunction getLangfuseTracerProviderKey(\n params: LangfuseSpanProcessorParams,\n langfuse?: t.LangfuseConfig\n): string {\n return JSON.stringify({\n publicKey: params.publicKey,\n secretKeyHash: hashCacheKeyValue(params.secretKey),\n baseUrl: params.baseUrl,\n environment: params.environment,\n toolOutputTracing: langfuse?.toolOutputTracing,\n });\n}\n\nclass RoutingLangfuseSpanProcessor implements SpanProcessor {\n // Processors live for the process lifetime. LibreChat tenant Langfuse\n // destinations are expected to be a bounded admin-managed set, and shutdown\n // drains every cached processor when the provider is disposed.\n private readonly processors = new Map<string, SpanProcessor>();\n private readonly spanProcessors = new WeakMap<object, SpanProcessor>();\n\n ensureProcessor(langfuse?: t.LangfuseConfig): SpanProcessor | undefined {\n const params = getLangfuseSpanProcessorParams(langfuse);\n if (params == null) {\n return undefined;\n }\n\n const processorKey = getLangfuseTracerProviderKey(params, langfuse);\n const existing = this.processors.get(processorKey);\n if (existing != null) {\n return existing;\n }\n\n const processor = createLangfuseSpanProcessor(params, langfuse);\n this.processors.set(processorKey, processor);\n return processor;\n }\n\n onStart(span: Span, parentContext: Context): void {\n const langfuse = resolveLangfuseConfigForSpan(parentContext);\n const processor = this.ensureProcessor(langfuse);\n if (processor == null) {\n return;\n }\n\n const librechatTraceAttributes = createLibreChatTraceAttributes(\n langfuse?.librechatTraceAttributes ?? {}\n );\n if (Object.keys(librechatTraceAttributes).length > 0) {\n span.setAttributes(librechatTraceAttributes);\n }\n\n this.spanProcessors.set(span, processor);\n processor.onStart(span, parentContext);\n }\n\n onEnd(span: ReadableSpan): void {\n this.spanProcessors.get(span)?.onEnd(span);\n }\n\n async forceFlush(): Promise<void> {\n await Promise.all(\n Array.from(this.processors.values(), (processor) =>\n processor.forceFlush()\n )\n );\n }\n\n async shutdown(): Promise<void> {\n await Promise.all(\n Array.from(this.processors.values(), (processor) => processor.shutdown())\n );\n }\n}\n\nexport function initializeLangfuseTracing(\n langfuse?: t.LangfuseConfig\n): BasicTracerProvider | undefined {\n const params = getLangfuseSpanProcessorParams(langfuse);\n if (params == null) {\n return undefined;\n }\n\n if (langfuseTracerProvider != null) {\n langfuseRoutingSpanProcessor?.ensureProcessor(langfuse);\n return langfuseTracerProvider;\n }\n\n ensureOpenTelemetryContextManager();\n langfuseRoutingSpanProcessor = new RoutingLangfuseSpanProcessor();\n langfuseRoutingSpanProcessor.ensureProcessor(langfuse);\n langfuseTracerProvider = new BasicTracerProvider({\n spanProcessors: [langfuseRoutingSpanProcessor],\n idGenerator: new SeededTraceIdGenerator(),\n });\n\n setLangfuseTracerProvider(langfuseTracerProvider);\n return langfuseTracerProvider;\n}\n\nexport function initializeLangfuseTracingFromEnv():\n | BasicTracerProvider\n | undefined {\n return initializeLangfuseTracing();\n}\n\ninitializeLangfuseTracingFromEnv();\n"],"mappings":"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"}
@@ -1,18 +1,54 @@
1
1
  const require_misc = require("./utils/misc.cjs");
2
+ const require_langfuseRuntimeScope = require("./langfuseRuntimeScope.cjs");
2
3
  let _langfuse_langchain = require("@langfuse/langchain");
4
+ let _opentelemetry_api = require("@opentelemetry/api");
3
5
  let _langfuse_tracing = require("@langfuse/tracing");
4
6
  //#region src/langfuse.ts
5
7
  const TRACE_METADATA_MAX_LENGTH = 200;
6
8
  const LANGFUSE_FORCE_FLUSH_ON_DISPOSE = "LANGFUSE_FORCE_FLUSH_ON_DISPOSE";
7
- function parseBooleanEnv(value) {
8
- if (value == null) return false;
9
- return [
10
- "1",
11
- "true",
12
- "yes",
13
- "on"
14
- ].includes(value.trim().toLowerCase());
15
- }
9
+ var ScopedLangfuseCallbackHandler = class extends _langfuse_langchain.CallbackHandler {
10
+ langfuse;
11
+ traceIdSeed;
12
+ constructor(params) {
13
+ const { langfuse, traceIdSeed, ...handlerParams } = params ?? {};
14
+ super(handlerParams);
15
+ this.langfuse = langfuse;
16
+ this.traceIdSeed = traceIdSeed;
17
+ }
18
+ getDeterministicTraceSeed() {
19
+ return this.langfuse?.deterministicTraceId === true ? this.traceIdSeed : void 0;
20
+ }
21
+ withRuntimeContext(action) {
22
+ const activeContext = _opentelemetry_api.context.active();
23
+ const langfuse = require_langfuseRuntimeScope.resolveLangfuseConfigForSpan(activeContext) ?? this.langfuse;
24
+ const seed = this.getDeterministicTraceSeed();
25
+ return require_langfuseRuntimeScope.withLangfuseRuntimeScope({
26
+ langfuse,
27
+ traceIdSeed: require_langfuseRuntimeScope.resolveTraceIdSeedForSpan(activeContext) ?? seed
28
+ }, action);
29
+ }
30
+ handleChainStart(...args) {
31
+ return this.withRuntimeContext(() => super.handleChainStart(...args));
32
+ }
33
+ handleAgentAction(...args) {
34
+ return this.withRuntimeContext(() => super.handleAgentAction(...args));
35
+ }
36
+ handleGenerationStart(...args) {
37
+ return this.withRuntimeContext(() => super.handleGenerationStart(...args));
38
+ }
39
+ handleChatModelStart(...args) {
40
+ return this.withRuntimeContext(() => super.handleChatModelStart(...args));
41
+ }
42
+ handleLLMStart(...args) {
43
+ return this.withRuntimeContext(() => super.handleLLMStart(...args));
44
+ }
45
+ handleToolStart(...args) {
46
+ return this.withRuntimeContext(() => super.handleToolStart(...args));
47
+ }
48
+ handleRetrieverStart(...args) {
49
+ return this.withRuntimeContext(() => super.handleRetrieverStart(...args));
50
+ }
51
+ };
16
52
  function hasLangfuseConfigCredentials(langfuse) {
17
53
  return langfuse != null && require_misc.isPresent(langfuse.publicKey) && require_misc.isPresent(langfuse.secretKey);
18
54
  }
@@ -29,6 +65,19 @@ function createTraceMetadata(metadata) {
29
65
  }
30
66
  return traceMetadata;
31
67
  }
68
+ function createLibreChatTraceAttributes(attributes) {
69
+ const librechatTraceAttributes = {};
70
+ for (const [key, value] of Object.entries(attributes)) {
71
+ if (value == null || key.trim() === "") continue;
72
+ if (typeof value === "string") {
73
+ if (value.trim() === "" || value.length > TRACE_METADATA_MAX_LENGTH) continue;
74
+ librechatTraceAttributes[key] = value;
75
+ continue;
76
+ }
77
+ librechatTraceAttributes[key] = value;
78
+ }
79
+ return librechatTraceAttributes;
80
+ }
32
81
  function createLangfuseTraceMetadata({ messageId, parentMessageId, agentId, agentName }) {
33
82
  return createTraceMetadata({
34
83
  messageId,
@@ -62,13 +111,15 @@ function shouldCreateLangfuseHandler(langfuse) {
62
111
  if (langfuse?.enabled === false) return false;
63
112
  return hasLangfuseEnvConfig() || hasLangfuseConfigCredentials(langfuse) || hasLangfuseConfigBaseUrl(langfuse) && hasLangfuseEnvCredentials();
64
113
  }
65
- function createLangfuseHandler({ langfuse, userId, sessionId, traceMetadata, tags }) {
114
+ function createLangfuseHandler({ langfuse, userId, sessionId, traceMetadata, tags, traceIdSeed }) {
66
115
  if (!shouldCreateLangfuseHandler(langfuse)) return;
67
- return new _langfuse_langchain.CallbackHandler({
116
+ return new ScopedLangfuseCallbackHandler({
68
117
  userId,
69
118
  sessionId,
70
119
  traceMetadata: mergeLangfuseTraceMetadata(traceMetadata, langfuse?.metadata),
71
- tags: mergeLangfuseTags(tags, langfuse?.tags)
120
+ tags: mergeLangfuseTags(tags, langfuse?.tags),
121
+ langfuse,
122
+ traceIdSeed
72
123
  });
73
124
  }
74
125
  function createPropagateAttributeParams({ langfuse, userId, sessionId, traceMetadata, traceName, tags }) {
@@ -88,12 +139,13 @@ function isLangfuseCallbackHandler(value) {
88
139
  return value instanceof _langfuse_langchain.CallbackHandler;
89
140
  }
90
141
  async function disposeLangfuseHandler(value) {
91
- if (value == null || !parseBooleanEnv(process.env[LANGFUSE_FORCE_FLUSH_ON_DISPOSE])) return;
142
+ if (value == null || !require_misc.parseBooleanEnv(process.env[LANGFUSE_FORCE_FLUSH_ON_DISPOSE])) return;
92
143
  await (0, _langfuse_tracing.getLangfuseTracerProvider)().forceFlush?.();
93
144
  }
94
145
  //#endregion
95
146
  exports.createLangfuseHandler = createLangfuseHandler;
96
147
  exports.createLangfuseTraceMetadata = createLangfuseTraceMetadata;
148
+ exports.createLibreChatTraceAttributes = createLibreChatTraceAttributes;
97
149
  exports.disposeLangfuseHandler = disposeLangfuseHandler;
98
150
  exports.getLangfuseTraceName = getLangfuseTraceName;
99
151
  exports.hasLangfuseConfigCredentials = hasLangfuseConfigCredentials;
@@ -1 +1 @@
1
- {"version":3,"file":"langfuse.cjs","names":["isPresent","CallbackHandler"],"sources":["../../src/langfuse.ts"],"sourcesContent":["import { CallbackHandler } from '@langfuse/langchain';\nimport {\n getLangfuseTracerProvider,\n propagateAttributes,\n} from '@langfuse/tracing';\nimport type { PropagateAttributesParams } from '@langfuse/tracing';\nimport type * as t from '@/types';\nimport { isPresent } from '@/utils/misc';\n\nconst TRACE_METADATA_MAX_LENGTH = 200;\nconst LANGFUSE_FORCE_FLUSH_ON_DISPOSE = 'LANGFUSE_FORCE_FLUSH_ON_DISPOSE';\n\nexport type LangfuseTraceMetadata = Record<string, string>;\ntype LangfuseMetadata = NonNullable<t.LangfuseConfig['metadata']>;\n\ntype LangfuseHandlerParams = {\n userId?: string;\n sessionId?: string;\n traceMetadata?: LangfuseTraceMetadata;\n tags?: string[];\n};\n\ntype AgentLangfuseHandlerParams = LangfuseHandlerParams & {\n langfuse?: t.LangfuseConfig;\n};\n\ntype LangfuseAttributeParams = AgentLangfuseHandlerParams & {\n traceName?: string;\n};\n\ntype FlushableTracerProvider = {\n forceFlush?: () => Promise<void> | void;\n};\n\nfunction parseBooleanEnv(value?: string): boolean {\n if (value == null) {\n return false;\n }\n return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());\n}\n\nfunction hasLangfuseTracingConfig(langfuse?: t.LangfuseConfig): boolean {\n return (\n langfuse?.toolNodeTracing != null || langfuse?.toolOutputTracing != null\n );\n}\n\nfunction hasLangfuseTraceAttributes(langfuse?: t.LangfuseConfig): boolean {\n return (\n Object.keys(createTraceMetadata(langfuse?.metadata ?? {})).length > 0 ||\n (mergeLangfuseTags(undefined, langfuse?.tags)?.length ?? 0) > 0\n );\n}\n\nexport function hasLangfuseConfigCredentials(\n langfuse?: t.LangfuseConfig\n): langfuse is t.LangfuseConfig & {\n publicKey: string;\n secretKey: string;\n} {\n return (\n langfuse != null &&\n isPresent(langfuse.publicKey) &&\n isPresent(langfuse.secretKey)\n );\n}\n\nfunction hasLangfuseConfigBaseUrl(langfuse?: t.LangfuseConfig): boolean {\n return isPresent(langfuse?.baseUrl);\n}\n\nexport function isExplicitLangfuseConfig(langfuse?: t.LangfuseConfig): boolean {\n return (\n langfuse?.enabled != null ||\n isPresent(langfuse?.publicKey) ||\n isPresent(langfuse?.secretKey) ||\n isPresent(langfuse?.baseUrl) ||\n hasLangfuseTraceAttributes(langfuse) ||\n hasLangfuseTracingConfig(langfuse)\n );\n}\n\nfunction createTraceMetadata(\n metadata: Record<string, unknown>\n): LangfuseTraceMetadata {\n const traceMetadata: LangfuseTraceMetadata = {};\n for (const [key, value] of Object.entries(metadata)) {\n if (value == null) {\n continue;\n }\n const stringValue = typeof value === 'string' ? value : String(value);\n if (\n stringValue.trim() === '' ||\n stringValue.length > TRACE_METADATA_MAX_LENGTH\n ) {\n continue;\n }\n traceMetadata[key] = stringValue;\n }\n return traceMetadata;\n}\n\nexport function createLangfuseTraceMetadata({\n messageId,\n parentMessageId,\n agentId,\n agentName,\n}: {\n messageId?: unknown;\n parentMessageId?: unknown;\n agentId?: unknown;\n agentName?: unknown;\n}): LangfuseTraceMetadata {\n return createTraceMetadata({\n messageId,\n parentMessageId,\n agentId,\n agentName,\n });\n}\n\nfunction mergeLangfuseTraceMetadata(\n traceMetadata?: LangfuseTraceMetadata,\n metadata?: LangfuseMetadata\n): LangfuseTraceMetadata | undefined {\n const merged = createTraceMetadata({\n ...(metadata ?? {}),\n ...(traceMetadata ?? {}),\n });\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\nfunction mergeLangfuseTags(\n tags?: string[],\n configTags?: string[]\n): string[] | undefined {\n const merged = [...(tags ?? []), ...(configTags ?? [])].filter(\n (tag) => tag.trim() !== ''\n );\n return merged.length > 0 ? [...new Set(merged)] : undefined;\n}\n\nexport function getLangfuseTraceName(\n traceMetadata?: LangfuseTraceMetadata,\n fallback: string = 'LibreChat Agent'\n): string {\n const agentName = traceMetadata?.agentName;\n return isPresent(agentName) ? `${fallback}: ${agentName}` : fallback;\n}\n\nexport function hasLangfuseEnvConfig(): boolean {\n return hasLangfuseEnvCredentials();\n}\n\nexport function hasLangfuseEnvCredentials(): boolean {\n return (\n isPresent(process.env.LANGFUSE_SECRET_KEY) &&\n isPresent(process.env.LANGFUSE_PUBLIC_KEY)\n );\n}\n\nexport function shouldCreateLangfuseHandler(\n langfuse?: t.LangfuseConfig\n): boolean {\n if (langfuse?.enabled === false) {\n return false;\n }\n return (\n hasLangfuseEnvConfig() ||\n hasLangfuseConfigCredentials(langfuse) ||\n (hasLangfuseConfigBaseUrl(langfuse) && hasLangfuseEnvCredentials())\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 tags,\n}: AgentLangfuseHandlerParams): CallbackHandler | undefined {\n if (!shouldCreateLangfuseHandler(langfuse)) {\n return undefined;\n }\n return new CallbackHandler({\n userId,\n sessionId,\n traceMetadata: mergeLangfuseTraceMetadata(\n traceMetadata,\n langfuse?.metadata\n ),\n tags: mergeLangfuseTags(tags, langfuse?.tags),\n });\n}\n\nfunction createPropagateAttributeParams({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n traceName,\n tags,\n}: LangfuseAttributeParams): PropagateAttributesParams {\n return {\n userId,\n sessionId,\n traceName,\n tags: mergeLangfuseTags(tags, langfuse?.tags),\n metadata: mergeLangfuseTraceMetadata(traceMetadata, langfuse?.metadata),\n };\n}\n\nexport function withLangfuseAttributes<T>(\n params: LangfuseAttributeParams,\n action: () => T\n): T {\n if (!shouldCreateLangfuseHandler(params.langfuse)) {\n return action();\n }\n return propagateAttributes(createPropagateAttributeParams(params), action);\n}\n\nexport function hasExplicitLangfuseConfig(\n contexts: Iterable<{ langfuse?: t.LangfuseConfig }>\n): boolean {\n for (const context of contexts) {\n if (isExplicitLangfuseConfig(context.langfuse)) {\n return true;\n }\n }\n return false;\n}\n\nexport function isLangfuseCallbackHandler(value: unknown): boolean {\n return value instanceof CallbackHandler;\n}\n\nexport async function disposeLangfuseHandler(value: unknown): Promise<void> {\n if (\n value == null ||\n !parseBooleanEnv(process.env[LANGFUSE_FORCE_FLUSH_ON_DISPOSE])\n ) {\n return;\n }\n const provider = getLangfuseTracerProvider() as FlushableTracerProvider;\n await provider.forceFlush?.();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"langfuse.cjs","names":["CallbackHandler","otelContext","resolveLangfuseConfigForSpan","withLangfuseRuntimeScope","resolveTraceIdSeedForSpan","isPresent","parseBooleanEnv"],"sources":["../../src/langfuse.ts"],"sourcesContent":["import { CallbackHandler } from '@langfuse/langchain';\nimport { context as otelContext } from '@opentelemetry/api';\nimport {\n getLangfuseTracerProvider,\n propagateAttributes,\n} from '@langfuse/tracing';\nimport type { PropagateAttributesParams } from '@langfuse/tracing';\nimport type * as t from '@/types';\nimport {\n resolveLangfuseConfigForSpan,\n resolveTraceIdSeedForSpan,\n withLangfuseRuntimeScope,\n} from '@/langfuseRuntimeScope';\nimport { isPresent, parseBooleanEnv } from '@/utils/misc';\n\nconst TRACE_METADATA_MAX_LENGTH = 200;\nconst LANGFUSE_FORCE_FLUSH_ON_DISPOSE = 'LANGFUSE_FORCE_FLUSH_ON_DISPOSE';\n\nexport type LangfuseTraceMetadata = Record<string, string>;\nexport type LangfuseTraceAttributes = Record<string, string | number | boolean>;\ntype LangfuseMetadata = NonNullable<t.LangfuseConfig['metadata']>;\ntype LangfuseConfigTraceAttributes = NonNullable<\n t.LangfuseConfig['librechatTraceAttributes']\n>;\n\ntype LangfuseHandlerParams = {\n userId?: string;\n sessionId?: string;\n traceMetadata?: LangfuseTraceMetadata;\n tags?: string[];\n traceIdSeed?: string;\n};\n\ntype AgentLangfuseHandlerParams = LangfuseHandlerParams & {\n langfuse?: t.LangfuseConfig;\n};\n\ntype LangfuseAttributeParams = AgentLangfuseHandlerParams & {\n traceName?: string;\n};\n\ntype FlushableTracerProvider = {\n forceFlush?: () => Promise<void> | void;\n};\n\nclass ScopedLangfuseCallbackHandler extends CallbackHandler {\n private readonly langfuse?: t.LangfuseConfig;\n private readonly traceIdSeed?: string;\n\n constructor(params?: AgentLangfuseHandlerParams) {\n const { langfuse, traceIdSeed, ...handlerParams } = params ?? {};\n super(handlerParams);\n this.langfuse = langfuse;\n this.traceIdSeed = traceIdSeed;\n }\n\n private getDeterministicTraceSeed(): string | undefined {\n return this.langfuse?.deterministicTraceId === true\n ? this.traceIdSeed\n : undefined;\n }\n\n private withRuntimeContext<T>(action: () => T): T {\n const activeContext = otelContext.active();\n const langfuse =\n resolveLangfuseConfigForSpan(activeContext) ?? this.langfuse;\n const seed = this.getDeterministicTraceSeed();\n return withLangfuseRuntimeScope(\n {\n langfuse,\n traceIdSeed: resolveTraceIdSeedForSpan(activeContext) ?? seed,\n },\n action\n );\n }\n\n // LangChain may invoke callback handlers outside the caller's OTEL context.\n // Re-enter tenant scope only for callbacks that start Langfuse observations;\n // end/error/token callbacks use spans already bound to a processor at start.\n override handleChainStart(\n ...args: Parameters<CallbackHandler['handleChainStart']>\n ): ReturnType<CallbackHandler['handleChainStart']> {\n return this.withRuntimeContext(() => super.handleChainStart(...args));\n }\n\n override handleAgentAction(\n ...args: Parameters<CallbackHandler['handleAgentAction']>\n ): ReturnType<CallbackHandler['handleAgentAction']> {\n return this.withRuntimeContext(() => super.handleAgentAction(...args));\n }\n\n override handleGenerationStart(\n ...args: Parameters<CallbackHandler['handleGenerationStart']>\n ): ReturnType<CallbackHandler['handleGenerationStart']> {\n return this.withRuntimeContext(() => super.handleGenerationStart(...args));\n }\n\n override handleChatModelStart(\n ...args: Parameters<CallbackHandler['handleChatModelStart']>\n ): ReturnType<CallbackHandler['handleChatModelStart']> {\n return this.withRuntimeContext(() => super.handleChatModelStart(...args));\n }\n\n override handleLLMStart(\n ...args: Parameters<CallbackHandler['handleLLMStart']>\n ): ReturnType<CallbackHandler['handleLLMStart']> {\n return this.withRuntimeContext(() => super.handleLLMStart(...args));\n }\n\n override handleToolStart(\n ...args: Parameters<CallbackHandler['handleToolStart']>\n ): ReturnType<CallbackHandler['handleToolStart']> {\n return this.withRuntimeContext(() => super.handleToolStart(...args));\n }\n\n override handleRetrieverStart(\n ...args: Parameters<CallbackHandler['handleRetrieverStart']>\n ): ReturnType<CallbackHandler['handleRetrieverStart']> {\n return this.withRuntimeContext(() => super.handleRetrieverStart(...args));\n }\n}\n\nfunction hasLangfuseTracingConfig(langfuse?: t.LangfuseConfig): boolean {\n return (\n langfuse?.toolNodeTracing != null || langfuse?.toolOutputTracing != null\n );\n}\n\nfunction hasLangfuseTraceAttributes(langfuse?: t.LangfuseConfig): boolean {\n return (\n Object.keys(createTraceMetadata(langfuse?.metadata ?? {})).length > 0 ||\n Object.keys(\n createLibreChatTraceAttributes(langfuse?.librechatTraceAttributes ?? {})\n ).length > 0 ||\n (mergeLangfuseTags(undefined, langfuse?.tags)?.length ?? 0) > 0\n );\n}\n\nexport function hasLangfuseConfigCredentials(\n langfuse?: t.LangfuseConfig\n): langfuse is t.LangfuseConfig & {\n publicKey: string;\n secretKey: string;\n} {\n return (\n langfuse != null &&\n isPresent(langfuse.publicKey) &&\n isPresent(langfuse.secretKey)\n );\n}\n\nfunction hasLangfuseConfigBaseUrl(langfuse?: t.LangfuseConfig): boolean {\n return isPresent(langfuse?.baseUrl);\n}\n\nexport function isExplicitLangfuseConfig(langfuse?: t.LangfuseConfig): boolean {\n return (\n langfuse?.enabled != null ||\n isPresent(langfuse?.publicKey) ||\n isPresent(langfuse?.secretKey) ||\n isPresent(langfuse?.baseUrl) ||\n hasLangfuseTraceAttributes(langfuse) ||\n hasLangfuseTracingConfig(langfuse)\n );\n}\n\nfunction createTraceMetadata(\n metadata: Record<string, unknown>\n): LangfuseTraceMetadata {\n const traceMetadata: LangfuseTraceMetadata = {};\n for (const [key, value] of Object.entries(metadata)) {\n if (value == null) {\n continue;\n }\n const stringValue = typeof value === 'string' ? value : String(value);\n if (\n stringValue.trim() === '' ||\n stringValue.length > TRACE_METADATA_MAX_LENGTH\n ) {\n continue;\n }\n traceMetadata[key] = stringValue;\n }\n return traceMetadata;\n}\n\nexport function createLibreChatTraceAttributes(\n attributes: LangfuseConfigTraceAttributes\n): LangfuseTraceAttributes {\n const librechatTraceAttributes: LangfuseTraceAttributes = {};\n for (const [key, value] of Object.entries(attributes)) {\n if (value == null || key.trim() === '') {\n continue;\n }\n if (typeof value === 'string') {\n if (value.trim() === '' || value.length > TRACE_METADATA_MAX_LENGTH) {\n continue;\n }\n librechatTraceAttributes[key] = value;\n continue;\n }\n librechatTraceAttributes[key] = value;\n }\n return librechatTraceAttributes;\n}\n\nexport function createLangfuseTraceMetadata({\n messageId,\n parentMessageId,\n agentId,\n agentName,\n}: {\n messageId?: unknown;\n parentMessageId?: unknown;\n agentId?: unknown;\n agentName?: unknown;\n}): LangfuseTraceMetadata {\n return createTraceMetadata({\n messageId,\n parentMessageId,\n agentId,\n agentName,\n });\n}\n\nfunction mergeLangfuseTraceMetadata(\n traceMetadata?: LangfuseTraceMetadata,\n metadata?: LangfuseMetadata\n): LangfuseTraceMetadata | undefined {\n const merged = createTraceMetadata({\n ...(metadata ?? {}),\n ...(traceMetadata ?? {}),\n });\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\nfunction mergeLangfuseTags(\n tags?: string[],\n configTags?: string[]\n): string[] | undefined {\n const merged = [...(tags ?? []), ...(configTags ?? [])].filter(\n (tag) => tag.trim() !== ''\n );\n return merged.length > 0 ? [...new Set(merged)] : undefined;\n}\n\nexport function getLangfuseTraceName(\n traceMetadata?: LangfuseTraceMetadata,\n fallback: string = 'LibreChat Agent'\n): string {\n const agentName = traceMetadata?.agentName;\n return isPresent(agentName) ? `${fallback}: ${agentName}` : fallback;\n}\n\nexport function hasLangfuseEnvConfig(): boolean {\n return hasLangfuseEnvCredentials();\n}\n\nexport function hasLangfuseEnvCredentials(): boolean {\n return (\n isPresent(process.env.LANGFUSE_SECRET_KEY) &&\n isPresent(process.env.LANGFUSE_PUBLIC_KEY)\n );\n}\n\nexport function shouldCreateLangfuseHandler(\n langfuse?: t.LangfuseConfig\n): boolean {\n if (langfuse?.enabled === false) {\n return false;\n }\n return (\n hasLangfuseEnvConfig() ||\n hasLangfuseConfigCredentials(langfuse) ||\n (hasLangfuseConfigBaseUrl(langfuse) && hasLangfuseEnvCredentials())\n );\n}\n\nexport function createLegacyLangfuseHandler(\n params: LangfuseHandlerParams\n): CallbackHandler {\n return new ScopedLangfuseCallbackHandler(params);\n}\n\nexport function createLangfuseHandler({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n tags,\n traceIdSeed,\n}: AgentLangfuseHandlerParams): CallbackHandler | undefined {\n if (!shouldCreateLangfuseHandler(langfuse)) {\n return undefined;\n }\n return new ScopedLangfuseCallbackHandler({\n userId,\n sessionId,\n traceMetadata: mergeLangfuseTraceMetadata(\n traceMetadata,\n langfuse?.metadata\n ),\n tags: mergeLangfuseTags(tags, langfuse?.tags),\n langfuse,\n traceIdSeed,\n });\n}\n\nfunction createPropagateAttributeParams({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n traceName,\n tags,\n}: LangfuseAttributeParams): PropagateAttributesParams {\n return {\n userId,\n sessionId,\n traceName,\n tags: mergeLangfuseTags(tags, langfuse?.tags),\n metadata: mergeLangfuseTraceMetadata(traceMetadata, langfuse?.metadata),\n };\n}\n\nexport function withLangfuseAttributes<T>(\n params: LangfuseAttributeParams,\n action: () => T\n): T {\n if (!shouldCreateLangfuseHandler(params.langfuse)) {\n return action();\n }\n return propagateAttributes(createPropagateAttributeParams(params), action);\n}\n\nexport function hasExplicitLangfuseConfig(\n contexts: Iterable<{ langfuse?: t.LangfuseConfig }>\n): boolean {\n for (const context of contexts) {\n if (isExplicitLangfuseConfig(context.langfuse)) {\n return true;\n }\n }\n return false;\n}\n\nexport function isLangfuseCallbackHandler(value: unknown): boolean {\n return value instanceof CallbackHandler;\n}\n\nexport async function disposeLangfuseHandler(value: unknown): Promise<void> {\n if (\n value == null ||\n !parseBooleanEnv(process.env[LANGFUSE_FORCE_FLUSH_ON_DISPOSE])\n ) {\n return;\n }\n const provider = getLangfuseTracerProvider() as FlushableTracerProvider;\n await provider.forceFlush?.();\n}\n"],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ const require_misc = require("./utils/misc.cjs");
2
+ //#region src/langfuseConfig.ts
3
+ const LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT = "[tool output redacted]";
4
+ function isPresent(value) {
5
+ return typeof value === "string" && value.trim() !== "";
6
+ }
7
+ function normalizeToolName(name) {
8
+ return name.trim().toLowerCase();
9
+ }
10
+ function normalizeToolNames(names) {
11
+ const normalized = /* @__PURE__ */ new Set();
12
+ for (const name of names ?? []) if (isPresent(name)) normalized.add(normalizeToolName(name));
13
+ return normalized;
14
+ }
15
+ function parseToolNames(value) {
16
+ if (!isPresent(value)) return;
17
+ return value.split(",").map((name) => name.trim()).filter((name) => name !== "");
18
+ }
19
+ function getEnvToolOutputTracingEnabled() {
20
+ const traceToolOutputs = require_misc.parseBooleanEnv(process.env.LANGFUSE_TRACE_TOOL_OUTPUTS);
21
+ if (traceToolOutputs != null) return traceToolOutputs;
22
+ const redactToolOutputs = require_misc.parseBooleanEnv(process.env.LANGFUSE_REDACT_TOOL_OUTPUTS);
23
+ if (redactToolOutputs != null) return !redactToolOutputs;
24
+ return require_misc.parseBooleanEnv(process.env.LANGFUSE_TOOL_OUTPUT_TRACING_ENABLED);
25
+ }
26
+ function getEnvRedactedToolNames() {
27
+ return parseToolNames(process.env.LANGFUSE_REDACT_TOOL_OUTPUT_NAMES) ?? parseToolNames(process.env.LANGFUSE_REDACT_TOOL_NAMES);
28
+ }
29
+ function getEnvRedactionText() {
30
+ return isPresent(process.env.LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT) ? process.env.LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT : void 0;
31
+ }
32
+ function getEnvToolNameMatchMode() {
33
+ const mode = (process.env.LANGFUSE_REDACT_TOOL_OUTPUT_NAME_MATCH_MODE ?? process.env.LANGFUSE_REDACT_TOOL_NAME_MATCH_MODE)?.trim().toLowerCase();
34
+ if (mode === "exact" || mode === "partial") return mode;
35
+ }
36
+ function hasEnvToolOutputTracingConfig() {
37
+ return getEnvToolOutputTracingEnabled() != null || getEnvRedactedToolNames() != null || getEnvRedactionText() != null || getEnvToolNameMatchMode() != null;
38
+ }
39
+ function resolveToolOutputTracingEnabled(runConfig, agentConfig) {
40
+ return agentConfig?.enabled ?? runConfig?.enabled ?? getEnvToolOutputTracingEnabled() ?? true;
41
+ }
42
+ function resolveRedactedToolNames(runConfig, agentConfig) {
43
+ return normalizeToolNames([
44
+ ...getEnvRedactedToolNames() ?? [],
45
+ ...runConfig?.redactedToolNames ?? [],
46
+ ...agentConfig?.redactedToolNames ?? []
47
+ ]);
48
+ }
49
+ function resolveToolNameMatchMode(runConfig, agentConfig) {
50
+ return [
51
+ getEnvToolNameMatchMode(),
52
+ runConfig?.redactedToolNameMatchMode,
53
+ agentConfig?.redactedToolNameMatchMode
54
+ ].includes("partial") ? "partial" : "exact";
55
+ }
56
+ function hasToolOutputTracingConfig(runLangfuse, agentLangfuse) {
57
+ return runLangfuse?.toolOutputTracing != null || agentLangfuse?.toolOutputTracing != null || hasEnvToolOutputTracingConfig();
58
+ }
59
+ function resolveToolOutputTracingConfig(runLangfuse, agentLangfuse) {
60
+ const runConfig = runLangfuse?.toolOutputTracing;
61
+ const agentConfig = agentLangfuse?.toolOutputTracing;
62
+ return {
63
+ enabled: resolveToolOutputTracingEnabled(runConfig, agentConfig),
64
+ redactedToolNames: resolveRedactedToolNames(runConfig, agentConfig),
65
+ redactedToolNameMatchMode: resolveToolNameMatchMode(runConfig, agentConfig),
66
+ redactionText: agentConfig?.redactionText ?? runConfig?.redactionText ?? getEnvRedactionText() ?? "[tool output redacted]"
67
+ };
68
+ }
69
+ function resolveLangfuseConfig(runLangfuse, agentLangfuse) {
70
+ if (runLangfuse == null) return agentLangfuse;
71
+ if (agentLangfuse == null) return runLangfuse;
72
+ const toolNodeTracing = runLangfuse.toolNodeTracing != null || agentLangfuse.toolNodeTracing != null ? {
73
+ ...runLangfuse.toolNodeTracing,
74
+ ...agentLangfuse.toolNodeTracing
75
+ } : void 0;
76
+ const toolOutputTracing = runLangfuse.toolOutputTracing != null || agentLangfuse.toolOutputTracing != null ? {
77
+ ...runLangfuse.toolOutputTracing,
78
+ ...agentLangfuse.toolOutputTracing
79
+ } : void 0;
80
+ const metadata = runLangfuse.metadata != null || agentLangfuse.metadata != null ? {
81
+ ...runLangfuse.metadata,
82
+ ...agentLangfuse.metadata
83
+ } : void 0;
84
+ const librechatTraceAttributes = runLangfuse.librechatTraceAttributes != null || agentLangfuse.librechatTraceAttributes != null ? {
85
+ ...runLangfuse.librechatTraceAttributes,
86
+ ...agentLangfuse.librechatTraceAttributes
87
+ } : void 0;
88
+ const tags = runLangfuse.tags != null || agentLangfuse.tags != null ? [...new Set([...runLangfuse.tags ?? [], ...agentLangfuse.tags ?? []])] : void 0;
89
+ return {
90
+ ...runLangfuse,
91
+ ...agentLangfuse,
92
+ ...metadata != null ? { metadata } : {},
93
+ ...librechatTraceAttributes != null ? { librechatTraceAttributes } : {},
94
+ ...tags != null ? { tags } : {},
95
+ ...toolNodeTracing != null ? { toolNodeTracing } : {},
96
+ ...toolOutputTracing != null ? { toolOutputTracing } : {}
97
+ };
98
+ }
99
+ //#endregion
100
+ exports.LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT = LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT;
101
+ exports.hasToolOutputTracingConfig = hasToolOutputTracingConfig;
102
+ exports.normalizeToolName = normalizeToolName;
103
+ exports.resolveLangfuseConfig = resolveLangfuseConfig;
104
+ exports.resolveToolOutputTracingConfig = resolveToolOutputTracingConfig;
105
+
106
+ //# sourceMappingURL=langfuseConfig.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"langfuseConfig.cjs","names":["parseBooleanEnv"],"sources":["../../src/langfuseConfig.ts"],"sourcesContent":["import type { ResolvedLangfuseToolOutputTracingConfig } from '@/langfuseRuntimeContext';\nimport type * as t from '@/types';\nimport { parseBooleanEnv } from '@/utils/misc';\n\nexport const LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT = '[tool output redacted]';\n\nfunction isPresent(value: unknown): value is string {\n return typeof value === 'string' && value.trim() !== '';\n}\n\nexport function normalizeToolName(name: string): string {\n return name.trim().toLowerCase();\n}\n\nfunction normalizeToolNames(names: string[] | undefined): Set<string> {\n const normalized = new Set<string>();\n for (const name of names ?? []) {\n if (isPresent(name)) {\n normalized.add(normalizeToolName(name));\n }\n }\n return normalized;\n}\n\nfunction parseToolNames(value: string | undefined): string[] | undefined {\n if (!isPresent(value)) {\n return undefined;\n }\n\n return value\n .split(',')\n .map((name) => name.trim())\n .filter((name) => name !== '');\n}\n\nfunction getEnvToolOutputTracingEnabled(): boolean | undefined {\n const traceToolOutputs = parseBooleanEnv(\n process.env.LANGFUSE_TRACE_TOOL_OUTPUTS\n );\n if (traceToolOutputs != null) {\n return traceToolOutputs;\n }\n\n const redactToolOutputs = parseBooleanEnv(\n process.env.LANGFUSE_REDACT_TOOL_OUTPUTS\n );\n if (redactToolOutputs != null) {\n return !redactToolOutputs;\n }\n\n return parseBooleanEnv(process.env.LANGFUSE_TOOL_OUTPUT_TRACING_ENABLED);\n}\n\nfunction getEnvRedactedToolNames(): string[] | undefined {\n return (\n parseToolNames(process.env.LANGFUSE_REDACT_TOOL_OUTPUT_NAMES) ??\n parseToolNames(process.env.LANGFUSE_REDACT_TOOL_NAMES)\n );\n}\n\nfunction getEnvRedactionText(): string | undefined {\n return isPresent(process.env.LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT)\n ? process.env.LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT\n : undefined;\n}\n\nfunction getEnvToolNameMatchMode(): 'exact' | 'partial' | undefined {\n const mode = (\n process.env.LANGFUSE_REDACT_TOOL_OUTPUT_NAME_MATCH_MODE ??\n process.env.LANGFUSE_REDACT_TOOL_NAME_MATCH_MODE\n )\n ?.trim()\n .toLowerCase();\n if (mode === 'exact' || mode === 'partial') {\n return mode;\n }\n return undefined;\n}\n\nfunction hasEnvToolOutputTracingConfig(): boolean {\n return (\n getEnvToolOutputTracingEnabled() != null ||\n getEnvRedactedToolNames() != null ||\n getEnvRedactionText() != null ||\n getEnvToolNameMatchMode() != null\n );\n}\n\nfunction resolveToolOutputTracingEnabled(\n runConfig?: t.LangfuseToolOutputTracingConfig,\n agentConfig?: t.LangfuseToolOutputTracingConfig\n): boolean {\n return (\n agentConfig?.enabled ??\n runConfig?.enabled ??\n getEnvToolOutputTracingEnabled() ??\n true\n );\n}\n\nfunction resolveRedactedToolNames(\n runConfig?: t.LangfuseToolOutputTracingConfig,\n agentConfig?: t.LangfuseToolOutputTracingConfig\n): Set<string> {\n return normalizeToolNames([\n ...(getEnvRedactedToolNames() ?? []),\n ...(runConfig?.redactedToolNames ?? []),\n ...(agentConfig?.redactedToolNames ?? []),\n ]);\n}\n\nfunction resolveToolNameMatchMode(\n runConfig?: t.LangfuseToolOutputTracingConfig,\n agentConfig?: t.LangfuseToolOutputTracingConfig\n): 'exact' | 'partial' {\n const modes = [\n getEnvToolNameMatchMode(),\n runConfig?.redactedToolNameMatchMode,\n agentConfig?.redactedToolNameMatchMode,\n ];\n return modes.includes('partial') ? 'partial' : 'exact';\n}\n\nexport function hasToolOutputTracingConfig(\n runLangfuse?: t.LangfuseConfig,\n agentLangfuse?: t.LangfuseConfig\n): boolean {\n return (\n runLangfuse?.toolOutputTracing != null ||\n agentLangfuse?.toolOutputTracing != null ||\n hasEnvToolOutputTracingConfig()\n );\n}\n\nexport function resolveToolOutputTracingConfig(\n runLangfuse?: t.LangfuseConfig,\n agentLangfuse?: t.LangfuseConfig\n): ResolvedLangfuseToolOutputTracingConfig {\n const runConfig = runLangfuse?.toolOutputTracing;\n const agentConfig = agentLangfuse?.toolOutputTracing;\n\n return {\n enabled: resolveToolOutputTracingEnabled(runConfig, agentConfig),\n redactedToolNames: resolveRedactedToolNames(runConfig, agentConfig),\n redactedToolNameMatchMode: resolveToolNameMatchMode(runConfig, agentConfig),\n redactionText:\n agentConfig?.redactionText ??\n runConfig?.redactionText ??\n getEnvRedactionText() ??\n LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT,\n };\n}\n\nexport function resolveLangfuseConfig(\n runLangfuse?: t.LangfuseConfig,\n agentLangfuse?: t.LangfuseConfig\n): t.LangfuseConfig | undefined {\n if (runLangfuse == null) {\n return agentLangfuse;\n }\n if (agentLangfuse == null) {\n return runLangfuse;\n }\n\n const toolNodeTracing =\n runLangfuse.toolNodeTracing != null || agentLangfuse.toolNodeTracing != null\n ? {\n ...runLangfuse.toolNodeTracing,\n ...agentLangfuse.toolNodeTracing,\n }\n : undefined;\n const toolOutputTracing =\n runLangfuse.toolOutputTracing != null ||\n agentLangfuse.toolOutputTracing != null\n ? {\n ...runLangfuse.toolOutputTracing,\n ...agentLangfuse.toolOutputTracing,\n }\n : undefined;\n const metadata =\n runLangfuse.metadata != null || agentLangfuse.metadata != null\n ? {\n ...runLangfuse.metadata,\n ...agentLangfuse.metadata,\n }\n : undefined;\n const librechatTraceAttributes =\n runLangfuse.librechatTraceAttributes != null ||\n agentLangfuse.librechatTraceAttributes != null\n ? {\n ...runLangfuse.librechatTraceAttributes,\n ...agentLangfuse.librechatTraceAttributes,\n }\n : undefined;\n const tags =\n runLangfuse.tags != null || agentLangfuse.tags != null\n ? [\n ...new Set([\n ...(runLangfuse.tags ?? []),\n ...(agentLangfuse.tags ?? []),\n ]),\n ]\n : undefined;\n\n return {\n ...runLangfuse,\n ...agentLangfuse,\n ...(metadata != null ? { metadata } : {}),\n ...(librechatTraceAttributes != null ? { librechatTraceAttributes } : {}),\n ...(tags != null ? { tags } : {}),\n ...(toolNodeTracing != null ? { toolNodeTracing } : {}),\n ...(toolOutputTracing != null ? { toolOutputTracing } : {}),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ let node_crypto = require("node:crypto");
2
+ //#region src/langfuseRuntimeContext.ts
3
+ const langfuseRuntimeContextStore = new (require("node:async_hooks")).AsyncLocalStorage();
4
+ function hasText(value) {
5
+ return value != null && value.trim() !== "";
6
+ }
7
+ function hasLangfuseRuntimeContextValue(context) {
8
+ return context.langfuse != null || hasText(context.traceIdSeed) || context.toolOutputTracing != null;
9
+ }
10
+ /** sha256(seed) -> first 32 hex chars; matches `@langfuse/tracing` `createTraceId`. */
11
+ function traceIdFromSeed(seed) {
12
+ return (0, node_crypto.createHash)("sha256").update(seed, "utf8").digest("hex").slice(0, 32);
13
+ }
14
+ function getLangfuseRuntimeContext() {
15
+ return langfuseRuntimeContextStore.getStore();
16
+ }
17
+ function getLangfuseRuntimeConfig() {
18
+ return getLangfuseRuntimeContext()?.langfuse;
19
+ }
20
+ function getTraceIdSeed() {
21
+ return getLangfuseRuntimeContext()?.traceIdSeed;
22
+ }
23
+ function getLangfuseRuntimeToolOutputTracingConfig() {
24
+ return getLangfuseRuntimeContext()?.toolOutputTracing;
25
+ }
26
+ /**
27
+ * Runs `fn` with a merged Langfuse runtime context. Undefined fields inherit
28
+ * from the parent scope; callers intentionally cannot clear parent values by
29
+ * passing `undefined`.
30
+ */
31
+ function runWithLangfuseRuntimeContext(context, fn) {
32
+ const next = {
33
+ ...getLangfuseRuntimeContext() ?? {},
34
+ ...context.langfuse !== void 0 ? { langfuse: context.langfuse } : {},
35
+ ...hasText(context.traceIdSeed) ? { traceIdSeed: context.traceIdSeed } : {},
36
+ ...context.toolOutputTracing !== void 0 ? { toolOutputTracing: context.toolOutputTracing } : {}
37
+ };
38
+ return hasLangfuseRuntimeContextValue(next) ? langfuseRuntimeContextStore.run(next, fn) : fn();
39
+ }
40
+ //#endregion
41
+ exports.getLangfuseRuntimeConfig = getLangfuseRuntimeConfig;
42
+ exports.getLangfuseRuntimeToolOutputTracingConfig = getLangfuseRuntimeToolOutputTracingConfig;
43
+ exports.getTraceIdSeed = getTraceIdSeed;
44
+ exports.hasLangfuseRuntimeContextValue = hasLangfuseRuntimeContextValue;
45
+ exports.runWithLangfuseRuntimeContext = runWithLangfuseRuntimeContext;
46
+ exports.traceIdFromSeed = traceIdFromSeed;
47
+
48
+ //# sourceMappingURL=langfuseRuntimeContext.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"langfuseRuntimeContext.cjs","names":["AsyncLocalStorage"],"sources":["../../src/langfuseRuntimeContext.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport type * as t from '@/types';\n\nexport type ResolvedLangfuseToolOutputTracingConfig = {\n enabled: boolean;\n redactedToolNames: Set<string>;\n redactedToolNameMatchMode: 'exact' | 'partial';\n redactionText: string;\n};\n\nexport type LangfuseRuntimeContext = {\n langfuse?: t.LangfuseConfig;\n traceIdSeed?: string;\n toolOutputTracing?: ResolvedLangfuseToolOutputTracingConfig;\n};\n\nconst langfuseRuntimeContextStore =\n new AsyncLocalStorage<LangfuseRuntimeContext>();\n\nfunction hasText(value: string | undefined): value is string {\n return value != null && value.trim() !== '';\n}\n\nexport function hasLangfuseRuntimeContextValue(\n context: LangfuseRuntimeContext\n): boolean {\n return (\n context.langfuse != null ||\n hasText(context.traceIdSeed) ||\n context.toolOutputTracing != null\n );\n}\n\n/** sha256(seed) -> first 32 hex chars; matches `@langfuse/tracing` `createTraceId`. */\nexport function traceIdFromSeed(seed: string): string {\n return createHash('sha256').update(seed, 'utf8').digest('hex').slice(0, 32);\n}\n\nexport function getLangfuseRuntimeContext():\n | LangfuseRuntimeContext\n | undefined {\n return langfuseRuntimeContextStore.getStore();\n}\n\nexport function getLangfuseRuntimeConfig(): t.LangfuseConfig | undefined {\n return getLangfuseRuntimeContext()?.langfuse;\n}\n\nexport function getTraceIdSeed(): string | undefined {\n return getLangfuseRuntimeContext()?.traceIdSeed;\n}\n\nexport function getLangfuseRuntimeToolOutputTracingConfig():\n | ResolvedLangfuseToolOutputTracingConfig\n | undefined {\n return getLangfuseRuntimeContext()?.toolOutputTracing;\n}\n\n/**\n * Runs `fn` with a merged Langfuse runtime context. Undefined fields inherit\n * from the parent scope; callers intentionally cannot clear parent values by\n * passing `undefined`.\n */\nexport function runWithLangfuseRuntimeContext<T>(\n context: LangfuseRuntimeContext,\n fn: () => T\n): T {\n const current = getLangfuseRuntimeContext();\n const next = {\n ...(current ?? {}),\n ...(context.langfuse !== undefined ? { langfuse: context.langfuse } : {}),\n ...(hasText(context.traceIdSeed)\n ? { traceIdSeed: context.traceIdSeed }\n : {}),\n ...(context.toolOutputTracing !== undefined\n ? { toolOutputTracing: context.toolOutputTracing }\n : {}),\n };\n\n return hasLangfuseRuntimeContextValue(next)\n ? langfuseRuntimeContextStore.run(next, fn)\n : fn();\n}\n\nexport function runWithTraceIdSeed<T>(\n seed: string | undefined,\n fn: () => T\n): T {\n return hasText(seed)\n ? runWithLangfuseRuntimeContext({ traceIdSeed: seed }, fn)\n : fn();\n}\n"],"mappings":";;AAiBA,MAAM,8BACJ,+BAAIA,EAAAA,CAAAA,kBAA0C;AAEhD,SAAS,QAAQ,OAA4C;CAC3D,OAAO,SAAS,QAAQ,MAAM,KAAK,MAAM;AAC3C;AAEA,SAAgB,+BACd,SACS;CACT,OACE,QAAQ,YAAY,QACpB,QAAQ,QAAQ,WAAW,KAC3B,QAAQ,qBAAqB;AAEjC;;AAGA,SAAgB,gBAAgB,MAAsB;CACpD,QAAA,GAAA,YAAA,WAAA,CAAkB,QAAQ,CAAC,CAAC,OAAO,MAAM,MAAM,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE;AAC5E;AAEA,SAAgB,4BAEF;CACZ,OAAO,4BAA4B,SAAS;AAC9C;AAEA,SAAgB,2BAAyD;CACvE,OAAO,0BAA0B,CAAC,EAAE;AACtC;AAEA,SAAgB,iBAAqC;CACnD,OAAO,0BAA0B,CAAC,EAAE;AACtC;AAEA,SAAgB,4CAEF;CACZ,OAAO,0BAA0B,CAAC,EAAE;AACtC;;;;;;AAOA,SAAgB,8BACd,SACA,IACG;CAEH,MAAM,OAAO;EACX,GAFc,0BAEJ,KAAK,CAAC;EAChB,GAAI,QAAQ,aAAa,KAAA,IAAY,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;EACvE,GAAI,QAAQ,QAAQ,WAAW,IAC3B,EAAE,aAAa,QAAQ,YAAY,IACnC,CAAC;EACL,GAAI,QAAQ,sBAAsB,KAAA,IAC9B,EAAE,mBAAmB,QAAQ,kBAAkB,IAC/C,CAAC;CACP;CAEA,OAAO,+BAA+B,IAAI,IACtC,4BAA4B,IAAI,MAAM,EAAE,IACxC,GAAG;AACT"}
@@ -0,0 +1,57 @@
1
+ const require_langfuseRuntimeContext = require("./langfuseRuntimeContext.cjs");
2
+ const require_langfuseConfig = require("./langfuseConfig.cjs");
3
+ let _opentelemetry_api = require("@opentelemetry/api");
4
+ //#region src/langfuseRuntimeScope.ts
5
+ const langfuseToolOutputTracingConfigKey = (0, _opentelemetry_api.createContextKey)("librechat.langfuse.tool-output-tracing");
6
+ const langfuseConfigKey = (0, _opentelemetry_api.createContextKey)("librechat.langfuse.config");
7
+ const langfuseTraceIdSeedKey = (0, _opentelemetry_api.createContextKey)("librechat.langfuse.trace-id-seed");
8
+ function isRecord(value) {
9
+ return value != null && typeof value === "object" && !Array.isArray(value);
10
+ }
11
+ function hasText(value) {
12
+ return value != null && value.trim() !== "";
13
+ }
14
+ function getOtelLangfuseConfig(activeContext) {
15
+ const value = activeContext.getValue(langfuseConfigKey);
16
+ return isRecord(value) ? value : void 0;
17
+ }
18
+ function getOtelTraceIdSeed(activeContext) {
19
+ const value = activeContext.getValue(langfuseTraceIdSeedKey);
20
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
21
+ }
22
+ function getOtelToolOutputTracingConfig(activeContext) {
23
+ const value = activeContext.getValue(langfuseToolOutputTracingConfigKey);
24
+ return isRecord(value) ? value : void 0;
25
+ }
26
+ function resolveLangfuseConfigForSpan(activeContext) {
27
+ return require_langfuseRuntimeContext.getLangfuseRuntimeConfig() ?? getOtelLangfuseConfig(activeContext);
28
+ }
29
+ function resolveTraceIdSeedForSpan(activeContext) {
30
+ return require_langfuseRuntimeContext.getTraceIdSeed() ?? getOtelTraceIdSeed(activeContext);
31
+ }
32
+ function resolveToolOutputTracingConfigForSpan(activeContext) {
33
+ return require_langfuseRuntimeContext.getLangfuseRuntimeToolOutputTracingConfig() ?? getOtelToolOutputTracingConfig(activeContext);
34
+ }
35
+ function withLangfuseRuntimeScope(scope, action) {
36
+ if (!require_langfuseRuntimeContext.hasLangfuseRuntimeContextValue(scope)) return action();
37
+ let activeContext = _opentelemetry_api.context.active();
38
+ if (scope.langfuse != null) activeContext = activeContext.setValue(langfuseConfigKey, scope.langfuse);
39
+ if (scope.toolOutputTracing != null) activeContext = activeContext.setValue(langfuseToolOutputTracingConfigKey, scope.toolOutputTracing);
40
+ if (hasText(scope.traceIdSeed)) activeContext = activeContext.setValue(langfuseTraceIdSeedKey, scope.traceIdSeed);
41
+ return require_langfuseRuntimeContext.runWithLangfuseRuntimeContext(scope, () => _opentelemetry_api.context.with(activeContext, action));
42
+ }
43
+ function resolveLangfuseRuntimeScope({ runLangfuse, langfuseOverlay, traceIdSeed }) {
44
+ return {
45
+ langfuse: require_langfuseConfig.resolveLangfuseConfig(runLangfuse, langfuseOverlay),
46
+ traceIdSeed,
47
+ toolOutputTracing: !require_langfuseConfig.hasToolOutputTracingConfig(runLangfuse, langfuseOverlay) ? void 0 : require_langfuseConfig.resolveToolOutputTracingConfig(runLangfuse, langfuseOverlay)
48
+ };
49
+ }
50
+ //#endregion
51
+ exports.resolveLangfuseConfigForSpan = resolveLangfuseConfigForSpan;
52
+ exports.resolveLangfuseRuntimeScope = resolveLangfuseRuntimeScope;
53
+ exports.resolveToolOutputTracingConfigForSpan = resolveToolOutputTracingConfigForSpan;
54
+ exports.resolveTraceIdSeedForSpan = resolveTraceIdSeedForSpan;
55
+ exports.withLangfuseRuntimeScope = withLangfuseRuntimeScope;
56
+
57
+ //# sourceMappingURL=langfuseRuntimeScope.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"langfuseRuntimeScope.cjs","names":["getLangfuseRuntimeConfig","getTraceIdSeed","getLangfuseRuntimeToolOutputTracingConfig","hasLangfuseRuntimeContextValue","context","runWithLangfuseRuntimeContext","resolveLangfuseConfig","hasToolOutputTracingConfig","resolveToolOutputTracingConfig"],"sources":["../../src/langfuseRuntimeScope.ts"],"sourcesContent":["import { context, createContextKey } from '@opentelemetry/api';\nimport type { Context } from '@opentelemetry/api';\nimport type {\n LangfuseRuntimeContext,\n ResolvedLangfuseToolOutputTracingConfig,\n} from '@/langfuseRuntimeContext';\nimport type * as t from '@/types';\nimport {\n getLangfuseRuntimeConfig,\n getLangfuseRuntimeToolOutputTracingConfig,\n getTraceIdSeed,\n hasLangfuseRuntimeContextValue,\n runWithLangfuseRuntimeContext,\n} from '@/langfuseRuntimeContext';\nimport {\n hasToolOutputTracingConfig,\n resolveLangfuseConfig,\n resolveToolOutputTracingConfig,\n} from '@/langfuseConfig';\n\nexport type LangfuseRuntimeScope = LangfuseRuntimeContext;\n\nexport type ResolveLangfuseRuntimeScopeParams = {\n runLangfuse?: t.LangfuseConfig;\n langfuseOverlay?: t.LangfuseConfig;\n traceIdSeed?: string;\n};\n\nconst langfuseToolOutputTracingConfigKey = createContextKey(\n 'librechat.langfuse.tool-output-tracing'\n);\nconst langfuseConfigKey = createContextKey('librechat.langfuse.config');\nconst langfuseTraceIdSeedKey = createContextKey(\n 'librechat.langfuse.trace-id-seed'\n);\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction hasText(value: string | undefined): value is string {\n return value != null && value.trim() !== '';\n}\n\nexport function getOtelLangfuseConfig(\n activeContext: Context\n): t.LangfuseConfig | undefined {\n const value = activeContext.getValue(langfuseConfigKey);\n return isRecord(value) ? (value as t.LangfuseConfig) : undefined;\n}\n\nexport function getOtelTraceIdSeed(activeContext: Context): string | undefined {\n const value = activeContext.getValue(langfuseTraceIdSeedKey);\n return typeof value === 'string' && value.trim() !== '' ? value : undefined;\n}\n\nexport function getOtelToolOutputTracingConfig(\n activeContext: Context\n): ResolvedLangfuseToolOutputTracingConfig | undefined {\n const value = activeContext.getValue(langfuseToolOutputTracingConfigKey);\n return isRecord(value)\n ? (value as ResolvedLangfuseToolOutputTracingConfig)\n : undefined;\n}\n\nexport function resolveLangfuseConfigForSpan(\n activeContext: Context\n): t.LangfuseConfig | undefined {\n return getLangfuseRuntimeConfig() ?? getOtelLangfuseConfig(activeContext);\n}\n\nexport function resolveTraceIdSeedForSpan(\n activeContext: Context\n): string | undefined {\n return getTraceIdSeed() ?? getOtelTraceIdSeed(activeContext);\n}\n\nexport function resolveToolOutputTracingConfigForSpan(\n activeContext: Context\n): ResolvedLangfuseToolOutputTracingConfig | undefined {\n return (\n getLangfuseRuntimeToolOutputTracingConfig() ??\n getOtelToolOutputTracingConfig(activeContext)\n );\n}\n\nexport function withLangfuseRuntimeScope<T>(\n scope: LangfuseRuntimeScope,\n action: () => T\n): T {\n if (!hasLangfuseRuntimeContextValue(scope)) {\n return action();\n }\n\n let activeContext = context.active();\n if (scope.langfuse != null) {\n activeContext = activeContext.setValue(langfuseConfigKey, scope.langfuse);\n }\n if (scope.toolOutputTracing != null) {\n activeContext = activeContext.setValue(\n langfuseToolOutputTracingConfigKey,\n scope.toolOutputTracing\n );\n }\n if (hasText(scope.traceIdSeed)) {\n activeContext = activeContext.setValue(\n langfuseTraceIdSeedKey,\n scope.traceIdSeed\n );\n }\n\n // Span processors receive the OTel parent context in `onStart`, while\n // LangChain callback handlers may run outside that context and need ALS.\n // The trace id generator reads the seed from ALS or OTel context so SDK\n // callbacks that preserve only one of those contexts still keep trace/score\n // cohesion.\n return runWithLangfuseRuntimeContext(scope, () =>\n context.with(activeContext, action)\n );\n}\n\nexport function resolveLangfuseRuntimeScope({\n runLangfuse,\n langfuseOverlay,\n traceIdSeed,\n}: ResolveLangfuseRuntimeScopeParams): LangfuseRuntimeScope {\n const langfuse = resolveLangfuseConfig(runLangfuse, langfuseOverlay);\n const toolOutputTracing = !hasToolOutputTracingConfig(\n runLangfuse,\n langfuseOverlay\n )\n ? undefined\n : resolveToolOutputTracingConfig(runLangfuse, langfuseOverlay);\n return { langfuse, traceIdSeed, toolOutputTracing };\n}\n"],"mappings":";;;;AA4BA,MAAM,sCAAA,GAAA,mBAAA,iBAAA,CACJ,wCACF;AACA,MAAM,qBAAA,GAAA,mBAAA,iBAAA,CAAqC,2BAA2B;AACtE,MAAM,0BAAA,GAAA,mBAAA,iBAAA,CACJ,kCACF;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,SAAS,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC3E;AAEA,SAAS,QAAQ,OAA4C;CAC3D,OAAO,SAAS,QAAQ,MAAM,KAAK,MAAM;AAC3C;AAEA,SAAgB,sBACd,eAC8B;CAC9B,MAAM,QAAQ,cAAc,SAAS,iBAAiB;CACtD,OAAO,SAAS,KAAK,IAAK,QAA6B,KAAA;AACzD;AAEA,SAAgB,mBAAmB,eAA4C;CAC7E,MAAM,QAAQ,cAAc,SAAS,sBAAsB;CAC3D,OAAO,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,KAAK,QAAQ,KAAA;AACpE;AAEA,SAAgB,+BACd,eACqD;CACrD,MAAM,QAAQ,cAAc,SAAS,kCAAkC;CACvE,OAAO,SAAS,KAAK,IAChB,QACD,KAAA;AACN;AAEA,SAAgB,6BACd,eAC8B;CAC9B,OAAOA,+BAAAA,yBAAyB,KAAK,sBAAsB,aAAa;AAC1E;AAEA,SAAgB,0BACd,eACoB;CACpB,OAAOC,+BAAAA,eAAe,KAAK,mBAAmB,aAAa;AAC7D;AAEA,SAAgB,sCACd,eACqD;CACrD,OACEC,+BAAAA,0CAA0C,KAC1C,+BAA+B,aAAa;AAEhD;AAEA,SAAgB,yBACd,OACA,QACG;CACH,IAAI,CAACC,+BAAAA,+BAA+B,KAAK,GACvC,OAAO,OAAO;CAGhB,IAAI,gBAAgBC,mBAAAA,QAAQ,OAAO;CACnC,IAAI,MAAM,YAAY,MACpB,gBAAgB,cAAc,SAAS,mBAAmB,MAAM,QAAQ;CAE1E,IAAI,MAAM,qBAAqB,MAC7B,gBAAgB,cAAc,SAC5B,oCACA,MAAM,iBACR;CAEF,IAAI,QAAQ,MAAM,WAAW,GAC3B,gBAAgB,cAAc,SAC5B,wBACA,MAAM,WACR;CAQF,OAAOC,+BAAAA,8BAA8B,aACnCD,mBAAAA,QAAQ,KAAK,eAAe,MAAM,CACpC;AACF;AAEA,SAAgB,4BAA4B,EAC1C,aACA,iBACA,eAC0D;CAQ1D,OAAO;EAAE,UAPQE,uBAAAA,sBAAsB,aAAa,eAOpC;EAAG;EAAa,mBANN,CAACC,uBAAAA,2BACzB,aACA,eACF,IACI,KAAA,IACAC,uBAAAA,+BAA+B,aAAa,eAAe;CACb;AACpD"}