refactor(openai-native): consolidate loaders to types.getOpenAiNativeModels(); remove duplicate host/webview loaders (no UI TTL change by design)

This commit is contained in:
Hannes Rudolph 2025-11-10 09:21:54 -07:00
parent cc7c50c959
commit 3ac3240d42
2 changed files with 4 additions and 98 deletions

View file

@ -1,15 +1,11 @@
import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"
import * as fsSync from "fs"
import * as pathSync from "path"
import * as osSync from "os"
import {
type ModelInfo,
openAiNativeDefaultModelId,
OpenAiNativeModelId,
openAiNativeModels,
validateModelInfoRecord,
getOpenAiNativeModels,
OPENAI_NATIVE_DEFAULT_TEMPERATURE,
GPT5_DEFAULT_TEMPERATURE,
type ReasoningEffort,
@ -35,50 +31,6 @@ export type OpenAiNativeModel = ReturnType<OpenAiNativeHandler["getModel"]>
// Constants for model identification
const GPT5_MODEL_PREFIX = "gpt-5"
/**
* Host-only sync loader for OpenAI Native models merged with ~/.roo overrides.
* Avoids the browser-safe loader in @roo-code/types which may not resolve extras in the extension host bundle.
*/
function loadMergedOpenAiNativeModelsOnHostSync(): Record<string, ModelInfo> {
try {
// 1) Inline JSON override
let extras: Record<string, ModelInfo> = {}
try {
const inline = process.env?.ROO_OPENAI_NATIVE_MODELS_JSON
if (inline) {
const parsed = JSON.parse(inline)
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
extras = validateModelInfoRecord(parsed)
}
}
} catch {
// ignore
}
// 2) File-based load when no inline provided
if (Object.keys(extras).length === 0) {
try {
const customPath =
process.env.ROO_OPENAI_NATIVE_MODELS_PATH ||
pathSync.join(osSync.homedir(), ".roo", "models", "openai-native.json")
if (customPath && fsSync.existsSync(customPath)) {
const raw = fsSync.readFileSync(customPath, "utf8")
const parsed = JSON.parse(raw)
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
extras = validateModelInfoRecord(parsed)
}
}
} catch {
// ignore file errors
}
}
return { ...openAiNativeModels, ...extras } as Record<string, ModelInfo>
} catch {
return openAiNativeModels as Record<string, ModelInfo>
}
}
export class OpenAiNativeHandler extends BaseProvider implements SingleCompletionHandler {
protected options: ApiHandlerOptions
private client: OpenAI
@ -1270,7 +1222,7 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
const modelId = this.options.apiModelId
// Get merged models (built-in + user-defined from ~/.roo/models/openai-native.json)
const allModels = loadMergedOpenAiNativeModelsOnHostSync()
const allModels = getOpenAiNativeModels()
let id = modelId && modelId in allModels ? (modelId as OpenAiNativeModelId) : openAiNativeDefaultModelId

View file

@ -11,7 +11,7 @@ import {
type ClineMessage,
type TelemetrySetting,
type ModelInfo,
validateModelInfoRecord,
getOpenAiNativeModels,
TelemetryEventName,
UserSettingsConfig,
DEFAULT_CHECKPOINT_TIMEOUT_SECONDS,
@ -55,7 +55,6 @@ import { getWorkspacePath } from "../../utils/path"
import { Mode, defaultModeSlug } from "../../shared/modes"
import { getModels, flushModels } from "../../api/providers/fetchers/modelCache"
import { GetModelsOptions } from "../../shared/api"
import { openAiNativeModels } from "@roo-code/types"
import { generateSystemPrompt } from "./generateSystemPrompt"
import { getCommand } from "../../utils/commands"
@ -100,51 +99,6 @@ export const webviewMessageHandler = async (
)
}
/**
* Host-only loader: merge built-in OpenAI native models with user additions from:
* - ROO_OPENAI_NATIVE_MODELS_JSON (JSON string)
* - ROO_OPENAI_NATIVE_MODELS_PATH or ~/.roo/models/openai-native.json
* Returns the merged models record.
*/
async function getMergedOpenAiNativeModelsOnHost(): Promise<Record<string, ModelInfo>> {
try {
// 1) Env JSON override
let extras: Record<string, any> = {}
const inline = process.env?.ROO_OPENAI_NATIVE_MODELS_JSON
if (inline) {
try {
const parsed = JSON.parse(inline)
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
extras = validateModelInfoRecord(parsed)
}
} catch {
// ignore malformed env json
}
}
// 2) File-based
if (Object.keys(extras).length === 0) {
const customPath =
process.env.ROO_OPENAI_NATIVE_MODELS_PATH ||
path.join(os.homedir(), ".roo", "models", "openai-native.json")
try {
const raw = await fs.readFile(customPath, "utf8")
const parsed = JSON.parse(raw)
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
extras = validateModelInfoRecord(parsed)
}
} catch {
// missing/invalid file: ignore
}
}
const merged = { ...openAiNativeModels, ...extras }
return merged as Record<string, ModelInfo>
} catch {
return openAiNativeModels as Record<string, ModelInfo>
}
}
/**
* Removes the target message and all subsequent messages
*/
@ -1031,7 +985,7 @@ export const webviewMessageHandler = async (
case "requestOpenAiNativeModels": {
// Return merged built-ins + user-defined from ~/.roo/models/openai-native.json
try {
const mergedModels = await getMergedOpenAiNativeModelsOnHost()
const mergedModels = getOpenAiNativeModels()
provider.postMessageToWebview({ type: "openAiNativeModels", openAiNativeModels: mergedModels })
} catch (error) {
console.error("Failed to load OpenAI Native models:", error)