import { existsSync, mkdirSync } from "fs"; import { readFile, writeFile } from "fs/promises"; import { dirname } from "path"; import type { RoutstrdConfig } from "../utils/config"; import type { IntegrationConfig, RoutstrModel } from "./registry"; import { callDaemon, getDaemonBaseUrl } from "../utils/daemon-client"; const OPENCODE_SMALL_MODEL = "routstr/minimax-m2.5"; export async function installOpencodeIntegration( config: RoutstrdConfig, apiKey: string, integrationConfig: IntegrationConfig, ): Promise { const { name, configPath } = integrationConfig; console.log("\nInstalling routstr models in opencode.json..."); console.log(`Using API key for ${name}`); const baseUrl = getDaemonBaseUrl(config); let opencodeConfig: { provider?: Record; }>; small_model?: string; }; try { if (existsSync(configPath)) { const content = await readFile(configPath, "utf-8"); opencodeConfig = JSON.parse(content); } else { opencodeConfig = { provider: {} }; } } catch (error) { console.error(`Failed to read or parse ${configPath}; leaving it unchanged:`, error); return; } if (!opencodeConfig.provider) { opencodeConfig.provider = {}; } try { mkdirSync(dirname(configPath), { recursive: true }); const data = await callDaemon("/models"); const models = (data.output as { models: RoutstrModel[] } | undefined)?.models || []; if (models.length === 0) { console.log("No models found from routstr daemon."); return; } const modelsObj: Record = {}; for (const model of models) { modelsObj[model.id] = { name: model.name || model.id }; } opencodeConfig.provider["routstr"] = { npm: "@ai-sdk/openai-compatible", name: "routstr", options: { baseURL: `${baseUrl}/`, apiKey, includeUsage: true, }, models: modelsObj, }; opencodeConfig.small_model = OPENCODE_SMALL_MODEL; await writeFile(configPath, JSON.stringify(opencodeConfig, null, 2)); console.log(`Added "routstr" provider with ${models.length} models to opencode.json`); } catch (error) { console.error("Failed to install models in opencode.json:", error); } }