Skip to content

Commit 9b4c4a8

Browse files
authored
[ResponsesAPI] Provider in model + clean input (#1588)
Some tweaks to make it work in a demo: - provider can be passed like this `model="cohere@CohereLabs/c4ai-command-a-03-2025"` - clean up input message if empty message (not supported by some providers) - check tools calls is not an empty list
1 parent c0bde43 commit 9b4c4a8

File tree

2 files changed

+41
-35
lines changed

2 files changed

+41
-35
lines changed

packages/responses-server/src/routes/responses.ts

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -45,46 +45,53 @@ export const postCreateResponse = async (
4545

4646
if (Array.isArray(req.body.input)) {
4747
messages.push(
48-
...req.body.input.map((item) => ({
49-
role: item.role,
50-
content:
51-
typeof item.content === "string"
52-
? item.content
53-
: item.content
54-
.map((content) => {
55-
switch (content.type) {
56-
case "input_image":
57-
return {
58-
type: "image_url" as ChatCompletionInputMessageChunkType,
59-
image_url: {
60-
url: content.image_url,
61-
},
62-
};
63-
case "output_text":
64-
return {
65-
type: "text" as ChatCompletionInputMessageChunkType,
66-
text: content.text,
67-
};
68-
case "refusal":
69-
return undefined;
70-
case "input_text":
71-
return {
72-
type: "text" as ChatCompletionInputMessageChunkType,
73-
text: content.text,
74-
};
75-
}
76-
})
77-
.filter((item) => item !== undefined),
78-
}))
48+
...req.body.input
49+
.map((item) => ({
50+
role: item.role,
51+
content:
52+
typeof item.content === "string"
53+
? item.content
54+
: item.content
55+
.map((content) => {
56+
switch (content.type) {
57+
case "input_image":
58+
return {
59+
type: "image_url" as ChatCompletionInputMessageChunkType,
60+
image_url: {
61+
url: content.image_url,
62+
},
63+
};
64+
case "output_text":
65+
return content.text
66+
? {
67+
type: "text" as ChatCompletionInputMessageChunkType,
68+
text: content.text,
69+
}
70+
: undefined;
71+
case "refusal":
72+
return undefined;
73+
case "input_text":
74+
return {
75+
type: "text" as ChatCompletionInputMessageChunkType,
76+
text: content.text,
77+
};
78+
}
79+
})
80+
.filter((item) => item !== undefined),
81+
}))
82+
.filter((message) => message.content?.length !== 0)
7983
);
8084
} else {
8185
messages.push({ role: "user", content: req.body.input });
8286
}
8387

88+
const model = req.body.model.includes("@") ? req.body.model.split("@")[1] : req.body.model;
89+
const provider = req.body.model.includes("@") ? req.body.model.split("@")[0] : undefined;
90+
8491
const payload: ChatCompletionInput = {
8592
// main params
86-
model: req.body.model,
87-
provider: req.body.provider,
93+
model: model,
94+
provider: provider,
8895
messages: messages,
8996
stream: req.body.stream,
9097
// options
@@ -239,7 +246,7 @@ export const postCreateResponse = async (
239246
delta: chunk.choices[0].delta.content,
240247
sequence_number: sequenceNumber++,
241248
});
242-
} else if (chunk.choices[0].delta.tool_calls) {
249+
} else if (chunk.choices[0].delta.tool_calls && chunk.choices[0].delta.tool_calls.length > 0) {
243250
if (chunk.choices[0].delta.tool_calls.length > 1) {
244251
throw new StreamingError("Not implemented: only single tool call is supported in streaming mode.");
245252
}

packages/responses-server/src/schemas.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ export const createResponseParamsSchema = z.object({
8484
.default(null),
8585
model: z.string(),
8686
// parallel_tool_calls: z.boolean().default(true), // TODO: how to handle this if chat completion doesn't?
87-
provider: z.string().optional(),
8887
// previous_response_id: z.string().nullable().default(null),
8988
// reasoning: z.object({
9089
// effort: z.enum(["low", "medium", "high"]).default("medium"),

0 commit comments

Comments
 (0)