Skip to content

Commit 3f98467

Browse files
committed
fix: handle zero timeout correctly for OpenAI-compatible providers
- Pass undefined instead of 0 to OpenAI SDK when apiRequestTimeout is set to 0 - OpenAI SDK interprets 0 as immediate timeout rather than no timeout - Fixes timeout issues with LM Studio and other OpenAI-compatible providers - Updates tests to verify the correct behavior Fixes #7366
1 parent fc70012 commit 3f98467

File tree

6 files changed

+17
-11
lines changed

6 files changed

+17
-11
lines changed

src/api/providers/__tests__/lm-studio-timeout.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ describe("LmStudioHandler timeout configuration", () => {
7272
)
7373
})
7474

75-
it("should handle zero timeout (no timeout)", () => {
75+
it("should handle zero timeout (no timeout) by passing undefined to OpenAI client", () => {
7676
;(getApiRequestTimeout as any).mockReturnValue(0)
7777

7878
const options: ApiHandlerOptions = {
@@ -84,7 +84,7 @@ describe("LmStudioHandler timeout configuration", () => {
8484

8585
expect(mockOpenAIConstructor).toHaveBeenCalledWith(
8686
expect.objectContaining({
87-
timeout: 0, // No timeout
87+
timeout: undefined, // OpenAI SDK expects undefined for no timeout, not 0
8888
}),
8989
)
9090
})

src/api/providers/__tests__/ollama-timeout.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ describe("OllamaHandler timeout configuration", () => {
7171
)
7272
})
7373

74-
it("should handle zero timeout (no timeout)", () => {
74+
it("should handle zero timeout (no timeout) by passing undefined to OpenAI client", () => {
7575
;(getApiRequestTimeout as any).mockReturnValue(0)
7676

7777
const options: ApiHandlerOptions = {
@@ -84,7 +84,7 @@ describe("OllamaHandler timeout configuration", () => {
8484

8585
expect(mockOpenAIConstructor).toHaveBeenCalledWith(
8686
expect.objectContaining({
87-
timeout: 0, // No timeout
87+
timeout: undefined, // OpenAI SDK expects undefined for no timeout, not 0
8888
}),
8989
)
9090
})

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ describe("OpenAiHandler timeout configuration", () => {
125125
)
126126
})
127127

128-
it("should handle zero timeout (no timeout)", () => {
128+
it("should handle zero timeout (no timeout) by passing undefined to OpenAI client", () => {
129129
;(getApiRequestTimeout as any).mockReturnValue(0)
130130

131131
const options: ApiHandlerOptions = {
@@ -137,7 +137,7 @@ describe("OpenAiHandler timeout configuration", () => {
137137

138138
expect(mockOpenAIConstructor).toHaveBeenCalledWith(
139139
expect.objectContaining({
140-
timeout: 0, // No timeout
140+
timeout: undefined, // OpenAI SDK expects undefined for no timeout, not 0
141141
}),
142142
)
143143
})

src/api/providers/lm-studio.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ export class LmStudioHandler extends BaseProvider implements SingleCompletionHan
2424
super()
2525
this.options = options
2626

27+
const timeout = getApiRequestTimeout()
2728
this.client = new OpenAI({
2829
baseURL: (this.options.lmStudioBaseUrl || "http://localhost:1234") + "/v1",
2930
apiKey: "noop",
30-
timeout: getApiRequestTimeout(),
31+
// OpenAI SDK expects undefined for no timeout, not 0
32+
timeout: timeout === 0 ? undefined : timeout,
3133
})
3234
}
3335

src/api/providers/ollama.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ export class OllamaHandler extends BaseProvider implements SingleCompletionHandl
2525
super()
2626
this.options = options
2727

28+
const timeout = getApiRequestTimeout()
2829
this.client = new OpenAI({
2930
baseURL: (this.options.ollamaBaseUrl || "http://localhost:11434") + "/v1",
3031
apiKey: "ollama",
31-
timeout: getApiRequestTimeout(),
32+
// OpenAI SDK expects undefined for no timeout, not 0
33+
timeout: timeout === 0 ? undefined : timeout,
3234
})
3335
}
3436

src/api/providers/openai.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
4848
}
4949

5050
const timeout = getApiRequestTimeout()
51+
// OpenAI SDK expects undefined for no timeout, not 0
52+
const clientTimeout = timeout === 0 ? undefined : timeout
5153

5254
if (isAzureAiInference) {
5355
// Azure AI Inference Service (e.g., for DeepSeek) uses a different path structure
@@ -56,7 +58,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
5658
apiKey,
5759
defaultHeaders: headers,
5860
defaultQuery: { "api-version": this.options.azureApiVersion || "2024-05-01-preview" },
59-
timeout,
61+
timeout: clientTimeout,
6062
})
6163
} else if (isAzureOpenAi) {
6264
// Azure API shape slightly differs from the core API shape:
@@ -66,14 +68,14 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
6668
apiKey,
6769
apiVersion: this.options.azureApiVersion || azureOpenAiDefaultApiVersion,
6870
defaultHeaders: headers,
69-
timeout,
71+
timeout: clientTimeout,
7072
})
7173
} else {
7274
this.client = new OpenAI({
7375
baseURL,
7476
apiKey,
7577
defaultHeaders: headers,
76-
timeout,
78+
timeout: clientTimeout,
7779
})
7880
}
7981
}

0 commit comments

Comments
 (0)