@@ -5,6 +5,69 @@ import * as models from "../models/index.js";
55import { EnhancedTool , MaxToolRounds } from "../lib/tool-types.js" ;
66import { convertEnhancedToolsToAPIFormat } from "../lib/tool-executor.js" ;
77
8+ /**
9+ * Input type that accepts both chat-style messages and responses-style input
10+ */
11+ export type CallModelInput =
12+ | models . OpenResponsesInput
13+ | models . Message [ ] ;
14+
15+ /**
16+ * Check if input is chat-style messages (Message[])
17+ */
18+ function isChatStyleMessages ( input : CallModelInput ) : input is models . Message [ ] {
19+ if ( ! Array . isArray ( input ) ) return false ;
20+ if ( input . length === 0 ) return false ;
21+
22+ const first = input [ 0 ] as any ;
23+ // Chat-style messages have role but no 'type' field at top level
24+ // Responses-style items have 'type' field (like 'message', 'function_call', etc.)
25+ return first && 'role' in first && ! ( 'type' in first ) ;
26+ }
27+
28+ /**
29+ * Convert chat-style messages to responses-style input
30+ */
31+ function convertChatToResponsesInput ( messages : models . Message [ ] ) : models . OpenResponsesInput {
32+ return messages . map ( ( msg ) : models . OpenResponsesEasyInputMessage | models . OpenResponsesFunctionCallOutput => {
33+ if ( msg . role === "tool" ) {
34+ const toolMsg = msg as models . ToolResponseMessage ;
35+ return {
36+ type : "function_call_output" ,
37+ callId : toolMsg . toolCallId ,
38+ output : typeof toolMsg . content === "string" ? toolMsg . content : JSON . stringify ( toolMsg . content ) ,
39+ } as models . OpenResponsesFunctionCallOutput ;
40+ }
41+
42+ // Handle assistant messages with tool calls
43+ if ( msg . role === "assistant" ) {
44+ const assistantMsg = msg as models . AssistantMessage ;
45+ // If it has tool calls, we need to convert them
46+ // For now, just convert the content part
47+ return {
48+ role : "assistant" ,
49+ content : typeof assistantMsg . content === "string"
50+ ? assistantMsg . content
51+ : assistantMsg . content === null
52+ ? ""
53+ : JSON . stringify ( assistantMsg . content ) ,
54+ } as models . OpenResponsesEasyInputMessage ;
55+ }
56+
57+ // System, user, developer messages
58+ const content = typeof msg . content === "string"
59+ ? msg . content
60+ : msg . content === null || msg . content === undefined
61+ ? ""
62+ : JSON . stringify ( msg . content ) ;
63+
64+ return {
65+ role : msg . role as "user" | "system" | "developer" ,
66+ content,
67+ } as models . OpenResponsesEasyInputMessage ;
68+ } ) as models . OpenResponsesInput ;
69+ }
70+
871/**
972 * Get a response with multiple consumption patterns
1073 *
@@ -75,13 +138,24 @@ import { convertEnhancedToolsToAPIFormat } from "../lib/tool-executor.js";
75138 */
76139export function callModel (
77140 client : OpenRouterCore ,
78- request : Omit < models . OpenResponsesRequest , "stream" | "tools" > & {
141+ request : Omit < models . OpenResponsesRequest , "stream" | "tools" | "input" > & {
142+ input ?: CallModelInput ;
79143 tools ?: EnhancedTool [ ] | models . OpenResponsesRequest [ "tools" ] ;
80144 maxToolRounds ?: MaxToolRounds ;
81145 } ,
82146 options ?: RequestOptions ,
83147) : ResponseWrapper {
84- const { tools, maxToolRounds, ...apiRequest } = request ;
148+ const { tools, maxToolRounds, input, ...restRequest } = request ;
149+
150+ // Convert chat-style messages to responses-style input if needed
151+ const convertedInput = input && isChatStyleMessages ( input )
152+ ? convertChatToResponsesInput ( input )
153+ : input ;
154+
155+ const apiRequest = {
156+ ...restRequest ,
157+ input : convertedInput ,
158+ } ;
85159
86160 // Separate enhanced tools from API tools
87161 let isEnhancedTools = false ;
0 commit comments