@librechat/agents 3.1.75-dev.1 → 3.1.76
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/dist/cjs/llm/openai/index.cjs +43 -0
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +19 -10
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +67 -10
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/tools/search/search.cjs +55 -66
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/tavily-scraper.cjs +189 -0
- package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -0
- package/dist/cjs/tools/search/tavily-search.cjs +372 -0
- package/dist/cjs/tools/search/tavily-search.cjs.map +1 -0
- package/dist/cjs/tools/search/tool.cjs +26 -4
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/search/utils.cjs +10 -3
- package/dist/cjs/tools/search/utils.cjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +43 -0
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +19 -10
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +67 -10
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/tools/search/search.mjs +55 -66
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/tavily-scraper.mjs +186 -0
- package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -0
- package/dist/esm/tools/search/tavily-search.mjs +370 -0
- package/dist/esm/tools/search/tavily-search.mjs.map +1 -0
- package/dist/esm/tools/search/tool.mjs +26 -4
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/search/utils.mjs +10 -3
- package/dist/esm/tools/search/utils.mjs.map +1 -1
- package/dist/types/messages/format.d.ts +4 -1
- package/dist/types/tools/search/tavily-scraper.d.ts +19 -0
- package/dist/types/tools/search/tavily-search.d.ts +4 -0
- package/dist/types/tools/search/types.d.ts +99 -5
- package/dist/types/tools/search/utils.d.ts +2 -2
- package/package.json +1 -1
- package/src/llm/custom-chat-models.smoke.test.ts +175 -1
- package/src/llm/openai/index.ts +124 -0
- package/src/llm/openai/utils/index.ts +23 -14
- package/src/llm/openai/utils/messages.test.ts +159 -0
- package/src/messages/format.ts +90 -13
- package/src/messages/formatAgentMessages.test.ts +166 -1
- package/src/tools/search/search.ts +83 -73
- package/src/tools/search/tavily-scraper.ts +235 -0
- package/src/tools/search/tavily-search.ts +424 -0
- package/src/tools/search/tavily.test.ts +965 -0
- package/src/tools/search/tool.ts +36 -26
- package/src/tools/search/types.ts +134 -11
- package/src/tools/search/utils.ts +13 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../../../../src/llm/openai/utils/index.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-ts-comment */\n/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport { type OpenAI as OpenAIClient } from 'openai';\nimport type {\n ChatCompletionContentPartText,\n ChatCompletionContentPartImage,\n ChatCompletionContentPartInputAudio,\n ChatCompletionContentPart,\n} from 'openai/resources/chat/completions';\nimport {\n AIMessage,\n AIMessageChunk,\n type BaseMessage,\n ChatMessage,\n ToolMessage,\n isAIMessage,\n type UsageMetadata,\n type BaseMessageFields,\n type MessageContentComplex,\n type InvalidToolCall,\n type MessageContentImageUrl,\n StandardContentBlockConverter,\n parseBase64DataUrl,\n parseMimeType,\n convertToProviderContentBlock,\n isDataContentBlock,\n} from '@langchain/core/messages';\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport {\n convertLangChainToolCallToOpenAI,\n makeInvalidToolCall,\n parseToolCall,\n} from '@langchain/core/output_parsers/openai_tools';\nimport type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';\nimport type {\n OpenAICallOptions,\n OpenAIChatInput,\n ChatOpenAIReasoningSummary,\n} from '@langchain/openai';\nimport { toLangChainContent } from '@/messages/langchain';\n\nexport type { OpenAICallOptions, OpenAIChatInput };\n\n// Utility types to get hidden OpenAI response types\ntype ExtractAsyncIterableType<T> = T extends AsyncIterable<infer U> ? U : never;\ntype ExcludeController<T> = T extends { controller: unknown } ? never : T;\ntype ExcludeNonController<T> = T extends { controller: unknown } ? T : never;\n\ntype ResponsesCreate = OpenAIClient.Responses['create'];\ntype ResponsesParse = OpenAIClient.Responses['parse'];\n\ntype ResponsesInputItem = OpenAIClient.Responses.ResponseInputItem;\n\ntype ResponsesCreateInvoke = ExcludeController<\n Awaited<ReturnType<ResponsesCreate>>\n>;\n\ntype ResponsesParseInvoke = ExcludeController<\n Awaited<ReturnType<ResponsesParse>>\n>;\n\ntype ResponsesCreateStream = ExcludeNonController<\n Awaited<ReturnType<ResponsesCreate>>\n>;\n\nexport type ResponseReturnStreamEvents =\n ExtractAsyncIterableType<ResponsesCreateStream>;\n\n// TODO import from SDK when available\ntype OpenAIRoleEnum =\n | 'system'\n | 'developer'\n | 'assistant'\n | 'user'\n | 'function'\n | 'tool';\n\ntype OpenAICompletionParam =\n OpenAIClient.Chat.Completions.ChatCompletionMessageParam;\n\nfunction extractGenericMessageCustomRole(message: ChatMessage) {\n if (\n message.role !== 'system' &&\n message.role !== 'developer' &&\n message.role !== 'assistant' &&\n message.role !== 'user' &&\n message.role !== 'function' &&\n message.role !== 'tool'\n ) {\n console.warn(`Unknown message role: ${message.role}`);\n }\n\n return message.role as OpenAIRoleEnum;\n}\n\nexport function messageToOpenAIRole(message: BaseMessage): OpenAIRoleEnum {\n const type = message._getType();\n switch (type) {\n case 'system':\n return 'system';\n case 'ai':\n return 'assistant';\n case 'human':\n return 'user';\n case 'function':\n return 'function';\n case 'tool':\n return 'tool';\n case 'generic': {\n if (!ChatMessage.isInstance(message))\n throw new Error('Invalid generic chat message');\n return extractGenericMessageCustomRole(message);\n }\n default:\n throw new Error(`Unknown message type: ${type}`);\n }\n}\n\nconst completionsApiContentBlockConverter: StandardContentBlockConverter<{\n text: ChatCompletionContentPartText;\n image: ChatCompletionContentPartImage;\n audio: ChatCompletionContentPartInputAudio;\n file: ChatCompletionContentPart.File;\n}> = {\n providerName: 'ChatOpenAI',\n\n fromStandardTextBlock(block): ChatCompletionContentPartText {\n return { type: 'text', text: block.text };\n },\n\n fromStandardImageBlock(block): ChatCompletionContentPartImage {\n if (block.source_type === 'url') {\n return {\n type: 'image_url',\n image_url: {\n url: block.url,\n ...(block.metadata?.detail\n ? { detail: block.metadata.detail as 'auto' | 'low' | 'high' }\n : {}),\n },\n };\n }\n\n if (block.source_type === 'base64') {\n const url = `data:${block.mime_type ?? ''};base64,${block.data}`;\n return {\n type: 'image_url',\n image_url: {\n url,\n ...(block.metadata?.detail\n ? { detail: block.metadata.detail as 'auto' | 'low' | 'high' }\n : {}),\n },\n };\n }\n\n throw new Error(\n `Image content blocks with source_type ${block.source_type} are not supported for ChatOpenAI`\n );\n },\n\n fromStandardAudioBlock(block): ChatCompletionContentPartInputAudio {\n if (block.source_type === 'url') {\n const data = parseBase64DataUrl({ dataUrl: block.url });\n if (!data) {\n throw new Error(\n `URL audio blocks with source_type ${block.source_type} must be formatted as a data URL for ChatOpenAI`\n );\n }\n\n const rawMimeType = data.mime_type || block.mime_type || '';\n let mimeType: { type: string; subtype: string };\n\n try {\n mimeType = parseMimeType(rawMimeType);\n } catch {\n throw new Error(\n `Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`\n );\n }\n\n if (\n mimeType.type !== 'audio' ||\n (mimeType.subtype !== 'wav' && mimeType.subtype !== 'mp3')\n ) {\n throw new Error(\n `Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`\n );\n }\n\n return {\n type: 'input_audio',\n input_audio: {\n format: mimeType.subtype,\n data: data.data,\n },\n };\n }\n\n if (block.source_type === 'base64') {\n let mimeType: { type: string; subtype: string };\n\n try {\n mimeType = parseMimeType(block.mime_type ?? '');\n } catch {\n throw new Error(\n `Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`\n );\n }\n\n if (\n mimeType.type !== 'audio' ||\n (mimeType.subtype !== 'wav' && mimeType.subtype !== 'mp3')\n ) {\n throw new Error(\n `Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`\n );\n }\n\n return {\n type: 'input_audio',\n input_audio: {\n format: mimeType.subtype,\n data: block.data,\n },\n };\n }\n\n throw new Error(\n `Audio content blocks with source_type ${block.source_type} are not supported for ChatOpenAI`\n );\n },\n\n fromStandardFileBlock(block): ChatCompletionContentPart.File {\n if (block.source_type === 'url') {\n const data = parseBase64DataUrl({ dataUrl: block.url });\n if (!data) {\n throw new Error(\n `URL file blocks with source_type ${block.source_type} must be formatted as a data URL for ChatOpenAI`\n );\n }\n\n return {\n type: 'file',\n file: {\n file_data: block.url, // formatted as base64 data URL\n ...(block.metadata?.filename || block.metadata?.name\n ? {\n filename: (block.metadata.filename ||\n block.metadata.name) as string,\n }\n : {}),\n },\n };\n }\n\n if (block.source_type === 'base64') {\n return {\n type: 'file',\n file: {\n file_data: `data:${block.mime_type ?? ''};base64,${block.data}`,\n ...(block.metadata?.filename ||\n block.metadata?.name ||\n block.metadata?.title\n ? {\n filename: (block.metadata.filename ||\n block.metadata.name ||\n block.metadata.title) as string,\n }\n : {}),\n },\n };\n }\n\n if (block.source_type === 'id') {\n return {\n type: 'file',\n file: {\n file_id: block.id,\n },\n };\n }\n\n throw new Error(\n `File content blocks with source_type ${block.source_type} are not supported for ChatOpenAI`\n );\n },\n};\n\n/** Options for converting messages to OpenAI params */\nexport interface ConvertMessagesOptions {\n /** Include reasoning_content field for DeepSeek thinking mode with tool calls */\n includeReasoningContent?: boolean;\n /** Include reasoning_details field for OpenRouter/Gemini thinking mode with tool calls */\n includeReasoningDetails?: boolean;\n /** Convert reasoning_details to content blocks for Claude (requires content array format) */\n convertReasoningDetailsToContent?: boolean;\n}\n\n// Used in LangSmith, export is important here\nexport function _convertMessagesToOpenAIParams(\n messages: BaseMessage[],\n model?: string,\n options?: ConvertMessagesOptions\n): OpenAICompletionParam[] {\n // TODO: Function messages do not support array content, fix cast\n return messages.flatMap((message) => {\n let role = messageToOpenAIRole(message);\n if (role === 'system' && isReasoningModel(model)) {\n role = 'developer';\n }\n\n let hasAnthropicThinkingBlock: boolean = false;\n\n const content =\n typeof message.content === 'string'\n ? message.content\n : message.content.map((m) => {\n if ('type' in m && m.type === 'thinking') {\n hasAnthropicThinkingBlock = true;\n return m;\n }\n if (isDataContentBlock(m)) {\n return convertToProviderContentBlock(\n m,\n completionsApiContentBlockConverter\n );\n }\n return m;\n });\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const completionParam: Record<string, any> = {\n role,\n content,\n };\n if (message.name != null) {\n completionParam.name = message.name;\n }\n if (message.additional_kwargs.function_call != null) {\n completionParam.function_call = message.additional_kwargs.function_call;\n completionParam.content = '';\n }\n if (isAIMessage(message) && !!message.tool_calls?.length) {\n completionParam.tool_calls = message.tool_calls.map(\n convertLangChainToolCallToOpenAI\n );\n completionParam.content = hasAnthropicThinkingBlock ? content : '';\n if (\n options?.includeReasoningContent === true &&\n message.additional_kwargs.reasoning_content != null\n ) {\n completionParam.reasoning_content =\n message.additional_kwargs.reasoning_content;\n }\n if (\n options?.includeReasoningDetails === true &&\n message.additional_kwargs.reasoning_details != null\n ) {\n // For Claude via OpenRouter, convert reasoning_details to content blocks\n const isClaudeModel =\n model?.includes('claude') === true ||\n model?.includes('anthropic') === true;\n if (\n options.convertReasoningDetailsToContent === true &&\n isClaudeModel\n ) {\n const reasoningDetails = message.additional_kwargs\n .reasoning_details as Record<string, unknown>[];\n const contentBlocks = [];\n\n // Add thinking blocks from reasoning_details\n for (const detail of reasoningDetails) {\n if (detail.type === 'reasoning.text' && detail.text != null) {\n contentBlocks.push({\n type: 'thinking',\n thinking: detail.text,\n });\n } else if (\n detail.type === 'reasoning.encrypted' &&\n detail.data != null\n ) {\n contentBlocks.push({\n type: 'redacted_thinking',\n data: detail.data,\n id: detail.id,\n });\n }\n }\n\n // Set content to array with thinking blocks\n if (contentBlocks.length > 0) {\n completionParam.content = contentBlocks;\n }\n } else {\n // For non-Claude models, pass as separate field\n completionParam.reasoning_details =\n message.additional_kwargs.reasoning_details;\n }\n }\n } else {\n if (message.additional_kwargs.tool_calls != null) {\n completionParam.tool_calls = message.additional_kwargs.tool_calls;\n if (\n options?.includeReasoningContent === true &&\n message.additional_kwargs.reasoning_content != null\n ) {\n completionParam.reasoning_content =\n message.additional_kwargs.reasoning_content;\n }\n if (\n options?.includeReasoningDetails === true &&\n message.additional_kwargs.reasoning_details != null\n ) {\n // For Claude via OpenRouter, convert reasoning_details to content blocks\n const isClaudeModel =\n model?.includes('claude') === true ||\n model?.includes('anthropic') === true;\n if (\n options.convertReasoningDetailsToContent === true &&\n isClaudeModel\n ) {\n const reasoningDetails = message.additional_kwargs\n .reasoning_details as Record<string, unknown>[];\n const contentBlocks = [];\n\n // Add thinking blocks from reasoning_details\n for (const detail of reasoningDetails) {\n if (detail.type === 'reasoning.text' && detail.text != null) {\n contentBlocks.push({\n type: 'thinking',\n thinking: detail.text,\n });\n } else if (\n detail.type === 'reasoning.encrypted' &&\n detail.data != null\n ) {\n contentBlocks.push({\n type: 'redacted_thinking',\n data: detail.data,\n id: detail.id,\n });\n }\n }\n\n // Set content to array with thinking blocks\n if (contentBlocks.length > 0) {\n completionParam.content = contentBlocks;\n }\n } else {\n // For non-Claude models, pass as separate field\n completionParam.reasoning_details =\n message.additional_kwargs.reasoning_details;\n }\n }\n }\n if ((message as ToolMessage).tool_call_id != null) {\n completionParam.tool_call_id = (message as ToolMessage).tool_call_id;\n }\n }\n\n if (\n message.additional_kwargs.audio &&\n typeof message.additional_kwargs.audio === 'object' &&\n 'id' in message.additional_kwargs.audio\n ) {\n const audioMessage = {\n role: 'assistant',\n audio: {\n id: message.additional_kwargs.audio.id,\n },\n };\n return [completionParam, audioMessage] as OpenAICompletionParam[];\n }\n\n return completionParam as OpenAICompletionParam;\n });\n}\n\nconst _FUNCTION_CALL_IDS_MAP_KEY = '__openai_function_call_ids__';\n\nfunction _convertReasoningSummaryToOpenAIResponsesParams(\n reasoning: ChatOpenAIReasoningSummary\n): OpenAIClient.Responses.ResponseReasoningItem {\n // combine summary parts that have the the same index and then remove the indexes\n const summary = (\n reasoning.summary.length > 1\n ? reasoning.summary.reduce(\n (acc, curr) => {\n const last = acc.at(-1);\n\n if (last!.index === curr.index) {\n last!.text += curr.text;\n } else {\n acc.push(curr);\n }\n return acc;\n },\n [{ ...reasoning.summary[0] }]\n )\n : reasoning.summary\n ).map((s) =>\n Object.fromEntries(Object.entries(s).filter(([k]) => k !== 'index'))\n ) as OpenAIClient.Responses.ResponseReasoningItem.Summary[];\n\n return {\n ...reasoning,\n summary,\n } as OpenAIClient.Responses.ResponseReasoningItem;\n}\n\nexport function _convertMessagesToOpenAIResponsesParams(\n messages: BaseMessage[],\n model?: string,\n zdrEnabled?: boolean\n): ResponsesInputItem[] {\n return messages.flatMap(\n (lcMsg): ResponsesInputItem | ResponsesInputItem[] => {\n const additional_kwargs =\n lcMsg.additional_kwargs as BaseMessageFields['additional_kwargs'] & {\n [_FUNCTION_CALL_IDS_MAP_KEY]?: Record<string, string>;\n reasoning?: OpenAIClient.Responses.ResponseReasoningItem;\n type?: string;\n refusal?: string;\n };\n const responseMetadata = lcMsg.response_metadata as {\n output?: ResponsesInputItem[];\n };\n\n let role = messageToOpenAIRole(lcMsg);\n if (role === 'system' && isReasoningModel(model)) role = 'developer';\n\n if (role === 'function') {\n throw new Error('Function messages are not supported in Responses API');\n }\n\n if (role === 'tool') {\n const toolMessage = lcMsg as ToolMessage;\n\n // Handle computer call output\n if (additional_kwargs.type === 'computer_call_output') {\n const output = (() => {\n if (typeof toolMessage.content === 'string') {\n return {\n type: 'computer_screenshot' as const,\n image_url: toolMessage.content,\n };\n }\n\n if (Array.isArray(toolMessage.content)) {\n const oaiScreenshot = toolMessage.content.find(\n (i) => i.type === 'computer_screenshot'\n ) as { type: 'computer_screenshot'; image_url: string };\n\n if (oaiScreenshot) return oaiScreenshot;\n\n const lcImage = toolMessage.content.find(\n (i) => i.type === 'image_url'\n ) as MessageContentImageUrl;\n\n if (lcImage) {\n return {\n type: 'computer_screenshot' as const,\n image_url:\n typeof lcImage.image_url === 'string'\n ? lcImage.image_url\n : lcImage.image_url.url,\n };\n }\n }\n\n throw new Error('Invalid computer call output');\n })();\n\n return {\n type: 'computer_call_output',\n output,\n call_id: toolMessage.tool_call_id,\n };\n }\n\n return {\n type: 'function_call_output',\n call_id: toolMessage.tool_call_id,\n id: toolMessage.id?.startsWith('fc_') ? toolMessage.id : undefined,\n output:\n typeof toolMessage.content !== 'string'\n ? JSON.stringify(toolMessage.content)\n : toolMessage.content,\n };\n }\n\n if (role === 'assistant') {\n // if we have the original response items, just reuse them\n if (\n !zdrEnabled &&\n responseMetadata.output != null &&\n Array.isArray(responseMetadata.output) &&\n responseMetadata.output.length > 0 &&\n responseMetadata.output.every((item) => 'type' in item)\n ) {\n return responseMetadata.output;\n }\n\n // otherwise, try to reconstruct the response from what we have\n\n const input: ResponsesInputItem[] = [];\n\n // reasoning items\n if (additional_kwargs.reasoning && !zdrEnabled) {\n const reasoningItem = _convertReasoningSummaryToOpenAIResponsesParams(\n additional_kwargs.reasoning\n );\n input.push(reasoningItem);\n }\n\n // ai content\n let content = lcMsg.content as\n | string\n | Array<\n | MessageContentComplex\n | OpenAIClient.Responses.ResponseOutputText\n | OpenAIClient.Responses.ResponseOutputRefusal\n >;\n if (additional_kwargs.refusal) {\n if (typeof content === 'string') {\n content = [{ type: 'output_text', text: content, annotations: [] }];\n }\n content = [\n ...content,\n { type: 'refusal', refusal: additional_kwargs.refusal },\n ];\n }\n\n input.push({\n type: 'message',\n role: 'assistant',\n ...(lcMsg.id && !zdrEnabled && lcMsg.id.startsWith('msg_')\n ? { id: lcMsg.id }\n : {}),\n content:\n typeof content === 'string'\n ? content\n : content.flatMap((item) => {\n if (item.type === 'text') {\n const textItem = item as MessageContentComplex & {\n annotations?: unknown[];\n };\n return {\n type: 'output_text',\n text: item.text,\n annotations: textItem.annotations ?? [],\n };\n }\n\n if (item.type === 'output_text' || item.type === 'refusal') {\n return item;\n }\n\n return [];\n }),\n } as ResponsesInputItem);\n\n const functionCallIds = additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY];\n\n if (isAIMessage(lcMsg) && !!lcMsg.tool_calls?.length) {\n input.push(\n ...lcMsg.tool_calls.map(\n (toolCall): ResponsesInputItem => ({\n type: 'function_call',\n name: toolCall.name,\n arguments: JSON.stringify(toolCall.args),\n call_id: toolCall.id!,\n ...(zdrEnabled ? { id: functionCallIds?.[toolCall.id!] } : {}),\n })\n )\n );\n } else if (additional_kwargs.tool_calls) {\n input.push(\n ...additional_kwargs.tool_calls.map(\n (toolCall): ResponsesInputItem => ({\n type: 'function_call',\n name: toolCall.function.name,\n call_id: toolCall.id,\n arguments: toolCall.function.arguments,\n ...(zdrEnabled ? { id: functionCallIds?.[toolCall.id] } : {}),\n })\n )\n );\n }\n\n const toolOutputs =\n ((responseMetadata.output as Array<ResponsesInputItem> | undefined)\n ?.length ?? 0) > 0\n ? responseMetadata.output\n : additional_kwargs.tool_outputs;\n\n const fallthroughCallTypes: ResponsesInputItem['type'][] = [\n 'computer_call',\n /** @ts-ignore */\n 'mcp_call',\n /** @ts-ignore */\n 'code_interpreter_call',\n /** @ts-ignore */\n 'image_generation_call',\n ];\n\n if (toolOutputs != null) {\n const castToolOutputs = toolOutputs as Array<ResponsesInputItem>;\n const fallthroughCalls = castToolOutputs.filter((item) =>\n fallthroughCallTypes.includes(item.type)\n );\n if (fallthroughCalls.length > 0) input.push(...fallthroughCalls);\n }\n\n return input;\n }\n\n if (role === 'user' || role === 'system' || role === 'developer') {\n if (typeof lcMsg.content === 'string') {\n return { type: 'message', role, content: lcMsg.content };\n }\n\n const messages: ResponsesInputItem[] = [];\n const content = (lcMsg.content as MessageContentComplex[]).flatMap(\n (item) => {\n if (item.type === 'mcp_approval_response') {\n const approvalResponse = item as MessageContentComplex & {\n approval_request_id: string;\n approve: boolean;\n };\n messages.push({\n // @ts-ignore\n type: 'mcp_approval_response',\n approval_request_id: approvalResponse.approval_request_id,\n approve: approvalResponse.approve,\n });\n }\n if (isDataContentBlock(item)) {\n return convertToProviderContentBlock(\n item,\n completionsApiContentBlockConverter\n );\n }\n if (item.type === 'text') {\n return {\n type: 'input_text',\n text: item.text,\n };\n }\n if (item.type === 'image_url') {\n const imageItem = item as MessageContentImageUrl;\n return {\n type: 'input_image',\n image_url:\n typeof imageItem.image_url === 'string'\n ? imageItem.image_url\n : imageItem.image_url.url,\n detail:\n typeof imageItem.image_url === 'string'\n ? 'auto'\n : imageItem.image_url.detail,\n };\n }\n if (\n item.type === 'input_text' ||\n item.type === 'input_image' ||\n item.type === 'input_file'\n ) {\n return item;\n }\n return [];\n }\n );\n\n if (content.length > 0) {\n messages.push({\n type: 'message',\n role,\n content,\n } as ResponsesInputItem);\n }\n return messages;\n }\n\n console.warn(\n `Unsupported role found when converting to OpenAI Responses API: ${role}`\n );\n return [];\n }\n );\n}\n\nexport function isReasoningModel(model?: string) {\n return model != null && model !== '' && /\\b(o\\d|gpt-[5-9])\\b/i.test(model);\n}\n\nfunction _convertOpenAIResponsesMessageToBaseMessage(\n response: ResponsesCreateInvoke | ResponsesParseInvoke\n): BaseMessage {\n if (response.error) {\n // TODO: add support for `addLangChainErrorFields`\n const error = new Error(response.error.message);\n error.name = response.error.code;\n throw error;\n }\n\n let messageId: string | undefined;\n const content: MessageContentComplex[] = [];\n const tool_calls: ToolCall[] = [];\n const invalid_tool_calls: InvalidToolCall[] = [];\n const response_metadata: Record<string, unknown> = {\n model: response.model,\n created_at: response.created_at,\n id: response.id,\n incomplete_details: response.incomplete_details,\n metadata: response.metadata,\n object: response.object,\n status: response.status,\n user: response.user,\n service_tier: response.service_tier,\n\n // for compatibility with chat completion calls.\n model_name: response.model,\n };\n\n const additional_kwargs: {\n [key: string]: unknown;\n refusal?: string;\n reasoning?: OpenAIClient.Responses.ResponseReasoningItem;\n tool_outputs?: unknown[];\n parsed?: unknown;\n [_FUNCTION_CALL_IDS_MAP_KEY]?: Record<string, string>;\n } = {};\n\n for (const item of response.output) {\n if (item.type === 'message') {\n messageId = item.id;\n content.push(\n ...item.content.flatMap((part) => {\n if (part.type === 'output_text') {\n if ('parsed' in part && part.parsed != null) {\n additional_kwargs.parsed = part.parsed;\n }\n return {\n type: 'text',\n text: part.text,\n annotations: part.annotations,\n };\n }\n\n if (part.type === 'refusal') {\n additional_kwargs.refusal = part.refusal;\n return [];\n }\n\n return part;\n })\n );\n } else if (item.type === 'function_call') {\n const fnAdapter = {\n function: { name: item.name, arguments: item.arguments },\n id: item.call_id,\n };\n\n try {\n tool_calls.push(parseToolCall(fnAdapter, { returnId: true }));\n } catch (e: unknown) {\n let errMessage: string | undefined;\n if (\n typeof e === 'object' &&\n e != null &&\n 'message' in e &&\n typeof e.message === 'string'\n ) {\n errMessage = e.message;\n }\n invalid_tool_calls.push(makeInvalidToolCall(fnAdapter, errMessage));\n }\n\n additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY] ??= {};\n if (item.id) {\n additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY][item.call_id] = item.id;\n }\n } else if (item.type === 'reasoning') {\n additional_kwargs.reasoning = item;\n } else {\n additional_kwargs.tool_outputs ??= [];\n additional_kwargs.tool_outputs.push(item);\n }\n }\n\n return new AIMessage({\n id: messageId,\n content: toLangChainContent(content),\n tool_calls,\n invalid_tool_calls,\n usage_metadata: response.usage,\n additional_kwargs,\n response_metadata,\n });\n}\n\nexport function _convertOpenAIResponsesDeltaToBaseMessageChunk(\n chunk: ResponseReturnStreamEvents\n) {\n const content: MessageContentComplex[] = [];\n let generationInfo: Record<string, unknown> = {};\n let usage_metadata: UsageMetadata | undefined;\n const tool_call_chunks: ToolCallChunk[] = [];\n const response_metadata: Record<string, unknown> = {};\n const additional_kwargs: {\n [key: string]: unknown;\n reasoning?: Partial<ChatOpenAIReasoningSummary>;\n tool_outputs?: unknown[];\n } = {};\n let id: string | undefined;\n if (chunk.type === 'response.output_text.delta') {\n content.push({\n type: 'text',\n text: chunk.delta,\n index: chunk.content_index,\n });\n /** @ts-ignore */\n } else if (chunk.type === 'response.output_text_annotation.added') {\n content.push({\n type: 'text',\n text: '',\n /** @ts-ignore */\n annotations: [chunk.annotation],\n /** @ts-ignore */\n index: chunk.content_index,\n });\n } else if (\n chunk.type === 'response.output_item.added' &&\n chunk.item.type === 'message'\n ) {\n id = chunk.item.id;\n } else if (\n chunk.type === 'response.output_item.added' &&\n chunk.item.type === 'function_call'\n ) {\n tool_call_chunks.push({\n type: 'tool_call_chunk',\n name: chunk.item.name,\n args: chunk.item.arguments,\n id: chunk.item.call_id,\n index: chunk.output_index,\n });\n\n additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY] = {\n [chunk.item.call_id]: chunk.item.id,\n };\n } else if (\n chunk.type === 'response.output_item.done' &&\n [\n 'web_search_call',\n 'file_search_call',\n 'computer_call',\n 'code_interpreter_call',\n 'mcp_call',\n 'mcp_list_tools',\n 'mcp_approval_request',\n 'image_generation_call',\n ].includes(chunk.item.type)\n ) {\n additional_kwargs.tool_outputs = [chunk.item];\n } else if (chunk.type === 'response.created') {\n response_metadata.id = chunk.response.id;\n response_metadata.model_name = chunk.response.model;\n response_metadata.model = chunk.response.model;\n } else if (chunk.type === 'response.completed') {\n const msg = _convertOpenAIResponsesMessageToBaseMessage(chunk.response);\n\n usage_metadata = chunk.response.usage;\n if (chunk.response.text?.format?.type === 'json_schema') {\n additional_kwargs.parsed ??= JSON.parse(msg.text);\n }\n for (const [key, value] of Object.entries(chunk.response)) {\n if (key !== 'id') response_metadata[key] = value;\n }\n } else if (chunk.type === 'response.function_call_arguments.delta') {\n tool_call_chunks.push({\n type: 'tool_call_chunk',\n args: chunk.delta,\n index: chunk.output_index,\n });\n } else if (\n chunk.type === 'response.web_search_call.completed' ||\n chunk.type === 'response.file_search_call.completed'\n ) {\n generationInfo = {\n tool_outputs: {\n id: chunk.item_id,\n type: chunk.type.replace('response.', '').replace('.completed', ''),\n status: 'completed',\n },\n };\n } else if (chunk.type === 'response.refusal.done') {\n additional_kwargs.refusal = chunk.refusal;\n } else if (\n chunk.type === 'response.output_item.added' &&\n 'item' in chunk &&\n chunk.item.type === 'reasoning'\n ) {\n const summary: ChatOpenAIReasoningSummary['summary'] | undefined = chunk\n .item.summary\n ? chunk.item.summary.map((s, index) => ({\n ...s,\n index,\n }))\n : undefined;\n\n additional_kwargs.reasoning = {\n // We only capture ID in the first chunk or else the concatenated result of all chunks will\n // have an ID field that is repeated once per chunk. There is special handling for the `type`\n // field that prevents this, however.\n id: chunk.item.id,\n type: chunk.item.type,\n ...(summary ? { summary } : {}),\n };\n } else if (chunk.type === 'response.reasoning_summary_part.added') {\n additional_kwargs.reasoning = {\n type: 'reasoning',\n summary: [{ ...chunk.part, index: chunk.summary_index }],\n };\n } else if (chunk.type === 'response.reasoning_summary_text.delta') {\n additional_kwargs.reasoning = {\n type: 'reasoning',\n summary: [\n { text: chunk.delta, type: 'summary_text', index: chunk.summary_index },\n ],\n };\n /** @ts-ignore */\n } else if (chunk.type === 'response.image_generation_call.partial_image') {\n // noop/fixme: retaining partial images in a message chunk means that _all_\n // partial images get kept in history, so we don't do anything here.\n return null;\n } else {\n return null;\n }\n\n return new ChatGenerationChunk({\n // Legacy reasons, `onLLMNewToken` should pulls this out\n text: content.map((part) => ('text' in part ? part.text : '')).join(''),\n message: new AIMessageChunk({\n id,\n content: toLangChainContent(content),\n tool_call_chunks,\n usage_metadata,\n additional_kwargs,\n response_metadata,\n }),\n generationInfo,\n });\n}\n"],"names":[],"mappings":";;;;AAgFA,SAAS,+BAA+B,CAAC,OAAoB,EAAA;AAC3D,IAAA,IACE,OAAO,CAAC,IAAI,KAAK,QAAQ;QACzB,OAAO,CAAC,IAAI,KAAK,WAAW;QAC5B,OAAO,CAAC,IAAI,KAAK,WAAW;QAC5B,OAAO,CAAC,IAAI,KAAK,MAAM;QACvB,OAAO,CAAC,IAAI,KAAK,UAAU;AAC3B,QAAA,OAAO,CAAC,IAAI,KAAK,MAAM,EACvB;QACA,OAAO,CAAC,IAAI,CAAC,CAAA,sBAAA,EAAyB,OAAO,CAAC,IAAI,CAAA,CAAE,CAAC;IACvD;IAEA,OAAO,OAAO,CAAC,IAAsB;AACvC;AAEM,SAAU,mBAAmB,CAAC,OAAoB,EAAA;AACtD,IAAA,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,EAAE;IAC/B,QAAQ,IAAI;AACZ,QAAA,KAAK,QAAQ;AACX,YAAA,OAAO,QAAQ;AACjB,QAAA,KAAK,IAAI;AACP,YAAA,OAAO,WAAW;AACpB,QAAA,KAAK,OAAO;AACV,YAAA,OAAO,MAAM;AACf,QAAA,KAAK,UAAU;AACb,YAAA,OAAO,UAAU;AACnB,QAAA,KAAK,MAAM;AACT,YAAA,OAAO,MAAM;QACf,KAAK,SAAS,EAAE;AACd,YAAA,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC;AAClC,gBAAA,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC;AACjD,YAAA,OAAO,+BAA+B,CAAC,OAAO,CAAC;QACjD;AACA,QAAA;AACE,YAAA,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,CAAA,CAAE,CAAC;;AAEpD;AAEA,MAAM,mCAAmC,GAKpC;AACH,IAAA,YAAY,EAAE,YAAY;AAE1B,IAAA,qBAAqB,CAAC,KAAK,EAAA;QACzB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;IAC3C,CAAC;AAED,IAAA,sBAAsB,CAAC,KAAK,EAAA;AAC1B,QAAA,IAAI,KAAK,CAAC,WAAW,KAAK,KAAK,EAAE;YAC/B,OAAO;AACL,gBAAA,IAAI,EAAE,WAAW;AACjB,gBAAA,SAAS,EAAE;oBACT,GAAG,EAAE,KAAK,CAAC,GAAG;AACd,oBAAA,IAAI,KAAK,CAAC,QAAQ,EAAE;0BAChB,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAiC;0BAC1D,EAAE,CAAC;AACR,iBAAA;aACF;QACH;AAEA,QAAA,IAAI,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE;AAClC,YAAA,MAAM,GAAG,GAAG,CAAA,KAAA,EAAQ,KAAK,CAAC,SAAS,IAAI,EAAE,CAAA,QAAA,EAAW,KAAK,CAAC,IAAI,EAAE;YAChE,OAAO;AACL,gBAAA,IAAI,EAAE,WAAW;AACjB,gBAAA,SAAS,EAAE;oBACT,GAAG;AACH,oBAAA,IAAI,KAAK,CAAC,QAAQ,EAAE;0BAChB,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAiC;0BAC1D,EAAE,CAAC;AACR,iBAAA;aACF;QACH;QAEA,MAAM,IAAI,KAAK,CACb,CAAA,sCAAA,EAAyC,KAAK,CAAC,WAAW,CAAA,iCAAA,CAAmC,CAC9F;IACH,CAAC;AAED,IAAA,sBAAsB,CAAC,KAAK,EAAA;AAC1B,QAAA,IAAI,KAAK,CAAC,WAAW,KAAK,KAAK,EAAE;AAC/B,YAAA,MAAM,IAAI,GAAG,kBAAkB,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;YACvD,IAAI,CAAC,IAAI,EAAE;gBACT,MAAM,IAAI,KAAK,CACb,CAAA,kCAAA,EAAqC,KAAK,CAAC,WAAW,CAAA,+CAAA,CAAiD,CACxG;YACH;YAEA,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,IAAI,EAAE;AAC3D,YAAA,IAAI,QAA2C;AAE/C,YAAA,IAAI;AACF,gBAAA,QAAQ,GAAG,aAAa,CAAC,WAAW,CAAC;YACvC;AAAE,YAAA,MAAM;gBACN,MAAM,IAAI,KAAK,CACb,CAAA,8BAAA,EAAiC,KAAK,CAAC,WAAW,CAAA,8CAAA,CAAgD,CACnG;YACH;AAEA,YAAA,IACE,QAAQ,CAAC,IAAI,KAAK,OAAO;AACzB,iBAAC,QAAQ,CAAC,OAAO,KAAK,KAAK,IAAI,QAAQ,CAAC,OAAO,KAAK,KAAK,CAAC,EAC1D;gBACA,MAAM,IAAI,KAAK,CACb,CAAA,8BAAA,EAAiC,KAAK,CAAC,WAAW,CAAA,8CAAA,CAAgD,CACnG;YACH;YAEA,OAAO;AACL,gBAAA,IAAI,EAAE,aAAa;AACnB,gBAAA,WAAW,EAAE;oBACX,MAAM,EAAE,QAAQ,CAAC,OAAO;oBACxB,IAAI,EAAE,IAAI,CAAC,IAAI;AAChB,iBAAA;aACF;QACH;AAEA,QAAA,IAAI,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE;AAClC,YAAA,IAAI,QAA2C;AAE/C,YAAA,IAAI;gBACF,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC;YACjD;AAAE,YAAA,MAAM;gBACN,MAAM,IAAI,KAAK,CACb,CAAA,8BAAA,EAAiC,KAAK,CAAC,WAAW,CAAA,8CAAA,CAAgD,CACnG;YACH;AAEA,YAAA,IACE,QAAQ,CAAC,IAAI,KAAK,OAAO;AACzB,iBAAC,QAAQ,CAAC,OAAO,KAAK,KAAK,IAAI,QAAQ,CAAC,OAAO,KAAK,KAAK,CAAC,EAC1D;gBACA,MAAM,IAAI,KAAK,CACb,CAAA,8BAAA,EAAiC,KAAK,CAAC,WAAW,CAAA,8CAAA,CAAgD,CACnG;YACH;YAEA,OAAO;AACL,gBAAA,IAAI,EAAE,aAAa;AACnB,gBAAA,WAAW,EAAE;oBACX,MAAM,EAAE,QAAQ,CAAC,OAAO;oBACxB,IAAI,EAAE,KAAK,CAAC,IAAI;AACjB,iBAAA;aACF;QACH;QAEA,MAAM,IAAI,KAAK,CACb,CAAA,sCAAA,EAAyC,KAAK,CAAC,WAAW,CAAA,iCAAA,CAAmC,CAC9F;IACH,CAAC;AAED,IAAA,qBAAqB,CAAC,KAAK,EAAA;AACzB,QAAA,IAAI,KAAK,CAAC,WAAW,KAAK,KAAK,EAAE;AAC/B,YAAA,MAAM,IAAI,GAAG,kBAAkB,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;YACvD,IAAI,CAAC,IAAI,EAAE;gBACT,MAAM,IAAI,KAAK,CACb,CAAA,iCAAA,EAAoC,KAAK,CAAC,WAAW,CAAA,+CAAA,CAAiD,CACvG;YACH;YAEA,OAAO;AACL,gBAAA,IAAI,EAAE,MAAM;AACZ,gBAAA,IAAI,EAAE;AACJ,oBAAA,SAAS,EAAE,KAAK,CAAC,GAAG;oBACpB,IAAI,KAAK,CAAC,QAAQ,EAAE,QAAQ,IAAI,KAAK,CAAC,QAAQ,EAAE;AAC9C,0BAAE;AACA,4BAAA,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ;AAC9B,gCAAA,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAW;AACnC;0BACC,EAAE,CAAC;AACR,iBAAA;aACF;QACH;AAEA,QAAA,IAAI,KAAK,CAAC,WAAW,KAAK,QAAQ,EAAE;YAClC,OAAO;AACL,gBAAA,IAAI,EAAE,MAAM;AACZ,gBAAA,IAAI,EAAE;oBACJ,SAAS,EAAE,CAAA,KAAA,EAAQ,KAAK,CAAC,SAAS,IAAI,EAAE,CAAA,QAAA,EAAW,KAAK,CAAC,IAAI,CAAA,CAAE;AAC/D,oBAAA,IAAI,KAAK,CAAC,QAAQ,EAAE,QAAQ;wBAC5B,KAAK,CAAC,QAAQ,EAAE,IAAI;wBACpB,KAAK,CAAC,QAAQ,EAAE;AACd,0BAAE;AACA,4BAAA,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ;gCAC9B,KAAK,CAAC,QAAQ,CAAC,IAAI;AACnB,gCAAA,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAW;AACpC;0BACC,EAAE,CAAC;AACR,iBAAA;aACF;QACH;AAEA,QAAA,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI,EAAE;YAC9B,OAAO;AACL,gBAAA,IAAI,EAAE,MAAM;AACZ,gBAAA,IAAI,EAAE;oBACJ,OAAO,EAAE,KAAK,CAAC,EAAE;AAClB,iBAAA;aACF;QACH;QAEA,MAAM,IAAI,KAAK,CACb,CAAA,qCAAA,EAAwC,KAAK,CAAC,WAAW,CAAA,iCAAA,CAAmC,CAC7F;IACH,CAAC;CACF;AAYD;SACgB,8BAA8B,CAC5C,QAAuB,EACvB,KAAc,EACd,OAAgC,EAAA;;AAGhC,IAAA,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,KAAI;AAClC,QAAA,IAAI,IAAI,GAAG,mBAAmB,CAAC,OAAO,CAAC;QACvC,IAAI,IAAI,KAAK,QAAQ,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE;YAChD,IAAI,GAAG,WAAW;QACpB;QAEA,IAAI,yBAAyB,GAAY,KAAK;AAE9C,QAAA,MAAM,OAAO,GACX,OAAO,OAAO,CAAC,OAAO,KAAK;cACvB,OAAO,CAAC;cACR,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAI;gBAC1B,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE;oBACxC,yBAAyB,GAAG,IAAI;AAChC,oBAAA,OAAO,CAAC;gBACV;AACA,gBAAA,IAAI,kBAAkB,CAAC,CAAC,CAAC,EAAE;AACzB,oBAAA,OAAO,6BAA6B,CAClC,CAAC,EACD,mCAAmC,CACpC;gBACH;AACA,gBAAA,OAAO,CAAC;AACV,YAAA,CAAC,CAAC;;AAEN,QAAA,MAAM,eAAe,GAAwB;YAC3C,IAAI;YACJ,OAAO;SACR;AACD,QAAA,IAAI,OAAO,CAAC,IAAI,IAAI,IAAI,EAAE;AACxB,YAAA,eAAe,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI;QACrC;QACA,IAAI,OAAO,CAAC,iBAAiB,CAAC,aAAa,IAAI,IAAI,EAAE;YACnD,eAAe,CAAC,aAAa,GAAG,OAAO,CAAC,iBAAiB,CAAC,aAAa;AACvE,YAAA,eAAe,CAAC,OAAO,GAAG,EAAE;QAC9B;AACA,QAAA,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE;YACxD,eAAe,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CACjD,gCAAgC,CACjC;AACD,YAAA,eAAe,CAAC,OAAO,GAAG,yBAAyB,GAAG,OAAO,GAAG,EAAE;AAClE,YAAA,IACE,OAAO,EAAE,uBAAuB,KAAK,IAAI;AACzC,gBAAA,OAAO,CAAC,iBAAiB,CAAC,iBAAiB,IAAI,IAAI,EACnD;AACA,gBAAA,eAAe,CAAC,iBAAiB;AAC/B,oBAAA,OAAO,CAAC,iBAAiB,CAAC,iBAAiB;YAC/C;AACA,YAAA,IACE,OAAO,EAAE,uBAAuB,KAAK,IAAI;AACzC,gBAAA,OAAO,CAAC,iBAAiB,CAAC,iBAAiB,IAAI,IAAI,EACnD;;gBAEA,MAAM,aAAa,GACjB,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,KAAK,IAAI;AAClC,oBAAA,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,KAAK,IAAI;AACvC,gBAAA,IACE,OAAO,CAAC,gCAAgC,KAAK,IAAI;AACjD,oBAAA,aAAa,EACb;AACA,oBAAA,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAC9B,yBAAA,iBAA8C;oBACjD,MAAM,aAAa,GAAG,EAAE;;AAGxB,oBAAA,KAAK,MAAM,MAAM,IAAI,gBAAgB,EAAE;AACrC,wBAAA,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,IAAI,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE;4BAC3D,aAAa,CAAC,IAAI,CAAC;AACjB,gCAAA,IAAI,EAAE,UAAU;gCAChB,QAAQ,EAAE,MAAM,CAAC,IAAI;AACtB,6BAAA,CAAC;wBACJ;AAAO,6BAAA,IACL,MAAM,CAAC,IAAI,KAAK,qBAAqB;AACrC,4BAAA,MAAM,CAAC,IAAI,IAAI,IAAI,EACnB;4BACA,aAAa,CAAC,IAAI,CAAC;AACjB,gCAAA,IAAI,EAAE,mBAAmB;gCACzB,IAAI,EAAE,MAAM,CAAC,IAAI;gCACjB,EAAE,EAAE,MAAM,CAAC,EAAE;AACd,6BAAA,CAAC;wBACJ;oBACF;;AAGA,oBAAA,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE;AAC5B,wBAAA,eAAe,CAAC,OAAO,GAAG,aAAa;oBACzC;gBACF;qBAAO;;AAEL,oBAAA,eAAe,CAAC,iBAAiB;AAC/B,wBAAA,OAAO,CAAC,iBAAiB,CAAC,iBAAiB;gBAC/C;YACF;QACF;aAAO;YACL,IAAI,OAAO,CAAC,iBAAiB,CAAC,UAAU,IAAI,IAAI,EAAE;gBAChD,eAAe,CAAC,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC,UAAU;AACjE,gBAAA,IACE,OAAO,EAAE,uBAAuB,KAAK,IAAI;AACzC,oBAAA,OAAO,CAAC,iBAAiB,CAAC,iBAAiB,IAAI,IAAI,EACnD;AACA,oBAAA,eAAe,CAAC,iBAAiB;AAC/B,wBAAA,OAAO,CAAC,iBAAiB,CAAC,iBAAiB;gBAC/C;AACA,gBAAA,IACE,OAAO,EAAE,uBAAuB,KAAK,IAAI;AACzC,oBAAA,OAAO,CAAC,iBAAiB,CAAC,iBAAiB,IAAI,IAAI,EACnD;;oBAEA,MAAM,aAAa,GACjB,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,KAAK,IAAI;AAClC,wBAAA,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,KAAK,IAAI;AACvC,oBAAA,IACE,OAAO,CAAC,gCAAgC,KAAK,IAAI;AACjD,wBAAA,aAAa,EACb;AACA,wBAAA,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAC9B,6BAAA,iBAA8C;wBACjD,MAAM,aAAa,GAAG,EAAE;;AAGxB,wBAAA,KAAK,MAAM,MAAM,IAAI,gBAAgB,EAAE;AACrC,4BAAA,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,IAAI,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE;gCAC3D,aAAa,CAAC,IAAI,CAAC;AACjB,oCAAA,IAAI,EAAE,UAAU;oCAChB,QAAQ,EAAE,MAAM,CAAC,IAAI;AACtB,iCAAA,CAAC;4BACJ;AAAO,iCAAA,IACL,MAAM,CAAC,IAAI,KAAK,qBAAqB;AACrC,gCAAA,MAAM,CAAC,IAAI,IAAI,IAAI,EACnB;gCACA,aAAa,CAAC,IAAI,CAAC;AACjB,oCAAA,IAAI,EAAE,mBAAmB;oCACzB,IAAI,EAAE,MAAM,CAAC,IAAI;oCACjB,EAAE,EAAE,MAAM,CAAC,EAAE;AACd,iCAAA,CAAC;4BACJ;wBACF;;AAGA,wBAAA,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE;AAC5B,4BAAA,eAAe,CAAC,OAAO,GAAG,aAAa;wBACzC;oBACF;yBAAO;;AAEL,wBAAA,eAAe,CAAC,iBAAiB;AAC/B,4BAAA,OAAO,CAAC,iBAAiB,CAAC,iBAAiB;oBAC/C;gBACF;YACF;AACA,YAAA,IAAK,OAAuB,CAAC,YAAY,IAAI,IAAI,EAAE;AACjD,gBAAA,eAAe,CAAC,YAAY,GAAI,OAAuB,CAAC,YAAY;YACtE;QACF;AAEA,QAAA,IACE,OAAO,CAAC,iBAAiB,CAAC,KAAK;AAC/B,YAAA,OAAO,OAAO,CAAC,iBAAiB,CAAC,KAAK,KAAK,QAAQ;AACnD,YAAA,IAAI,IAAI,OAAO,CAAC,iBAAiB,CAAC,KAAK,EACvC;AACA,YAAA,MAAM,YAAY,GAAG;AACnB,gBAAA,IAAI,EAAE,WAAW;AACjB,gBAAA,KAAK,EAAE;AACL,oBAAA,EAAE,EAAE,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE;AACvC,iBAAA;aACF;AACD,YAAA,OAAO,CAAC,eAAe,EAAE,YAAY,CAA4B;QACnE;AAEA,QAAA,OAAO,eAAwC;AACjD,IAAA,CAAC,CAAC;AACJ;AA4TM,SAAU,gBAAgB,CAAC,KAAc,EAAA;AAC7C,IAAA,OAAO,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,EAAE,IAAI,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC;AAC5E;;;;"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../../../../src/llm/openai/utils/index.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/ban-ts-comment */\n/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport { type OpenAI as OpenAIClient } from 'openai';\nimport type {\n ChatCompletionContentPartText,\n ChatCompletionContentPartImage,\n ChatCompletionContentPartInputAudio,\n ChatCompletionContentPart,\n} from 'openai/resources/chat/completions';\nimport {\n AIMessage,\n AIMessageChunk,\n type BaseMessage,\n ChatMessage,\n ToolMessage,\n isAIMessage,\n type UsageMetadata,\n type BaseMessageFields,\n type MessageContentComplex,\n type InvalidToolCall,\n type MessageContentImageUrl,\n StandardContentBlockConverter,\n parseBase64DataUrl,\n parseMimeType,\n convertToProviderContentBlock,\n isDataContentBlock,\n} from '@langchain/core/messages';\nimport { ChatGenerationChunk } from '@langchain/core/outputs';\nimport {\n convertLangChainToolCallToOpenAI,\n makeInvalidToolCall,\n parseToolCall,\n} from '@langchain/core/output_parsers/openai_tools';\nimport type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';\nimport type {\n OpenAICallOptions,\n OpenAIChatInput,\n ChatOpenAIReasoningSummary,\n} from '@langchain/openai';\nimport { toLangChainContent } from '@/messages/langchain';\n\nexport type { OpenAICallOptions, OpenAIChatInput };\n\n// Utility types to get hidden OpenAI response types\ntype ExtractAsyncIterableType<T> = T extends AsyncIterable<infer U> ? U : never;\ntype ExcludeController<T> = T extends { controller: unknown } ? never : T;\ntype ExcludeNonController<T> = T extends { controller: unknown } ? T : never;\n\ntype ResponsesCreate = OpenAIClient.Responses['create'];\ntype ResponsesParse = OpenAIClient.Responses['parse'];\n\ntype ResponsesInputItem = OpenAIClient.Responses.ResponseInputItem;\n\ntype ResponsesCreateInvoke = ExcludeController<\n Awaited<ReturnType<ResponsesCreate>>\n>;\n\ntype ResponsesParseInvoke = ExcludeController<\n Awaited<ReturnType<ResponsesParse>>\n>;\n\ntype ResponsesCreateStream = ExcludeNonController<\n Awaited<ReturnType<ResponsesCreate>>\n>;\n\nexport type ResponseReturnStreamEvents =\n ExtractAsyncIterableType<ResponsesCreateStream>;\n\n// TODO import from SDK when available\ntype OpenAIRoleEnum =\n | 'system'\n | 'developer'\n | 'assistant'\n | 'user'\n | 'function'\n | 'tool';\n\ntype OpenAICompletionParam =\n OpenAIClient.Chat.Completions.ChatCompletionMessageParam;\n\nfunction extractGenericMessageCustomRole(message: ChatMessage) {\n if (\n message.role !== 'system' &&\n message.role !== 'developer' &&\n message.role !== 'assistant' &&\n message.role !== 'user' &&\n message.role !== 'function' &&\n message.role !== 'tool'\n ) {\n console.warn(`Unknown message role: ${message.role}`);\n }\n\n return message.role as OpenAIRoleEnum;\n}\n\nexport function messageToOpenAIRole(message: BaseMessage): OpenAIRoleEnum {\n const type = message._getType();\n switch (type) {\n case 'system':\n return 'system';\n case 'ai':\n return 'assistant';\n case 'human':\n return 'user';\n case 'function':\n return 'function';\n case 'tool':\n return 'tool';\n case 'generic': {\n if (!ChatMessage.isInstance(message))\n throw new Error('Invalid generic chat message');\n return extractGenericMessageCustomRole(message);\n }\n default:\n throw new Error(`Unknown message type: ${type}`);\n }\n}\n\nconst completionsApiContentBlockConverter: StandardContentBlockConverter<{\n text: ChatCompletionContentPartText;\n image: ChatCompletionContentPartImage;\n audio: ChatCompletionContentPartInputAudio;\n file: ChatCompletionContentPart.File;\n}> = {\n providerName: 'ChatOpenAI',\n\n fromStandardTextBlock(block): ChatCompletionContentPartText {\n return { type: 'text', text: block.text };\n },\n\n fromStandardImageBlock(block): ChatCompletionContentPartImage {\n if (block.source_type === 'url') {\n return {\n type: 'image_url',\n image_url: {\n url: block.url,\n ...(block.metadata?.detail\n ? { detail: block.metadata.detail as 'auto' | 'low' | 'high' }\n : {}),\n },\n };\n }\n\n if (block.source_type === 'base64') {\n const url = `data:${block.mime_type ?? ''};base64,${block.data}`;\n return {\n type: 'image_url',\n image_url: {\n url,\n ...(block.metadata?.detail\n ? { detail: block.metadata.detail as 'auto' | 'low' | 'high' }\n : {}),\n },\n };\n }\n\n throw new Error(\n `Image content blocks with source_type ${block.source_type} are not supported for ChatOpenAI`\n );\n },\n\n fromStandardAudioBlock(block): ChatCompletionContentPartInputAudio {\n if (block.source_type === 'url') {\n const data = parseBase64DataUrl({ dataUrl: block.url });\n if (!data) {\n throw new Error(\n `URL audio blocks with source_type ${block.source_type} must be formatted as a data URL for ChatOpenAI`\n );\n }\n\n const rawMimeType = data.mime_type || block.mime_type || '';\n let mimeType: { type: string; subtype: string };\n\n try {\n mimeType = parseMimeType(rawMimeType);\n } catch {\n throw new Error(\n `Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`\n );\n }\n\n if (\n mimeType.type !== 'audio' ||\n (mimeType.subtype !== 'wav' && mimeType.subtype !== 'mp3')\n ) {\n throw new Error(\n `Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`\n );\n }\n\n return {\n type: 'input_audio',\n input_audio: {\n format: mimeType.subtype,\n data: data.data,\n },\n };\n }\n\n if (block.source_type === 'base64') {\n let mimeType: { type: string; subtype: string };\n\n try {\n mimeType = parseMimeType(block.mime_type ?? '');\n } catch {\n throw new Error(\n `Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`\n );\n }\n\n if (\n mimeType.type !== 'audio' ||\n (mimeType.subtype !== 'wav' && mimeType.subtype !== 'mp3')\n ) {\n throw new Error(\n `Audio blocks with source_type ${block.source_type} must have mime type of audio/wav or audio/mp3`\n );\n }\n\n return {\n type: 'input_audio',\n input_audio: {\n format: mimeType.subtype,\n data: block.data,\n },\n };\n }\n\n throw new Error(\n `Audio content blocks with source_type ${block.source_type} are not supported for ChatOpenAI`\n );\n },\n\n fromStandardFileBlock(block): ChatCompletionContentPart.File {\n if (block.source_type === 'url') {\n const data = parseBase64DataUrl({ dataUrl: block.url });\n if (!data) {\n throw new Error(\n `URL file blocks with source_type ${block.source_type} must be formatted as a data URL for ChatOpenAI`\n );\n }\n\n return {\n type: 'file',\n file: {\n file_data: block.url, // formatted as base64 data URL\n ...(block.metadata?.filename || block.metadata?.name\n ? {\n filename: (block.metadata.filename ||\n block.metadata.name) as string,\n }\n : {}),\n },\n };\n }\n\n if (block.source_type === 'base64') {\n return {\n type: 'file',\n file: {\n file_data: `data:${block.mime_type ?? ''};base64,${block.data}`,\n ...(block.metadata?.filename ||\n block.metadata?.name ||\n block.metadata?.title\n ? {\n filename: (block.metadata.filename ||\n block.metadata.name ||\n block.metadata.title) as string,\n }\n : {}),\n },\n };\n }\n\n if (block.source_type === 'id') {\n return {\n type: 'file',\n file: {\n file_id: block.id,\n },\n };\n }\n\n throw new Error(\n `File content blocks with source_type ${block.source_type} are not supported for ChatOpenAI`\n );\n },\n};\n\n/** Options for converting messages to OpenAI params */\nexport interface ConvertMessagesOptions {\n /** Include reasoning_content field for DeepSeek thinking mode with tool calls */\n includeReasoningContent?: boolean;\n /** Include reasoning_details field for OpenRouter/Gemini thinking mode with tool calls */\n includeReasoningDetails?: boolean;\n /** Convert reasoning_details to content blocks for Claude (requires content array format) */\n convertReasoningDetailsToContent?: boolean;\n}\n\n// Used in LangSmith, export is important here\nexport function _convertMessagesToOpenAIParams(\n messages: BaseMessage[],\n model?: string,\n options?: ConvertMessagesOptions\n): OpenAICompletionParam[] {\n let hasReasoningToolCallContext = false;\n // TODO: Function messages do not support array content, fix cast\n return messages.flatMap((message) => {\n let role = messageToOpenAIRole(message);\n if (role === 'system' && isReasoningModel(model)) {\n role = 'developer';\n }\n\n let hasAnthropicThinkingBlock: boolean = false;\n\n const content =\n typeof message.content === 'string'\n ? message.content\n : message.content.map((m) => {\n if ('type' in m && m.type === 'thinking') {\n hasAnthropicThinkingBlock = true;\n return m;\n }\n if (isDataContentBlock(m)) {\n return convertToProviderContentBlock(\n m,\n completionsApiContentBlockConverter\n );\n }\n return m;\n });\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const completionParam: Record<string, any> = {\n role,\n content,\n };\n let messageHasToolCalls = false;\n let messageIsToolResult = false;\n if (message.name != null) {\n completionParam.name = message.name;\n }\n if (message.additional_kwargs.function_call != null) {\n completionParam.function_call = message.additional_kwargs.function_call;\n completionParam.content = '';\n }\n if (isAIMessage(message) && !!message.tool_calls?.length) {\n messageHasToolCalls = true;\n completionParam.tool_calls = message.tool_calls.map(\n convertLangChainToolCallToOpenAI\n );\n completionParam.content = hasAnthropicThinkingBlock ? content : '';\n if (\n options?.includeReasoningDetails === true &&\n message.additional_kwargs.reasoning_details != null\n ) {\n // For Claude via OpenRouter, convert reasoning_details to content blocks\n const isClaudeModel =\n model?.includes('claude') === true ||\n model?.includes('anthropic') === true;\n if (\n options.convertReasoningDetailsToContent === true &&\n isClaudeModel\n ) {\n const reasoningDetails = message.additional_kwargs\n .reasoning_details as Record<string, unknown>[];\n const contentBlocks = [];\n\n // Add thinking blocks from reasoning_details\n for (const detail of reasoningDetails) {\n if (detail.type === 'reasoning.text' && detail.text != null) {\n contentBlocks.push({\n type: 'thinking',\n thinking: detail.text,\n });\n } else if (\n detail.type === 'reasoning.encrypted' &&\n detail.data != null\n ) {\n contentBlocks.push({\n type: 'redacted_thinking',\n data: detail.data,\n id: detail.id,\n });\n }\n }\n\n // Set content to array with thinking blocks\n if (contentBlocks.length > 0) {\n completionParam.content = contentBlocks;\n }\n } else {\n // For non-Claude models, pass as separate field\n completionParam.reasoning_details =\n message.additional_kwargs.reasoning_details;\n }\n }\n } else {\n if (message.additional_kwargs.tool_calls != null) {\n messageHasToolCalls =\n !Array.isArray(message.additional_kwargs.tool_calls) ||\n message.additional_kwargs.tool_calls.length > 0;\n completionParam.tool_calls = message.additional_kwargs.tool_calls;\n if (\n options?.includeReasoningDetails === true &&\n message.additional_kwargs.reasoning_details != null\n ) {\n // For Claude via OpenRouter, convert reasoning_details to content blocks\n const isClaudeModel =\n model?.includes('claude') === true ||\n model?.includes('anthropic') === true;\n if (\n options.convertReasoningDetailsToContent === true &&\n isClaudeModel\n ) {\n const reasoningDetails = message.additional_kwargs\n .reasoning_details as Record<string, unknown>[];\n const contentBlocks = [];\n\n // Add thinking blocks from reasoning_details\n for (const detail of reasoningDetails) {\n if (detail.type === 'reasoning.text' && detail.text != null) {\n contentBlocks.push({\n type: 'thinking',\n thinking: detail.text,\n });\n } else if (\n detail.type === 'reasoning.encrypted' &&\n detail.data != null\n ) {\n contentBlocks.push({\n type: 'redacted_thinking',\n data: detail.data,\n id: detail.id,\n });\n }\n }\n\n // Set content to array with thinking blocks\n if (contentBlocks.length > 0) {\n completionParam.content = contentBlocks;\n }\n } else {\n // For non-Claude models, pass as separate field\n completionParam.reasoning_details =\n message.additional_kwargs.reasoning_details;\n }\n }\n }\n if ((message as ToolMessage).tool_call_id != null) {\n messageIsToolResult = true;\n completionParam.tool_call_id = (message as ToolMessage).tool_call_id;\n }\n }\n\n if (\n options?.includeReasoningContent === true &&\n isAIMessage(message) &&\n (hasReasoningToolCallContext || messageHasToolCalls) &&\n typeof message.additional_kwargs.reasoning_content === 'string' &&\n message.additional_kwargs.reasoning_content !== ''\n ) {\n completionParam.reasoning_content =\n message.additional_kwargs.reasoning_content;\n }\n\n if (messageHasToolCalls || messageIsToolResult) {\n hasReasoningToolCallContext = true;\n }\n\n if (\n message.additional_kwargs.audio &&\n typeof message.additional_kwargs.audio === 'object' &&\n 'id' in message.additional_kwargs.audio\n ) {\n const audioMessage = {\n role: 'assistant',\n audio: {\n id: message.additional_kwargs.audio.id,\n },\n };\n return [completionParam, audioMessage] as OpenAICompletionParam[];\n }\n\n return completionParam as OpenAICompletionParam;\n });\n}\n\nconst _FUNCTION_CALL_IDS_MAP_KEY = '__openai_function_call_ids__';\n\nfunction _convertReasoningSummaryToOpenAIResponsesParams(\n reasoning: ChatOpenAIReasoningSummary\n): OpenAIClient.Responses.ResponseReasoningItem {\n // combine summary parts that have the the same index and then remove the indexes\n const summary = (\n reasoning.summary.length > 1\n ? reasoning.summary.reduce(\n (acc, curr) => {\n const last = acc.at(-1);\n\n if (last!.index === curr.index) {\n last!.text += curr.text;\n } else {\n acc.push(curr);\n }\n return acc;\n },\n [{ ...reasoning.summary[0] }]\n )\n : reasoning.summary\n ).map((s) =>\n Object.fromEntries(Object.entries(s).filter(([k]) => k !== 'index'))\n ) as OpenAIClient.Responses.ResponseReasoningItem.Summary[];\n\n return {\n ...reasoning,\n summary,\n } as OpenAIClient.Responses.ResponseReasoningItem;\n}\n\nexport function _convertMessagesToOpenAIResponsesParams(\n messages: BaseMessage[],\n model?: string,\n zdrEnabled?: boolean\n): ResponsesInputItem[] {\n return messages.flatMap(\n (lcMsg): ResponsesInputItem | ResponsesInputItem[] => {\n const additional_kwargs =\n lcMsg.additional_kwargs as BaseMessageFields['additional_kwargs'] & {\n [_FUNCTION_CALL_IDS_MAP_KEY]?: Record<string, string>;\n reasoning?: OpenAIClient.Responses.ResponseReasoningItem;\n type?: string;\n refusal?: string;\n };\n const responseMetadata = lcMsg.response_metadata as {\n output?: ResponsesInputItem[];\n };\n\n let role = messageToOpenAIRole(lcMsg);\n if (role === 'system' && isReasoningModel(model)) role = 'developer';\n\n if (role === 'function') {\n throw new Error('Function messages are not supported in Responses API');\n }\n\n if (role === 'tool') {\n const toolMessage = lcMsg as ToolMessage;\n\n // Handle computer call output\n if (additional_kwargs.type === 'computer_call_output') {\n const output = (() => {\n if (typeof toolMessage.content === 'string') {\n return {\n type: 'computer_screenshot' as const,\n image_url: toolMessage.content,\n };\n }\n\n if (Array.isArray(toolMessage.content)) {\n const oaiScreenshot = toolMessage.content.find(\n (i) => i.type === 'computer_screenshot'\n ) as { type: 'computer_screenshot'; image_url: string };\n\n if (oaiScreenshot) return oaiScreenshot;\n\n const lcImage = toolMessage.content.find(\n (i) => i.type === 'image_url'\n ) as MessageContentImageUrl;\n\n if (lcImage) {\n return {\n type: 'computer_screenshot' as const,\n image_url:\n typeof lcImage.image_url === 'string'\n ? lcImage.image_url\n : lcImage.image_url.url,\n };\n }\n }\n\n throw new Error('Invalid computer call output');\n })();\n\n return {\n type: 'computer_call_output',\n output,\n call_id: toolMessage.tool_call_id,\n };\n }\n\n return {\n type: 'function_call_output',\n call_id: toolMessage.tool_call_id,\n id: toolMessage.id?.startsWith('fc_') ? toolMessage.id : undefined,\n output:\n typeof toolMessage.content !== 'string'\n ? JSON.stringify(toolMessage.content)\n : toolMessage.content,\n };\n }\n\n if (role === 'assistant') {\n // if we have the original response items, just reuse them\n if (\n !zdrEnabled &&\n responseMetadata.output != null &&\n Array.isArray(responseMetadata.output) &&\n responseMetadata.output.length > 0 &&\n responseMetadata.output.every((item) => 'type' in item)\n ) {\n return responseMetadata.output;\n }\n\n // otherwise, try to reconstruct the response from what we have\n\n const input: ResponsesInputItem[] = [];\n\n // reasoning items\n if (additional_kwargs.reasoning && !zdrEnabled) {\n const reasoningItem = _convertReasoningSummaryToOpenAIResponsesParams(\n additional_kwargs.reasoning\n );\n input.push(reasoningItem);\n }\n\n // ai content\n let content = lcMsg.content as\n | string\n | Array<\n | MessageContentComplex\n | OpenAIClient.Responses.ResponseOutputText\n | OpenAIClient.Responses.ResponseOutputRefusal\n >;\n if (additional_kwargs.refusal) {\n if (typeof content === 'string') {\n content = [{ type: 'output_text', text: content, annotations: [] }];\n }\n content = [\n ...content,\n { type: 'refusal', refusal: additional_kwargs.refusal },\n ];\n }\n\n input.push({\n type: 'message',\n role: 'assistant',\n ...(lcMsg.id && !zdrEnabled && lcMsg.id.startsWith('msg_')\n ? { id: lcMsg.id }\n : {}),\n content:\n typeof content === 'string'\n ? content\n : content.flatMap((item) => {\n if (item.type === 'text') {\n const textItem = item as MessageContentComplex & {\n annotations?: unknown[];\n };\n return {\n type: 'output_text',\n text: item.text,\n annotations: textItem.annotations ?? [],\n };\n }\n\n if (item.type === 'output_text' || item.type === 'refusal') {\n return item;\n }\n\n return [];\n }),\n } as ResponsesInputItem);\n\n const functionCallIds = additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY];\n\n if (isAIMessage(lcMsg) && !!lcMsg.tool_calls?.length) {\n input.push(\n ...lcMsg.tool_calls.map(\n (toolCall): ResponsesInputItem => ({\n type: 'function_call',\n name: toolCall.name,\n arguments: JSON.stringify(toolCall.args),\n call_id: toolCall.id!,\n ...(zdrEnabled ? { id: functionCallIds?.[toolCall.id!] } : {}),\n })\n )\n );\n } else if (additional_kwargs.tool_calls) {\n input.push(\n ...additional_kwargs.tool_calls.map(\n (toolCall): ResponsesInputItem => ({\n type: 'function_call',\n name: toolCall.function.name,\n call_id: toolCall.id,\n arguments: toolCall.function.arguments,\n ...(zdrEnabled ? { id: functionCallIds?.[toolCall.id] } : {}),\n })\n )\n );\n }\n\n const toolOutputs =\n ((responseMetadata.output as Array<ResponsesInputItem> | undefined)\n ?.length ?? 0) > 0\n ? responseMetadata.output\n : additional_kwargs.tool_outputs;\n\n const fallthroughCallTypes: ResponsesInputItem['type'][] = [\n 'computer_call',\n /** @ts-ignore */\n 'mcp_call',\n /** @ts-ignore */\n 'code_interpreter_call',\n /** @ts-ignore */\n 'image_generation_call',\n ];\n\n if (toolOutputs != null) {\n const castToolOutputs = toolOutputs as Array<ResponsesInputItem>;\n const fallthroughCalls = castToolOutputs.filter((item) =>\n fallthroughCallTypes.includes(item.type)\n );\n if (fallthroughCalls.length > 0) input.push(...fallthroughCalls);\n }\n\n return input;\n }\n\n if (role === 'user' || role === 'system' || role === 'developer') {\n if (typeof lcMsg.content === 'string') {\n return { type: 'message', role, content: lcMsg.content };\n }\n\n const messages: ResponsesInputItem[] = [];\n const content = (lcMsg.content as MessageContentComplex[]).flatMap(\n (item) => {\n if (item.type === 'mcp_approval_response') {\n const approvalResponse = item as MessageContentComplex & {\n approval_request_id: string;\n approve: boolean;\n };\n messages.push({\n // @ts-ignore\n type: 'mcp_approval_response',\n approval_request_id: approvalResponse.approval_request_id,\n approve: approvalResponse.approve,\n });\n }\n if (isDataContentBlock(item)) {\n return convertToProviderContentBlock(\n item,\n completionsApiContentBlockConverter\n );\n }\n if (item.type === 'text') {\n return {\n type: 'input_text',\n text: item.text,\n };\n }\n if (item.type === 'image_url') {\n const imageItem = item as MessageContentImageUrl;\n return {\n type: 'input_image',\n image_url:\n typeof imageItem.image_url === 'string'\n ? imageItem.image_url\n : imageItem.image_url.url,\n detail:\n typeof imageItem.image_url === 'string'\n ? 'auto'\n : imageItem.image_url.detail,\n };\n }\n if (\n item.type === 'input_text' ||\n item.type === 'input_image' ||\n item.type === 'input_file'\n ) {\n return item;\n }\n return [];\n }\n );\n\n if (content.length > 0) {\n messages.push({\n type: 'message',\n role,\n content,\n } as ResponsesInputItem);\n }\n return messages;\n }\n\n console.warn(\n `Unsupported role found when converting to OpenAI Responses API: ${role}`\n );\n return [];\n }\n );\n}\n\nexport function isReasoningModel(model?: string) {\n return model != null && model !== '' && /\\b(o\\d|gpt-[5-9])\\b/i.test(model);\n}\n\nfunction _convertOpenAIResponsesMessageToBaseMessage(\n response: ResponsesCreateInvoke | ResponsesParseInvoke\n): BaseMessage {\n if (response.error) {\n // TODO: add support for `addLangChainErrorFields`\n const error = new Error(response.error.message);\n error.name = response.error.code;\n throw error;\n }\n\n let messageId: string | undefined;\n const content: MessageContentComplex[] = [];\n const tool_calls: ToolCall[] = [];\n const invalid_tool_calls: InvalidToolCall[] = [];\n const response_metadata: Record<string, unknown> = {\n model: response.model,\n created_at: response.created_at,\n id: response.id,\n incomplete_details: response.incomplete_details,\n metadata: response.metadata,\n object: response.object,\n status: response.status,\n user: response.user,\n service_tier: response.service_tier,\n\n // for compatibility with chat completion calls.\n model_name: response.model,\n };\n\n const additional_kwargs: {\n [key: string]: unknown;\n refusal?: string;\n reasoning?: OpenAIClient.Responses.ResponseReasoningItem;\n tool_outputs?: unknown[];\n parsed?: unknown;\n [_FUNCTION_CALL_IDS_MAP_KEY]?: Record<string, string>;\n } = {};\n\n for (const item of response.output) {\n if (item.type === 'message') {\n messageId = item.id;\n content.push(\n ...item.content.flatMap((part) => {\n if (part.type === 'output_text') {\n if ('parsed' in part && part.parsed != null) {\n additional_kwargs.parsed = part.parsed;\n }\n return {\n type: 'text',\n text: part.text,\n annotations: part.annotations,\n };\n }\n\n if (part.type === 'refusal') {\n additional_kwargs.refusal = part.refusal;\n return [];\n }\n\n return part;\n })\n );\n } else if (item.type === 'function_call') {\n const fnAdapter = {\n function: { name: item.name, arguments: item.arguments },\n id: item.call_id,\n };\n\n try {\n tool_calls.push(parseToolCall(fnAdapter, { returnId: true }));\n } catch (e: unknown) {\n let errMessage: string | undefined;\n if (\n typeof e === 'object' &&\n e != null &&\n 'message' in e &&\n typeof e.message === 'string'\n ) {\n errMessage = e.message;\n }\n invalid_tool_calls.push(makeInvalidToolCall(fnAdapter, errMessage));\n }\n\n additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY] ??= {};\n if (item.id) {\n additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY][item.call_id] = item.id;\n }\n } else if (item.type === 'reasoning') {\n additional_kwargs.reasoning = item;\n } else {\n additional_kwargs.tool_outputs ??= [];\n additional_kwargs.tool_outputs.push(item);\n }\n }\n\n return new AIMessage({\n id: messageId,\n content: toLangChainContent(content),\n tool_calls,\n invalid_tool_calls,\n usage_metadata: response.usage,\n additional_kwargs,\n response_metadata,\n });\n}\n\nexport function _convertOpenAIResponsesDeltaToBaseMessageChunk(\n chunk: ResponseReturnStreamEvents\n) {\n const content: MessageContentComplex[] = [];\n let generationInfo: Record<string, unknown> = {};\n let usage_metadata: UsageMetadata | undefined;\n const tool_call_chunks: ToolCallChunk[] = [];\n const response_metadata: Record<string, unknown> = {};\n const additional_kwargs: {\n [key: string]: unknown;\n reasoning?: Partial<ChatOpenAIReasoningSummary>;\n tool_outputs?: unknown[];\n } = {};\n let id: string | undefined;\n if (chunk.type === 'response.output_text.delta') {\n content.push({\n type: 'text',\n text: chunk.delta,\n index: chunk.content_index,\n });\n /** @ts-ignore */\n } else if (chunk.type === 'response.output_text_annotation.added') {\n content.push({\n type: 'text',\n text: '',\n /** @ts-ignore */\n annotations: [chunk.annotation],\n /** @ts-ignore */\n index: chunk.content_index,\n });\n } else if (\n chunk.type === 'response.output_item.added' &&\n chunk.item.type === 'message'\n ) {\n id = chunk.item.id;\n } else if (\n chunk.type === 'response.output_item.added' &&\n chunk.item.type === 'function_call'\n ) {\n tool_call_chunks.push({\n type: 'tool_call_chunk',\n name: chunk.item.name,\n args: chunk.item.arguments,\n id: chunk.item.call_id,\n index: chunk.output_index,\n });\n\n additional_kwargs[_FUNCTION_CALL_IDS_MAP_KEY] = {\n [chunk.item.call_id]: chunk.item.id,\n };\n } else if (\n chunk.type === 'response.output_item.done' &&\n [\n 'web_search_call',\n 'file_search_call',\n 'computer_call',\n 'code_interpreter_call',\n 'mcp_call',\n 'mcp_list_tools',\n 'mcp_approval_request',\n 'image_generation_call',\n ].includes(chunk.item.type)\n ) {\n additional_kwargs.tool_outputs = [chunk.item];\n } else if (chunk.type === 'response.created') {\n response_metadata.id = chunk.response.id;\n response_metadata.model_name = chunk.response.model;\n response_metadata.model = chunk.response.model;\n } else if (chunk.type === 'response.completed') {\n const msg = _convertOpenAIResponsesMessageToBaseMessage(chunk.response);\n\n usage_metadata = chunk.response.usage;\n if (chunk.response.text?.format?.type === 'json_schema') {\n additional_kwargs.parsed ??= JSON.parse(msg.text);\n }\n for (const [key, value] of Object.entries(chunk.response)) {\n if (key !== 'id') response_metadata[key] = value;\n }\n } else if (chunk.type === 'response.function_call_arguments.delta') {\n tool_call_chunks.push({\n type: 'tool_call_chunk',\n args: chunk.delta,\n index: chunk.output_index,\n });\n } else if (\n chunk.type === 'response.web_search_call.completed' ||\n chunk.type === 'response.file_search_call.completed'\n ) {\n generationInfo = {\n tool_outputs: {\n id: chunk.item_id,\n type: chunk.type.replace('response.', '').replace('.completed', ''),\n status: 'completed',\n },\n };\n } else if (chunk.type === 'response.refusal.done') {\n additional_kwargs.refusal = chunk.refusal;\n } else if (\n chunk.type === 'response.output_item.added' &&\n 'item' in chunk &&\n chunk.item.type === 'reasoning'\n ) {\n const summary: ChatOpenAIReasoningSummary['summary'] | undefined = chunk\n .item.summary\n ? chunk.item.summary.map((s, index) => ({\n ...s,\n index,\n }))\n : undefined;\n\n additional_kwargs.reasoning = {\n // We only capture ID in the first chunk or else the concatenated result of all chunks will\n // have an ID field that is repeated once per chunk. There is special handling for the `type`\n // field that prevents this, however.\n id: chunk.item.id,\n type: chunk.item.type,\n ...(summary ? { summary } : {}),\n };\n } else if (chunk.type === 'response.reasoning_summary_part.added') {\n additional_kwargs.reasoning = {\n type: 'reasoning',\n summary: [{ ...chunk.part, index: chunk.summary_index }],\n };\n } else if (chunk.type === 'response.reasoning_summary_text.delta') {\n additional_kwargs.reasoning = {\n type: 'reasoning',\n summary: [\n { text: chunk.delta, type: 'summary_text', index: chunk.summary_index },\n ],\n };\n /** @ts-ignore */\n } else if (chunk.type === 'response.image_generation_call.partial_image') {\n // noop/fixme: retaining partial images in a message chunk means that _all_\n // partial images get kept in history, so we don't do anything here.\n return null;\n } else {\n return null;\n }\n\n return new ChatGenerationChunk({\n // Legacy reasons, `onLLMNewToken` should pulls this out\n text: content.map((part) => ('text' in part ? part.text : '')).join(''),\n message: new AIMessageChunk({\n id,\n content: toLangChainContent(content),\n tool_call_chunks,\n usage_metadata,\n additional_kwargs,\n response_metadata,\n }),\n generationInfo,\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -149,16 +149,68 @@ const formatFromLangChain = (message) => {
|
|
|
149
149
|
...additional_kwargs,
|
|
150
150
|
};
|
|
151
151
|
};
|
|
152
|
+
function extractReasoningContent(part) {
|
|
153
|
+
if (part == null || typeof part !== 'object') {
|
|
154
|
+
return '';
|
|
155
|
+
}
|
|
156
|
+
if (part.type === ContentTypes.THINK) {
|
|
157
|
+
const think = part.think;
|
|
158
|
+
return typeof think === 'string' ? think : '';
|
|
159
|
+
}
|
|
160
|
+
if (part.type === ContentTypes.THINKING) {
|
|
161
|
+
const thinking = part.thinking;
|
|
162
|
+
return typeof thinking === 'string' ? thinking : '';
|
|
163
|
+
}
|
|
164
|
+
if (part.type === ContentTypes.REASONING) {
|
|
165
|
+
const reasoning = part.reasoning;
|
|
166
|
+
return typeof reasoning === 'string' ? reasoning : '';
|
|
167
|
+
}
|
|
168
|
+
if (part.type === ContentTypes.REASONING_CONTENT) {
|
|
169
|
+
const reasoningText = part.reasoningText;
|
|
170
|
+
return typeof reasoningText.text === 'string' ? reasoningText.text : '';
|
|
171
|
+
}
|
|
172
|
+
return '';
|
|
173
|
+
}
|
|
152
174
|
/**
|
|
153
175
|
* Helper function to format an assistant message
|
|
154
176
|
* @param message The message to format
|
|
177
|
+
* @param options Optional formatting options
|
|
155
178
|
* @returns Array of formatted messages
|
|
156
179
|
*/
|
|
157
|
-
function formatAssistantMessage(message) {
|
|
180
|
+
function formatAssistantMessage(message, options) {
|
|
158
181
|
const formattedMessages = [];
|
|
159
182
|
let currentContent = [];
|
|
160
183
|
let lastAIMessage = null;
|
|
161
184
|
let hasReasoning = false;
|
|
185
|
+
let pendingReasoningContent = '';
|
|
186
|
+
const shouldPreserveReasoningContent = options?.preserveReasoningContent === true;
|
|
187
|
+
const takePendingReasoningContent = () => {
|
|
188
|
+
if (!shouldPreserveReasoningContent || !pendingReasoningContent) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
const reasoningContent = pendingReasoningContent;
|
|
192
|
+
pendingReasoningContent = '';
|
|
193
|
+
return reasoningContent;
|
|
194
|
+
};
|
|
195
|
+
const createAIMessage = (content) => {
|
|
196
|
+
const reasoningContent = takePendingReasoningContent();
|
|
197
|
+
return new AIMessage({
|
|
198
|
+
content,
|
|
199
|
+
...(reasoningContent != null && {
|
|
200
|
+
additional_kwargs: { reasoning_content: reasoningContent },
|
|
201
|
+
}),
|
|
202
|
+
});
|
|
203
|
+
};
|
|
204
|
+
const attachPendingReasoningContent = (aiMessage) => {
|
|
205
|
+
const reasoningContent = takePendingReasoningContent();
|
|
206
|
+
if (reasoningContent == null) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
aiMessage.additional_kwargs.reasoning_content =
|
|
210
|
+
typeof aiMessage.additional_kwargs.reasoning_content === 'string'
|
|
211
|
+
? `${aiMessage.additional_kwargs.reasoning_content}${reasoningContent}`
|
|
212
|
+
: reasoningContent;
|
|
213
|
+
};
|
|
162
214
|
if (Array.isArray(message.content)) {
|
|
163
215
|
for (const part of message.content) {
|
|
164
216
|
if (part == null) {
|
|
@@ -178,15 +230,13 @@ function formatAssistantMessage(message) {
|
|
|
178
230
|
}, '');
|
|
179
231
|
content =
|
|
180
232
|
`${content}\n${part[ContentTypes.TEXT] ?? part.text ?? ''}`.trim();
|
|
181
|
-
lastAIMessage =
|
|
233
|
+
lastAIMessage = createAIMessage(content);
|
|
182
234
|
formattedMessages.push(lastAIMessage);
|
|
183
235
|
currentContent = [];
|
|
184
236
|
continue;
|
|
185
237
|
}
|
|
186
238
|
// Create a new AIMessage with this text and prepare for tool calls
|
|
187
|
-
lastAIMessage =
|
|
188
|
-
content: part.text != null ? part.text : '',
|
|
189
|
-
});
|
|
239
|
+
lastAIMessage = createAIMessage(part.text != null ? part.text : '');
|
|
190
240
|
formattedMessages.push(lastAIMessage);
|
|
191
241
|
}
|
|
192
242
|
else if (part.type === ContentTypes.TOOL_CALL) {
|
|
@@ -203,9 +253,12 @@ function formatAssistantMessage(message) {
|
|
|
203
253
|
}
|
|
204
254
|
if (!lastAIMessage) {
|
|
205
255
|
// "Heal" the payload by creating an AIMessage to precede the tool call
|
|
206
|
-
lastAIMessage =
|
|
256
|
+
lastAIMessage = createAIMessage('');
|
|
207
257
|
formattedMessages.push(lastAIMessage);
|
|
208
258
|
}
|
|
259
|
+
else {
|
|
260
|
+
attachPendingReasoningContent(lastAIMessage);
|
|
261
|
+
}
|
|
209
262
|
const tool_call = _tool_call;
|
|
210
263
|
// TODO: investigate; args as dictionary may need to be providers-or-tool-specific
|
|
211
264
|
let args = _args;
|
|
@@ -232,9 +285,11 @@ function formatAssistantMessage(message) {
|
|
|
232
285
|
}
|
|
233
286
|
else if (part.type === ContentTypes.THINK ||
|
|
234
287
|
part.type === ContentTypes.THINKING ||
|
|
288
|
+
part.type === ContentTypes.REASONING ||
|
|
235
289
|
part.type === ContentTypes.REASONING_CONTENT ||
|
|
236
290
|
part.type === 'redacted_thinking') {
|
|
237
291
|
hasReasoning = true;
|
|
292
|
+
pendingReasoningContent += extractReasoningContent(part);
|
|
238
293
|
continue;
|
|
239
294
|
}
|
|
240
295
|
else if (part.type === ContentTypes.ERROR ||
|
|
@@ -261,11 +316,11 @@ function formatAssistantMessage(message) {
|
|
|
261
316
|
}, '')
|
|
262
317
|
.trim();
|
|
263
318
|
if (content) {
|
|
264
|
-
formattedMessages.push(
|
|
319
|
+
formattedMessages.push(createAIMessage(content));
|
|
265
320
|
}
|
|
266
321
|
}
|
|
267
322
|
else if (currentContent.length > 0) {
|
|
268
|
-
formattedMessages.push(
|
|
323
|
+
formattedMessages.push(createAIMessage(toLangChainContent(currentContent)));
|
|
269
324
|
}
|
|
270
325
|
return formattedMessages;
|
|
271
326
|
}
|
|
@@ -584,7 +639,7 @@ const formatAgentMessages = (payload, indexTokenCountMap, tools,
|
|
|
584
639
|
/** Pre-resolved skill bodies keyed by skill name. When present, HumanMessages
|
|
585
640
|
* are reconstructed after skill ToolMessages to restore skill instructions
|
|
586
641
|
* that were only in LangGraph state during the original run. */
|
|
587
|
-
skills) => {
|
|
642
|
+
skills, options) => {
|
|
588
643
|
const messages = [];
|
|
589
644
|
// If indexTokenCountMap is provided, create a new map to track the updated indices
|
|
590
645
|
const updatedIndexTokenCountMap = {};
|
|
@@ -767,7 +822,9 @@ skills) => {
|
|
|
767
822
|
}
|
|
768
823
|
}
|
|
769
824
|
}
|
|
770
|
-
const formattedMessages = formatAssistantMessage(processedMessage
|
|
825
|
+
const formattedMessages = formatAssistantMessage(processedMessage, {
|
|
826
|
+
preserveReasoningContent: options?.provider === Providers.DEEPSEEK,
|
|
827
|
+
});
|
|
771
828
|
if (sourceMessageId != null && sourceMessageId !== '') {
|
|
772
829
|
for (const formattedMessage of formattedMessages) {
|
|
773
830
|
formattedMessage.id = sourceMessageId;
|