@ai-sdk/langchain 2.0.0-beta.98 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +641 -0
- package/README.md +200 -1
- package/dist/index.d.mts +104 -32
- package/dist/index.d.ts +104 -32
- package/dist/index.js +751 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +759 -56
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/stream-callbacks.ts","../src/langchain-adapter.ts"],"sourcesContent":["export * from './langchain-adapter';\n","/**\n * Configuration options and helper callback methods for stream lifecycle events.\n */\nexport interface StreamCallbacks {\n /** `onStart`: Called once when the stream is initialized. */\n onStart?: () => Promise<void> | void;\n\n /** `onFinal`: Called once when the stream is closed with the final completion message. */\n onFinal?: (completion: string) => Promise<void> | void;\n\n /** `onToken`: Called for each tokenized message. */\n onToken?: (token: string) => Promise<void> | void;\n\n /** `onText`: Called for each text chunk. */\n onText?: (text: string) => Promise<void> | void;\n}\n\n/**\n * Creates a transform stream that encodes input messages and invokes optional callback functions.\n * The transform stream uses the provided callbacks to execute custom logic at different stages of the stream's lifecycle.\n * - `onStart`: Called once when the stream is initialized.\n * - `onToken`: Called for each tokenized message.\n * - `onFinal`: Called once when the stream is closed with the final completion message.\n *\n * This function is useful when you want to process a stream of messages and perform specific actions during the stream's lifecycle.\n *\n * @param {StreamCallbacks} [callbacks] - An object containing the callback functions.\n * @return {TransformStream<string, Uint8Array>} A transform stream that encodes input messages as Uint8Array and allows the execution of custom logic through callbacks.\n *\n * @example\n * const callbacks = {\n * onStart: async () => console.log('Stream started'),\n * onToken: async (token) => console.log(`Token: ${token}`),\n * onFinal: async () => data.close()\n * };\n * const transformer = createCallbacksTransformer(callbacks);\n */\nexport function createCallbacksTransformer(\n callbacks: StreamCallbacks | undefined = {},\n): TransformStream<string, string> {\n let aggregatedResponse = '';\n\n return new TransformStream({\n async start(): Promise<void> {\n if (callbacks.onStart) await callbacks.onStart();\n },\n\n async transform(message, controller): Promise<void> {\n controller.enqueue(message);\n\n aggregatedResponse += message;\n\n if (callbacks.onToken) await callbacks.onToken(message);\n if (callbacks.onText && typeof message === 'string') {\n await callbacks.onText(message);\n }\n },\n\n async flush(): Promise<void> {\n if (callbacks.onFinal) {\n await callbacks.onFinal(aggregatedResponse);\n }\n },\n });\n}\n","import { UIMessageChunk } from 'ai';\nimport {\n createCallbacksTransformer,\n StreamCallbacks,\n} from './stream-callbacks';\n\ntype LangChainImageDetail = 'auto' | 'low' | 'high';\n\ntype LangChainMessageContentText = {\n type: 'text';\n text: string;\n};\n\ntype LangChainMessageContentImageUrl = {\n type: 'image_url';\n image_url:\n | string\n | {\n url: string;\n detail?: LangChainImageDetail;\n };\n};\n\ntype LangChainMessageContentComplex =\n | LangChainMessageContentText\n | LangChainMessageContentImageUrl\n | (Record<string, any> & {\n type?: 'text' | 'image_url' | string;\n })\n | (Record<string, any> & {\n type?: never;\n });\n\ntype LangChainMessageContent = string | LangChainMessageContentComplex[];\n\ntype LangChainAIMessageChunk = {\n content: LangChainMessageContent;\n};\n\n// LC stream event v2\ntype LangChainStreamEvent = {\n event: string;\n data: any;\n};\n\n/**\nConverts LangChain output streams to an AI SDK Data Stream.\n\nThe following streams are supported:\n- `LangChainAIMessageChunk` streams (LangChain `model.stream` output)\n- `string` streams (LangChain `StringOutputParser` output)\n */\nexport function toUIMessageStream(\n stream:\n | ReadableStream<LangChainStreamEvent>\n | ReadableStream<LangChainAIMessageChunk>\n | ReadableStream<string>,\n callbacks?: StreamCallbacks,\n) {\n return stream\n .pipeThrough(\n new TransformStream<\n LangChainStreamEvent | LangChainAIMessageChunk | string\n >({\n transform: async (value, controller) => {\n // text stream:\n if (typeof value === 'string') {\n controller.enqueue(value);\n return;\n }\n\n // LC stream events v2:\n if ('event' in value) {\n // chunk is AIMessage Chunk for on_chat_model_stream event:\n if (value.event === 'on_chat_model_stream') {\n forwardAIMessageChunk(\n value.data?.chunk as LangChainAIMessageChunk,\n controller,\n );\n }\n return;\n }\n\n // AI Message chunk stream:\n forwardAIMessageChunk(value, controller);\n },\n }),\n )\n .pipeThrough(createCallbacksTransformer(callbacks))\n .pipeThrough(\n new TransformStream<string, UIMessageChunk>({\n start: async controller => {\n controller.enqueue({ type: 'text-start', id: '1' });\n },\n transform: async (chunk, controller) => {\n controller.enqueue({ type: 'text-delta', delta: chunk, id: '1' });\n },\n flush: async controller => {\n controller.enqueue({ type: 'text-end', id: '1' });\n },\n }),\n );\n}\n\nfunction forwardAIMessageChunk(\n chunk: LangChainAIMessageChunk,\n controller: TransformStreamDefaultController<any>,\n) {\n if (typeof chunk.content === 'string') {\n controller.enqueue(chunk.content);\n } else {\n const content: LangChainMessageContentComplex[] = chunk.content;\n for (const item of content) {\n if (item.type === 'text') {\n controller.enqueue(item.text);\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqCO,SAAS,2BACd,YAAyC,CAAC,GACT;AACjC,MAAI,qBAAqB;AAEzB,SAAO,IAAI,gBAAgB;AAAA,IACzB,MAAM,QAAuB;AAC3B,UAAI,UAAU,QAAS,OAAM,UAAU,QAAQ;AAAA,IACjD;AAAA,IAEA,MAAM,UAAU,SAAS,YAA2B;AAClD,iBAAW,QAAQ,OAAO;AAE1B,4BAAsB;AAEtB,UAAI,UAAU,QAAS,OAAM,UAAU,QAAQ,OAAO;AACtD,UAAI,UAAU,UAAU,OAAO,YAAY,UAAU;AACnD,cAAM,UAAU,OAAO,OAAO;AAAA,MAChC;AAAA,IACF;AAAA,IAEA,MAAM,QAAuB;AAC3B,UAAI,UAAU,SAAS;AACrB,cAAM,UAAU,QAAQ,kBAAkB;AAAA,MAC5C;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;ACZO,SAAS,kBACd,QAIA,WACA;AACA,SAAO,OACJ;AAAA,IACC,IAAI,gBAEF;AAAA,MACA,WAAW,OAAO,OAAO,eAAe;AAhEhD;AAkEU,YAAI,OAAO,UAAU,UAAU;AAC7B,qBAAW,QAAQ,KAAK;AACxB;AAAA,QACF;AAGA,YAAI,WAAW,OAAO;AAEpB,cAAI,MAAM,UAAU,wBAAwB;AAC1C;AAAA,eACE,WAAM,SAAN,mBAAY;AAAA,cACZ;AAAA,YACF;AAAA,UACF;AACA;AAAA,QACF;AAGA,8BAAsB,OAAO,UAAU;AAAA,MACzC;AAAA,IACF,CAAC;AAAA,EACH,EACC,YAAY,2BAA2B,SAAS,CAAC,EACjD;AAAA,IACC,IAAI,gBAAwC;AAAA,MAC1C,OAAO,OAAM,eAAc;AACzB,mBAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,IAAI,CAAC;AAAA,MACpD;AAAA,MACA,WAAW,OAAO,OAAO,eAAe;AACtC,mBAAW,QAAQ,EAAE,MAAM,cAAc,OAAO,OAAO,IAAI,IAAI,CAAC;AAAA,MAClE;AAAA,MACA,OAAO,OAAM,eAAc;AACzB,mBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,IAAI,CAAC;AAAA,MAClD;AAAA,IACF,CAAC;AAAA,EACH;AACJ;AAEA,SAAS,sBACP,OACA,YACA;AACA,MAAI,OAAO,MAAM,YAAY,UAAU;AACrC,eAAW,QAAQ,MAAM,OAAO;AAAA,EAClC,OAAO;AACL,UAAM,UAA4C,MAAM;AACxD,eAAW,QAAQ,SAAS;AAC1B,UAAI,KAAK,SAAS,QAAQ;AACxB,mBAAW,QAAQ,KAAK,IAAI;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/adapter.ts","../src/utils.ts","../src/transport.ts"],"sourcesContent":["export {\n toBaseMessages,\n toUIMessageStream,\n convertModelMessages,\n} from './adapter';\n\nexport {\n LangSmithDeploymentTransport,\n type LangSmithDeploymentTransportOptions,\n} from './transport';\n\nexport { type StreamCallbacks } from './stream-callbacks';\n","import {\n SystemMessage,\n BaseMessage,\n AIMessageChunk,\n} from '@langchain/core/messages';\nimport {\n type UIMessage,\n type UIMessageChunk,\n convertToModelMessages,\n type ModelMessage,\n} from 'ai';\nimport {\n convertToolResultPart,\n convertAssistantContent,\n convertUserContent,\n processModelChunk,\n processLangGraphEvent,\n isToolResultPart,\n} from './utils';\nimport { type LangGraphEventState } from './types';\nimport { type StreamCallbacks } from './stream-callbacks';\n\n/**\n * Converts AI SDK UIMessages to LangChain BaseMessage objects.\n *\n * This function transforms the AI SDK's message format into LangChain's message\n * format, enabling seamless integration between the two frameworks.\n *\n * @param messages - Array of AI SDK UIMessage objects to convert.\n * @returns Promise resolving to an array of LangChain BaseMessage objects.\n *\n * @example\n * ```ts\n * import { toBaseMessages } from '@ai-sdk/langchain';\n *\n * const langchainMessages = await toBaseMessages(uiMessages);\n *\n * // Use with LangChain\n * const response = await model.invoke(langchainMessages);\n * ```\n */\nexport async function toBaseMessages(\n messages: UIMessage[],\n): Promise<BaseMessage[]> {\n const modelMessages = await convertToModelMessages(messages);\n return convertModelMessages(modelMessages);\n}\n\n/**\n * Converts ModelMessages to LangChain BaseMessage objects.\n *\n * @param modelMessages - Array of ModelMessage objects from convertToModelMessages.\n * @returns Array of LangChain BaseMessage objects.\n */\nexport function convertModelMessages(\n modelMessages: ModelMessage[],\n): BaseMessage[] {\n const result: BaseMessage[] = [];\n\n for (const message of modelMessages) {\n switch (message.role) {\n case 'tool': {\n // Tool messages contain an array of tool results\n for (const item of message.content) {\n if (isToolResultPart(item)) {\n result.push(convertToolResultPart(item));\n }\n }\n break;\n }\n\n case 'assistant': {\n result.push(convertAssistantContent(message.content));\n break;\n }\n\n case 'system': {\n result.push(new SystemMessage({ content: message.content }));\n break;\n }\n\n case 'user': {\n result.push(convertUserContent(message.content));\n break;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Converts a LangChain stream to an AI SDK UIMessageStream.\n *\n * This function automatically detects the stream type and handles both:\n * - Direct model streams (AsyncIterable from `model.stream()`)\n * - LangGraph streams (ReadableStream with `streamMode: ['values', 'messages']`)\n *\n * @param stream - A stream from LangChain model.stream() or LangGraph graph.stream().\n * @param callbacks - Optional callbacks for stream lifecycle events.\n * @returns A ReadableStream of UIMessageChunk objects.\n *\n * @example\n * ```ts\n * // With a direct model stream\n * const model = new ChatOpenAI({ model: 'gpt-4o-mini' });\n * const stream = await model.stream(messages);\n * return createUIMessageStreamResponse({\n * stream: toUIMessageStream(stream),\n * });\n *\n * // With a LangGraph stream\n * const graphStream = await graph.stream(\n * { messages },\n * { streamMode: ['values', 'messages'] }\n * );\n * return createUIMessageStreamResponse({\n * stream: toUIMessageStream(graphStream),\n * });\n * ```\n */\nexport function toUIMessageStream(\n stream: AsyncIterable<AIMessageChunk> | ReadableStream,\n callbacks?: StreamCallbacks,\n): ReadableStream<UIMessageChunk> {\n /**\n * Track text chunks for onFinal callback\n */\n const textChunks: string[] = [];\n\n /**\n * State for model stream handling\n */\n const modelState = {\n started: false,\n messageId: 'langchain-msg-1',\n reasoningStarted: false,\n textStarted: false,\n };\n\n /**\n * State for LangGraph stream handling\n */\n const langGraphState: LangGraphEventState = {\n messageSeen: {} as Record<\n string,\n { text?: boolean; reasoning?: boolean; tool?: Record<string, boolean> }\n >,\n messageConcat: {} as Record<string, AIMessageChunk>,\n emittedToolCalls: new Set<string>(),\n emittedImages: new Set<string>(),\n emittedReasoningIds: new Set<string>(),\n messageReasoningIds: {} as Record<string, string>,\n toolCallInfoByIndex: {} as Record<\n string,\n Record<number, { id: string; name: string }>\n >,\n currentStep: null as number | null,\n emittedToolCallsByKey: new Map<string, string>(),\n };\n\n /**\n * Track detected stream type: null = not yet detected\n */\n let streamType: 'model' | 'langgraph' | null = null;\n\n /**\n * Get async iterator from the stream (works for both AsyncIterable and ReadableStream)\n */\n const getAsyncIterator = (): AsyncIterator<unknown> => {\n if (Symbol.asyncIterator in stream) {\n return (stream as AsyncIterable<unknown>)[Symbol.asyncIterator]();\n }\n /**\n * For ReadableStream without Symbol.asyncIterator\n */\n const reader = (stream as ReadableStream).getReader();\n return {\n async next() {\n const { done, value } = await reader.read();\n return { done, value };\n },\n };\n };\n\n const iterator = getAsyncIterator();\n\n /**\n * Create a wrapper around the controller to intercept text chunks for callbacks\n */\n const createCallbackController = (\n originalController: ReadableStreamDefaultController<UIMessageChunk>,\n ): ReadableStreamDefaultController<UIMessageChunk> => {\n return {\n get desiredSize() {\n return originalController.desiredSize;\n },\n close: () => originalController.close(),\n error: (e?: unknown) => originalController.error(e),\n enqueue: (chunk: UIMessageChunk) => {\n /**\n * Intercept text-delta chunks for callbacks\n */\n if (callbacks && chunk.type === 'text-delta' && chunk.delta) {\n textChunks.push(chunk.delta);\n callbacks.onToken?.(chunk.delta);\n callbacks.onText?.(chunk.delta);\n }\n originalController.enqueue(chunk);\n },\n };\n };\n\n return new ReadableStream<UIMessageChunk>({\n async start(controller) {\n await callbacks?.onStart?.();\n\n const wrappedController = createCallbackController(controller);\n controller.enqueue({ type: 'start' });\n\n try {\n while (true) {\n const { done, value } = await iterator.next();\n if (done) break;\n\n /**\n * Detect stream type on first value\n */\n if (streamType === null) {\n if (Array.isArray(value)) {\n streamType = 'langgraph';\n } else {\n streamType = 'model';\n }\n }\n\n /**\n * Process based on detected type\n */\n if (streamType === 'model') {\n processModelChunk(\n value as AIMessageChunk,\n modelState,\n wrappedController,\n );\n } else {\n processLangGraphEvent(\n value as unknown[],\n langGraphState,\n wrappedController,\n );\n }\n }\n\n /**\n * Finalize based on stream type\n */\n if (streamType === 'model') {\n if (modelState.reasoningStarted) {\n controller.enqueue({\n type: 'reasoning-end',\n id: modelState.messageId,\n });\n }\n if (modelState.textStarted) {\n controller.enqueue({ type: 'text-end', id: modelState.messageId });\n }\n controller.enqueue({ type: 'finish' });\n }\n\n /**\n * Call onFinal callback with aggregated text\n */\n await callbacks?.onFinal?.(textChunks.join(''));\n } catch (error) {\n controller.enqueue({\n type: 'error',\n errorText: error instanceof Error ? error.message : 'Unknown error',\n });\n } finally {\n controller.close();\n }\n },\n });\n}\n","import {\n AIMessage,\n HumanMessage,\n ToolMessage,\n BaseMessage,\n AIMessageChunk,\n BaseMessageChunk,\n ToolCallChunk,\n type ToolCall,\n} from '@langchain/core/messages';\nimport {\n type UIMessageChunk,\n type ToolResultPart,\n type AssistantContent,\n type UserContent,\n} from 'ai';\n\nimport {\n type LangGraphEventState,\n type ReasoningContentBlock,\n type ThinkingContentBlock,\n type GPT5ReasoningOutput,\n type ImageGenerationOutput,\n} from './types';\n\n/**\n * Converts a ToolResultPart to a LangChain ToolMessage\n * @param block - The ToolResultPart to convert.\n * @returns The converted ToolMessage.\n */\nexport function convertToolResultPart(block: ToolResultPart): ToolMessage {\n const content = (() => {\n if (block.output.type === 'text' || block.output.type === 'error-text') {\n return block.output.value;\n }\n\n if (block.output.type === 'json' || block.output.type === 'error-json') {\n return JSON.stringify(block.output.value);\n }\n\n if (block.output.type === 'content') {\n return block.output.value\n .map(outputBlock => {\n if (outputBlock.type === 'text') {\n return outputBlock.text;\n }\n return '';\n })\n .join('');\n }\n\n return '';\n })();\n\n return new ToolMessage({\n tool_call_id: block.toolCallId,\n content,\n });\n}\n\n/**\n * Converts AssistantContent to LangChain AIMessage\n * @param content - The AssistantContent to convert.\n * @returns The converted AIMessage.\n */\nexport function convertAssistantContent(content: AssistantContent): AIMessage {\n if (typeof content === 'string') {\n return new AIMessage({ content });\n }\n\n const textParts: string[] = [];\n const toolCalls: Array<{\n id: string;\n name: string;\n args: Record<string, unknown>;\n }> = [];\n\n for (const part of content) {\n if (part.type === 'text') {\n textParts.push(part.text);\n } else if (part.type === 'tool-call') {\n toolCalls.push({\n id: part.toolCallId,\n name: part.toolName,\n args: part.input as Record<string, unknown>,\n });\n }\n }\n\n return new AIMessage({\n content: textParts.join(''),\n tool_calls: toolCalls.length > 0 ? toolCalls : undefined,\n });\n}\n\n/**\n * Converts UserContent to LangChain HumanMessage\n * @param content - The UserContent to convert.\n * @returns The converted HumanMessage.\n */\nexport function convertUserContent(content: UserContent): HumanMessage {\n if (typeof content === 'string') {\n return new HumanMessage({ content });\n }\n\n const textParts = content\n .filter(\n (part): part is { type: 'text'; text: string } => part.type === 'text',\n )\n .map(part => part.text);\n\n return new HumanMessage({ content: textParts.join('') });\n}\n\n/**\n * Helper to check if a content item is a ToolResultPart\n * @param item - The item to check.\n * @returns True if the item is a ToolResultPart, false otherwise.\n */\nexport function isToolResultPart(item: unknown): item is ToolResultPart {\n return (\n item != null &&\n typeof item === 'object' &&\n 'type' in item &&\n (item as { type: string }).type === 'tool-result'\n );\n}\n\n/**\n * Processes a model stream chunk and emits UI message chunks.\n * @param chunk - The AIMessageChunk to process.\n * @param state - The state of the model stream.\n * @param controller - The controller to use to emit the UI message chunks.\n */\nexport function processModelChunk(\n chunk: AIMessageChunk,\n state: {\n started: boolean;\n messageId: string;\n reasoningStarted?: boolean;\n textStarted?: boolean;\n },\n controller: ReadableStreamDefaultController<UIMessageChunk>,\n): void {\n /**\n * Get the message ID from the chunk if available\n */\n if (chunk.id) {\n state.messageId = chunk.id;\n }\n\n /**\n * Handle reasoning content from contentBlocks or response_metadata.output\n * For direct model streams, we check both sources since there's no values event\n * that would cause duplication (unlike LangGraph streams)\n */\n const reasoning =\n extractReasoningFromContentBlocks(chunk) ||\n extractReasoningFromValuesMessage(chunk);\n if (reasoning) {\n if (!state.reasoningStarted) {\n controller.enqueue({ type: 'reasoning-start', id: state.messageId });\n state.reasoningStarted = true;\n state.started = true;\n }\n controller.enqueue({\n type: 'reasoning-delta',\n delta: reasoning,\n id: state.messageId,\n });\n }\n\n /**\n * Extract text content from AIMessageChunk\n */\n const text =\n typeof chunk.content === 'string'\n ? chunk.content\n : Array.isArray(chunk.content)\n ? chunk.content\n .filter(\n (c): c is { type: 'text'; text: string } =>\n typeof c === 'object' &&\n c !== null &&\n 'type' in c &&\n c.type === 'text',\n )\n .map(c => c.text)\n .join('')\n : '';\n\n if (text) {\n /**\n * If reasoning was streamed before text, close reasoning first\n */\n if (state.reasoningStarted && !state.textStarted) {\n controller.enqueue({ type: 'reasoning-end', id: state.messageId });\n state.reasoningStarted = false;\n }\n\n if (!state.textStarted) {\n controller.enqueue({ type: 'text-start', id: state.messageId });\n state.textStarted = true;\n state.started = true;\n }\n controller.enqueue({\n type: 'text-delta',\n delta: text,\n id: state.messageId,\n });\n }\n}\n\n/**\n * Checks if a message is a plain object (not a LangChain class instance).\n * LangChain class instances have a _getType method.\n *\n * @param msg - The message to check.\n * @returns True if the message is a plain object, false otherwise.\n */\nexport function isPlainMessageObject(msg: unknown): boolean {\n if (msg == null || typeof msg !== 'object') return false;\n /**\n * LangChain class instances have _getType method\n */\n return typeof (msg as { _getType?: unknown })._getType !== 'function';\n}\n\n/**\n * Extracts the actual message ID from a message.\n * Handles both class instances (msg.id) and serialized LangChain messages (msg.kwargs.id).\n *\n * @param msg - The message to extract the ID from.\n * @returns The message ID string, or undefined if not found.\n */\nexport function getMessageId(msg: unknown): string | undefined {\n if (msg == null || typeof msg !== 'object') return undefined;\n\n const msgObj = msg as Record<string, unknown>;\n\n /**\n * For class instances, id is directly on the object\n */\n if (typeof msgObj.id === 'string') {\n return msgObj.id;\n }\n\n /**\n * For serialized LangChain messages, id is in kwargs\n */\n if (\n msgObj.type === 'constructor' &&\n msgObj.kwargs &&\n typeof msgObj.kwargs === 'object'\n ) {\n const kwargs = msgObj.kwargs as Record<string, unknown>;\n if (typeof kwargs.id === 'string') {\n return kwargs.id;\n }\n }\n\n return undefined;\n}\n\n/**\n * Checks if a message is an AI message chunk (works for both class instances and plain objects).\n * For class instances, only AIMessageChunk is matched (not AIMessage).\n * For plain objects from RemoteGraph API, matches type === 'ai'.\n * For serialized LangChain messages, matches type === 'constructor' with AIMessageChunk in id path.\n *\n * @param msg - The message to check.\n * @returns True if the message is an AI message chunk, false otherwise.\n */\nexport function isAIMessageChunk(\n msg: unknown,\n): msg is AIMessageChunk & { type?: string; content?: string } {\n /**\n * Actual AIMessageChunk class instance\n */\n if (AIMessageChunk.isInstance(msg)) return true;\n /**\n * Plain object from RemoteGraph API (not a LangChain class instance)\n */\n if (isPlainMessageObject(msg)) {\n const obj = msg as Record<string, unknown>;\n /**\n * Direct type === 'ai' (RemoteGraph format)\n */\n if ('type' in obj && obj.type === 'ai') return true;\n /**\n * Serialized LangChain message format: { lc: 1, type: \"constructor\", id: [\"...\", \"AIMessageChunk\"], kwargs: {...} }\n */\n if (\n obj.type === 'constructor' &&\n Array.isArray(obj.id) &&\n (obj.id.includes('AIMessageChunk') || obj.id.includes('AIMessage'))\n ) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Checks if a message is a Tool message (works for both class instances and plain objects).\n *\n * @param msg - The message to check.\n * @returns True if the message is a Tool message, false otherwise.\n */\nexport function isToolMessageType(\n msg: unknown,\n): msg is ToolMessage & { type?: string; tool_call_id?: string } {\n if (ToolMessage.isInstance(msg)) return true;\n /**\n * Plain object from RemoteGraph API (not a LangChain class instance)\n */\n if (isPlainMessageObject(msg)) {\n const obj = msg as Record<string, unknown>;\n // Direct type === 'tool' (RemoteGraph format)\n if ('type' in obj && obj.type === 'tool') return true;\n // Serialized LangChain message format\n if (\n obj.type === 'constructor' &&\n Array.isArray(obj.id) &&\n obj.id.includes('ToolMessage')\n ) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Gets text content from a message (works for both class instances and plain objects).\n *\n * @param msg - The message to get the text from.\n * @returns The text content of the message.\n */\nexport function getMessageText(msg: unknown): string {\n if (AIMessageChunk.isInstance(msg)) {\n return msg.text ?? '';\n }\n\n if (msg == null || typeof msg !== 'object') return '';\n\n const msgObj = msg as Record<string, unknown>;\n\n // For serialized LangChain messages, content is in kwargs\n const dataSource =\n msgObj.type === 'constructor' &&\n msgObj.kwargs &&\n typeof msgObj.kwargs === 'object'\n ? (msgObj.kwargs as Record<string, unknown>)\n : msgObj;\n\n if ('content' in dataSource) {\n const content = dataSource.content;\n /**\n * Handle string content\n */\n if (typeof content === 'string') {\n return content;\n }\n /**\n * Handle array of content blocks (e.g., [{ type: 'text', text: 'The', index: 0 }])\n */\n if (Array.isArray(content)) {\n return content\n .filter(\n (block): block is { type: 'text'; text: string } =>\n block != null &&\n typeof block === 'object' &&\n block.type === 'text' &&\n typeof block.text === 'string',\n )\n .map(block => block.text)\n .join('');\n }\n return '';\n }\n return '';\n}\n\n/**\n * Checks if an object is a reasoning content block\n *\n * @param obj - The object to check.\n * @returns True if the object is a reasoning content block, false otherwise.\n */\nexport function isReasoningContentBlock(\n obj: unknown,\n): obj is ReasoningContentBlock {\n return (\n obj != null &&\n typeof obj === 'object' &&\n 'type' in obj &&\n (obj as { type: string }).type === 'reasoning' &&\n 'reasoning' in obj &&\n typeof (obj as { reasoning: unknown }).reasoning === 'string'\n );\n}\n\n/**\n * Checks if an object is a thinking content block (Anthropic-style)\n *\n * @param obj - The object to check.\n * @returns True if the object is a thinking content block, false otherwise.\n */\nexport function isThinkingContentBlock(\n obj: unknown,\n): obj is ThinkingContentBlock {\n return (\n obj != null &&\n typeof obj === 'object' &&\n 'type' in obj &&\n (obj as { type: string }).type === 'thinking' &&\n 'thinking' in obj &&\n typeof (obj as { thinking: unknown }).thinking === 'string'\n );\n}\n\n/**\n * Checks if an object is a GPT-5 reasoning output block\n */\nfunction isGPT5ReasoningOutput(obj: unknown): obj is GPT5ReasoningOutput {\n return (\n obj != null &&\n typeof obj === 'object' &&\n 'type' in obj &&\n (obj as { type: string }).type === 'reasoning' &&\n 'summary' in obj &&\n Array.isArray((obj as { summary: unknown }).summary)\n );\n}\n\n/**\n * Extracts the reasoning block ID from a message (GPT-5 format).\n * This ID is consistent across streaming and values events.\n * Handles both class instances and serialized LangChain message objects.\n *\n * @param msg - The message to extract the reasoning ID from.\n * @returns The reasoning block ID if found, undefined otherwise.\n */\nexport function extractReasoningId(msg: unknown): string | undefined {\n if (msg == null || typeof msg !== 'object') return undefined;\n\n // For serialized LangChain messages, the data is in kwargs\n const msgObj = msg as Record<string, unknown>;\n const kwargs =\n msgObj.kwargs && typeof msgObj.kwargs === 'object'\n ? (msgObj.kwargs as Record<string, unknown>)\n : msgObj;\n\n // Check additional_kwargs.reasoning.id (GPT-5 streaming format)\n const additionalKwargs = (\n kwargs as { additional_kwargs?: { reasoning?: { id?: string } } }\n ).additional_kwargs;\n if (additionalKwargs?.reasoning?.id) {\n return additionalKwargs.reasoning.id;\n }\n\n // Check response_metadata.output for reasoning block ID (GPT-5 final format)\n const responseMetadata = (\n kwargs as { response_metadata?: { output?: unknown[] } }\n ).response_metadata;\n if (responseMetadata && Array.isArray(responseMetadata.output)) {\n for (const item of responseMetadata.output) {\n if (isGPT5ReasoningOutput(item)) {\n return item.id;\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Extracts reasoning content from contentBlocks or additional_kwargs.reasoning.summary\n *\n * IMPORTANT: This function is designed for STREAMING chunks where content is delta-based.\n * It does NOT extract from response_metadata.output because that contains accumulated\n * content (not deltas) and would cause duplication during streaming.\n *\n * For non-streaming/values events, use extractReasoningFromValuesMessage instead.\n *\n * Handles both class instances and serialized LangChain message objects.\n *\n * @param msg - The message to extract reasoning from.\n * @returns The reasoning text if found, undefined otherwise.\n */\nexport function extractReasoningFromContentBlocks(\n msg: unknown,\n): string | undefined {\n if (msg == null || typeof msg !== 'object') return undefined;\n\n // For serialized LangChain messages, the data is in kwargs\n const msgObj = msg as Record<string, unknown>;\n const kwargs =\n msgObj.kwargs && typeof msgObj.kwargs === 'object'\n ? (msgObj.kwargs as Record<string, unknown>)\n : msgObj;\n\n // Check contentBlocks (Anthropic-style) - highest priority\n const contentBlocks = (kwargs as { contentBlocks?: unknown[] }).contentBlocks;\n if (Array.isArray(contentBlocks)) {\n const reasoningParts: string[] = [];\n for (const block of contentBlocks) {\n if (isReasoningContentBlock(block)) {\n reasoningParts.push(block.reasoning);\n } else if (isThinkingContentBlock(block)) {\n reasoningParts.push(block.thinking);\n }\n }\n if (reasoningParts.length > 0) {\n return reasoningParts.join('');\n }\n }\n\n // Check additional_kwargs.reasoning.summary (GPT-5 streaming format)\n // This contains DELTA content during streaming, not accumulated content\n // Format can be either { type: \"summary_text\", text: \"...\" } or just { text: \"...\" }\n const additionalKwargs = (\n kwargs as { additional_kwargs?: { reasoning?: { summary?: unknown[] } } }\n ).additional_kwargs;\n if (\n additionalKwargs?.reasoning &&\n Array.isArray(additionalKwargs.reasoning.summary)\n ) {\n const reasoningParts: string[] = [];\n for (const summaryItem of additionalKwargs.reasoning.summary) {\n if (\n typeof summaryItem === 'object' &&\n summaryItem !== null &&\n 'text' in summaryItem &&\n typeof (summaryItem as { text: unknown }).text === 'string'\n ) {\n reasoningParts.push((summaryItem as { text: string }).text);\n }\n }\n if (reasoningParts.length > 0) {\n return reasoningParts.join('');\n }\n }\n\n return undefined;\n}\n\n/**\n * Extracts reasoning content from a values event message.\n * This checks response_metadata.output which contains the full accumulated reasoning.\n *\n * @param msg - The message to extract reasoning from.\n * @returns The reasoning text if found, undefined otherwise.\n */\nexport function extractReasoningFromValuesMessage(\n msg: unknown,\n): string | undefined {\n if (msg == null || typeof msg !== 'object') return undefined;\n\n // For serialized LangChain messages, the data is in kwargs\n const msgObj = msg as Record<string, unknown>;\n const kwargs =\n msgObj.kwargs && typeof msgObj.kwargs === 'object'\n ? (msgObj.kwargs as Record<string, unknown>)\n : msgObj;\n\n // Check response_metadata.output (GPT-5 final style) - for values events\n const responseMetadata = (\n kwargs as { response_metadata?: { output?: unknown[] } }\n ).response_metadata;\n if (responseMetadata && Array.isArray(responseMetadata.output)) {\n const reasoningParts: string[] = [];\n for (const item of responseMetadata.output) {\n if (isGPT5ReasoningOutput(item)) {\n // Extract text from summary array - handles both { type: \"summary_text\", text } and { text } formats\n for (const summaryItem of item.summary) {\n if (typeof summaryItem === 'object' && summaryItem !== null) {\n const text = (summaryItem as { text?: string }).text;\n if (typeof text === 'string' && text) {\n reasoningParts.push(text);\n }\n }\n }\n }\n }\n if (reasoningParts.length > 0) {\n return reasoningParts.join('');\n }\n }\n\n // Also check additional_kwargs.reasoning.summary as fallback\n const additionalKwargs = (\n kwargs as { additional_kwargs?: { reasoning?: { summary?: unknown[] } } }\n ).additional_kwargs;\n if (\n additionalKwargs?.reasoning &&\n Array.isArray(additionalKwargs.reasoning.summary)\n ) {\n const reasoningParts: string[] = [];\n for (const summaryItem of additionalKwargs.reasoning.summary) {\n if (\n typeof summaryItem === 'object' &&\n summaryItem !== null &&\n 'text' in summaryItem &&\n typeof (summaryItem as { text: unknown }).text === 'string'\n ) {\n reasoningParts.push((summaryItem as { text: string }).text);\n }\n }\n if (reasoningParts.length > 0) {\n return reasoningParts.join('');\n }\n }\n\n return undefined;\n}\n\n/**\n * Checks if an object is an image generation output\n *\n * @param obj - The object to check.\n * @returns True if the object is an image generation output, false otherwise.\n */\nexport function isImageGenerationOutput(\n obj: unknown,\n): obj is ImageGenerationOutput {\n return (\n obj != null &&\n typeof obj === 'object' &&\n 'type' in obj &&\n (obj as { type: string }).type === 'image_generation_call'\n );\n}\n\n/**\n * Extracts image generation outputs from `additional_kwargs`\n *\n * @param additionalKwargs - The additional kwargs to extract the image generation outputs from.\n * @returns The image generation outputs.\n */\nexport function extractImageOutputs(\n additionalKwargs: Record<string, unknown> | undefined,\n): ImageGenerationOutput[] {\n if (!additionalKwargs) return [];\n\n const toolOutputs = additionalKwargs.tool_outputs;\n if (!Array.isArray(toolOutputs)) return [];\n\n return toolOutputs.filter(isImageGenerationOutput);\n}\n\n/**\n * Processes a LangGraph event and emits UI message chunks.\n *\n * @param event - The event to process.\n * @param state - The state of the LangGraph event.\n * @param controller - The controller to use to emit the UI message chunks.\n */\nexport function processLangGraphEvent(\n event: unknown[],\n state: LangGraphEventState,\n controller: ReadableStreamDefaultController<UIMessageChunk>,\n): void {\n const {\n messageSeen,\n messageConcat,\n emittedToolCalls,\n emittedImages,\n emittedReasoningIds,\n messageReasoningIds,\n toolCallInfoByIndex,\n emittedToolCallsByKey,\n } = state;\n const [type, data] = event.length === 3 ? event.slice(1) : event;\n\n switch (type) {\n case 'custom': {\n /**\n * Extract custom event type from the data's 'type' field if present.\n * This allows users to emit custom events like:\n * writer({ type: 'progress', value: 50 }) -> { type: 'data-progress', data: {...} }\n * writer({ type: 'status', message: '...' }) -> { type: 'data-status', data: {...} }\n * writer({ key: 'value' }) -> { type: 'data-custom', data: {...} } (fallback)\n *\n * The 'id' field can be used to make parts persistent and updateable.\n * Parts with an 'id' are NOT transient (added to message.parts).\n * Parts without an 'id' are transient (only passed to onData callback).\n */\n let customTypeName = 'custom';\n let partId: string | undefined;\n\n if (data != null && typeof data === 'object' && !Array.isArray(data)) {\n const dataObj = data as Record<string, unknown>;\n if (typeof dataObj.type === 'string' && dataObj.type) {\n customTypeName = dataObj.type;\n }\n if (typeof dataObj.id === 'string' && dataObj.id) {\n partId = dataObj.id;\n }\n }\n\n controller.enqueue({\n type: `data-${customTypeName}` as `data-${string}`,\n id: partId,\n transient: partId == null,\n data,\n });\n break;\n }\n\n case 'messages': {\n const [rawMsg, metadata] = data as [\n BaseMessageChunk | BaseMessage | undefined,\n Record<string, unknown> | undefined,\n ];\n\n const msg = rawMsg;\n const msgId = getMessageId(msg);\n\n if (!msgId) return;\n\n /**\n * Track LangGraph step changes and emit start-step/finish-step events\n */\n const langgraphStep =\n typeof metadata?.langgraph_step === 'number'\n ? metadata.langgraph_step\n : null;\n if (langgraphStep !== null && langgraphStep !== state.currentStep) {\n if (state.currentStep !== null) {\n controller.enqueue({ type: 'finish-step' });\n }\n controller.enqueue({ type: 'start-step' });\n state.currentStep = langgraphStep;\n }\n\n /**\n * Accumulate message chunks for later reference\n * Note: Only works for actual class instances, not serialized messages\n */\n if (AIMessageChunk.isInstance(msg)) {\n if (messageConcat[msgId]) {\n messageConcat[msgId] = messageConcat[msgId].concat(\n msg,\n ) as AIMessageChunk;\n } else {\n messageConcat[msgId] = msg;\n }\n }\n\n if (isAIMessageChunk(msg)) {\n const concatChunk = messageConcat[msgId];\n\n /**\n * Handle image generation outputs from additional_kwargs.tool_outputs\n * Handle both direct properties and serialized messages (kwargs)\n */\n const msgObj = msg as unknown as Record<string, unknown>;\n const dataSource =\n msgObj.type === 'constructor' &&\n msgObj.kwargs &&\n typeof msgObj.kwargs === 'object'\n ? (msgObj.kwargs as Record<string, unknown>)\n : msgObj;\n const additionalKwargs = dataSource.additional_kwargs as\n | Record<string, unknown>\n | undefined;\n const imageOutputs = extractImageOutputs(additionalKwargs);\n\n for (const imageOutput of imageOutputs) {\n /**\n * Only emit if we have image data and haven't emitted this image yet\n */\n if (imageOutput.result && !emittedImages.has(imageOutput.id)) {\n emittedImages.add(imageOutput.id);\n\n /**\n * Emit as a file part using proper AI SDK multimodal format\n */\n const mediaType = `image/${imageOutput.output_format || 'png'}`;\n controller.enqueue({\n type: 'file',\n mediaType,\n url: `data:${mediaType};base64,${imageOutput.result}`,\n });\n }\n }\n\n /**\n * Handle tool call chunks for streaming tool calls\n * Access from dataSource to handle both direct and serialized messages\n *\n * Tool call chunks are streamed as follows:\n * 1. First chunk: has name, id, but often empty args\n * 2. Subsequent chunks: have args but NO id or name\n *\n * We store tool call info by index when we first see it, then look it up\n * for subsequent chunks that don't include the id.\n */\n const toolCallChunks = dataSource.tool_call_chunks as\n | ToolCallChunk[]\n | undefined;\n if (toolCallChunks?.length) {\n for (const toolCallChunk of toolCallChunks) {\n const idx = toolCallChunk.index ?? 0;\n\n /**\n * If this chunk has an id, store it for future lookups by index\n */\n if (toolCallChunk.id) {\n toolCallInfoByIndex[msgId] ??= {};\n toolCallInfoByIndex[msgId][idx] = {\n id: toolCallChunk.id,\n name:\n toolCallChunk.name ||\n concatChunk?.tool_call_chunks?.[idx]?.name ||\n 'unknown',\n };\n }\n\n /**\n * Get the tool call ID from the chunk, stored info, or accumulated chunks\n */\n const toolCallId =\n toolCallChunk.id ||\n toolCallInfoByIndex[msgId]?.[idx]?.id ||\n concatChunk?.tool_call_chunks?.[idx]?.id;\n\n /**\n * Skip if we don't have a proper tool call ID - we'll handle it in values\n */\n if (!toolCallId) {\n continue;\n }\n\n const toolName =\n toolCallChunk.name ||\n toolCallInfoByIndex[msgId]?.[idx]?.name ||\n concatChunk?.tool_call_chunks?.[idx]?.name ||\n 'unknown';\n\n /**\n * Emit tool-input-start when we first see this tool call\n * (even if args is empty - the first chunk often has empty args)\n * Set dynamic: true to enable HITL approval requests\n */\n if (!messageSeen[msgId]?.tool?.[toolCallId]) {\n controller.enqueue({\n type: 'tool-input-start',\n toolCallId: toolCallId,\n toolName: toolName,\n dynamic: true,\n });\n\n messageSeen[msgId] ??= {};\n messageSeen[msgId].tool ??= {};\n messageSeen[msgId].tool![toolCallId] = true;\n emittedToolCalls.add(toolCallId);\n }\n\n /**\n * Only emit tool-input-delta when args is non-empty\n */\n if (toolCallChunk.args) {\n controller.enqueue({\n type: 'tool-input-delta',\n toolCallId: toolCallId,\n inputTextDelta: toolCallChunk.args,\n });\n }\n }\n\n return;\n }\n\n /**\n * Handle reasoning content from contentBlocks\n * Streaming chunks contain DELTA text (not accumulated), so emit directly.\n * Use reasoning block ID for deduplication as it's consistent across streaming and values events.\n *\n * Important: Early chunks may have reasoning ID but no content, later chunks may\n * have content but no reasoning ID. We capture the ID when first seen and reuse it.\n * We also immediately add to emittedReasoningIds to prevent values events from\n * emitting the same reasoning (values events can arrive between streaming chunks).\n */\n // Capture reasoning ID when we first see it (even if no content yet)\n const chunkReasoningId = extractReasoningId(msg);\n if (chunkReasoningId) {\n if (!messageReasoningIds[msgId]) {\n messageReasoningIds[msgId] = chunkReasoningId;\n }\n // Immediately mark as emitted to prevent values from duplicating\n // This must happen as soon as we see the ID, before content arrives\n emittedReasoningIds.add(chunkReasoningId);\n }\n\n const reasoning = extractReasoningFromContentBlocks(msg);\n if (reasoning) {\n // Use stored reasoning ID, or current chunk's ID, or fall back to message ID\n const reasoningId =\n messageReasoningIds[msgId] ?? chunkReasoningId ?? msgId;\n\n if (!messageSeen[msgId]?.reasoning) {\n controller.enqueue({ type: 'reasoning-start', id: msgId });\n messageSeen[msgId] ??= {};\n messageSeen[msgId].reasoning = true;\n }\n\n // Streaming chunks have delta text, emit directly without slicing\n controller.enqueue({\n type: 'reasoning-delta',\n delta: reasoning,\n id: msgId,\n });\n // Also ensure the reasoning ID is marked (handles case where ID wasn't in first chunk)\n emittedReasoningIds.add(reasoningId);\n }\n\n /**\n * Handle text content\n */\n const text = getMessageText(msg);\n if (text) {\n if (!messageSeen[msgId]?.text) {\n controller.enqueue({ type: 'text-start', id: msgId });\n messageSeen[msgId] ??= {};\n messageSeen[msgId].text = true;\n }\n\n controller.enqueue({\n type: 'text-delta',\n delta: text,\n id: msgId,\n });\n }\n } else if (isToolMessageType(msg)) {\n // Handle both direct properties and serialized messages (kwargs)\n const msgObj = msg as unknown as Record<string, unknown>;\n const dataSource =\n msgObj.type === 'constructor' &&\n msgObj.kwargs &&\n typeof msgObj.kwargs === 'object'\n ? (msgObj.kwargs as Record<string, unknown>)\n : msgObj;\n\n const toolCallId = dataSource.tool_call_id as string | undefined;\n const status = dataSource.status as string | undefined;\n\n if (toolCallId) {\n if (status === 'error') {\n // Tool execution failed\n controller.enqueue({\n type: 'tool-output-error',\n toolCallId,\n errorText:\n typeof dataSource.content === 'string'\n ? dataSource.content\n : 'Tool execution failed',\n });\n } else {\n // Tool execution succeeded\n controller.enqueue({\n type: 'tool-output-available',\n toolCallId,\n output: dataSource.content,\n });\n }\n }\n }\n\n return;\n }\n\n case 'values': {\n /**\n * Finalize all pending message chunks\n */\n for (const [id, seen] of Object.entries(messageSeen)) {\n if (seen.text) controller.enqueue({ type: 'text-end', id });\n if (seen.tool) {\n for (const [toolCallId, toolCallSeen] of Object.entries(seen.tool)) {\n const concatMsg = messageConcat[id];\n const toolCall = concatMsg?.tool_calls?.find(\n call => call.id === toolCallId,\n );\n\n if (toolCallSeen && toolCall) {\n emittedToolCalls.add(toolCallId);\n // Store mapping for HITL interrupt lookup\n const toolCallKey = `${toolCall.name}:${JSON.stringify(toolCall.args)}`;\n emittedToolCallsByKey.set(toolCallKey, toolCallId);\n controller.enqueue({\n type: 'tool-input-available',\n toolCallId,\n toolName: toolCall.name,\n input: toolCall.args,\n dynamic: true,\n });\n }\n }\n }\n\n if (seen.reasoning) {\n controller.enqueue({ type: 'reasoning-end', id });\n }\n\n delete messageSeen[id];\n delete messageConcat[id];\n delete messageReasoningIds[id];\n }\n\n /**\n * Also check for tool calls in the final state that weren't streamed\n * This handles cases where tool calls appear directly in values without being in messages events\n */\n if (data != null && typeof data === 'object' && 'messages' in data) {\n const messages = (data as { messages?: unknown[] }).messages;\n if (Array.isArray(messages)) {\n for (const msg of messages) {\n if (!msg || typeof msg !== 'object') continue;\n\n // Use getMessageId to handle both class instances and serialized messages\n const msgId = getMessageId(msg);\n if (!msgId) continue;\n\n /**\n * Check if this is an AI message with tool calls\n */\n let toolCalls: ToolCall[] | undefined;\n\n /**\n * For class instances\n */\n if (AIMessageChunk.isInstance(msg) || AIMessage.isInstance(msg)) {\n toolCalls = msg.tool_calls;\n } else if (isPlainMessageObject(msg)) {\n /**\n * For plain objects from RemoteGraph API or serialized LangChain messages\n */\n const obj = msg as Record<string, unknown>;\n\n /**\n * Determine the data source (handle both direct and serialized formats)\n */\n const isSerializedFormat =\n obj.type === 'constructor' &&\n Array.isArray(obj.id) &&\n ((obj.id as string[]).includes('AIMessageChunk') ||\n (obj.id as string[]).includes('AIMessage'));\n const dataSource = isSerializedFormat\n ? (obj.kwargs as Record<string, unknown>)\n : obj;\n\n if (obj.type === 'ai' || isSerializedFormat) {\n /**\n * Try tool_calls first (normalized format)\n */\n if (Array.isArray(dataSource?.tool_calls)) {\n toolCalls = dataSource.tool_calls as ToolCall[];\n } else if (\n /**\n * Fall back to additional_kwargs.tool_calls (OpenAI format)\n */\n dataSource?.additional_kwargs &&\n typeof dataSource.additional_kwargs === 'object'\n ) {\n const additionalKwargs =\n dataSource.additional_kwargs as Record<string, unknown>;\n if (Array.isArray(additionalKwargs.tool_calls)) {\n /**\n * Convert OpenAI format to normalized format\n */\n toolCalls = (\n additionalKwargs.tool_calls as Array<{\n id?: string;\n function?: { name?: string; arguments?: string };\n }>\n ).map((tc, idx) => {\n const functionData = tc.function;\n let args: unknown;\n try {\n args = functionData?.arguments\n ? JSON.parse(functionData.arguments)\n : {};\n } catch {\n args = {};\n }\n return {\n id: tc.id || `call_${idx}`,\n name: functionData?.name || 'unknown',\n args,\n } as ToolCall;\n });\n }\n }\n }\n }\n\n if (toolCalls && toolCalls.length > 0) {\n for (const toolCall of toolCalls) {\n /**\n * Only emit if we haven't already processed this tool call\n */\n if (toolCall.id && !emittedToolCalls.has(toolCall.id)) {\n emittedToolCalls.add(toolCall.id);\n // Store mapping for HITL interrupt lookup\n const toolCallKey = `${toolCall.name}:${JSON.stringify(toolCall.args)}`;\n emittedToolCallsByKey.set(toolCallKey, toolCall.id);\n /**\n * Emit tool-input-start first to ensure proper lifecycle.\n * Tool calls that weren't streamed (no tool_call_chunks) need\n * the start event before tool-input-available.\n */\n controller.enqueue({\n type: 'tool-input-start',\n toolCallId: toolCall.id,\n toolName: toolCall.name,\n dynamic: true,\n });\n controller.enqueue({\n type: 'tool-input-available',\n toolCallId: toolCall.id,\n toolName: toolCall.name,\n input: toolCall.args,\n dynamic: true,\n });\n }\n }\n }\n\n /**\n * Check for reasoning content that wasn't streamed\n * Use reasoning block ID for deduplication as it's consistent across streaming and values.\n *\n * IMPORTANT: Handle two cases differently:\n * 1. Message has reasoning WITHOUT tool_calls → emit reasoning (pure reasoning case)\n * 2. Message has reasoning WITH tool_calls → only emit if streamed this request\n * (When resuming from HITL interrupt, historical messages have both reasoning\n * AND tool_calls. We skip those to avoid duplicate reasoning entries.)\n */\n const reasoningId = extractReasoningId(msg);\n const wasStreamedThisRequest = !!messageSeen[msgId];\n const hasToolCalls = toolCalls && toolCalls.length > 0;\n\n /**\n * Determine if we should emit reasoning:\n * - If we already emitted this reasoning ID, skip\n * - If the message was streamed this request, emit (normal flow)\n * - If NOT streamed but has NO tool_calls, emit (pure reasoning in values case)\n * - If NOT streamed but HAS tool_calls, skip (historical HITL message)\n */\n const shouldEmitReasoning =\n reasoningId &&\n !emittedReasoningIds.has(reasoningId) &&\n (wasStreamedThisRequest || !hasToolCalls);\n\n if (shouldEmitReasoning) {\n /**\n * Use extractReasoningFromValuesMessage which extracts from response_metadata.output\n * This is the full accumulated reasoning, not deltas\n */\n const reasoning = extractReasoningFromValuesMessage(msg);\n\n if (reasoning) {\n controller.enqueue({ type: 'reasoning-start', id: msgId });\n controller.enqueue({\n type: 'reasoning-delta',\n delta: reasoning,\n id: msgId,\n });\n controller.enqueue({ type: 'reasoning-end', id: msgId });\n emittedReasoningIds.add(reasoningId);\n }\n }\n }\n }\n }\n\n /**\n * Handle Human-in-the-Loop interrupts\n * When HITL middleware pauses execution, the interrupt data is in __interrupt__\n * Note: This is outside the 'messages' check because interrupt can come as a separate event\n */\n if (data != null && typeof data === 'object') {\n const interrupt = (data as Record<string, unknown>).__interrupt__;\n if (Array.isArray(interrupt) && interrupt.length > 0) {\n for (const interruptItem of interrupt) {\n const interruptValue = (interruptItem as { value?: unknown })\n ?.value as Record<string, unknown> | undefined;\n\n if (!interruptValue) continue;\n\n /**\n * Support both camelCase (JS SDK) and snake_case (Python SDK)\n */\n const actionRequests = (interruptValue.actionRequests ||\n interruptValue.action_requests) as\n | Array<{\n name: string;\n args?: Record<string, unknown>; // JS SDK uses 'args'\n arguments?: Record<string, unknown>; // Python SDK uses 'arguments'\n id?: string;\n }>\n | undefined;\n\n if (!Array.isArray(actionRequests)) continue;\n\n for (const actionRequest of actionRequests) {\n const toolName = actionRequest.name;\n /**\n * Support both 'args' (JS SDK) and 'arguments' (Python SDK)\n */\n const input = actionRequest.args || actionRequest.arguments;\n\n /**\n * Look up the original tool call ID using the name+args key\n * Fall back to action request ID or generate one if not found\n */\n const toolCallKey = `${toolName}:${JSON.stringify(input)}`;\n const toolCallId =\n emittedToolCallsByKey.get(toolCallKey) ||\n actionRequest.id ||\n `hitl-${toolName}-${Date.now()}`;\n\n /**\n * First emit tool-input-start then tool-input-available\n * so the UI knows what tool is being called with proper lifecycle\n */\n if (!emittedToolCalls.has(toolCallId)) {\n emittedToolCalls.add(toolCallId);\n emittedToolCallsByKey.set(toolCallKey, toolCallId);\n controller.enqueue({\n type: 'tool-input-start',\n toolCallId,\n toolName,\n dynamic: true,\n });\n controller.enqueue({\n type: 'tool-input-available',\n toolCallId,\n toolName,\n input,\n dynamic: true,\n });\n }\n\n /**\n * Then emit tool-approval-request to mark it as awaiting approval\n */\n controller.enqueue({\n type: 'tool-approval-request',\n approvalId: toolCallId,\n toolCallId,\n });\n }\n }\n }\n }\n\n break;\n }\n }\n}\n","import { AIMessageChunk } from '@langchain/core/messages';\nimport {\n type UIMessage,\n type UIMessageChunk,\n type ChatTransport,\n type ChatRequestOptions,\n} from 'ai';\nimport {\n RemoteGraph,\n type RemoteGraphParams,\n} from '@langchain/langgraph/remote';\nimport { toBaseMessages, toUIMessageStream } from './adapter';\n\n/**\n * Options for configuring a LangSmith deployment transport.\n * Extends RemoteGraphParams but makes graphId optional (defaults to 'agent').\n */\nexport type LangSmithDeploymentTransportOptions = Omit<\n RemoteGraphParams,\n 'graphId'\n> & {\n /**\n * The ID of the graph to connect to.\n * @default 'agent'\n */\n graphId?: string;\n};\n\n/**\n * A ChatTransport implementation for LangSmith/LangGraph deployments.\n *\n * This transport enables seamless integration between the AI SDK's useChat hook\n * and LangSmith deployed LangGraph agents.\n *\n * @example\n * ```ts\n * import { LangSmithDeploymentTransport } from '@ai-sdk/langchain';\n *\n * // Use with useChat\n * const { messages, input, handleSubmit } = useChat({\n * transport: new LangSmithDeploymentTransport({\n * url: 'https://your-deployment.us.langgraph.app',\n * apiKey: 'my-api-key',\n * }),\n * });\n * ```\n */\nexport class LangSmithDeploymentTransport<UI_MESSAGE extends UIMessage>\n implements ChatTransport<UI_MESSAGE>\n{\n protected graph: RemoteGraph;\n\n constructor(options: LangSmithDeploymentTransportOptions) {\n this.graph = new RemoteGraph({\n ...options,\n graphId: options.graphId ?? 'agent',\n });\n }\n\n async sendMessages(\n options: {\n trigger: 'submit-message' | 'regenerate-message';\n chatId: string;\n messageId: string | undefined;\n messages: UI_MESSAGE[];\n abortSignal: AbortSignal | undefined;\n } & ChatRequestOptions,\n ): Promise<ReadableStream<UIMessageChunk>> {\n const baseMessages = await toBaseMessages(options.messages);\n\n const stream = await this.graph.stream(\n { messages: baseMessages },\n { streamMode: ['values', 'messages'] },\n );\n\n return toUIMessageStream(\n stream as AsyncIterable<AIMessageChunk> | ReadableStream,\n );\n }\n\n async reconnectToStream(\n _options: {\n chatId: string;\n } & ChatRequestOptions,\n ): Promise<ReadableStream<UIMessageChunk> | null> {\n throw new Error('Method not implemented.');\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,mBAIO;AACP,gBAKO;;;ACVP,sBASO;AAqBA,SAAS,sBAAsB,OAAoC;AACxE,QAAM,WAAW,MAAM;AACrB,QAAI,MAAM,OAAO,SAAS,UAAU,MAAM,OAAO,SAAS,cAAc;AACtE,aAAO,MAAM,OAAO;AAAA,IACtB;AAEA,QAAI,MAAM,OAAO,SAAS,UAAU,MAAM,OAAO,SAAS,cAAc;AACtE,aAAO,KAAK,UAAU,MAAM,OAAO,KAAK;AAAA,IAC1C;AAEA,QAAI,MAAM,OAAO,SAAS,WAAW;AACnC,aAAO,MAAM,OAAO,MACjB,IAAI,iBAAe;AAClB,YAAI,YAAY,SAAS,QAAQ;AAC/B,iBAAO,YAAY;AAAA,QACrB;AACA,eAAO;AAAA,MACT,CAAC,EACA,KAAK,EAAE;AAAA,IACZ;AAEA,WAAO;AAAA,EACT,GAAG;AAEH,SAAO,IAAI,4BAAY;AAAA,IACrB,cAAc,MAAM;AAAA,IACpB;AAAA,EACF,CAAC;AACH;AAOO,SAAS,wBAAwB,SAAsC;AAC5E,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO,IAAI,0BAAU,EAAE,QAAQ,CAAC;AAAA,EAClC;AAEA,QAAM,YAAsB,CAAC;AAC7B,QAAM,YAID,CAAC;AAEN,aAAW,QAAQ,SAAS;AAC1B,QAAI,KAAK,SAAS,QAAQ;AACxB,gBAAU,KAAK,KAAK,IAAI;AAAA,IAC1B,WAAW,KAAK,SAAS,aAAa;AACpC,gBAAU,KAAK;AAAA,QACb,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,MAAM,KAAK;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,IAAI,0BAAU;AAAA,IACnB,SAAS,UAAU,KAAK,EAAE;AAAA,IAC1B,YAAY,UAAU,SAAS,IAAI,YAAY;AAAA,EACjD,CAAC;AACH;AAOO,SAAS,mBAAmB,SAAoC;AACrE,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO,IAAI,6BAAa,EAAE,QAAQ,CAAC;AAAA,EACrC;AAEA,QAAM,YAAY,QACf;AAAA,IACC,CAAC,SAAiD,KAAK,SAAS;AAAA,EAClE,EACC,IAAI,UAAQ,KAAK,IAAI;AAExB,SAAO,IAAI,6BAAa,EAAE,SAAS,UAAU,KAAK,EAAE,EAAE,CAAC;AACzD;AAOO,SAAS,iBAAiB,MAAuC;AACtE,SACE,QAAQ,QACR,OAAO,SAAS,YAChB,UAAU,QACT,KAA0B,SAAS;AAExC;AAQO,SAAS,kBACd,OACA,OAMA,YACM;AAIN,MAAI,MAAM,IAAI;AACZ,UAAM,YAAY,MAAM;AAAA,EAC1B;AAOA,QAAM,YACJ,kCAAkC,KAAK,KACvC,kCAAkC,KAAK;AACzC,MAAI,WAAW;AACb,QAAI,CAAC,MAAM,kBAAkB;AAC3B,iBAAW,QAAQ,EAAE,MAAM,mBAAmB,IAAI,MAAM,UAAU,CAAC;AACnE,YAAM,mBAAmB;AACzB,YAAM,UAAU;AAAA,IAClB;AACA,eAAW,QAAQ;AAAA,MACjB,MAAM;AAAA,MACN,OAAO;AAAA,MACP,IAAI,MAAM;AAAA,IACZ,CAAC;AAAA,EACH;AAKA,QAAM,OACJ,OAAO,MAAM,YAAY,WACrB,MAAM,UACN,MAAM,QAAQ,MAAM,OAAO,IACzB,MAAM,QACH;AAAA,IACC,CAAC,MACC,OAAO,MAAM,YACb,MAAM,QACN,UAAU,KACV,EAAE,SAAS;AAAA,EACf,EACC,IAAI,OAAK,EAAE,IAAI,EACf,KAAK,EAAE,IACV;AAER,MAAI,MAAM;AAIR,QAAI,MAAM,oBAAoB,CAAC,MAAM,aAAa;AAChD,iBAAW,QAAQ,EAAE,MAAM,iBAAiB,IAAI,MAAM,UAAU,CAAC;AACjE,YAAM,mBAAmB;AAAA,IAC3B;AAEA,QAAI,CAAC,MAAM,aAAa;AACtB,iBAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,MAAM,UAAU,CAAC;AAC9D,YAAM,cAAc;AACpB,YAAM,UAAU;AAAA,IAClB;AACA,eAAW,QAAQ;AAAA,MACjB,MAAM;AAAA,MACN,OAAO;AAAA,MACP,IAAI,MAAM;AAAA,IACZ,CAAC;AAAA,EACH;AACF;AASO,SAAS,qBAAqB,KAAuB;AAC1D,MAAI,OAAO,QAAQ,OAAO,QAAQ,SAAU,QAAO;AAInD,SAAO,OAAQ,IAA+B,aAAa;AAC7D;AASO,SAAS,aAAa,KAAkC;AAC7D,MAAI,OAAO,QAAQ,OAAO,QAAQ,SAAU,QAAO;AAEnD,QAAM,SAAS;AAKf,MAAI,OAAO,OAAO,OAAO,UAAU;AACjC,WAAO,OAAO;AAAA,EAChB;AAKA,MACE,OAAO,SAAS,iBAChB,OAAO,UACP,OAAO,OAAO,WAAW,UACzB;AACA,UAAM,SAAS,OAAO;AACtB,QAAI,OAAO,OAAO,OAAO,UAAU;AACjC,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;AAWO,SAAS,iBACd,KAC6D;AAI7D,MAAI,+BAAe,WAAW,GAAG,EAAG,QAAO;AAI3C,MAAI,qBAAqB,GAAG,GAAG;AAC7B,UAAM,MAAM;AAIZ,QAAI,UAAU,OAAO,IAAI,SAAS,KAAM,QAAO;AAI/C,QACE,IAAI,SAAS,iBACb,MAAM,QAAQ,IAAI,EAAE,MACnB,IAAI,GAAG,SAAS,gBAAgB,KAAK,IAAI,GAAG,SAAS,WAAW,IACjE;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAQO,SAAS,kBACd,KAC+D;AAC/D,MAAI,4BAAY,WAAW,GAAG,EAAG,QAAO;AAIxC,MAAI,qBAAqB,GAAG,GAAG;AAC7B,UAAM,MAAM;AAEZ,QAAI,UAAU,OAAO,IAAI,SAAS,OAAQ,QAAO;AAEjD,QACE,IAAI,SAAS,iBACb,MAAM,QAAQ,IAAI,EAAE,KACpB,IAAI,GAAG,SAAS,aAAa,GAC7B;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAQO,SAAS,eAAe,KAAsB;AAlVrD;AAmVE,MAAI,+BAAe,WAAW,GAAG,GAAG;AAClC,YAAO,SAAI,SAAJ,YAAY;AAAA,EACrB;AAEA,MAAI,OAAO,QAAQ,OAAO,QAAQ,SAAU,QAAO;AAEnD,QAAM,SAAS;AAGf,QAAM,aACJ,OAAO,SAAS,iBAChB,OAAO,UACP,OAAO,OAAO,WAAW,WACpB,OAAO,SACR;AAEN,MAAI,aAAa,YAAY;AAC3B,UAAM,UAAU,WAAW;AAI3B,QAAI,OAAO,YAAY,UAAU;AAC/B,aAAO;AAAA,IACT;AAIA,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,aAAO,QACJ;AAAA,QACC,CAAC,UACC,SAAS,QACT,OAAO,UAAU,YACjB,MAAM,SAAS,UACf,OAAO,MAAM,SAAS;AAAA,MAC1B,EACC,IAAI,WAAS,MAAM,IAAI,EACvB,KAAK,EAAE;AAAA,IACZ;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAQO,SAAS,wBACd,KAC8B;AAC9B,SACE,OAAO,QACP,OAAO,QAAQ,YACf,UAAU,OACT,IAAyB,SAAS,eACnC,eAAe,OACf,OAAQ,IAA+B,cAAc;AAEzD;AAQO,SAAS,uBACd,KAC6B;AAC7B,SACE,OAAO,QACP,OAAO,QAAQ,YACf,UAAU,OACT,IAAyB,SAAS,cACnC,cAAc,OACd,OAAQ,IAA8B,aAAa;AAEvD;AAKA,SAAS,sBAAsB,KAA0C;AACvE,SACE,OAAO,QACP,OAAO,QAAQ,YACf,UAAU,OACT,IAAyB,SAAS,eACnC,aAAa,OACb,MAAM,QAAS,IAA6B,OAAO;AAEvD;AAUO,SAAS,mBAAmB,KAAkC;AA3brE;AA4bE,MAAI,OAAO,QAAQ,OAAO,QAAQ,SAAU,QAAO;AAGnD,QAAM,SAAS;AACf,QAAM,SACJ,OAAO,UAAU,OAAO,OAAO,WAAW,WACrC,OAAO,SACR;AAGN,QAAM,mBACJ,OACA;AACF,OAAI,0DAAkB,cAAlB,mBAA6B,IAAI;AACnC,WAAO,iBAAiB,UAAU;AAAA,EACpC;AAGA,QAAM,mBACJ,OACA;AACF,MAAI,oBAAoB,MAAM,QAAQ,iBAAiB,MAAM,GAAG;AAC9D,eAAW,QAAQ,iBAAiB,QAAQ;AAC1C,UAAI,sBAAsB,IAAI,GAAG;AAC/B,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAgBO,SAAS,kCACd,KACoB;AACpB,MAAI,OAAO,QAAQ,OAAO,QAAQ,SAAU,QAAO;AAGnD,QAAM,SAAS;AACf,QAAM,SACJ,OAAO,UAAU,OAAO,OAAO,WAAW,WACrC,OAAO,SACR;AAGN,QAAM,gBAAiB,OAAyC;AAChE,MAAI,MAAM,QAAQ,aAAa,GAAG;AAChC,UAAM,iBAA2B,CAAC;AAClC,eAAW,SAAS,eAAe;AACjC,UAAI,wBAAwB,KAAK,GAAG;AAClC,uBAAe,KAAK,MAAM,SAAS;AAAA,MACrC,WAAW,uBAAuB,KAAK,GAAG;AACxC,uBAAe,KAAK,MAAM,QAAQ;AAAA,MACpC;AAAA,IACF;AACA,QAAI,eAAe,SAAS,GAAG;AAC7B,aAAO,eAAe,KAAK,EAAE;AAAA,IAC/B;AAAA,EACF;AAKA,QAAM,mBACJ,OACA;AACF,OACE,qDAAkB,cAClB,MAAM,QAAQ,iBAAiB,UAAU,OAAO,GAChD;AACA,UAAM,iBAA2B,CAAC;AAClC,eAAW,eAAe,iBAAiB,UAAU,SAAS;AAC5D,UACE,OAAO,gBAAgB,YACvB,gBAAgB,QAChB,UAAU,eACV,OAAQ,YAAkC,SAAS,UACnD;AACA,uBAAe,KAAM,YAAiC,IAAI;AAAA,MAC5D;AAAA,IACF;AACA,QAAI,eAAe,SAAS,GAAG;AAC7B,aAAO,eAAe,KAAK,EAAE;AAAA,IAC/B;AAAA,EACF;AAEA,SAAO;AACT;AASO,SAAS,kCACd,KACoB;AACpB,MAAI,OAAO,QAAQ,OAAO,QAAQ,SAAU,QAAO;AAGnD,QAAM,SAAS;AACf,QAAM,SACJ,OAAO,UAAU,OAAO,OAAO,WAAW,WACrC,OAAO,SACR;AAGN,QAAM,mBACJ,OACA;AACF,MAAI,oBAAoB,MAAM,QAAQ,iBAAiB,MAAM,GAAG;AAC9D,UAAM,iBAA2B,CAAC;AAClC,eAAW,QAAQ,iBAAiB,QAAQ;AAC1C,UAAI,sBAAsB,IAAI,GAAG;AAE/B,mBAAW,eAAe,KAAK,SAAS;AACtC,cAAI,OAAO,gBAAgB,YAAY,gBAAgB,MAAM;AAC3D,kBAAM,OAAQ,YAAkC;AAChD,gBAAI,OAAO,SAAS,YAAY,MAAM;AACpC,6BAAe,KAAK,IAAI;AAAA,YAC1B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,QAAI,eAAe,SAAS,GAAG;AAC7B,aAAO,eAAe,KAAK,EAAE;AAAA,IAC/B;AAAA,EACF;AAGA,QAAM,mBACJ,OACA;AACF,OACE,qDAAkB,cAClB,MAAM,QAAQ,iBAAiB,UAAU,OAAO,GAChD;AACA,UAAM,iBAA2B,CAAC;AAClC,eAAW,eAAe,iBAAiB,UAAU,SAAS;AAC5D,UACE,OAAO,gBAAgB,YACvB,gBAAgB,QAChB,UAAU,eACV,OAAQ,YAAkC,SAAS,UACnD;AACA,uBAAe,KAAM,YAAiC,IAAI;AAAA,MAC5D;AAAA,IACF;AACA,QAAI,eAAe,SAAS,GAAG;AAC7B,aAAO,eAAe,KAAK,EAAE;AAAA,IAC/B;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,wBACd,KAC8B;AAC9B,SACE,OAAO,QACP,OAAO,QAAQ,YACf,UAAU,OACT,IAAyB,SAAS;AAEvC;AAQO,SAAS,oBACd,kBACyB;AACzB,MAAI,CAAC,iBAAkB,QAAO,CAAC;AAE/B,QAAM,cAAc,iBAAiB;AACrC,MAAI,CAAC,MAAM,QAAQ,WAAW,EAAG,QAAO,CAAC;AAEzC,SAAO,YAAY,OAAO,uBAAuB;AACnD;AASO,SAAS,sBACd,OACA,OACA,YACM;AAtpBR;AAupBE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,CAAC,MAAM,IAAI,IAAI,MAAM,WAAW,IAAI,MAAM,MAAM,CAAC,IAAI;AAE3D,UAAQ,MAAM;AAAA,IACZ,KAAK,UAAU;AAYb,UAAI,iBAAiB;AACrB,UAAI;AAEJ,UAAI,QAAQ,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI,GAAG;AACpE,cAAM,UAAU;AAChB,YAAI,OAAO,QAAQ,SAAS,YAAY,QAAQ,MAAM;AACpD,2BAAiB,QAAQ;AAAA,QAC3B;AACA,YAAI,OAAO,QAAQ,OAAO,YAAY,QAAQ,IAAI;AAChD,mBAAS,QAAQ;AAAA,QACnB;AAAA,MACF;AAEA,iBAAW,QAAQ;AAAA,QACjB,MAAM,QAAQ,cAAc;AAAA,QAC5B,IAAI;AAAA,QACJ,WAAW,UAAU;AAAA,QACrB;AAAA,MACF,CAAC;AACD;AAAA,IACF;AAAA,IAEA,KAAK,YAAY;AACf,YAAM,CAAC,QAAQ,QAAQ,IAAI;AAK3B,YAAM,MAAM;AACZ,YAAM,QAAQ,aAAa,GAAG;AAE9B,UAAI,CAAC,MAAO;AAKZ,YAAM,gBACJ,QAAO,qCAAU,oBAAmB,WAChC,SAAS,iBACT;AACN,UAAI,kBAAkB,QAAQ,kBAAkB,MAAM,aAAa;AACjE,YAAI,MAAM,gBAAgB,MAAM;AAC9B,qBAAW,QAAQ,EAAE,MAAM,cAAc,CAAC;AAAA,QAC5C;AACA,mBAAW,QAAQ,EAAE,MAAM,aAAa,CAAC;AACzC,cAAM,cAAc;AAAA,MACtB;AAMA,UAAI,+BAAe,WAAW,GAAG,GAAG;AAClC,YAAI,cAAc,KAAK,GAAG;AACxB,wBAAc,KAAK,IAAI,cAAc,KAAK,EAAE;AAAA,YAC1C;AAAA,UACF;AAAA,QACF,OAAO;AACL,wBAAc,KAAK,IAAI;AAAA,QACzB;AAAA,MACF;AAEA,UAAI,iBAAiB,GAAG,GAAG;AACzB,cAAM,cAAc,cAAc,KAAK;AAMvC,cAAM,SAAS;AACf,cAAM,aACJ,OAAO,SAAS,iBAChB,OAAO,UACP,OAAO,OAAO,WAAW,WACpB,OAAO,SACR;AACN,cAAM,mBAAmB,WAAW;AAGpC,cAAM,eAAe,oBAAoB,gBAAgB;AAEzD,mBAAW,eAAe,cAAc;AAItC,cAAI,YAAY,UAAU,CAAC,cAAc,IAAI,YAAY,EAAE,GAAG;AAC5D,0BAAc,IAAI,YAAY,EAAE;AAKhC,kBAAM,YAAY,SAAS,YAAY,iBAAiB,KAAK;AAC7D,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN;AAAA,cACA,KAAK,QAAQ,SAAS,WAAW,YAAY,MAAM;AAAA,YACrD,CAAC;AAAA,UACH;AAAA,QACF;AAaA,cAAM,iBAAiB,WAAW;AAGlC,YAAI,iDAAgB,QAAQ;AAC1B,qBAAW,iBAAiB,gBAAgB;AAC1C,kBAAM,OAAM,mBAAc,UAAd,YAAuB;AAKnC,gBAAI,cAAc,IAAI;AACpB,4FAA+B,CAAC;AAChC,kCAAoB,KAAK,EAAE,GAAG,IAAI;AAAA,gBAChC,IAAI,cAAc;AAAA,gBAClB,MACE,cAAc,UACd,sDAAa,qBAAb,mBAAgC,SAAhC,mBAAsC,SACtC;AAAA,cACJ;AAAA,YACF;AAKA,kBAAM,aACJ,cAAc,QACd,+BAAoB,KAAK,MAAzB,mBAA6B,SAA7B,mBAAmC,SACnC,sDAAa,qBAAb,mBAAgC,SAAhC,mBAAsC;AAKxC,gBAAI,CAAC,YAAY;AACf;AAAA,YACF;AAEA,kBAAM,WACJ,cAAc,UACd,+BAAoB,KAAK,MAAzB,mBAA6B,SAA7B,mBAAmC,WACnC,sDAAa,qBAAb,mBAAgC,SAAhC,mBAAsC,SACtC;AAOF,gBAAI,GAAC,uBAAY,KAAK,MAAjB,mBAAoB,SAApB,mBAA2B,cAAa;AAC3C,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN;AAAA,gBACA;AAAA,gBACA,SAAS;AAAA,cACX,CAAC;AAED,4EAAuB,CAAC;AACxB,sCAAY,KAAK,GAAE,SAAnB,eAAmB,OAAS,CAAC;AAC7B,0BAAY,KAAK,EAAE,KAAM,UAAU,IAAI;AACvC,+BAAiB,IAAI,UAAU;AAAA,YACjC;AAKA,gBAAI,cAAc,MAAM;AACtB,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN;AAAA,gBACA,gBAAgB,cAAc;AAAA,cAChC,CAAC;AAAA,YACH;AAAA,UACF;AAEA;AAAA,QACF;AAaA,cAAM,mBAAmB,mBAAmB,GAAG;AAC/C,YAAI,kBAAkB;AACpB,cAAI,CAAC,oBAAoB,KAAK,GAAG;AAC/B,gCAAoB,KAAK,IAAI;AAAA,UAC/B;AAGA,8BAAoB,IAAI,gBAAgB;AAAA,QAC1C;AAEA,cAAM,YAAY,kCAAkC,GAAG;AACvD,YAAI,WAAW;AAEb,gBAAM,eACJ,+BAAoB,KAAK,MAAzB,YAA8B,qBAA9B,YAAkD;AAEpD,cAAI,GAAC,iBAAY,KAAK,MAAjB,mBAAoB,YAAW;AAClC,uBAAW,QAAQ,EAAE,MAAM,mBAAmB,IAAI,MAAM,CAAC;AACzD,0EAAuB,CAAC;AACxB,wBAAY,KAAK,EAAE,YAAY;AAAA,UACjC;AAGA,qBAAW,QAAQ;AAAA,YACjB,MAAM;AAAA,YACN,OAAO;AAAA,YACP,IAAI;AAAA,UACN,CAAC;AAED,8BAAoB,IAAI,WAAW;AAAA,QACrC;AAKA,cAAM,OAAO,eAAe,GAAG;AAC/B,YAAI,MAAM;AACR,cAAI,GAAC,iBAAY,KAAK,MAAjB,mBAAoB,OAAM;AAC7B,uBAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,MAAM,CAAC;AACpD,0EAAuB,CAAC;AACxB,wBAAY,KAAK,EAAE,OAAO;AAAA,UAC5B;AAEA,qBAAW,QAAQ;AAAA,YACjB,MAAM;AAAA,YACN,OAAO;AAAA,YACP,IAAI;AAAA,UACN,CAAC;AAAA,QACH;AAAA,MACF,WAAW,kBAAkB,GAAG,GAAG;AAEjC,cAAM,SAAS;AACf,cAAM,aACJ,OAAO,SAAS,iBAChB,OAAO,UACP,OAAO,OAAO,WAAW,WACpB,OAAO,SACR;AAEN,cAAM,aAAa,WAAW;AAC9B,cAAM,SAAS,WAAW;AAE1B,YAAI,YAAY;AACd,cAAI,WAAW,SAAS;AAEtB,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN;AAAA,cACA,WACE,OAAO,WAAW,YAAY,WAC1B,WAAW,UACX;AAAA,YACR,CAAC;AAAA,UACH,OAAO;AAEL,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN;AAAA,cACA,QAAQ,WAAW;AAAA,YACrB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA;AAAA,IACF;AAAA,IAEA,KAAK,UAAU;AAIb,iBAAW,CAAC,IAAI,IAAI,KAAK,OAAO,QAAQ,WAAW,GAAG;AACpD,YAAI,KAAK,KAAM,YAAW,QAAQ,EAAE,MAAM,YAAY,GAAG,CAAC;AAC1D,YAAI,KAAK,MAAM;AACb,qBAAW,CAAC,YAAY,YAAY,KAAK,OAAO,QAAQ,KAAK,IAAI,GAAG;AAClE,kBAAM,YAAY,cAAc,EAAE;AAClC,kBAAM,YAAW,4CAAW,eAAX,mBAAuB;AAAA,cACtC,UAAQ,KAAK,OAAO;AAAA;AAGtB,gBAAI,gBAAgB,UAAU;AAC5B,+BAAiB,IAAI,UAAU;AAE/B,oBAAM,cAAc,GAAG,SAAS,IAAI,IAAI,KAAK,UAAU,SAAS,IAAI,CAAC;AACrE,oCAAsB,IAAI,aAAa,UAAU;AACjD,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN;AAAA,gBACA,UAAU,SAAS;AAAA,gBACnB,OAAO,SAAS;AAAA,gBAChB,SAAS;AAAA,cACX,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAEA,YAAI,KAAK,WAAW;AAClB,qBAAW,QAAQ,EAAE,MAAM,iBAAiB,GAAG,CAAC;AAAA,QAClD;AAEA,eAAO,YAAY,EAAE;AACrB,eAAO,cAAc,EAAE;AACvB,eAAO,oBAAoB,EAAE;AAAA,MAC/B;AAMA,UAAI,QAAQ,QAAQ,OAAO,SAAS,YAAY,cAAc,MAAM;AAClE,cAAM,WAAY,KAAkC;AACpD,YAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,qBAAW,OAAO,UAAU;AAC1B,gBAAI,CAAC,OAAO,OAAO,QAAQ,SAAU;AAGrC,kBAAM,QAAQ,aAAa,GAAG;AAC9B,gBAAI,CAAC,MAAO;AAKZ,gBAAI;AAKJ,gBAAI,+BAAe,WAAW,GAAG,KAAK,0BAAU,WAAW,GAAG,GAAG;AAC/D,0BAAY,IAAI;AAAA,YAClB,WAAW,qBAAqB,GAAG,GAAG;AAIpC,oBAAM,MAAM;AAKZ,oBAAM,qBACJ,IAAI,SAAS,iBACb,MAAM,QAAQ,IAAI,EAAE,MAClB,IAAI,GAAgB,SAAS,gBAAgB,KAC5C,IAAI,GAAgB,SAAS,WAAW;AAC7C,oBAAM,aAAa,qBACd,IAAI,SACL;AAEJ,kBAAI,IAAI,SAAS,QAAQ,oBAAoB;AAI3C,oBAAI,MAAM,QAAQ,yCAAY,UAAU,GAAG;AACzC,8BAAY,WAAW;AAAA,gBACzB;AAAA;AAAA;AAAA;AAAA,mBAIE,yCAAY,sBACZ,OAAO,WAAW,sBAAsB;AAAA,kBACxC;AACA,wBAAM,mBACJ,WAAW;AACb,sBAAI,MAAM,QAAQ,iBAAiB,UAAU,GAAG;AAI9C,gCACE,iBAAiB,WAIjB,IAAI,CAAC,IAAI,QAAQ;AACjB,4BAAM,eAAe,GAAG;AACxB,0BAAI;AACJ,0BAAI;AACF,gCAAO,6CAAc,aACjB,KAAK,MAAM,aAAa,SAAS,IACjC,CAAC;AAAA,sBACP,SAAQ;AACN,+BAAO,CAAC;AAAA,sBACV;AACA,6BAAO;AAAA,wBACL,IAAI,GAAG,MAAM,QAAQ,GAAG;AAAA,wBACxB,OAAM,6CAAc,SAAQ;AAAA,wBAC5B;AAAA,sBACF;AAAA,oBACF,CAAC;AAAA,kBACH;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAEA,gBAAI,aAAa,UAAU,SAAS,GAAG;AACrC,yBAAW,YAAY,WAAW;AAIhC,oBAAI,SAAS,MAAM,CAAC,iBAAiB,IAAI,SAAS,EAAE,GAAG;AACrD,mCAAiB,IAAI,SAAS,EAAE;AAEhC,wBAAM,cAAc,GAAG,SAAS,IAAI,IAAI,KAAK,UAAU,SAAS,IAAI,CAAC;AACrE,wCAAsB,IAAI,aAAa,SAAS,EAAE;AAMlD,6BAAW,QAAQ;AAAA,oBACjB,MAAM;AAAA,oBACN,YAAY,SAAS;AAAA,oBACrB,UAAU,SAAS;AAAA,oBACnB,SAAS;AAAA,kBACX,CAAC;AACD,6BAAW,QAAQ;AAAA,oBACjB,MAAM;AAAA,oBACN,YAAY,SAAS;AAAA,oBACrB,UAAU,SAAS;AAAA,oBACnB,OAAO,SAAS;AAAA,oBAChB,SAAS;AAAA,kBACX,CAAC;AAAA,gBACH;AAAA,cACF;AAAA,YACF;AAYA,kBAAM,cAAc,mBAAmB,GAAG;AAC1C,kBAAM,yBAAyB,CAAC,CAAC,YAAY,KAAK;AAClD,kBAAM,eAAe,aAAa,UAAU,SAAS;AASrD,kBAAM,sBACJ,eACA,CAAC,oBAAoB,IAAI,WAAW,MACnC,0BAA0B,CAAC;AAE9B,gBAAI,qBAAqB;AAKvB,oBAAM,YAAY,kCAAkC,GAAG;AAEvD,kBAAI,WAAW;AACb,2BAAW,QAAQ,EAAE,MAAM,mBAAmB,IAAI,MAAM,CAAC;AACzD,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN,OAAO;AAAA,kBACP,IAAI;AAAA,gBACN,CAAC;AACD,2BAAW,QAAQ,EAAE,MAAM,iBAAiB,IAAI,MAAM,CAAC;AACvD,oCAAoB,IAAI,WAAW;AAAA,cACrC;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAOA,UAAI,QAAQ,QAAQ,OAAO,SAAS,UAAU;AAC5C,cAAM,YAAa,KAAiC;AACpD,YAAI,MAAM,QAAQ,SAAS,KAAK,UAAU,SAAS,GAAG;AACpD,qBAAW,iBAAiB,WAAW;AACrC,kBAAM,iBAAkB,+CACpB;AAEJ,gBAAI,CAAC,eAAgB;AAKrB,kBAAM,iBAAkB,eAAe,kBACrC,eAAe;AASjB,gBAAI,CAAC,MAAM,QAAQ,cAAc,EAAG;AAEpC,uBAAW,iBAAiB,gBAAgB;AAC1C,oBAAM,WAAW,cAAc;AAI/B,oBAAM,QAAQ,cAAc,QAAQ,cAAc;AAMlD,oBAAM,cAAc,GAAG,QAAQ,IAAI,KAAK,UAAU,KAAK,CAAC;AACxD,oBAAM,aACJ,sBAAsB,IAAI,WAAW,KACrC,cAAc,MACd,QAAQ,QAAQ,IAAI,KAAK,IAAI,CAAC;AAMhC,kBAAI,CAAC,iBAAiB,IAAI,UAAU,GAAG;AACrC,iCAAiB,IAAI,UAAU;AAC/B,sCAAsB,IAAI,aAAa,UAAU;AACjD,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN;AAAA,kBACA;AAAA,kBACA,SAAS;AAAA,gBACX,CAAC;AACD,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA,SAAS;AAAA,gBACX,CAAC;AAAA,cACH;AAKA,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA;AAAA,IACF;AAAA,EACF;AACF;;;ADrsCA,eAAsB,eACpB,UACwB;AACxB,QAAM,gBAAgB,UAAM,kCAAuB,QAAQ;AAC3D,SAAO,qBAAqB,aAAa;AAC3C;AAQO,SAAS,qBACd,eACe;AACf,QAAM,SAAwB,CAAC;AAE/B,aAAW,WAAW,eAAe;AACnC,YAAQ,QAAQ,MAAM;AAAA,MACpB,KAAK,QAAQ;AAEX,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,iBAAiB,IAAI,GAAG;AAC1B,mBAAO,KAAK,sBAAsB,IAAI,CAAC;AAAA,UACzC;AAAA,QACF;AACA;AAAA,MACF;AAAA,MAEA,KAAK,aAAa;AAChB,eAAO,KAAK,wBAAwB,QAAQ,OAAO,CAAC;AACpD;AAAA,MACF;AAAA,MAEA,KAAK,UAAU;AACb,eAAO,KAAK,IAAI,+BAAc,EAAE,SAAS,QAAQ,QAAQ,CAAC,CAAC;AAC3D;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,eAAO,KAAK,mBAAmB,QAAQ,OAAO,CAAC;AAC/C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAgCO,SAAS,kBACd,QACA,WACgC;AAIhC,QAAM,aAAuB,CAAC;AAK9B,QAAM,aAAa;AAAA,IACjB,SAAS;AAAA,IACT,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB,aAAa;AAAA,EACf;AAKA,QAAM,iBAAsC;AAAA,IAC1C,aAAa,CAAC;AAAA,IAId,eAAe,CAAC;AAAA,IAChB,kBAAkB,oBAAI,IAAY;AAAA,IAClC,eAAe,oBAAI,IAAY;AAAA,IAC/B,qBAAqB,oBAAI,IAAY;AAAA,IACrC,qBAAqB,CAAC;AAAA,IACtB,qBAAqB,CAAC;AAAA,IAItB,aAAa;AAAA,IACb,uBAAuB,oBAAI,IAAoB;AAAA,EACjD;AAKA,MAAI,aAA2C;AAK/C,QAAM,mBAAmB,MAA8B;AACrD,QAAI,OAAO,iBAAiB,QAAQ;AAClC,aAAQ,OAAkC,OAAO,aAAa,EAAE;AAAA,IAClE;AAIA,UAAM,SAAU,OAA0B,UAAU;AACpD,WAAO;AAAA,MACL,MAAM,OAAO;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,eAAO,EAAE,MAAM,MAAM;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,iBAAiB;AAKlC,QAAM,2BAA2B,CAC/B,uBACoD;AACpD,WAAO;AAAA,MACL,IAAI,cAAc;AAChB,eAAO,mBAAmB;AAAA,MAC5B;AAAA,MACA,OAAO,MAAM,mBAAmB,MAAM;AAAA,MACtC,OAAO,CAAC,MAAgB,mBAAmB,MAAM,CAAC;AAAA,MAClD,SAAS,CAAC,UAA0B;AAvM1C;AA2MQ,YAAI,aAAa,MAAM,SAAS,gBAAgB,MAAM,OAAO;AAC3D,qBAAW,KAAK,MAAM,KAAK;AAC3B,0BAAU,YAAV,mCAAoB,MAAM;AAC1B,0BAAU,WAAV,mCAAmB,MAAM;AAAA,QAC3B;AACA,2BAAmB,QAAQ,KAAK;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,IAAI,eAA+B;AAAA,IACxC,MAAM,MAAM,YAAY;AAtN5B;AAuNM,cAAM,4CAAW,YAAX;AAEN,YAAM,oBAAoB,yBAAyB,UAAU;AAC7D,iBAAW,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAEpC,UAAI;AACF,eAAO,MAAM;AACX,gBAAM,EAAE,MAAM,MAAM,IAAI,MAAM,SAAS,KAAK;AAC5C,cAAI,KAAM;AAKV,cAAI,eAAe,MAAM;AACvB,gBAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,2BAAa;AAAA,YACf,OAAO;AACL,2BAAa;AAAA,YACf;AAAA,UACF;AAKA,cAAI,eAAe,SAAS;AAC1B;AAAA,cACE;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF,OAAO;AACL;AAAA,cACE;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAKA,YAAI,eAAe,SAAS;AAC1B,cAAI,WAAW,kBAAkB;AAC/B,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,IAAI,WAAW;AAAA,YACjB,CAAC;AAAA,UACH;AACA,cAAI,WAAW,aAAa;AAC1B,uBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,WAAW,UAAU,CAAC;AAAA,UACnE;AACA,qBAAW,QAAQ,EAAE,MAAM,SAAS,CAAC;AAAA,QACvC;AAKA,gBAAM,4CAAW,YAAX,mCAAqB,WAAW,KAAK,EAAE;AAAA,MAC/C,SAAS,OAAO;AACd,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,WAAW,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QACtD,CAAC;AAAA,MACH,UAAE;AACA,mBAAW,MAAM;AAAA,MACnB;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;AErRA,oBAGO;AAqCA,IAAM,+BAAN,MAEP;AAAA,EAGE,YAAY,SAA8C;AApD5D;AAqDI,SAAK,QAAQ,IAAI,0BAAY;AAAA,MAC3B,GAAG;AAAA,MACH,UAAS,aAAQ,YAAR,YAAmB;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aACJ,SAOyC;AACzC,UAAM,eAAe,MAAM,eAAe,QAAQ,QAAQ;AAE1D,UAAM,SAAS,MAAM,KAAK,MAAM;AAAA,MAC9B,EAAE,UAAU,aAAa;AAAA,MACzB,EAAE,YAAY,CAAC,UAAU,UAAU,EAAE;AAAA,IACvC;AAEA,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,kBACJ,UAGgD;AAChD,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AACF;","names":["import_messages"]}
|