@librechat/agents 3.1.97 → 3.1.99

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 (49) hide show
  1. package/dist/cjs/graphs/Graph.cjs +6 -0
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/langfuseToolOutputTracing.cjs +16 -5
  4. package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
  5. package/dist/cjs/llm/bedrock/index.cjs +10 -0
  6. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  7. package/dist/cjs/llm/bedrock/toolCache.cjs +125 -0
  8. package/dist/cjs/llm/bedrock/toolCache.cjs.map +1 -0
  9. package/dist/cjs/messages/cache.cjs +17 -9
  10. package/dist/cjs/messages/cache.cjs.map +1 -1
  11. package/dist/cjs/messages/prune.cjs +45 -8
  12. package/dist/cjs/messages/prune.cjs.map +1 -1
  13. package/dist/cjs/tools/ToolNode.cjs +6 -1
  14. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  15. package/dist/esm/graphs/Graph.mjs +6 -0
  16. package/dist/esm/graphs/Graph.mjs.map +1 -1
  17. package/dist/esm/langfuseToolOutputTracing.mjs +16 -5
  18. package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
  19. package/dist/esm/llm/bedrock/index.mjs +10 -0
  20. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  21. package/dist/esm/llm/bedrock/toolCache.mjs +122 -0
  22. package/dist/esm/llm/bedrock/toolCache.mjs.map +1 -0
  23. package/dist/esm/messages/cache.mjs +17 -9
  24. package/dist/esm/messages/cache.mjs.map +1 -1
  25. package/dist/esm/messages/prune.mjs +45 -8
  26. package/dist/esm/messages/prune.mjs.map +1 -1
  27. package/dist/esm/tools/ToolNode.mjs +6 -1
  28. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  29. package/dist/types/llm/bedrock/index.d.ts +16 -0
  30. package/dist/types/llm/bedrock/toolCache.d.ts +4 -0
  31. package/dist/types/messages/cache.d.ts +2 -2
  32. package/dist/types/types/llm.d.ts +2 -2
  33. package/package.json +1 -1
  34. package/src/agents/__tests__/AgentContext.anthropic.live.test.ts +332 -0
  35. package/src/agents/__tests__/AgentContext.bedrock.live.test.ts +504 -0
  36. package/src/graphs/Graph.ts +14 -0
  37. package/src/langfuseToolOutputTracing.ts +26 -7
  38. package/src/llm/bedrock/index.ts +32 -1
  39. package/src/llm/bedrock/llm.spec.ts +154 -1
  40. package/src/llm/bedrock/toolCache.test.ts +131 -0
  41. package/src/llm/bedrock/toolCache.ts +191 -0
  42. package/src/messages/cache.test.ts +97 -38
  43. package/src/messages/cache.ts +18 -10
  44. package/src/messages/prune.ts +55 -17
  45. package/src/specs/langfuse-tool-output-tracing.test.ts +28 -0
  46. package/src/specs/prune.test.ts +193 -0
  47. package/src/tools/ToolNode.ts +7 -1
  48. package/src/tools/__tests__/ToolNode.langfuse.test.ts +6 -0
  49. package/src/types/llm.ts +2 -2
@@ -8,6 +8,7 @@ const langfuseToolOutputTracingConfigKey = createContextKey('librechat.langfuse.
8
8
  const langfuseConfigKey = createContextKey('librechat.langfuse.config');
9
9
  const toolOutputTracingStorage = new AsyncLocalStorage();
10
10
  const langfuseConfigStorage = new AsyncLocalStorage();
11
+ const LANGGRAPH_TOOL_NODE_PREFIX = 'tools=';
11
12
  const CHAT_ROLES = new Set([
12
13
  'assistant',
13
14
  'developer',
@@ -299,6 +300,17 @@ function isToolObservation(attributes) {
299
300
  const type = attributes[LangfuseOtelSpanAttributes.OBSERVATION_TYPE];
300
301
  return typeof type === 'string' && type.toLowerCase() === 'tool';
301
302
  }
303
+ function classifyLangGraphToolNodeSpan(attributes) {
304
+ const type = attributes[LangfuseOtelSpanAttributes.OBSERVATION_TYPE];
305
+ if (typeof type !== 'string' || type.toLowerCase() !== 'span') {
306
+ return;
307
+ }
308
+ const langGraphNode = attributes[`${LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.langgraph_node`];
309
+ if (typeof langGraphNode === 'string' &&
310
+ langGraphNode.startsWith(LANGGRAPH_TOOL_NODE_PREFIX)) {
311
+ attributes[LangfuseOtelSpanAttributes.OBSERVATION_TYPE] = 'tool';
312
+ }
313
+ }
302
314
  function redactToolObservationOutput(span, attributes, config) {
303
315
  if (!(isToolObservation(attributes) &&
304
316
  shouldRedactTool(span.name, config) &&
@@ -309,10 +321,11 @@ function redactToolObservationOutput(span, attributes, config) {
309
321
  config.redactionText;
310
322
  }
311
323
  function redactLangfuseSpanToolOutputs(span, config) {
324
+ const attributes = span.attributes;
325
+ classifyLangGraphToolNodeSpan(attributes);
312
326
  if (!shouldApplyToolOutputRedaction(config)) {
313
327
  return;
314
328
  }
315
- const attributes = span.attributes;
316
329
  redactToolObservationOutput(span, attributes, config);
317
330
  for (const key of [
318
331
  LangfuseOtelSpanAttributes.OBSERVATION_INPUT,
@@ -410,8 +423,7 @@ function hasLangfuseConfigKeys(langfuse) {
410
423
  if (langfuse == null) {
411
424
  return false;
412
425
  }
413
- return (isPresent(langfuse.secretKey) &&
414
- isPresent(langfuse.publicKey));
426
+ return isPresent(langfuse.secretKey) && isPresent(langfuse.publicKey);
415
427
  }
416
428
  function shouldTraceToolNodeForLangfuse({ runLangfuse, agentLangfuse, }) {
417
429
  const langfuse = resolveLangfuseConfig(runLangfuse, agentLangfuse);
@@ -420,8 +432,7 @@ function shouldTraceToolNodeForLangfuse({ runLangfuse, agentLangfuse, }) {
420
432
  }
421
433
  const explicit = langfuse?.toolNodeTracing?.enabled;
422
434
  if (explicit != null) {
423
- return (explicit &&
424
- (hasLangfuseConfigKeys(langfuse) || hasLangfuseEnvKeys()));
435
+ return (explicit && (hasLangfuseConfigKeys(langfuse) || hasLangfuseEnvKeys()));
425
436
  }
426
437
  return hasLangfuseConfigKeys(langfuse) || hasLangfuseEnvKeys();
427
438
  }
@@ -1 +1 @@
1
- {"version":3,"file":"langfuseToolOutputTracing.mjs","sources":["../../src/langfuseToolOutputTracing.ts"],"sourcesContent":["import { context, createContextKey } from '@opentelemetry/api';\nimport { LangfuseSpanProcessor } from '@langfuse/otel';\nimport { LangfuseOtelSpanAttributes } from '@langfuse/tracing';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport type {\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';\n\nexport const LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT = '[tool output redacted]';\n\nconst langfuseToolOutputTracingConfigKey = createContextKey(\n 'librechat.langfuse.tool-output-tracing'\n);\nconst langfuseConfigKey = createContextKey('librechat.langfuse.config');\nconst toolOutputTracingStorage =\n new AsyncLocalStorage<ResolvedLangfuseToolOutputTracingConfig>();\nconst langfuseConfigStorage = new AsyncLocalStorage<t.LangfuseConfig>();\n\nconst CHAT_ROLES = new Set([\n 'assistant',\n 'developer',\n 'human',\n 'system',\n 'user',\n]);\n\nexport type ResolvedLangfuseToolOutputTracingConfig = {\n enabled: boolean;\n redactedToolNames: Set<string>;\n redactedToolNameMatchMode: 'exact' | 'partial';\n redactionText: string;\n};\n\ntype SpanWithAttributes = ReadableSpan & {\n attributes: Record<string, unknown>;\n};\n\ntype RedactionResult = {\n value: unknown;\n changed: boolean;\n};\n\ntype RedactionContext = {\n toolNamesByCallId: Map<string, string>;\n};\n\nconst TOOL_OUTPUT_FIELD_KEYS = ['content', 'artifact'];\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isPresent(value: unknown): value is string {\n return typeof value === 'string' && value.trim() !== '';\n}\n\nfunction parseBoolean(value: string | undefined): boolean | undefined {\n if (value == null) {\n return undefined;\n }\n\n const normalized = value.trim().toLowerCase();\n if (['1', 'true', 'yes', 'on'].includes(normalized)) {\n return true;\n }\n if (['0', 'false', 'no', 'off'].includes(normalized)) {\n return false;\n }\n\n return undefined;\n}\n\nfunction 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 = parseBoolean(\n process.env.LANGFUSE_TRACE_TOOL_OUTPUTS\n );\n if (traceToolOutputs != null) {\n return traceToolOutputs;\n }\n\n const redactToolOutputs = parseBoolean(\n process.env.LANGFUSE_REDACT_TOOL_OUTPUTS\n );\n if (redactToolOutputs != null) {\n return !redactToolOutputs;\n }\n\n return parseBoolean(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 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:\n agentConfig?.enabled ??\n runConfig?.enabled ??\n getEnvToolOutputTracingEnabled() ??\n true,\n redactedToolNames: normalizeToolNames(\n agentConfig?.redactedToolNames ??\n runConfig?.redactedToolNames ??\n getEnvRedactedToolNames()\n ),\n redactedToolNameMatchMode:\n agentConfig?.redactedToolNameMatchMode ??\n runConfig?.redactedToolNameMatchMode ??\n getEnvToolNameMatchMode() ??\n 'exact',\n redactionText:\n agentConfig?.redactionText ??\n runConfig?.redactionText ??\n getEnvRedactionText() ??\n LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT,\n };\n}\n\nfunction shouldApplyToolOutputRedaction(\n config: ResolvedLangfuseToolOutputTracingConfig\n): boolean {\n return config.enabled === false || config.redactedToolNames.size > 0;\n}\n\nfunction toolNameMatches(\n toolName: string | undefined,\n config: ResolvedLangfuseToolOutputTracingConfig\n): boolean {\n if (!isPresent(toolName)) {\n return false;\n }\n\n const normalizedToolName = normalizeToolName(toolName);\n if (config.redactedToolNameMatchMode === 'partial') {\n for (const redactedToolName of config.redactedToolNames) {\n if (normalizedToolName.includes(redactedToolName)) {\n return true;\n }\n }\n return false;\n }\n\n return config.redactedToolNames.has(normalizedToolName);\n}\n\nfunction shouldRedactTool(\n toolName: string | undefined,\n config: ResolvedLangfuseToolOutputTracingConfig\n): boolean {\n return config.enabled === false || toolNameMatches(toolName, config);\n}\n\nfunction getStringField(\n value: Record<string, unknown>,\n key: string\n): string | undefined {\n const field = value[key];\n return typeof field === 'string' ? field : undefined;\n}\n\nfunction getNestedStringField(\n value: Record<string, unknown>,\n objectKey: string,\n fieldKey: string\n): string | undefined {\n const nested = value[objectKey];\n if (!isRecord(nested)) {\n return undefined;\n }\n return getStringField(nested, fieldKey);\n}\n\nfunction getSerializedToolCallId(\n value: Record<string, unknown>\n): string | undefined {\n return (\n getStringField(value, 'tool_call_id') ??\n getNestedStringField(value, 'kwargs', 'tool_call_id') ??\n getNestedStringField(value, 'additional_kwargs', 'tool_call_id') ??\n getNestedStringField(value, 'data', 'tool_call_id') ??\n (typeof value.id === 'string' ? value.id : undefined)\n );\n}\n\nfunction getSerializedToolName(\n value: Record<string, unknown>,\n redactionContext?: RedactionContext\n): string | undefined {\n const role = getStringField(value, 'role');\n const explicitName =\n getStringField(value, 'name') ??\n getStringField(value, 'tool_name') ??\n getNestedStringField(value, 'function', 'name') ??\n getNestedStringField(value, 'kwargs', 'name') ??\n getNestedStringField(value, 'additional_kwargs', 'name') ??\n getNestedStringField(value, 'data', 'name') ??\n (role != null && role.toLowerCase() !== 'tool' ? role : undefined);\n\n if (explicitName != null) {\n return explicitName;\n }\n\n const toolCallId = getSerializedToolCallId(value);\n return toolCallId != null\n ? redactionContext?.toolNamesByCallId.get(toolCallId)\n : undefined;\n}\n\nfunction hasToolMessageIdentity(value: Record<string, unknown>): boolean {\n const type = getStringField(value, 'type') ?? getStringField(value, '_type');\n if (type === 'tool' || type === 'tool_message') {\n return true;\n }\n\n const id = value.id;\n if (\n Array.isArray(id) &&\n id.some((part) => typeof part === 'string' && part.includes('ToolMessage'))\n ) {\n return true;\n }\n\n if (\n 'tool_call_id' in value ||\n getNestedStringField(value, 'kwargs', 'tool_call_id') != null ||\n getNestedStringField(value, 'additional_kwargs', 'tool_call_id') != null\n ) {\n return true;\n }\n\n const role = getStringField(value, 'role');\n return (\n role != null &&\n !CHAT_ROLES.has(role.toLowerCase()) &&\n ('content' in value || isRecord(value.kwargs) || isRecord(value.data))\n );\n}\n\nfunction redactToolContentFields(\n value: Record<string, unknown>,\n config: ResolvedLangfuseToolOutputTracingConfig\n): Record<string, unknown> {\n const next = { ...value };\n\n for (const outputKey of TOOL_OUTPUT_FIELD_KEYS) {\n if (outputKey in next) {\n next[outputKey] = config.redactionText;\n }\n }\n\n for (const nestedKey of ['kwargs', 'data', 'additional_kwargs']) {\n const nested = next[nestedKey];\n if (!isRecord(nested)) {\n continue;\n }\n const nextNested = { ...nested };\n let changed = false;\n for (const outputKey of TOOL_OUTPUT_FIELD_KEYS) {\n if (outputKey in nextNested) {\n nextNested[outputKey] = config.redactionText;\n changed = true;\n }\n }\n if (changed) {\n next[nestedKey] = nextNested;\n }\n }\n\n return next;\n}\n\nfunction collectToolCallNames(\n value: unknown,\n redactionContext: RedactionContext\n): void {\n if (Array.isArray(value)) {\n for (const item of value) {\n collectToolCallNames(item, redactionContext);\n }\n return;\n }\n\n if (!isRecord(value)) {\n return;\n }\n\n const toolCallId = getSerializedToolCallId(value);\n const toolName = getSerializedToolName(value);\n if (toolCallId != null && toolName != null) {\n redactionContext.toolNamesByCallId.set(toolCallId, toolName);\n }\n\n for (const child of Object.values(value)) {\n collectToolCallNames(child, redactionContext);\n }\n}\n\nfunction redactValue(\n value: unknown,\n config: ResolvedLangfuseToolOutputTracingConfig,\n redactionContext: RedactionContext\n): RedactionResult {\n if (Array.isArray(value)) {\n let changed = false;\n const next: unknown[] = [];\n for (const item of value) {\n const result = redactValue(item, config, redactionContext);\n if (result.changed) {\n changed = true;\n }\n next.push(result.value);\n }\n return changed ? { value: next, changed } : { value, changed };\n }\n\n if (!isRecord(value)) {\n return { value, changed: false };\n }\n\n const toolName = getSerializedToolName(value, redactionContext);\n if (hasToolMessageIdentity(value) && shouldRedactTool(toolName, config)) {\n return {\n value: redactToolContentFields(value, config),\n changed: true,\n };\n }\n\n let changed = false;\n const next: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n const result = redactValue(child, config, redactionContext);\n if (result.changed) {\n changed = true;\n }\n next[key] = result.value;\n }\n\n return changed ? { value: next, changed } : { value, changed };\n}\n\nfunction redactSerializedValue(\n value: unknown,\n config: ResolvedLangfuseToolOutputTracingConfig\n): RedactionResult {\n const redactionContext: RedactionContext = {\n toolNamesByCallId: new Map(),\n };\n if (typeof value !== 'string') {\n collectToolCallNames(value, redactionContext);\n return redactValue(value, config, redactionContext);\n }\n\n const trimmed = value.trim();\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {\n return { value, changed: false };\n }\n\n try {\n const parsed = JSON.parse(value) as unknown;\n collectToolCallNames(parsed, redactionContext);\n const result = redactValue(parsed, config, redactionContext);\n return result.changed\n ? { value: JSON.stringify(result.value), changed: true }\n : { value, changed: false };\n } catch {\n return { value, changed: false };\n }\n}\n\nfunction redactAttribute(\n attributes: Record<string, unknown>,\n key: string,\n config: ResolvedLangfuseToolOutputTracingConfig\n): void {\n if (!(key in attributes)) {\n return;\n }\n\n const result = redactSerializedValue(attributes[key], config);\n if (result.changed) {\n attributes[key] = result.value;\n }\n}\n\nfunction isToolObservation(attributes: Record<string, unknown>): boolean {\n const type = attributes[LangfuseOtelSpanAttributes.OBSERVATION_TYPE];\n return typeof type === 'string' && type.toLowerCase() === 'tool';\n}\n\nfunction redactToolObservationOutput(\n span: ReadableSpan,\n attributes: Record<string, unknown>,\n config: ResolvedLangfuseToolOutputTracingConfig\n): void {\n if (\n !(\n isToolObservation(attributes) &&\n shouldRedactTool(span.name, config) &&\n LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT in attributes\n )\n ) {\n return;\n }\n\n attributes[LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT] =\n config.redactionText;\n}\n\nexport function redactLangfuseSpanToolOutputs(\n span: ReadableSpan,\n config: ResolvedLangfuseToolOutputTracingConfig\n): void {\n if (!shouldApplyToolOutputRedaction(config)) {\n return;\n }\n\n const attributes = (span as SpanWithAttributes).attributes;\n redactToolObservationOutput(span, attributes, config);\n\n for (const key of [\n LangfuseOtelSpanAttributes.OBSERVATION_INPUT,\n LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT,\n LangfuseOtelSpanAttributes.TRACE_INPUT,\n LangfuseOtelSpanAttributes.TRACE_OUTPUT,\n ]) {\n redactAttribute(attributes, key, config);\n }\n}\n\nfunction getContextToolOutputTracingConfig(\n activeContext: Context\n): ResolvedLangfuseToolOutputTracingConfig | undefined {\n const asyncConfig = toolOutputTracingStorage.getStore();\n if (asyncConfig != null) {\n return asyncConfig;\n }\n\n const value = activeContext.getValue(langfuseToolOutputTracingConfigKey);\n return isRecord(value)\n ? (value as ResolvedLangfuseToolOutputTracingConfig)\n : undefined;\n}\n\nexport function getContextLangfuseConfig(\n activeContext: Context\n): t.LangfuseConfig | undefined {\n const asyncConfig = langfuseConfigStorage.getStore();\n if (asyncConfig != null) {\n return asyncConfig;\n }\n\n const value = activeContext.getValue(langfuseConfigKey);\n return isRecord(value) ? (value as t.LangfuseConfig) : undefined;\n}\n\nclass ToolOutputRedactingLangfuseSpanProcessor implements SpanProcessor {\n private readonly processor: LangfuseSpanProcessor;\n private readonly fallbackConfig?: ResolvedLangfuseToolOutputTracingConfig;\n private readonly spanConfigs = new WeakMap<\n object,\n ResolvedLangfuseToolOutputTracingConfig\n >();\n\n constructor(\n params?: LangfuseSpanProcessorParams,\n fallbackConfig?: ResolvedLangfuseToolOutputTracingConfig\n ) {\n this.processor = new LangfuseSpanProcessor(params);\n this.fallbackConfig = fallbackConfig;\n }\n\n onStart(span: Span, parentContext: Context): void {\n const config =\n getContextToolOutputTracingConfig(parentContext) ?? this.fallbackConfig;\n if (config != null) {\n this.spanConfigs.set(span, config);\n }\n this.processor.onStart(span, parentContext);\n }\n\n onEnd(span: ReadableSpan): void {\n const config =\n this.spanConfigs.get(span) ??\n toolOutputTracingStorage.getStore() ??\n this.fallbackConfig ??\n resolveToolOutputTracingConfig();\n redactLangfuseSpanToolOutputs(span, config);\n this.processor.onEnd(span);\n }\n\n forceFlush(): Promise<void> {\n return this.processor.forceFlush();\n }\n\n shutdown(): Promise<void> {\n return this.processor.shutdown();\n }\n}\n\nexport function createLangfuseSpanProcessor(\n params?: LangfuseSpanProcessorParams,\n runLangfuse?: t.LangfuseConfig,\n agentLangfuse?: t.LangfuseConfig\n): SpanProcessor {\n const fallbackConfig =\n runLangfuse != null || agentLangfuse != null\n ? resolveToolOutputTracingConfig(runLangfuse, agentLangfuse)\n : undefined;\n return new ToolOutputRedactingLangfuseSpanProcessor(params, fallbackConfig);\n}\n\nexport function withLangfuseToolOutputTracingConfig<T>(\n runLangfuse: t.LangfuseConfig | undefined,\n action: () => T,\n agentLangfuse?: t.LangfuseConfig\n): T {\n const langfuse = resolveLangfuseConfig(runLangfuse, agentLangfuse);\n const hasNoToolOutputConfig =\n runLangfuse?.toolOutputTracing == null &&\n agentLangfuse?.toolOutputTracing == null;\n\n if (langfuse == null && hasNoToolOutputConfig) {\n return action();\n }\n\n const config = hasNoToolOutputConfig\n ? undefined\n : resolveToolOutputTracingConfig(runLangfuse, agentLangfuse);\n let activeContext = context.active();\n if (langfuse != null) {\n activeContext = activeContext.setValue(langfuseConfigKey, langfuse);\n }\n if (config != null) {\n activeContext = activeContext.setValue(\n langfuseToolOutputTracingConfigKey,\n config\n );\n }\n\n const runWithContext = (): T => context.with(activeContext, action);\n const runWithToolOutputConfig = (): T =>\n config != null\n ? toolOutputTracingStorage.run(config, runWithContext)\n : runWithContext();\n\n return langfuse != null\n ? langfuseConfigStorage.run(langfuse, runWithToolOutputConfig)\n : runWithToolOutputConfig();\n}\n\nfunction hasLangfuseEnvKeys(): boolean {\n return (\n isPresent(process.env.LANGFUSE_SECRET_KEY) &&\n isPresent(process.env.LANGFUSE_PUBLIC_KEY)\n );\n}\n\nfunction hasLangfuseConfigKeys(langfuse?: t.LangfuseConfig): boolean {\n if (langfuse == null) {\n return false;\n }\n return (\n isPresent(langfuse.secretKey) &&\n isPresent(langfuse.publicKey)\n );\n}\n\nexport function shouldTraceToolNodeForLangfuse({\n runLangfuse,\n agentLangfuse,\n}: {\n runLangfuse?: t.LangfuseConfig;\n agentLangfuse?: t.LangfuseConfig;\n}): boolean {\n const langfuse = resolveLangfuseConfig(runLangfuse, agentLangfuse);\n if (langfuse?.enabled === false) {\n return false;\n }\n\n const explicit = langfuse?.toolNodeTracing?.enabled;\n if (explicit != null) {\n return (\n explicit &&\n (hasLangfuseConfigKeys(langfuse) || hasLangfuseEnvKeys())\n );\n }\n\n return hasLangfuseConfigKeys(langfuse) || hasLangfuseEnvKeys();\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\n return {\n ...runLangfuse,\n ...agentLangfuse,\n ...(toolNodeTracing != null ? { toolNodeTracing } : {}),\n ...(toolOutputTracing != null ? { toolOutputTracing } : {}),\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"langfuseToolOutputTracing.mjs","sources":["../../src/langfuseToolOutputTracing.ts"],"sourcesContent":["import { context, createContextKey } from '@opentelemetry/api';\nimport { LangfuseSpanProcessor } from '@langfuse/otel';\nimport { LangfuseOtelSpanAttributes } from '@langfuse/tracing';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport type {\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';\n\nexport const LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT = '[tool output redacted]';\n\nconst langfuseToolOutputTracingConfigKey = createContextKey(\n 'librechat.langfuse.tool-output-tracing'\n);\nconst langfuseConfigKey = createContextKey('librechat.langfuse.config');\nconst toolOutputTracingStorage =\n new AsyncLocalStorage<ResolvedLangfuseToolOutputTracingConfig>();\nconst langfuseConfigStorage = new AsyncLocalStorage<t.LangfuseConfig>();\nconst LANGGRAPH_TOOL_NODE_PREFIX = 'tools=';\n\nconst CHAT_ROLES = new Set([\n 'assistant',\n 'developer',\n 'human',\n 'system',\n 'user',\n]);\n\nexport type ResolvedLangfuseToolOutputTracingConfig = {\n enabled: boolean;\n redactedToolNames: Set<string>;\n redactedToolNameMatchMode: 'exact' | 'partial';\n redactionText: string;\n};\n\ntype SpanWithAttributes = ReadableSpan & {\n attributes: Record<string, unknown>;\n};\n\ntype RedactionResult = {\n value: unknown;\n changed: boolean;\n};\n\ntype RedactionContext = {\n toolNamesByCallId: Map<string, string>;\n};\n\nconst TOOL_OUTPUT_FIELD_KEYS = ['content', 'artifact'];\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isPresent(value: unknown): value is string {\n return typeof value === 'string' && value.trim() !== '';\n}\n\nfunction parseBoolean(value: string | undefined): boolean | undefined {\n if (value == null) {\n return undefined;\n }\n\n const normalized = value.trim().toLowerCase();\n if (['1', 'true', 'yes', 'on'].includes(normalized)) {\n return true;\n }\n if (['0', 'false', 'no', 'off'].includes(normalized)) {\n return false;\n }\n\n return undefined;\n}\n\nfunction 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 = parseBoolean(\n process.env.LANGFUSE_TRACE_TOOL_OUTPUTS\n );\n if (traceToolOutputs != null) {\n return traceToolOutputs;\n }\n\n const redactToolOutputs = parseBoolean(\n process.env.LANGFUSE_REDACT_TOOL_OUTPUTS\n );\n if (redactToolOutputs != null) {\n return !redactToolOutputs;\n }\n\n return parseBoolean(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 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:\n agentConfig?.enabled ??\n runConfig?.enabled ??\n getEnvToolOutputTracingEnabled() ??\n true,\n redactedToolNames: normalizeToolNames(\n agentConfig?.redactedToolNames ??\n runConfig?.redactedToolNames ??\n getEnvRedactedToolNames()\n ),\n redactedToolNameMatchMode:\n agentConfig?.redactedToolNameMatchMode ??\n runConfig?.redactedToolNameMatchMode ??\n getEnvToolNameMatchMode() ??\n 'exact',\n redactionText:\n agentConfig?.redactionText ??\n runConfig?.redactionText ??\n getEnvRedactionText() ??\n LANGFUSE_TOOL_OUTPUT_REDACTION_TEXT,\n };\n}\n\nfunction shouldApplyToolOutputRedaction(\n config: ResolvedLangfuseToolOutputTracingConfig\n): boolean {\n return config.enabled === false || config.redactedToolNames.size > 0;\n}\n\nfunction toolNameMatches(\n toolName: string | undefined,\n config: ResolvedLangfuseToolOutputTracingConfig\n): boolean {\n if (!isPresent(toolName)) {\n return false;\n }\n\n const normalizedToolName = normalizeToolName(toolName);\n if (config.redactedToolNameMatchMode === 'partial') {\n for (const redactedToolName of config.redactedToolNames) {\n if (normalizedToolName.includes(redactedToolName)) {\n return true;\n }\n }\n return false;\n }\n\n return config.redactedToolNames.has(normalizedToolName);\n}\n\nfunction shouldRedactTool(\n toolName: string | undefined,\n config: ResolvedLangfuseToolOutputTracingConfig\n): boolean {\n return config.enabled === false || toolNameMatches(toolName, config);\n}\n\nfunction getStringField(\n value: Record<string, unknown>,\n key: string\n): string | undefined {\n const field = value[key];\n return typeof field === 'string' ? field : undefined;\n}\n\nfunction getNestedStringField(\n value: Record<string, unknown>,\n objectKey: string,\n fieldKey: string\n): string | undefined {\n const nested = value[objectKey];\n if (!isRecord(nested)) {\n return undefined;\n }\n return getStringField(nested, fieldKey);\n}\n\nfunction getSerializedToolCallId(\n value: Record<string, unknown>\n): string | undefined {\n return (\n getStringField(value, 'tool_call_id') ??\n getNestedStringField(value, 'kwargs', 'tool_call_id') ??\n getNestedStringField(value, 'additional_kwargs', 'tool_call_id') ??\n getNestedStringField(value, 'data', 'tool_call_id') ??\n (typeof value.id === 'string' ? value.id : undefined)\n );\n}\n\nfunction getSerializedToolName(\n value: Record<string, unknown>,\n redactionContext?: RedactionContext\n): string | undefined {\n const role = getStringField(value, 'role');\n const explicitName =\n getStringField(value, 'name') ??\n getStringField(value, 'tool_name') ??\n getNestedStringField(value, 'function', 'name') ??\n getNestedStringField(value, 'kwargs', 'name') ??\n getNestedStringField(value, 'additional_kwargs', 'name') ??\n getNestedStringField(value, 'data', 'name') ??\n (role != null && role.toLowerCase() !== 'tool' ? role : undefined);\n\n if (explicitName != null) {\n return explicitName;\n }\n\n const toolCallId = getSerializedToolCallId(value);\n return toolCallId != null\n ? redactionContext?.toolNamesByCallId.get(toolCallId)\n : undefined;\n}\n\nfunction hasToolMessageIdentity(value: Record<string, unknown>): boolean {\n const type = getStringField(value, 'type') ?? getStringField(value, '_type');\n if (type === 'tool' || type === 'tool_message') {\n return true;\n }\n\n const id = value.id;\n if (\n Array.isArray(id) &&\n id.some((part) => typeof part === 'string' && part.includes('ToolMessage'))\n ) {\n return true;\n }\n\n if (\n 'tool_call_id' in value ||\n getNestedStringField(value, 'kwargs', 'tool_call_id') != null ||\n getNestedStringField(value, 'additional_kwargs', 'tool_call_id') != null\n ) {\n return true;\n }\n\n const role = getStringField(value, 'role');\n return (\n role != null &&\n !CHAT_ROLES.has(role.toLowerCase()) &&\n ('content' in value || isRecord(value.kwargs) || isRecord(value.data))\n );\n}\n\nfunction redactToolContentFields(\n value: Record<string, unknown>,\n config: ResolvedLangfuseToolOutputTracingConfig\n): Record<string, unknown> {\n const next = { ...value };\n\n for (const outputKey of TOOL_OUTPUT_FIELD_KEYS) {\n if (outputKey in next) {\n next[outputKey] = config.redactionText;\n }\n }\n\n for (const nestedKey of ['kwargs', 'data', 'additional_kwargs']) {\n const nested = next[nestedKey];\n if (!isRecord(nested)) {\n continue;\n }\n const nextNested = { ...nested };\n let changed = false;\n for (const outputKey of TOOL_OUTPUT_FIELD_KEYS) {\n if (outputKey in nextNested) {\n nextNested[outputKey] = config.redactionText;\n changed = true;\n }\n }\n if (changed) {\n next[nestedKey] = nextNested;\n }\n }\n\n return next;\n}\n\nfunction collectToolCallNames(\n value: unknown,\n redactionContext: RedactionContext\n): void {\n if (Array.isArray(value)) {\n for (const item of value) {\n collectToolCallNames(item, redactionContext);\n }\n return;\n }\n\n if (!isRecord(value)) {\n return;\n }\n\n const toolCallId = getSerializedToolCallId(value);\n const toolName = getSerializedToolName(value);\n if (toolCallId != null && toolName != null) {\n redactionContext.toolNamesByCallId.set(toolCallId, toolName);\n }\n\n for (const child of Object.values(value)) {\n collectToolCallNames(child, redactionContext);\n }\n}\n\nfunction redactValue(\n value: unknown,\n config: ResolvedLangfuseToolOutputTracingConfig,\n redactionContext: RedactionContext\n): RedactionResult {\n if (Array.isArray(value)) {\n let changed = false;\n const next: unknown[] = [];\n for (const item of value) {\n const result = redactValue(item, config, redactionContext);\n if (result.changed) {\n changed = true;\n }\n next.push(result.value);\n }\n return changed ? { value: next, changed } : { value, changed };\n }\n\n if (!isRecord(value)) {\n return { value, changed: false };\n }\n\n const toolName = getSerializedToolName(value, redactionContext);\n if (hasToolMessageIdentity(value) && shouldRedactTool(toolName, config)) {\n return {\n value: redactToolContentFields(value, config),\n changed: true,\n };\n }\n\n let changed = false;\n const next: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n const result = redactValue(child, config, redactionContext);\n if (result.changed) {\n changed = true;\n }\n next[key] = result.value;\n }\n\n return changed ? { value: next, changed } : { value, changed };\n}\n\nfunction redactSerializedValue(\n value: unknown,\n config: ResolvedLangfuseToolOutputTracingConfig\n): RedactionResult {\n const redactionContext: RedactionContext = {\n toolNamesByCallId: new Map(),\n };\n if (typeof value !== 'string') {\n collectToolCallNames(value, redactionContext);\n return redactValue(value, config, redactionContext);\n }\n\n const trimmed = value.trim();\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {\n return { value, changed: false };\n }\n\n try {\n const parsed = JSON.parse(value) as unknown;\n collectToolCallNames(parsed, redactionContext);\n const result = redactValue(parsed, config, redactionContext);\n return result.changed\n ? { value: JSON.stringify(result.value), changed: true }\n : { value, changed: false };\n } catch {\n return { value, changed: false };\n }\n}\n\nfunction redactAttribute(\n attributes: Record<string, unknown>,\n key: string,\n config: ResolvedLangfuseToolOutputTracingConfig\n): void {\n if (!(key in attributes)) {\n return;\n }\n\n const result = redactSerializedValue(attributes[key], config);\n if (result.changed) {\n attributes[key] = result.value;\n }\n}\n\nfunction isToolObservation(attributes: Record<string, unknown>): boolean {\n const type = attributes[LangfuseOtelSpanAttributes.OBSERVATION_TYPE];\n return typeof type === 'string' && type.toLowerCase() === 'tool';\n}\n\nfunction classifyLangGraphToolNodeSpan(\n attributes: Record<string, unknown>\n): void {\n const type = attributes[LangfuseOtelSpanAttributes.OBSERVATION_TYPE];\n if (typeof type !== 'string' || type.toLowerCase() !== 'span') {\n return;\n }\n\n const langGraphNode =\n attributes[\n `${LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.langgraph_node`\n ];\n if (\n typeof langGraphNode === 'string' &&\n langGraphNode.startsWith(LANGGRAPH_TOOL_NODE_PREFIX)\n ) {\n attributes[LangfuseOtelSpanAttributes.OBSERVATION_TYPE] = 'tool';\n }\n}\n\nfunction redactToolObservationOutput(\n span: ReadableSpan,\n attributes: Record<string, unknown>,\n config: ResolvedLangfuseToolOutputTracingConfig\n): void {\n if (\n !(\n isToolObservation(attributes) &&\n shouldRedactTool(span.name, config) &&\n LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT in attributes\n )\n ) {\n return;\n }\n\n attributes[LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT] =\n config.redactionText;\n}\n\nexport function redactLangfuseSpanToolOutputs(\n span: ReadableSpan,\n config: ResolvedLangfuseToolOutputTracingConfig\n): void {\n const attributes = (span as SpanWithAttributes).attributes;\n classifyLangGraphToolNodeSpan(attributes);\n\n if (!shouldApplyToolOutputRedaction(config)) {\n return;\n }\n\n redactToolObservationOutput(span, attributes, config);\n\n for (const key of [\n LangfuseOtelSpanAttributes.OBSERVATION_INPUT,\n LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT,\n LangfuseOtelSpanAttributes.TRACE_INPUT,\n LangfuseOtelSpanAttributes.TRACE_OUTPUT,\n ]) {\n redactAttribute(attributes, key, config);\n }\n}\n\nfunction getContextToolOutputTracingConfig(\n activeContext: Context\n): ResolvedLangfuseToolOutputTracingConfig | undefined {\n const asyncConfig = toolOutputTracingStorage.getStore();\n if (asyncConfig != null) {\n return asyncConfig;\n }\n\n const value = activeContext.getValue(langfuseToolOutputTracingConfigKey);\n return isRecord(value)\n ? (value as ResolvedLangfuseToolOutputTracingConfig)\n : undefined;\n}\n\nexport function getContextLangfuseConfig(\n activeContext: Context\n): t.LangfuseConfig | undefined {\n const asyncConfig = langfuseConfigStorage.getStore();\n if (asyncConfig != null) {\n return asyncConfig;\n }\n\n const value = activeContext.getValue(langfuseConfigKey);\n return isRecord(value) ? (value as t.LangfuseConfig) : undefined;\n}\n\nclass ToolOutputRedactingLangfuseSpanProcessor implements SpanProcessor {\n private readonly processor: LangfuseSpanProcessor;\n private readonly fallbackConfig?: ResolvedLangfuseToolOutputTracingConfig;\n private readonly spanConfigs = new WeakMap<\n object,\n ResolvedLangfuseToolOutputTracingConfig\n >();\n\n constructor(\n params?: LangfuseSpanProcessorParams,\n fallbackConfig?: ResolvedLangfuseToolOutputTracingConfig\n ) {\n this.processor = new LangfuseSpanProcessor(params);\n this.fallbackConfig = fallbackConfig;\n }\n\n onStart(span: Span, parentContext: Context): void {\n const config =\n getContextToolOutputTracingConfig(parentContext) ?? this.fallbackConfig;\n if (config != null) {\n this.spanConfigs.set(span, config);\n }\n this.processor.onStart(span, parentContext);\n }\n\n onEnd(span: ReadableSpan): void {\n const config =\n this.spanConfigs.get(span) ??\n toolOutputTracingStorage.getStore() ??\n this.fallbackConfig ??\n resolveToolOutputTracingConfig();\n redactLangfuseSpanToolOutputs(span, config);\n this.processor.onEnd(span);\n }\n\n forceFlush(): Promise<void> {\n return this.processor.forceFlush();\n }\n\n shutdown(): Promise<void> {\n return this.processor.shutdown();\n }\n}\n\nexport function createLangfuseSpanProcessor(\n params?: LangfuseSpanProcessorParams,\n runLangfuse?: t.LangfuseConfig,\n agentLangfuse?: t.LangfuseConfig\n): SpanProcessor {\n const fallbackConfig =\n runLangfuse != null || agentLangfuse != null\n ? resolveToolOutputTracingConfig(runLangfuse, agentLangfuse)\n : undefined;\n return new ToolOutputRedactingLangfuseSpanProcessor(params, fallbackConfig);\n}\n\nexport function withLangfuseToolOutputTracingConfig<T>(\n runLangfuse: t.LangfuseConfig | undefined,\n action: () => T,\n agentLangfuse?: t.LangfuseConfig\n): T {\n const langfuse = resolveLangfuseConfig(runLangfuse, agentLangfuse);\n const hasNoToolOutputConfig =\n runLangfuse?.toolOutputTracing == null &&\n agentLangfuse?.toolOutputTracing == null;\n\n if (langfuse == null && hasNoToolOutputConfig) {\n return action();\n }\n\n const config = hasNoToolOutputConfig\n ? undefined\n : resolveToolOutputTracingConfig(runLangfuse, agentLangfuse);\n let activeContext = context.active();\n if (langfuse != null) {\n activeContext = activeContext.setValue(langfuseConfigKey, langfuse);\n }\n if (config != null) {\n activeContext = activeContext.setValue(\n langfuseToolOutputTracingConfigKey,\n config\n );\n }\n\n const runWithContext = (): T => context.with(activeContext, action);\n const runWithToolOutputConfig = (): T =>\n config != null\n ? toolOutputTracingStorage.run(config, runWithContext)\n : runWithContext();\n\n return langfuse != null\n ? langfuseConfigStorage.run(langfuse, runWithToolOutputConfig)\n : runWithToolOutputConfig();\n}\n\nfunction hasLangfuseEnvKeys(): boolean {\n return (\n isPresent(process.env.LANGFUSE_SECRET_KEY) &&\n isPresent(process.env.LANGFUSE_PUBLIC_KEY)\n );\n}\n\nfunction hasLangfuseConfigKeys(langfuse?: t.LangfuseConfig): boolean {\n if (langfuse == null) {\n return false;\n }\n return isPresent(langfuse.secretKey) && isPresent(langfuse.publicKey);\n}\n\nexport function shouldTraceToolNodeForLangfuse({\n runLangfuse,\n agentLangfuse,\n}: {\n runLangfuse?: t.LangfuseConfig;\n agentLangfuse?: t.LangfuseConfig;\n}): boolean {\n const langfuse = resolveLangfuseConfig(runLangfuse, agentLangfuse);\n if (langfuse?.enabled === false) {\n return false;\n }\n\n const explicit = langfuse?.toolNodeTracing?.enabled;\n if (explicit != null) {\n return (\n explicit && (hasLangfuseConfigKeys(langfuse) || hasLangfuseEnvKeys())\n );\n }\n\n return hasLangfuseConfigKeys(langfuse) || hasLangfuseEnvKeys();\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\n return {\n ...runLangfuse,\n ...agentLangfuse,\n ...(toolNodeTracing != null ? { toolNodeTracing } : {}),\n ...(toolOutputTracing != null ? { toolOutputTracing } : {}),\n };\n}\n"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import { ChatBedrockConverse } from '@langchain/aws';
2
2
  import { ConverseStreamCommand } from '@aws-sdk/client-bedrock-runtime';
3
3
  import { AIMessageChunk } from '@langchain/core/messages';
4
4
  import { ChatGenerationChunk } from '@langchain/core/outputs';
5
+ import { insertBedrockToolCachePoint } from './toolCache.mjs';
5
6
  import { convertToConverseMessages } from './utils/message_inputs.mjs';
6
7
  import { handleConverseStreamContentBlockStart, handleConverseStreamContentBlockDelta, handleConverseStreamMetadata } from './utils/message_outputs.mjs';
7
8
 
@@ -28,6 +29,10 @@ import { handleConverseStreamContentBlockStart, handleConverseStreamContentBlock
28
29
  * the accumulated content is already an array.
29
30
  */
30
31
  class CustomChatBedrockConverse extends ChatBedrockConverse {
32
+ /**
33
+ * Whether to insert Bedrock prompt cache checkpoints when available.
34
+ */
35
+ promptCache;
31
36
  /**
32
37
  * Application Inference Profile ARN to use instead of model ID.
33
38
  */
@@ -38,6 +43,7 @@ class CustomChatBedrockConverse extends ChatBedrockConverse {
38
43
  serviceTier;
39
44
  constructor(fields) {
40
45
  super(fields);
46
+ this.promptCache = fields?.promptCache;
41
47
  this.applicationInferenceProfile = fields?.applicationInferenceProfile;
42
48
  this.serviceTier = fields?.serviceTier;
43
49
  }
@@ -56,10 +62,14 @@ class CustomChatBedrockConverse extends ChatBedrockConverse {
56
62
  */
57
63
  invocationParams(options) {
58
64
  const baseParams = super.invocationParams(options);
65
+ const toolConfig = this.promptCache === true
66
+ ? insertBedrockToolCachePoint(baseParams.toolConfig)
67
+ : baseParams.toolConfig;
59
68
  /** Service tier from options or fall back to class-level setting */
60
69
  const serviceTierType = options?.serviceTier ?? this.serviceTier;
61
70
  return {
62
71
  ...baseParams,
72
+ toolConfig,
63
73
  serviceTier: serviceTierType ? { type: serviceTierType } : undefined,
64
74
  };
65
75
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../../../src/llm/bedrock/index.ts"],"sourcesContent":["/**\n * Optimized ChatBedrockConverse wrapper that fixes content block merging for\n * streaming responses and adds support for latest @langchain/aws features:\n *\n * - Application Inference Profiles (PR #9129)\n * - Service Tiers (Priority/Standard/Flex) (PR #9785) - requires AWS SDK 3.966.0+\n *\n * Bedrock's `@langchain/aws` library does not include an `index` property on content\n * blocks (unlike Anthropic/OpenAI), which causes LangChain's `_mergeLists` to append\n * each streaming chunk as a separate array entry instead of merging by index.\n *\n * This wrapper takes full ownership of the stream by directly interfacing with the\n * AWS SDK client (`this.client`) and using custom handlers from `./utils/` that\n * include `contentBlockIndex` in response_metadata for every delta type. It then\n * promotes `contentBlockIndex` to an `index` property on each content block\n * (mirroring Anthropic's pattern) and strips it from metadata to avoid\n * `_mergeDicts` conflicts.\n *\n * When multiple content block types are present (e.g. reasoning + text), text deltas\n * are promoted from strings to array form with `index` so they merge correctly once\n * the accumulated content is already an array.\n */\n\nimport { ChatBedrockConverse } from '@langchain/aws';\nimport { ConverseStreamCommand } from '@aws-sdk/client-bedrock-runtime';\nimport { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatGenerationChunk, ChatResult } from '@langchain/core/outputs';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { ChatBedrockConverseInput } from '@langchain/aws';\nimport type { BaseMessage, ResponseMetadata } from '@langchain/core/messages';\nimport {\n convertToConverseMessages,\n handleConverseStreamContentBlockStart,\n handleConverseStreamContentBlockDelta,\n handleConverseStreamMetadata,\n} from './utils';\n\n/**\n * Service tier type for Bedrock invocations.\n * Requires AWS SDK >= 3.966.0 to actually work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\nexport type ServiceTierType = 'priority' | 'default' | 'flex' | 'reserved';\n\n/**\n * Extended input interface with additional features:\n * - applicationInferenceProfile: Use an inference profile ARN instead of model ID\n * - serviceTier: Specify service tier (Priority, Standard, Flex, Reserved)\n */\nexport interface CustomChatBedrockConverseInput\n extends ChatBedrockConverseInput {\n /**\n * Application Inference Profile ARN to use for the model.\n * For example, \"arn:aws:bedrock:eu-west-1:123456789102:application-inference-profile/fm16bt65tzgx\"\n * When provided, this ARN will be used for the actual inference calls instead of the model ID.\n * Must still provide `model` as normal modelId to benefit from all the metadata.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-create.html\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n * Specifies the processing tier type used for serving the request.\n * Supported values are 'priority', 'default', 'flex', and 'reserved'.\n *\n * - 'priority': Prioritized processing for lower latency\n * - 'default': Standard processing tier\n * - 'flex': Flexible processing tier with lower cost\n * - 'reserved': Reserved capacity for consistent performance\n *\n * If not provided, AWS uses the default tier.\n * Note: Requires AWS SDK >= 3.966.0 to work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\n serviceTier?: ServiceTierType;\n}\n\n/**\n * Extended call options with serviceTier override support.\n */\nexport interface CustomChatBedrockConverseCallOptions {\n serviceTier?: ServiceTierType;\n}\n\nexport class CustomChatBedrockConverse extends ChatBedrockConverse {\n /**\n * Application Inference Profile ARN to use instead of model ID.\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n */\n serviceTier?: ServiceTierType;\n\n constructor(fields?: CustomChatBedrockConverseInput) {\n super(fields);\n this.applicationInferenceProfile = fields?.applicationInferenceProfile;\n this.serviceTier = fields?.serviceTier;\n }\n\n static lc_name(): string {\n return 'LibreChatBedrockConverse';\n }\n\n /**\n * Get the model ID to use for API calls.\n * Returns applicationInferenceProfile if set, otherwise returns this.model.\n */\n protected getModelId(): string {\n return this.applicationInferenceProfile ?? this.model;\n }\n\n /**\n * Override invocationParams to add serviceTier support.\n */\n override invocationParams(\n options?: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions\n ): ReturnType<ChatBedrockConverse['invocationParams']> & {\n serviceTier?: { type: ServiceTierType };\n } {\n const baseParams = super.invocationParams(options);\n\n /** Service tier from options or fall back to class-level setting */\n const serviceTierType = options?.serviceTier ?? this.serviceTier;\n\n return {\n ...baseParams,\n serviceTier: serviceTierType ? { type: serviceTierType } : undefined,\n };\n }\n\n /**\n * Override _generateNonStreaming to use applicationInferenceProfile as modelId.\n * Uses the same model-swapping pattern as streaming for consistency.\n */\n override async _generateNonStreaming(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n const originalModel = this.model;\n if (\n this.applicationInferenceProfile != null &&\n this.applicationInferenceProfile !== ''\n ) {\n this.model = this.applicationInferenceProfile;\n }\n\n try {\n return await super._generateNonStreaming(messages, options, runManager);\n } finally {\n this.model = originalModel;\n }\n }\n\n /**\n * Own the stream end-to-end so we have direct access to every\n * `contentBlockDelta.contentBlockIndex` from the AWS SDK.\n *\n * This replaces the parent's implementation which strips contentBlockIndex\n * from text and reasoning deltas, making it impossible to merge correctly.\n */\n override async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const { converseMessages, converseSystem } =\n convertToConverseMessages(messages);\n const params = this.invocationParams(options);\n\n let { streamUsage } = this;\n if ((options as Record<string, unknown>).streamUsage !== undefined) {\n streamUsage = (options as Record<string, unknown>).streamUsage as boolean;\n }\n\n const modelId = this.getModelId();\n\n const command = new ConverseStreamCommand({\n modelId,\n messages: converseMessages,\n system: converseSystem,\n ...(params as Record<string, unknown>),\n });\n\n const response = await this.client.send(command, {\n abortSignal: options.signal,\n });\n\n if (!response.stream) {\n return;\n }\n\n const seenBlockIndices = new Set<number>();\n\n for await (const event of response.stream) {\n if (event.contentBlockStart != null) {\n const startChunk = handleConverseStreamContentBlockStart(\n event.contentBlockStart\n );\n if (startChunk != null) {\n const idx = event.contentBlockStart.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n }\n yield this.enrichChunk(startChunk, seenBlockIndices);\n }\n } else if (event.contentBlockDelta != null) {\n const deltaChunk = handleConverseStreamContentBlockDelta(\n event.contentBlockDelta\n );\n\n const idx = event.contentBlockDelta.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n }\n\n yield this.enrichChunk(deltaChunk, seenBlockIndices);\n\n await runManager?.handleLLMNewToken(\n deltaChunk.text,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: deltaChunk }\n );\n } else if (event.metadata != null) {\n yield handleConverseStreamMetadata(event.metadata, { streamUsage });\n } else if (event.contentBlockStop != null) {\n const stopIdx = event.contentBlockStop.contentBlockIndex;\n if (stopIdx != null) {\n seenBlockIndices.add(stopIdx);\n }\n } else {\n yield new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n response_metadata: { ...event } as ResponseMetadata,\n }),\n });\n }\n }\n }\n\n /**\n * Inject `index` on content blocks for proper merge behaviour, then strip\n * `contentBlockIndex` from response_metadata to prevent `_mergeDicts` conflicts.\n *\n * Text string content is promoted to array form only when the stream contains\n * multiple content block indices (e.g. reasoning at index 0, text at index 1),\n * ensuring text merges correctly with the already-array accumulated content.\n */\n private enrichChunk(\n chunk: ChatGenerationChunk,\n seenBlockIndices: Set<number>\n ): ChatGenerationChunk {\n const message = chunk.message;\n if (!(message instanceof AIMessageChunk)) {\n return chunk;\n }\n\n const metadata = message.response_metadata as Record<string, unknown>;\n const blockIndex = this.extractContentBlockIndex(metadata);\n const hasMetadataIndex = blockIndex != null;\n\n let content: AIMessageChunk['content'] = message.content;\n let contentModified = false;\n\n if (Array.isArray(content) && blockIndex != null) {\n content = content.map((block) =>\n typeof block === 'object' && !('index' in block)\n ? { ...block, index: blockIndex }\n : block\n );\n contentModified = true;\n } else if (\n typeof content === 'string' &&\n content !== '' &&\n blockIndex != null &&\n seenBlockIndices.size > 1\n ) {\n content = [{ type: 'text', text: content, index: blockIndex }];\n contentModified = true;\n }\n\n if (!contentModified && !hasMetadataIndex) {\n return chunk;\n }\n\n const cleanedMetadata = hasMetadataIndex\n ? (this.removeContentBlockIndex(metadata) as Record<string, unknown>)\n : metadata;\n\n return new ChatGenerationChunk({\n text: chunk.text,\n message: new AIMessageChunk({\n ...message,\n content,\n response_metadata: cleanedMetadata,\n }),\n generationInfo: chunk.generationInfo,\n });\n }\n\n /**\n * Extract `contentBlockIndex` from the top level of response_metadata.\n * Our custom handlers always place it at the top level.\n */\n private extractContentBlockIndex(\n metadata: Record<string, unknown>\n ): number | undefined {\n if (\n 'contentBlockIndex' in metadata &&\n typeof metadata.contentBlockIndex === 'number'\n ) {\n return metadata.contentBlockIndex;\n }\n return undefined;\n }\n\n private removeContentBlockIndex(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => this.removeContentBlockIndex(item));\n }\n\n if (typeof obj === 'object') {\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (key !== 'contentBlockIndex') {\n cleaned[key] = this.removeContentBlockIndex(value);\n }\n }\n return cleaned;\n }\n\n return obj;\n }\n}\n\nexport type { ChatBedrockConverseInput };\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../../../../src/llm/bedrock/index.ts"],"sourcesContent":["/**\n * Optimized ChatBedrockConverse wrapper that fixes content block merging for\n * streaming responses and adds support for latest @langchain/aws features:\n *\n * - Application Inference Profiles (PR #9129)\n * - Service Tiers (Priority/Standard/Flex) (PR #9785) - requires AWS SDK 3.966.0+\n *\n * Bedrock's `@langchain/aws` library does not include an `index` property on content\n * blocks (unlike Anthropic/OpenAI), which causes LangChain's `_mergeLists` to append\n * each streaming chunk as a separate array entry instead of merging by index.\n *\n * This wrapper takes full ownership of the stream by directly interfacing with the\n * AWS SDK client (`this.client`) and using custom handlers from `./utils/` that\n * include `contentBlockIndex` in response_metadata for every delta type. It then\n * promotes `contentBlockIndex` to an `index` property on each content block\n * (mirroring Anthropic's pattern) and strips it from metadata to avoid\n * `_mergeDicts` conflicts.\n *\n * When multiple content block types are present (e.g. reasoning + text), text deltas\n * are promoted from strings to array form with `index` so they merge correctly once\n * the accumulated content is already an array.\n */\n\nimport { ChatBedrockConverse } from '@langchain/aws';\nimport {\n ConverseStreamCommand,\n type GuardrailConfiguration,\n type GuardrailStreamConfiguration,\n} from '@aws-sdk/client-bedrock-runtime';\nimport { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatGenerationChunk, ChatResult } from '@langchain/core/outputs';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { ChatBedrockConverseInput } from '@langchain/aws';\nimport type { BaseMessage, ResponseMetadata } from '@langchain/core/messages';\nimport { insertBedrockToolCachePoint } from './toolCache';\nimport {\n convertToConverseMessages,\n handleConverseStreamContentBlockStart,\n handleConverseStreamContentBlockDelta,\n handleConverseStreamMetadata,\n} from './utils';\n\n/**\n * Service tier type for Bedrock invocations.\n * Requires AWS SDK >= 3.966.0 to actually work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\nexport type ServiceTierType = 'priority' | 'default' | 'flex' | 'reserved';\n\nexport type CustomGuardrailConfiguration = GuardrailConfiguration &\n Pick<GuardrailStreamConfiguration, 'streamProcessingMode'>;\n\n/**\n * Extended input interface with additional features:\n * - applicationInferenceProfile: Use an inference profile ARN instead of model ID\n * - serviceTier: Specify service tier (Priority, Standard, Flex, Reserved)\n */\nexport interface CustomChatBedrockConverseInput\n extends ChatBedrockConverseInput {\n /**\n * Enables Bedrock prompt cache checkpoints for message and tool prefixes.\n */\n promptCache?: boolean;\n\n /**\n * Guardrail configuration for Converse and ConverseStream invocations.\n * `streamProcessingMode` is only used by ConverseStream.\n */\n guardrailConfig?: CustomGuardrailConfiguration;\n\n /**\n * Application Inference Profile ARN to use for the model.\n * For example, \"arn:aws:bedrock:eu-west-1:123456789102:application-inference-profile/fm16bt65tzgx\"\n * When provided, this ARN will be used for the actual inference calls instead of the model ID.\n * Must still provide `model` as normal modelId to benefit from all the metadata.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-create.html\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n * Specifies the processing tier type used for serving the request.\n * Supported values are 'priority', 'default', 'flex', and 'reserved'.\n *\n * - 'priority': Prioritized processing for lower latency\n * - 'default': Standard processing tier\n * - 'flex': Flexible processing tier with lower cost\n * - 'reserved': Reserved capacity for consistent performance\n *\n * If not provided, AWS uses the default tier.\n * Note: Requires AWS SDK >= 3.966.0 to work.\n * @see https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html\n */\n serviceTier?: ServiceTierType;\n}\n\n/**\n * Extended call options with serviceTier override support.\n */\nexport interface CustomChatBedrockConverseCallOptions {\n serviceTier?: ServiceTierType;\n guardrailConfig?: CustomGuardrailConfiguration;\n}\n\nexport class CustomChatBedrockConverse extends ChatBedrockConverse {\n /**\n * Whether to insert Bedrock prompt cache checkpoints when available.\n */\n promptCache?: boolean;\n\n /**\n * Application Inference Profile ARN to use instead of model ID.\n */\n applicationInferenceProfile?: string;\n\n /**\n * Service tier for model invocation.\n */\n serviceTier?: ServiceTierType;\n\n constructor(fields?: CustomChatBedrockConverseInput) {\n super(fields);\n this.promptCache = fields?.promptCache;\n this.applicationInferenceProfile = fields?.applicationInferenceProfile;\n this.serviceTier = fields?.serviceTier;\n }\n\n static lc_name(): string {\n return 'LibreChatBedrockConverse';\n }\n\n /**\n * Get the model ID to use for API calls.\n * Returns applicationInferenceProfile if set, otherwise returns this.model.\n */\n protected getModelId(): string {\n return this.applicationInferenceProfile ?? this.model;\n }\n\n /**\n * Override invocationParams to add serviceTier support.\n */\n override invocationParams(\n options?: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions\n ): ReturnType<ChatBedrockConverse['invocationParams']> & {\n serviceTier?: { type: ServiceTierType };\n } {\n const baseParams = super.invocationParams(options);\n const toolConfig =\n this.promptCache === true\n ? insertBedrockToolCachePoint(baseParams.toolConfig, true)\n : baseParams.toolConfig;\n\n /** Service tier from options or fall back to class-level setting */\n const serviceTierType = options?.serviceTier ?? this.serviceTier;\n\n return {\n ...baseParams,\n toolConfig,\n serviceTier: serviceTierType ? { type: serviceTierType } : undefined,\n };\n }\n\n /**\n * Override _generateNonStreaming to use applicationInferenceProfile as modelId.\n * Uses the same model-swapping pattern as streaming for consistency.\n */\n override async _generateNonStreaming(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): Promise<ChatResult> {\n const originalModel = this.model;\n if (\n this.applicationInferenceProfile != null &&\n this.applicationInferenceProfile !== ''\n ) {\n this.model = this.applicationInferenceProfile;\n }\n\n try {\n return await super._generateNonStreaming(messages, options, runManager);\n } finally {\n this.model = originalModel;\n }\n }\n\n /**\n * Own the stream end-to-end so we have direct access to every\n * `contentBlockDelta.contentBlockIndex` from the AWS SDK.\n *\n * This replaces the parent's implementation which strips contentBlockIndex\n * from text and reasoning deltas, making it impossible to merge correctly.\n */\n override async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'] & CustomChatBedrockConverseCallOptions,\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const { converseMessages, converseSystem } =\n convertToConverseMessages(messages);\n const params = this.invocationParams(options);\n\n let { streamUsage } = this;\n if ((options as Record<string, unknown>).streamUsage !== undefined) {\n streamUsage = (options as Record<string, unknown>).streamUsage as boolean;\n }\n\n const modelId = this.getModelId();\n\n const command = new ConverseStreamCommand({\n modelId,\n messages: converseMessages,\n system: converseSystem,\n ...(params as Record<string, unknown>),\n });\n\n const response = await this.client.send(command, {\n abortSignal: options.signal,\n });\n\n if (!response.stream) {\n return;\n }\n\n const seenBlockIndices = new Set<number>();\n\n for await (const event of response.stream) {\n if (event.contentBlockStart != null) {\n const startChunk = handleConverseStreamContentBlockStart(\n event.contentBlockStart\n );\n if (startChunk != null) {\n const idx = event.contentBlockStart.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n }\n yield this.enrichChunk(startChunk, seenBlockIndices);\n }\n } else if (event.contentBlockDelta != null) {\n const deltaChunk = handleConverseStreamContentBlockDelta(\n event.contentBlockDelta\n );\n\n const idx = event.contentBlockDelta.contentBlockIndex;\n if (idx != null) {\n seenBlockIndices.add(idx);\n }\n\n yield this.enrichChunk(deltaChunk, seenBlockIndices);\n\n await runManager?.handleLLMNewToken(\n deltaChunk.text,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: deltaChunk }\n );\n } else if (event.metadata != null) {\n yield handleConverseStreamMetadata(event.metadata, { streamUsage });\n } else if (event.contentBlockStop != null) {\n const stopIdx = event.contentBlockStop.contentBlockIndex;\n if (stopIdx != null) {\n seenBlockIndices.add(stopIdx);\n }\n } else {\n yield new ChatGenerationChunk({\n text: '',\n message: new AIMessageChunk({\n content: '',\n response_metadata: { ...event } as ResponseMetadata,\n }),\n });\n }\n }\n }\n\n /**\n * Inject `index` on content blocks for proper merge behaviour, then strip\n * `contentBlockIndex` from response_metadata to prevent `_mergeDicts` conflicts.\n *\n * Text string content is promoted to array form only when the stream contains\n * multiple content block indices (e.g. reasoning at index 0, text at index 1),\n * ensuring text merges correctly with the already-array accumulated content.\n */\n private enrichChunk(\n chunk: ChatGenerationChunk,\n seenBlockIndices: Set<number>\n ): ChatGenerationChunk {\n const message = chunk.message;\n if (!(message instanceof AIMessageChunk)) {\n return chunk;\n }\n\n const metadata = message.response_metadata as Record<string, unknown>;\n const blockIndex = this.extractContentBlockIndex(metadata);\n const hasMetadataIndex = blockIndex != null;\n\n let content: AIMessageChunk['content'] = message.content;\n let contentModified = false;\n\n if (Array.isArray(content) && blockIndex != null) {\n content = content.map((block) =>\n typeof block === 'object' && !('index' in block)\n ? { ...block, index: blockIndex }\n : block\n );\n contentModified = true;\n } else if (\n typeof content === 'string' &&\n content !== '' &&\n blockIndex != null &&\n seenBlockIndices.size > 1\n ) {\n content = [{ type: 'text', text: content, index: blockIndex }];\n contentModified = true;\n }\n\n if (!contentModified && !hasMetadataIndex) {\n return chunk;\n }\n\n const cleanedMetadata = hasMetadataIndex\n ? (this.removeContentBlockIndex(metadata) as Record<string, unknown>)\n : metadata;\n\n return new ChatGenerationChunk({\n text: chunk.text,\n message: new AIMessageChunk({\n ...message,\n content,\n response_metadata: cleanedMetadata,\n }),\n generationInfo: chunk.generationInfo,\n });\n }\n\n /**\n * Extract `contentBlockIndex` from the top level of response_metadata.\n * Our custom handlers always place it at the top level.\n */\n private extractContentBlockIndex(\n metadata: Record<string, unknown>\n ): number | undefined {\n if (\n 'contentBlockIndex' in metadata &&\n typeof metadata.contentBlockIndex === 'number'\n ) {\n return metadata.contentBlockIndex;\n }\n return undefined;\n }\n\n private removeContentBlockIndex(obj: unknown): unknown {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => this.removeContentBlockIndex(item));\n }\n\n if (typeof obj === 'object') {\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (key !== 'contentBlockIndex') {\n cleaned[key] = this.removeContentBlockIndex(value);\n }\n }\n return cleaned;\n }\n\n return obj;\n }\n}\n\nexport type { ChatBedrockConverseInput };\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ import { _convertToOpenAITool } from '../openai/index.mjs';
2
+
3
+ const CACHE_POINT = {
4
+ cachePoint: { type: 'default' },
5
+ };
6
+ const BEDROCK_TOOL_CACHE_MARKER = '__lc_bedrock_cache_point_after';
7
+ const BEDROCK_TOOL_CACHE_DISABLED_MARKER = '__lc_bedrock_skip_tool_cache';
8
+ function isBedrockToolSpec(tool) {
9
+ return (typeof tool === 'object' &&
10
+ tool != null &&
11
+ 'toolSpec' in tool &&
12
+ typeof tool.toolSpec?.name === 'string');
13
+ }
14
+ function isBedrockCachePoint(tool) {
15
+ return 'cachePoint' in tool && tool.cachePoint != null;
16
+ }
17
+ function getToolName(tool) {
18
+ const candidate = tool;
19
+ if (typeof candidate.toolSpec?.name === 'string') {
20
+ return candidate.toolSpec.name;
21
+ }
22
+ if (typeof candidate.name === 'string') {
23
+ return candidate.name;
24
+ }
25
+ if (typeof candidate.function?.name === 'string') {
26
+ return candidate.function.name;
27
+ }
28
+ return undefined;
29
+ }
30
+ function openAIToBedrockTool(tool) {
31
+ return {
32
+ toolSpec: {
33
+ name: tool.function.name,
34
+ description: tool.function.description,
35
+ inputSchema: { json: tool.function.parameters },
36
+ },
37
+ };
38
+ }
39
+ function toBedrockTool(tool) {
40
+ if (isBedrockToolSpec(tool)) {
41
+ return { ...tool };
42
+ }
43
+ return openAIToBedrockTool(_convertToOpenAITool(tool));
44
+ }
45
+ function markCachePointAfter(tool) {
46
+ return {
47
+ ...tool,
48
+ [BEDROCK_TOOL_CACHE_MARKER]: true,
49
+ };
50
+ }
51
+ function markToolCacheDisabled(tool) {
52
+ return {
53
+ ...tool,
54
+ [BEDROCK_TOOL_CACHE_DISABLED_MARKER]: true,
55
+ };
56
+ }
57
+ function stripCachePointMarker(tool) {
58
+ const { [BEDROCK_TOOL_CACHE_MARKER]: _marker, [BEDROCK_TOOL_CACHE_DISABLED_MARKER]: _disabled, ...rest } = tool;
59
+ return rest;
60
+ }
61
+ function partitionAndMarkBedrockToolCache(tools, isDeferred) {
62
+ if (tools == null || tools.length === 0) {
63
+ return tools;
64
+ }
65
+ const staticTools = [];
66
+ const deferredTools = [];
67
+ for (const tool of tools) {
68
+ const converted = toBedrockTool(tool);
69
+ const name = getToolName(converted) ?? getToolName(tool);
70
+ if (name != null && isDeferred(name)) {
71
+ deferredTools.push(converted);
72
+ continue;
73
+ }
74
+ staticTools.push(converted);
75
+ }
76
+ if (staticTools.length === 0) {
77
+ deferredTools[0] = markToolCacheDisabled(deferredTools[0]);
78
+ return [...deferredTools];
79
+ }
80
+ staticTools[staticTools.length - 1] = markCachePointAfter(staticTools[staticTools.length - 1]);
81
+ return [...staticTools, ...deferredTools];
82
+ }
83
+ function insertBedrockToolCachePoint(toolConfig, fallbackToEnd) {
84
+ const tools = toolConfig?.tools;
85
+ if (tools == null || tools.length === 0) {
86
+ return toolConfig;
87
+ }
88
+ let markerIndex = -1;
89
+ let hasCachePoint = false;
90
+ let hasDisabledMarker = false;
91
+ const cleanedTools = [];
92
+ for (let i = 0; i < tools.length; i++) {
93
+ const tool = tools[i];
94
+ if (isBedrockCachePoint(tool)) {
95
+ hasCachePoint = true;
96
+ cleanedTools.push(tool);
97
+ continue;
98
+ }
99
+ if (tool[BEDROCK_TOOL_CACHE_MARKER] === true) {
100
+ markerIndex = cleanedTools.length;
101
+ }
102
+ if (tool[BEDROCK_TOOL_CACHE_DISABLED_MARKER] === true) {
103
+ hasDisabledMarker = true;
104
+ }
105
+ cleanedTools.push(stripCachePointMarker(tool));
106
+ }
107
+ if (hasCachePoint || hasDisabledMarker) {
108
+ return { ...toolConfig, tools: cleanedTools };
109
+ }
110
+ const insertionIndex = markerIndex >= 0 ? markerIndex : tools.length - 1;
111
+ return {
112
+ ...toolConfig,
113
+ tools: [
114
+ ...cleanedTools.slice(0, insertionIndex + 1),
115
+ CACHE_POINT,
116
+ ...cleanedTools.slice(insertionIndex + 1),
117
+ ],
118
+ };
119
+ }
120
+
121
+ export { insertBedrockToolCachePoint, partitionAndMarkBedrockToolCache };
122
+ //# sourceMappingURL=toolCache.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolCache.mjs","sources":["../../../../src/llm/bedrock/toolCache.ts"],"sourcesContent":["import type { Tool, ToolConfiguration } from '@aws-sdk/client-bedrock-runtime';\nimport type { BindToolsInput } from '@langchain/core/language_models/chat_models';\nimport type { OpenAIClient } from '@langchain/openai';\nimport type { DocumentType } from '@smithy/types';\nimport type { GraphTools } from '@/types';\nimport { _convertToOpenAITool } from '@/llm/openai';\n\nconst CACHE_POINT: Tool.CachePointMember = {\n cachePoint: { type: 'default' },\n};\n\nconst BEDROCK_TOOL_CACHE_MARKER = '__lc_bedrock_cache_point_after';\nconst BEDROCK_TOOL_CACHE_DISABLED_MARKER = '__lc_bedrock_skip_tool_cache';\n\ntype BedrockToolWithCacheMarker = Tool & {\n [BEDROCK_TOOL_CACHE_MARKER]?: true;\n [BEDROCK_TOOL_CACHE_DISABLED_MARKER]?: true;\n};\n\ntype OpenAIFunctionTool = Extract<\n OpenAIClient.ChatCompletionTool,\n { type: 'function' }\n>;\n\ntype ToolNameCandidate = {\n name?: unknown;\n function?: {\n name?: unknown;\n };\n toolSpec?: {\n name?: unknown;\n };\n};\n\nfunction isBedrockToolSpec(tool: unknown): tool is Tool.ToolSpecMember {\n return (\n typeof tool === 'object' &&\n tool != null &&\n 'toolSpec' in tool &&\n typeof (tool as ToolNameCandidate).toolSpec?.name === 'string'\n );\n}\n\nfunction isBedrockCachePoint(tool: Tool): tool is Tool.CachePointMember {\n return 'cachePoint' in tool && tool.cachePoint != null;\n}\n\nfunction getToolName(tool: unknown): string | undefined {\n const candidate = tool as ToolNameCandidate;\n if (typeof candidate.toolSpec?.name === 'string') {\n return candidate.toolSpec.name;\n }\n if (typeof candidate.name === 'string') {\n return candidate.name;\n }\n if (typeof candidate.function?.name === 'string') {\n return candidate.function.name;\n }\n return undefined;\n}\n\nfunction openAIToBedrockTool(tool: OpenAIFunctionTool): Tool.ToolSpecMember {\n return {\n toolSpec: {\n name: tool.function.name,\n description: tool.function.description,\n inputSchema: { json: tool.function.parameters as DocumentType },\n },\n };\n}\n\nfunction toBedrockTool(tool: unknown): BedrockToolWithCacheMarker {\n if (isBedrockToolSpec(tool)) {\n return { ...tool };\n }\n\n return openAIToBedrockTool(\n _convertToOpenAITool(tool as BindToolsInput) as OpenAIFunctionTool\n ) as BedrockToolWithCacheMarker;\n}\n\nfunction markCachePointAfter(\n tool: BedrockToolWithCacheMarker\n): BedrockToolWithCacheMarker {\n return {\n ...tool,\n [BEDROCK_TOOL_CACHE_MARKER]: true,\n };\n}\n\nfunction markToolCacheDisabled(\n tool: BedrockToolWithCacheMarker\n): BedrockToolWithCacheMarker {\n return {\n ...tool,\n [BEDROCK_TOOL_CACHE_DISABLED_MARKER]: true,\n };\n}\n\nfunction stripCachePointMarker(tool: BedrockToolWithCacheMarker): Tool {\n const {\n [BEDROCK_TOOL_CACHE_MARKER]: _marker,\n [BEDROCK_TOOL_CACHE_DISABLED_MARKER]: _disabled,\n ...rest\n } = tool;\n return rest as Tool;\n}\n\nexport function partitionAndMarkBedrockToolCache(\n tools: GraphTools | undefined,\n isDeferred: (toolName: string) => boolean\n): GraphTools | undefined {\n if (tools == null || tools.length === 0) {\n return tools;\n }\n\n const staticTools: BedrockToolWithCacheMarker[] = [];\n const deferredTools: BedrockToolWithCacheMarker[] = [];\n\n for (const tool of tools as readonly unknown[]) {\n const converted = toBedrockTool(tool);\n const name = getToolName(converted) ?? getToolName(tool);\n\n if (name != null && isDeferred(name)) {\n deferredTools.push(converted);\n continue;\n }\n\n staticTools.push(converted);\n }\n\n if (staticTools.length === 0) {\n deferredTools[0] = markToolCacheDisabled(deferredTools[0]);\n return [...deferredTools] as GraphTools;\n }\n\n staticTools[staticTools.length - 1] = markCachePointAfter(\n staticTools[staticTools.length - 1]\n );\n\n return [...staticTools, ...deferredTools] as GraphTools;\n}\n\nexport function insertBedrockToolCachePoint(\n toolConfig: ToolConfiguration | undefined,\n fallbackToEnd: boolean\n): ToolConfiguration | undefined {\n const tools = toolConfig?.tools as BedrockToolWithCacheMarker[] | undefined;\n if (tools == null || tools.length === 0) {\n return toolConfig;\n }\n\n let markerIndex = -1;\n let hasCachePoint = false;\n let hasDisabledMarker = false;\n const cleanedTools: Tool[] = [];\n\n for (let i = 0; i < tools.length; i++) {\n const tool = tools[i];\n if (isBedrockCachePoint(tool)) {\n hasCachePoint = true;\n cleanedTools.push(tool);\n continue;\n }\n if (tool[BEDROCK_TOOL_CACHE_MARKER] === true) {\n markerIndex = cleanedTools.length;\n }\n if (tool[BEDROCK_TOOL_CACHE_DISABLED_MARKER] === true) {\n hasDisabledMarker = true;\n }\n cleanedTools.push(stripCachePointMarker(tool));\n }\n\n if (hasCachePoint || hasDisabledMarker) {\n return { ...toolConfig, tools: cleanedTools };\n }\n\n const insertionIndex = markerIndex >= 0 ? markerIndex : tools.length - 1;\n if (markerIndex < 0 && !fallbackToEnd) {\n return { ...toolConfig, tools: cleanedTools };\n }\n\n return {\n ...toolConfig,\n tools: [\n ...cleanedTools.slice(0, insertionIndex + 1),\n CACHE_POINT,\n ...cleanedTools.slice(insertionIndex + 1),\n ],\n };\n}\n"],"names":[],"mappings":"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"}
@@ -334,22 +334,22 @@ function stripBedrockCacheControl(messages) {
334
334
  return updatedMessages;
335
335
  }
336
336
  /**
337
- * Adds Bedrock Converse API cache points to the last two messages.
337
+ * Adds Bedrock Converse API cache points to the latest two user messages.
338
338
  * Inserts `{ cachePoint: { type: 'default' } }` as a separate content block
339
339
  * immediately after the last text block in each targeted message.
340
340
  * Strips ALL existing cache control (both Bedrock and Anthropic formats) from all messages,
341
- * then adds fresh cache points to the last 2 messages in a single backward pass.
341
+ * then adds fresh cache points to the latest two non-tool user messages in a single backward pass.
342
342
  * This ensures we don't accumulate stale cache points across multiple turns.
343
343
  * Returns a new array - only clones messages that require modification.
344
344
  * @param messages - The array of message objects.
345
345
  * @returns - A new array of message objects with cache points added.
346
346
  */
347
347
  function addBedrockCacheControl(messages) {
348
- if (!Array.isArray(messages) || messages.length < 2) {
348
+ if (!Array.isArray(messages) || messages.length === 0) {
349
349
  return messages;
350
350
  }
351
351
  const updatedMessages = [...messages];
352
- let messagesModified = 0;
352
+ let cachePointsAdded = 0;
353
353
  for (let i = updatedMessages.length - 1; i >= 0; i--) {
354
354
  const originalMessage = updatedMessages[i];
355
355
  const messageType = 'getType' in originalMessage &&
@@ -365,18 +365,23 @@ function addBedrockCacheControl(messages) {
365
365
  continue;
366
366
  }
367
367
  const isToolMessage = messageType === 'tool' || messageRole === 'tool';
368
+ const isUserMessage = messageType === 'human' || messageRole === 'user';
368
369
  const content = originalMessage.content;
370
+ const hasSerializationProps = 'lc_kwargs' in originalMessage ||
371
+ 'lc_serializable' in originalMessage ||
372
+ 'lc_namespace' in originalMessage;
369
373
  const hasArrayContent = Array.isArray(content);
370
374
  const isEmptyString = typeof content === 'string' && content === '';
371
- const needsCacheAdd = messagesModified < 2 &&
375
+ const needsCacheAdd = cachePointsAdded < 2 &&
376
+ isUserMessage &&
372
377
  !isToolMessage &&
373
378
  !isEmptyString &&
374
379
  (typeof content === 'string' || hasArrayContent);
375
- if (!needsCacheAdd && !hasArrayContent) {
380
+ if (!needsCacheAdd && !hasArrayContent && !hasSerializationProps) {
376
381
  continue;
377
382
  }
378
383
  let workingContent;
379
- let modified = false;
384
+ let modified = hasSerializationProps;
380
385
  if (hasArrayContent) {
381
386
  // Single pass: clone blocks, strip cache markers, find last
382
387
  // non-empty text block for cache point insertion — all at once.
@@ -412,7 +417,7 @@ function addBedrockCacheControl(messages) {
412
417
  workingContent.splice(lastNonEmptyTextIndex + 1, 0, {
413
418
  cachePoint: { type: 'default' },
414
419
  });
415
- messagesModified++;
420
+ cachePointsAdded++;
416
421
  }
417
422
  }
418
423
  else if (typeof content === 'string' && needsCacheAdd) {
@@ -420,7 +425,10 @@ function addBedrockCacheControl(messages) {
420
425
  { type: ContentTypes.TEXT, text: content },
421
426
  { cachePoint: { type: 'default' } },
422
427
  ];
423
- messagesModified++;
428
+ cachePointsAdded++;
429
+ }
430
+ else if (typeof content === 'string' && hasSerializationProps) {
431
+ workingContent = content;
424
432
  }
425
433
  else {
426
434
  continue;