Download src/server/proxy/transform/openaiChatToAnthropic.ts from chenbhao/codev: direct link, hf CLI and curl.
- Browser
- Download file 3.42 kB
-
https://huggingface.co/chenbhao/codev/resolve/afbc7edaae4e6bb0102ba024b49ce8be89d2264c/src/server/proxy/transform/openaiChatToAnthropic.ts
- Command line
-
hf download hf://chenbhao/codev@afbc7edaae4e6bb0102ba024b49ce8be89d2264c/src/server/proxy/transform/openaiChatToAnthropic.ts
-
curl -L -o openaiChatToAnthropic.ts https://huggingface.co/chenbhao/codev/resolve/afbc7edaae4e6bb0102ba024b49ce8be89d2264c/src/server/proxy/transform/openaiChatToAnthropic.ts
3.42 kB
| /** | |
| * Response transformation: OpenAI Chat Completions → Anthropic Messages | |
| * Derived from cc-switch (https://github.com/farion1231/cc-switch) | |
| * Original work by Jason Young, MIT License | |
| */ | |
| import type { | |
| OpenAIChatResponse, | |
| AnthropicResponse, | |
| AnthropicContentBlock, | |
| } from './types.js' | |
| import { parseOpenAIToolArguments } from './toolArguments.js' | |
| /** | |
| * Convert OpenAI Chat Completions response to Anthropic Messages response. | |
| */ | |
| export function openaiChatToAnthropic(response: OpenAIChatResponse, model: string): AnthropicResponse { | |
| const choice = response.choices?.[0] | |
| if (!choice) { | |
| return createEmptyResponse(response, model) | |
| } | |
| const content: AnthropicContentBlock[] = [] | |
| // Convert reasoning/thinking content (all provider formats) | |
| const msg = choice.message as Record<string, unknown> | |
| // Format 1: reasoning_content (DeepSeek, OpenRouter, XAI, Perplexity) | |
| if (typeof msg.reasoning_content === 'string' && msg.reasoning_content) { | |
| content.push({ type: 'thinking', thinking: msg.reasoning_content }) | |
| } | |
| // Format 2: reasoning (GLM-5, Cerebras, Groq) | |
| else if (typeof msg.reasoning === 'string' && msg.reasoning) { | |
| content.push({ type: 'thinking', thinking: msg.reasoning }) | |
| } | |
| // Format 3: thinking_blocks (OpenAI o-series) | |
| else if (Array.isArray(msg.thinking_blocks)) { | |
| for (const tb of msg.thinking_blocks as Array<Record<string, unknown>>) { | |
| if (tb.type === 'thinking' && typeof tb.thinking === 'string') { | |
| content.push({ type: 'thinking', thinking: tb.thinking, signature: tb.signature as string | undefined }) | |
| } | |
| } | |
| } | |
| // Convert text content | |
| if (choice.message.content) { | |
| content.push({ type: 'text', text: choice.message.content }) | |
| } | |
| // Convert tool calls | |
| if (choice.message.tool_calls) { | |
| for (const tc of choice.message.tool_calls) { | |
| content.push({ | |
| type: 'tool_use', | |
| id: tc.id, | |
| name: tc.function.name, | |
| input: parseOpenAIToolArguments(tc.function.arguments), | |
| }) | |
| } | |
| } | |
| // If no content at all, add empty text | |
| if (content.length === 0) { | |
| content.push({ type: 'text', text: '' }) | |
| } | |
| return { | |
| id: response.id || `msg_${Date.now()}`, | |
| type: 'message', | |
| role: 'assistant', | |
| content, | |
| model: response.model || model, | |
| stop_reason: mapFinishReason(choice.finish_reason), | |
| stop_sequence: null, | |
| usage: mapUsage(response.usage), | |
| } | |
| } | |
| function mapFinishReason(reason: string | null): string { | |
| switch (reason) { | |
| case 'stop': return 'end_turn' | |
| case 'tool_calls': return 'tool_use' | |
| case 'length': return 'max_tokens' | |
| case 'content_filter': return 'end_turn' | |
| default: return 'end_turn' | |
| } | |
| } | |
| function mapUsage(usage?: OpenAIChatResponse['usage']): AnthropicResponse['usage'] { | |
| if (!usage) { | |
| return { input_tokens: 0, output_tokens: 0 } | |
| } | |
| return { | |
| input_tokens: usage.prompt_tokens || 0, | |
| output_tokens: usage.completion_tokens || 0, | |
| cache_read_input_tokens: usage.prompt_tokens_details?.cached_tokens || 0, | |
| } | |
| } | |
| function createEmptyResponse(response: OpenAIChatResponse, model: string): AnthropicResponse { | |
| return { | |
| id: response.id || `msg_${Date.now()}`, | |
| type: 'message', | |
| role: 'assistant', | |
| content: [{ type: 'text', text: '' }], | |
| model: response.model || model, | |
| stop_reason: 'end_turn', | |
| stop_sequence: null, | |
| usage: mapUsage(response.usage), | |
| } | |
| } | |