Skip to content

Commit 51d391d

Browse files
committed
fix(openai-native): background resume/poll logging + terminal handling for 401/403; types: GPT-5 Pro metadata — no prompt cache, no reasoningEffort flag; tests: remove duplicate GPT‑5 Pro background test
1 parent 4dbedc0 commit 51d391d

File tree

3 files changed

+57
-25
lines changed

3 files changed

+57
-25
lines changed

packages/types/src/providers/openai.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ export const openAiNativeModels = {
4141
maxTokens: 128000,
4242
contextWindow: 400000,
4343
supportsImages: true,
44-
supportsPromptCache: true,
44+
// GPT-5 Pro does NOT support prompt caching
45+
supportsPromptCache: false,
46+
// Reasoning effort is not user-configurable for this model; do not expose the flag or default
4547
supportsReasoningEffort: false,
46-
reasoningEffort: "high",
4748
inputPrice: 15.0,
4849
outputPrice: 120.0,
4950
description:

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

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,26 +1842,6 @@ describe("OpenAI Native background mode behavior", () => {
18421842
expect(requestBodyWithOptionFalse.stream).toBe(true)
18431843
})
18441844

1845-
it("auto-enables background mode for gpt-5-pro when no override is specified", async () => {
1846-
const handler = new OpenAiNativeHandler({
1847-
apiModelId: "gpt-5-pro-2025-10-06",
1848-
openAiNativeApiKey: "test",
1849-
// no openAiNativeBackgroundMode provided
1850-
})
1851-
1852-
mockResponsesCreate.mockResolvedValueOnce(createMinimalIterable())
1853-
1854-
const chunks: any[] = []
1855-
for await (const chunk of handler.createMessage(systemPrompt, baseMessages, metadataStoreFalse)) {
1856-
chunks.push(chunk)
1857-
}
1858-
1859-
expect(chunks).not.toHaveLength(0)
1860-
const requestBody = mockResponsesCreate.mock.calls[0][0]
1861-
expect(requestBody.background).toBe(true)
1862-
expect(requestBody.stream).toBe(true)
1863-
expect(requestBody.store).toBe(true)
1864-
})
18651845
it("forces store:true and includes background:true when falling back to SSE", async () => {
18661846
const handler = new OpenAiNativeHandler({
18671847
apiModelId: "gpt-5-pro-2025-10-06",

src/api/providers/openai-native.ts

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,7 +1323,28 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
13231323
})
13241324

13251325
if (!res.ok) {
1326-
throw new Error(`Resume request failed (${res.status})`)
1326+
// Attach status and classify permanent failures
1327+
const err: any = new Error(`Resume request failed (${res.status})`)
1328+
err.status = res.status
1329+
1330+
// 401/403 are permanent for the current request - emit failed and stop
1331+
if (res.status === 401 || res.status === 403) {
1332+
yield {
1333+
type: "status",
1334+
mode: "background",
1335+
status: "failed",
1336+
responseId,
1337+
}
1338+
throw createTerminalBackgroundError(`Resume unauthorized/forbidden (${res.status})`)
1339+
}
1340+
1341+
// Other statuses (e.g., 404/429/5xx) are treated as transient; log and retry with backoff
1342+
console.warn?.("[openai-native] resume attempt failed", {
1343+
attempt,
1344+
status: res.status,
1345+
responseId,
1346+
})
1347+
throw err
13271348
}
13281349
if (!res.body) {
13291350
throw new Error("Resume request failed (no body)")
@@ -1358,10 +1379,24 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
13581379
} catch (err) {
13591380
// If terminal error, don't keep retrying resume; fall back to polling immediately
13601381
const delay = resumeBaseDelayMs * Math.pow(2, attempt)
1382+
13611383
if (isTerminalBackgroundError(err)) {
1384+
console.warn?.("[openai-native] resume terminated", {
1385+
attempt,
1386+
responseId,
1387+
error: (err as any)?.message,
1388+
})
13621389
break
13631390
}
1364-
// Otherwise retry with backoff
1391+
1392+
// Otherwise retry with backoff and lightweight logging for diagnostics
1393+
console.warn?.("[openai-native] resume retry", {
1394+
attempt,
1395+
responseId,
1396+
error: (err as any)?.message,
1397+
nextDelayMs: delay,
1398+
})
1399+
13651400
if (delay > 0) {
13661401
await new Promise((r) => setTimeout(r, delay))
13671402
}
@@ -1392,7 +1427,23 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
13921427
})
13931428

13941429
if (!pollRes.ok) {
1395-
// transient; wait and retry
1430+
// Treat auth/permission as permanent; others as transient with logging
1431+
if (pollRes.status === 401 || pollRes.status === 403) {
1432+
yield {
1433+
type: "status",
1434+
mode: "background",
1435+
status: "failed",
1436+
responseId,
1437+
}
1438+
throw createTerminalBackgroundError(
1439+
`Polling unauthorized/forbidden (${pollRes.status}) for ${responseId}`,
1440+
)
1441+
}
1442+
1443+
console.warn?.("[openai-native] polling non-OK response", {
1444+
status: pollRes.status,
1445+
responseId,
1446+
})
13961447
await new Promise((r) => setTimeout(r, pollIntervalMs))
13971448
continue
13981449
}

0 commit comments

Comments
 (0)