@librechat/agents 3.2.46 → 3.2.52

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 (57) hide show
  1. package/dist/cjs/graphs/MultiAgentGraph.cjs +6 -6
  2. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  3. package/dist/cjs/llm/anthropic/index.cjs +4 -3
  4. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  5. package/dist/cjs/llm/anthropic/utils/tools.cjs +2 -1
  6. package/dist/cjs/llm/anthropic/utils/tools.cjs.map +1 -1
  7. package/dist/cjs/llm/bedrock/cachePoints.cjs +28 -0
  8. package/dist/cjs/llm/bedrock/cachePoints.cjs.map +1 -0
  9. package/dist/cjs/llm/bedrock/index.cjs +10 -1
  10. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  11. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  12. package/dist/cjs/run.cjs +21 -3
  13. package/dist/cjs/run.cjs.map +1 -1
  14. package/dist/cjs/tools/ToolNode.cjs +26 -5
  15. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  16. package/dist/esm/graphs/MultiAgentGraph.mjs +7 -7
  17. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  18. package/dist/esm/llm/anthropic/index.mjs +4 -3
  19. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  20. package/dist/esm/llm/anthropic/utils/tools.mjs +2 -1
  21. package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -1
  22. package/dist/esm/llm/bedrock/cachePoints.mjs +28 -0
  23. package/dist/esm/llm/bedrock/cachePoints.mjs.map +1 -0
  24. package/dist/esm/llm/bedrock/index.mjs +10 -1
  25. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  26. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  27. package/dist/esm/run.mjs +21 -3
  28. package/dist/esm/run.mjs.map +1 -1
  29. package/dist/esm/tools/ToolNode.mjs +26 -5
  30. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  31. package/dist/types/llm/anthropic/utils/tools.d.ts +1 -1
  32. package/dist/types/llm/bedrock/cachePoints.d.ts +9 -0
  33. package/dist/types/run.d.ts +15 -1
  34. package/dist/types/tools/ToolNode.d.ts +9 -2
  35. package/package.json +16 -21
  36. package/src/graphs/MultiAgentGraph.ts +7 -12
  37. package/src/llm/anthropic/index.ts +13 -2
  38. package/src/llm/anthropic/inherited-content-utils.spec.ts +244 -0
  39. package/src/llm/anthropic/inherited-stream-events.spec.ts +752 -0
  40. package/src/llm/anthropic/inherited-strict.spec.ts +302 -0
  41. package/src/llm/anthropic/llm.spec.ts +65 -0
  42. package/src/llm/anthropic/utils/tools.ts +7 -1
  43. package/src/llm/bedrock/cachePoints.ts +86 -0
  44. package/src/llm/bedrock/index.ts +9 -0
  45. package/src/llm/bedrock/inherited-cache.spec.ts +144 -0
  46. package/src/llm/bedrock/inherited.spec.ts +724 -0
  47. package/src/llm/google/inherited-stream-events.spec.ts +350 -0
  48. package/src/llm/openai/inherited-deepseek.spec.ts +347 -0
  49. package/src/llm/openai/inherited-xai.spec.ts +416 -0
  50. package/src/llm/openai/llm.spec.ts +1568 -0
  51. package/src/llm/openrouter/index.ts +1 -3
  52. package/src/llm/vertexai/inherited-stream-events.spec.ts +271 -0
  53. package/src/run.ts +31 -3
  54. package/src/scripts/handoff-test.ts +5 -6
  55. package/src/tools/ToolNode.ts +43 -5
  56. package/src/tools/__tests__/ToolNode.runtimeState.test.ts +120 -0
  57. package/src/tools/__tests__/hitl.test.ts +162 -0
@@ -3,6 +3,7 @@ import { insertBedrockToolCachePoint } from "./toolCache.mjs";
3
3
  import { convertToConverseMessages } from "./utils/message_inputs.mjs";
4
4
  import { createConverseToolUseStopChunk, handleConverseStreamContentBlockDelta, handleConverseStreamContentBlockStart, handleConverseStreamMetadata } from "./utils/message_outputs.mjs";
5
5
  import "./utils/index.mjs";
6
+ import { applyCachePointsToConversePayload } from "./cachePoints.mjs";
6
7
  import { AIMessageChunk } from "@langchain/core/messages";
7
8
  import { ChatGenerationChunk } from "@langchain/core/outputs";
8
9
  import { ChatBedrockConverse } from "@langchain/aws";
@@ -111,8 +112,16 @@ var CustomChatBedrockConverse = class extends ChatBedrockConverse {
111
112
  const params = this.invocationParams(options);
112
113
  let { streamUsage } = this;
113
114
  if (options.streamUsage !== void 0) streamUsage = options.streamUsage;
115
+ const modelId = this.getModelId();
116
+ applyCachePointsToConversePayload({
117
+ cacheControl: options.cache_control,
118
+ system: converseSystem,
119
+ messages: converseMessages,
120
+ params,
121
+ modelId
122
+ });
114
123
  const command = new ConverseStreamCommand({
115
- modelId: this.getModelId(),
124
+ modelId,
116
125
  messages: converseMessages,
117
126
  system: converseSystem,
118
127
  ...params
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"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 { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatGenerationChunk, ChatResult } from '@langchain/core/outputs';\nimport {\n ConverseStreamCommand,\n type GuardrailConfiguration,\n type GuardrailStreamConfiguration,\n} from '@aws-sdk/client-bedrock-runtime';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { BaseMessage, ResponseMetadata } from '@langchain/core/messages';\nimport type { ChatBedrockConverseInput } from '@langchain/aws';\nimport {\n convertToConverseMessages,\n createConverseToolUseStopChunk,\n handleConverseStreamContentBlockStart,\n handleConverseStreamContentBlockDelta,\n handleConverseStreamMetadata,\n} from './utils';\nimport {\n resolveBedrockPromptCacheTtl,\n supportsBedrockToolCache,\n type PromptCacheTtl,\n} from '@/messages/cache';\nimport { insertBedrockToolCachePoint } from './toolCache';\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 * Prompt-cache checkpoint TTL. Defaults to `'1h'` (extended cache) when\n * `promptCache` is enabled; set `'5m'` for the legacy 5-minute behavior.\n * Bedrock models that don't support the 1-hour TTL downgrade to 5m\n * server-side (verified on Sonnet/Opus 4.6), so the default is safe to leave\n * on; use `'5m'` for any model that rejects it.\n */\n promptCacheTtl?: PromptCacheTtl;\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 * Prompt-cache checkpoint TTL (`'5m'` legacy or `'1h'` extended cache).\n */\n promptCacheTtl?: PromptCacheTtl;\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 /**\n * The configured model id, captured at construction so it survives the\n * temporary `this.model` swap to an application-inference-profile ARN during\n * generation. Used to gate the Bedrock tool cache point to Claude models\n * (see {@link supportsBedrockToolCache}).\n */\n private readonly cacheModelId: string;\n\n constructor(fields?: CustomChatBedrockConverseInput) {\n super(fields);\n this.promptCache = fields?.promptCache;\n this.promptCacheTtl = fields?.promptCacheTtl;\n this.applicationInferenceProfile = fields?.applicationInferenceProfile;\n this.serviceTier = fields?.serviceTier;\n // `super(fields)` initializes `this.model` to LangChain's default Claude\n // model when `fields.model` is omitted, so fall back to it rather than ''\n // (which would treat the default Claude model as tool-cache-unsupported).\n this.cacheModelId = fields?.model ?? this.model;\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 && supportsBedrockToolCache(this.cacheModelId)\n ? insertBedrockToolCachePoint(\n baseParams.toolConfig,\n true,\n resolveBedrockPromptCacheTtl(this.promptCacheTtl, this.cacheModelId)\n )\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 const toolUseBlockIndices = new Set<number>();\n /**\n * Guardrails can reject an already-streamed toolUse block at\n * `messageStop` (`guardrail_intervened`), after `contentBlockStop` has\n * passed. Only emit eager-execution seals when no guardrails are\n * configured, so a later intervention can't race an eagerly started tool.\n */\n const sealToolUseOnStop =\n options.guardrailConfig == null && this.guardrailConfig == null;\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 if (event.contentBlockStart.start?.toolUse != null) {\n toolUseBlockIndices.add(idx);\n }\n }\n yield this.enrichChunk(startChunk, seenBlockIndices);\n\n // Registered stream handlers receive chunks through callback\n // events, not the yielded generator — dispatch the start chunk so\n // they see the tool call's id/name (eager chunk state needs both).\n await runManager?.handleLLMNewToken(\n startChunk.text,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: startChunk }\n );\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 if (sealToolUseOnStop && toolUseBlockIndices.has(stopIdx)) {\n // Converse guarantees the block's input is complete at stop, so\n // emit an explicit seal chunk for eager tool execution — through\n // the callback path too, for registered stream handlers.\n const sealChunk = createConverseToolUseStopChunk(stopIdx);\n yield sealChunk;\n await runManager?.handleLLMNewToken(\n sealChunk.text,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: sealChunk }\n );\n }\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"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"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 { AIMessageChunk } from '@langchain/core/messages';\nimport { ChatGenerationChunk, ChatResult } from '@langchain/core/outputs';\nimport {\n ConverseStreamCommand,\n type GuardrailConfiguration,\n type GuardrailStreamConfiguration,\n} from '@aws-sdk/client-bedrock-runtime';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { BaseMessage, ResponseMetadata } from '@langchain/core/messages';\nimport type { ChatBedrockConverseInput } from '@langchain/aws';\nimport {\n convertToConverseMessages,\n createConverseToolUseStopChunk,\n handleConverseStreamContentBlockStart,\n handleConverseStreamContentBlockDelta,\n handleConverseStreamMetadata,\n} from './utils';\nimport {\n resolveBedrockPromptCacheTtl,\n supportsBedrockToolCache,\n type PromptCacheTtl,\n} from '@/messages/cache';\nimport { applyCachePointsToConversePayload } from './cachePoints';\nimport { insertBedrockToolCachePoint } from './toolCache';\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 * Prompt-cache checkpoint TTL. Defaults to `'1h'` (extended cache) when\n * `promptCache` is enabled; set `'5m'` for the legacy 5-minute behavior.\n * Bedrock models that don't support the 1-hour TTL downgrade to 5m\n * server-side (verified on Sonnet/Opus 4.6), so the default is safe to leave\n * on; use `'5m'` for any model that rejects it.\n */\n promptCacheTtl?: PromptCacheTtl;\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 * Prompt-cache checkpoint TTL (`'5m'` legacy or `'1h'` extended cache).\n */\n promptCacheTtl?: PromptCacheTtl;\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 /**\n * The configured model id, captured at construction so it survives the\n * temporary `this.model` swap to an application-inference-profile ARN during\n * generation. Used to gate the Bedrock tool cache point to Claude models\n * (see {@link supportsBedrockToolCache}).\n */\n private readonly cacheModelId: string;\n\n constructor(fields?: CustomChatBedrockConverseInput) {\n super(fields);\n this.promptCache = fields?.promptCache;\n this.promptCacheTtl = fields?.promptCacheTtl;\n this.applicationInferenceProfile = fields?.applicationInferenceProfile;\n this.serviceTier = fields?.serviceTier;\n // `super(fields)` initializes `this.model` to LangChain's default Claude\n // model when `fields.model` is omitted, so fall back to it rather than ''\n // (which would treat the default Claude model as tool-cache-unsupported).\n this.cacheModelId = fields?.model ?? this.model;\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 && supportsBedrockToolCache(this.cacheModelId)\n ? insertBedrockToolCachePoint(\n baseParams.toolConfig,\n true,\n resolveBedrockPromptCacheTtl(this.promptCacheTtl, this.cacheModelId)\n )\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 applyCachePointsToConversePayload({\n cacheControl: options.cache_control,\n system: converseSystem,\n messages: converseMessages,\n params,\n modelId,\n });\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 const toolUseBlockIndices = new Set<number>();\n /**\n * Guardrails can reject an already-streamed toolUse block at\n * `messageStop` (`guardrail_intervened`), after `contentBlockStop` has\n * passed. Only emit eager-execution seals when no guardrails are\n * configured, so a later intervention can't race an eagerly started tool.\n */\n const sealToolUseOnStop =\n options.guardrailConfig == null && this.guardrailConfig == null;\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 if (event.contentBlockStart.start?.toolUse != null) {\n toolUseBlockIndices.add(idx);\n }\n }\n yield this.enrichChunk(startChunk, seenBlockIndices);\n\n // Registered stream handlers receive chunks through callback\n // events, not the yielded generator — dispatch the start chunk so\n // they see the tool call's id/name (eager chunk state needs both).\n await runManager?.handleLLMNewToken(\n startChunk.text,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: startChunk }\n );\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 if (sealToolUseOnStop && toolUseBlockIndices.has(stopIdx)) {\n // Converse guarantees the block's input is complete at stop, so\n // emit an explicit seal chunk for eager tool execution — through\n // the callback path too, for registered stream handlers.\n const sealChunk = createConverseToolUseStopChunk(stopIdx);\n yield sealChunk;\n await runManager?.handleLLMNewToken(\n sealChunk.text,\n undefined,\n undefined,\n undefined,\n undefined,\n { chunk: sealChunk }\n );\n }\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"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/llm/openrouter/index.ts"],"sourcesContent":["import type {\n ChatOpenAICallOptions,\n OpenAIChatInput,\n OpenAIClient,\n} from '@langchain/openai';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport type { PromptCacheTtl } from '@/messages/cache';\nimport { ChatOpenAI, emitStreamChunkCallback } from '@/llm/openai';\n\nexport type OpenRouterReasoningEffort =\n | 'xhigh'\n | 'high'\n | 'medium'\n | 'low'\n | 'minimal'\n | 'none';\n\nexport interface OpenRouterReasoning {\n effort?: OpenRouterReasoningEffort;\n max_tokens?: number;\n exclude?: boolean;\n enabled?: boolean;\n}\n\nexport interface ChatOpenRouterCallOptions\n extends Omit<ChatOpenAICallOptions, 'reasoning'> {\n /** @deprecated Use `reasoning` object instead */\n include_reasoning?: boolean;\n reasoning?: OpenRouterReasoning;\n modelKwargs?: OpenAIChatInput['modelKwargs'];\n promptCache?: boolean;\n /**\n * Prompt-cache breakpoint TTL. Defaults to `'1h'` (extended cache) when\n * `promptCache` is enabled; set `'5m'` for the legacy 5-minute behavior.\n * OpenRouter forwards this to Claude upstreams (Anthropic / Bedrock / Vertex),\n * which downgrade to 5m where the extended TTL isn't supported.\n */\n promptCacheTtl?: PromptCacheTtl;\n}\n\nexport type ChatOpenRouterInput = Partial<\n ChatOpenRouterCallOptions & OpenAIChatInput\n>;\n\n/** invocationParams return type extended with OpenRouter reasoning */\nexport type OpenRouterInvocationParams = Omit<\n OpenAIClient.Chat.ChatCompletionCreateParams,\n 'messages'\n> & {\n reasoning?: OpenRouterReasoning;\n};\n\ntype InvocationParamsExtra = {\n streaming?: boolean;\n};\n\ninterface OpenRouterReasoningTextDetail {\n type: 'reasoning.text';\n text?: string;\n format?: string;\n index?: number;\n}\n\ninterface OpenRouterReasoningEncryptedDetail {\n type: 'reasoning.encrypted';\n id?: string;\n data?: string;\n format?: string;\n index?: number;\n}\n\ntype OpenRouterReasoningDetail =\n | OpenRouterReasoningTextDetail\n | OpenRouterReasoningEncryptedDetail;\n\nfunction isReasoningTextDetail(\n value: unknown\n): value is OpenRouterReasoningTextDetail {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n value.type === 'reasoning.text'\n );\n}\n\nfunction isReasoningEncryptedDetail(\n value: unknown\n): value is OpenRouterReasoningEncryptedDetail {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n value.type === 'reasoning.encrypted'\n );\n}\n\nfunction getReasoningDetails(value: unknown): OpenRouterReasoningDetail[] {\n if (!Array.isArray(value)) {\n return [];\n }\n return value.filter(\n (detail): detail is OpenRouterReasoningDetail =>\n isReasoningTextDetail(detail) || isReasoningEncryptedDetail(detail)\n );\n}\n\nexport class ChatOpenRouter extends ChatOpenAI {\n private openRouterReasoning?: OpenRouterReasoning;\n /** @deprecated Use `reasoning` object instead */\n private includeReasoning?: boolean;\n\n constructor(_fields: ChatOpenRouterInput) {\n const fieldsWithoutPromptCache: ChatOpenRouterInput = { ..._fields };\n delete fieldsWithoutPromptCache.promptCache;\n delete fieldsWithoutPromptCache.promptCacheTtl;\n\n const {\n include_reasoning,\n reasoning: openRouterReasoning,\n modelKwargs = {},\n ...fields\n } = fieldsWithoutPromptCache;\n\n // Extract reasoning from modelKwargs if provided there (e.g., from LLMConfig)\n const { reasoning: mkReasoning, ...restModelKwargs } = modelKwargs as {\n reasoning?: OpenRouterReasoning;\n } & Record<string, unknown>;\n const mergedReasoning =\n mkReasoning != null || openRouterReasoning != null\n ? {\n ...mkReasoning,\n ...openRouterReasoning,\n }\n : undefined;\n const runtimeReasoning =\n mergedReasoning ??\n (include_reasoning === true ? { enabled: true } : undefined);\n const parentModelKwargs =\n runtimeReasoning == null\n ? restModelKwargs\n : { ...restModelKwargs, reasoning: runtimeReasoning };\n\n super({\n ...fields,\n modelKwargs: parentModelKwargs,\n includeReasoningDetails: true,\n convertReasoningDetailsToContent: true,\n });\n\n // Merge reasoning config: modelKwargs.reasoning < constructor reasoning\n if (mergedReasoning != null) {\n this.openRouterReasoning = mergedReasoning;\n }\n\n this.includeReasoning = include_reasoning;\n }\n static lc_name(): 'LibreChatOpenRouter' {\n return 'LibreChatOpenRouter';\n }\n\n // @ts-expect-error - OpenRouter reasoning extends OpenAI Reasoning with additional\n // effort levels ('xhigh' | 'none' | 'minimal') not in ReasoningEffort.\n // The parent's generic conditional return type cannot be widened in an override.\n override invocationParams(\n options?: this['ParsedCallOptions'],\n extra?: InvocationParamsExtra\n ): OpenRouterInvocationParams {\n type MutableParams = Omit<\n OpenAIClient.Chat.ChatCompletionCreateParams,\n 'messages'\n > & { reasoning_effort?: string; reasoning?: OpenRouterReasoning };\n\n const optionsWithDefaults = this._combineCallOptions(options);\n const params = (\n this._useResponsesApi(options)\n ? this.responses.invocationParams(optionsWithDefaults)\n : this.completions.invocationParams(optionsWithDefaults, extra)\n ) as MutableParams;\n\n // Remove the OpenAI-native reasoning_effort that the parent sets;\n // OpenRouter uses a `reasoning` object instead\n delete params.reasoning_effort;\n\n // Build the OpenRouter reasoning config\n const reasoning = this.buildOpenRouterReasoning(optionsWithDefaults);\n if (reasoning != null) {\n params.reasoning = reasoning;\n } else {\n delete params.reasoning;\n }\n\n return params;\n }\n\n private buildOpenRouterReasoning(\n options?: this['ParsedCallOptions']\n ): OpenRouterReasoning | undefined {\n let reasoning: OpenRouterReasoning | undefined;\n\n // 1. Instance-level reasoning config (from constructor)\n if (this.openRouterReasoning != null) {\n reasoning = { ...this.openRouterReasoning };\n }\n\n // 2. LangChain-style reasoning params (from parent's `this.reasoning`)\n const lcReasoning = this.getReasoningParams(options);\n if (lcReasoning?.effort != null) {\n reasoning = {\n ...reasoning,\n effort: lcReasoning.effort as OpenRouterReasoningEffort,\n };\n }\n\n // 3. Call-level reasoning override\n const callReasoning = (options as ChatOpenRouterCallOptions | undefined)\n ?.reasoning;\n if (callReasoning != null) {\n reasoning = { ...reasoning, ...callReasoning };\n }\n\n // 4. Legacy include_reasoning backward compatibility\n if (reasoning == null && this.includeReasoning === true) {\n reasoning = { enabled: true };\n }\n\n return reasoning;\n }\n\n override async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const reasoningTextByIndex = new Map<\n number,\n OpenRouterReasoningTextDetail\n >();\n const reasoningEncryptedById = new Map<\n string,\n OpenRouterReasoningEncryptedDetail\n >();\n\n for await (const generationChunk of super._streamResponseChunks(\n messages,\n options,\n undefined\n )) {\n let currentReasoningText = '';\n const reasoningDetails = getReasoningDetails(\n generationChunk.message.additional_kwargs.reasoning_details\n );\n\n for (const detail of reasoningDetails) {\n if (detail.type === 'reasoning.text') {\n currentReasoningText += detail.text ?? '';\n const index = detail.index ?? 0;\n const existing = reasoningTextByIndex.get(index);\n if (existing != null) {\n existing.text = `${existing.text ?? ''}${detail.text ?? ''}`;\n continue;\n }\n reasoningTextByIndex.set(index, {\n ...detail,\n text: detail.text ?? '',\n });\n continue;\n }\n if (detail.id != null) {\n reasoningEncryptedById.set(detail.id, { ...detail });\n }\n }\n\n if (\n currentReasoningText.length > 0 &&\n generationChunk.message.additional_kwargs.reasoning == null\n ) {\n generationChunk.message.additional_kwargs.reasoning =\n currentReasoningText;\n }\n\n if (generationChunk.generationInfo?.finish_reason != null) {\n const finalReasoningDetails = [\n ...reasoningTextByIndex.values(),\n ...reasoningEncryptedById.values(),\n ];\n if (finalReasoningDetails.length > 0) {\n generationChunk.message.additional_kwargs.reasoning_details =\n finalReasoningDetails;\n } else {\n delete generationChunk.message.additional_kwargs.reasoning_details;\n }\n await emitStreamChunkCallback(generationChunk, runManager);\n yield generationChunk;\n continue;\n }\n\n delete generationChunk.message.additional_kwargs.reasoning_details;\n await emitStreamChunkCallback(generationChunk, runManager);\n yield generationChunk;\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/llm/openrouter/index.ts"],"sourcesContent":["import type {\n ChatOpenAICallOptions,\n OpenAIChatInput,\n OpenAIClient,\n} from '@langchain/openai';\nimport type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';\nimport type { ChatGenerationChunk } from '@langchain/core/outputs';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport type { PromptCacheTtl } from '@/messages/cache';\nimport { ChatOpenAI, emitStreamChunkCallback } from '@/llm/openai';\n\nexport type OpenRouterReasoningEffort =\n | 'xhigh'\n | 'high'\n | 'medium'\n | 'low'\n | 'minimal'\n | 'none';\n\nexport interface OpenRouterReasoning {\n effort?: OpenRouterReasoningEffort;\n max_tokens?: number;\n exclude?: boolean;\n enabled?: boolean;\n}\n\nexport interface ChatOpenRouterCallOptions\n extends Omit<ChatOpenAICallOptions, 'reasoning'> {\n /** @deprecated Use `reasoning` object instead */\n include_reasoning?: boolean;\n reasoning?: OpenRouterReasoning;\n modelKwargs?: OpenAIChatInput['modelKwargs'];\n promptCache?: boolean;\n /**\n * Prompt-cache breakpoint TTL. Defaults to `'1h'` (extended cache) when\n * `promptCache` is enabled; set `'5m'` for the legacy 5-minute behavior.\n * OpenRouter forwards this to Claude upstreams (Anthropic / Bedrock / Vertex),\n * which downgrade to 5m where the extended TTL isn't supported.\n */\n promptCacheTtl?: PromptCacheTtl;\n}\n\nexport type ChatOpenRouterInput = Partial<\n ChatOpenRouterCallOptions & OpenAIChatInput\n>;\n\n/** invocationParams return type extended with OpenRouter reasoning */\nexport type OpenRouterInvocationParams = Omit<\n OpenAIClient.Chat.ChatCompletionCreateParams,\n 'messages'\n> & {\n reasoning?: OpenRouterReasoning;\n};\n\ntype InvocationParamsExtra = {\n streaming?: boolean;\n};\n\ninterface OpenRouterReasoningTextDetail {\n type: 'reasoning.text';\n text?: string;\n format?: string;\n index?: number;\n}\n\ninterface OpenRouterReasoningEncryptedDetail {\n type: 'reasoning.encrypted';\n id?: string;\n data?: string;\n format?: string;\n index?: number;\n}\n\ntype OpenRouterReasoningDetail =\n | OpenRouterReasoningTextDetail\n | OpenRouterReasoningEncryptedDetail;\n\nfunction isReasoningTextDetail(\n value: unknown\n): value is OpenRouterReasoningTextDetail {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n value.type === 'reasoning.text'\n );\n}\n\nfunction isReasoningEncryptedDetail(\n value: unknown\n): value is OpenRouterReasoningEncryptedDetail {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'type' in value &&\n value.type === 'reasoning.encrypted'\n );\n}\n\nfunction getReasoningDetails(value: unknown): OpenRouterReasoningDetail[] {\n if (!Array.isArray(value)) {\n return [];\n }\n return value.filter(\n (detail): detail is OpenRouterReasoningDetail =>\n isReasoningTextDetail(detail) || isReasoningEncryptedDetail(detail)\n );\n}\n\nexport class ChatOpenRouter extends ChatOpenAI {\n private openRouterReasoning?: OpenRouterReasoning;\n /** @deprecated Use `reasoning` object instead */\n private includeReasoning?: boolean;\n\n constructor(_fields: ChatOpenRouterInput) {\n const fieldsWithoutPromptCache: ChatOpenRouterInput = { ..._fields };\n delete fieldsWithoutPromptCache.promptCache;\n delete fieldsWithoutPromptCache.promptCacheTtl;\n\n const {\n include_reasoning,\n reasoning: openRouterReasoning,\n modelKwargs = {},\n ...fields\n } = fieldsWithoutPromptCache;\n\n // Extract reasoning from modelKwargs if provided there (e.g., from LLMConfig)\n const { reasoning: mkReasoning, ...restModelKwargs } = modelKwargs as {\n reasoning?: OpenRouterReasoning;\n } & Record<string, unknown>;\n const mergedReasoning =\n mkReasoning != null || openRouterReasoning != null\n ? {\n ...mkReasoning,\n ...openRouterReasoning,\n }\n : undefined;\n const runtimeReasoning =\n mergedReasoning ??\n (include_reasoning === true ? { enabled: true } : undefined);\n const parentModelKwargs =\n runtimeReasoning == null\n ? restModelKwargs\n : { ...restModelKwargs, reasoning: runtimeReasoning };\n\n super({\n ...fields,\n modelKwargs: parentModelKwargs,\n includeReasoningDetails: true,\n convertReasoningDetailsToContent: true,\n });\n\n // Merge reasoning config: modelKwargs.reasoning < constructor reasoning\n if (mergedReasoning != null) {\n this.openRouterReasoning = mergedReasoning;\n }\n\n this.includeReasoning = include_reasoning;\n }\n static lc_name(): 'LibreChatOpenRouter' {\n return 'LibreChatOpenRouter';\n }\n\n // OpenRouter widens OpenAI reasoning with extra effort levels ('xhigh' | 'none' | 'minimal').\n override invocationParams(\n options?: this['ParsedCallOptions'],\n extra?: InvocationParamsExtra\n ): OpenRouterInvocationParams {\n type MutableParams = Omit<\n OpenAIClient.Chat.ChatCompletionCreateParams,\n 'messages'\n > & { reasoning_effort?: string; reasoning?: OpenRouterReasoning };\n\n const optionsWithDefaults = this._combineCallOptions(options);\n const params = (\n this._useResponsesApi(options)\n ? this.responses.invocationParams(optionsWithDefaults)\n : this.completions.invocationParams(optionsWithDefaults, extra)\n ) as MutableParams;\n\n // Remove the OpenAI-native reasoning_effort that the parent sets;\n // OpenRouter uses a `reasoning` object instead\n delete params.reasoning_effort;\n\n // Build the OpenRouter reasoning config\n const reasoning = this.buildOpenRouterReasoning(optionsWithDefaults);\n if (reasoning != null) {\n params.reasoning = reasoning;\n } else {\n delete params.reasoning;\n }\n\n return params;\n }\n\n private buildOpenRouterReasoning(\n options?: this['ParsedCallOptions']\n ): OpenRouterReasoning | undefined {\n let reasoning: OpenRouterReasoning | undefined;\n\n // 1. Instance-level reasoning config (from constructor)\n if (this.openRouterReasoning != null) {\n reasoning = { ...this.openRouterReasoning };\n }\n\n // 2. LangChain-style reasoning params (from parent's `this.reasoning`)\n const lcReasoning = this.getReasoningParams(options);\n if (lcReasoning?.effort != null) {\n reasoning = {\n ...reasoning,\n effort: lcReasoning.effort as OpenRouterReasoningEffort,\n };\n }\n\n // 3. Call-level reasoning override\n const callReasoning = (options as ChatOpenRouterCallOptions | undefined)\n ?.reasoning;\n if (callReasoning != null) {\n reasoning = { ...reasoning, ...callReasoning };\n }\n\n // 4. Legacy include_reasoning backward compatibility\n if (reasoning == null && this.includeReasoning === true) {\n reasoning = { enabled: true };\n }\n\n return reasoning;\n }\n\n override async *_streamResponseChunks(\n messages: BaseMessage[],\n options: this['ParsedCallOptions'],\n runManager?: CallbackManagerForLLMRun\n ): AsyncGenerator<ChatGenerationChunk> {\n const reasoningTextByIndex = new Map<\n number,\n OpenRouterReasoningTextDetail\n >();\n const reasoningEncryptedById = new Map<\n string,\n OpenRouterReasoningEncryptedDetail\n >();\n\n for await (const generationChunk of super._streamResponseChunks(\n messages,\n options,\n undefined\n )) {\n let currentReasoningText = '';\n const reasoningDetails = getReasoningDetails(\n generationChunk.message.additional_kwargs.reasoning_details\n );\n\n for (const detail of reasoningDetails) {\n if (detail.type === 'reasoning.text') {\n currentReasoningText += detail.text ?? '';\n const index = detail.index ?? 0;\n const existing = reasoningTextByIndex.get(index);\n if (existing != null) {\n existing.text = `${existing.text ?? ''}${detail.text ?? ''}`;\n continue;\n }\n reasoningTextByIndex.set(index, {\n ...detail,\n text: detail.text ?? '',\n });\n continue;\n }\n if (detail.id != null) {\n reasoningEncryptedById.set(detail.id, { ...detail });\n }\n }\n\n if (\n currentReasoningText.length > 0 &&\n generationChunk.message.additional_kwargs.reasoning == null\n ) {\n generationChunk.message.additional_kwargs.reasoning =\n currentReasoningText;\n }\n\n if (generationChunk.generationInfo?.finish_reason != null) {\n const finalReasoningDetails = [\n ...reasoningTextByIndex.values(),\n ...reasoningEncryptedById.values(),\n ];\n if (finalReasoningDetails.length > 0) {\n generationChunk.message.additional_kwargs.reasoning_details =\n finalReasoningDetails;\n } else {\n delete generationChunk.message.additional_kwargs.reasoning_details;\n }\n await emitStreamChunkCallback(generationChunk, runManager);\n yield generationChunk;\n continue;\n }\n\n delete generationChunk.message.additional_kwargs.reasoning_details;\n await emitStreamChunkCallback(generationChunk, runManager);\n yield generationChunk;\n }\n }\n}\n"],"mappings":"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"}
package/dist/esm/run.mjs CHANGED
@@ -421,7 +421,7 @@ var Run = class Run {
421
421
  const graphRunnable = this.graphRunnable;
422
422
  const graph = this.Graph;
423
423
  /**
424
- * `Command` inputs (currently only `Command({ resume })`) are
424
+ * `Command` inputs (`Command({ resume, update?, goto? })`) are
425
425
  * resume-mode invocations: LangGraph rebuilds graph state from the
426
426
  * checkpointer, so we skip RunStart / UserPromptSubmit hooks (no
427
427
  * new prompt to evaluate) and read run-state from the Graph wrapper
@@ -777,11 +777,29 @@ var Run = class Run {
777
777
  const cp = this.getFileCheckpointer();
778
778
  return cp == null ? 0 : cp.rewind();
779
779
  }
780
- async resume(resumeValue, callerConfig, streamOptions) {
780
+ /**
781
+ * Resume an interrupted run. `commandOptions` forwards langgraph 1.4.5
782
+ * `Command` fields applied together with `resume` in one superstep:
783
+ * - `update`: channel updates committed at the resume point. On a *rebuilt*
784
+ * Run (new instance + durable checkpointer), `update.messages` are the first
785
+ * write the fresh wrapper sees, so they seed the `getRunMessages()` /
786
+ * `returnContent` baseline and are excluded from them (still committed to the
787
+ * checkpoint). Hosts that rebuild + inject messages should persist them
788
+ * directly or read from `getState`. Unreachable without a durable checkpointer.
789
+ * - `goto`: a *dynamic* edge that does not cancel static `addEdge` routes. On
790
+ * the built-in standard graph the fixed `toolNode -> agentNode/END` edge still
791
+ * fires, so `goto` adds rather than replaces (e.g. `goto: END` will not stop a
792
+ * tool-node resume). Intended for custom, Command-routed graphs.
793
+ */
794
+ async resume(resumeValue, callerConfig, streamOptions, commandOptions) {
781
795
  const interruptId = this._interrupt?.interruptId;
782
796
  const scopedResume = typeof interruptId === "string" && interruptId.length > 0 && !isLangGraphResumeMapForInterrupt(resumeValue, interruptId) ? { [interruptId]: resumeValue } : resumeValue;
783
797
  const resumeConfig = await this.resolveInterruptResumeConfig(callerConfig);
784
- return this.processStream(new Command({ resume: scopedResume }), resumeConfig, streamOptions);
798
+ return this.processStream(new Command({
799
+ resume: scopedResume,
800
+ ...commandOptions?.update !== void 0 ? { update: commandOptions.update } : {},
801
+ ...commandOptions?.goto !== void 0 ? { goto: commandOptions.goto } : {}
802
+ }), resumeConfig, streamOptions);
785
803
  }
786
804
  async resolveInterruptResumeConfig(callerConfig) {
787
805
  const interrupt = this._interrupt;
@@ -1 +1 @@
1
- {"version":3,"file":"run.mjs","names":[],"sources":["../../src/run.ts"],"sourcesContent":["// src/run.ts\nimport { HumanMessage } from '@langchain/core/messages';\nimport { PromptTemplate } from '@langchain/core/prompts';\nimport { RunnableLambda } from '@langchain/core/runnables';\nimport { AzureChatOpenAI, ChatOpenAI } from '@langchain/openai';\nimport { BaseCallbackHandler } from '@langchain/core/callbacks/base';\nimport {\n Command,\n INTERRUPT,\n MemorySaver,\n isInterrupted,\n} from '@langchain/langgraph';\nimport type {\n MessageContentComplex,\n BaseMessage,\n} from '@langchain/core/messages';\nimport type { StringPromptValue } from '@langchain/core/prompt_values';\nimport type { RunnableConfig } from '@langchain/core/runnables';\nimport type { HookRegistry } from '@/hooks';\nimport type * as t from '@/types';\nimport {\n createLangfuseTraceMetadata,\n createLangfuseHandler,\n disposeLangfuseHandler,\n getLangfuseTraceName,\n isLangfuseCallbackHandler,\n withLangfuseAttributes,\n} from '@/langfuse';\nimport {\n resolveLangfuseRuntimeScope,\n withLangfuseRuntimeScope,\n} from '@/langfuseRuntimeScope';\nimport {\n appendCallbacks,\n findCallback,\n type CallbackEntry,\n} from '@/utils/callbacks';\nimport {\n createCompletionTitleRunnable,\n createTitleRunnable,\n} from '@/utils/title';\nimport { createTokenCounter, encodingForModel } from '@/utils/tokens';\nimport { initializeLangfuseTracing } from './instrumentation';\nimport { GraphEvents, Callback, TitleMethod } from '@/common';\nimport { MultiAgentGraph } from '@/graphs/MultiAgentGraph';\nimport { resolveLangfuseConfig } from '@/langfuseConfig';\nimport { StandardGraph } from '@/graphs/Graph';\nimport { initializeModel } from '@/llm/init';\nimport { HandlerRegistry } from '@/events';\nimport { isOpenAILike } from '@/utils/llm';\nimport { executeHooks } from '@/hooks';\n\nexport const defaultOmitOptions = new Set([\n 'stream',\n 'thinking',\n 'streaming',\n 'maxTokens',\n 'clientOptions',\n 'thinkingConfig',\n 'thinkingBudget',\n 'includeThoughts',\n 'maxOutputTokens',\n 'additionalModelRequestFields',\n]);\n\nconst CUSTOM_GRAPH_EVENTS = new Set<string>([\n GraphEvents.ON_AGENT_UPDATE,\n GraphEvents.ON_RUN_STEP,\n GraphEvents.ON_RUN_STEP_DELTA,\n GraphEvents.ON_RUN_STEP_COMPLETED,\n GraphEvents.ON_MESSAGE_DELTA,\n GraphEvents.ON_REASONING_DELTA,\n GraphEvents.ON_TOOL_EXECUTE,\n GraphEvents.ON_SUMMARIZE_START,\n GraphEvents.ON_SUMMARIZE_DELTA,\n GraphEvents.ON_SUMMARIZE_COMPLETE,\n GraphEvents.ON_SUBAGENT_UPDATE,\n GraphEvents.ON_AGENT_LOG,\n GraphEvents.ON_CONTEXT_USAGE,\n GraphEvents.ON_CUSTOM_EVENT,\n]);\n\nconst DIRECT_DISPATCHED_STEP_EVENTS = new Set<string>([\n GraphEvents.ON_RUN_STEP,\n GraphEvents.ON_RUN_STEP_DELTA,\n GraphEvents.ON_MESSAGE_DELTA,\n GraphEvents.ON_REASONING_DELTA,\n]);\n\nfunction getStepScopedEventId(data: unknown): string | undefined {\n if (data == null || typeof data !== 'object') {\n return undefined;\n }\n const candidate = data as { id?: unknown };\n return typeof candidate.id === 'string' ? candidate.id : undefined;\n}\n\nfunction isLangGraphResumeMapForInterrupt(\n value: unknown,\n interruptId: string\n): value is Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n return Object.prototype.hasOwnProperty.call(value, interruptId);\n}\n\ntype InterruptStateSnapshot = {\n config?: RunnableConfig;\n tasks?: Array<{\n interrupts?: Array<{ id?: string }>;\n }>;\n};\n\ntype WorkflowWithStateHistory = {\n getStateHistory?(\n config: RunnableConfig\n ): AsyncIterableIterator<InterruptStateSnapshot>;\n};\n\nexport class Run<_T extends t.BaseGraphState> {\n id: string;\n private tokenCounter?: t.TokenCounter;\n private handlerRegistry?: HandlerRegistry;\n private hookRegistry?: HookRegistry;\n private humanInTheLoop?: t.HumanInTheLoopConfig;\n private langfuse?: t.LangfuseConfig;\n private toolOutputReferences?: t.ToolOutputReferencesConfig;\n private eagerEventToolExecution?: t.EagerEventToolExecutionConfig;\n private toolExecution?: t.ToolExecutionConfig;\n private subagentUsageSink?: t.SubagentUsageSink;\n private indexTokenCountMap?: Record<string, number>;\n calibrationRatio: number = 1;\n graphRunnable?: t.CompiledStateWorkflow;\n Graph: StandardGraph | MultiAgentGraph | undefined;\n returnContent: boolean = false;\n private skipCleanup: boolean = false;\n private _streamResult: t.MessageContentComplex[] | undefined;\n /**\n * Captured interrupt payload typed as `unknown` because the SDK\n * does not validate the runtime shape — custom graph nodes can\n * raise interrupts with arbitrary payloads (not just the SDK's\n * `HumanInterruptPayload` union). The public `getInterrupt<T>()`\n * lets callers assert the type they expect.\n */\n private _interrupt: t.RunInterruptResult<unknown> | undefined;\n private _haltedReason: string | undefined;\n\n private constructor(config: Partial<t.RunConfig>) {\n const runId = config.runId ?? '';\n if (!runId) {\n throw new Error('Run ID not provided');\n }\n\n this.id = runId;\n this.tokenCounter = config.tokenCounter;\n this.indexTokenCountMap = config.indexTokenCountMap;\n if (config.calibrationRatio != null && config.calibrationRatio > 0) {\n this.calibrationRatio = config.calibrationRatio;\n }\n\n const handlerRegistry = new HandlerRegistry();\n\n if (config.customHandlers) {\n for (const [eventType, handler] of Object.entries(\n config.customHandlers\n )) {\n handlerRegistry.register(eventType, handler);\n }\n }\n\n this.handlerRegistry = handlerRegistry;\n this.hookRegistry = config.hooks;\n this.humanInTheLoop = config.humanInTheLoop;\n this.langfuse = config.langfuse;\n this.toolOutputReferences = config.toolOutputReferences;\n this.eagerEventToolExecution = config.eagerEventToolExecution;\n this.toolExecution = config.toolExecution;\n this.subagentUsageSink = config.subagentUsageSink;\n\n if (!config.graphConfig) {\n throw new Error('Graph config not provided');\n }\n\n /** Handle different graph types */\n if (config.graphConfig.type === 'multi-agent') {\n this.graphRunnable = this.createMultiAgentGraph(config.graphConfig);\n if (this.Graph) {\n this.Graph.handlerRegistry = handlerRegistry;\n }\n } else {\n /** Default to legacy graph for 'standard' or undefined type */\n this.graphRunnable = this.createLegacyGraph(config.graphConfig);\n if (this.Graph) {\n this.Graph.compileOptions =\n config.graphConfig.compileOptions ?? this.Graph.compileOptions;\n this.Graph.handlerRegistry = handlerRegistry;\n }\n }\n\n if (config.initialSessions && this.Graph) {\n for (const [key, value] of config.initialSessions) {\n this.Graph.sessions.set(key, value);\n }\n }\n\n this.returnContent = config.returnContent ?? false;\n this.skipCleanup = config.skipCleanup ?? false;\n }\n\n private createLegacyGraph(\n config: t.LegacyGraphConfig | t.StandardGraphConfig\n ): t.CompiledStateWorkflow {\n let agentConfig: t.AgentInputs;\n let signal: AbortSignal | undefined;\n\n /** Check if this is a multi-agent style config (has agents array) */\n if ('agents' in config && Array.isArray(config.agents)) {\n if (config.agents.length === 0) {\n throw new Error('At least one agent must be provided');\n }\n agentConfig = config.agents[0];\n signal = config.signal;\n } else {\n /** Legacy path: build agent config from llmConfig */\n const {\n type: _type,\n llmConfig,\n signal: legacySignal,\n tools = [],\n ...agentInputs\n } = config as t.LegacyGraphConfig;\n const { provider, ...clientOptions } = llmConfig;\n\n agentConfig = {\n ...agentInputs,\n tools,\n provider,\n clientOptions,\n agentId: 'default',\n };\n signal = legacySignal;\n }\n\n const standardGraph = new StandardGraph({\n signal,\n runId: this.id,\n agents: [agentConfig],\n langfuse: this.langfuse,\n tokenCounter: this.tokenCounter,\n indexTokenCountMap: this.indexTokenCountMap,\n calibrationRatio: this.calibrationRatio,\n subagentUsageSink: this.subagentUsageSink,\n });\n /** Propagate compile options from graph config */\n standardGraph.compileOptions = this.applyHITLCheckpointerFallback(\n config.compileOptions\n );\n standardGraph.hookRegistry = this.hookRegistry;\n standardGraph.humanInTheLoop = this.humanInTheLoop;\n standardGraph.toolOutputReferences = this.toolOutputReferences;\n standardGraph.eagerEventToolExecution = this.eagerEventToolExecution;\n standardGraph.toolExecution = this.toolExecution;\n this.Graph = standardGraph;\n return standardGraph.createWorkflow();\n }\n\n private createMultiAgentGraph(\n config: t.MultiAgentGraphConfig\n ): t.CompiledStateWorkflow {\n const { agents, edges, compileOptions } = config;\n\n const multiAgentGraph = new MultiAgentGraph({\n runId: this.id,\n agents,\n edges,\n langfuse: this.langfuse,\n tokenCounter: this.tokenCounter,\n indexTokenCountMap: this.indexTokenCountMap,\n calibrationRatio: this.calibrationRatio,\n subagentUsageSink: this.subagentUsageSink,\n });\n\n multiAgentGraph.compileOptions =\n this.applyHITLCheckpointerFallback(compileOptions);\n\n multiAgentGraph.hookRegistry = this.hookRegistry;\n multiAgentGraph.humanInTheLoop = this.humanInTheLoop;\n multiAgentGraph.toolOutputReferences = this.toolOutputReferences;\n multiAgentGraph.eagerEventToolExecution = this.eagerEventToolExecution;\n multiAgentGraph.toolExecution = this.toolExecution;\n this.Graph = multiAgentGraph;\n return multiAgentGraph.createWorkflow();\n }\n\n /**\n * When the host opted into HITL via `humanInTheLoop: { enabled: true }`\n * and did not supply a checkpointer, install an in-memory `MemorySaver`\n * so `interrupt()` can persist checkpoints and `Command({ resume })`\n * can rebuild state. The fallback is intentionally process-local:\n * production hosts that need durable resumption across processes /\n * restarts must provide their own checkpointer (Redis, Postgres, etc.)\n * on `compileOptions.checkpointer`.\n *\n * No-op when HITL is off (the default — omitted, or\n * `{ enabled: false }`) or the host already supplied a checkpointer\n * of their own. See `HumanInTheLoopConfig` JSDoc for the rationale\n * behind the default-off stance.\n */\n private applyHITLCheckpointerFallback(\n compileOptions: t.CompileOptions | undefined\n ): t.CompileOptions | undefined {\n if (this.humanInTheLoop?.enabled !== true) {\n return compileOptions;\n }\n if (compileOptions?.checkpointer != null) {\n return compileOptions;\n }\n return {\n ...(compileOptions ?? {}),\n checkpointer: new MemorySaver(),\n };\n }\n\n /**\n * Run RunStart + UserPromptSubmit hooks before the graph stream\n * begins, accumulate any `additionalContext` strings into the input\n * messages, and short-circuit when a hook signals the run should not\n * proceed (deny / ask decision on the prompt, or `preventContinuation`\n * on either hook).\n *\n * Returns `true` when the caller should bail with `undefined` (run\n * was halted before any model call); returns `false` to proceed\n * into the stream loop.\n *\n * ## Side effects\n *\n * On the success path:\n * - Mutates `stateInputs.messages` in place to append a\n * consolidated `HumanMessage` carrying any hook\n * `additionalContext` strings. Safe because the host owns the\n * array and `processStream` is the only consumer until LangGraph\n * reads it.\n *\n * On the halt path (returning `true`):\n * - Sets `this._haltedReason` so callers (and the eventual host)\n * can distinguish a hook-driven halt from a natural completion.\n * - Calls `registry.clearSession(this.id)` and\n * `registry.clearHaltSignal(this.id)` because no resume is\n * expected from a pre-stream halt — the run never entered the\n * graph, so the session/halt state for this run would otherwise\n * leak to the next `processStream` invocation on the same\n * registry. Other concurrent runs on the same registry are\n * untouched (halt signals are scoped per session id).\n * - Sets `config.callbacks = undefined` to drop the callback\n * references the caller built (langfuse handler, custom event\n * handler, etc.) since they won't be exercised. Mirrors the\n * equivalent cleanup the `processStream` `finally` block does\n * on the natural-completion path.\n */\n private async runPreStreamHooks(\n stateInputs: t.IState,\n threadId: string | undefined,\n config: Partial<RunnableConfig>\n ): Promise<boolean> {\n const registry = this.hookRegistry;\n /**\n * Defensive guard: `processStream` already validated `this.Graph`\n * before calling this helper, but TypeScript can't propagate that\n * narrowing across method boundaries. The check keeps the body\n * free of `this.Graph!` non-null assertions.\n */\n if (registry == null || this.Graph == null) {\n return false;\n }\n\n const preStreamContexts: string[] = [];\n\n const runStartResult = await executeHooks({\n registry,\n input: {\n hook_event_name: 'RunStart',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n messages: stateInputs.messages,\n },\n sessionId: this.id,\n });\n for (const ctx of runStartResult.additionalContexts) {\n preStreamContexts.push(ctx);\n }\n /**\n * Honor `preventContinuation` from RunStart before the stream\n * starts. Mid-flight halts (from tool/compact/subagent hooks)\n * route through `HookRegistry.haltRun` and are polled by the\n * stream loop in `processStream` — different mechanism, same\n * intent.\n */\n if (runStartResult.preventContinuation === true) {\n this._haltedReason = runStartResult.stopReason ?? 'preventContinuation';\n registry.clearSession(this.id);\n registry.clearHaltSignal(this.id);\n config.callbacks = undefined;\n return true;\n }\n\n const lastHuman = findLastMessageOfType(stateInputs.messages, 'human');\n if (lastHuman != null) {\n const promptResult = await executeHooks({\n registry,\n input: {\n hook_event_name: 'UserPromptSubmit',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n prompt: extractPromptText(lastHuman),\n // attachments: not yet wired — Phase 2 will extract\n // non-text content blocks (images, files) from messages\n },\n sessionId: this.id,\n });\n if (\n promptResult.decision === 'deny' ||\n promptResult.decision === 'ask' ||\n promptResult.preventContinuation === true\n ) {\n /**\n * Always set `_haltedReason` so the host can call\n * `getHaltReason()` and distinguish a hook-blocked prompt\n * from a natural empty-output completion. Three signals can\n * land here, each with its own canonical reason string when\n * the hook didn't supply one.\n */\n if (promptResult.preventContinuation === true) {\n this._haltedReason = promptResult.stopReason ?? 'preventContinuation';\n } else if (promptResult.decision === 'deny') {\n this._haltedReason = promptResult.reason ?? 'prompt_denied';\n } else {\n this._haltedReason =\n promptResult.reason ?? 'prompt_requires_approval';\n }\n registry.clearSession(this.id);\n registry.clearHaltSignal(this.id);\n config.callbacks = undefined;\n return true;\n }\n for (const ctx of promptResult.additionalContexts) {\n preStreamContexts.push(ctx);\n }\n }\n\n if (preStreamContexts.length > 0) {\n /**\n * Wraps the joined hook contexts as a `HumanMessage` even though\n * the intent is system-level guidance. Using a `SystemMessage`\n * mid-conversation is rejected by Anthropic and Google providers\n * (system messages must be the leading entry), so the LangChain\n * convention — also used by `ToolNode.convertInjectedMessages`\n * — is `HumanMessage` carrying `additional_kwargs.role` as a\n * marker for hosts inspecting state. The model still sees a\n * user-role message; the `role: 'system'` field is metadata\n * only. Hosts that want a true system message should compose\n * it into the agent's `instructions` config instead.\n */\n stateInputs.messages.push(\n new HumanMessage({\n content: preStreamContexts.join('\\n\\n'),\n additional_kwargs: { role: 'system', source: 'hook' },\n })\n );\n }\n\n return false;\n }\n\n static async create<T extends t.BaseGraphState>(\n config: t.RunConfig\n ): Promise<Run<T>> {\n /** Create tokenCounter if indexTokenCountMap is provided but tokenCounter is not */\n if (config.indexTokenCountMap && !config.tokenCounter) {\n const gc = config.graphConfig;\n const clientOpts =\n 'agents' in gc ? gc.agents[0]?.clientOptions : gc.clientOptions;\n const model = (clientOpts as { model?: string } | undefined)?.model ?? '';\n config.tokenCounter = await createTokenCounter(encodingForModel(model));\n }\n return new Run<T>(config);\n }\n\n getRunMessages(): BaseMessage[] | undefined {\n if (!this.Graph) {\n throw new Error(\n 'Graph not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n return this.Graph.getRunMessages();\n }\n\n /**\n * Returns the current calibration ratio (EMA of provider-vs-estimate token ratios).\n * Hosts should persist this value and pass it back as `RunConfig.calibrationRatio`\n * on the next run for the same conversation so the pruner starts with an accurate\n * scaling factor instead of the default (1).\n */\n getCalibrationRatio(): number {\n return this.calibrationRatio;\n }\n\n getResolvedInstructionOverhead(): number | undefined {\n return this.Graph?.getResolvedInstructionOverhead();\n }\n\n getToolCount(): number {\n return this.Graph?.getToolCount() ?? 0;\n }\n\n /**\n * Creates a custom event callback handler that intercepts custom events\n * and processes them through our handler registry instead of EventStreamCallbackHandler\n */\n private createCustomEventCallback() {\n return async (\n eventName: string,\n data: unknown,\n runId: string,\n tags?: string[],\n metadata?: Record<string, unknown>\n ): Promise<void> => {\n // Step-scoped SDK events are dispatched directly via the handler\n // registry first. Skip callback-based echoes to prevent double\n // handling when LangGraph invokes custom callbacks more than once.\n const stepScopedEventId = getStepScopedEventId(data);\n if (\n DIRECT_DISPATCHED_STEP_EVENTS.has(eventName) &&\n this.Graph != null &&\n stepScopedEventId != null &&\n this.Graph.hasHandlerDispatchedEvent(eventName, stepScopedEventId)\n ) {\n return;\n }\n const handler = this.handlerRegistry?.getHandler(eventName);\n if (handler && this.Graph) {\n return await handler.handle(\n eventName,\n data as\n | t.StreamEventData\n | t.ModelEndData\n | t.RunStep\n | t.RunStepDeltaEvent\n | t.MessageDeltaEvent\n | t.ReasoningDeltaEvent\n | { result: t.ToolEndEvent },\n metadata,\n this.Graph\n );\n }\n };\n }\n\n private shouldClearHookSession(streamThrew: boolean): boolean {\n return this._interrupt == null || this._haltedReason != null || streamThrew;\n }\n\n private isAwaitingResume(streamThrew: boolean): boolean {\n return (\n this._interrupt != null && this._haltedReason == null && !streamThrew\n );\n }\n\n private getStreamLangfuseConfig(\n graph: StandardGraph | MultiAgentGraph\n ): t.LangfuseConfig | undefined {\n const primaryContext = graph.agentContexts.get(graph.defaultAgentId);\n if (primaryContext != null) {\n return resolveLangfuseConfig(this.langfuse, primaryContext.langfuse);\n }\n\n for (const context of graph.agentContexts.values()) {\n const langfuse = resolveLangfuseConfig(this.langfuse, context.langfuse);\n if (langfuse != null) {\n return langfuse;\n }\n }\n\n return this.langfuse;\n }\n\n private getStreamToolOutputTracingLangfuseConfig(\n graph: StandardGraph | MultiAgentGraph\n ): t.LangfuseConfig | undefined {\n const toolOutputTracingConfigs = Array.from(graph.agentContexts.values())\n .map((context) => {\n return resolveLangfuseConfig(this.langfuse, context.langfuse)\n ?.toolOutputTracing;\n })\n .filter((config): config is t.LangfuseToolOutputTracingConfig => {\n return config != null;\n });\n\n if (toolOutputTracingConfigs.length === 0) {\n return this.langfuse?.toolOutputTracing != null\n ? { toolOutputTracing: this.langfuse.toolOutputTracing }\n : undefined;\n }\n if (toolOutputTracingConfigs.length === 1) {\n return { toolOutputTracing: toolOutputTracingConfigs[0] };\n }\n\n let enabled: boolean | undefined;\n let redactionText: string | undefined;\n let redactedToolNameMatchMode: 'exact' | 'partial' | undefined;\n const redactedToolNames = new Set<string>();\n\n for (const config of toolOutputTracingConfigs) {\n if (config.enabled === false) {\n enabled = false;\n } else if (enabled !== false && config.enabled != null) {\n enabled = config.enabled;\n }\n\n redactionText ??= config.redactionText;\n if (config.redactedToolNameMatchMode === 'partial') {\n redactedToolNameMatchMode = 'partial';\n } else {\n redactedToolNameMatchMode ??= config.redactedToolNameMatchMode;\n }\n\n for (const toolName of config.redactedToolNames ?? []) {\n redactedToolNames.add(toolName);\n }\n }\n\n return {\n toolOutputTracing: {\n ...(enabled != null ? { enabled } : {}),\n ...(redactedToolNames.size > 0\n ? { redactedToolNames: Array.from(redactedToolNames) }\n : {}),\n ...(redactedToolNameMatchMode != null\n ? { redactedToolNameMatchMode }\n : {}),\n ...(redactionText != null ? { redactionText } : {}),\n },\n };\n }\n\n async processStream(\n inputs: t.IState | Command,\n callerConfig: Partial<RunnableConfig> & {\n version: 'v1' | 'v2';\n run_id?: string;\n },\n streamOptions?: t.EventStreamOptions\n ): Promise<MessageContentComplex[] | undefined> {\n if (this.graphRunnable == null) {\n throw new Error(\n 'Run not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n if (!this.Graph) {\n throw new Error(\n 'Graph not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n const graphRunnable = this.graphRunnable;\n const graph = this.Graph;\n\n /**\n * `Command` inputs (currently only `Command({ resume })`) are\n * resume-mode invocations: LangGraph rebuilds graph state from the\n * checkpointer, so we skip RunStart / UserPromptSubmit hooks (no\n * new prompt to evaluate) and read run-state from the Graph wrapper\n * instead of `inputs.messages`.\n */\n const isResume = inputs instanceof Command;\n const stateInputs = isResume ? undefined : (inputs as t.IState);\n\n const config: Partial<RunnableConfig> & {\n version: 'v1' | 'v2';\n run_id?: string;\n } = {\n recursionLimit: 50,\n ...callerConfig,\n configurable: { ...callerConfig.configurable },\n };\n\n /**\n * Skip `resetValues` on resume — we're continuing an in-flight\n * run, not starting a fresh one. Resetting would wipe the\n * sidecars (`toolCallStepIds`, `stepKeyIds`, accumulated\n * `messages`, etc.) the resumed `ToolNode` needs to dispatch\n * tool completions with the correct step ids and re-resolve\n * `{{tool<i>turn<n>}}` references. Pairs with the\n * `awaitingResume` gate on `clearHeavyState` in the `finally`\n * block so the sidecars survive both ends of the interrupt\n * boundary.\n */\n if (!isResume) {\n graph.resetValues(streamOptions?.keepContent);\n }\n this._interrupt = undefined;\n this._haltedReason = undefined;\n this.hookRegistry?.clearHaltSignal(this.id);\n\n /** Custom event callback to intercept and handle custom events */\n const customEventCallback = this.createCustomEventCallback();\n\n const streamCallbacks = streamOptions?.callbacks\n ? this.getCallbacks(streamOptions.callbacks)\n : undefined;\n\n const customHandler = BaseCallbackHandler.fromMethods({\n [Callback.CUSTOM_EVENT]: customEventCallback,\n });\n customHandler.awaitHandlers = true;\n\n config.callbacks = appendCallbacks(\n config.callbacks,\n streamCallbacks ? [streamCallbacks, customHandler] : [customHandler]\n );\n\n const primaryContext = graph.agentContexts.get(graph.defaultAgentId);\n const userId =\n typeof config.configurable?.user_id === 'string'\n ? config.configurable.user_id\n : undefined;\n const sessionId =\n typeof config.configurable?.thread_id === 'string'\n ? config.configurable.thread_id\n : undefined;\n const traceMetadata = createLangfuseTraceMetadata({\n messageId: this.id,\n parentMessageId: config.configurable?.requestBody?.parentMessageId,\n agentId: graph.defaultAgentId,\n agentName: primaryContext?.name,\n });\n const traceName = config.runName ?? getLangfuseTraceName(traceMetadata);\n const streamLangfuseConfig = this.getStreamLangfuseConfig(graph);\n initializeLangfuseTracing(streamLangfuseConfig);\n const langfuseHandler = createLangfuseHandler({\n langfuse: streamLangfuseConfig,\n userId,\n sessionId,\n traceMetadata,\n tags: ['librechat', 'agent'],\n traceIdSeed:\n streamLangfuseConfig?.deterministicTraceId === true\n ? this.id\n : undefined,\n });\n if (langfuseHandler != null) {\n config.runName = traceName;\n config.callbacks = appendCallbacks(config.callbacks, [langfuseHandler]);\n }\n\n if (!this.id) {\n throw new Error('Run ID not provided');\n }\n\n config.run_id = this.id;\n config.configurable = Object.assign(config.configurable ?? {}, {\n run_id: this.id,\n });\n\n const threadId = config.configurable.thread_id as string | undefined;\n\n if (this.hookRegistry != null && stateInputs != null) {\n const shouldHalt = await this.runPreStreamHooks(\n stateInputs,\n threadId,\n config\n );\n if (shouldHalt) {\n return undefined;\n }\n }\n\n /**\n * Tracks whether the stream loop threw. Used by the `finally`\n * block to decide whether to honor the interrupt-preservation\n * guard for session hooks: a captured `_interrupt` is only\n * meaningful if the stream completed cleanly. If the loop errored\n * after stashing an interrupt (e.g. a downstream handler throws\n * after the interrupt event landed), the interrupt is stale —\n * preserving session hooks would leak them into the next run.\n */\n let streamThrew = false;\n\n const consumeStream = async (): Promise<void> => {\n /**\n * `streamEvents` accepts both state inputs and `Command` (resume) at\n * runtime, but our `CompiledStateWorkflow` type narrows the first\n * arg to `BaseGraphState`. Cast on the call so the resume path\n * type-checks without widening the wrapper for every caller.\n */\n const stream = graphRunnable.streamEvents(inputs as t.IState, config, {\n raiseError: true,\n /**\n * Prevent EventStreamCallbackHandler from processing custom events.\n * Custom events are already handled via our createCustomEventCallback()\n * which routes them through the handlerRegistry.\n * Without this flag, EventStreamCallbackHandler throws errors when\n * custom events are dispatched for run IDs not in its internal map\n * (due to timing issues in parallel execution or after run cleanup).\n */\n ignoreCustomEvent: true,\n });\n\n for await (const event of stream) {\n const { data, metadata, ...info } = event;\n\n const eventName: t.EventName = info.event;\n\n /** Skip custom events as they're handled by our callback */\n if (CUSTOM_GRAPH_EVENTS.has(eventName)) {\n continue;\n }\n\n /**\n * Detect interrupts surfaced by LangGraph as a synthetic\n * `__interrupt__` field on the streamed chunk and stash the\n * first one for the host to read via `run.getInterrupt()`\n * once the stream drains. Captured as `unknown` because the\n * SDK does not validate the runtime payload shape — the\n * built-in ToolNode raises a `HumanInterruptPayload`\n * (`tool_approval` / `ask_user_question`), but custom nodes\n * can pass any payload to `interrupt()`. Callers narrow with\n * the `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt`\n * guards or assert via `getInterrupt<T>()`.\n */\n if (\n this._interrupt == null &&\n data.chunk != null &&\n isInterrupted<unknown>(data.chunk)\n ) {\n const interrupts = data.chunk[INTERRUPT];\n if (interrupts.length > 0) {\n const first = interrupts[0];\n /**\n * Capture the interrupt unconditionally — `interrupt(null)`\n * and `interrupt(undefined)` are valid pauses (a custom\n * node may want to pause without metadata) and the host\n * still needs to know the run is awaiting resume. Gating\n * on `payload != null` would silently downgrade a paused\n * run to \"completed\" and let the `Stop` hook fire,\n * breaking host resume handling.\n */\n this._interrupt = {\n interruptId: first.id ?? '',\n threadId,\n payload: first.value,\n };\n }\n }\n\n const handler = this.handlerRegistry?.getHandler(eventName);\n if (handler) {\n await handler.handle(eventName, data, metadata, this.Graph);\n }\n\n /**\n * Mid-flight halt: any hook (PreToolUse, PostToolUse,\n * PostToolBatch, SubagentStart/Stop, PreCompact, PostCompact)\n * that returned `preventContinuation: true` raises a halt\n * signal on the registry via `executeHooks`. We poll between\n * stream events and break out as soon as one is set so the\n * graph doesn't take another model turn after the halting\n * operation completes.\n *\n * Limitation: the current step (in-flight model call, ongoing\n * tool batch) is not aborted — only the next step is skipped.\n * This matches Claude Code's `continue: false` semantic where\n * the active operation finishes before halting takes effect.\n */\n const haltSignal = this.hookRegistry?.getHaltSignal(this.id);\n if (haltSignal != null) {\n this._haltedReason = haltSignal.reason;\n break;\n }\n }\n\n if (this._interrupt != null) {\n await this.resolveInterruptResumeConfig(config);\n }\n\n /**\n * Skip the Stop hook when the run paused on a HITL interrupt\n * (still pending human input) or was halted by a hook (the host\n * already chose to stop, so a Stop hook firing now would be\n * misleading). The host fires Stop on the resumed-and-completed\n * run instead.\n */\n if (\n this._interrupt == null &&\n this._haltedReason == null &&\n this.hookRegistry?.hasHookFor('Stop', this.id) === true\n ) {\n await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'Stop',\n runId: this.id,\n threadId,\n agentId: graph.defaultAgentId,\n messages: graph.getRunMessages() ?? stateInputs?.messages ?? [],\n stopHookActive: false, // will be true when stop is triggered by a hook (Phase 2)\n },\n sessionId: this.id,\n }).catch(() => {\n /* Stop hook errors must not masquerade as stream failures */\n });\n }\n };\n\n try {\n // When opted in, seed the root trace id from this run's id so feedback /\n // other external signals can be attached to the trace later without a\n // lookup (see SeededTraceIdGenerator in ./instrumentation).\n await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: streamLangfuseConfig,\n langfuseOverlay: this.getStreamToolOutputTracingLangfuseConfig(graph),\n traceIdSeed:\n streamLangfuseConfig?.deterministicTraceId === true\n ? this.id\n : undefined,\n }),\n () =>\n withLangfuseAttributes(\n {\n langfuse: streamLangfuseConfig,\n userId,\n sessionId,\n traceName,\n traceMetadata,\n tags: ['librechat', 'agent'],\n },\n consumeStream\n )\n );\n } catch (err) {\n streamThrew = true;\n if (this.hookRegistry?.hasHookFor('StopFailure', this.id) === true) {\n const runMessages = this.Graph.getRunMessages() ?? [];\n await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'StopFailure',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n error: err instanceof Error ? err.message : String(err),\n lastAssistantMessage: findLastMessageOfType(runMessages, 'ai'),\n },\n sessionId: this.id,\n }).catch(() => {\n /* swallow hook errors — the original error must propagate */\n });\n }\n throw err;\n } finally {\n /**\n * Preserve session-scoped hooks when the run paused on a HITL\n * interrupt — the very next call will be `Run.resume()`, which\n * needs the same policy hooks (e.g., the `PreToolUse` matcher\n * that triggered the interrupt) to fire on the re-executed node\n * and uphold the approval flow. Clearing here would leak the\n * approval gate on resume. The session is cleared instead at\n * natural completion, error (including errors that happen AFTER\n * an interrupt was captured — those interrupts are stale), or\n * hook-driven halt (including hooks that returned BOTH `ask`\n * and `preventContinuation` — the halt wins, no resume is\n * expected, sessions must drop). Every state where no resume\n * is expected clears.\n */\n if (this.shouldClearHookSession(streamThrew)) {\n this.hookRegistry?.clearSession(this.id);\n }\n /**\n * Drop any halt signal raised mid-stream for this run so a\n * subsequent `processStream` / `resume` starts with clean state.\n * The Run captured `_haltedReason` already; the registry entry\n * for this `sessionId` would otherwise spuriously trip the next\n * loop. Other concurrent runs sharing this registry are\n * unaffected — their entries live under their own session ids.\n */\n this.hookRegistry?.clearHaltSignal(this.id);\n await disposeLangfuseHandler(langfuseHandler);\n\n /**\n * Break the reference chain that keeps heavy data alive via\n * LangGraph's internal `__pregel_scratchpad.currentTaskInput` →\n * `@langchain/core` `RunTree.extra[lc:child_config]` →\n * Node.js `AsyncLocalStorage` context captured by timers/promises.\n *\n * Without this, base64-encoded images/PDFs in message content remain\n * reachable from lingering `Timeout` handles until GC runs.\n */\n if (!this.skipCleanup) {\n if (\n (config.configurable as Record<string, unknown> | undefined) != null\n ) {\n for (const key of Object.getOwnPropertySymbols(config.configurable)) {\n const val = config.configurable[key as unknown as string] as\n | Record<string, unknown>\n | undefined;\n if (\n val != null &&\n typeof val === 'object' &&\n 'currentTaskInput' in val\n ) {\n (val as Record<string, unknown>).currentTaskInput = undefined;\n }\n delete config.configurable[key as unknown as string];\n }\n config.configurable = undefined;\n }\n config.callbacks = undefined;\n }\n\n const result = this.returnContent\n ? this.Graph.getContentParts()\n : undefined;\n\n this.calibrationRatio = this.Graph.getCalibrationRatio();\n\n /**\n * Skip `clearHeavyState()` when the run paused on a clean HITL\n * interrupt awaiting resume — `Run.resume()` re-enters the same\n * `ToolNode` instance and needs the sidecars `clearHeavyState`\n * would wipe (`toolCallStepIds` for completion-event step ids,\n * the `_toolOutputRegistry` for `{{tool<i>turn<n>}}`\n * substitutions, `sessions` for code-env continuity, plus the\n * `hookRegistry` and `humanInTheLoop` config the interrupt\n * branch itself relies on). Without preservation, the resumed\n * tool completion would dispatch `ON_RUN_STEP_COMPLETED` with\n * an empty step id and downstream stream consumers would drop\n * the result.\n *\n * The natural-completion / error / hook-driven-halt paths still\n * clean up — `_haltedReason != null` or `streamThrew` mean no\n * resume is expected. Cross-process resume (host rebuilds the\n * Run from scratch) is a separate concern; see\n * `HumanInTheLoopConfig` JSDoc.\n */\n const awaitingResume = this.isAwaitingResume(streamThrew);\n if (!this.skipCleanup && !awaitingResume) {\n this.Graph.clearHeavyState();\n }\n\n this._streamResult = result;\n }\n\n return this._streamResult;\n }\n\n /**\n * Returns the pending interrupt captured during the most recent\n * `processStream` (or `resume`) invocation. `undefined` when the run\n * either has not been streamed yet or completed without pausing.\n *\n * Hosts call this immediately after `processStream` returns to decide\n * whether the run is awaiting human input. Persist the returned\n * descriptor (alongside `thread_id` and the agent run config) so a\n * later `resume(decisions)` can rebuild the run.\n *\n * The default `TPayload` is the SDK's `HumanInterruptPayload` union\n * (`tool_approval` / `ask_user_question`), suitable for the common\n * case where interrupts come from the built-in ToolNode or\n * `askUserQuestion()` helper. Hosts that raise custom interrupts\n * from custom graph nodes pass their own type — the SDK does not\n * validate the runtime shape, it just transports whatever the\n * `interrupt()` call carried. When in doubt, narrow with the\n * `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt` type\n * guards (which accept `unknown`) before reading variant-specific\n * fields.\n */\n getInterrupt<TPayload = t.HumanInterruptPayload>():\n | t.RunInterruptResult<TPayload>\n | undefined {\n return this._interrupt as t.RunInterruptResult<TPayload> | undefined;\n }\n\n /**\n * Returns the reason a hook halted the run via\n * `preventContinuation: true`, or `undefined` if no hook halted.\n *\n * Hosts inspect this after `processStream` returns to distinguish a\n * natural completion (`undefined`) from a hook-driven halt (a\n * truthy string). Independent from `getInterrupt()` — a halted run\n * has no interrupt; an interrupted run has no halt reason.\n */\n getHaltReason(): string | undefined {\n return this._haltedReason;\n }\n\n /**\n * Resume a paused HITL run with the value the user (or whatever\n * decided the interrupt) supplied. The default `TResume` covers the\n * `tool_approval` interrupt (the common case): an array of decisions\n * in `action_requests` order, or a record keyed by `tool_call_id`.\n *\n * For other interrupt types (e.g., `ask_user_question` →\n * `AskUserQuestionResolution`, or any custom interrupt a host raises\n * from a custom node), pass the type parameter and the SDK forwards\n * the value through unchanged. LangGraph delivers it as the return\n * value of the original `interrupt()` call inside the paused node.\n *\n * The host MUST construct this Run with the same `thread_id` and the\n * same checkpointer as the original paused run; LangGraph rebuilds\n * graph state from the checkpoint and re-enters the interrupted node\n * from the start.\n */\n /**\n * Returns the per-Run file checkpointer when\n * `toolExecution.local.fileCheckpointing === true` was set on the\n * RunConfig. Hosts can capture extra paths or call `rewind()`\n * directly. Returns undefined when checkpointing is disabled.\n *\n * Construction-time invariant: the checkpointer is shared across\n * every ToolNode the graph compiles (single-agent and multi-agent),\n * so a `rewind()` call here unwinds writes made by ANY agent in the\n * run.\n */\n getFileCheckpointer(): t.LocalFileCheckpointer | undefined {\n return this.Graph?.getOrCreateFileCheckpointer();\n }\n\n /**\n * Convenience wrapper that calls `rewind()` on the per-Run file\n * checkpointer. Restores every file the local engine snapshotted\n * during this Run to its pre-write content (and deletes any path\n * that didn't exist before being created). Returns the count of\n * paths processed; returns 0 when checkpointing is disabled.\n */\n async rewindFiles(): Promise<number> {\n const cp = this.getFileCheckpointer();\n return cp == null ? 0 : cp.rewind();\n }\n\n async resume<TResume = t.ToolApprovalDecision[] | t.ToolApprovalDecisionMap>(\n resumeValue: TResume,\n callerConfig: Partial<RunnableConfig> & {\n version: 'v1' | 'v2';\n run_id?: string;\n },\n streamOptions?: t.EventStreamOptions\n ): Promise<MessageContentComplex[] | undefined> {\n const interruptId = this._interrupt?.interruptId;\n const scopedResume =\n typeof interruptId === 'string' &&\n interruptId.length > 0 &&\n !isLangGraphResumeMapForInterrupt(resumeValue, interruptId)\n ? { [interruptId]: resumeValue }\n : resumeValue;\n const resumeConfig = await this.resolveInterruptResumeConfig(callerConfig);\n return this.processStream(\n new Command({ resume: scopedResume }),\n resumeConfig,\n streamOptions\n );\n }\n\n private async resolveInterruptResumeConfig(\n callerConfig: Partial<RunnableConfig> & {\n version: 'v1' | 'v2';\n run_id?: string;\n }\n ): Promise<\n Partial<RunnableConfig> & {\n version: 'v1' | 'v2';\n run_id?: string;\n }\n > {\n const interrupt = this._interrupt;\n const interruptId = interrupt?.interruptId;\n const workflow = this.graphRunnable as\n | (t.CompiledStateWorkflow & WorkflowWithStateHistory)\n | undefined;\n const stateHistory = workflow?.getStateHistory;\n if (interrupt?.checkpointId != null && interrupt.checkpointId.length > 0) {\n return {\n ...callerConfig,\n configurable: {\n ...callerConfig.configurable,\n checkpoint_id: interrupt.checkpointId,\n ...(typeof interrupt.checkpointNs === 'string'\n ? { checkpoint_ns: interrupt.checkpointNs }\n : {}),\n },\n };\n }\n if (\n interrupt == null ||\n typeof interruptId !== 'string' ||\n interruptId.length === 0 ||\n typeof stateHistory !== 'function'\n ) {\n return callerConfig;\n }\n\n for await (const snapshot of stateHistory.call(\n this.graphRunnable,\n callerConfig as RunnableConfig\n )) {\n const hasMatchingInterrupt =\n snapshot.tasks?.some(\n (task) =>\n task.interrupts?.some(\n (interrupt) => interrupt.id === interruptId\n ) === true\n ) === true;\n const checkpointConfigurable = snapshot.config?.configurable;\n if (!hasMatchingInterrupt || checkpointConfigurable == null) {\n continue;\n }\n\n const checkpointId = checkpointConfigurable.checkpoint_id;\n const checkpointNs = checkpointConfigurable.checkpoint_ns;\n if (typeof checkpointId === 'string' && checkpointId.length > 0) {\n this._interrupt = {\n ...interrupt,\n checkpointId,\n ...(typeof checkpointNs === 'string' ? { checkpointNs } : {}),\n };\n return {\n ...callerConfig,\n configurable: {\n ...callerConfig.configurable,\n checkpoint_id: checkpointId,\n ...(typeof checkpointNs === 'string'\n ? { checkpoint_ns: checkpointNs }\n : {}),\n },\n };\n }\n }\n\n return callerConfig;\n }\n\n private createSystemCallback<K extends keyof t.ClientCallbacks>(\n clientCallbacks: t.ClientCallbacks,\n key: K\n ): t.SystemCallbacks[K] {\n return ((...args: unknown[]) => {\n const clientCallback = clientCallbacks[key];\n if (clientCallback && this.Graph) {\n (clientCallback as (...args: unknown[]) => void)(this.Graph, ...args);\n }\n }) as t.SystemCallbacks[K];\n }\n\n getCallbacks(clientCallbacks: t.ClientCallbacks): t.SystemCallbacks {\n return {\n [Callback.TOOL_ERROR]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_ERROR\n ),\n [Callback.TOOL_START]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_START\n ),\n [Callback.TOOL_END]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_END\n ),\n };\n }\n\n async generateTitle({\n provider,\n inputText,\n contentParts,\n titlePrompt,\n clientOptions,\n chainOptions,\n skipLanguage,\n titleMethod = TitleMethod.COMPLETION,\n titlePromptTemplate,\n }: t.RunTitleOptions): Promise<{ language?: string; title?: string }> {\n let titleLangfuseHandler: CallbackEntry | undefined;\n let titleLangfuseConfig: t.LangfuseConfig | undefined;\n let titleUserId: string | undefined;\n let titleSessionId: string | undefined;\n const titleContext =\n this.Graph == null\n ? undefined\n : this.Graph.agentContexts.get(this.Graph.defaultAgentId);\n const traceMetadata = createLangfuseTraceMetadata({\n messageId: 'title-' + this.id,\n agentName: titleContext?.name,\n });\n const titleRunName = getLangfuseTraceName(traceMetadata, 'LibreChat Title');\n\n if (chainOptions != null) {\n titleUserId =\n typeof chainOptions.configurable?.user_id === 'string'\n ? chainOptions.configurable.user_id\n : undefined;\n titleSessionId =\n typeof chainOptions.configurable?.thread_id === 'string'\n ? chainOptions.configurable.thread_id\n : undefined;\n titleLangfuseConfig = resolveLangfuseConfig(\n this.langfuse,\n titleContext?.langfuse\n );\n initializeLangfuseTracing(titleLangfuseConfig);\n titleLangfuseHandler = createLangfuseHandler({\n langfuse: titleLangfuseConfig,\n userId: titleUserId,\n sessionId: titleSessionId,\n traceMetadata,\n tags: ['librechat', 'title'],\n traceIdSeed:\n titleLangfuseConfig?.deterministicTraceId === true\n ? 'title-' + this.id\n : undefined,\n });\n\n if (titleLangfuseHandler != null) {\n chainOptions.callbacks = appendCallbacks(chainOptions.callbacks, [\n titleLangfuseHandler,\n ]);\n }\n }\n\n const convoTemplate = PromptTemplate.fromTemplate(\n titlePromptTemplate ?? 'User: {input}\\nAI: {output}'\n );\n\n const response = contentParts\n .map((part) => {\n if (part?.type === 'text') return part.text;\n return '';\n })\n .join('\\n');\n\n const model = initializeModel({\n provider,\n clientOptions,\n }) as t.ChatModelInstance;\n\n if (\n isOpenAILike(provider) &&\n (model instanceof ChatOpenAI || model instanceof AzureChatOpenAI)\n ) {\n model.temperature = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.temperature as number;\n model.topP = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.topP as number;\n model.frequencyPenalty = (\n clientOptions as t.OpenAIClientOptions | undefined\n )?.frequencyPenalty as number;\n model.presencePenalty = (\n clientOptions as t.OpenAIClientOptions | undefined\n )?.presencePenalty as number;\n model.n = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.n as number;\n }\n\n const convoToTitleInput = new RunnableLambda({\n func: (\n promptValue: StringPromptValue\n ): { convo: string; inputText: string; skipLanguage?: boolean } => ({\n convo: promptValue.value,\n inputText,\n skipLanguage,\n }),\n }).withConfig({ runName: 'ConvoTransform' });\n\n const titleChain =\n titleMethod === TitleMethod.COMPLETION\n ? await createCompletionTitleRunnable(model, titlePrompt)\n : await createTitleRunnable(model, titlePrompt);\n\n /** Pipes `convoTemplate` -> `transformer` -> `titleChain` */\n const fullChain = convoTemplate\n .withConfig({ runName: 'ConvoTemplate' })\n .pipe(convoToTitleInput)\n .pipe(titleChain)\n .withConfig({ runName: 'TitleChain' });\n\n const invokeConfig = Object.assign({}, chainOptions, {\n run_id: this.id,\n runId: this.id,\n runName: chainOptions?.runName ?? titleRunName,\n });\n\n const invokeTitleChain = (\n runtimeConfig: Partial<RunnableConfig>\n ): Promise<{ language?: string; title?: string }> =>\n withLangfuseAttributes(\n {\n langfuse: titleLangfuseConfig,\n userId: titleUserId,\n sessionId: titleSessionId,\n traceName: runtimeConfig.runName ?? titleRunName,\n traceMetadata,\n tags: ['librechat', 'title'],\n },\n () =>\n fullChain.invoke(\n { input: inputText, output: response },\n runtimeConfig\n )\n );\n\n try {\n try {\n return await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: this.langfuse,\n langfuseOverlay: titleContext?.langfuse,\n }),\n () => invokeTitleChain(invokeConfig)\n );\n } catch (_e) {\n // Fallback: strip callbacks to avoid EventStream tracer errors in certain environments\n // but preserve Langfuse tracing if it exists.\n const langfuseHandler = findCallback(\n invokeConfig.callbacks,\n isLangfuseCallbackHandler\n );\n const { callbacks: _cb, ...rest } = invokeConfig;\n const safeConfig = Object.assign({}, rest, {\n callbacks: langfuseHandler ? [langfuseHandler] : [],\n });\n return await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: this.langfuse,\n langfuseOverlay: titleContext?.langfuse,\n }),\n () => invokeTitleChain(safeConfig as Partial<RunnableConfig>)\n );\n }\n } finally {\n await disposeLangfuseHandler(titleLangfuseHandler);\n }\n }\n}\n\nfunction findLastMessageOfType(\n messages: BaseMessage[],\n type: string\n): BaseMessage | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].getType() === type) {\n return messages[i];\n }\n }\n return undefined;\n}\n\nfunction extractPromptText(message: BaseMessage): string {\n const content = message.content;\n if (typeof content === 'string') {\n return content;\n }\n if (!Array.isArray(content)) {\n return String(content);\n }\n const parts: string[] = [];\n for (const block of content) {\n if (\n typeof block === 'object' &&\n 'type' in block &&\n block.type === 'text' &&\n 'text' in block &&\n typeof block.text === 'string'\n ) {\n parts.push(block.text);\n }\n }\n return parts.join('\\n');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoDA,MAAa,qBAAqB,IAAI,IAAI;CACxC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,sBAAsB,IAAI,IAAY;;;;;;;;;;;;;;;AAe5C,CAAC;AAED,MAAM,gCAAgC,IAAI,IAAY;;;;;AAKtD,CAAC;AAED,SAAS,qBAAqB,MAAmC;CAC/D,IAAI,QAAQ,QAAQ,OAAO,SAAS,UAClC;CAEF,MAAM,YAAY;CAClB,OAAO,OAAO,UAAU,OAAO,WAAW,UAAU,KAAK,KAAA;AAC3D;AAEA,SAAS,iCACP,OACA,aACkC;CAClC,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GACpE,OAAO;CAET,OAAO,OAAO,UAAU,eAAe,KAAK,OAAO,WAAW;AAChE;AAeA,IAAa,MAAb,MAAa,IAAiC;CAC5C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,mBAA2B;CAC3B;CACA;CACA,gBAAyB;CACzB,cAA+B;CAC/B;;;;;;;;CAQA;CACA;CAEA,YAAoB,QAA8B;EAChD,MAAM,QAAQ,OAAO,SAAS;EAC9B,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,qBAAqB;EAGvC,KAAK,KAAK;EACV,KAAK,eAAe,OAAO;EAC3B,KAAK,qBAAqB,OAAO;EACjC,IAAI,OAAO,oBAAoB,QAAQ,OAAO,mBAAmB,GAC/D,KAAK,mBAAmB,OAAO;EAGjC,MAAM,kBAAkB,IAAI,gBAAgB;EAE5C,IAAI,OAAO,gBACT,KAAK,MAAM,CAAC,WAAW,YAAY,OAAO,QACxC,OAAO,cACT,GACE,gBAAgB,SAAS,WAAW,OAAO;EAI/C,KAAK,kBAAkB;EACvB,KAAK,eAAe,OAAO;EAC3B,KAAK,iBAAiB,OAAO;EAC7B,KAAK,WAAW,OAAO;EACvB,KAAK,uBAAuB,OAAO;EACnC,KAAK,0BAA0B,OAAO;EACtC,KAAK,gBAAgB,OAAO;EAC5B,KAAK,oBAAoB,OAAO;EAEhC,IAAI,CAAC,OAAO,aACV,MAAM,IAAI,MAAM,2BAA2B;;EAI7C,IAAI,OAAO,YAAY,SAAS,eAAe;GAC7C,KAAK,gBAAgB,KAAK,sBAAsB,OAAO,WAAW;GAClE,IAAI,KAAK,OACP,KAAK,MAAM,kBAAkB;EAEjC,OAAO;;GAEL,KAAK,gBAAgB,KAAK,kBAAkB,OAAO,WAAW;GAC9D,IAAI,KAAK,OAAO;IACd,KAAK,MAAM,iBACT,OAAO,YAAY,kBAAkB,KAAK,MAAM;IAClD,KAAK,MAAM,kBAAkB;GAC/B;EACF;EAEA,IAAI,OAAO,mBAAmB,KAAK,OACjC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,iBAChC,KAAK,MAAM,SAAS,IAAI,KAAK,KAAK;EAItC,KAAK,gBAAgB,OAAO,iBAAiB;EAC7C,KAAK,cAAc,OAAO,eAAe;CAC3C;CAEA,kBACE,QACyB;EACzB,IAAI;EACJ,IAAI;;EAGJ,IAAI,YAAY,UAAU,MAAM,QAAQ,OAAO,MAAM,GAAG;GACtD,IAAI,OAAO,OAAO,WAAW,GAC3B,MAAM,IAAI,MAAM,qCAAqC;GAEvD,cAAc,OAAO,OAAO;GAC5B,SAAS,OAAO;EAClB,OAAO;;GAEL,MAAM,EACJ,MAAM,OACN,WACA,QAAQ,cACR,QAAQ,CAAC,GACT,GAAG,gBACD;GACJ,MAAM,EAAE,UAAU,GAAG,kBAAkB;GAEvC,cAAc;IACZ,GAAG;IACH;IACA;IACA;IACA,SAAS;GACX;GACA,SAAS;EACX;EAEA,MAAM,gBAAgB,IAAI,cAAc;GACtC;GACA,OAAO,KAAK;GACZ,QAAQ,CAAC,WAAW;GACpB,UAAU,KAAK;GACf,cAAc,KAAK;GACnB,oBAAoB,KAAK;GACzB,kBAAkB,KAAK;GACvB,mBAAmB,KAAK;EAC1B,CAAC;;EAED,cAAc,iBAAiB,KAAK,8BAClC,OAAO,cACT;EACA,cAAc,eAAe,KAAK;EAClC,cAAc,iBAAiB,KAAK;EACpC,cAAc,uBAAuB,KAAK;EAC1C,cAAc,0BAA0B,KAAK;EAC7C,cAAc,gBAAgB,KAAK;EACnC,KAAK,QAAQ;EACb,OAAO,cAAc,eAAe;CACtC;CAEA,sBACE,QACyB;EACzB,MAAM,EAAE,QAAQ,OAAO,mBAAmB;EAE1C,MAAM,kBAAkB,IAAI,gBAAgB;GAC1C,OAAO,KAAK;GACZ;GACA;GACA,UAAU,KAAK;GACf,cAAc,KAAK;GACnB,oBAAoB,KAAK;GACzB,kBAAkB,KAAK;GACvB,mBAAmB,KAAK;EAC1B,CAAC;EAED,gBAAgB,iBACd,KAAK,8BAA8B,cAAc;EAEnD,gBAAgB,eAAe,KAAK;EACpC,gBAAgB,iBAAiB,KAAK;EACtC,gBAAgB,uBAAuB,KAAK;EAC5C,gBAAgB,0BAA0B,KAAK;EAC/C,gBAAgB,gBAAgB,KAAK;EACrC,KAAK,QAAQ;EACb,OAAO,gBAAgB,eAAe;CACxC;;;;;;;;;;;;;;;CAgBA,8BACE,gBAC8B;EAC9B,IAAI,KAAK,gBAAgB,YAAY,MACnC,OAAO;EAET,IAAI,gBAAgB,gBAAgB,MAClC,OAAO;EAET,OAAO;GACL,GAAI,kBAAkB,CAAC;GACvB,cAAc,IAAI,YAAY;EAChC;CACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCA,MAAc,kBACZ,aACA,UACA,QACkB;EAClB,MAAM,WAAW,KAAK;;;;;;;EAOtB,IAAI,YAAY,QAAQ,KAAK,SAAS,MACpC,OAAO;EAGT,MAAM,oBAA8B,CAAC;EAErC,MAAM,iBAAiB,MAAM,aAAa;GACxC;GACA,OAAO;IACL,iBAAiB;IACjB,OAAO,KAAK;IACZ;IACA,SAAS,KAAK,MAAM;IACpB,UAAU,YAAY;GACxB;GACA,WAAW,KAAK;EAClB,CAAC;EACD,KAAK,MAAM,OAAO,eAAe,oBAC/B,kBAAkB,KAAK,GAAG;;;;;;;;EAS5B,IAAI,eAAe,wBAAwB,MAAM;GAC/C,KAAK,gBAAgB,eAAe,cAAc;GAClD,SAAS,aAAa,KAAK,EAAE;GAC7B,SAAS,gBAAgB,KAAK,EAAE;GAChC,OAAO,YAAY,KAAA;GACnB,OAAO;EACT;EAEA,MAAM,YAAY,sBAAsB,YAAY,UAAU,OAAO;EACrE,IAAI,aAAa,MAAM;GACrB,MAAM,eAAe,MAAM,aAAa;IACtC;IACA,OAAO;KACL,iBAAiB;KACjB,OAAO,KAAK;KACZ;KACA,SAAS,KAAK,MAAM;KACpB,QAAQ,kBAAkB,SAAS;IAGrC;IACA,WAAW,KAAK;GAClB,CAAC;GACD,IACE,aAAa,aAAa,UAC1B,aAAa,aAAa,SAC1B,aAAa,wBAAwB,MACrC;;;;;;;;IAQA,IAAI,aAAa,wBAAwB,MACvC,KAAK,gBAAgB,aAAa,cAAc;SAC3C,IAAI,aAAa,aAAa,QACnC,KAAK,gBAAgB,aAAa,UAAU;SAE5C,KAAK,gBACH,aAAa,UAAU;IAE3B,SAAS,aAAa,KAAK,EAAE;IAC7B,SAAS,gBAAgB,KAAK,EAAE;IAChC,OAAO,YAAY,KAAA;IACnB,OAAO;GACT;GACA,KAAK,MAAM,OAAO,aAAa,oBAC7B,kBAAkB,KAAK,GAAG;EAE9B;EAEA,IAAI,kBAAkB,SAAS;;;;;;;;;;;;;EAa7B,YAAY,SAAS,KACnB,IAAI,aAAa;GACf,SAAS,kBAAkB,KAAK,MAAM;GACtC,mBAAmB;IAAE,MAAM;IAAU,QAAQ;GAAO;EACtD,CAAC,CACH;EAGF,OAAO;CACT;CAEA,aAAa,OACX,QACiB;;EAEjB,IAAI,OAAO,sBAAsB,CAAC,OAAO,cAAc;GACrD,MAAM,KAAK,OAAO;GAIlB,OAAO,eAAe,MAAM,mBAAmB,kBAF7C,YAAY,KAAK,GAAG,OAAO,EAAE,EAAE,gBAAgB,GAAG,cAAA,EACU,SAAS,EACF,CAAC;EACxE;EACA,OAAO,IAAI,IAAO,MAAM;CAC1B;CAEA,iBAA4C;EAC1C,IAAI,CAAC,KAAK,OACR,MAAM,IAAI,MACR,8EACF;EAEF,OAAO,KAAK,MAAM,eAAe;CACnC;;;;;;;CAQA,sBAA8B;EAC5B,OAAO,KAAK;CACd;CAEA,iCAAqD;EACnD,OAAO,KAAK,OAAO,+BAA+B;CACpD;CAEA,eAAuB;EACrB,OAAO,KAAK,OAAO,aAAa,KAAK;CACvC;;;;;CAMA,4BAAoC;EAClC,OAAO,OACL,WACA,MACA,OACA,MACA,aACkB;GAIlB,MAAM,oBAAoB,qBAAqB,IAAI;GACnD,IACE,8BAA8B,IAAI,SAAS,KAC3C,KAAK,SAAS,QACd,qBAAqB,QACrB,KAAK,MAAM,0BAA0B,WAAW,iBAAiB,GAEjE;GAEF,MAAM,UAAU,KAAK,iBAAiB,WAAW,SAAS;GAC1D,IAAI,WAAW,KAAK,OAClB,OAAO,MAAM,QAAQ,OACnB,WACA,MAQA,UACA,KAAK,KACP;EAEJ;CACF;CAEA,uBAA+B,aAA+B;EAC5D,OAAO,KAAK,cAAc,QAAQ,KAAK,iBAAiB,QAAQ;CAClE;CAEA,iBAAyB,aAA+B;EACtD,OACE,KAAK,cAAc,QAAQ,KAAK,iBAAiB,QAAQ,CAAC;CAE9D;CAEA,wBACE,OAC8B;EAC9B,MAAM,iBAAiB,MAAM,cAAc,IAAI,MAAM,cAAc;EACnE,IAAI,kBAAkB,MACpB,OAAO,sBAAsB,KAAK,UAAU,eAAe,QAAQ;EAGrE,KAAK,MAAM,WAAW,MAAM,cAAc,OAAO,GAAG;GAClD,MAAM,WAAW,sBAAsB,KAAK,UAAU,QAAQ,QAAQ;GACtE,IAAI,YAAY,MACd,OAAO;EAEX;EAEA,OAAO,KAAK;CACd;CAEA,yCACE,OAC8B;EAC9B,MAAM,2BAA2B,MAAM,KAAK,MAAM,cAAc,OAAO,CAAC,CAAC,CACtE,KAAK,YAAY;GAChB,OAAO,sBAAsB,KAAK,UAAU,QAAQ,QAAQ,CAAC,EACzD;EACN,CAAC,CAAC,CACD,QAAQ,WAAwD;GAC/D,OAAO,UAAU;EACnB,CAAC;EAEH,IAAI,yBAAyB,WAAW,GACtC,OAAO,KAAK,UAAU,qBAAqB,OACvC,EAAE,mBAAmB,KAAK,SAAS,kBAAkB,IACrD,KAAA;EAEN,IAAI,yBAAyB,WAAW,GACtC,OAAO,EAAE,mBAAmB,yBAAyB,GAAG;EAG1D,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,MAAM,oCAAoB,IAAI,IAAY;EAE1C,KAAK,MAAM,UAAU,0BAA0B;GAC7C,IAAI,OAAO,YAAY,OACrB,UAAU;QACL,IAAI,YAAY,SAAS,OAAO,WAAW,MAChD,UAAU,OAAO;GAGnB,kBAAkB,OAAO;GACzB,IAAI,OAAO,8BAA8B,WACvC,4BAA4B;QAE5B,8BAA8B,OAAO;GAGvC,KAAK,MAAM,YAAY,OAAO,qBAAqB,CAAC,GAClD,kBAAkB,IAAI,QAAQ;EAElC;EAEA,OAAO,EACL,mBAAmB;GACjB,GAAI,WAAW,OAAO,EAAE,QAAQ,IAAI,CAAC;GACrC,GAAI,kBAAkB,OAAO,IACzB,EAAE,mBAAmB,MAAM,KAAK,iBAAiB,EAAE,IACnD,CAAC;GACL,GAAI,6BAA6B,OAC7B,EAAE,0BAA0B,IAC5B,CAAC;GACL,GAAI,iBAAiB,OAAO,EAAE,cAAc,IAAI,CAAC;EACnD,EACF;CACF;CAEA,MAAM,cACJ,QACA,cAIA,eAC8C;EAC9C,IAAI,KAAK,iBAAiB,MACxB,MAAM,IAAI,MACR,4EACF;EAEF,IAAI,CAAC,KAAK,OACR,MAAM,IAAI,MACR,8EACF;EAEF,MAAM,gBAAgB,KAAK;EAC3B,MAAM,QAAQ,KAAK;;;;;;;;EASnB,MAAM,WAAW,kBAAkB;EACnC,MAAM,cAAc,WAAW,KAAA,IAAa;EAE5C,MAAM,SAGF;GACF,gBAAgB;GAChB,GAAG;GACH,cAAc,EAAE,GAAG,aAAa,aAAa;EAC/C;;;;;;;;;;;;EAaA,IAAI,CAAC,UACH,MAAM,YAAY,eAAe,WAAW;EAE9C,KAAK,aAAa,KAAA;EAClB,KAAK,gBAAgB,KAAA;EACrB,KAAK,cAAc,gBAAgB,KAAK,EAAE;;EAG1C,MAAM,sBAAsB,KAAK,0BAA0B;EAE3D,MAAM,kBAAkB,eAAe,YACnC,KAAK,aAAa,cAAc,SAAS,IACzC,KAAA;EAEJ,MAAM,gBAAgB,oBAAoB,YAAY,GAAA,sBAC3B,oBAC3B,CAAC;EACD,cAAc,gBAAgB;EAE9B,OAAO,YAAY,gBACjB,OAAO,WACP,kBAAkB,CAAC,iBAAiB,aAAa,IAAI,CAAC,aAAa,CACrE;EAEA,MAAM,iBAAiB,MAAM,cAAc,IAAI,MAAM,cAAc;EACnE,MAAM,SACJ,OAAO,OAAO,cAAc,YAAY,WACpC,OAAO,aAAa,UACpB,KAAA;EACN,MAAM,YACJ,OAAO,OAAO,cAAc,cAAc,WACtC,OAAO,aAAa,YACpB,KAAA;EACN,MAAM,gBAAgB,4BAA4B;GAChD,WAAW,KAAK;GAChB,iBAAiB,OAAO,cAAc,aAAa;GACnD,SAAS,MAAM;GACf,WAAW,gBAAgB;EAC7B,CAAC;EACD,MAAM,YAAY,OAAO,WAAW,qBAAqB,aAAa;EACtE,MAAM,uBAAuB,KAAK,wBAAwB,KAAK;EAC/D,0BAA0B,oBAAoB;EAC9C,MAAM,kBAAkB,sBAAsB;GAC5C,UAAU;GACV;GACA;GACA;GACA,MAAM,CAAC,aAAa,OAAO;GAC3B,aACE,sBAAsB,yBAAyB,OAC3C,KAAK,KACL,KAAA;EACR,CAAC;EACD,IAAI,mBAAmB,MAAM;GAC3B,OAAO,UAAU;GACjB,OAAO,YAAY,gBAAgB,OAAO,WAAW,CAAC,eAAe,CAAC;EACxE;EAEA,IAAI,CAAC,KAAK,IACR,MAAM,IAAI,MAAM,qBAAqB;EAGvC,OAAO,SAAS,KAAK;EACrB,OAAO,eAAe,OAAO,OAAO,OAAO,gBAAgB,CAAC,GAAG,EAC7D,QAAQ,KAAK,GACf,CAAC;EAED,MAAM,WAAW,OAAO,aAAa;EAErC,IAAI,KAAK,gBAAgB,QAAQ,eAAe;OAM1C,MALqB,KAAK,kBAC5B,aACA,UACA,MACF,GAEE;EAAA;;;;;;;;;;EAaJ,IAAI,cAAc;EAElB,MAAM,gBAAgB,YAA2B;;;;;;;GAO/C,MAAM,SAAS,cAAc,aAAa,QAAoB,QAAQ;IACpE,YAAY;;;;;;;;;IASZ,mBAAmB;GACrB,CAAC;GAED,WAAW,MAAM,SAAS,QAAQ;IAChC,MAAM,EAAE,MAAM,UAAU,GAAG,SAAS;IAEpC,MAAM,YAAyB,KAAK;;IAGpC,IAAI,oBAAoB,IAAI,SAAS,GACnC;;;;;;;;;;;;;IAeF,IACE,KAAK,cAAc,QACnB,KAAK,SAAS,QACd,cAAuB,KAAK,KAAK,GACjC;KACA,MAAM,aAAa,KAAK,MAAM;KAC9B,IAAI,WAAW,SAAS,GAAG;MACzB,MAAM,QAAQ,WAAW;;;;;;;;;;MAUzB,KAAK,aAAa;OAChB,aAAa,MAAM,MAAM;OACzB;OACA,SAAS,MAAM;MACjB;KACF;IACF;IAEA,MAAM,UAAU,KAAK,iBAAiB,WAAW,SAAS;IAC1D,IAAI,SACF,MAAM,QAAQ,OAAO,WAAW,MAAM,UAAU,KAAK,KAAK;;;;;;;;;;;;;;;IAiB5D,MAAM,aAAa,KAAK,cAAc,cAAc,KAAK,EAAE;IAC3D,IAAI,cAAc,MAAM;KACtB,KAAK,gBAAgB,WAAW;KAChC;IACF;GACF;GAEA,IAAI,KAAK,cAAc,MACrB,MAAM,KAAK,6BAA6B,MAAM;;;;;;;;GAUhD,IACE,KAAK,cAAc,QACnB,KAAK,iBAAiB,QACtB,KAAK,cAAc,WAAW,QAAQ,KAAK,EAAE,MAAM,MAEnD,MAAM,aAAa;IACjB,UAAU,KAAK;IACf,OAAO;KACL,iBAAiB;KACjB,OAAO,KAAK;KACZ;KACA,SAAS,MAAM;KACf,UAAU,MAAM,eAAe,KAAK,aAAa,YAAY,CAAC;KAC9D,gBAAgB;IAClB;IACA,WAAW,KAAK;GAClB,CAAC,CAAC,CAAC,YAAY,CAEf,CAAC;EAEL;EAEA,IAAI;GAIF,MAAM,yBACJ,4BAA4B;IAC1B,aAAa;IACb,iBAAiB,KAAK,yCAAyC,KAAK;IACpE,aACE,sBAAsB,yBAAyB,OAC3C,KAAK,KACL,KAAA;GACR,CAAC,SAEC,uBACE;IACE,UAAU;IACV;IACA;IACA;IACA;IACA,MAAM,CAAC,aAAa,OAAO;GAC7B,GACA,aACF,CACJ;EACF,SAAS,KAAK;GACZ,cAAc;GACd,IAAI,KAAK,cAAc,WAAW,eAAe,KAAK,EAAE,MAAM,MAAM;IAClE,MAAM,cAAc,KAAK,MAAM,eAAe,KAAK,CAAC;IACpD,MAAM,aAAa;KACjB,UAAU,KAAK;KACf,OAAO;MACL,iBAAiB;MACjB,OAAO,KAAK;MACZ;MACA,SAAS,KAAK,MAAM;MACpB,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;MACtD,sBAAsB,sBAAsB,aAAa,IAAI;KAC/D;KACA,WAAW,KAAK;IAClB,CAAC,CAAC,CAAC,YAAY,CAEf,CAAC;GACH;GACA,MAAM;EACR,UAAU;;;;;;;;;;;;;;;GAeR,IAAI,KAAK,uBAAuB,WAAW,GACzC,KAAK,cAAc,aAAa,KAAK,EAAE;;;;;;;;;GAUzC,KAAK,cAAc,gBAAgB,KAAK,EAAE;GAC1C,MAAM,uBAAuB,eAAe;;;;;;;;;;GAW5C,IAAI,CAAC,KAAK,aAAa;IACrB,IACG,OAAO,gBAAwD,MAChE;KACA,KAAK,MAAM,OAAO,OAAO,sBAAsB,OAAO,YAAY,GAAG;MACnE,MAAM,MAAM,OAAO,aAAa;MAGhC,IACE,OAAO,QACP,OAAO,QAAQ,YACf,sBAAsB,KAEtB,IAAiC,mBAAmB,KAAA;MAEtD,OAAO,OAAO,aAAa;KAC7B;KACA,OAAO,eAAe,KAAA;IACxB;IACA,OAAO,YAAY,KAAA;GACrB;GAEA,MAAM,SAAS,KAAK,gBAChB,KAAK,MAAM,gBAAgB,IAC3B,KAAA;GAEJ,KAAK,mBAAmB,KAAK,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;GAqBvD,MAAM,iBAAiB,KAAK,iBAAiB,WAAW;GACxD,IAAI,CAAC,KAAK,eAAe,CAAC,gBACxB,KAAK,MAAM,gBAAgB;GAG7B,KAAK,gBAAgB;EACvB;EAEA,OAAO,KAAK;CACd;;;;;;;;;;;;;;;;;;;;;;CAuBA,eAEc;EACZ,OAAO,KAAK;CACd;;;;;;;;;;CAWA,gBAAoC;EAClC,OAAO,KAAK;CACd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BA,sBAA2D;EACzD,OAAO,KAAK,OAAO,4BAA4B;CACjD;;;;;;;;CASA,MAAM,cAA+B;EACnC,MAAM,KAAK,KAAK,oBAAoB;EACpC,OAAO,MAAM,OAAO,IAAI,GAAG,OAAO;CACpC;CAEA,MAAM,OACJ,aACA,cAIA,eAC8C;EAC9C,MAAM,cAAc,KAAK,YAAY;EACrC,MAAM,eACJ,OAAO,gBAAgB,YACvB,YAAY,SAAS,KACrB,CAAC,iCAAiC,aAAa,WAAW,IACtD,GAAG,cAAc,YAAY,IAC7B;EACN,MAAM,eAAe,MAAM,KAAK,6BAA6B,YAAY;EACzE,OAAO,KAAK,cACV,IAAI,QAAQ,EAAE,QAAQ,aAAa,CAAC,GACpC,cACA,aACF;CACF;CAEA,MAAc,6BACZ,cASA;EACA,MAAM,YAAY,KAAK;EACvB,MAAM,cAAc,WAAW;EAI/B,MAAM,eAHW,KAAK,eAGS;EAC/B,IAAI,WAAW,gBAAgB,QAAQ,UAAU,aAAa,SAAS,GACrE,OAAO;GACL,GAAG;GACH,cAAc;IACZ,GAAG,aAAa;IAChB,eAAe,UAAU;IACzB,GAAI,OAAO,UAAU,iBAAiB,WAClC,EAAE,eAAe,UAAU,aAAa,IACxC,CAAC;GACP;EACF;EAEF,IACE,aAAa,QACb,OAAO,gBAAgB,YACvB,YAAY,WAAW,KACvB,OAAO,iBAAiB,YAExB,OAAO;EAGT,WAAW,MAAM,YAAY,aAAa,KACxC,KAAK,eACL,YACF,GAAG;GACD,MAAM,uBACJ,SAAS,OAAO,MACb,SACC,KAAK,YAAY,MACd,cAAc,UAAU,OAAO,WAClC,MAAM,IACV,MAAM;GACR,MAAM,yBAAyB,SAAS,QAAQ;GAChD,IAAI,CAAC,wBAAwB,0BAA0B,MACrD;GAGF,MAAM,eAAe,uBAAuB;GAC5C,MAAM,eAAe,uBAAuB;GAC5C,IAAI,OAAO,iBAAiB,YAAY,aAAa,SAAS,GAAG;IAC/D,KAAK,aAAa;KAChB,GAAG;KACH;KACA,GAAI,OAAO,iBAAiB,WAAW,EAAE,aAAa,IAAI,CAAC;IAC7D;IACA,OAAO;KACL,GAAG;KACH,cAAc;MACZ,GAAG,aAAa;MAChB,eAAe;MACf,GAAI,OAAO,iBAAiB,WACxB,EAAE,eAAe,aAAa,IAC9B,CAAC;KACP;IACF;GACF;EACF;EAEA,OAAO;CACT;CAEA,qBACE,iBACA,KACsB;EACtB,SAAS,GAAG,SAAoB;GAC9B,MAAM,iBAAiB,gBAAgB;GACvC,IAAI,kBAAkB,KAAK,OACzB,eAAiD,KAAK,OAAO,GAAG,IAAI;EAExE;CACF;CAEA,aAAa,iBAAuD;EAClE,OAAO;wBACkB,KAAK,qBAC1B,iBAAA,iBAEF;wBACuB,KAAK,qBAC1B,iBAAA,iBAEF;sBACqB,KAAK,qBACxB,iBAAA,eAEF;EACF;CACF;CAEA,MAAM,cAAc,EAClB,UACA,WACA,cACA,aACA,eACA,cACA,cACA,cAAA,cACA,uBACoE;EACpE,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,MAAM,eACJ,KAAK,SAAS,OACV,KAAA,IACA,KAAK,MAAM,cAAc,IAAI,KAAK,MAAM,cAAc;EAC5D,MAAM,gBAAgB,4BAA4B;GAChD,WAAW,WAAW,KAAK;GAC3B,WAAW,cAAc;EAC3B,CAAC;EACD,MAAM,eAAe,qBAAqB,eAAe,iBAAiB;EAE1E,IAAI,gBAAgB,MAAM;GACxB,cACE,OAAO,aAAa,cAAc,YAAY,WAC1C,aAAa,aAAa,UAC1B,KAAA;GACN,iBACE,OAAO,aAAa,cAAc,cAAc,WAC5C,aAAa,aAAa,YAC1B,KAAA;GACN,sBAAsB,sBACpB,KAAK,UACL,cAAc,QAChB;GACA,0BAA0B,mBAAmB;GAC7C,uBAAuB,sBAAsB;IAC3C,UAAU;IACV,QAAQ;IACR,WAAW;IACX;IACA,MAAM,CAAC,aAAa,OAAO;IAC3B,aACE,qBAAqB,yBAAyB,OAC1C,WAAW,KAAK,KAChB,KAAA;GACR,CAAC;GAED,IAAI,wBAAwB,MAC1B,aAAa,YAAY,gBAAgB,aAAa,WAAW,CAC/D,oBACF,CAAC;EAEL;EAEA,MAAM,gBAAgB,eAAe,aACnC,uBAAuB,6BACzB;EAEA,MAAM,WAAW,aACd,KAAK,SAAS;GACb,IAAI,MAAM,SAAS,QAAQ,OAAO,KAAK;GACvC,OAAO;EACT,CAAC,CAAC,CACD,KAAK,IAAI;EAEZ,MAAM,QAAQ,gBAAgB;GAC5B;GACA;EACF,CAAC;EAED,IACE,aAAa,QAAQ,MACpB,iBAAiB,cAAc,iBAAiB,kBACjD;GACA,MAAM,cAAe,eACjB;GACJ,MAAM,OAAQ,eACV;GACJ,MAAM,mBACJ,eACC;GACH,MAAM,kBACJ,eACC;GACH,MAAM,IAAK,eACP;EACN;EAEA,MAAM,oBAAoB,IAAI,eAAe,EAC3C,OACE,iBACkE;GAClE,OAAO,YAAY;GACnB;GACA;EACF,GACF,CAAC,CAAC,CAAC,WAAW,EAAE,SAAS,iBAAiB,CAAC;EAE3C,MAAM,aACJ,gBAAA,eACI,MAAM,8BAA8B,OAAO,WAAW,IACtD,MAAM,oBAAoB,OAAO,WAAW;;EAGlD,MAAM,YAAY,cACf,WAAW,EAAE,SAAS,gBAAgB,CAAC,CAAC,CACxC,KAAK,iBAAiB,CAAC,CACvB,KAAK,UAAU,CAAC,CAChB,WAAW,EAAE,SAAS,aAAa,CAAC;EAEvC,MAAM,eAAe,OAAO,OAAO,CAAC,GAAG,cAAc;GACnD,QAAQ,KAAK;GACb,OAAO,KAAK;GACZ,SAAS,cAAc,WAAW;EACpC,CAAC;EAED,MAAM,oBACJ,kBAEA,uBACE;GACE,UAAU;GACV,QAAQ;GACR,WAAW;GACX,WAAW,cAAc,WAAW;GACpC;GACA,MAAM,CAAC,aAAa,OAAO;EAC7B,SAEE,UAAU,OACR;GAAE,OAAO;GAAW,QAAQ;EAAS,GACrC,aACF,CACJ;EAEF,IAAI;GACF,IAAI;IACF,OAAO,MAAM,yBACX,4BAA4B;KAC1B,aAAa,KAAK;KAClB,iBAAiB,cAAc;IACjC,CAAC,SACK,iBAAiB,YAAY,CACrC;GACF,SAAS,IAAI;IAGX,MAAM,kBAAkB,aACtB,aAAa,WACb,yBACF;IACA,MAAM,EAAE,WAAW,KAAK,GAAG,SAAS;IACpC,MAAM,aAAa,OAAO,OAAO,CAAC,GAAG,MAAM,EACzC,WAAW,kBAAkB,CAAC,eAAe,IAAI,CAAC,EACpD,CAAC;IACD,OAAO,MAAM,yBACX,4BAA4B;KAC1B,aAAa,KAAK;KAClB,iBAAiB,cAAc;IACjC,CAAC,SACK,iBAAiB,UAAqC,CAC9D;GACF;EACF,UAAU;GACR,MAAM,uBAAuB,oBAAoB;EACnD;CACF;AACF;AAEA,SAAS,sBACP,UACA,MACyB;CACzB,KAAK,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KACxC,IAAI,SAAS,EAAE,CAAC,QAAQ,MAAM,MAC5B,OAAO,SAAS;AAItB;AAEA,SAAS,kBAAkB,SAA8B;CACvD,MAAM,UAAU,QAAQ;CACxB,IAAI,OAAO,YAAY,UACrB,OAAO;CAET,IAAI,CAAC,MAAM,QAAQ,OAAO,GACxB,OAAO,OAAO,OAAO;CAEvB,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,SAAS,SAClB,IACE,OAAO,UAAU,YACjB,UAAU,SACV,MAAM,SAAS,UACf,UAAU,SACV,OAAO,MAAM,SAAS,UAEtB,MAAM,KAAK,MAAM,IAAI;CAGzB,OAAO,MAAM,KAAK,IAAI;AACxB"}
1
+ {"version":3,"file":"run.mjs","names":[],"sources":["../../src/run.ts"],"sourcesContent":["// src/run.ts\nimport { HumanMessage } from '@langchain/core/messages';\nimport { PromptTemplate } from '@langchain/core/prompts';\nimport { RunnableLambda } from '@langchain/core/runnables';\nimport { AzureChatOpenAI, ChatOpenAI } from '@langchain/openai';\nimport { BaseCallbackHandler } from '@langchain/core/callbacks/base';\nimport {\n Command,\n INTERRUPT,\n MemorySaver,\n isInterrupted,\n} from '@langchain/langgraph';\nimport type {\n MessageContentComplex,\n BaseMessage,\n} from '@langchain/core/messages';\nimport type { StringPromptValue } from '@langchain/core/prompt_values';\nimport type { RunnableConfig } from '@langchain/core/runnables';\nimport type { HookRegistry } from '@/hooks';\nimport type * as t from '@/types';\nimport {\n createLangfuseTraceMetadata,\n createLangfuseHandler,\n disposeLangfuseHandler,\n getLangfuseTraceName,\n isLangfuseCallbackHandler,\n withLangfuseAttributes,\n} from '@/langfuse';\nimport {\n resolveLangfuseRuntimeScope,\n withLangfuseRuntimeScope,\n} from '@/langfuseRuntimeScope';\nimport {\n appendCallbacks,\n findCallback,\n type CallbackEntry,\n} from '@/utils/callbacks';\nimport {\n createCompletionTitleRunnable,\n createTitleRunnable,\n} from '@/utils/title';\nimport { createTokenCounter, encodingForModel } from '@/utils/tokens';\nimport { initializeLangfuseTracing } from './instrumentation';\nimport { GraphEvents, Callback, TitleMethod } from '@/common';\nimport { MultiAgentGraph } from '@/graphs/MultiAgentGraph';\nimport { resolveLangfuseConfig } from '@/langfuseConfig';\nimport { StandardGraph } from '@/graphs/Graph';\nimport { initializeModel } from '@/llm/init';\nimport { HandlerRegistry } from '@/events';\nimport { isOpenAILike } from '@/utils/llm';\nimport { executeHooks } from '@/hooks';\n\nexport const defaultOmitOptions = new Set([\n 'stream',\n 'thinking',\n 'streaming',\n 'maxTokens',\n 'clientOptions',\n 'thinkingConfig',\n 'thinkingBudget',\n 'includeThoughts',\n 'maxOutputTokens',\n 'additionalModelRequestFields',\n]);\n\nconst CUSTOM_GRAPH_EVENTS = new Set<string>([\n GraphEvents.ON_AGENT_UPDATE,\n GraphEvents.ON_RUN_STEP,\n GraphEvents.ON_RUN_STEP_DELTA,\n GraphEvents.ON_RUN_STEP_COMPLETED,\n GraphEvents.ON_MESSAGE_DELTA,\n GraphEvents.ON_REASONING_DELTA,\n GraphEvents.ON_TOOL_EXECUTE,\n GraphEvents.ON_SUMMARIZE_START,\n GraphEvents.ON_SUMMARIZE_DELTA,\n GraphEvents.ON_SUMMARIZE_COMPLETE,\n GraphEvents.ON_SUBAGENT_UPDATE,\n GraphEvents.ON_AGENT_LOG,\n GraphEvents.ON_CONTEXT_USAGE,\n GraphEvents.ON_CUSTOM_EVENT,\n]);\n\nconst DIRECT_DISPATCHED_STEP_EVENTS = new Set<string>([\n GraphEvents.ON_RUN_STEP,\n GraphEvents.ON_RUN_STEP_DELTA,\n GraphEvents.ON_MESSAGE_DELTA,\n GraphEvents.ON_REASONING_DELTA,\n]);\n\nfunction getStepScopedEventId(data: unknown): string | undefined {\n if (data == null || typeof data !== 'object') {\n return undefined;\n }\n const candidate = data as { id?: unknown };\n return typeof candidate.id === 'string' ? candidate.id : undefined;\n}\n\nfunction isLangGraphResumeMapForInterrupt(\n value: unknown,\n interruptId: string\n): value is Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n return Object.prototype.hasOwnProperty.call(value, interruptId);\n}\n\ntype InterruptStateSnapshot = {\n config?: RunnableConfig;\n tasks?: Array<{\n interrupts?: Array<{ id?: string }>;\n }>;\n};\n\ntype WorkflowWithStateHistory = {\n getStateHistory?(\n config: RunnableConfig\n ): AsyncIterableIterator<InterruptStateSnapshot>;\n};\n\nexport class Run<_T extends t.BaseGraphState> {\n id: string;\n private tokenCounter?: t.TokenCounter;\n private handlerRegistry?: HandlerRegistry;\n private hookRegistry?: HookRegistry;\n private humanInTheLoop?: t.HumanInTheLoopConfig;\n private langfuse?: t.LangfuseConfig;\n private toolOutputReferences?: t.ToolOutputReferencesConfig;\n private eagerEventToolExecution?: t.EagerEventToolExecutionConfig;\n private toolExecution?: t.ToolExecutionConfig;\n private subagentUsageSink?: t.SubagentUsageSink;\n private indexTokenCountMap?: Record<string, number>;\n calibrationRatio: number = 1;\n graphRunnable?: t.CompiledStateWorkflow;\n Graph: StandardGraph | MultiAgentGraph | undefined;\n returnContent: boolean = false;\n private skipCleanup: boolean = false;\n private _streamResult: t.MessageContentComplex[] | undefined;\n /**\n * Captured interrupt payload typed as `unknown` because the SDK\n * does not validate the runtime shape — custom graph nodes can\n * raise interrupts with arbitrary payloads (not just the SDK's\n * `HumanInterruptPayload` union). The public `getInterrupt<T>()`\n * lets callers assert the type they expect.\n */\n private _interrupt: t.RunInterruptResult<unknown> | undefined;\n private _haltedReason: string | undefined;\n\n private constructor(config: Partial<t.RunConfig>) {\n const runId = config.runId ?? '';\n if (!runId) {\n throw new Error('Run ID not provided');\n }\n\n this.id = runId;\n this.tokenCounter = config.tokenCounter;\n this.indexTokenCountMap = config.indexTokenCountMap;\n if (config.calibrationRatio != null && config.calibrationRatio > 0) {\n this.calibrationRatio = config.calibrationRatio;\n }\n\n const handlerRegistry = new HandlerRegistry();\n\n if (config.customHandlers) {\n for (const [eventType, handler] of Object.entries(\n config.customHandlers\n )) {\n handlerRegistry.register(eventType, handler);\n }\n }\n\n this.handlerRegistry = handlerRegistry;\n this.hookRegistry = config.hooks;\n this.humanInTheLoop = config.humanInTheLoop;\n this.langfuse = config.langfuse;\n this.toolOutputReferences = config.toolOutputReferences;\n this.eagerEventToolExecution = config.eagerEventToolExecution;\n this.toolExecution = config.toolExecution;\n this.subagentUsageSink = config.subagentUsageSink;\n\n if (!config.graphConfig) {\n throw new Error('Graph config not provided');\n }\n\n /** Handle different graph types */\n if (config.graphConfig.type === 'multi-agent') {\n this.graphRunnable = this.createMultiAgentGraph(config.graphConfig);\n if (this.Graph) {\n this.Graph.handlerRegistry = handlerRegistry;\n }\n } else {\n /** Default to legacy graph for 'standard' or undefined type */\n this.graphRunnable = this.createLegacyGraph(config.graphConfig);\n if (this.Graph) {\n this.Graph.compileOptions =\n config.graphConfig.compileOptions ?? this.Graph.compileOptions;\n this.Graph.handlerRegistry = handlerRegistry;\n }\n }\n\n if (config.initialSessions && this.Graph) {\n for (const [key, value] of config.initialSessions) {\n this.Graph.sessions.set(key, value);\n }\n }\n\n this.returnContent = config.returnContent ?? false;\n this.skipCleanup = config.skipCleanup ?? false;\n }\n\n private createLegacyGraph(\n config: t.LegacyGraphConfig | t.StandardGraphConfig\n ): t.CompiledStateWorkflow {\n let agentConfig: t.AgentInputs;\n let signal: AbortSignal | undefined;\n\n /** Check if this is a multi-agent style config (has agents array) */\n if ('agents' in config && Array.isArray(config.agents)) {\n if (config.agents.length === 0) {\n throw new Error('At least one agent must be provided');\n }\n agentConfig = config.agents[0];\n signal = config.signal;\n } else {\n /** Legacy path: build agent config from llmConfig */\n const {\n type: _type,\n llmConfig,\n signal: legacySignal,\n tools = [],\n ...agentInputs\n } = config as t.LegacyGraphConfig;\n const { provider, ...clientOptions } = llmConfig;\n\n agentConfig = {\n ...agentInputs,\n tools,\n provider,\n clientOptions,\n agentId: 'default',\n };\n signal = legacySignal;\n }\n\n const standardGraph = new StandardGraph({\n signal,\n runId: this.id,\n agents: [agentConfig],\n langfuse: this.langfuse,\n tokenCounter: this.tokenCounter,\n indexTokenCountMap: this.indexTokenCountMap,\n calibrationRatio: this.calibrationRatio,\n subagentUsageSink: this.subagentUsageSink,\n });\n /** Propagate compile options from graph config */\n standardGraph.compileOptions = this.applyHITLCheckpointerFallback(\n config.compileOptions\n );\n standardGraph.hookRegistry = this.hookRegistry;\n standardGraph.humanInTheLoop = this.humanInTheLoop;\n standardGraph.toolOutputReferences = this.toolOutputReferences;\n standardGraph.eagerEventToolExecution = this.eagerEventToolExecution;\n standardGraph.toolExecution = this.toolExecution;\n this.Graph = standardGraph;\n return standardGraph.createWorkflow();\n }\n\n private createMultiAgentGraph(\n config: t.MultiAgentGraphConfig\n ): t.CompiledStateWorkflow {\n const { agents, edges, compileOptions } = config;\n\n const multiAgentGraph = new MultiAgentGraph({\n runId: this.id,\n agents,\n edges,\n langfuse: this.langfuse,\n tokenCounter: this.tokenCounter,\n indexTokenCountMap: this.indexTokenCountMap,\n calibrationRatio: this.calibrationRatio,\n subagentUsageSink: this.subagentUsageSink,\n });\n\n multiAgentGraph.compileOptions =\n this.applyHITLCheckpointerFallback(compileOptions);\n\n multiAgentGraph.hookRegistry = this.hookRegistry;\n multiAgentGraph.humanInTheLoop = this.humanInTheLoop;\n multiAgentGraph.toolOutputReferences = this.toolOutputReferences;\n multiAgentGraph.eagerEventToolExecution = this.eagerEventToolExecution;\n multiAgentGraph.toolExecution = this.toolExecution;\n this.Graph = multiAgentGraph;\n return multiAgentGraph.createWorkflow();\n }\n\n /**\n * When the host opted into HITL via `humanInTheLoop: { enabled: true }`\n * and did not supply a checkpointer, install an in-memory `MemorySaver`\n * so `interrupt()` can persist checkpoints and `Command({ resume })`\n * can rebuild state. The fallback is intentionally process-local:\n * production hosts that need durable resumption across processes /\n * restarts must provide their own checkpointer (Redis, Postgres, etc.)\n * on `compileOptions.checkpointer`.\n *\n * No-op when HITL is off (the default — omitted, or\n * `{ enabled: false }`) or the host already supplied a checkpointer\n * of their own. See `HumanInTheLoopConfig` JSDoc for the rationale\n * behind the default-off stance.\n */\n private applyHITLCheckpointerFallback(\n compileOptions: t.CompileOptions | undefined\n ): t.CompileOptions | undefined {\n if (this.humanInTheLoop?.enabled !== true) {\n return compileOptions;\n }\n if (compileOptions?.checkpointer != null) {\n return compileOptions;\n }\n return {\n ...(compileOptions ?? {}),\n checkpointer: new MemorySaver(),\n };\n }\n\n /**\n * Run RunStart + UserPromptSubmit hooks before the graph stream\n * begins, accumulate any `additionalContext` strings into the input\n * messages, and short-circuit when a hook signals the run should not\n * proceed (deny / ask decision on the prompt, or `preventContinuation`\n * on either hook).\n *\n * Returns `true` when the caller should bail with `undefined` (run\n * was halted before any model call); returns `false` to proceed\n * into the stream loop.\n *\n * ## Side effects\n *\n * On the success path:\n * - Mutates `stateInputs.messages` in place to append a\n * consolidated `HumanMessage` carrying any hook\n * `additionalContext` strings. Safe because the host owns the\n * array and `processStream` is the only consumer until LangGraph\n * reads it.\n *\n * On the halt path (returning `true`):\n * - Sets `this._haltedReason` so callers (and the eventual host)\n * can distinguish a hook-driven halt from a natural completion.\n * - Calls `registry.clearSession(this.id)` and\n * `registry.clearHaltSignal(this.id)` because no resume is\n * expected from a pre-stream halt — the run never entered the\n * graph, so the session/halt state for this run would otherwise\n * leak to the next `processStream` invocation on the same\n * registry. Other concurrent runs on the same registry are\n * untouched (halt signals are scoped per session id).\n * - Sets `config.callbacks = undefined` to drop the callback\n * references the caller built (langfuse handler, custom event\n * handler, etc.) since they won't be exercised. Mirrors the\n * equivalent cleanup the `processStream` `finally` block does\n * on the natural-completion path.\n */\n private async runPreStreamHooks(\n stateInputs: t.IState,\n threadId: string | undefined,\n config: Partial<RunnableConfig>\n ): Promise<boolean> {\n const registry = this.hookRegistry;\n /**\n * Defensive guard: `processStream` already validated `this.Graph`\n * before calling this helper, but TypeScript can't propagate that\n * narrowing across method boundaries. The check keeps the body\n * free of `this.Graph!` non-null assertions.\n */\n if (registry == null || this.Graph == null) {\n return false;\n }\n\n const preStreamContexts: string[] = [];\n\n const runStartResult = await executeHooks({\n registry,\n input: {\n hook_event_name: 'RunStart',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n messages: stateInputs.messages,\n },\n sessionId: this.id,\n });\n for (const ctx of runStartResult.additionalContexts) {\n preStreamContexts.push(ctx);\n }\n /**\n * Honor `preventContinuation` from RunStart before the stream\n * starts. Mid-flight halts (from tool/compact/subagent hooks)\n * route through `HookRegistry.haltRun` and are polled by the\n * stream loop in `processStream` — different mechanism, same\n * intent.\n */\n if (runStartResult.preventContinuation === true) {\n this._haltedReason = runStartResult.stopReason ?? 'preventContinuation';\n registry.clearSession(this.id);\n registry.clearHaltSignal(this.id);\n config.callbacks = undefined;\n return true;\n }\n\n const lastHuman = findLastMessageOfType(stateInputs.messages, 'human');\n if (lastHuman != null) {\n const promptResult = await executeHooks({\n registry,\n input: {\n hook_event_name: 'UserPromptSubmit',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n prompt: extractPromptText(lastHuman),\n // attachments: not yet wired — Phase 2 will extract\n // non-text content blocks (images, files) from messages\n },\n sessionId: this.id,\n });\n if (\n promptResult.decision === 'deny' ||\n promptResult.decision === 'ask' ||\n promptResult.preventContinuation === true\n ) {\n /**\n * Always set `_haltedReason` so the host can call\n * `getHaltReason()` and distinguish a hook-blocked prompt\n * from a natural empty-output completion. Three signals can\n * land here, each with its own canonical reason string when\n * the hook didn't supply one.\n */\n if (promptResult.preventContinuation === true) {\n this._haltedReason = promptResult.stopReason ?? 'preventContinuation';\n } else if (promptResult.decision === 'deny') {\n this._haltedReason = promptResult.reason ?? 'prompt_denied';\n } else {\n this._haltedReason =\n promptResult.reason ?? 'prompt_requires_approval';\n }\n registry.clearSession(this.id);\n registry.clearHaltSignal(this.id);\n config.callbacks = undefined;\n return true;\n }\n for (const ctx of promptResult.additionalContexts) {\n preStreamContexts.push(ctx);\n }\n }\n\n if (preStreamContexts.length > 0) {\n /**\n * Wraps the joined hook contexts as a `HumanMessage` even though\n * the intent is system-level guidance. Using a `SystemMessage`\n * mid-conversation is rejected by Anthropic and Google providers\n * (system messages must be the leading entry), so the LangChain\n * convention — also used by `ToolNode.convertInjectedMessages`\n * — is `HumanMessage` carrying `additional_kwargs.role` as a\n * marker for hosts inspecting state. The model still sees a\n * user-role message; the `role: 'system'` field is metadata\n * only. Hosts that want a true system message should compose\n * it into the agent's `instructions` config instead.\n */\n stateInputs.messages.push(\n new HumanMessage({\n content: preStreamContexts.join('\\n\\n'),\n additional_kwargs: { role: 'system', source: 'hook' },\n })\n );\n }\n\n return false;\n }\n\n static async create<T extends t.BaseGraphState>(\n config: t.RunConfig\n ): Promise<Run<T>> {\n /** Create tokenCounter if indexTokenCountMap is provided but tokenCounter is not */\n if (config.indexTokenCountMap && !config.tokenCounter) {\n const gc = config.graphConfig;\n const clientOpts =\n 'agents' in gc ? gc.agents[0]?.clientOptions : gc.clientOptions;\n const model = (clientOpts as { model?: string } | undefined)?.model ?? '';\n config.tokenCounter = await createTokenCounter(encodingForModel(model));\n }\n return new Run<T>(config);\n }\n\n getRunMessages(): BaseMessage[] | undefined {\n if (!this.Graph) {\n throw new Error(\n 'Graph not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n return this.Graph.getRunMessages();\n }\n\n /**\n * Returns the current calibration ratio (EMA of provider-vs-estimate token ratios).\n * Hosts should persist this value and pass it back as `RunConfig.calibrationRatio`\n * on the next run for the same conversation so the pruner starts with an accurate\n * scaling factor instead of the default (1).\n */\n getCalibrationRatio(): number {\n return this.calibrationRatio;\n }\n\n getResolvedInstructionOverhead(): number | undefined {\n return this.Graph?.getResolvedInstructionOverhead();\n }\n\n getToolCount(): number {\n return this.Graph?.getToolCount() ?? 0;\n }\n\n /**\n * Creates a custom event callback handler that intercepts custom events\n * and processes them through our handler registry instead of EventStreamCallbackHandler\n */\n private createCustomEventCallback() {\n return async (\n eventName: string,\n data: unknown,\n runId: string,\n tags?: string[],\n metadata?: Record<string, unknown>\n ): Promise<void> => {\n // Step-scoped SDK events are dispatched directly via the handler\n // registry first. Skip callback-based echoes to prevent double\n // handling when LangGraph invokes custom callbacks more than once.\n const stepScopedEventId = getStepScopedEventId(data);\n if (\n DIRECT_DISPATCHED_STEP_EVENTS.has(eventName) &&\n this.Graph != null &&\n stepScopedEventId != null &&\n this.Graph.hasHandlerDispatchedEvent(eventName, stepScopedEventId)\n ) {\n return;\n }\n const handler = this.handlerRegistry?.getHandler(eventName);\n if (handler && this.Graph) {\n return await handler.handle(\n eventName,\n data as\n | t.StreamEventData\n | t.ModelEndData\n | t.RunStep\n | t.RunStepDeltaEvent\n | t.MessageDeltaEvent\n | t.ReasoningDeltaEvent\n | { result: t.ToolEndEvent },\n metadata,\n this.Graph\n );\n }\n };\n }\n\n private shouldClearHookSession(streamThrew: boolean): boolean {\n return this._interrupt == null || this._haltedReason != null || streamThrew;\n }\n\n private isAwaitingResume(streamThrew: boolean): boolean {\n return (\n this._interrupt != null && this._haltedReason == null && !streamThrew\n );\n }\n\n private getStreamLangfuseConfig(\n graph: StandardGraph | MultiAgentGraph\n ): t.LangfuseConfig | undefined {\n const primaryContext = graph.agentContexts.get(graph.defaultAgentId);\n if (primaryContext != null) {\n return resolveLangfuseConfig(this.langfuse, primaryContext.langfuse);\n }\n\n for (const context of graph.agentContexts.values()) {\n const langfuse = resolveLangfuseConfig(this.langfuse, context.langfuse);\n if (langfuse != null) {\n return langfuse;\n }\n }\n\n return this.langfuse;\n }\n\n private getStreamToolOutputTracingLangfuseConfig(\n graph: StandardGraph | MultiAgentGraph\n ): t.LangfuseConfig | undefined {\n const toolOutputTracingConfigs = Array.from(graph.agentContexts.values())\n .map((context) => {\n return resolveLangfuseConfig(this.langfuse, context.langfuse)\n ?.toolOutputTracing;\n })\n .filter((config): config is t.LangfuseToolOutputTracingConfig => {\n return config != null;\n });\n\n if (toolOutputTracingConfigs.length === 0) {\n return this.langfuse?.toolOutputTracing != null\n ? { toolOutputTracing: this.langfuse.toolOutputTracing }\n : undefined;\n }\n if (toolOutputTracingConfigs.length === 1) {\n return { toolOutputTracing: toolOutputTracingConfigs[0] };\n }\n\n let enabled: boolean | undefined;\n let redactionText: string | undefined;\n let redactedToolNameMatchMode: 'exact' | 'partial' | undefined;\n const redactedToolNames = new Set<string>();\n\n for (const config of toolOutputTracingConfigs) {\n if (config.enabled === false) {\n enabled = false;\n } else if (enabled !== false && config.enabled != null) {\n enabled = config.enabled;\n }\n\n redactionText ??= config.redactionText;\n if (config.redactedToolNameMatchMode === 'partial') {\n redactedToolNameMatchMode = 'partial';\n } else {\n redactedToolNameMatchMode ??= config.redactedToolNameMatchMode;\n }\n\n for (const toolName of config.redactedToolNames ?? []) {\n redactedToolNames.add(toolName);\n }\n }\n\n return {\n toolOutputTracing: {\n ...(enabled != null ? { enabled } : {}),\n ...(redactedToolNames.size > 0\n ? { redactedToolNames: Array.from(redactedToolNames) }\n : {}),\n ...(redactedToolNameMatchMode != null\n ? { redactedToolNameMatchMode }\n : {}),\n ...(redactionText != null ? { redactionText } : {}),\n },\n };\n }\n\n async processStream(\n inputs: t.IState | Command,\n callerConfig: Partial<RunnableConfig> & {\n version: 'v1' | 'v2';\n run_id?: string;\n },\n streamOptions?: t.EventStreamOptions\n ): Promise<MessageContentComplex[] | undefined> {\n if (this.graphRunnable == null) {\n throw new Error(\n 'Run not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n if (!this.Graph) {\n throw new Error(\n 'Graph not initialized. Make sure to use Run.create() to instantiate the Run.'\n );\n }\n const graphRunnable = this.graphRunnable;\n const graph = this.Graph;\n\n /**\n * `Command` inputs (`Command({ resume, update?, goto? })`) are\n * resume-mode invocations: LangGraph rebuilds graph state from the\n * checkpointer, so we skip RunStart / UserPromptSubmit hooks (no\n * new prompt to evaluate) and read run-state from the Graph wrapper\n * instead of `inputs.messages`.\n */\n const isResume = inputs instanceof Command;\n const stateInputs = isResume ? undefined : (inputs as t.IState);\n\n const config: Partial<RunnableConfig> & {\n version: 'v1' | 'v2';\n run_id?: string;\n } = {\n recursionLimit: 50,\n ...callerConfig,\n configurable: { ...callerConfig.configurable },\n };\n\n /**\n * Skip `resetValues` on resume — we're continuing an in-flight\n * run, not starting a fresh one. Resetting would wipe the\n * sidecars (`toolCallStepIds`, `stepKeyIds`, accumulated\n * `messages`, etc.) the resumed `ToolNode` needs to dispatch\n * tool completions with the correct step ids and re-resolve\n * `{{tool<i>turn<n>}}` references. Pairs with the\n * `awaitingResume` gate on `clearHeavyState` in the `finally`\n * block so the sidecars survive both ends of the interrupt\n * boundary.\n */\n if (!isResume) {\n graph.resetValues(streamOptions?.keepContent);\n }\n this._interrupt = undefined;\n this._haltedReason = undefined;\n this.hookRegistry?.clearHaltSignal(this.id);\n\n /** Custom event callback to intercept and handle custom events */\n const customEventCallback = this.createCustomEventCallback();\n\n const streamCallbacks = streamOptions?.callbacks\n ? this.getCallbacks(streamOptions.callbacks)\n : undefined;\n\n const customHandler = BaseCallbackHandler.fromMethods({\n [Callback.CUSTOM_EVENT]: customEventCallback,\n });\n customHandler.awaitHandlers = true;\n\n config.callbacks = appendCallbacks(\n config.callbacks,\n streamCallbacks ? [streamCallbacks, customHandler] : [customHandler]\n );\n\n const primaryContext = graph.agentContexts.get(graph.defaultAgentId);\n const userId =\n typeof config.configurable?.user_id === 'string'\n ? config.configurable.user_id\n : undefined;\n const sessionId =\n typeof config.configurable?.thread_id === 'string'\n ? config.configurable.thread_id\n : undefined;\n const traceMetadata = createLangfuseTraceMetadata({\n messageId: this.id,\n parentMessageId: config.configurable?.requestBody?.parentMessageId,\n agentId: graph.defaultAgentId,\n agentName: primaryContext?.name,\n });\n const traceName = config.runName ?? getLangfuseTraceName(traceMetadata);\n const streamLangfuseConfig = this.getStreamLangfuseConfig(graph);\n initializeLangfuseTracing(streamLangfuseConfig);\n const langfuseHandler = createLangfuseHandler({\n langfuse: streamLangfuseConfig,\n userId,\n sessionId,\n traceMetadata,\n tags: ['librechat', 'agent'],\n traceIdSeed:\n streamLangfuseConfig?.deterministicTraceId === true\n ? this.id\n : undefined,\n });\n if (langfuseHandler != null) {\n config.runName = traceName;\n config.callbacks = appendCallbacks(config.callbacks, [langfuseHandler]);\n }\n\n if (!this.id) {\n throw new Error('Run ID not provided');\n }\n\n config.run_id = this.id;\n config.configurable = Object.assign(config.configurable ?? {}, {\n run_id: this.id,\n });\n\n const threadId = config.configurable.thread_id as string | undefined;\n\n if (this.hookRegistry != null && stateInputs != null) {\n const shouldHalt = await this.runPreStreamHooks(\n stateInputs,\n threadId,\n config\n );\n if (shouldHalt) {\n return undefined;\n }\n }\n\n /**\n * Tracks whether the stream loop threw. Used by the `finally`\n * block to decide whether to honor the interrupt-preservation\n * guard for session hooks: a captured `_interrupt` is only\n * meaningful if the stream completed cleanly. If the loop errored\n * after stashing an interrupt (e.g. a downstream handler throws\n * after the interrupt event landed), the interrupt is stale —\n * preserving session hooks would leak them into the next run.\n */\n let streamThrew = false;\n\n const consumeStream = async (): Promise<void> => {\n /**\n * `streamEvents` accepts both state inputs and `Command` (resume) at\n * runtime, but our `CompiledStateWorkflow` type narrows the first\n * arg to `BaseGraphState`. Cast on the call so the resume path\n * type-checks without widening the wrapper for every caller.\n */\n const stream = graphRunnable.streamEvents(inputs as t.IState, config, {\n raiseError: true,\n /**\n * Prevent EventStreamCallbackHandler from processing custom events.\n * Custom events are already handled via our createCustomEventCallback()\n * which routes them through the handlerRegistry.\n * Without this flag, EventStreamCallbackHandler throws errors when\n * custom events are dispatched for run IDs not in its internal map\n * (due to timing issues in parallel execution or after run cleanup).\n */\n ignoreCustomEvent: true,\n });\n\n for await (const event of stream) {\n const { data, metadata, ...info } = event;\n\n const eventName: t.EventName = info.event;\n\n /** Skip custom events as they're handled by our callback */\n if (CUSTOM_GRAPH_EVENTS.has(eventName)) {\n continue;\n }\n\n /**\n * Detect interrupts surfaced by LangGraph as a synthetic\n * `__interrupt__` field on the streamed chunk and stash the\n * first one for the host to read via `run.getInterrupt()`\n * once the stream drains. Captured as `unknown` because the\n * SDK does not validate the runtime payload shape — the\n * built-in ToolNode raises a `HumanInterruptPayload`\n * (`tool_approval` / `ask_user_question`), but custom nodes\n * can pass any payload to `interrupt()`. Callers narrow with\n * the `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt`\n * guards or assert via `getInterrupt<T>()`.\n */\n if (\n this._interrupt == null &&\n data.chunk != null &&\n isInterrupted<unknown>(data.chunk)\n ) {\n const interrupts = data.chunk[INTERRUPT];\n if (interrupts.length > 0) {\n const first = interrupts[0];\n /**\n * Capture the interrupt unconditionally — `interrupt(null)`\n * and `interrupt(undefined)` are valid pauses (a custom\n * node may want to pause without metadata) and the host\n * still needs to know the run is awaiting resume. Gating\n * on `payload != null` would silently downgrade a paused\n * run to \"completed\" and let the `Stop` hook fire,\n * breaking host resume handling.\n */\n this._interrupt = {\n interruptId: first.id ?? '',\n threadId,\n payload: first.value,\n };\n }\n }\n\n const handler = this.handlerRegistry?.getHandler(eventName);\n if (handler) {\n await handler.handle(eventName, data, metadata, this.Graph);\n }\n\n /**\n * Mid-flight halt: any hook (PreToolUse, PostToolUse,\n * PostToolBatch, SubagentStart/Stop, PreCompact, PostCompact)\n * that returned `preventContinuation: true` raises a halt\n * signal on the registry via `executeHooks`. We poll between\n * stream events and break out as soon as one is set so the\n * graph doesn't take another model turn after the halting\n * operation completes.\n *\n * Limitation: the current step (in-flight model call, ongoing\n * tool batch) is not aborted — only the next step is skipped.\n * This matches Claude Code's `continue: false` semantic where\n * the active operation finishes before halting takes effect.\n */\n const haltSignal = this.hookRegistry?.getHaltSignal(this.id);\n if (haltSignal != null) {\n this._haltedReason = haltSignal.reason;\n break;\n }\n }\n\n if (this._interrupt != null) {\n await this.resolveInterruptResumeConfig(config);\n }\n\n /**\n * Skip the Stop hook when the run paused on a HITL interrupt\n * (still pending human input) or was halted by a hook (the host\n * already chose to stop, so a Stop hook firing now would be\n * misleading). The host fires Stop on the resumed-and-completed\n * run instead.\n */\n if (\n this._interrupt == null &&\n this._haltedReason == null &&\n this.hookRegistry?.hasHookFor('Stop', this.id) === true\n ) {\n await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'Stop',\n runId: this.id,\n threadId,\n agentId: graph.defaultAgentId,\n messages: graph.getRunMessages() ?? stateInputs?.messages ?? [],\n stopHookActive: false, // will be true when stop is triggered by a hook (Phase 2)\n },\n sessionId: this.id,\n }).catch(() => {\n /* Stop hook errors must not masquerade as stream failures */\n });\n }\n };\n\n try {\n // When opted in, seed the root trace id from this run's id so feedback /\n // other external signals can be attached to the trace later without a\n // lookup (see SeededTraceIdGenerator in ./instrumentation).\n await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: streamLangfuseConfig,\n langfuseOverlay: this.getStreamToolOutputTracingLangfuseConfig(graph),\n traceIdSeed:\n streamLangfuseConfig?.deterministicTraceId === true\n ? this.id\n : undefined,\n }),\n () =>\n withLangfuseAttributes(\n {\n langfuse: streamLangfuseConfig,\n userId,\n sessionId,\n traceName,\n traceMetadata,\n tags: ['librechat', 'agent'],\n },\n consumeStream\n )\n );\n } catch (err) {\n streamThrew = true;\n if (this.hookRegistry?.hasHookFor('StopFailure', this.id) === true) {\n const runMessages = this.Graph.getRunMessages() ?? [];\n await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'StopFailure',\n runId: this.id,\n threadId,\n agentId: this.Graph.defaultAgentId,\n error: err instanceof Error ? err.message : String(err),\n lastAssistantMessage: findLastMessageOfType(runMessages, 'ai'),\n },\n sessionId: this.id,\n }).catch(() => {\n /* swallow hook errors — the original error must propagate */\n });\n }\n throw err;\n } finally {\n /**\n * Preserve session-scoped hooks when the run paused on a HITL\n * interrupt — the very next call will be `Run.resume()`, which\n * needs the same policy hooks (e.g., the `PreToolUse` matcher\n * that triggered the interrupt) to fire on the re-executed node\n * and uphold the approval flow. Clearing here would leak the\n * approval gate on resume. The session is cleared instead at\n * natural completion, error (including errors that happen AFTER\n * an interrupt was captured — those interrupts are stale), or\n * hook-driven halt (including hooks that returned BOTH `ask`\n * and `preventContinuation` — the halt wins, no resume is\n * expected, sessions must drop). Every state where no resume\n * is expected clears.\n */\n if (this.shouldClearHookSession(streamThrew)) {\n this.hookRegistry?.clearSession(this.id);\n }\n /**\n * Drop any halt signal raised mid-stream for this run so a\n * subsequent `processStream` / `resume` starts with clean state.\n * The Run captured `_haltedReason` already; the registry entry\n * for this `sessionId` would otherwise spuriously trip the next\n * loop. Other concurrent runs sharing this registry are\n * unaffected — their entries live under their own session ids.\n */\n this.hookRegistry?.clearHaltSignal(this.id);\n await disposeLangfuseHandler(langfuseHandler);\n\n /**\n * Break the reference chain that keeps heavy data alive via\n * LangGraph's internal `__pregel_scratchpad.currentTaskInput` →\n * `@langchain/core` `RunTree.extra[lc:child_config]` →\n * Node.js `AsyncLocalStorage` context captured by timers/promises.\n *\n * Without this, base64-encoded images/PDFs in message content remain\n * reachable from lingering `Timeout` handles until GC runs.\n */\n if (!this.skipCleanup) {\n if (\n (config.configurable as Record<string, unknown> | undefined) != null\n ) {\n for (const key of Object.getOwnPropertySymbols(config.configurable)) {\n const val = config.configurable[key as unknown as string] as\n | Record<string, unknown>\n | undefined;\n if (\n val != null &&\n typeof val === 'object' &&\n 'currentTaskInput' in val\n ) {\n (val as Record<string, unknown>).currentTaskInput = undefined;\n }\n delete config.configurable[key as unknown as string];\n }\n config.configurable = undefined;\n }\n config.callbacks = undefined;\n }\n\n const result = this.returnContent\n ? this.Graph.getContentParts()\n : undefined;\n\n this.calibrationRatio = this.Graph.getCalibrationRatio();\n\n /**\n * Skip `clearHeavyState()` when the run paused on a clean HITL\n * interrupt awaiting resume — `Run.resume()` re-enters the same\n * `ToolNode` instance and needs the sidecars `clearHeavyState`\n * would wipe (`toolCallStepIds` for completion-event step ids,\n * the `_toolOutputRegistry` for `{{tool<i>turn<n>}}`\n * substitutions, `sessions` for code-env continuity, plus the\n * `hookRegistry` and `humanInTheLoop` config the interrupt\n * branch itself relies on). Without preservation, the resumed\n * tool completion would dispatch `ON_RUN_STEP_COMPLETED` with\n * an empty step id and downstream stream consumers would drop\n * the result.\n *\n * The natural-completion / error / hook-driven-halt paths still\n * clean up — `_haltedReason != null` or `streamThrew` mean no\n * resume is expected. Cross-process resume (host rebuilds the\n * Run from scratch) is a separate concern; see\n * `HumanInTheLoopConfig` JSDoc.\n */\n const awaitingResume = this.isAwaitingResume(streamThrew);\n if (!this.skipCleanup && !awaitingResume) {\n this.Graph.clearHeavyState();\n }\n\n this._streamResult = result;\n }\n\n return this._streamResult;\n }\n\n /**\n * Returns the pending interrupt captured during the most recent\n * `processStream` (or `resume`) invocation. `undefined` when the run\n * either has not been streamed yet or completed without pausing.\n *\n * Hosts call this immediately after `processStream` returns to decide\n * whether the run is awaiting human input. Persist the returned\n * descriptor (alongside `thread_id` and the agent run config) so a\n * later `resume(decisions)` can rebuild the run.\n *\n * The default `TPayload` is the SDK's `HumanInterruptPayload` union\n * (`tool_approval` / `ask_user_question`), suitable for the common\n * case where interrupts come from the built-in ToolNode or\n * `askUserQuestion()` helper. Hosts that raise custom interrupts\n * from custom graph nodes pass their own type — the SDK does not\n * validate the runtime shape, it just transports whatever the\n * `interrupt()` call carried. When in doubt, narrow with the\n * `isToolApprovalInterrupt` / `isAskUserQuestionInterrupt` type\n * guards (which accept `unknown`) before reading variant-specific\n * fields.\n */\n getInterrupt<TPayload = t.HumanInterruptPayload>():\n | t.RunInterruptResult<TPayload>\n | undefined {\n return this._interrupt as t.RunInterruptResult<TPayload> | undefined;\n }\n\n /**\n * Returns the reason a hook halted the run via\n * `preventContinuation: true`, or `undefined` if no hook halted.\n *\n * Hosts inspect this after `processStream` returns to distinguish a\n * natural completion (`undefined`) from a hook-driven halt (a\n * truthy string). Independent from `getInterrupt()` — a halted run\n * has no interrupt; an interrupted run has no halt reason.\n */\n getHaltReason(): string | undefined {\n return this._haltedReason;\n }\n\n /**\n * Resume a paused HITL run with the value the user (or whatever\n * decided the interrupt) supplied. The default `TResume` covers the\n * `tool_approval` interrupt (the common case): an array of decisions\n * in `action_requests` order, or a record keyed by `tool_call_id`.\n *\n * For other interrupt types (e.g., `ask_user_question` →\n * `AskUserQuestionResolution`, or any custom interrupt a host raises\n * from a custom node), pass the type parameter and the SDK forwards\n * the value through unchanged. LangGraph delivers it as the return\n * value of the original `interrupt()` call inside the paused node.\n *\n * The host MUST construct this Run with the same `thread_id` and the\n * same checkpointer as the original paused run; LangGraph rebuilds\n * graph state from the checkpoint and re-enters the interrupted node\n * from the start.\n */\n /**\n * Returns the per-Run file checkpointer when\n * `toolExecution.local.fileCheckpointing === true` was set on the\n * RunConfig. Hosts can capture extra paths or call `rewind()`\n * directly. Returns undefined when checkpointing is disabled.\n *\n * Construction-time invariant: the checkpointer is shared across\n * every ToolNode the graph compiles (single-agent and multi-agent),\n * so a `rewind()` call here unwinds writes made by ANY agent in the\n * run.\n */\n getFileCheckpointer(): t.LocalFileCheckpointer | undefined {\n return this.Graph?.getOrCreateFileCheckpointer();\n }\n\n /**\n * Convenience wrapper that calls `rewind()` on the per-Run file\n * checkpointer. Restores every file the local engine snapshotted\n * during this Run to its pre-write content (and deletes any path\n * that didn't exist before being created). Returns the count of\n * paths processed; returns 0 when checkpointing is disabled.\n */\n async rewindFiles(): Promise<number> {\n const cp = this.getFileCheckpointer();\n return cp == null ? 0 : cp.rewind();\n }\n\n /**\n * Resume an interrupted run. `commandOptions` forwards langgraph 1.4.5\n * `Command` fields applied together with `resume` in one superstep:\n * - `update`: channel updates committed at the resume point. On a *rebuilt*\n * Run (new instance + durable checkpointer), `update.messages` are the first\n * write the fresh wrapper sees, so they seed the `getRunMessages()` /\n * `returnContent` baseline and are excluded from them (still committed to the\n * checkpoint). Hosts that rebuild + inject messages should persist them\n * directly or read from `getState`. Unreachable without a durable checkpointer.\n * - `goto`: a *dynamic* edge that does not cancel static `addEdge` routes. On\n * the built-in standard graph the fixed `toolNode -> agentNode/END` edge still\n * fires, so `goto` adds rather than replaces (e.g. `goto: END` will not stop a\n * tool-node resume). Intended for custom, Command-routed graphs.\n */\n async resume<TResume = t.ToolApprovalDecision[] | t.ToolApprovalDecisionMap>(\n resumeValue: TResume,\n callerConfig: Partial<RunnableConfig> & {\n version: 'v1' | 'v2';\n run_id?: string;\n },\n streamOptions?: t.EventStreamOptions,\n commandOptions?: Pick<\n ConstructorParameters<typeof Command>[0],\n 'update' | 'goto'\n >\n ): Promise<MessageContentComplex[] | undefined> {\n const interruptId = this._interrupt?.interruptId;\n const scopedResume =\n typeof interruptId === 'string' &&\n interruptId.length > 0 &&\n !isLangGraphResumeMapForInterrupt(resumeValue, interruptId)\n ? { [interruptId]: resumeValue }\n : resumeValue;\n const resumeConfig = await this.resolveInterruptResumeConfig(callerConfig);\n // langgraph 1.4.5 applies resume + state update + reroute in one superstep\n // (single checkpoint). `update`/`goto` are omitted unless the caller sets them.\n return this.processStream(\n new Command({\n resume: scopedResume,\n ...(commandOptions?.update !== undefined\n ? { update: commandOptions.update }\n : {}),\n ...(commandOptions?.goto !== undefined\n ? { goto: commandOptions.goto }\n : {}),\n }),\n resumeConfig,\n streamOptions\n );\n }\n\n private async resolveInterruptResumeConfig(\n callerConfig: Partial<RunnableConfig> & {\n version: 'v1' | 'v2';\n run_id?: string;\n }\n ): Promise<\n Partial<RunnableConfig> & {\n version: 'v1' | 'v2';\n run_id?: string;\n }\n > {\n const interrupt = this._interrupt;\n const interruptId = interrupt?.interruptId;\n const workflow = this.graphRunnable as\n | (t.CompiledStateWorkflow & WorkflowWithStateHistory)\n | undefined;\n const stateHistory = workflow?.getStateHistory;\n if (interrupt?.checkpointId != null && interrupt.checkpointId.length > 0) {\n return {\n ...callerConfig,\n configurable: {\n ...callerConfig.configurable,\n checkpoint_id: interrupt.checkpointId,\n ...(typeof interrupt.checkpointNs === 'string'\n ? { checkpoint_ns: interrupt.checkpointNs }\n : {}),\n },\n };\n }\n if (\n interrupt == null ||\n typeof interruptId !== 'string' ||\n interruptId.length === 0 ||\n typeof stateHistory !== 'function'\n ) {\n return callerConfig;\n }\n\n for await (const snapshot of stateHistory.call(\n this.graphRunnable,\n callerConfig as RunnableConfig\n )) {\n const hasMatchingInterrupt =\n snapshot.tasks?.some(\n (task) =>\n task.interrupts?.some(\n (interrupt) => interrupt.id === interruptId\n ) === true\n ) === true;\n const checkpointConfigurable = snapshot.config?.configurable;\n if (!hasMatchingInterrupt || checkpointConfigurable == null) {\n continue;\n }\n\n const checkpointId = checkpointConfigurable.checkpoint_id;\n const checkpointNs = checkpointConfigurable.checkpoint_ns;\n if (typeof checkpointId === 'string' && checkpointId.length > 0) {\n this._interrupt = {\n ...interrupt,\n checkpointId,\n ...(typeof checkpointNs === 'string' ? { checkpointNs } : {}),\n };\n return {\n ...callerConfig,\n configurable: {\n ...callerConfig.configurable,\n checkpoint_id: checkpointId,\n ...(typeof checkpointNs === 'string'\n ? { checkpoint_ns: checkpointNs }\n : {}),\n },\n };\n }\n }\n\n return callerConfig;\n }\n\n private createSystemCallback<K extends keyof t.ClientCallbacks>(\n clientCallbacks: t.ClientCallbacks,\n key: K\n ): t.SystemCallbacks[K] {\n return ((...args: unknown[]) => {\n const clientCallback = clientCallbacks[key];\n if (clientCallback && this.Graph) {\n (clientCallback as (...args: unknown[]) => void)(this.Graph, ...args);\n }\n }) as t.SystemCallbacks[K];\n }\n\n getCallbacks(clientCallbacks: t.ClientCallbacks): t.SystemCallbacks {\n return {\n [Callback.TOOL_ERROR]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_ERROR\n ),\n [Callback.TOOL_START]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_START\n ),\n [Callback.TOOL_END]: this.createSystemCallback(\n clientCallbacks,\n Callback.TOOL_END\n ),\n };\n }\n\n async generateTitle({\n provider,\n inputText,\n contentParts,\n titlePrompt,\n clientOptions,\n chainOptions,\n skipLanguage,\n titleMethod = TitleMethod.COMPLETION,\n titlePromptTemplate,\n }: t.RunTitleOptions): Promise<{ language?: string; title?: string }> {\n let titleLangfuseHandler: CallbackEntry | undefined;\n let titleLangfuseConfig: t.LangfuseConfig | undefined;\n let titleUserId: string | undefined;\n let titleSessionId: string | undefined;\n const titleContext =\n this.Graph == null\n ? undefined\n : this.Graph.agentContexts.get(this.Graph.defaultAgentId);\n const traceMetadata = createLangfuseTraceMetadata({\n messageId: 'title-' + this.id,\n agentName: titleContext?.name,\n });\n const titleRunName = getLangfuseTraceName(traceMetadata, 'LibreChat Title');\n\n if (chainOptions != null) {\n titleUserId =\n typeof chainOptions.configurable?.user_id === 'string'\n ? chainOptions.configurable.user_id\n : undefined;\n titleSessionId =\n typeof chainOptions.configurable?.thread_id === 'string'\n ? chainOptions.configurable.thread_id\n : undefined;\n titleLangfuseConfig = resolveLangfuseConfig(\n this.langfuse,\n titleContext?.langfuse\n );\n initializeLangfuseTracing(titleLangfuseConfig);\n titleLangfuseHandler = createLangfuseHandler({\n langfuse: titleLangfuseConfig,\n userId: titleUserId,\n sessionId: titleSessionId,\n traceMetadata,\n tags: ['librechat', 'title'],\n traceIdSeed:\n titleLangfuseConfig?.deterministicTraceId === true\n ? 'title-' + this.id\n : undefined,\n });\n\n if (titleLangfuseHandler != null) {\n chainOptions.callbacks = appendCallbacks(chainOptions.callbacks, [\n titleLangfuseHandler,\n ]);\n }\n }\n\n const convoTemplate = PromptTemplate.fromTemplate(\n titlePromptTemplate ?? 'User: {input}\\nAI: {output}'\n );\n\n const response = contentParts\n .map((part) => {\n if (part?.type === 'text') return part.text;\n return '';\n })\n .join('\\n');\n\n const model = initializeModel({\n provider,\n clientOptions,\n }) as t.ChatModelInstance;\n\n if (\n isOpenAILike(provider) &&\n (model instanceof ChatOpenAI || model instanceof AzureChatOpenAI)\n ) {\n model.temperature = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.temperature as number;\n model.topP = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.topP as number;\n model.frequencyPenalty = (\n clientOptions as t.OpenAIClientOptions | undefined\n )?.frequencyPenalty as number;\n model.presencePenalty = (\n clientOptions as t.OpenAIClientOptions | undefined\n )?.presencePenalty as number;\n model.n = (clientOptions as t.OpenAIClientOptions | undefined)\n ?.n as number;\n }\n\n const convoToTitleInput = new RunnableLambda({\n func: (\n promptValue: StringPromptValue\n ): { convo: string; inputText: string; skipLanguage?: boolean } => ({\n convo: promptValue.value,\n inputText,\n skipLanguage,\n }),\n }).withConfig({ runName: 'ConvoTransform' });\n\n const titleChain =\n titleMethod === TitleMethod.COMPLETION\n ? await createCompletionTitleRunnable(model, titlePrompt)\n : await createTitleRunnable(model, titlePrompt);\n\n /** Pipes `convoTemplate` -> `transformer` -> `titleChain` */\n const fullChain = convoTemplate\n .withConfig({ runName: 'ConvoTemplate' })\n .pipe(convoToTitleInput)\n .pipe(titleChain)\n .withConfig({ runName: 'TitleChain' });\n\n const invokeConfig = Object.assign({}, chainOptions, {\n run_id: this.id,\n runId: this.id,\n runName: chainOptions?.runName ?? titleRunName,\n });\n\n const invokeTitleChain = (\n runtimeConfig: Partial<RunnableConfig>\n ): Promise<{ language?: string; title?: string }> =>\n withLangfuseAttributes(\n {\n langfuse: titleLangfuseConfig,\n userId: titleUserId,\n sessionId: titleSessionId,\n traceName: runtimeConfig.runName ?? titleRunName,\n traceMetadata,\n tags: ['librechat', 'title'],\n },\n () =>\n fullChain.invoke(\n { input: inputText, output: response },\n runtimeConfig\n )\n );\n\n try {\n try {\n return await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: this.langfuse,\n langfuseOverlay: titleContext?.langfuse,\n }),\n () => invokeTitleChain(invokeConfig)\n );\n } catch (_e) {\n // Fallback: strip callbacks to avoid EventStream tracer errors in certain environments\n // but preserve Langfuse tracing if it exists.\n const langfuseHandler = findCallback(\n invokeConfig.callbacks,\n isLangfuseCallbackHandler\n );\n const { callbacks: _cb, ...rest } = invokeConfig;\n const safeConfig = Object.assign({}, rest, {\n callbacks: langfuseHandler ? [langfuseHandler] : [],\n });\n return await withLangfuseRuntimeScope(\n resolveLangfuseRuntimeScope({\n runLangfuse: this.langfuse,\n langfuseOverlay: titleContext?.langfuse,\n }),\n () => invokeTitleChain(safeConfig as Partial<RunnableConfig>)\n );\n }\n } finally {\n await disposeLangfuseHandler(titleLangfuseHandler);\n }\n }\n}\n\nfunction findLastMessageOfType(\n messages: BaseMessage[],\n type: string\n): BaseMessage | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].getType() === type) {\n return messages[i];\n }\n }\n return undefined;\n}\n\nfunction extractPromptText(message: BaseMessage): string {\n const content = message.content;\n if (typeof content === 'string') {\n return content;\n }\n if (!Array.isArray(content)) {\n return String(content);\n }\n const parts: string[] = [];\n for (const block of content) {\n if (\n typeof block === 'object' &&\n 'type' in block &&\n block.type === 'text' &&\n 'text' in block &&\n typeof block.text === 'string'\n ) {\n parts.push(block.text);\n }\n }\n return parts.join('\\n');\n}\n"],"mappings":"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"}