@@ -91,74 +91,26 @@ interface AnthropicToolUseBlock {
9191 input : Record < string , unknown >
9292}
9393
94- // Translation functions
94+ // Payload translation
9595
96- function getAnthropicTextBlocks (
97- messageContent : Message [ "content" ] ,
98- ) : Array < AnthropicTextBlock > {
99- if ( typeof messageContent === "string" ) {
100- return [ { type : "text" , text : messageContent } ]
101- }
102-
103- if ( Array . isArray ( messageContent ) ) {
104- return messageContent
105- . filter ( ( part ) : part is TextPart => part . type === "text" )
106- . map ( ( part ) => ( { type : "text" , text : part . text } ) )
107- }
108-
109- return [ ]
110- }
111-
112- function getAnthropicToolUseBlocks (
113- toolCalls : Array < ToolCall > | undefined ,
114- ) : Array < AnthropicToolUseBlock > {
115- if ( ! toolCalls ) {
116- return [ ]
117- }
118- return toolCalls . map ( ( toolCall ) => ( {
119- type : "tool_use" ,
120- id : toolCall . id ,
121- name : toolCall . function . name ,
122- input : JSON . parse ( toolCall . function . arguments ) as Record < string , unknown > ,
123- } ) )
124- }
125-
126- function mapOpenAIStopReasonToAnthropic (
127- finishReason : ChatCompletionResponse [ "choices" ] [ 0 ] [ "finish_reason" ] ,
128- ) : AnthropicResponse [ "stop_reason" ] {
129- const stopReasonMap = {
130- stop : "end_turn" ,
131- length : "max_tokens" ,
132- tool_calls : "tool_use" ,
133- content_filter : "end_turn" ,
134- } as const
135- return stopReasonMap [ finishReason ]
136- }
137-
138- function mapContent (
139- content : string | Array < AnthropicContentBlock > ,
140- ) : string | Array < ContentPart > | null {
141- if ( typeof content === "string" ) {
142- return content
143- }
144- if ( ! Array . isArray ( content ) ) {
145- return null
146- }
147-
148- const contentParts : Array < ContentPart > = [ ]
149- for ( const block of content ) {
150- if ( block . type === "text" ) {
151- contentParts . push ( { type : "text" , text : block . text } )
152- } else if ( block . type === "image" ) {
153- contentParts . push ( {
154- type : "image_url" ,
155- image_url : {
156- url : `data:${ block . source . media_type } ;base64,${ block . source . data } ` ,
157- } ,
158- } )
159- }
96+ export function translateToOpenAI (
97+ payload : AnthropicMessagesPayload ,
98+ ) : ChatCompletionsPayload {
99+ return {
100+ model : payload . model ,
101+ messages : translateAnthropicMessagesToOpenAI (
102+ payload . messages ,
103+ payload . system ,
104+ ) ,
105+ max_tokens : payload . max_tokens ,
106+ stop : payload . stop_sequences ,
107+ stream : payload . stream ,
108+ temperature : payload . temperature ,
109+ top_p : payload . top_p ,
110+ user : payload . metadata ?. user_id ,
111+ tools : translateAnthropicToolsToOpenAI ( payload . tools ) ,
112+ tool_choice : translateAnthropicToolChoiceToOpenAI ( payload . tool_choice ) ,
160113 }
161- return contentParts
162114}
163115
164116function translateAnthropicMessagesToOpenAI (
@@ -210,6 +162,32 @@ function translateAnthropicMessagesToOpenAI(
210162 return messages
211163}
212164
165+ function mapContent (
166+ content : string | Array < AnthropicContentBlock > ,
167+ ) : string | Array < ContentPart > | null {
168+ if ( typeof content === "string" ) {
169+ return content
170+ }
171+ if ( ! Array . isArray ( content ) ) {
172+ return null
173+ }
174+
175+ const contentParts : Array < ContentPart > = [ ]
176+ for ( const block of content ) {
177+ if ( block . type === "text" ) {
178+ contentParts . push ( { type : "text" , text : block . text } )
179+ } else if ( block . type === "image" ) {
180+ contentParts . push ( {
181+ type : "image_url" ,
182+ image_url : {
183+ url : `data:${ block . source . media_type } ;base64,${ block . source . data } ` ,
184+ } ,
185+ } )
186+ }
187+ }
188+ return contentParts
189+ }
190+
213191function translateAnthropicToolsToOpenAI (
214192 anthropicTools : Array < AnthropicTool > | undefined ,
215193) : Array < Tool > | undefined {
@@ -238,9 +216,6 @@ function translateAnthropicToolChoiceToOpenAI(
238216 return "auto"
239217 }
240218 case "any" : {
241- // The type definition for tool_choice is missing "required", but it's a valid value.
242- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
243- // @ts -expect-error
244219 return "required"
245220 }
246221 case "tool" : {
@@ -258,25 +233,7 @@ function translateAnthropicToolChoiceToOpenAI(
258233 }
259234}
260235
261- export function translateToOpenAI (
262- payload : AnthropicMessagesPayload ,
263- ) : ChatCompletionsPayload {
264- return {
265- model : payload . model ,
266- messages : translateAnthropicMessagesToOpenAI (
267- payload . messages ,
268- payload . system ,
269- ) ,
270- max_tokens : payload . max_tokens ,
271- stop : payload . stop_sequences ,
272- stream : payload . stream ,
273- temperature : payload . temperature ,
274- top_p : payload . top_p ,
275- user : payload . metadata ?. user_id ,
276- tools : translateAnthropicToolsToOpenAI ( payload . tools ) ,
277- tool_choice : translateAnthropicToolChoiceToOpenAI ( payload . tool_choice ) ,
278- }
279- }
236+ // Response translation
280237
281238export function translateToAnthropic (
282239 response : ChatCompletionResponse ,
@@ -299,3 +256,45 @@ export function translateToAnthropic(
299256 } ,
300257 }
301258}
259+
260+ function getAnthropicTextBlocks (
261+ messageContent : Message [ "content" ] ,
262+ ) : Array < AnthropicTextBlock > {
263+ if ( typeof messageContent === "string" ) {
264+ return [ { type : "text" , text : messageContent } ]
265+ }
266+
267+ if ( Array . isArray ( messageContent ) ) {
268+ return messageContent
269+ . filter ( ( part ) : part is TextPart => part . type === "text" )
270+ . map ( ( part ) => ( { type : "text" , text : part . text } ) )
271+ }
272+
273+ return [ ]
274+ }
275+
276+ function getAnthropicToolUseBlocks (
277+ toolCalls : Array < ToolCall > | undefined ,
278+ ) : Array < AnthropicToolUseBlock > {
279+ if ( ! toolCalls ) {
280+ return [ ]
281+ }
282+ return toolCalls . map ( ( toolCall ) => ( {
283+ type : "tool_use" ,
284+ id : toolCall . id ,
285+ name : toolCall . function . name ,
286+ input : JSON . parse ( toolCall . function . arguments ) as Record < string , unknown > ,
287+ } ) )
288+ }
289+
290+ function mapOpenAIStopReasonToAnthropic (
291+ finishReason : ChatCompletionResponse [ "choices" ] [ 0 ] [ "finish_reason" ] ,
292+ ) : AnthropicResponse [ "stop_reason" ] {
293+ const stopReasonMap = {
294+ stop : "end_turn" ,
295+ length : "max_tokens" ,
296+ tool_calls : "tool_use" ,
297+ content_filter : "end_turn" ,
298+ } as const
299+ return stopReasonMap [ finishReason ]
300+ }
0 commit comments