@librechat/agents 3.1.91 → 3.1.93

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 (45) hide show
  1. package/dist/cjs/graphs/Graph.cjs +5 -3
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/instrumentation.cjs +2 -7
  4. package/dist/cjs/instrumentation.cjs.map +1 -1
  5. package/dist/cjs/langfuse.cjs +62 -11
  6. package/dist/cjs/langfuse.cjs.map +1 -1
  7. package/dist/cjs/run.cjs +33 -19
  8. package/dist/cjs/run.cjs.map +1 -1
  9. package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs +1 -0
  10. package/dist/cjs/tools/cloudflare/CloudflareBridgeRuntime.cjs.map +1 -1
  11. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs +13 -7
  12. package/dist/cjs/tools/cloudflare/CloudflareSandboxExecutionEngine.cjs.map +1 -1
  13. package/dist/cjs/utils/callbacks.cjs +27 -0
  14. package/dist/cjs/utils/callbacks.cjs.map +1 -0
  15. package/dist/esm/graphs/Graph.mjs +6 -4
  16. package/dist/esm/graphs/Graph.mjs.map +1 -1
  17. package/dist/esm/instrumentation.mjs +2 -7
  18. package/dist/esm/instrumentation.mjs.map +1 -1
  19. package/dist/esm/langfuse.mjs +63 -14
  20. package/dist/esm/langfuse.mjs.map +1 -1
  21. package/dist/esm/run.mjs +34 -20
  22. package/dist/esm/run.mjs.map +1 -1
  23. package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs +1 -0
  24. package/dist/esm/tools/cloudflare/CloudflareBridgeRuntime.mjs.map +1 -1
  25. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs +13 -7
  26. package/dist/esm/tools/cloudflare/CloudflareSandboxExecutionEngine.mjs.map +1 -1
  27. package/dist/esm/utils/callbacks.mjs +24 -0
  28. package/dist/esm/utils/callbacks.mjs.map +1 -0
  29. package/dist/types/langfuse.d.ts +13 -4
  30. package/dist/types/types/run.d.ts +2 -2
  31. package/dist/types/types/tools.d.ts +6 -0
  32. package/dist/types/utils/callbacks.d.ts +5 -0
  33. package/package.json +4 -4
  34. package/src/graphs/Graph.ts +10 -6
  35. package/src/instrumentation.ts +2 -7
  36. package/src/langfuse.ts +98 -15
  37. package/src/run.ts +53 -29
  38. package/src/specs/langfuse-callbacks.test.ts +75 -0
  39. package/src/specs/langfuse-config.test.ts +58 -1
  40. package/src/tools/__tests__/CloudflareSandboxExecution.test.ts +87 -8
  41. package/src/tools/cloudflare/CloudflareBridgeRuntime.ts +1 -0
  42. package/src/tools/cloudflare/CloudflareSandboxExecutionEngine.ts +13 -7
  43. package/src/types/run.ts +2 -7
  44. package/src/types/tools.ts +6 -0
  45. package/src/utils/callbacks.ts +39 -0
@@ -1,11 +1,39 @@
1
1
  import { CallbackHandler } from '@langfuse/langchain';
2
- import { LangfuseSpanProcessor } from '@langfuse/otel';
3
- import { createObservationAttributes, createTraceAttributes } from '@langfuse/tracing';
2
+ import { LangfuseSpanProcessor, isDefaultExportSpan } from '@langfuse/otel';
3
+ import { createObservationAttributes, LangfuseOtelSpanAttributes } from '@langfuse/tracing';
4
4
  import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
5
5
  import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
6
6
  import { SpanStatusCode } from '@opentelemetry/api';
7
7
  import { isPresent } from './utils/misc.mjs';
8
8
 
9
+ const TRACE_METADATA_MAX_LENGTH = 200;
10
+ const LANGFUSE_TRACER_NAME = 'langfuse-sdk';
11
+ function getEnvLangfuseBaseUrl() {
12
+ return process.env.LANGFUSE_BASE_URL ?? process.env.LANGFUSE_BASEURL;
13
+ }
14
+ function createTraceMetadata(metadata) {
15
+ const traceMetadata = {};
16
+ for (const [key, value] of Object.entries(metadata)) {
17
+ if (value == null) {
18
+ continue;
19
+ }
20
+ const stringValue = typeof value === 'string' ? value : String(value);
21
+ if (stringValue.trim() === '' ||
22
+ stringValue.length > TRACE_METADATA_MAX_LENGTH) {
23
+ continue;
24
+ }
25
+ traceMetadata[key] = stringValue;
26
+ }
27
+ return traceMetadata;
28
+ }
29
+ function createLangfuseTraceMetadata({ messageId, parentMessageId, agentId, agentName, }) {
30
+ return createTraceMetadata({
31
+ messageId,
32
+ parentMessageId,
33
+ agentId,
34
+ agentName,
35
+ });
36
+ }
9
37
  function getModelName(serialized) {
10
38
  const serializedRecord = serialized;
11
39
  const kwargs = serializedRecord.kwargs;
@@ -51,11 +79,27 @@ function getUsageDetails(output) {
51
79
  ? Object.fromEntries(usageEntries)
52
80
  : undefined;
53
81
  }
54
- function getTraceName(traceMetadata) {
82
+ function getLangfuseTraceName(traceMetadata, fallback = 'LibreChat Agent') {
55
83
  const agentName = traceMetadata?.agentName;
56
- return typeof agentName === 'string' && agentName.trim() !== ''
57
- ? `LibreChat Agent: ${agentName}`
58
- : 'LibreChat Agent';
84
+ return isPresent(agentName) ? `${fallback}: ${agentName}` : fallback;
85
+ }
86
+ function getTraceAttributes({ userId, sessionId, traceMetadata, tags, }) {
87
+ const attributes = {
88
+ [LangfuseOtelSpanAttributes.TRACE_NAME]: getLangfuseTraceName(traceMetadata),
89
+ };
90
+ if (isPresent(userId)) {
91
+ attributes[LangfuseOtelSpanAttributes.TRACE_USER_ID] = userId;
92
+ }
93
+ if (isPresent(sessionId)) {
94
+ attributes[LangfuseOtelSpanAttributes.TRACE_SESSION_ID] = sessionId;
95
+ }
96
+ if (tags != null && tags.length > 0) {
97
+ attributes[LangfuseOtelSpanAttributes.TRACE_TAGS] = tags;
98
+ }
99
+ for (const [key, value] of Object.entries(traceMetadata ?? {})) {
100
+ attributes[`${LangfuseOtelSpanAttributes.TRACE_METADATA}.${key}`] = value;
101
+ }
102
+ return attributes;
59
103
  }
60
104
  class LangfuseAgentCallbackHandler extends BaseCallbackHandler {
61
105
  name = 'librechat_langfuse_agent_handler';
@@ -64,12 +108,14 @@ class LangfuseAgentCallbackHandler extends BaseCallbackHandler {
64
108
  userId;
65
109
  sessionId;
66
110
  traceMetadata;
111
+ tags;
67
112
  spans = new Map();
68
- constructor({ langfuse, userId, sessionId, traceMetadata, }) {
113
+ constructor({ langfuse, userId, sessionId, traceMetadata, tags, }) {
69
114
  super();
70
115
  this.userId = userId;
71
116
  this.sessionId = sessionId;
72
117
  this.traceMetadata = traceMetadata;
118
+ this.tags = tags;
73
119
  this.processor = new LangfuseSpanProcessor({
74
120
  publicKey: langfuse.publicKey,
75
121
  secretKey: langfuse.secretKey,
@@ -78,6 +124,8 @@ class LangfuseAgentCallbackHandler extends BaseCallbackHandler {
78
124
  process.env.NODE_ENV ??
79
125
  'development',
80
126
  exportMode: 'immediate',
127
+ shouldExportSpan: ({ otelSpan }) => isDefaultExportSpan(otelSpan) ||
128
+ otelSpan.instrumentationScope.name === LANGFUSE_TRACER_NAME,
81
129
  });
82
130
  this.provider = new BasicTracerProvider({
83
131
  spanProcessors: [this.processor],
@@ -87,15 +135,15 @@ class LangfuseAgentCallbackHandler extends BaseCallbackHandler {
87
135
  if (this.spans.has(runId)) {
88
136
  return;
89
137
  }
90
- const tracer = this.provider.getTracer('librechat-agents-langfuse');
138
+ const tracer = this.provider.getTracer(LANGFUSE_TRACER_NAME);
91
139
  const spanName = typeof name === 'string' && name.trim() !== '' ? name : getModelName(llm);
92
140
  const span = tracer.startSpan(spanName, {
93
141
  attributes: {
94
- ...createTraceAttributes({
95
- name: getTraceName(this.traceMetadata),
142
+ ...getTraceAttributes({
96
143
  userId: this.userId,
97
144
  sessionId: this.sessionId,
98
- metadata: this.traceMetadata,
145
+ traceMetadata: this.traceMetadata,
146
+ tags: this.tags,
99
147
  }),
100
148
  ...createObservationAttributes('generation', {
101
149
  input,
@@ -188,7 +236,7 @@ function hasRequiredLangfuseConfig(langfuse) {
188
236
  function createLegacyLangfuseHandler(params) {
189
237
  return new CallbackHandler(params);
190
238
  }
191
- function createLangfuseHandler({ langfuse, userId, sessionId, traceMetadata, }) {
239
+ function createLangfuseHandler({ langfuse, userId, sessionId, traceMetadata, tags, }) {
192
240
  if (!hasRequiredLangfuseConfig(langfuse)) {
193
241
  return undefined;
194
242
  }
@@ -197,6 +245,7 @@ function createLangfuseHandler({ langfuse, userId, sessionId, traceMetadata, })
197
245
  userId,
198
246
  sessionId,
199
247
  traceMetadata,
248
+ tags,
200
249
  });
201
250
  }
202
251
  function hasExplicitLangfuseConfig(contexts) {
@@ -210,7 +259,7 @@ function hasExplicitLangfuseConfig(contexts) {
210
259
  function hasLangfuseEnvConfig() {
211
260
  return (isPresent(process.env.LANGFUSE_SECRET_KEY) &&
212
261
  isPresent(process.env.LANGFUSE_PUBLIC_KEY) &&
213
- isPresent(process.env.LANGFUSE_BASE_URL));
262
+ isPresent(getEnvLangfuseBaseUrl()));
214
263
  }
215
264
  function isLangfuseCallbackHandler(value) {
216
265
  return (value instanceof CallbackHandler ||
@@ -222,5 +271,5 @@ async function disposeLangfuseHandler(value) {
222
271
  }
223
272
  }
224
273
 
225
- export { LangfuseAgentCallbackHandler, createLangfuseHandler, createLegacyLangfuseHandler, disposeLangfuseHandler, hasExplicitLangfuseConfig, hasLangfuseEnvConfig, isLangfuseCallbackHandler };
274
+ export { LangfuseAgentCallbackHandler, createLangfuseHandler, createLangfuseTraceMetadata, createLegacyLangfuseHandler, disposeLangfuseHandler, getLangfuseTraceName, hasExplicitLangfuseConfig, hasLangfuseEnvConfig, isLangfuseCallbackHandler };
226
275
  //# sourceMappingURL=langfuse.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"langfuse.mjs","sources":["../../src/langfuse.ts"],"sourcesContent":["import { CallbackHandler } from '@langfuse/langchain';\nimport { LangfuseSpanProcessor } from '@langfuse/otel';\nimport {\n createObservationAttributes,\n createTraceAttributes,\n} from '@langfuse/tracing';\nimport { BaseCallbackHandler } from '@langchain/core/callbacks/base';\nimport { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport type { Serialized } from '@langchain/core/load/serializable';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport type { LLMResult } from '@langchain/core/outputs';\nimport type { Span } from '@opentelemetry/api';\nimport type * as t from '@/types';\nimport { isPresent } from '@/utils/misc';\n\ntype TraceMetadata = Record<string, unknown>;\n\ntype LangfuseHandlerParams = {\n userId?: string;\n sessionId?: string;\n traceMetadata?: TraceMetadata;\n};\n\ntype AgentLangfuseHandlerParams = LangfuseHandlerParams & {\n langfuse?: t.LangfuseConfig;\n};\n\ntype ResolvedLangfuseConfig = t.LangfuseConfig & {\n enabled: true;\n publicKey: string;\n secretKey: string;\n};\n\nfunction getModelName(serialized: Serialized): string {\n const serializedRecord = serialized as unknown as Record<string, unknown>;\n const kwargs = serializedRecord.kwargs as Record<string, unknown> | undefined;\n const modelName =\n kwargs?.model ??\n kwargs?.model_name ??\n kwargs?.modelName ??\n kwargs?.model_id ??\n kwargs?.modelId ??\n serializedRecord.name;\n\n if (typeof modelName === 'string' && modelName.trim() !== '') {\n return modelName;\n }\n\n if (Array.isArray(serializedRecord.id) && serializedRecord.id.length > 0) {\n return String(serializedRecord.id[serializedRecord.id.length - 1]);\n }\n\n return 'ChatModel';\n}\n\nfunction getModelParameters(\n extraParams?: Record<string, unknown>\n): Record<string, string | number> {\n const invocationParams = extraParams?.invocation_params;\n const params =\n invocationParams != null && typeof invocationParams === 'object'\n ? (invocationParams as Record<string, unknown>)\n : (extraParams ?? {});\n\n return Object.fromEntries(\n Object.entries(params).filter(([, value]) => {\n return typeof value === 'string' || typeof value === 'number';\n })\n ) as Record<string, string | number>;\n}\n\nfunction getOutput(output: LLMResult): unknown {\n return output.generations.map((generation) =>\n generation.map((item) => {\n if ('message' in item && item.message != null) {\n return (item.message as { content?: unknown }).content;\n }\n return item.text;\n })\n );\n}\n\nfunction getUsageDetails(\n output: LLMResult\n): Record<string, number> | undefined {\n const llmOutput = output.llmOutput as Record<string, unknown> | undefined;\n const usage = llmOutput?.tokenUsage ?? llmOutput?.usage;\n if (usage == null || typeof usage !== 'object') {\n return undefined;\n }\n\n const usageEntries = Object.entries(usage as Record<string, unknown>).filter(\n ([, value]) => typeof value === 'number'\n );\n\n return usageEntries.length > 0\n ? (Object.fromEntries(usageEntries) as Record<string, number>)\n : undefined;\n}\n\nfunction getTraceName(traceMetadata?: TraceMetadata): string {\n const agentName = traceMetadata?.agentName;\n return typeof agentName === 'string' && agentName.trim() !== ''\n ? `LibreChat Agent: ${agentName}`\n : 'LibreChat Agent';\n}\n\nexport class LangfuseAgentCallbackHandler extends BaseCallbackHandler {\n name = 'librechat_langfuse_agent_handler';\n\n private readonly provider: BasicTracerProvider;\n private readonly processor: LangfuseSpanProcessor;\n private readonly userId?: string;\n private readonly sessionId?: string;\n private readonly traceMetadata?: TraceMetadata;\n private readonly spans = new Map<string, Span>();\n\n constructor({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n }: LangfuseHandlerParams & { langfuse: ResolvedLangfuseConfig }) {\n super();\n this.userId = userId;\n this.sessionId = sessionId;\n this.traceMetadata = traceMetadata;\n this.processor = new LangfuseSpanProcessor({\n publicKey: langfuse.publicKey,\n secretKey: langfuse.secretKey,\n ...(isPresent(langfuse.baseUrl) ? { baseUrl: langfuse.baseUrl } : {}),\n environment:\n process.env.LANGFUSE_TRACING_ENVIRONMENT ??\n process.env.NODE_ENV ??\n 'development',\n exportMode: 'immediate',\n });\n this.provider = new BasicTracerProvider({\n spanProcessors: [this.processor],\n });\n }\n\n private startGenerationSpan({\n llm,\n input,\n runId,\n extraParams,\n metadata,\n name,\n }: {\n llm: Serialized;\n input: unknown;\n runId: string;\n extraParams?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n name?: string;\n }): void {\n if (this.spans.has(runId)) {\n return;\n }\n\n const tracer = this.provider.getTracer('librechat-agents-langfuse');\n const spanName =\n typeof name === 'string' && name.trim() !== '' ? name : getModelName(llm);\n const span = tracer.startSpan(spanName, {\n attributes: {\n ...createTraceAttributes({\n name: getTraceName(this.traceMetadata),\n userId: this.userId,\n sessionId: this.sessionId,\n metadata: this.traceMetadata,\n }),\n ...createObservationAttributes('generation', {\n input,\n model: getModelName(llm),\n modelParameters: getModelParameters(extraParams),\n metadata: {\n ...metadata,\n ...this.traceMetadata,\n },\n }),\n },\n });\n this.spans.set(runId, span);\n }\n\n async handleChatModelStart(\n llm: Serialized,\n messages: BaseMessage[][],\n runId: string,\n _parentRunId?: string,\n extraParams?: Record<string, unknown>,\n _tags?: string[],\n metadata?: Record<string, unknown>,\n name?: string\n ): Promise<void> {\n this.startGenerationSpan({\n llm,\n input: messages,\n runId,\n extraParams,\n metadata,\n name,\n });\n }\n\n async handleLLMStart(\n llm: Serialized,\n prompts: string[],\n runId: string,\n _parentRunId?: string,\n extraParams?: Record<string, unknown>,\n _tags?: string[],\n metadata?: Record<string, unknown>,\n name?: string\n ): Promise<void> {\n this.startGenerationSpan({\n llm,\n input: prompts,\n runId,\n extraParams,\n metadata,\n name,\n });\n }\n\n async handleLLMEnd(output: LLMResult, runId: string): Promise<void> {\n const span = this.spans.get(runId);\n if (!span) {\n return;\n }\n\n span.setAttributes(\n createObservationAttributes('generation', {\n output: getOutput(output),\n usageDetails: getUsageDetails(output),\n })\n );\n span.end();\n this.spans.delete(runId);\n await this.flush();\n }\n\n async handleLLMError(err: unknown, runId: string): Promise<void> {\n const span = this.spans.get(runId);\n if (!span) {\n return;\n }\n\n const message = err instanceof Error ? err.message : String(err);\n span.setStatus({ code: SpanStatusCode.ERROR, message });\n span.setAttributes(\n createObservationAttributes('generation', {\n level: 'ERROR',\n statusMessage: message,\n })\n );\n span.end();\n this.spans.delete(runId);\n await this.flush();\n }\n\n private async flush(): Promise<void> {\n try {\n await this.provider.forceFlush();\n } catch (error) {\n process.emitWarning(\n `[LangfuseAgentCallbackHandler] Failed to flush Langfuse spans: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n async dispose(): Promise<void> {\n for (const span of this.spans.values()) {\n span.end();\n }\n this.spans.clear();\n await this.flush();\n try {\n await this.provider.shutdown();\n } catch (error) {\n process.emitWarning(\n `[LangfuseAgentCallbackHandler] Failed to shut down Langfuse provider: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n}\n\nfunction hasRequiredLangfuseConfig(\n langfuse?: t.LangfuseConfig\n): langfuse is ResolvedLangfuseConfig {\n return (\n langfuse?.enabled === true &&\n isPresent(langfuse.publicKey) &&\n isPresent(langfuse.secretKey)\n );\n}\n\nexport function createLegacyLangfuseHandler(\n params: LangfuseHandlerParams\n): CallbackHandler {\n return new CallbackHandler(params);\n}\n\nexport function createLangfuseHandler({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n}: AgentLangfuseHandlerParams): LangfuseAgentCallbackHandler | undefined {\n if (!hasRequiredLangfuseConfig(langfuse)) {\n return undefined;\n }\n\n return new LangfuseAgentCallbackHandler({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n });\n}\n\nexport function hasExplicitLangfuseConfig(\n contexts: Iterable<{ langfuse?: t.LangfuseConfig }>\n): boolean {\n for (const context of contexts) {\n if (context.langfuse != null) {\n return true;\n }\n }\n return false;\n}\n\nexport function hasLangfuseEnvConfig(): boolean {\n return (\n isPresent(process.env.LANGFUSE_SECRET_KEY) &&\n isPresent(process.env.LANGFUSE_PUBLIC_KEY) &&\n isPresent(process.env.LANGFUSE_BASE_URL)\n );\n}\n\nexport function isLangfuseCallbackHandler(value: unknown): boolean {\n return (\n value instanceof CallbackHandler ||\n value instanceof LangfuseAgentCallbackHandler\n );\n}\n\nexport async function disposeLangfuseHandler(value: unknown): Promise<void> {\n if (value instanceof LangfuseAgentCallbackHandler) {\n await value.dispose();\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"langfuse.mjs","sources":["../../src/langfuse.ts"],"sourcesContent":["import { CallbackHandler } from '@langfuse/langchain';\nimport { isDefaultExportSpan, LangfuseSpanProcessor } from '@langfuse/otel';\nimport {\n LangfuseOtelSpanAttributes,\n createObservationAttributes,\n} from '@langfuse/tracing';\nimport { BaseCallbackHandler } from '@langchain/core/callbacks/base';\nimport { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport type { Serialized } from '@langchain/core/load/serializable';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport type { LLMResult } from '@langchain/core/outputs';\nimport type { Attributes, Span } from '@opentelemetry/api';\nimport type * as t from '@/types';\nimport { isPresent } from '@/utils/misc';\n\nconst TRACE_METADATA_MAX_LENGTH = 200;\nconst LANGFUSE_TRACER_NAME = 'langfuse-sdk';\n\nexport type LangfuseTraceMetadata = Record<string, string>;\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 ResolvedLangfuseConfig = t.LangfuseConfig & {\n enabled: true;\n publicKey: string;\n secretKey: string;\n};\n\nfunction getEnvLangfuseBaseUrl(): string | undefined {\n return process.env.LANGFUSE_BASE_URL ?? process.env.LANGFUSE_BASEURL;\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 getModelName(serialized: Serialized): string {\n const serializedRecord = serialized as unknown as Record<string, unknown>;\n const kwargs = serializedRecord.kwargs as Record<string, unknown> | undefined;\n const modelName =\n kwargs?.model ??\n kwargs?.model_name ??\n kwargs?.modelName ??\n kwargs?.model_id ??\n kwargs?.modelId ??\n serializedRecord.name;\n\n if (typeof modelName === 'string' && modelName.trim() !== '') {\n return modelName;\n }\n\n if (Array.isArray(serializedRecord.id) && serializedRecord.id.length > 0) {\n return String(serializedRecord.id[serializedRecord.id.length - 1]);\n }\n\n return 'ChatModel';\n}\n\nfunction getModelParameters(\n extraParams?: Record<string, unknown>\n): Record<string, string | number> {\n const invocationParams = extraParams?.invocation_params;\n const params =\n invocationParams != null && typeof invocationParams === 'object'\n ? (invocationParams as Record<string, unknown>)\n : (extraParams ?? {});\n\n return Object.fromEntries(\n Object.entries(params).filter(([, value]) => {\n return typeof value === 'string' || typeof value === 'number';\n })\n ) as Record<string, string | number>;\n}\n\nfunction getOutput(output: LLMResult): unknown {\n return output.generations.map((generation) =>\n generation.map((item) => {\n if ('message' in item && item.message != null) {\n return (item.message as { content?: unknown }).content;\n }\n return item.text;\n })\n );\n}\n\nfunction getUsageDetails(\n output: LLMResult\n): Record<string, number> | undefined {\n const llmOutput = output.llmOutput as Record<string, unknown> | undefined;\n const usage = llmOutput?.tokenUsage ?? llmOutput?.usage;\n if (usage == null || typeof usage !== 'object') {\n return undefined;\n }\n\n const usageEntries = Object.entries(usage as Record<string, unknown>).filter(\n ([, value]) => typeof value === 'number'\n );\n\n return usageEntries.length > 0\n ? (Object.fromEntries(usageEntries) as Record<string, number>)\n : undefined;\n}\n\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\nfunction getTraceAttributes({\n userId,\n sessionId,\n traceMetadata,\n tags,\n}: LangfuseHandlerParams): Attributes {\n const attributes: Attributes = {\n [LangfuseOtelSpanAttributes.TRACE_NAME]:\n getLangfuseTraceName(traceMetadata),\n };\n\n if (isPresent(userId)) {\n attributes[LangfuseOtelSpanAttributes.TRACE_USER_ID] = userId;\n }\n if (isPresent(sessionId)) {\n attributes[LangfuseOtelSpanAttributes.TRACE_SESSION_ID] = sessionId;\n }\n if (tags != null && tags.length > 0) {\n attributes[LangfuseOtelSpanAttributes.TRACE_TAGS] = tags;\n }\n for (const [key, value] of Object.entries(traceMetadata ?? {})) {\n attributes[`${LangfuseOtelSpanAttributes.TRACE_METADATA}.${key}`] = value;\n }\n\n return attributes;\n}\n\nexport class LangfuseAgentCallbackHandler extends BaseCallbackHandler {\n name = 'librechat_langfuse_agent_handler';\n\n private readonly provider: BasicTracerProvider;\n private readonly processor: LangfuseSpanProcessor;\n private readonly userId?: string;\n private readonly sessionId?: string;\n private readonly traceMetadata?: LangfuseTraceMetadata;\n private readonly tags?: string[];\n private readonly spans = new Map<string, Span>();\n\n constructor({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n tags,\n }: LangfuseHandlerParams & { langfuse: ResolvedLangfuseConfig }) {\n super();\n this.userId = userId;\n this.sessionId = sessionId;\n this.traceMetadata = traceMetadata;\n this.tags = tags;\n this.processor = new LangfuseSpanProcessor({\n publicKey: langfuse.publicKey,\n secretKey: langfuse.secretKey,\n ...(isPresent(langfuse.baseUrl) ? { baseUrl: langfuse.baseUrl } : {}),\n environment:\n process.env.LANGFUSE_TRACING_ENVIRONMENT ??\n process.env.NODE_ENV ??\n 'development',\n exportMode: 'immediate',\n shouldExportSpan: ({ otelSpan }): boolean =>\n isDefaultExportSpan(otelSpan) ||\n otelSpan.instrumentationScope.name === LANGFUSE_TRACER_NAME,\n });\n this.provider = new BasicTracerProvider({\n spanProcessors: [this.processor],\n });\n }\n\n private startGenerationSpan({\n llm,\n input,\n runId,\n extraParams,\n metadata,\n name,\n }: {\n llm: Serialized;\n input: unknown;\n runId: string;\n extraParams?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n name?: string;\n }): void {\n if (this.spans.has(runId)) {\n return;\n }\n\n const tracer = this.provider.getTracer(LANGFUSE_TRACER_NAME);\n const spanName =\n typeof name === 'string' && name.trim() !== '' ? name : getModelName(llm);\n const span = tracer.startSpan(spanName, {\n attributes: {\n ...getTraceAttributes({\n userId: this.userId,\n sessionId: this.sessionId,\n traceMetadata: this.traceMetadata,\n tags: this.tags,\n }),\n ...createObservationAttributes('generation', {\n input,\n model: getModelName(llm),\n modelParameters: getModelParameters(extraParams),\n metadata: {\n ...metadata,\n ...this.traceMetadata,\n },\n }),\n },\n });\n this.spans.set(runId, span);\n }\n\n async handleChatModelStart(\n llm: Serialized,\n messages: BaseMessage[][],\n runId: string,\n _parentRunId?: string,\n extraParams?: Record<string, unknown>,\n _tags?: string[],\n metadata?: Record<string, unknown>,\n name?: string\n ): Promise<void> {\n this.startGenerationSpan({\n llm,\n input: messages,\n runId,\n extraParams,\n metadata,\n name,\n });\n }\n\n async handleLLMStart(\n llm: Serialized,\n prompts: string[],\n runId: string,\n _parentRunId?: string,\n extraParams?: Record<string, unknown>,\n _tags?: string[],\n metadata?: Record<string, unknown>,\n name?: string\n ): Promise<void> {\n this.startGenerationSpan({\n llm,\n input: prompts,\n runId,\n extraParams,\n metadata,\n name,\n });\n }\n\n async handleLLMEnd(output: LLMResult, runId: string): Promise<void> {\n const span = this.spans.get(runId);\n if (!span) {\n return;\n }\n\n span.setAttributes(\n createObservationAttributes('generation', {\n output: getOutput(output),\n usageDetails: getUsageDetails(output),\n })\n );\n span.end();\n this.spans.delete(runId);\n await this.flush();\n }\n\n async handleLLMError(err: unknown, runId: string): Promise<void> {\n const span = this.spans.get(runId);\n if (!span) {\n return;\n }\n\n const message = err instanceof Error ? err.message : String(err);\n span.setStatus({ code: SpanStatusCode.ERROR, message });\n span.setAttributes(\n createObservationAttributes('generation', {\n level: 'ERROR',\n statusMessage: message,\n })\n );\n span.end();\n this.spans.delete(runId);\n await this.flush();\n }\n\n private async flush(): Promise<void> {\n try {\n await this.provider.forceFlush();\n } catch (error) {\n process.emitWarning(\n `[LangfuseAgentCallbackHandler] Failed to flush Langfuse spans: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n async dispose(): Promise<void> {\n for (const span of this.spans.values()) {\n span.end();\n }\n this.spans.clear();\n await this.flush();\n try {\n await this.provider.shutdown();\n } catch (error) {\n process.emitWarning(\n `[LangfuseAgentCallbackHandler] Failed to shut down Langfuse provider: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n}\n\nfunction hasRequiredLangfuseConfig(\n langfuse?: t.LangfuseConfig\n): langfuse is ResolvedLangfuseConfig {\n return (\n langfuse?.enabled === true &&\n isPresent(langfuse.publicKey) &&\n isPresent(langfuse.secretKey)\n );\n}\n\nexport function createLegacyLangfuseHandler(\n params: LangfuseHandlerParams\n): CallbackHandler {\n return new CallbackHandler(params);\n}\n\nexport function createLangfuseHandler({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n tags,\n}: AgentLangfuseHandlerParams): LangfuseAgentCallbackHandler | undefined {\n if (!hasRequiredLangfuseConfig(langfuse)) {\n return undefined;\n }\n\n return new LangfuseAgentCallbackHandler({\n langfuse,\n userId,\n sessionId,\n traceMetadata,\n tags,\n });\n}\n\nexport function hasExplicitLangfuseConfig(\n contexts: Iterable<{ langfuse?: t.LangfuseConfig }>\n): boolean {\n for (const context of contexts) {\n if (context.langfuse != null) {\n return true;\n }\n }\n return false;\n}\n\nexport function hasLangfuseEnvConfig(): boolean {\n return (\n isPresent(process.env.LANGFUSE_SECRET_KEY) &&\n isPresent(process.env.LANGFUSE_PUBLIC_KEY) &&\n isPresent(getEnvLangfuseBaseUrl())\n );\n}\n\nexport function isLangfuseCallbackHandler(value: unknown): boolean {\n return (\n value instanceof CallbackHandler ||\n value instanceof LangfuseAgentCallbackHandler\n );\n}\n\nexport async function disposeLangfuseHandler(value: unknown): Promise<void> {\n if (value instanceof LangfuseAgentCallbackHandler) {\n await value.dispose();\n }\n}\n"],"names":[],"mappings":"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"}
package/dist/esm/run.mjs CHANGED
@@ -15,7 +15,8 @@ import { HandlerRegistry } from './events.mjs';
15
15
  import { executeHooks } from './hooks/executeHooks.mjs';
16
16
  import './hooks/createWorkspacePolicyHook.mjs';
17
17
  import { isOpenAILike } from './utils/llm.mjs';
18
- import { hasLangfuseEnvConfig, hasExplicitLangfuseConfig, createLegacyLangfuseHandler, createLangfuseHandler, isLangfuseCallbackHandler, disposeLangfuseHandler } from './langfuse.mjs';
18
+ import { appendCallbacks, findCallback } from './utils/callbacks.mjs';
19
+ import { hasLangfuseEnvConfig, hasExplicitLangfuseConfig, createLangfuseTraceMetadata, createLegacyLangfuseHandler, getLangfuseTraceName, createLangfuseHandler, isLangfuseCallbackHandler, disposeLangfuseHandler } from './langfuse.mjs';
19
20
 
20
21
  // src/run.ts
21
22
  const defaultOmitOptions = new Set([
@@ -460,33 +461,36 @@ class Run {
460
461
  this.hookRegistry?.clearHaltSignal(this.id);
461
462
  /** Custom event callback to intercept and handle custom events */
462
463
  const customEventCallback = this.createCustomEventCallback();
463
- const baseCallbacks = config.callbacks ?? [];
464
464
  const streamCallbacks = streamOptions?.callbacks
465
465
  ? this.getCallbacks(streamOptions.callbacks)
466
- : [];
466
+ : undefined;
467
467
  const customHandler = BaseCallbackHandler.fromMethods({
468
468
  [Callback.CUSTOM_EVENT]: customEventCallback,
469
469
  });
470
470
  customHandler.awaitHandlers = true;
471
- config.callbacks = baseCallbacks
472
- .concat(streamCallbacks)
473
- .concat(customHandler);
471
+ config.callbacks = appendCallbacks(config.callbacks, streamCallbacks ? [streamCallbacks, customHandler] : [customHandler]);
474
472
  if (hasLangfuseEnvConfig() &&
475
473
  !hasExplicitLangfuseConfig(this.Graph.agentContexts.values())) {
476
- const userId = config.configurable?.user_id;
477
- const sessionId = config.configurable?.thread_id;
474
+ const userId = typeof config.configurable?.user_id === 'string'
475
+ ? config.configurable.user_id
476
+ : undefined;
477
+ const sessionId = typeof config.configurable?.thread_id === 'string'
478
+ ? config.configurable.thread_id
479
+ : undefined;
478
480
  const primaryContext = this.Graph.agentContexts.get(this.Graph.defaultAgentId);
479
- const traceMetadata = {
481
+ const traceMetadata = createLangfuseTraceMetadata({
480
482
  messageId: this.id,
481
483
  parentMessageId: config.configurable?.requestBody?.parentMessageId,
482
484
  agentName: primaryContext?.name,
483
- };
485
+ });
484
486
  const handler = createLegacyLangfuseHandler({
485
487
  userId,
486
488
  sessionId,
487
489
  traceMetadata,
490
+ tags: ['librechat', 'agent'],
488
491
  });
489
- config.callbacks = (config.callbacks ?? []).concat([handler]);
492
+ config.runName = config.runName ?? getLangfuseTraceName(traceMetadata);
493
+ config.callbacks = appendCallbacks(config.callbacks, [handler]);
490
494
  }
491
495
  if (!this.id) {
492
496
  throw new Error('Run ID not provided');
@@ -886,14 +890,21 @@ class Run {
886
890
  }
887
891
  async generateTitle({ provider, inputText, contentParts, titlePrompt, clientOptions, chainOptions, skipLanguage, titleMethod = TitleMethod.COMPLETION, titlePromptTemplate, }) {
888
892
  let titleLangfuseHandler;
893
+ const titleContext = this.Graph == null
894
+ ? undefined
895
+ : this.Graph.agentContexts.get(this.Graph.defaultAgentId);
896
+ const traceMetadata = createLangfuseTraceMetadata({
897
+ messageId: 'title-' + this.id,
898
+ agentName: titleContext?.name,
899
+ });
900
+ const titleRunName = getLangfuseTraceName(traceMetadata, 'LibreChat Title');
889
901
  if (chainOptions != null) {
890
- const userId = chainOptions.configurable?.user_id;
891
- const sessionId = chainOptions.configurable?.thread_id;
892
- const titleContext = this.Graph?.agentContexts.get(this.Graph.defaultAgentId);
893
- const traceMetadata = {
894
- messageId: 'title-' + this.id,
895
- agentName: titleContext?.name,
896
- };
902
+ const userId = typeof chainOptions.configurable?.user_id === 'string'
903
+ ? chainOptions.configurable.user_id
904
+ : undefined;
905
+ const sessionId = typeof chainOptions.configurable?.thread_id === 'string'
906
+ ? chainOptions.configurable.thread_id
907
+ : undefined;
897
908
  const hasExplicitLangfuse = this.Graph != null &&
898
909
  hasExplicitLangfuseConfig(this.Graph.agentContexts.values());
899
910
  if (titleContext?.langfuse != null) {
@@ -902,6 +913,7 @@ class Run {
902
913
  userId,
903
914
  sessionId,
904
915
  traceMetadata,
916
+ tags: ['librechat', 'title'],
905
917
  });
906
918
  }
907
919
  else if (hasLangfuseEnvConfig() && !hasExplicitLangfuse) {
@@ -909,10 +921,11 @@ class Run {
909
921
  userId,
910
922
  sessionId,
911
923
  traceMetadata,
924
+ tags: ['librechat', 'title'],
912
925
  });
913
926
  }
914
927
  if (titleLangfuseHandler != null) {
915
- chainOptions.callbacks = (chainOptions.callbacks ?? []).concat([
928
+ chainOptions.callbacks = appendCallbacks(chainOptions.callbacks, [
916
929
  titleLangfuseHandler,
917
930
  ]);
918
931
  }
@@ -959,6 +972,7 @@ class Run {
959
972
  const invokeConfig = Object.assign({}, chainOptions, {
960
973
  run_id: this.id,
961
974
  runId: this.id,
975
+ runName: chainOptions?.runName ?? titleRunName,
962
976
  });
963
977
  try {
964
978
  try {
@@ -967,7 +981,7 @@ class Run {
967
981
  catch (_e) {
968
982
  // Fallback: strip callbacks to avoid EventStream tracer errors in certain environments
969
983
  // but preserve Langfuse tracing if it exists.
970
- const langfuseHandler = invokeConfig.callbacks?.find(isLangfuseCallbackHandler);
984
+ const langfuseHandler = findCallback(invokeConfig.callbacks, isLangfuseCallbackHandler);
971
985
  const { callbacks: _cb, ...rest } = invokeConfig;
972
986
  const safeConfig = Object.assign({}, rest, {
973
987
  callbacks: langfuseHandler ? [langfuseHandler] : [],