Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/api/providers/__tests__/deepseek.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,14 @@ describe("DeepSeekHandler", () => {
expect(chunks).toContainEqual({ type: "reasoning", text: "router-style thought" })
})

it("should throw a wrapped error when the API call fails", async () => {
const apiError = Object.assign(new Error("Invalid API key"), { status: 401 })
mockCreate.mockRejectedValueOnce(apiError)

const stream = handler.createMessage(systemPrompt, messages)
await expect(stream.next()).rejects.toThrow("DeepSeek completion error: Invalid API key")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test checks the message format, but .status is what the retry/backoff logic reads downstream — could we assert that it is preserved too?

Suggested change
await expect(stream.next()).rejects.toThrow("DeepSeek completion error: Invalid API key")
const err = await stream.next().catch((e) => e)
expect(err.message).toBe("DeepSeek completion error: Invalid API key")
expect((err as any).status).toBe(401)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve updated the DeepSeek error test to capture the thrown error and assert both the wrapped message and the preserved status value.
This should cover the downstream retry/backoff logic that reads .status.

})

it("prefers delta.reasoning_content over delta.reasoning when both are present", async () => {
mockCreate.mockImplementationOnce(async () => ({
[Symbol.asyncIterator]: async function* () {
Expand Down
2 changes: 1 addition & 1 deletion src/api/providers/base-openai-compatible-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { convertToOpenAiMessages } from "../transform/openai-format"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { DEFAULT_HEADERS } from "./constants"
import { BaseProvider } from "./base-provider"
import { handleOpenAIError } from "./utils/openai-error-handler"
import { handleOpenAIError } from "./utils/error-handler"
import { calculateApiCostOpenAI } from "../../shared/cost"
import { extractReasoningFromDelta } from "./utils/extract-reasoning"

Expand Down
2 changes: 1 addition & 1 deletion src/api/providers/deepseek.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export class DeepSeekHandler extends OpenAiHandler {
isAzureAiInference ? { path: OPENAI_AZURE_AI_INFERENCE_PATH } : {},
)
} catch (error) {
const { handleOpenAIError } = await import("./utils/openai-error-handler")
const { handleOpenAIError } = await import("./utils/error-handler")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every other provider uses a static import for handleOpenAIError at the top of the file — is there a reason this one uses a dynamic import inside the catch block? If not, a static import would keep it consistent.

Suggested change
const { handleOpenAIError } = await import("./utils/error-handler")
import { handleOpenAIError } from "./utils/error-handler"

(And the catch body becomes just throw handleOpenAIError(error, "DeepSeek"))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There wasn’t a specific reason to keep this as a dynamic import.
I’ve updated DeepSeek to use the same static handleOpenAIError import as the other providers and simplified the catch block to call throw handleOpenAIError(error, "DeepSeek") directly.

throw handleOpenAIError(error, "DeepSeek")
}

Expand Down
2 changes: 1 addition & 1 deletion src/api/providers/lm-studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ApiStream } from "../transform/stream"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { getModelsFromCache } from "./fetchers/modelCache"
import { handleOpenAIError } from "./utils/openai-error-handler"
import { handleOpenAIError } from "./utils/error-handler"

export class LmStudioHandler extends BaseProvider implements SingleCompletionHandler {
protected options: ApiHandlerOptions
Expand Down
2 changes: 1 addition & 1 deletion src/api/providers/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { getModelParams } from "../transform/model-params"
import { DEFAULT_HEADERS } from "./constants"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { handleOpenAIError } from "./utils/openai-error-handler"
import { handleOpenAIError } from "./utils/error-handler"
import { extractReasoningFromDelta } from "./utils/extract-reasoning"

// TODO: Rename this to OpenAICompatibleHandler. Also, I think the
Expand Down
2 changes: 1 addition & 1 deletion src/api/providers/openrouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { getModelEndpoints } from "./fetchers/modelEndpointCache"
import { DEFAULT_HEADERS } from "./constants"
import { BaseProvider } from "./base-provider"
import type { ApiHandlerCreateMessageMetadata, SingleCompletionHandler } from "../index"
import { handleOpenAIError } from "./utils/openai-error-handler"
import { handleOpenAIError } from "./utils/error-handler"
import { generateImageWithProvider, ImageGenerationResult } from "./utils/image-generation"
import { applyRouterToolPreferences } from "./utils/router-tool-preferences"

Expand Down
2 changes: 1 addition & 1 deletion src/api/providers/requesty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { getModels } from "./fetchers/modelCache"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { toRequestyServiceUrl } from "../../shared/utils/requesty"
import { handleOpenAIError } from "./utils/openai-error-handler"
import { handleOpenAIError } from "./utils/error-handler"
import { applyRouterToolPreferences } from "./utils/router-tool-preferences"
import { extractReasoningFromDelta } from "./utils/extract-reasoning"

Expand Down
2 changes: 1 addition & 1 deletion src/api/providers/unbound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { DEFAULT_HEADERS } from "./constants"
import { getModels } from "./fetchers/modelCache"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { handleOpenAIError } from "./utils/openai-error-handler"
import { handleOpenAIError } from "./utils/error-handler"
import { applyRouterToolPreferences } from "./utils/router-tool-preferences"
import { extractReasoningFromDelta } from "./utils/extract-reasoning"

Expand Down
186 changes: 0 additions & 186 deletions src/api/providers/utils/__tests__/openai-error-handler.spec.ts

This file was deleted.

19 changes: 0 additions & 19 deletions src/api/providers/utils/openai-error-handler.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/api/providers/xai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { getModelParams } from "../transform/model-params"
import { DEFAULT_HEADERS } from "./constants"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { handleOpenAIError } from "./utils/openai-error-handler"
import { handleOpenAIError } from "./utils/error-handler"
import { isMcpTool } from "../../utils/mcp-name"

const XAI_DEFAULT_TEMPERATURE = 0
Expand Down
2 changes: 1 addition & 1 deletion src/api/providers/zai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { convertToZAiFormat } from "../transform/zai-format"

import type { ApiHandlerCreateMessageMetadata } from "../index"
import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"
import { handleOpenAIError } from "./utils/openai-error-handler"
import { handleOpenAIError } from "./utils/error-handler"

// Custom interface for Z.ai params to support thinking mode and reasoning effort tiers.
// Z.ai accepts the standard `reasoning_effort` ladder (none/minimal/low/medium/high/xhigh/max)
Expand Down
2 changes: 1 addition & 1 deletion src/services/code-index/embedders/openai-compatible.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { withValidationErrorHandling, HttpError, formatEmbeddingError } from "..
import { TelemetryEventName } from "@roo-code/types"
import { TelemetryService } from "@roo-code/telemetry"
import { Mutex } from "async-mutex"
import { handleOpenAIError } from "../../../api/providers/utils/openai-error-handler"
import { handleOpenAIError } from "../../../api/providers/utils/error-handler"

interface EmbeddingItem {
embedding: string | number[]
Expand Down
2 changes: 1 addition & 1 deletion src/services/code-index/embedders/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { t } from "../../../i18n"
import { withValidationErrorHandling, formatEmbeddingError, HttpError } from "../shared/validation-helpers"
import { TelemetryEventName } from "@roo-code/types"
import { TelemetryService } from "@roo-code/telemetry"
import { handleOpenAIError } from "../../../api/providers/utils/openai-error-handler"
import { handleOpenAIError } from "../../../api/providers/utils/error-handler"

/**
* OpenAI implementation of the embedder interface with batching and rate limiting
Expand Down
2 changes: 1 addition & 1 deletion src/services/code-index/embedders/openrouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { withValidationErrorHandling, HttpError, formatEmbeddingError } from "..
import { TelemetryEventName } from "@roo-code/types"
import { TelemetryService } from "@roo-code/telemetry"
import { Mutex } from "async-mutex"
import { handleOpenAIError } from "../../../api/providers/utils/openai-error-handler"
import { handleOpenAIError } from "../../../api/providers/utils/error-handler"

// Default provider name when no specific provider is selected
export const OPENROUTER_DEFAULT_PROVIDER_NAME = "[default]"
Expand Down
Loading