mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-28 19:11:03 +08:00
feat(vscode): add 'Not set' option to autocomplete model picker
Aligns the autocomplete model selector with the small/subagent/per-mode
model selectors by exposing a 'Not set (use server default)' option.
Users who pick it follow future default-model changes automatically;
users who explicitly pin a model keep their selection.
Also runs a one-time migration that clears
`kilo-code.new.autocomplete.{provider,model}` when they exactly equal
the current `DEFAULT_AUTOCOMPLETE_MODEL` (Codestral via Kilo Gateway).
Many users have these stored only because it was the only thing visible
in the dropdown; without this they would stay pinned to the current
default and miss future improvements.
This commit is contained in:
committed by
Mark IJbema
parent
17e0b2d6b5
commit
f18a452082
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": minor
|
||||
---
|
||||
|
||||
Add a "Not set (use server default)" option to the autocomplete model picker so users can follow the recommended default automatically. Users who previously had the default model pinned only because it was the only thing visible in the dropdown are migrated to "Not set" once.
|
||||
@@ -850,13 +850,13 @@
|
||||
"mercury-next-edit"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Codestral via Kilo Gateway (default)",
|
||||
"Codestral via Kilo Gateway",
|
||||
"Mercury Edit 2 via Kilo Gateway",
|
||||
"Codestral via your connected Mistral provider API key",
|
||||
"Mercury Edit 2 (FIM) via your connected Inception provider API key",
|
||||
"Mercury Next Edit (multi-line edit predictions with jump-to-edit UX) via your connected Inception provider API key"
|
||||
],
|
||||
"description": "Model to use for inline autocomplete suggestions"
|
||||
"description": "Model to use for inline autocomplete suggestions. If unset, the recommended default is used."
|
||||
},
|
||||
"kilo-code.new.autocomplete.provider": {
|
||||
"type": "string",
|
||||
|
||||
@@ -3030,7 +3030,11 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
const { section, leaf } = buildSettingPath(key)
|
||||
if (section === "autocomplete" && !validAutocompleteSetting(leaf, value)) return
|
||||
const config = vscode.workspace.getConfiguration(`kilo-code.new${section ? `.${section}` : ""}`)
|
||||
await config.update(leaf, value, vscode.ConfigurationTarget.Global)
|
||||
// Normalize a webview-side clear to `undefined` so VS Code removes the
|
||||
// key from settings.json rather than persisting a literal `null`. This
|
||||
// lets the runtime fall back to the resolved default.
|
||||
const next = value === null ? undefined : value
|
||||
await config.update(leaf, next, vscode.ConfigurationTarget.Global)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,45 +33,31 @@ describe("autocomplete settings", () => {
|
||||
expect(buildAutocompleteSettingsMessage().settings.model).toBe("mercury-edit-2")
|
||||
})
|
||||
|
||||
it("does not infer direct provider from a bare model name when provider is unset", async () => {
|
||||
// Safety: a legacy `model` setting alone must never silently route to a
|
||||
// direct BYOK provider. Direct providers require an explicit `provider`.
|
||||
it("passes a bare model setting through unchanged so the webview can render it as-is", async () => {
|
||||
// The webview now distinguishes "no explicit setting" (null) from "user
|
||||
// picked something." We don't try to interpret a bare `model` here —
|
||||
// resolving it to a default happens at the runtime layer, not in the
|
||||
// settings message.
|
||||
state.set("model", "mercury-edit-2")
|
||||
const { buildAutocompleteSettingsMessage } = await import("../settings")
|
||||
|
||||
expect(buildAutocompleteSettingsMessage().settings.provider).toBe("kilo")
|
||||
expect(buildAutocompleteSettingsMessage().settings.model).toBe("mistralai/codestral-2508")
|
||||
expect(buildAutocompleteSettingsMessage().settings.provider).toBeNull()
|
||||
expect(buildAutocompleteSettingsMessage().settings.model).toBe("mercury-edit-2")
|
||||
})
|
||||
|
||||
it("defaults to codestral when no model is set", async () => {
|
||||
it("returns null for both keys when nothing is set (let the webview render 'Not set')", async () => {
|
||||
const { buildAutocompleteSettingsMessage } = await import("../settings")
|
||||
|
||||
expect(buildAutocompleteSettingsMessage().settings.provider).toBe("kilo")
|
||||
expect(buildAutocompleteSettingsMessage().settings.model).toBe("mistralai/codestral-2508")
|
||||
expect(buildAutocompleteSettingsMessage().settings.provider).toBeNull()
|
||||
expect(buildAutocompleteSettingsMessage().settings.model).toBeNull()
|
||||
})
|
||||
|
||||
it("defaults to codestral when stored model is no longer supported", async () => {
|
||||
it("preserves an unsupported stored model verbatim — runtime fallback handles resolution", async () => {
|
||||
state.set("model", "some/removed-model")
|
||||
const { buildAutocompleteSettingsMessage } = await import("../settings")
|
||||
|
||||
expect(buildAutocompleteSettingsMessage().settings.provider).toBe("kilo")
|
||||
expect(buildAutocompleteSettingsMessage().settings.model).toBe("mistralai/codestral-2508")
|
||||
})
|
||||
|
||||
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.provider).toBe("kilo")
|
||||
expect(buildAutocompleteSettingsMessage().settings.model).toBe("inception/mercury-edit-2")
|
||||
})
|
||||
|
||||
it("maps legacy inception/mercury-edit-2 to Kilo Gateway Mercury", async () => {
|
||||
state.set("model", "inception/mercury-edit-2")
|
||||
const { buildAutocompleteSettingsMessage } = await import("../settings")
|
||||
|
||||
expect(buildAutocompleteSettingsMessage().settings.provider).toBe("kilo")
|
||||
expect(buildAutocompleteSettingsMessage().settings.model).toBe("inception/mercury-edit-2")
|
||||
expect(buildAutocompleteSettingsMessage().settings.provider).toBeNull()
|
||||
expect(buildAutocompleteSettingsMessage().settings.model).toBe("some/removed-model")
|
||||
})
|
||||
|
||||
it("validates supported model updates", async () => {
|
||||
@@ -81,12 +67,20 @@ describe("autocomplete settings", () => {
|
||||
expect(validAutocompleteSetting("provider", "inception")).toBe(true)
|
||||
})
|
||||
|
||||
it("accepts null/undefined for provider and model so users can clear the setting", async () => {
|
||||
const { validAutocompleteSetting } = await import("../settings")
|
||||
|
||||
expect(validAutocompleteSetting("provider", null)).toBe(true)
|
||||
expect(validAutocompleteSetting("provider", undefined)).toBe(true)
|
||||
expect(validAutocompleteSetting("model", null)).toBe(true)
|
||||
expect(validAutocompleteSetting("model", undefined)).toBe(true)
|
||||
})
|
||||
|
||||
it("rejects unsupported autocomplete updates", async () => {
|
||||
const { validAutocompleteSetting } = await import("../settings")
|
||||
|
||||
expect(validAutocompleteSetting("model", "other/model")).toBe(false)
|
||||
expect(validAutocompleteSetting("provider", undefined)).toBe(false)
|
||||
expect(validAutocompleteSetting("provider", null)).toBe(false)
|
||||
expect(validAutocompleteSetting("provider", "openrouter")).toBe(false)
|
||||
})
|
||||
|
||||
it("rejects non-boolean toggle updates", async () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as vscode from "vscode"
|
||||
import { AutocompleteServiceManager } from "./AutocompleteServiceManager"
|
||||
import { ensureBackendForAutocomplete } from "./ensure-backend"
|
||||
import { migrateDefaultAutocompleteSettings } from "./migrate-default"
|
||||
import { nesLog } from "./next-edit/log"
|
||||
import { INLINE_COMPLETION_ACCEPTED_COMMAND as NEXT_EDIT_ACCEPTED_COMMAND } from "./next-edit/NextEditInlineCompletionProvider"
|
||||
import { chainNextPrediction } from "./next-edit/NextEditSuggestionManager"
|
||||
@@ -10,6 +11,10 @@ export const registerAutocompleteProvider = (
|
||||
context: vscode.ExtensionContext,
|
||||
connectionService: KiloConnectionService,
|
||||
) => {
|
||||
// Run before constructing the manager so its initial readSettings() sees
|
||||
// the cleared state and behaves as "Not set."
|
||||
void migrateDefaultAutocompleteSettings(context)
|
||||
|
||||
const autocompleteManager = new AutocompleteServiceManager(context, connectionService)
|
||||
context.subscriptions.push(autocompleteManager)
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import * as vscode from "vscode"
|
||||
import { DEFAULT_AUTOCOMPLETE_MODEL } from "../../shared/autocomplete-models"
|
||||
|
||||
const FLAG = "kilo.autocomplete.defaultClearMigrationV1"
|
||||
|
||||
/**
|
||||
* One-time migration: clear `kilo-code.new.autocomplete.{provider,model}` when
|
||||
* they exactly match the current `DEFAULT_AUTOCOMPLETE_MODEL`. Many users have
|
||||
* the default explicitly stored only because it was the only thing visible in
|
||||
* the dropdown — leaving it pinned would block them from picking up future
|
||||
* default changes (e.g. a switch to Mercury Next Edit) silently. After the
|
||||
* migration runs they show up as "Not set" and follow the resolved default.
|
||||
*
|
||||
* Users who picked a different model are untouched. The migration runs once
|
||||
* per machine and is gated on a globalState flag.
|
||||
*/
|
||||
export async function migrateDefaultAutocompleteSettings(context: vscode.ExtensionContext): Promise<void> {
|
||||
if (context.globalState.get<boolean>(FLAG)) return
|
||||
|
||||
const config = vscode.workspace.getConfiguration("kilo-code.new.autocomplete")
|
||||
const provider = config.get<string>("provider")
|
||||
const model = config.get<string>("model")
|
||||
|
||||
const matchesDefault =
|
||||
provider === DEFAULT_AUTOCOMPLETE_MODEL.providerID && model === DEFAULT_AUTOCOMPLETE_MODEL.modelID
|
||||
|
||||
if (matchesDefault) {
|
||||
await config.update("provider", undefined, vscode.ConfigurationTarget.Global)
|
||||
await config.update("model", undefined, vscode.ConfigurationTarget.Global)
|
||||
}
|
||||
|
||||
await context.globalState.update(FLAG, true)
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
import * as vscode from "vscode"
|
||||
import {
|
||||
getAutocompleteModel,
|
||||
validAutocompleteModel,
|
||||
validAutocompleteProvider,
|
||||
} from "../../shared/autocomplete-models"
|
||||
import { validAutocompleteModel, validAutocompleteProvider } from "../../shared/autocomplete-models"
|
||||
|
||||
type Message = {
|
||||
type: string
|
||||
@@ -22,15 +18,17 @@ export async function routeAutocompleteMessage(message: Message, post: Post): Pr
|
||||
|
||||
export function buildAutocompleteSettingsMessage() {
|
||||
const config = vscode.workspace.getConfiguration("kilo-code.new.autocomplete")
|
||||
const info = getAutocompleteModel(config.get<string>("provider"), config.get<string>("model"))
|
||||
// Pass through provider/model as-is (null when unset) so the webview can
|
||||
// distinguish "user hasn't picked" from "user picked the current default."
|
||||
// The runtime resolves null → DEFAULT_AUTOCOMPLETE_MODEL via getAutocompleteModel().
|
||||
return {
|
||||
type: "autocompleteSettingsLoaded" as const,
|
||||
settings: {
|
||||
enableAutoTrigger: config.get<boolean>("enableAutoTrigger", true),
|
||||
enableSmartInlineTaskKeybinding: config.get<boolean>("enableSmartInlineTaskKeybinding", false),
|
||||
enableChatAutocomplete: config.get<boolean>("enableChatAutocomplete", false),
|
||||
provider: info.providerID,
|
||||
model: info.modelID,
|
||||
provider: config.get<string>("provider") ?? null,
|
||||
model: config.get<string>("model") ?? null,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -46,10 +44,13 @@ export function watchAutocompleteConfig(post: Post): vscode.Disposable {
|
||||
|
||||
export function validAutocompleteSetting(key: string, value: unknown) {
|
||||
if (key === "model") {
|
||||
// Allow clearing back to the server-side default.
|
||||
if (value === null || value === undefined) return true
|
||||
return validAutocompleteModel(value)
|
||||
}
|
||||
|
||||
if (key === "provider") {
|
||||
if (value === null || value === undefined) return true
|
||||
return validAutocompleteProvider(value)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import { describe, it, expect, afterEach, beforeEach } from "bun:test"
|
||||
import * as vscode from "vscode"
|
||||
import { migrateDefaultAutocompleteSettings } from "../../src/services/autocomplete/migrate-default"
|
||||
import { DEFAULT_AUTOCOMPLETE_MODEL } from "../../src/shared/autocomplete-models"
|
||||
|
||||
type Stub = {
|
||||
getConfiguration: (section?: string) => {
|
||||
get: (key: string, fallback?: unknown) => unknown
|
||||
update: (key: string, value: unknown, target: unknown) => Promise<void>
|
||||
}
|
||||
}
|
||||
|
||||
const original = vscode.workspace.getConfiguration
|
||||
|
||||
function makeContext(initial: Record<string, unknown> = {}) {
|
||||
const flag = new Map<string, unknown>(Object.entries(initial))
|
||||
return {
|
||||
flag,
|
||||
context: {
|
||||
globalState: {
|
||||
get: <T>(key: string) => flag.get(key) as T | undefined,
|
||||
update: async (key: string, value: unknown) => {
|
||||
flag.set(key, value)
|
||||
},
|
||||
},
|
||||
} as any,
|
||||
}
|
||||
}
|
||||
|
||||
function stubConfig(state: Map<string, unknown>) {
|
||||
;(vscode.workspace as unknown as Stub).getConfiguration = (section?: string) => {
|
||||
if (section !== "kilo-code.new.autocomplete") {
|
||||
return { get: () => undefined, update: async () => {} }
|
||||
}
|
||||
return {
|
||||
get: (key: string, fallback?: unknown) => state.get(key) ?? fallback,
|
||||
update: async (key: string, value: unknown) => {
|
||||
if (value === undefined) state.delete(key)
|
||||
else state.set(key, value)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
;(vscode.workspace as unknown as Stub).getConfiguration = original as Stub["getConfiguration"]
|
||||
})
|
||||
|
||||
describe("migrateDefaultAutocompleteSettings", () => {
|
||||
let state: Map<string, unknown>
|
||||
|
||||
beforeEach(() => {
|
||||
state = new Map()
|
||||
stubConfig(state)
|
||||
})
|
||||
|
||||
it("clears provider/model when both equal the current default", async () => {
|
||||
state.set("provider", DEFAULT_AUTOCOMPLETE_MODEL.providerID)
|
||||
state.set("model", DEFAULT_AUTOCOMPLETE_MODEL.modelID)
|
||||
const { context, flag } = makeContext()
|
||||
|
||||
await migrateDefaultAutocompleteSettings(context)
|
||||
|
||||
expect(state.has("provider")).toBe(false)
|
||||
expect(state.has("model")).toBe(false)
|
||||
expect(flag.get("kilo.autocomplete.defaultClearMigrationV1")).toBe(true)
|
||||
})
|
||||
|
||||
it("leaves an explicitly chosen non-default model untouched", async () => {
|
||||
state.set("provider", "inception")
|
||||
state.set("model", "mercury-edit-2")
|
||||
const { context, flag } = makeContext()
|
||||
|
||||
await migrateDefaultAutocompleteSettings(context)
|
||||
|
||||
expect(state.get("provider")).toBe("inception")
|
||||
expect(state.get("model")).toBe("mercury-edit-2")
|
||||
expect(flag.get("kilo.autocomplete.defaultClearMigrationV1")).toBe(true)
|
||||
})
|
||||
|
||||
it("leaves a partial match untouched", async () => {
|
||||
state.set("provider", DEFAULT_AUTOCOMPLETE_MODEL.providerID)
|
||||
state.set("model", "inception/mercury-edit-2")
|
||||
const { context } = makeContext()
|
||||
|
||||
await migrateDefaultAutocompleteSettings(context)
|
||||
|
||||
expect(state.get("provider")).toBe(DEFAULT_AUTOCOMPLETE_MODEL.providerID)
|
||||
expect(state.get("model")).toBe("inception/mercury-edit-2")
|
||||
})
|
||||
|
||||
it("only runs once per machine", async () => {
|
||||
state.set("provider", DEFAULT_AUTOCOMPLETE_MODEL.providerID)
|
||||
state.set("model", DEFAULT_AUTOCOMPLETE_MODEL.modelID)
|
||||
const { context } = makeContext({ "kilo.autocomplete.defaultClearMigrationV1": true })
|
||||
|
||||
await migrateDefaultAutocompleteSettings(context)
|
||||
|
||||
// Setting was preserved — second run is a no-op.
|
||||
expect(state.get("provider")).toBe(DEFAULT_AUTOCOMPLETE_MODEL.providerID)
|
||||
expect(state.get("model")).toBe(DEFAULT_AUTOCOMPLETE_MODEL.modelID)
|
||||
})
|
||||
|
||||
it("sets the flag even when nothing needed clearing", async () => {
|
||||
const { context, flag } = makeContext()
|
||||
|
||||
await migrateDefaultAutocompleteSettings(context)
|
||||
|
||||
expect(flag.get("kilo.autocomplete.defaultClearMigrationV1")).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,85 @@
|
||||
import { describe, it, expect, afterEach, beforeEach } from "bun:test"
|
||||
import * as vscode from "vscode"
|
||||
import { buildAutocompleteSettingsMessage, validAutocompleteSetting } from "../../src/services/autocomplete/settings"
|
||||
|
||||
type Stub = {
|
||||
getConfiguration: (section?: string) => {
|
||||
get: <T>(key: string, fallback?: T) => T | undefined
|
||||
update?: (key: string, value: unknown) => Promise<void>
|
||||
}
|
||||
}
|
||||
|
||||
const original = vscode.workspace.getConfiguration
|
||||
|
||||
function stubConfig(state: Map<string, unknown>) {
|
||||
;(vscode.workspace as unknown as Stub).getConfiguration = (section?: string) => {
|
||||
if (section !== "kilo-code.new.autocomplete") {
|
||||
return { get: <T>(_key: string, fallback?: T) => fallback }
|
||||
}
|
||||
return {
|
||||
get: <T>(key: string, fallback?: T) => (state.has(key) ? (state.get(key) as T) : fallback),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
;(vscode.workspace as unknown as Stub).getConfiguration = original as Stub["getConfiguration"]
|
||||
})
|
||||
|
||||
describe("buildAutocompleteSettingsMessage", () => {
|
||||
let state: Map<string, unknown>
|
||||
|
||||
beforeEach(() => {
|
||||
state = new Map()
|
||||
stubConfig(state)
|
||||
})
|
||||
|
||||
it("returns null for both keys when nothing is set so the webview renders 'Not set'", () => {
|
||||
const msg = buildAutocompleteSettingsMessage()
|
||||
|
||||
expect(msg.settings.provider).toBeNull()
|
||||
expect(msg.settings.model).toBeNull()
|
||||
})
|
||||
|
||||
it("passes an explicit BYOK selection through verbatim", () => {
|
||||
state.set("provider", "inception")
|
||||
state.set("model", "mercury-edit-2")
|
||||
|
||||
const msg = buildAutocompleteSettingsMessage()
|
||||
|
||||
expect(msg.settings.provider).toBe("inception")
|
||||
expect(msg.settings.model).toBe("mercury-edit-2")
|
||||
})
|
||||
|
||||
it("does not coerce a bare model setting to a default — let the webview see what was stored", () => {
|
||||
state.set("model", "mercury-edit-2")
|
||||
|
||||
const msg = buildAutocompleteSettingsMessage()
|
||||
|
||||
expect(msg.settings.provider).toBeNull()
|
||||
expect(msg.settings.model).toBe("mercury-edit-2")
|
||||
})
|
||||
})
|
||||
|
||||
describe("validAutocompleteSetting", () => {
|
||||
it("accepts null/undefined for provider and model so the user can clear back to the default", () => {
|
||||
expect(validAutocompleteSetting("provider", null)).toBe(true)
|
||||
expect(validAutocompleteSetting("provider", undefined)).toBe(true)
|
||||
expect(validAutocompleteSetting("model", null)).toBe(true)
|
||||
expect(validAutocompleteSetting("model", undefined)).toBe(true)
|
||||
})
|
||||
|
||||
it("accepts known providers and models", () => {
|
||||
expect(validAutocompleteSetting("provider", "inception")).toBe(true)
|
||||
expect(validAutocompleteSetting("model", "mercury-edit-2")).toBe(true)
|
||||
})
|
||||
|
||||
it("rejects unknown providers and models", () => {
|
||||
expect(validAutocompleteSetting("provider", "openrouter")).toBe(false)
|
||||
expect(validAutocompleteSetting("model", "gpt-5")).toBe(false)
|
||||
})
|
||||
|
||||
it("rejects non-boolean toggle updates", () => {
|
||||
expect(validAutocompleteSetting("enableAutoTrigger", "true")).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -5,7 +5,6 @@ import { useLanguage } from "../../context/language"
|
||||
import { useProvider } from "../../context/provider"
|
||||
import { useSession } from "../../context/session"
|
||||
import { parseModelString } from "../../../../src/shared/provider-model"
|
||||
import { DEFAULT_AUTOCOMPLETE_MODEL } from "../../../../src/shared/autocomplete-models"
|
||||
import { ModelSelectorBase } from "../shared/ModelSelector"
|
||||
import { ThinkingSelectorBase } from "../shared/ThinkingSelector"
|
||||
import SettingsRow from "./SettingsRow"
|
||||
@@ -17,9 +16,14 @@ const ModelsTab: Component = () => {
|
||||
const provider = useProvider()
|
||||
const session = useSession()
|
||||
|
||||
const autocompleteProvider = () =>
|
||||
String(settings()["autocomplete.provider"] ?? DEFAULT_AUTOCOMPLETE_MODEL.providerID)
|
||||
const autocompleteModel = () => String(settings()["autocomplete.model"] ?? DEFAULT_AUTOCOMPLETE_MODEL.modelID)
|
||||
const autocompleteProvider = () => {
|
||||
const v = settings()["autocomplete.provider"]
|
||||
return typeof v === "string" ? v : undefined
|
||||
}
|
||||
const autocompleteModel = () => {
|
||||
const v = settings()["autocomplete.model"]
|
||||
return typeof v === "string" ? v : undefined
|
||||
}
|
||||
|
||||
function handleModelSelect(configKey: "model" | "small_model") {
|
||||
return (providerID: string, modelID: string) => {
|
||||
@@ -73,7 +77,13 @@ const ModelsTab: Component = () => {
|
||||
}
|
||||
|
||||
function handleAutocompleteModelSelect(providerID: string, modelID: string) {
|
||||
if (!providerID || !modelID) return
|
||||
if (!providerID || !modelID) {
|
||||
// Clearing both keys reverts to the resolved server-side default. Users
|
||||
// who pick "Not set" follow future default changes automatically.
|
||||
updateSetting("autocomplete.provider", null)
|
||||
updateSetting("autocomplete.model", null)
|
||||
return
|
||||
}
|
||||
updateSetting("autocomplete.provider", providerID)
|
||||
updateSetting("autocomplete.model", modelID)
|
||||
}
|
||||
@@ -137,6 +147,8 @@ const ModelsTab: Component = () => {
|
||||
placement="bottom-start"
|
||||
models={AUTOCOMPLETE_SELECTOR_MODELS}
|
||||
favorites={false}
|
||||
allowClear
|
||||
clearLabel={language.t("settings.providers.notSet")}
|
||||
/>
|
||||
</SettingsRow>
|
||||
</Card>
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { AUTOCOMPLETE_MODELS, getAutocompleteModel } from "../../../../src/shared/autocomplete-models"
|
||||
import type { EnrichedModel } from "../../context/provider"
|
||||
|
||||
/**
|
||||
* Resolve the (provider, model) pair to the dropdown's value. Returns
|
||||
* `null` when neither is set so the selector renders the "Not set" (clear)
|
||||
* state via `allowClear`. The runtime resolves unset values to
|
||||
* `DEFAULT_AUTOCOMPLETE_MODEL` separately.
|
||||
*/
|
||||
export function getAutocompleteSelection(provider?: string, modelID?: string) {
|
||||
if (!provider && !modelID) return null
|
||||
const model = getAutocompleteModel(provider, modelID)
|
||||
return { providerID: model.providerID, modelID: model.modelID }
|
||||
}
|
||||
|
||||
@@ -336,8 +336,10 @@ export interface AutocompleteSettingsLoadedMessage {
|
||||
enableAutoTrigger: boolean
|
||||
enableSmartInlineTaskKeybinding: boolean
|
||||
enableChatAutocomplete: boolean
|
||||
provider: string
|
||||
model: string
|
||||
/** `null` means "no explicit setting — use the resolved default." */
|
||||
provider: string | null
|
||||
/** `null` means "no explicit setting — use the resolved default." */
|
||||
model: string | null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user