Skip to content
Merged
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
6 changes: 6 additions & 0 deletions .changeset/custom-provider-edit-screen-improvements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"kilo-code": patch
"@kilocode/kilo-ui": patch
---

Improve custom provider edit dialog layout, make advanced configuration action prominent, and add bulk toggle buttons for reasoning and image modalities across all models.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions packages/kilo-ui/src/components/dialog.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,24 @@
border: 1px solid var(--border-weak-base);
}

&[data-size="large"] [data-slot="dialog-container"] {
width: min(calc(100vw - 32px), 800px);
height: min(calc(100vh - 32px), 720px);
}

&[data-size="large"] [data-slot="dialog-content"] {
max-width: 800px;
}

&[data-size="x-large"] [data-slot="dialog-container"] {
width: min(calc(100vw - 32px), 980px);
height: min(calc(100vh - 32px), 800px);
}

&[data-size="x-large"] [data-slot="dialog-content"] {
max-width: 980px;
}

[data-slot="dialog-header"] {
font-size: var(--kilo-font-size-14);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,4 +292,20 @@ describe("validateCustomProvider – variant name validation", () => {
const saved = out.result!.config.models["model-1"] as Record<string, unknown>
expect(saved.modalities).toEqual({ input: ["text", "audio", "video", "pdf"], output: ["text", "audio"] })
})

it("handles multiple models with reasoning and images toggled", () => {
const form = base()
form.models = [
{ id: "m1", name: "Model 1", reasoning: true, supportsImages: true, modalities: {}, variants: [] },
{ id: "m2", name: "Model 2", reasoning: true, supportsImages: false, modalities: {}, variants: [] },
]
const out = validateCustomProvider(args(form))
expect(out.result).toBeDefined()
const m1 = out.result!.config.models["m1"] as Record<string, unknown>
const m2 = out.result!.config.models["m2"] as Record<string, unknown>
expect(m1.reasoning).toBe(true)
expect(m1.modalities).toEqual({ input: ["text", "image"] })
expect(m2.reasoning).toBe(true)
expect(m2.modalities).toBeUndefined()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,18 @@ const CustomProviderDialog = (props: CustomProviderDialogProps) => {
setErrors("models", (v) => v.filter((_, i) => i !== index))
}

function toggleAllReasoning() {
const all = form.models.length > 0 && form.models.every((m) => m.reasoning)
const target = !all
form.models.forEach((_, i) => setForm("models", i, "reasoning", target))
}

function toggleAllImages() {
const all = form.models.length > 0 && form.models.every((m) => m.supportsImages)
const target = !all
form.models.forEach((_, i) => setForm("models", i, "supportsImages", target))
}

function addHeader() {
setForm("headers", (v) => [...v, { key: "", value: "" }])
setErrors("headers", (v) => [...v, {}])
Expand Down Expand Up @@ -515,6 +527,7 @@ const CustomProviderDialog = (props: CustomProviderDialogProps) => {

return (
<Dialog
size="large"
Comment thread
chrarnoldus marked this conversation as resolved.
title={
<IconButton
tabIndex={-1}
Expand All @@ -530,13 +543,15 @@ const CustomProviderDialog = (props: CustomProviderDialogProps) => {
style={{
display: "flex",
"flex-direction": "column",
gap: "24px",
padding: "0 10px 12px 10px",
gap: "20px",
padding: "0 16px 16px 16px",
"overflow-y": "auto",
"max-height": "60vh",
flex: 1,
width: "100%",
"box-sizing": "border-box",
}}
>
<div style={{ padding: "0 10px", display: "flex", gap: "16px", "align-items": "center" }}>
<div style={{ display: "flex", gap: "16px", "align-items": "center" }}>
<ProviderIcon id="synthetic" width={20} height={20} />
<div
style={{ "font-size": "var(--kilo-font-size-16)", "font-weight": "500", color: "var(--vscode-foreground)" }}
Expand All @@ -545,36 +560,35 @@ const CustomProviderDialog = (props: CustomProviderDialogProps) => {
</div>
</div>

<form
onSubmit={save}
style={{ padding: "0 10px 24px 10px", display: "flex", "flex-direction": "column", gap: "24px" }}
>
<div style={{ "font-size": "var(--kilo-font-size-14)", color: "var(--text-base)" }}>
{language.t("provider.custom.description.prefix")}
<a
href="https://kilo.ai/docs/ai-providers#custom-provider"
onClick={(e) => {
e.preventDefault()
vscode.postMessage({
type: "openExternal",
url: "https://kilo.ai/docs/ai-providers#custom-provider",
})
}}
>
{language.t("provider.custom.description.link")}
</a>
{language.t("provider.custom.description.suffix")}
<form onSubmit={save} style={{ display: "flex", "flex-direction": "column", gap: "20px" }}>
<div style={{ display: "flex", "flex-direction": "column", gap: "10px" }}>
<div style={{ "font-size": "var(--kilo-font-size-14)", color: "var(--text-base)" }}>
{language.t("provider.custom.description.prefix")}
<a
href="https://kilo.ai/docs/ai-providers#custom-provider"
onClick={(e) => {
e.preventDefault()
vscode.postMessage({
type: "openExternal",
url: "https://kilo.ai/docs/ai-providers#custom-provider",
})
}}
>
{language.t("provider.custom.description.link")}
</a>
{language.t("provider.custom.description.suffix")}
</div>
<Show when={editing()}>
<div style={{ "margin-top": "8px" }}>
<a
href="#"
onClick={(e) => {
e.preventDefault()
vscode.postMessage(configMessage("global", language.t))
}}
<div>
<Button
type="button"
variant="secondary"
size="small"
icon="edit"
onClick={() => vscode.postMessage(configMessage("global", language.t))}
>
{language.t("provider.custom.edit.advanced")}
</a>
</Button>
</div>
</Show>
</div>
Expand Down Expand Up @@ -651,19 +665,49 @@ const CustomProviderDialog = (props: CustomProviderDialogProps) => {

{/* Models */}
<div style={{ display: "flex", "flex-direction": "column", gap: "12px" }}>
<div style={{ display: "flex", "align-items": "center", gap: "8px" }}>
<label
style={{
"font-size": "var(--kilo-font-size-12)",
"font-weight": "500",
color: "var(--text-weak-base)",
}}
>
{language.t("provider.custom.models.label")}
</label>
<Show when={fetching()}>
<Spinner style={{ width: "12px", height: "12px" }} />
</Show>
<div
style={{
display: "flex",
"justify-content": "space-between",
"align-items": "center",
"flex-wrap": "wrap",
gap: "8px",
}}
>
<div style={{ display: "flex", "align-items": "center", gap: "8px" }}>
<label
style={{
"font-size": "var(--kilo-font-size-12)",
"font-weight": "500",
color: "var(--text-weak-base)",
}}
>
{language.t("provider.custom.models.label")}
</label>
<Show when={fetching()}>
<Spinner style={{ width: "12px", height: "12px" }} />
</Show>
</div>
<div style={{ display: "flex", gap: "8px", "align-items": "center", "flex-wrap": "wrap" }}>
<Button
type="button"
size="small"
variant="ghost"
onClick={toggleAllReasoning}
disabled={form.models.length === 0}
>
{language.t("provider.custom.models.toggleReasoning")}
</Button>
<Button
type="button"
size="small"
variant="ghost"
onClick={toggleAllImages}
disabled={form.models.length === 0}
>
{language.t("provider.custom.models.toggleImages")}
</Button>
</div>
</div>
<For each={form.models}>
{(m, i) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,42 +98,44 @@ export function ModelCard(props: ModelCardProps) {
/>
</div>

{/* Reasoning toggle */}
<label
style={{
display: "flex",
"align-items": "center",
gap: "8px",
cursor: "pointer",
"font-size": "var(--kilo-font-size-13)",
color: "var(--vscode-foreground)",
}}
>
<input
type="checkbox"
checked={props.m.reasoning}
onChange={(e) => props.onChangeReasoning(e.currentTarget.checked)}
/>
{props.t("provider.custom.models.reasoning.label")}
</label>
{/* Reasoning and Image toggles */}
<div style={{ display: "flex", gap: "16px", "align-items": "center", "flex-wrap": "wrap" }}>
<label
style={{
display: "flex",
"align-items": "center",
gap: "8px",
cursor: "pointer",
"font-size": "var(--kilo-font-size-13)",
color: "var(--vscode-foreground)",
}}
>
<input
type="checkbox"
checked={props.m.reasoning}
onChange={(e) => props.onChangeReasoning(e.currentTarget.checked)}
/>
{props.t("provider.custom.models.reasoning.label")}
</label>

<label
style={{
display: "flex",
"align-items": "center",
gap: "8px",
cursor: "pointer",
"font-size": "var(--kilo-font-size-13)",
color: "var(--vscode-foreground)",
}}
>
<input
type="checkbox"
checked={props.m.supportsImages}
onChange={(e) => props.onChangeSupportsImages(e.currentTarget.checked)}
/>
{props.t("provider.custom.models.modalities.image")}
</label>
<label
style={{
display: "flex",
"align-items": "center",
gap: "8px",
cursor: "pointer",
"font-size": "var(--kilo-font-size-13)",
color: "var(--vscode-foreground)",
}}
>
<input
type="checkbox"
checked={props.m.supportsImages}
onChange={(e) => props.onChangeSupportsImages(e.currentTarget.checked)}
/>
{props.t("provider.custom.models.modalities.image")}
</label>
</div>

<Show when={issue()}>
{(error) => (
Expand Down
2 changes: 2 additions & 0 deletions packages/kilo-vscode/webview-ui/src/i18n/ar.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/kilo-vscode/webview-ui/src/i18n/br.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/kilo-vscode/webview-ui/src/i18n/bs.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/kilo-vscode/webview-ui/src/i18n/da.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/kilo-vscode/webview-ui/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,8 @@ export const dict = {
"provider.custom.models.name.placeholder": "Anzeigename",
"provider.custom.models.reasoning.label": "Schlussfolgerung",
"provider.custom.models.modalities.image": "Bild",
"provider.custom.models.toggleReasoning": "Schlussfolgerung für alle umschalten",
"provider.custom.models.toggleImages": "Bild für alle umschalten",
"provider.custom.models.remove": "Modell entfernen",
"provider.custom.models.add": "Modell hinzufügen",
"provider.custom.models.fetch.authError":
Expand Down
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 @@ -408,6 +408,8 @@ export const dict = {
"provider.custom.models.name.placeholder": "Display Name",
"provider.custom.models.reasoning.label": "Reasoning",
"provider.custom.models.modalities.image": "Image",
"provider.custom.models.toggleReasoning": "Toggle reasoning for all",
"provider.custom.models.toggleImages": "Toggle image for all",
"provider.custom.models.remove": "Remove model",
"provider.custom.models.add": "Add model",
"provider.custom.models.fetch.authError": "Authentication failed. Check the API key above and try again.",
Expand Down
2 changes: 2 additions & 0 deletions packages/kilo-vscode/webview-ui/src/i18n/es.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/kilo-vscode/webview-ui/src/i18n/fa.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/kilo-vscode/webview-ui/src/i18n/fr.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading