From 0ae6ba7aa8e71f50ca3d21862b62dd6d1581c118 Mon Sep 17 00:00:00 2001 From: Hannes Rudolph Date: Thu, 18 Dec 2025 16:38:03 -0700 Subject: [PATCH] feat(api): integrate createLoggingFetch into all OpenAI-client providers Addresses Daniel's review feedback to wire createLoggingFetch into other providers that use the OpenAI client. Providers updated: - base-openai-compatible-provider.ts - openai.ts (including Azure AI Inference and Azure OpenAI) - openai-native.ts - lm-studio.ts - huggingface.ts - xai.ts - requesty.ts - router-provider.ts - qwen-code.ts OpenRouter was already implemented as the reference. --- src/api/providers/__tests__/openai.spec.ts | 1 + src/api/providers/__tests__/requesty.spec.ts | 2 ++ src/api/providers/__tests__/vercel-ai-gateway.spec.ts | 1 + src/api/providers/base-openai-compatible-provider.ts | 3 ++- src/api/providers/huggingface.ts | 2 ++ src/api/providers/lm-studio.ts | 2 ++ src/api/providers/openai-native.ts | 8 ++++++-- src/api/providers/openai.ts | 5 ++++- src/api/providers/qwen-code.ts | 2 ++ src/api/providers/requesty.ts | 2 ++ src/api/providers/router-provider.ts | 2 ++ src/api/providers/xai.ts | 2 ++ 12 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/api/providers/__tests__/openai.spec.ts b/src/api/providers/__tests__/openai.spec.ts index 31fdaa2389..c1da8e56dc 100644 --- a/src/api/providers/__tests__/openai.spec.ts +++ b/src/api/providers/__tests__/openai.spec.ts @@ -116,6 +116,7 @@ describe("OpenAiHandler", () => { "User-Agent": `RooCode/${Package.version}`, }, timeout: expect.any(Number), + fetch: expect.any(Function), }) }) }) diff --git a/src/api/providers/__tests__/requesty.spec.ts b/src/api/providers/__tests__/requesty.spec.ts index df799426a7..0e855da420 100644 --- a/src/api/providers/__tests__/requesty.spec.ts +++ b/src/api/providers/__tests__/requesty.spec.ts @@ -69,6 +69,7 @@ describe("RequestyHandler", () => { "X-Title": "Roo Code", "User-Agent": `RooCode/${Package.version}`, }, + fetch: expect.any(Function), }) }) @@ -84,6 +85,7 @@ describe("RequestyHandler", () => { "X-Title": "Roo Code", "User-Agent": `RooCode/${Package.version}`, }, + fetch: expect.any(Function), }) }) diff --git a/src/api/providers/__tests__/vercel-ai-gateway.spec.ts b/src/api/providers/__tests__/vercel-ai-gateway.spec.ts index 3c6b1c1069..4120774777 100644 --- a/src/api/providers/__tests__/vercel-ai-gateway.spec.ts +++ b/src/api/providers/__tests__/vercel-ai-gateway.spec.ts @@ -100,6 +100,7 @@ describe("VercelAiGatewayHandler", () => { "X-Title": "Roo Code", "User-Agent": expect.stringContaining("RooCode/"), }), + fetch: expect.any(Function), }) }) diff --git a/src/api/providers/base-openai-compatible-provider.ts b/src/api/providers/base-openai-compatible-provider.ts index ee5dbfd004..5f80713dcc 100644 --- a/src/api/providers/base-openai-compatible-provider.ts +++ b/src/api/providers/base-openai-compatible-provider.ts @@ -14,7 +14,7 @@ import { BaseProvider } from "./base-provider" import { handleOpenAIError } from "./utils/openai-error-handler" import { calculateApiCostOpenAI } from "../../shared/cost" import { getApiRequestTimeout } from "./utils/timeout-config" -import { withLogging, ApiLogger } from "../core/logging" +import { withLogging, ApiLogger, createLoggingFetch } from "../core/logging" type BaseOpenAiCompatibleProviderOptions = ApiHandlerOptions & { providerName: string @@ -65,6 +65,7 @@ export abstract class BaseOpenAiCompatibleProvider apiKey: this.options.apiKey, defaultHeaders: DEFAULT_HEADERS, timeout: getApiRequestTimeout(), + fetch: createLoggingFetch(this._providerName), }) } diff --git a/src/api/providers/huggingface.ts b/src/api/providers/huggingface.ts index 9704ead86f..934023c482 100644 --- a/src/api/providers/huggingface.ts +++ b/src/api/providers/huggingface.ts @@ -9,6 +9,7 @@ import { DEFAULT_HEADERS } from "./constants" import { BaseProvider } from "./base-provider" import { getHuggingFaceModels, getCachedHuggingFaceModels } from "./fetchers/huggingface" import { handleOpenAIError } from "./utils/openai-error-handler" +import { createLoggingFetch } from "../core/logging" export class HuggingFaceHandler extends BaseProvider implements SingleCompletionHandler { private client: OpenAI @@ -31,6 +32,7 @@ export class HuggingFaceHandler extends BaseProvider implements SingleCompletion baseURL: "https://router.huggingface.co/v1", apiKey: this.options.huggingFaceApiKey, defaultHeaders: DEFAULT_HEADERS, + fetch: createLoggingFetch(this.providerName), }) // Try to get cached models first diff --git a/src/api/providers/lm-studio.ts b/src/api/providers/lm-studio.ts index c0121ac253..f6b023d7d3 100644 --- a/src/api/providers/lm-studio.ts +++ b/src/api/providers/lm-studio.ts @@ -17,6 +17,7 @@ import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from ". import { getModelsFromCache } from "./fetchers/modelCache" import { getApiRequestTimeout } from "./utils/timeout-config" import { handleOpenAIError } from "./utils/openai-error-handler" +import { createLoggingFetch } from "../core/logging" export class LmStudioHandler extends BaseProvider implements SingleCompletionHandler { protected options: ApiHandlerOptions @@ -37,6 +38,7 @@ export class LmStudioHandler extends BaseProvider implements SingleCompletionHan baseURL: (this.options.lmStudioBaseUrl || "http://localhost:1234") + "/v1", apiKey: apiKey, timeout: getApiRequestTimeout(), + fetch: createLoggingFetch(this.providerName), }) } diff --git a/src/api/providers/openai-native.ts b/src/api/providers/openai-native.ts index 1bc17f0607..5993de776a 100644 --- a/src/api/providers/openai-native.ts +++ b/src/api/providers/openai-native.ts @@ -23,7 +23,7 @@ import { ApiStream, ApiStreamUsageChunk } from "../transform/stream" import { getModelParams } from "../transform/model-params" import { BaseProvider } from "./base-provider" -import { withLogging, ApiLogger } from "../core/logging" +import { withLogging, ApiLogger, createLoggingFetch } from "../core/logging" import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index" export type OpenAiNativeModel = ReturnType @@ -71,7 +71,11 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio this.options.enableResponsesReasoningSummary = true } const apiKey = this.options.openAiNativeApiKey ?? "not-provided" - this.client = new OpenAI({ baseURL: this.options.openAiNativeBaseUrl, apiKey }) + this.client = new OpenAI({ + baseURL: this.options.openAiNativeBaseUrl, + apiKey, + fetch: createLoggingFetch(this.providerName), + }) } private normalizeUsage(usage: any, model: OpenAiNativeModel): ApiStreamUsageChunk | undefined { diff --git a/src/api/providers/openai.ts b/src/api/providers/openai.ts index cd0bc798d7..fa380aaf45 100644 --- a/src/api/providers/openai.ts +++ b/src/api/providers/openai.ts @@ -22,7 +22,7 @@ import { getModelParams } from "../transform/model-params" import { DEFAULT_HEADERS } from "./constants" import { BaseProvider } from "./base-provider" -import { withLogging, ApiLogger } from "../core/logging" +import { withLogging, ApiLogger, createLoggingFetch } from "../core/logging" import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index" import { getApiRequestTimeout } from "./utils/timeout-config" import { handleOpenAIError } from "./utils/openai-error-handler" @@ -63,6 +63,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl defaultHeaders: headers, defaultQuery: { "api-version": this.options.azureApiVersion || "2024-05-01-preview" }, timeout, + fetch: createLoggingFetch(this.providerName), }) } else if (isAzureOpenAi) { // Azure API shape slightly differs from the core API shape: @@ -73,6 +74,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl apiVersion: this.options.azureApiVersion || azureOpenAiDefaultApiVersion, defaultHeaders: headers, timeout, + fetch: createLoggingFetch(this.providerName), }) } else { this.client = new OpenAI({ @@ -80,6 +82,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl apiKey, defaultHeaders: headers, timeout, + fetch: createLoggingFetch(this.providerName), }) } } diff --git a/src/api/providers/qwen-code.ts b/src/api/providers/qwen-code.ts index 8f26273eba..90f1457cab 100644 --- a/src/api/providers/qwen-code.ts +++ b/src/api/providers/qwen-code.ts @@ -15,6 +15,7 @@ import { ApiStream } from "../transform/stream" import { BaseProvider } from "./base-provider" import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index" +import { createLoggingFetch } from "../core/logging" const QWEN_OAUTH_BASE_URL = "https://chat.qwen.ai" const QWEN_OAUTH_TOKEN_ENDPOINT = `${QWEN_OAUTH_BASE_URL}/api/v1/oauth2/token` @@ -69,6 +70,7 @@ export class QwenCodeHandler extends BaseProvider implements SingleCompletionHan this.client = new OpenAI({ apiKey: "dummy-key-will-be-replaced", baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1", + fetch: createLoggingFetch("QwenCode"), }) } return this.client diff --git a/src/api/providers/requesty.ts b/src/api/providers/requesty.ts index 280be83a67..a84d348e57 100644 --- a/src/api/providers/requesty.ts +++ b/src/api/providers/requesty.ts @@ -25,6 +25,7 @@ import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from ". import { toRequestyServiceUrl } from "../../shared/utils/requesty" import { handleOpenAIError } from "./utils/openai-error-handler" import { applyRouterToolPreferences } from "./utils/router-tool-preferences" +import { createLoggingFetch } from "../core/logging" // Requesty usage includes an extra field for Anthropic use cases. // Safely cast the prompt token details section to the appropriate structure. @@ -78,6 +79,7 @@ export class RequestyHandler extends BaseProvider implements SingleCompletionHan baseURL: this.baseURL, apiKey: apiKey, defaultHeaders: DEFAULT_HEADERS, + fetch: createLoggingFetch(this.providerName), }) } diff --git a/src/api/providers/router-provider.ts b/src/api/providers/router-provider.ts index 01942e2172..db14e6273f 100644 --- a/src/api/providers/router-provider.ts +++ b/src/api/providers/router-provider.ts @@ -6,6 +6,7 @@ import { ApiHandlerOptions, RouterName, ModelRecord } from "../../shared/api" import { BaseProvider } from "./base-provider" import { getModels, getModelsFromCache } from "./fetchers/modelCache" +import { createLoggingFetch } from "../core/logging" import { DEFAULT_HEADERS } from "./constants" @@ -52,6 +53,7 @@ export abstract class RouterProvider extends BaseProvider { ...DEFAULT_HEADERS, ...(options.openAiHeaders || {}), }, + fetch: createLoggingFetch(name), }) } diff --git a/src/api/providers/xai.ts b/src/api/providers/xai.ts index 61238d9db7..68325a9335 100644 --- a/src/api/providers/xai.ts +++ b/src/api/providers/xai.ts @@ -15,6 +15,7 @@ import { DEFAULT_HEADERS } from "./constants" import { BaseProvider } from "./base-provider" import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index" import { handleOpenAIError } from "./utils/openai-error-handler" +import { createLoggingFetch } from "../core/logging" const XAI_DEFAULT_TEMPERATURE = 0 @@ -36,6 +37,7 @@ export class XAIHandler extends BaseProvider implements SingleCompletionHandler baseURL: "https://api.x.ai/v1", apiKey: apiKey, defaultHeaders: DEFAULT_HEADERS, + fetch: createLoggingFetch(this.providerName), }) }