From 25e89db23382f8dadd45db3f015d05ef5fca4fbe Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Mon, 25 May 2026 17:16:00 +0200 Subject: [PATCH] refactor(gateway): own autocomplete model catalog --- packages/kilo-gateway/src/autocomplete.ts | 76 +++++++++++++++ packages/kilo-gateway/src/index.ts | 6 ++ packages/kilo-gateway/src/server/fim.ts | 12 ++- packages/kilo-gateway/test/fim.test.ts | 19 +++- packages/kilo-vscode/package.json | 6 +- .../autocomplete/__tests__/settings.spec.ts | 8 +- .../src/shared/autocomplete-models.ts | 92 ++----------------- 7 files changed, 118 insertions(+), 101 deletions(-) create mode 100644 packages/kilo-gateway/src/autocomplete.ts diff --git a/packages/kilo-gateway/src/autocomplete.ts b/packages/kilo-gateway/src/autocomplete.ts new file mode 100644 index 00000000000..dded9628edb --- /dev/null +++ b/packages/kilo-gateway/src/autocomplete.ts @@ -0,0 +1,76 @@ +export interface AutocompleteModelDef { + /** Stable setting value. */ + readonly id: string + /** Model ID displayed under the selector provider group. */ + readonly modelID: string + /** Human-readable label shown in settings. */ + readonly label: string + /** Provider ID used by the selector group. */ + readonly providerID: string + /** Provider display name for status bar / telemetry. */ + readonly provider: string + /** Full model ID sent to the FIM API. */ + readonly requestModel: string + /** Provider key to use for direct BYOK FIM. Empty means Kilo Gateway. */ + readonly directProvider?: "mistral" | "inception" + /** FIM request temperature. */ + readonly temperature: number +} + +const models: AutocompleteModelDef[] = [ + { + id: "kilo/mistralai/codestral-2508", + modelID: "mistralai/codestral-2508", + label: "Codestral", + providerID: "kilo", + provider: "Kilo Gateway", + requestModel: "mistralai/codestral-2508", + temperature: 0.2, + }, + { + id: "kilo/inception/mercury-edit-2", + modelID: "inception/mercury-edit-2", + label: "Mercury Edit 2", + providerID: "kilo", + provider: "Kilo Gateway", + requestModel: "inception/mercury-edit-2", + temperature: 0, + }, + { + id: "mistral/codestral-2508", + modelID: "codestral-2508", + label: "Codestral", + providerID: "mistral", + provider: "Mistral", + requestModel: "codestral-2508", + directProvider: "mistral", + temperature: 0.2, + }, + { + id: "inception/mercury-edit-2", + modelID: "mercury-edit-2", + label: "Mercury Edit 2", + providerID: "inception", + provider: "Inception", + requestModel: "mercury-edit-2", + directProvider: "inception", + temperature: 0, + }, +] + +export const AUTOCOMPLETE_MODELS: readonly AutocompleteModelDef[] = models + +export const DEFAULT_AUTOCOMPLETE_MODEL: AutocompleteModelDef = models[0]! + +const aliases: Record = { + "mistralai/codestral-2508": "kilo/mistralai/codestral-2508", + "inception/mercury-edit": "kilo/inception/mercury-edit-2", +} + +export function getAutocompleteModel(id: string): AutocompleteModelDef { + const resolved = aliases[id] ?? id + for (const m of models) { + if (m.id === resolved) return m + } + return DEFAULT_AUTOCOMPLETE_MODEL +} diff --git a/packages/kilo-gateway/src/index.ts b/packages/kilo-gateway/src/index.ts index e84cb0c7dcf..948ff711624 100644 --- a/packages/kilo-gateway/src/index.ts +++ b/packages/kilo-gateway/src/index.ts @@ -41,6 +41,12 @@ export { type KiloEmbeddingModelCatalog, } from "./api/embedding-models.js" export { resolveKiloGatewayBaseUrl, resolveKiloOpenRouterBaseUrl } from "./api/url.js" +export { + AUTOCOMPLETE_MODELS, + DEFAULT_AUTOCOMPLETE_MODEL, + getAutocompleteModel, + type AutocompleteModelDef, +} from "./autocomplete.js" export { fetchOrganizationModes, clearModesCache, diff --git a/packages/kilo-gateway/src/server/fim.ts b/packages/kilo-gateway/src/server/fim.ts index b668646197d..800df5240a6 100644 --- a/packages/kilo-gateway/src/server/fim.ts +++ b/packages/kilo-gateway/src/server/fim.ts @@ -1,4 +1,5 @@ import { HEADER_FEATURE, KILO_API_BASE } from "../api/constants.js" +import { getAutocompleteModel } from "../autocomplete.js" import { buildKiloHeaders } from "../headers.js" type Auth = any @@ -18,13 +19,14 @@ const CODESTRAL_FIM_URL = "https://codestral.mistral.ai/v1/fim/completions" const INCEPTION_FIM_URL = "https://api.inceptionlabs.ai/v1/fim/completions" export function resolveFimTarget(model?: string): FimTarget { - if (model === "mistral/codestral-2508") { - return { provider: "mistral", model: "codestral-2508", urls: [MISTRAL_FIM_URL, CODESTRAL_FIM_URL] } + const info = getAutocompleteModel(model ?? "") + if (info.directProvider === "mistral") { + return { provider: "mistral", model: info.requestModel, urls: [MISTRAL_FIM_URL, CODESTRAL_FIM_URL] } } - if (model === "inception-direct/mercury-edit-2") { - return { provider: "inception", model: "mercury-edit-2", urls: [INCEPTION_FIM_URL] } + if (info.directProvider === "inception") { + return { provider: "inception", model: info.requestModel, urls: [INCEPTION_FIM_URL] } } - return { provider: "kilo", model: model ?? "mistralai/codestral-2501", urls: [KILO_FIM_URL] } + return { provider: "kilo", model: info.requestModel, urls: [KILO_FIM_URL] } } async function getProxyAuth(Auth: Auth) { diff --git a/packages/kilo-gateway/test/fim.test.ts b/packages/kilo-gateway/test/fim.test.ts index e90315311a5..7c968603363 100644 --- a/packages/kilo-gateway/test/fim.test.ts +++ b/packages/kilo-gateway/test/fim.test.ts @@ -3,12 +3,12 @@ import { resolveFimTarget } from "../src/server/fim" describe("FIM target resolution", () => { test("keeps gateway autocomplete models on Kilo Gateway", () => { - expect(resolveFimTarget("mistralai/codestral-2508")).toEqual({ + expect(resolveFimTarget("kilo/mistralai/codestral-2508")).toEqual({ provider: "kilo", model: "mistralai/codestral-2508", urls: ["https://api.kilo.ai/api/fim/completions"], }) - expect(resolveFimTarget("inception/mercury-edit-2")).toEqual({ + expect(resolveFimTarget("kilo/inception/mercury-edit-2")).toEqual({ provider: "kilo", model: "inception/mercury-edit-2", urls: ["https://api.kilo.ai/api/fim/completions"], @@ -21,10 +21,23 @@ describe("FIM target resolution", () => { model: "codestral-2508", urls: ["https://api.mistral.ai/v1/fim/completions", "https://codestral.mistral.ai/v1/fim/completions"], }) - expect(resolveFimTarget("inception-direct/mercury-edit-2")).toEqual({ + expect(resolveFimTarget("inception/mercury-edit-2")).toEqual({ provider: "inception", model: "mercury-edit-2", urls: ["https://api.inceptionlabs.ai/v1/fim/completions"], }) }) + + test("maps legacy gateway IDs to explicit Kilo Gateway targets", () => { + expect(resolveFimTarget("mistralai/codestral-2508")).toEqual({ + provider: "kilo", + model: "mistralai/codestral-2508", + urls: ["https://api.kilo.ai/api/fim/completions"], + }) + expect(resolveFimTarget("inception/mercury-edit")).toEqual({ + provider: "kilo", + model: "inception/mercury-edit-2", + urls: ["https://api.kilo.ai/api/fim/completions"], + }) + }) }) diff --git a/packages/kilo-vscode/package.json b/packages/kilo-vscode/package.json index 082adf9bd71..ab2cfb49033 100644 --- a/packages/kilo-vscode/package.json +++ b/packages/kilo-vscode/package.json @@ -752,10 +752,10 @@ "kilo-code.new.autocomplete.model": { "type": "string", "enum": [ - "mistralai/codestral-2508", - "inception/mercury-edit-2", + "kilo/mistralai/codestral-2508", + "kilo/inception/mercury-edit-2", "mistral/codestral-2508", - "inception-direct/mercury-edit-2" + "inception/mercury-edit-2" ], "enumDescriptions": [ "Codestral via Kilo Gateway (default)", diff --git a/packages/kilo-vscode/src/services/autocomplete/__tests__/settings.spec.ts b/packages/kilo-vscode/src/services/autocomplete/__tests__/settings.spec.ts index 5552d8c9fa6..4aa3f1e5208 100644 --- a/packages/kilo-vscode/src/services/autocomplete/__tests__/settings.spec.ts +++ b/packages/kilo-vscode/src/services/autocomplete/__tests__/settings.spec.ts @@ -34,21 +34,21 @@ describe("autocomplete settings", () => { it("defaults to codestral when no model is set", async () => { const { buildAutocompleteSettingsMessage } = await import("../settings") - expect(buildAutocompleteSettingsMessage().settings.model).toBe("mistralai/codestral-2508") + expect(buildAutocompleteSettingsMessage().settings.model).toBe("kilo/mistralai/codestral-2508") }) it("defaults to codestral when stored model is no longer supported", async () => { state.set("model", "some/removed-model") const { buildAutocompleteSettingsMessage } = await import("../settings") - expect(buildAutocompleteSettingsMessage().settings.model).toBe("mistralai/codestral-2508") + expect(buildAutocompleteSettingsMessage().settings.model).toBe("kilo/mistralai/codestral-2508") }) - it("maps legacy inception/mercury-edit to inception/mercury-edit-2", async () => { + it("maps legacy inception/mercury-edit to Kilo Gateway Mercury", async () => { state.set("model", "inception/mercury-edit") const { buildAutocompleteSettingsMessage } = await import("../settings") - expect(buildAutocompleteSettingsMessage().settings.model).toBe("inception/mercury-edit-2") + expect(buildAutocompleteSettingsMessage().settings.model).toBe("kilo/inception/mercury-edit-2") }) it("validates supported model updates", async () => { diff --git a/packages/kilo-vscode/src/shared/autocomplete-models.ts b/packages/kilo-vscode/src/shared/autocomplete-models.ts index 23a805b6b0a..649987df648 100644 --- a/packages/kilo-vscode/src/shared/autocomplete-models.ts +++ b/packages/kilo-vscode/src/shared/autocomplete-models.ts @@ -1,86 +1,6 @@ -/** - * Single source of truth for autocomplete FIM model definitions. - * - * Shared between extension code (src/) and webview code (webview-ui/). - * When adding a new model, update ONLY this file and package.json's - * `kilo-code.new.autocomplete.model` enum. - */ - -export interface AutocompleteModelDef { - /** Stable setting value. */ - readonly id: string - /** Model ID displayed under the selector provider group. */ - readonly modelID: string - /** Human-readable label shown in the settings dropdown */ - readonly label: string - /** Provider ID used by the selector group. */ - readonly providerID: string - /** Provider display name for status bar / telemetry */ - readonly provider: string - /** Full model ID sent to the FIM API. */ - readonly requestModel: string - /** Provider key to use for direct BYOK FIM. Empty means Kilo Gateway. */ - readonly directProvider?: "mistral" | "inception" - /** FIM request temperature */ - readonly temperature: number -} - -const models: AutocompleteModelDef[] = [ - { - id: "mistralai/codestral-2508", - modelID: "mistralai/codestral-2508", - label: "Codestral", - providerID: "kilo", - provider: "Kilo Gateway", - requestModel: "mistralai/codestral-2508", - temperature: 0.2, - }, - { - id: "inception/mercury-edit-2", - modelID: "inception/mercury-edit-2", - label: "Mercury Edit 2", - providerID: "kilo", - provider: "Kilo Gateway", - requestModel: "inception/mercury-edit-2", - temperature: 0, - }, - { - id: "mistral/codestral-2508", - modelID: "codestral-2508", - label: "Codestral", - providerID: "mistral", - provider: "Mistral", - requestModel: "codestral-2508", - directProvider: "mistral", - temperature: 0.2, - }, - { - id: "inception-direct/mercury-edit-2", - modelID: "mercury-edit-2", - label: "Mercury Edit 2", - providerID: "inception", - provider: "Inception", - requestModel: "mercury-edit-2", - directProvider: "inception", - temperature: 0, - }, -] - -export const AUTOCOMPLETE_MODELS: readonly AutocompleteModelDef[] = models - -export const DEFAULT_AUTOCOMPLETE_MODEL: AutocompleteModelDef = models[0]! - -// Map inception/mercury-edit to inception/mercury-edit-2 so users who -// already have the old id saved in settings.json keep working without a -// silent fallback to Codestral. Not exposed in the dropdown. -const aliases: Record = { - "inception/mercury-edit": "inception/mercury-edit-2", -} - -export function getAutocompleteModel(id: string): AutocompleteModelDef { - const resolved = aliases[id] ?? id - for (const m of models) { - if (m.id === resolved) return m - } - return DEFAULT_AUTOCOMPLETE_MODEL -} +export { + AUTOCOMPLETE_MODELS, + DEFAULT_AUTOCOMPLETE_MODEL, + getAutocompleteModel, + type AutocompleteModelDef, +} from "@kilocode/kilo-gateway"