Skip to content

Commit ee9d7c6

Browse files
committed
refactor: remove special Codex Mini handling - use same GPT-5 infrastructure
- Removed handleCodexMiniWithResponsesApi method as Codex Mini should behave exactly like GPT-5 - Both models now use the same v1/responses endpoint format - Updated tests to reflect unified behavior - Addresses review feedback about including all messages in conversation context
1 parent 737d70d commit ee9d7c6

File tree

2 files changed

+12
-112
lines changed

2 files changed

+12
-112
lines changed

src/api/providers/__tests__/openai-native.spec.ts

Lines changed: 9 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,8 +1609,7 @@ describe("GPT-5 streaming event coverage (additional)", () => {
16091609
const requestBody = JSON.parse(mockFetch.mock.calls[0][1].body)
16101610
expect(requestBody).toMatchObject({
16111611
model: "codex-mini-latest",
1612-
instructions: systemPrompt,
1613-
input: "Write a hello world function",
1612+
input: "Developer: You are a helpful coding assistant.\n\nUser: Write a hello world function",
16141613
stream: true,
16151614
})
16161615

@@ -1619,47 +1618,15 @@ describe("GPT-5 streaming event coverage (additional)", () => {
16191618
})
16201619

16211620
it("should handle codex-mini-latest non-streaming completion", async () => {
1622-
// Mock fetch for non-streaming response
1623-
const mockFetch = vitest.fn().mockResolvedValue({
1624-
ok: true,
1625-
json: async () => ({
1626-
output_text: "def hello_world():\n print('Hello, World!')",
1627-
}),
1628-
})
1629-
global.fetch = mockFetch as any
1630-
16311621
handler = new OpenAiNativeHandler({
16321622
...mockOptions,
16331623
apiModelId: "codex-mini-latest",
16341624
})
16351625

1636-
const result = await handler.completePrompt("Write a hello world function in Python")
1637-
1638-
expect(result).toBe("def hello_world():\n print('Hello, World!')")
1639-
1640-
// Verify the request
1641-
expect(mockFetch).toHaveBeenCalledWith(
1642-
"https://api.openai.com/v1/responses",
1643-
expect.objectContaining({
1644-
method: "POST",
1645-
headers: expect.objectContaining({
1646-
"Content-Type": "application/json",
1647-
Authorization: "Bearer test-api-key",
1648-
}),
1649-
body: expect.any(String),
1650-
}),
1626+
// Codex Mini now uses the same Responses API as GPT-5, which doesn't support non-streaming
1627+
await expect(handler.completePrompt("Write a hello world function in Python")).rejects.toThrow(
1628+
"completePrompt is not supported for codex-mini-latest. Use createMessage (Responses API) instead.",
16511629
)
1652-
1653-
const requestBody = JSON.parse(mockFetch.mock.calls[0][1].body)
1654-
expect(requestBody).toMatchObject({
1655-
model: "codex-mini-latest",
1656-
instructions: "Complete the following prompt:",
1657-
input: "Write a hello world function in Python",
1658-
stream: false,
1659-
})
1660-
1661-
// Clean up
1662-
delete (global as any).fetch
16631630
})
16641631

16651632
it("should handle codex-mini-latest API errors", async () => {
@@ -1730,10 +1697,12 @@ describe("GPT-5 streaming event coverage (additional)", () => {
17301697
chunks.push(chunk)
17311698
}
17321699

1733-
// Verify the request body only includes user messages
1700+
// Verify the request body includes full conversation like GPT-5
17341701
const requestBody = JSON.parse(mockFetch.mock.calls[0][1].body)
1735-
expect(requestBody.input).toBe("First question\n\nSecond question")
1736-
expect(requestBody.input).not.toContain("First answer")
1702+
expect(requestBody.input).toContain("Developer: You are a helpful assistant")
1703+
expect(requestBody.input).toContain("User: First question")
1704+
expect(requestBody.input).toContain("Assistant: First answer")
1705+
expect(requestBody.input).toContain("User: Second question")
17371706

17381707
// Clean up
17391708
delete (global as any).fetch

src/api/providers/openai-native.ts

Lines changed: 3 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,7 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
222222
// Prefer the official SDK Responses API with streaming; fall back to fetch-based SSE if needed.
223223
const { verbosity } = this.getModel()
224224

225-
// For Codex Mini, we use a simpler request format
226-
if (model.id === "codex-mini-latest") {
227-
yield* this.handleCodexMiniWithResponsesApi(model, systemPrompt, messages)
228-
return
229-
}
225+
// Both GPT-5 and Codex Mini use the same v1/responses endpoint format
230226

231227
// Resolve reasoning effort (supports "minimal" for GPT‑5)
232228
const reasoningEffort = this.getGpt5ReasoningEffort(model)
@@ -1146,38 +1142,6 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
11461142
return modelId.startsWith("gpt-5") || modelId === "codex-mini-latest"
11471143
}
11481144

1149-
private async *handleCodexMiniWithResponsesApi(
1150-
model: OpenAiNativeModel,
1151-
systemPrompt: string,
1152-
messages: Anthropic.Messages.MessageParam[],
1153-
): ApiStream {
1154-
const input = messages
1155-
.filter((msg) => msg.role === "user")
1156-
.map((msg) => {
1157-
if (typeof msg.content === "string") {
1158-
return msg.content
1159-
} else if (Array.isArray(msg.content)) {
1160-
return msg.content
1161-
.filter((part) => part.type === "text")
1162-
.map((part) => (part as any).text)
1163-
.join("\n")
1164-
}
1165-
return ""
1166-
})
1167-
.filter((content) => content)
1168-
.join("\n\n")
1169-
1170-
// Build request body for Codex Mini
1171-
const requestBody = {
1172-
model: model.id,
1173-
instructions: systemPrompt,
1174-
input: input,
1175-
stream: true,
1176-
}
1177-
1178-
yield* this.makeGpt5ResponsesAPIRequest(requestBody, model)
1179-
}
1180-
11811145
private async *handleStreamResponse(
11821146
stream: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,
11831147
model: OpenAiNativeModel,
@@ -1284,41 +1248,8 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
12841248
const isResponsesApi = this.isResponsesApiModel(id)
12851249

12861250
if (isResponsesApi) {
1287-
// Handle models that use the Responses API
1288-
if (id === "codex-mini-latest") {
1289-
// Codex Mini can use the responses API for non-streaming completion
1290-
const apiKey = this.options.openAiNativeApiKey ?? "not-provided"
1291-
const baseURL = this.options.openAiNativeBaseUrl ?? "https://api.openai.com/v1"
1292-
1293-
const response = await fetch(`${baseURL}/responses`, {
1294-
method: "POST",
1295-
headers: {
1296-
"Content-Type": "application/json",
1297-
Authorization: `Bearer ${apiKey}`,
1298-
},
1299-
body: JSON.stringify({
1300-
model: id,
1301-
instructions: "Complete the following prompt:",
1302-
input: prompt,
1303-
stream: false,
1304-
}),
1305-
})
1306-
1307-
if (!response.ok) {
1308-
const errorText = await response.text()
1309-
throw new Error(
1310-
`Codex Mini API error: ${response.status} ${response.statusText} - ${errorText}`,
1311-
)
1312-
}
1313-
1314-
const data = await response.json()
1315-
return data.output_text || ""
1316-
} else {
1317-
// GPT-5 models don't support non-streaming completion
1318-
throw new Error(
1319-
"completePrompt is not supported for GPT-5 models. Use createMessage (Responses API) instead.",
1320-
)
1321-
}
1251+
// Models that use the Responses API (GPT-5 and Codex Mini) don't support non-streaming completion
1252+
throw new Error(`completePrompt is not supported for ${id}. Use createMessage (Responses API) instead.`)
13221253
}
13231254

13241255
const params: any = {

0 commit comments

Comments
 (0)