Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions packages/kilo-vscode/tests/unit/model-selector-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,42 @@ describe("buildTriggerLabel", () => {
const raw = { providerID: "", modelID: "claude-3-5-sonnet" }
expect(buildTriggerLabel(undefined, undefined, undefined, raw, false, "", true, labels)).toBe("Select model")
})

it("returns placeholder when allowClear, no selection, and placeholder is provided", () => {
expect(
buildTriggerLabel(
undefined,
undefined,
undefined,
null,
true,
"Not set",
true,
labels,
"kilo-auto/small (default)",
),
).toBe("kilo-auto/small (default)")
})

it("returns clearLabel when allowClear, no selection, and no placeholder", () => {
expect(buildTriggerLabel(undefined, undefined, undefined, null, true, "Not set", true, labels, undefined)).toBe(
"Not set",
)
})

it("prefers resolved name over placeholder when value is selected", () => {
expect(
buildTriggerLabel(
"Claude Haiku",
"anthropic",
"Anthropic",
null,
true,
"Not set",
true,
labels,
"kilo-auto/small (default)",
),
).toBe("Anthropic / Claude Haiku")
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ const ModelsTab: Component = () => {
onSelect={handleModelSelect("small_model")}
placement="bottom-start"
allowClear
clearLabel={language.t("settings.providers.notSet")}
clearLabel={language.t("settings.providers.smallModel.notSet")}
includeAutoSmall
placeholder={language.t("settings.providers.smallModel.default")}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Unset small model is not always kilo-auto/small

This placeholder (and the matching clear label above) describes small_model = null as a fixed fallback, but the backend does not work that way. Provider.getSmallModel(defaultModel.providerID) first tries a provider-specific small model, and only falls back to kilo-auto/small in some Kilo paths. Users with Anthropic/OpenAI defaults will see misleading copy here.

/>
</SettingsRow>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export interface ModelSelectorBaseProps {
clearLabel?: string
/** Include the kilo-auto/small model in the list — defaults to false */
includeAutoSmall?: boolean
/** Placeholder shown on the trigger when no value is selected (e.g. default fallback model) */
placeholder?: string
}

export const ModelSelectorBase: Component<ModelSelectorBaseProps> = (props) => {
Expand Down Expand Up @@ -294,8 +296,11 @@ export const ModelSelectorBase: Component<ModelSelectorBaseProps> = (props) => {
noProviders: language.t("dialog.model.noProviders"),
notSet: language.t("dialog.model.notSet"),
},
props.placeholder,
)

const isPlaceholder = () => !props.value?.providerID && !!props.placeholder

return (
<PopupSelector
expanded={expanded()}
Expand All @@ -316,7 +321,12 @@ export const ModelSelectorBase: Component<ModelSelectorBaseProps> = (props) => {
}}
trigger={
<>
<span class="model-selector-trigger-label">{triggerLabel()}</span>
<span
class="model-selector-trigger-label"
style={isPlaceholder() ? { opacity: "0.6", "font-style": "italic" } : {}}
>
{triggerLabel()}
</span>
<svg class="model-selector-trigger-chevron" width="10" height="10" viewBox="0 0 16 16" fill="currentColor">
<path d="M8 4l4 5H4l4-5z" />
</svg>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export function buildTriggerLabel(
clearLabel: string,
hasProviders: boolean,
labels: { select: string; noProviders: string; notSet: string },
placeholder?: string,
): string {
if (resolvedName) {
if (providerID === KILO_GATEWAY_ID) return stripSubProviderPrefix(resolvedName)
Expand All @@ -57,6 +58,6 @@ export function buildTriggerLabel(
if (raw?.providerID && raw?.modelID) {
return raw.providerID === KILO_GATEWAY_ID ? raw.modelID : `${raw.providerID} / ${raw.modelID}`
}
if (allowClear) return clearLabel || labels.notSet
if (allowClear) return placeholder || clearLabel || labels.notSet
return hasProviders ? labels.select : labels.noProviders
}
2 changes: 2 additions & 0 deletions packages/kilo-vscode/webview-ui/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,8 @@ export const dict = {
"settings.providers.smallModel.title": "Small Model",
"settings.providers.smallModel.description":
"Lightweight model for title generation, commit message generation, prompt enhancement, and other quick tasks",
"settings.providers.smallModel.default": "kilo-auto/small (default)",
"settings.providers.smallModel.notSet": "Not set (use kilo-auto/small)",
"settings.providers.modeModels": "Model per Mode",
"settings.providers.modeModels.description":
"Override the default model for specific modes. If not set, the global default model is used.",
Expand Down
Loading