UNPKG

@langchain/core

Version:
1 lines 22.8 kB
{"version":3,"file":"openai.cjs","names":["isOpenAIDataBlock","convertToV1FromOpenAIDataBlock","_isObject","_isArray","_isString","_isContentBlock","iife"],"sources":["../../../src/messages/block_translators/openai.ts"],"sourcesContent":["import type { ContentBlock } from \"../content/index.js\";\nimport type { AIMessageChunk, AIMessage } from \"../ai.js\";\nimport type { StandardContentBlockTranslator } from \"./index.js\";\nimport { convertToV1FromOpenAIDataBlock, isOpenAIDataBlock } from \"./data.js\";\nimport {\n _isArray,\n _isContentBlock,\n _isObject,\n _isString,\n iife,\n} from \"./utils.js\";\n\n/**\n * Converts a ChatOpenAICompletions message to an array of v1 standard content blocks.\n *\n * This function processes an AI message from ChatOpenAICompletions API format\n * and converts it to the standardized v1 content block format. It handles both\n * string content and structured content blocks, as well as tool calls.\n *\n * @param message - The AI message containing ChatOpenAICompletions formatted content\n * @returns Array of content blocks in v1 standard format\n *\n * @example\n * ```typescript\n * const message = new AIMessage(\"Hello world\");\n * const standardBlocks = convertToV1FromChatCompletions(message);\n * // Returns: [{ type: \"text\", text: \"Hello world\" }]\n * ```\n *\n * @example\n * ```typescript\n * const message = new AIMessage([\n * { type: \"text\", text: \"Hello\" },\n * { type: \"image_url\", image_url: { url: \"https://example.com/image.png\" } }\n * ]);\n * message.tool_calls = [\n * { id: \"call_123\", name: \"calculator\", args: { a: 1, b: 2 } }\n * ];\n *\n * const standardBlocks = convertToV1FromChatCompletions(message);\n * // Returns:\n * // [\n * // { type: \"text\", text: \"Hello\" },\n * // { type: \"image\", url: \"https://example.com/image.png\" },\n * // { type: \"tool_call\", id: \"call_123\", name: \"calculator\", args: { a: 1, b: 2 } }\n * // ]\n * ```\n */\nexport function convertToV1FromChatCompletions(\n message: AIMessage\n): Array<ContentBlock.Standard> {\n const blocks: Array<ContentBlock.Standard> = [];\n if (typeof message.content === \"string\") {\n // Only add text block if content is non-empty\n if (message.content.length > 0) {\n blocks.push({\n type: \"text\",\n text: message.content,\n });\n }\n } else {\n blocks.push(...convertToV1FromChatCompletionsInput(message.content));\n }\n for (const toolCall of message.tool_calls ?? []) {\n blocks.push({\n type: \"tool_call\",\n id: toolCall.id,\n name: toolCall.name,\n args: toolCall.args,\n });\n }\n return blocks;\n}\n\n/**\n * Converts a ChatOpenAICompletions message chunk to an array of v1 standard content blocks.\n *\n * This function processes an AI message chunk from OpenAI's chat completions API and converts\n * it to the standardized v1 content block format. It handles both string and array content,\n * as well as tool calls that may be present in the chunk.\n *\n * @param message - The AI message chunk containing OpenAI-formatted content blocks\n * @returns Array of content blocks in v1 standard format\n *\n * @example\n * ```typescript\n * const chunk = new AIMessage(\"Hello\");\n * const standardBlocks = convertToV1FromChatCompletionsChunk(chunk);\n * // Returns: [{ type: \"text\", text: \"Hello\" }]\n * ```\n *\n * @example\n * ```typescript\n * const chunk = new AIMessage([\n * { type: \"text\", text: \"Processing...\" }\n * ]);\n * chunk.tool_calls = [\n * { id: \"call_456\", name: \"search\", args: { query: \"test\" } }\n * ];\n *\n * const standardBlocks = convertToV1FromChatCompletionsChunk(chunk);\n * // Returns:\n * // [\n * // { type: \"text\", text: \"Processing...\" },\n * // { type: \"tool_call\", id: \"call_456\", name: \"search\", args: { query: \"test\" } }\n * // ]\n * ```\n */\nexport function convertToV1FromChatCompletionsChunk(\n message: AIMessage\n): Array<ContentBlock.Standard> {\n const blocks: Array<ContentBlock.Standard> = [];\n if (typeof message.content === \"string\") {\n // Only add text block if content is non-empty\n if (message.content.length > 0) {\n blocks.push({\n type: \"text\",\n text: message.content,\n });\n }\n } else {\n blocks.push(...convertToV1FromChatCompletionsInput(message.content));\n }\n\n // TODO: parse chunk position information\n for (const toolCall of message.tool_calls ?? []) {\n blocks.push({\n type: \"tool_call\",\n id: toolCall.id,\n name: toolCall.name,\n args: toolCall.args,\n });\n }\n return blocks;\n}\n\n/**\n * Converts an array of ChatOpenAICompletions content blocks to v1 standard content blocks.\n *\n * This function processes content blocks from OpenAI's Chat Completions API format\n * and converts them to the standardized v1 content block format. It handles both\n * OpenAI-specific data blocks (which require conversion) and standard blocks\n * (which are passed through with type assertion).\n *\n * @param blocks - Array of content blocks in ChatOpenAICompletions format\n * @returns Array of content blocks in v1 standard format\n *\n * @example\n * ```typescript\n * const openaiBlocks = [\n * { type: \"text\", text: \"Hello world\" },\n * { type: \"image_url\", image_url: { url: \"https://example.com/image.png\" } }\n * ];\n *\n * const standardBlocks = convertToV1FromChatCompletionsInput(openaiBlocks);\n * // Returns:\n * // [\n * // { type: \"text\", text: \"Hello world\" },\n * // { type: \"image\", url: \"https://example.com/image.png\" }\n * // ]\n * ```\n */\nexport function convertToV1FromChatCompletionsInput(\n blocks: Array<ContentBlock>\n): Array<ContentBlock.Standard> {\n const convertedBlocks: Array<ContentBlock.Standard> = [];\n for (const block of blocks) {\n if (isOpenAIDataBlock(block)) {\n convertedBlocks.push(convertToV1FromOpenAIDataBlock(block));\n } else {\n convertedBlocks.push(block as ContentBlock.Standard);\n }\n }\n return convertedBlocks;\n}\n\nfunction convertResponsesAnnotation(\n annotation: ContentBlock\n): ContentBlock | ContentBlock.Citation {\n if (annotation.type === \"url_citation\") {\n const { url, title, start_index, end_index } = annotation;\n return {\n type: \"citation\",\n url,\n title,\n startIndex: start_index,\n endIndex: end_index,\n };\n }\n if (annotation.type === \"file_citation\") {\n const { file_id, filename, index } = annotation;\n return {\n type: \"citation\",\n title: filename,\n startIndex: index,\n endIndex: index,\n fileId: file_id,\n };\n }\n return annotation;\n}\n\n/**\n * Converts a ChatOpenAIResponses message to an array of v1 standard content blocks.\n *\n * This function processes an AI message containing OpenAI Responses-specific content blocks\n * and converts them to the standardized v1 content block format. It handles reasoning summaries,\n * text content with annotations, tool calls, and various tool outputs including code interpreter,\n * web search, file search, computer calls, and MCP-related blocks.\n *\n * @param message - The AI message containing OpenAI Responses-formatted content blocks\n * @returns Array of content blocks in v1 standard format\n *\n * @example\n * ```typescript\n * const message = new AIMessage({\n * content: [{ type: \"text\", text: \"Hello world\", annotations: [] }],\n * tool_calls: [{ id: \"123\", name: \"calculator\", args: { a: 1, b: 2 } }],\n * additional_kwargs: {\n * reasoning: { summary: [{ text: \"Let me calculate this...\" }] },\n * tool_outputs: [\n * {\n * type: \"code_interpreter_call\",\n * code: \"print('hello')\",\n * outputs: [{ type: \"logs\", logs: \"hello\" }]\n * }\n * ]\n * }\n * });\n *\n * const standardBlocks = convertToV1FromResponses(message);\n * // Returns:\n * // [\n * // { type: \"reasoning\", reasoning: \"Let me calculate this...\" },\n * // { type: \"text\", text: \"Hello world\", annotations: [] },\n * // { type: \"tool_call\", id: \"123\", name: \"calculator\", args: { a: 1, b: 2 } },\n * // { type: \"code_interpreter_call\", code: \"print('hello')\" },\n * // { type: \"code_interpreter_result\", output: [{ type: \"code_interpreter_output\", returnCode: 0, stdout: \"hello\" }] }\n * // ]\n * ```\n */\nexport function convertToV1FromResponses(\n message: AIMessage\n): Array<ContentBlock.Standard> {\n function* iterateContent(): Iterable<ContentBlock.Standard> {\n if (\n _isObject(message.additional_kwargs?.reasoning) &&\n _isArray(message.additional_kwargs.reasoning.summary)\n ) {\n const summary =\n message.additional_kwargs.reasoning.summary.reduce<string>(\n (acc, item) => {\n if (_isObject(item) && _isString(item.text)) {\n return `${acc}${item.text}`;\n }\n return acc;\n },\n \"\"\n );\n yield {\n type: \"reasoning\",\n reasoning: summary,\n };\n }\n const content =\n typeof message.content === \"string\"\n ? [{ type: \"text\", text: message.content }]\n : message.content;\n for (const block of content) {\n if (_isContentBlock(block, \"text\")) {\n const { text, annotations, ...rest } = block;\n if (Array.isArray(annotations)) {\n yield {\n ...rest,\n type: \"text\",\n text: String(text),\n annotations: annotations.map(convertResponsesAnnotation),\n };\n } else {\n yield {\n ...rest,\n type: \"text\",\n text: String(text),\n };\n }\n }\n }\n for (const toolCall of message.tool_calls ?? []) {\n yield {\n type: \"tool_call\",\n id: toolCall.id,\n name: toolCall.name,\n args: toolCall.args,\n };\n }\n if (\n _isObject(message.additional_kwargs) &&\n _isArray(message.additional_kwargs.tool_outputs)\n ) {\n for (const toolOutput of message.additional_kwargs.tool_outputs) {\n if (_isContentBlock(toolOutput, \"web_search_call\")) {\n /**\n * Build args from available action data.\n * The ResponseFunctionWebSearch base type only has id, status, type.\n * The action field (with query, sources, etc.) may be present at\n * runtime when the `include` parameter includes \"web_search_call.action.sources\".\n */\n const webSearchArgs: Record<string, unknown> = {};\n if (\n _isObject(toolOutput.action) &&\n _isString(toolOutput.action.query)\n ) {\n webSearchArgs.query = toolOutput.action.query;\n }\n yield {\n id: toolOutput.id,\n type: \"server_tool_call\",\n name: \"web_search\",\n args: webSearchArgs,\n };\n // Emit a server_tool_call_result when the search has completed or failed\n if (\n toolOutput.status === \"completed\" ||\n toolOutput.status === \"failed\"\n ) {\n const output: Record<string, unknown> = {};\n if (_isObject(toolOutput.action)) {\n output.action = toolOutput.action;\n }\n yield {\n type: \"server_tool_call_result\",\n toolCallId: _isString(toolOutput.id) ? toolOutput.id : \"\",\n status: toolOutput.status === \"completed\" ? \"success\" : \"error\",\n output,\n };\n }\n continue;\n } else if (_isContentBlock(toolOutput, \"file_search_call\")) {\n yield {\n id: toolOutput.id,\n type: \"server_tool_call\",\n name: \"file_search\",\n args: {\n queries: _isArray(toolOutput.queries) ? toolOutput.queries : [],\n },\n };\n // Emit a server_tool_call_result when results are available\n if (\n toolOutput.status === \"completed\" ||\n toolOutput.status === \"failed\"\n ) {\n yield {\n type: \"server_tool_call_result\",\n toolCallId: _isString(toolOutput.id) ? toolOutput.id : \"\",\n status: toolOutput.status === \"completed\" ? \"success\" : \"error\",\n output: _isArray(toolOutput.results)\n ? { results: toolOutput.results }\n : {},\n };\n }\n continue;\n } else if (_isContentBlock(toolOutput, \"computer_call\")) {\n yield { type: \"non_standard\", value: toolOutput };\n continue;\n } else if (_isContentBlock(toolOutput, \"code_interpreter_call\")) {\n if (_isString(toolOutput.code)) {\n yield {\n id: toolOutput.id,\n type: \"server_tool_call\",\n name: \"code_interpreter\",\n args: { code: toolOutput.code },\n };\n }\n if (_isArray(toolOutput.outputs)) {\n const returnCode = iife(() => {\n if (toolOutput.status === \"in_progress\") return undefined;\n if (toolOutput.status === \"completed\") return 0;\n if (toolOutput.status === \"incomplete\") return 127;\n if (toolOutput.status === \"interpreting\") return undefined;\n if (toolOutput.status === \"failed\") return 1;\n return undefined;\n });\n for (const output of toolOutput.outputs) {\n if (_isContentBlock(output, \"logs\")) {\n yield {\n type: \"server_tool_call_result\",\n toolCallId: toolOutput.id ?? \"\",\n status: \"success\",\n output: {\n type: \"code_interpreter_output\",\n returnCode: returnCode ?? 0,\n stderr: [0, undefined].includes(returnCode)\n ? undefined\n : String(output.logs),\n stdout: [0, undefined].includes(returnCode)\n ? String(output.logs)\n : undefined,\n },\n };\n continue;\n }\n }\n }\n continue;\n } else if (_isContentBlock(toolOutput, \"mcp_call\")) {\n yield {\n id: toolOutput.id,\n type: \"server_tool_call\",\n name: \"mcp_call\",\n args: toolOutput.input,\n };\n continue;\n } else if (_isContentBlock(toolOutput, \"mcp_list_tools\")) {\n yield {\n id: toolOutput.id,\n type: \"server_tool_call\",\n name: \"mcp_list_tools\",\n args: toolOutput.input,\n };\n continue;\n } else if (_isContentBlock(toolOutput, \"mcp_approval_request\")) {\n yield { type: \"non_standard\", value: toolOutput };\n continue;\n } else if (_isContentBlock(toolOutput, \"image_generation_call\")) {\n // Convert image_generation_call to proper image content block if result is available\n if (_isString(toolOutput.result)) {\n yield {\n type: \"image\",\n mimeType: \"image/png\",\n data: toolOutput.result,\n id: _isString(toolOutput.id) ? toolOutput.id : undefined,\n metadata: {\n status: _isString(toolOutput.status)\n ? toolOutput.status\n : undefined,\n },\n };\n }\n // Also yield as non_standard for backwards compatibility\n yield { type: \"non_standard\", value: toolOutput };\n continue;\n }\n if (_isObject(toolOutput)) {\n yield { type: \"non_standard\", value: toolOutput };\n }\n }\n }\n }\n return Array.from(iterateContent());\n}\n\n/**\n * Converts a ChatOpenAIResponses message chunk to an array of v1 standard content blocks.\n *\n * This function processes an AI message chunk containing OpenAI-specific content blocks\n * and converts them to the standardized v1 content block format. It handles both the\n * regular message content and tool call chunks that are specific to streaming responses.\n *\n * @param message - The AI message chunk containing OpenAI-formatted content blocks\n * @returns Array of content blocks in v1 standard format\n *\n * @example\n * ```typescript\n * const messageChunk = new AIMessageChunk({\n * content: [{ type: \"text\", text: \"Hello\" }],\n * tool_call_chunks: [\n * { id: \"call_123\", name: \"calculator\", args: '{\"a\": 1' }\n * ]\n * });\n *\n * const standardBlocks = convertToV1FromResponsesChunk(messageChunk);\n * // Returns:\n * // [\n * // { type: \"text\", text: \"Hello\" },\n * // { type: \"tool_call_chunk\", id: \"call_123\", name: \"calculator\", args: '{\"a\": 1' }\n * // ]\n * ```\n */\nexport function convertToV1FromResponsesChunk(\n message: AIMessageChunk\n): Array<ContentBlock.Standard> {\n function* iterateContent(): Iterable<ContentBlock.Standard> {\n yield* convertToV1FromResponses(message);\n for (const toolCallChunk of message.tool_call_chunks ?? []) {\n yield {\n type: \"tool_call_chunk\",\n id: toolCallChunk.id,\n name: toolCallChunk.name,\n args: toolCallChunk.args,\n };\n }\n }\n return Array.from(iterateContent());\n}\n\nexport const ChatOpenAITranslator: StandardContentBlockTranslator = {\n translateContent: (message) => {\n if (typeof message.content === \"string\") {\n return convertToV1FromChatCompletions(message);\n }\n return convertToV1FromResponses(message);\n },\n translateContentChunk: (message) => {\n if (typeof message.content === \"string\") {\n return convertToV1FromChatCompletionsChunk(message);\n }\n return convertToV1FromResponsesChunk(message);\n },\n};\n"],"mappings":"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"}