From 2fa0890928f7dd060125ad4f4083b8bd2bf3e69b Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Tue, 16 Jun 2026 11:49:21 +0200 Subject: [PATCH 1/4] fix(vscode): restore speech input availability --- .../restore-authenticated-speech-input.md | 7 ++ .../code-with-ai/features/speech-to-text.md | 2 +- .../pages/getting-started/settings/index.md | 23 +++---- packages/kilo-vscode/package.json | 4 -- packages/kilo-vscode/src/provider-actions.ts | 18 +++-- .../kilo-vscode/src/speech-to-text/models.ts | 10 +-- .../model-selector-accessibility.spec.ts | 7 ++ .../tests/unit/provider-actions-save.test.ts | 44 +++++++++++++ .../unit/speech-to-text-availability.test.ts | 19 +++--- .../unit/speech-to-text-models-sync.test.ts | 3 +- .../tests/unit/use-speech-to-text.test.ts | 34 +++++++++- .../webview-ui/agent-manager/DiffPanel.tsx | 2 +- .../agent-manager/NewWorktreeDialog.tsx | 2 +- .../diff-viewer/FullScreenDiffView.tsx | 2 +- .../src/components/chat/PromptInput.tsx | 2 +- .../components/settings/ExperimentalTab.tsx | 40 ----------- .../src/components/settings/ModelsTab.tsx | 47 +++++++++++++ .../src/components/settings/ProvidersTab.tsx | 2 +- .../components/speech-to-text/availability.ts | 13 ++-- .../speech-to-text/useSpeechToText.ts | 31 +++++---- .../kilo-vscode/webview-ui/src/i18n/ar.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/br.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/bs.ts | 7 +- .../kilo-vscode/webview-ui/src/i18n/da.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/de.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/en.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/es.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/fr.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/it.ts | 7 +- .../kilo-vscode/webview-ui/src/i18n/ja.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/ko.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/nl.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/no.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/pl.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/ru.ts | 7 +- .../kilo-vscode/webview-ui/src/i18n/th.ts | 7 +- .../kilo-vscode/webview-ui/src/i18n/tr.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/uk.ts | 7 +- .../kilo-vscode/webview-ui/src/i18n/zh.ts | 6 +- .../kilo-vscode/webview-ui/src/i18n/zht.ts | 6 +- .../src/stories/settings.stories.tsx | 11 ++++ .../server/httpapi/groups/kilo-gateway.ts | 17 +++++ .../server/httpapi/handlers/kilo-gateway.ts | 8 +++ .../server/httpapi-exercise-scenarios.ts | 5 ++ .../kilocode/server/httpapi-public.test.ts | 7 ++ .../server/kilo-gateway-statuses.test.ts | 11 ++++ packages/sdk/js/src/v2/gen/sdk.gen.ts | 32 +++++++++ packages/sdk/js/src/v2/gen/types.gen.ts | 31 +++++++++ packages/sdk/openapi.json | 66 +++++++++++++++++++ 49 files changed, 460 insertions(+), 165 deletions(-) create mode 100644 .changeset/restore-authenticated-speech-input.md diff --git a/.changeset/restore-authenticated-speech-input.md b/.changeset/restore-authenticated-speech-input.md new file mode 100644 index 00000000000..6f826ad0660 --- /dev/null +++ b/.changeset/restore-authenticated-speech-input.md @@ -0,0 +1,7 @@ +--- +"@kilocode/cli": patch +"@kilocode/sdk": patch +"kilo-code": patch +--- + +Restore speech input when profile details are unavailable, move transcription model selection to the Models tab, and default transcription to Whisper Large V3 Turbo. diff --git a/packages/kilo-docs/pages/code-with-ai/features/speech-to-text.md b/packages/kilo-docs/pages/code-with-ai/features/speech-to-text.md index c98ae767c66..f95f55bfadb 100644 --- a/packages/kilo-docs/pages/code-with-ai/features/speech-to-text.md +++ b/packages/kilo-docs/pages/code-with-ai/features/speech-to-text.md @@ -41,7 +41,7 @@ Enable and sign in to the Kilo provider to use voice input in prompt fields. Req ## Choose a model -You can optionally choose a transcription model in **Settings** > **Experimental** > **Speech to Text Model**. Kilo stores this choice as `experimental.speech_to_text_model` in your global Kilo CLI config (`~/.config/kilo/kilo.jsonc`). +You can optionally choose a transcription model in **Settings** > **Models** > **Speech to Text Model**. Kilo stores this choice as `experimental.speech_to_text_model` in your global Kilo CLI config (`~/.config/kilo/kilo.jsonc`). --- diff --git a/packages/kilo-docs/pages/getting-started/settings/index.md b/packages/kilo-docs/pages/getting-started/settings/index.md index 79faf946cf5..a3e9ddd5361 100644 --- a/packages/kilo-docs/pages/getting-started/settings/index.md +++ b/packages/kilo-docs/pages/getting-started/settings/index.md @@ -47,6 +47,18 @@ Use **Local Config** or **Global Config** in the Settings header to open the mat If you check config files into version control, make sure they do not contain API keys or other secrets (e.g., `provider.*.options.apiKey`). Use environment variables for credentials instead. {% /callout %} +### Voice Transcription Model + +When the Kilo provider is enabled and you are signed in, choose the transcription model under **Models** > **Speech to Text Model**. This stores `experimental.speech_to_text_model` in your global Kilo CLI config: + +```json +{ + "experimental": { + "speech_to_text_model": "openai/whisper-large-v3-turbo" + } +} +``` + ### Reasoning Blocks Reasoning blocks stay expanded by default in the VS Code chat UI. Enable **Auto-Collapse Reasoning** in the Display tab, or set `auto_collapse_reasoning` in `kilo.jsonc`, to collapse them after the agent finishes writing them: @@ -198,20 +210,9 @@ Available experimental settings include: - **Share mode** - `manual`, `auto`, or `disabled` session sharing - **LSP integration** - expose language server diagnostics to the agent - **Paste summary** - summarize large clipboard pastes before including them -- **Speech to Text Model** - optionally select the transcription model - **Batch tool** - allow the agent to batch multiple tool calls in one step - **OpenTelemetry** - enable Kilo telemetry and optional OTLP export when configured -Voice input appears automatically when the Kilo provider is enabled and you are signed in. Choosing **Speech to Text Model** stores `experimental.speech_to_text_model` in your global Kilo CLI config (`~/.config/kilo/kilo.jsonc`): - -```json -{ - "experimental": { - "speech_to_text_model": "openai/gpt-4o-mini-transcribe" - } -} -``` - Advanced options not exposed in the UI can be configured via the `experimental` key in `kilo.jsonc`: ```json diff --git a/packages/kilo-vscode/package.json b/packages/kilo-vscode/package.json index 876b6f9e9f4..59993be026c 100644 --- a/packages/kilo-vscode/package.json +++ b/packages/kilo-vscode/package.json @@ -902,10 +902,6 @@ "default": false, "description": "Enable chat textarea autocomplete" }, - "kilo-code.new.speechToText.model": { - "type": "string", - "description": "Model to use for experimental speech-to-text voice input. Requires Kilo Gateway." - }, "kilo-code.new.claudeCodeCompat": { "type": "boolean", "default": false, diff --git a/packages/kilo-vscode/src/provider-actions.ts b/packages/kilo-vscode/src/provider-actions.ts index 739ff339e9d..650d3e1714a 100644 --- a/packages/kilo-vscode/src/provider-actions.ts +++ b/packages/kilo-vscode/src/provider-actions.ts @@ -9,7 +9,7 @@ import { sanitizeCustomProviderConfig, withCustomProviderDeletions, } from "./shared/custom-provider" -import { isCustomProviderPackage, KILO_AUTO, parseModelString } from "./shared/provider-model" +import { isCustomProviderPackage, KILO_AUTO, KILO_PROVIDER_ID, parseModelString } from "./shared/provider-model" import { configFeatures } from "./features" /** @@ -50,7 +50,7 @@ function same(a: unknown, b: unknown): boolean { return akeys.every((key, index) => key === bkeys[index] && same(a[key], b[key])) } -/** Fetch auth methods alongside the provider list. Auth states default to empty (endpoint not yet available). */ +/** Fetch provider availability and authentication state without exposing stored credentials. */ export async function fetchProviderData(client: KiloClient, dir: string) { const authRequest = typeof client.provider.auth === "function" @@ -59,10 +59,18 @@ export async function fetchProviderData(client: KiloClient, dir: string) { .then((r) => r.data ?? {}) .catch(() => ({})) : Promise.resolve({}) - - const [{ data: response }, authMethods] = await Promise.all([ + const kiloRequest = + typeof client.kilo?.authStatus === "function" + ? client.kilo + .authStatus({ directory: dir }, { throwOnError: true }) + .then((r) => (r.data?.authenticated ? (r.data.type ?? null) : null)) + .catch(() => null) + : Promise.resolve(null) + + const [{ data: response }, authMethods, kiloAuth] = await Promise.all([ client.provider.list({ directory: dir }, { throwOnError: true }), authRequest, + kiloRequest, ]) const authStates: Record = {} const storedKeys: Record = {} @@ -83,6 +91,8 @@ export async function fetchProviderData(client: KiloClient, dir: string) { delete next.key return next as (typeof response.all)[number] }) + delete authStates[KILO_PROVIDER_ID] + if (kiloAuth) authStates[KILO_PROVIDER_ID] = kiloAuth return { response: { ...response, all }, authMethods, authStates, storedKeys } } diff --git a/packages/kilo-vscode/src/speech-to-text/models.ts b/packages/kilo-vscode/src/speech-to-text/models.ts index be872d81c96..7eab1dfa181 100644 --- a/packages/kilo-vscode/src/speech-to-text/models.ts +++ b/packages/kilo-vscode/src/speech-to-text/models.ts @@ -6,6 +6,11 @@ export interface SpeechToTextModelDef { } const models: SpeechToTextModelDef[] = [ + { + id: "openai/whisper-large-v3-turbo", + label: "Whisper Large V3 Turbo", + provider: "OpenAI-compatible", + }, { id: "openai/gpt-4o-mini-transcribe", label: "GPT-4o Mini Transcribe", @@ -23,11 +28,6 @@ const models: SpeechToTextModelDef[] = [ label: "Whisper 1", provider: "OpenAI", }, - { - id: "openai/whisper-large-v3-turbo", - label: "Whisper Large V3 Turbo", - provider: "OpenAI-compatible", - }, { id: "openai/whisper-large-v3", label: "Whisper Large V3", diff --git a/packages/kilo-vscode/tests/model-selector-accessibility.spec.ts b/packages/kilo-vscode/tests/model-selector-accessibility.spec.ts index dd634e67ff9..fcd2111199e 100644 --- a/packages/kilo-vscode/tests/model-selector-accessibility.spec.ts +++ b/packages/kilo-vscode/tests/model-selector-accessibility.spec.ts @@ -133,6 +133,13 @@ test("settings and mode editing expose distinct model field purposes", async ({ /Override the default model for specific modes/, ) + await load(page, "settings--models-speech-to-text") + const speech = page.getByRole("button", { name: "Speech to Text Model: Chirp 3" }) + await expect(speech).toBeEnabled() + await speech.click() + await page.getByRole("option", { name: "GPT-4o Mini Transcribe (OpenAI)" }).click() + await expect(page.getByRole("button", { name: "Speech to Text Model: GPT-4o Mini Transcribe" })).toBeVisible() + await load(page, "settings--mode-edit-export") await expect(page.getByRole("button", { name: /Model Override:/ })).toHaveAccessibleDescription( "Override the default model for this agent", diff --git a/packages/kilo-vscode/tests/unit/provider-actions-save.test.ts b/packages/kilo-vscode/tests/unit/provider-actions-save.test.ts index 523ba6f94d8..e80edd36879 100644 --- a/packages/kilo-vscode/tests/unit/provider-actions-save.test.ts +++ b/packages/kilo-vscode/tests/unit/provider-actions-save.test.ts @@ -444,6 +444,50 @@ describe("fetchProviderData", () => { expect("key" in item).toBe(false) }) + it("uses local Kilo auth status instead of profile availability", async () => { + const client = { + provider: { + list: async () => ({ + data: { + all: [{ id: "kilo", name: "Kilo Gateway", source: "custom", env: [], models: {} }], + connected: ["kilo"], + default: { kilo: "kilo-auto/frontier" }, + }, + }), + auth: async () => ({ data: {} }), + }, + kilo: { + authStatus: async () => ({ data: { authenticated: true, type: "oauth" } }), + }, + } as unknown as Parameters[0] + + const result = await fetchProviderData(client, "/tmp") + + expect(result.authStates).toEqual({ kilo: "oauth" }) + }) + + it("does not infer Kilo speech access without stored Gateway auth", async () => { + const client = { + provider: { + list: async () => ({ + data: { + all: [{ id: "kilo", name: "Kilo Gateway", source: "config", key: "configured", env: [], models: {} }], + connected: ["kilo"], + default: { kilo: "kilo-auto/frontier" }, + }, + }), + auth: async () => ({ data: {} }), + }, + kilo: { + authStatus: async () => ({ data: { authenticated: false } }), + }, + } as unknown as Parameters[0] + + const result = await fetchProviderData(client, "/tmp") + + expect(result.authStates).toEqual({}) + }) + it("retains stripped keys for providers with a configured baseURL", async () => { const client = { provider: { diff --git a/packages/kilo-vscode/tests/unit/speech-to-text-availability.test.ts b/packages/kilo-vscode/tests/unit/speech-to-text-availability.test.ts index 2e6de323033..83848168963 100644 --- a/packages/kilo-vscode/tests/unit/speech-to-text-availability.test.ts +++ b/packages/kilo-vscode/tests/unit/speech-to-text-availability.test.ts @@ -6,17 +6,20 @@ import { import { DEFAULT_SPEECH_TO_TEXT_MODEL } from "../../src/speech-to-text/models" describe("speech-to-text availability", () => { - const providers = ["kilo"] - const profile = {} + it("shows speech input for stored Kilo credentials", () => { + expect(canUseSpeechToText({}, { kilo: "oauth" })).toBe(true) + expect(canUseSpeechToText({}, { kilo: "api" })).toBe(true) + }) - it("shows speech input by default when Kilo access exists", () => { - expect(canUseSpeechToText({}, providers, profile)).toBe(true) + it("hides speech input without usable Kilo credentials", () => { + expect(canUseSpeechToText({}, {})).toBe(false) + expect(canUseSpeechToText({}, { kilo: "wellknown" })).toBe(false) }) - it("hides speech input without a signed-in, enabled Kilo provider", () => { - expect(canUseSpeechToText({}, [], profile)).toBe(false) - expect(canUseSpeechToText({}, providers, null)).toBe(false) - expect(canUseSpeechToText({ disabled_providers: ["kilo"] }, providers, profile)).toBe(false) + it("honors enabled and disabled provider configuration", () => { + expect(canUseSpeechToText({ disabled_providers: ["kilo"] }, { kilo: "oauth" })).toBe(false) + expect(canUseSpeechToText({ enabled_providers: ["openai"] }, { kilo: "oauth" })).toBe(false) + expect(canUseSpeechToText({ enabled_providers: ["kilo"] }, { kilo: "oauth" })).toBe(true) }) it("normalizes configured and unknown transcription models", () => { diff --git a/packages/kilo-vscode/tests/unit/speech-to-text-models-sync.test.ts b/packages/kilo-vscode/tests/unit/speech-to-text-models-sync.test.ts index a09e20e8261..79a75d87256 100644 --- a/packages/kilo-vscode/tests/unit/speech-to-text-models-sync.test.ts +++ b/packages/kilo-vscode/tests/unit/speech-to-text-models-sync.test.ts @@ -6,7 +6,8 @@ import { } from "../../src/speech-to-text/models" describe("speech-to-text model catalog", () => { - it("keeps the first speech model as the fallback default", () => { + it("uses Whisper Large V3 Turbo as the fallback default", () => { + expect(DEFAULT_SPEECH_TO_TEXT_MODEL.id).toBe("openai/whisper-large-v3-turbo") expect(DEFAULT_SPEECH_TO_TEXT_MODEL.id).toBe(SPEECH_TO_TEXT_MODELS[0]?.id) }) diff --git a/packages/kilo-vscode/tests/unit/use-speech-to-text.test.ts b/packages/kilo-vscode/tests/unit/use-speech-to-text.test.ts index 52ac796d67a..ae28f0b4171 100644 --- a/packages/kilo-vscode/tests/unit/use-speech-to-text.test.ts +++ b/packages/kilo-vscode/tests/unit/use-speech-to-text.test.ts @@ -2,8 +2,13 @@ import { describe, expect, it, mock } from "bun:test" import { createRoot } from "solid-js" import type { ExtensionMessage, WebviewMessage } from "../../webview-ui/src/types/messages" +type Toast = { + actions?: Array<{ onClick: string | (() => void) }> +} + +const toasts: Toast[] = [] mock.module("@kilocode/kilo-ui/toast", () => ({ - showToast: () => undefined, + showToast: (toast: Toast) => toasts.push(toast), })) const { useSpeechToText } = await import("../../webview-ui/src/components/speech-to-text/useSpeechToText") @@ -11,6 +16,8 @@ const { useSpeechToText } = await import("../../webview-ui/src/components/speech function setup() { const sent: WebviewMessage[] = [] let handler: ((message: ExtensionMessage) => void) | undefined + let logins = 0 + toasts.length = 0 const root = createRoot((dispose) => ({ dispose, @@ -24,16 +31,37 @@ function setup() { } }, }, - { profileData: () => ({}), goToLogin: () => {} }, + { goToLogin: () => logins++ }, { t: (key) => key }, ), })) const fire = (message: ExtensionMessage) => handler?.(message) - return { ...root, fire, sent } + return { ...root, fire, sent, logins: () => logins } } describe("useSpeechToText", () => { + it("offers sign-in when stored credentials stop authenticating", () => { + const ctx = setup() + + ctx.speech.start({ model: "scribe", insert: () => {} }) + const start = ctx.sent[0] + if (start?.type !== "speechToTextStart") throw new Error("speech start message missing") + + ctx.fire({ + type: "speechToTextError", + requestId: start.requestId, + error: "Unauthorized", + code: "not_authenticated", + }) + const action = toasts[0]?.actions?.find((item) => typeof item.onClick === "function") + if (typeof action?.onClick === "function") action.onClick() + + expect(ctx.logins()).toBe(1) + expect(ctx.speech.error()).toBe("speechToText.error.loginRequired") + ctx.dispose() + }) + it("runs the stop completion after inserting a transcript", () => { const ctx = setup() const text: string[] = [] diff --git a/packages/kilo-vscode/webview-ui/agent-manager/DiffPanel.tsx b/packages/kilo-vscode/webview-ui/agent-manager/DiffPanel.tsx index 78be9646d81..9dfb2d4e28f 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/DiffPanel.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/DiffPanel.tsx @@ -92,7 +92,7 @@ export const DiffPanel: Component = (props) => { const provider = useProvider() const { config } = useConfig() const speech = useSpeechToText(vscode, server, { t }) - const canUseSpeech = () => canUseSpeechToText(config(), provider.connected(), server.profileData()) + const canUseSpeech = () => canUseSpeechToText(config(), provider.authStates()) const speechModel = () => selectedSpeechToTextModel(config()) const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.userAgent) const sendAllKeybind = () => diff --git a/packages/kilo-vscode/webview-ui/agent-manager/NewWorktreeDialog.tsx b/packages/kilo-vscode/webview-ui/agent-manager/NewWorktreeDialog.tsx index 0685e6b72b1..25679aad3c0 100644 --- a/packages/kilo-vscode/webview-ui/agent-manager/NewWorktreeDialog.tsx +++ b/packages/kilo-vscode/webview-ui/agent-manager/NewWorktreeDialog.tsx @@ -103,7 +103,7 @@ export const NewWorktreeDialog: Component<{ onClose: () => void; defaultBaseBran const [highlightedIndex, setHighlightedIndex] = createSignal(0) const [variant, setVariant] = createSignal(session.currentVariant()) const speech = useSpeechToText(vscode, server, { t }) - const canUseSpeech = () => canUseSpeechToText(config(), provider.connected(), server.profileData()) + const canUseSpeech = () => canUseSpeechToText(config(), provider.authStates()) const speechModel = () => selectedSpeechToTextModel(config()) // Variant list for the currently selected model diff --git a/packages/kilo-vscode/webview-ui/diff-viewer/FullScreenDiffView.tsx b/packages/kilo-vscode/webview-ui/diff-viewer/FullScreenDiffView.tsx index 9a881d61244..efb58d344b6 100644 --- a/packages/kilo-vscode/webview-ui/diff-viewer/FullScreenDiffView.tsx +++ b/packages/kilo-vscode/webview-ui/diff-viewer/FullScreenDiffView.tsx @@ -96,7 +96,7 @@ export const FullScreenDiffView: Component = (props) => const provider = useProvider() const { config } = useConfig() const speech = useSpeechToText(vscode, server, { t }) - const canUseSpeech = () => canUseSpeechToText(config(), provider.connected(), server.profileData()) + const canUseSpeech = () => canUseSpeechToText(config(), provider.authStates()) const speechModel = () => selectedSpeechToTextModel(config()) const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.userAgent) const sendAllKeybind = () => diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx index d30f37f1b77..f53a5dcbed4 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx @@ -295,7 +295,7 @@ export const PromptInput: Component = (props) => { const isBusy = () => isPromptBusy(session.status(), !!props.suggesting?.(), !!props.questioning?.(), session.submitting()) const isDisabled = () => !server.isConnected() - const canUseSpeech = () => canUseSpeechToText(config(), provider.connected(), server.profileData()) + const canUseSpeech = () => canUseSpeechToText(config(), provider.authStates()) const speechModel = () => selectedSpeechToTextModel(config()) const hasInput = () => text().trim().length > 0 || imageAttach.images().length > 0 || reviewComments().length > 0 const canSend = () => diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/ExperimentalTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/ExperimentalTab.tsx index 0b4400918d5..30c240b4f97 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/ExperimentalTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/ExperimentalTab.tsx @@ -1,19 +1,13 @@ import { Component, For, Show, createMemo, createSignal, onCleanup, onMount } from "solid-js" import { Switch } from "@kilocode/kilo-ui/switch" -import { Tooltip } from "@kilocode/kilo-ui/tooltip" import { Select } from "@kilocode/kilo-ui/select" import { TextField } from "@kilocode/kilo-ui/text-field" import { Card } from "@kilocode/kilo-ui/card" import { useConfig } from "../../context/config" import { useLanguage } from "../../context/language" -import { useProvider } from "../../context/provider" -import { useServer } from "../../context/server" import { useVSCode } from "../../context/vscode" import type { ExtensionMessage } from "../../types/messages" import SettingsRow from "./SettingsRow" -import { DEFAULT_SPEECH_TO_TEXT_MODEL } from "../../../../src/speech-to-text/models" -import { hasSpeechToTextAccess, selectedSpeechToTextModel } from "../speech-to-text/availability" -import { SPEECH_TO_TEXT_MODEL_OPTIONS } from "../speech-to-text/model-selector" interface ShareOption { value: string @@ -29,8 +23,6 @@ const SHARE_OPTIONS: ShareOption[] = [ const ExperimentalTab: Component = () => { const { config, updateConfig } = useConfig() const language = useLanguage() - const provider = useProvider() - const server = useServer() const vscode = useVSCode() const [active, setActive] = createSignal(false) @@ -47,8 +39,6 @@ const ExperimentalTab: Component = () => { }) const experimental = createMemo(() => config().experimental ?? {}) - const kiloReady = createMemo(() => hasSpeechToTextAccess(config(), provider.connected(), server.profileData())) - const speechModel = createMemo(() => selectedSpeechToTextModel(config())) const updateExperimental = (key: string, value: unknown) => { updateConfig({ @@ -164,36 +154,6 @@ const ExperimentalTab: Component = () => { - - - item.value} + label={(item) => `${item.label} (${item.provider})`} + onSelect={(item) => + updateConfig({ + experimental: { + ...config().experimental, + speech_to_text_model: item?.value ?? DEFAULT_SPEECH_TO_TEXT_MODEL.id, + }, + }) + } + variant="secondary" + size="small" + triggerVariant="settings" + triggerProps={{ + "aria-label": `${language.t("settings.models.speechToTextModel.title")}: ${speechOption()?.label}`, + }} + disabled={!kiloReady()} + placeholder={DEFAULT_SPEECH_TO_TEXT_MODEL.label} + /> + + { onCleanup(action.dispose) - const kiloLoggedIn = createMemo(() => !!server.profileData()) + const kiloLoggedIn = createMemo(() => !!provider.authStates()[KILO_PROVIDER_ID]) const connectedProviders = createMemo(() => { const ids = visibleConnectedIds(provider.connected(), provider.authStates()) diff --git a/packages/kilo-vscode/webview-ui/src/components/speech-to-text/availability.ts b/packages/kilo-vscode/webview-ui/src/components/speech-to-text/availability.ts index 32a263c2b6c..3c386670b20 100644 --- a/packages/kilo-vscode/webview-ui/src/components/speech-to-text/availability.ts +++ b/packages/kilo-vscode/webview-ui/src/components/speech-to-text/availability.ts @@ -2,18 +2,23 @@ import { KILO_PROVIDER_ID } from "../../../../src/shared/provider-model" import { getSpeechToTextModel } from "../../../../src/speech-to-text/models" type Cfg = { + enabled_providers?: string[] disabled_providers?: string[] experimental?: { speech_to_text_model?: string } } -export function hasSpeechToTextAccess(cfg: Cfg, providers: readonly string[], profile: unknown | null): boolean { - return providers.includes(KILO_PROVIDER_ID) && !cfg.disabled_providers?.includes(KILO_PROVIDER_ID) && !!profile +type AuthState = "api" | "oauth" | "wellknown" + +export function hasSpeechToTextAccess(cfg: Cfg, auth: Readonly>): boolean { + const enabled = !cfg.enabled_providers || cfg.enabled_providers.includes(KILO_PROVIDER_ID) + const type = auth[KILO_PROVIDER_ID] + return enabled && !cfg.disabled_providers?.includes(KILO_PROVIDER_ID) && (type === "api" || type === "oauth") } -export function canUseSpeechToText(cfg: Cfg, providers: readonly string[], profile: unknown | null): boolean { - return hasSpeechToTextAccess(cfg, providers, profile) +export function canUseSpeechToText(cfg: Cfg, auth: Readonly>): boolean { + return hasSpeechToTextAccess(cfg, auth) } export function selectedSpeechToTextModel(cfg: Cfg): string { diff --git a/packages/kilo-vscode/webview-ui/src/components/speech-to-text/useSpeechToText.ts b/packages/kilo-vscode/webview-ui/src/components/speech-to-text/useSpeechToText.ts index a22afef7f8f..7deb0c06721 100644 --- a/packages/kilo-vscode/webview-ui/src/components/speech-to-text/useSpeechToText.ts +++ b/packages/kilo-vscode/webview-ui/src/components/speech-to-text/useSpeechToText.ts @@ -9,7 +9,6 @@ type VSCode = { } type Server = { - profileData: Accessor goToLogin: () => void } @@ -70,6 +69,10 @@ export function useSpeechToText(vscode: VSCode, server: Server, lang: Lang): Spe } if (msg.type === "speechToTextError") { + if (msg.code === "not_authenticated") { + login() + return + } fail(msg.error) return } @@ -98,19 +101,6 @@ export function useSpeechToText(vscode: VSCode, server: Server, lang: Lang): Spe insert = opts.insert setError(undefined) - if (!server.profileData()) { - showToast({ - variant: "error", - title: lang.t("speechToText.error.loginRequired"), - actions: [ - { label: lang.t("common.signIn"), onClick: server.goToLogin }, - { label: lang.t("common.dismiss"), onClick: "dismiss" }, - ], - }) - fail(lang.t("speechToText.error.loginRequired"), false) - return - } - counter++ request = `${prefix}-${counter}` setState("recording") @@ -144,6 +134,19 @@ export function useSpeechToText(vscode: VSCode, server: Server, lang: Lang): Spe setError(undefined) } + function login() { + const message = lang.t("speechToText.error.loginRequired") + showToast({ + variant: "error", + title: message, + actions: [ + { label: lang.t("common.signIn"), onClick: server.goToLogin }, + { label: lang.t("common.dismiss"), onClick: "dismiss" }, + ], + }) + fail(message, false) + } + function fail(message: string, toast = true) { cleanup() setState("error") diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index 02f8c0dc6f8..e119b2c8fae 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -1298,10 +1298,10 @@ export const dict = { "settings.experimental.speechToText.title": "تحويل الصوت إلى نص", "settings.experimental.speechToText.description": "تمكين الإدخال الصوتي في حقول المطالبة باستخدام حساب Kilo الخاص بك من خلال Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "قم بتمكين وتسجيل الدخول إلى مزود Kilo لاستخدام Speech to Text. ميزة Speech to Text مدعومة حاليًا فقط مع Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "نموذج تحويل الصوت إلى نص", - "settings.experimental.speechToTextModel.description": "اختر نموذج نسخ Kilo Gateway للإدخال الصوتي.", + "settings.models.speechToTextModel.title": "نموذج تحويل الصوت إلى نص", + "settings.models.speechToTextModel.description": "اختر نموذج نسخ Kilo Gateway للإدخال الصوتي.", "settings.experimental.continueOnDeny.title": "المتابعة عند الرفض", "settings.experimental.continueOnDeny.description": "متابعة حلقة الوكيل عند رفض الإذن", "settings.experimental.mcpTimeout.title": "مهلة MCP (مللي ثانية)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index e38574210f2..da360635cbb 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -1329,10 +1329,10 @@ export const dict = { "settings.experimental.speechToText.title": "Fala para texto", "settings.experimental.speechToText.description": "Ative a entrada de voz nos campos de prompt usando sua conta do Kilo por meio do Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Ative e faça login no provedor Kilo para usar o Speech to Text. Atualmente, o Speech to Text é compatível apenas com o Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Modelo de fala para texto", - "settings.experimental.speechToTextModel.description": + "settings.models.speechToTextModel.title": "Modelo de fala para texto", + "settings.models.speechToTextModel.description": "Escolha o modelo de transcrição do Kilo Gateway para entrada de voz.", "settings.experimental.continueOnDeny.title": "Continuar ao negar", "settings.experimental.continueOnDeny.description": "Continuar o loop do agente quando uma permissão é negada", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts index 09bc1ef88a5..55734c100f9 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts @@ -1328,11 +1328,10 @@ export const dict = { "settings.experimental.speechToText.title": "Govor u tekst", "settings.experimental.speechToText.description": "Omogućite glasovni unos u poljima za promptove koristeći vaš Kilo račun preko Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Omogućite i prijavite se na Kilo provajder da biste koristili Speech to Text. Speech to Text je trenutno podržan samo uz Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Model govora u tekst", - "settings.experimental.speechToTextModel.description": - "Odaberite Kilo Gateway model za transkripciju za glasovni unos.", + "settings.models.speechToTextModel.title": "Model govora u tekst", + "settings.models.speechToTextModel.description": "Odaberite Kilo Gateway model za transkripciju za glasovni unos.", "settings.experimental.continueOnDeny.title": "Nastavi pri odbijanju", "settings.experimental.continueOnDeny.description": "Nastavi petlju agenta kada je dozvola odbijena", "settings.experimental.mcpTimeout.title": "MCP istek vremena (ms)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index 855f8235953..610a769b57c 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -1322,10 +1322,10 @@ export const dict = { "settings.experimental.speechToText.title": "Tale til tekst", "settings.experimental.speechToText.description": "Aktivér stemmeinput i prompt-felter ved hjælp af din Kilo-konto gennem Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Aktivér og log ind på Kilo-udbyderen for at bruge Speech to Text. Speech to Text understøttes i øjeblikket kun med Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Model til tale til tekst", - "settings.experimental.speechToTextModel.description": "Vælg Kilo Gateway-transskriptionsmodellen til stemmeinput.", + "settings.models.speechToTextModel.title": "Model til tale til tekst", + "settings.models.speechToTextModel.description": "Vælg Kilo Gateway-transskriptionsmodellen til stemmeinput.", "settings.experimental.continueOnDeny.title": "Fortsæt ved afvisning", "settings.experimental.continueOnDeny.description": "Fortsæt agentløkken, når en tilladelse afvises", "settings.experimental.mcpTimeout.title": "MCP-timeout (ms)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index 933f1c9c84f..9404c93acc4 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -1345,10 +1345,10 @@ export const dict = { "settings.experimental.speechToText.title": "Sprache zu Text", "settings.experimental.speechToText.description": "Aktivieren Sie die Spracheingabe in Prompt-Feldern mit Ihrem Kilo-Konto über Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Aktivieren Sie den Kilo-Anbieter und melden Sie sich an, um Speech to Text zu verwenden. Speech to Text wird derzeit nur mit Kilo Gateway unterstützt.", - "settings.experimental.speechToTextModel.title": "Sprache-zu-Text-Modell", - "settings.experimental.speechToTextModel.description": + "settings.models.speechToTextModel.title": "Sprache-zu-Text-Modell", + "settings.models.speechToTextModel.description": "Wählen Sie das Kilo Gateway-Transkriptionsmodell für die Spracheingabe.", "settings.experimental.continueOnDeny.title": "Bei Ablehnung fortfahren", "settings.experimental.continueOnDeny.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts index 1f487e3049f..ba6a8c2029e 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts @@ -1305,10 +1305,10 @@ export const dict = { "settings.experimental.speechToText.title": "Speech to Text", "settings.experimental.speechToText.description": "Enable voice input in prompt fields using your Kilo account through Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Enable and sign in to the Kilo provider to use Speech to Text. Speech to Text is currently only supported through Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Speech to Text Model", - "settings.experimental.speechToTextModel.description": "Choose the Kilo Gateway transcription model for voice input.", + "settings.models.speechToTextModel.title": "Speech to Text Model", + "settings.models.speechToTextModel.description": "Choose the Kilo Gateway transcription model for voice input.", "settings.experimental.continueOnDeny.title": "Continue on Deny", "settings.experimental.continueOnDeny.description": "Continue the agent loop when a permission is denied", "settings.experimental.mcpTimeout.title": "MCP Timeout (ms)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index 6e69ac5ae69..e0cf93835dc 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -1337,10 +1337,10 @@ export const dict = { "settings.experimental.speechToText.title": "Voz a texto", "settings.experimental.speechToText.description": "Habilita la entrada de voz en los campos de prompt usando tu cuenta de Kilo a través de Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Habilita e inicia sesión en el proveedor Kilo para usar Speech to Text. Actualmente, Speech to Text solo es compatible con Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Modelo de voz a texto", - "settings.experimental.speechToTextModel.description": + "settings.models.speechToTextModel.title": "Modelo de voz a texto", + "settings.models.speechToTextModel.description": "Elige el modelo de transcripción de Kilo Gateway para la entrada de voz.", "settings.experimental.continueOnDeny.title": "Continuar al denegar", "settings.experimental.continueOnDeny.description": "Continuar el bucle del agente cuando se deniega un permiso", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index f514c29142d..72da1869a21 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -1352,10 +1352,10 @@ export const dict = { "settings.experimental.speechToText.title": "Transcription vocale", "settings.experimental.speechToText.description": "Activez la saisie vocale dans les champs de prompt en utilisant votre compte Kilo via Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Activez et connectez-vous au fournisseur Kilo pour utiliser Speech to Text. Speech to Text n'est actuellement pris en charge qu'avec Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Modèle de transcription vocale", - "settings.experimental.speechToTextModel.description": + "settings.models.speechToTextModel.title": "Modèle de transcription vocale", + "settings.models.speechToTextModel.description": "Choisissez le modèle de transcription Kilo Gateway pour la saisie vocale.", "settings.experimental.continueOnDeny.title": "Continuer en cas de refus", "settings.experimental.continueOnDeny.description": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/it.ts b/packages/kilo-vscode/webview-ui/src/i18n/it.ts index b1d7a95367d..3c6fdd12cdc 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/it.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/it.ts @@ -1535,11 +1535,10 @@ export const dict = { "settings.experimental.speechToText.title": "Da voce a testo", "settings.experimental.speechToText.description": "Abilita input vocale nei campi prompt usando il tuo account Kilo tramite Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Abilita e accedi al provider Kilo per usare Da voce a testo. Da voce a testo è attualmente supportato solo tramite Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Modello Da voce a testo", - "settings.experimental.speechToTextModel.description": - "Scegli il modello di trascrizione Kilo Gateway per l'input vocale.", + "settings.models.speechToTextModel.title": "Modello Da voce a testo", + "settings.models.speechToTextModel.description": "Scegli il modello di trascrizione Kilo Gateway per l'input vocale.", // Compaction limit "settings.context.compactionLimit.title": "Limite compattazione automatica", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index 373ca32ef55..719e7e46106 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -1316,10 +1316,10 @@ export const dict = { "settings.experimental.speechToText.title": "音声認識", "settings.experimental.speechToText.description": "Kilo Gateway経由でKiloアカウントを使用して、プロンプトフィールドでの音声入力を有効にします。", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Speech to Text を使用するには、Kilo プロバイダーを有効にしてサインインしてください。現在、Speech to Text は Kilo Gateway でのみサポートされています。", - "settings.experimental.speechToTextModel.title": "音声認識モデル", - "settings.experimental.speechToTextModel.description": "音声入力に使用するKilo Gateway文字起こしモデルを選択します。", + "settings.models.speechToTextModel.title": "音声認識モデル", + "settings.models.speechToTextModel.description": "音声入力に使用するKilo Gateway文字起こしモデルを選択します。", "settings.experimental.continueOnDeny.title": "拒否時に続行", "settings.experimental.continueOnDeny.description": "権限が拒否された場合にエージェントループを続行", "settings.experimental.mcpTimeout.title": "MCPタイムアウト(ミリ秒)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index 509214bf2e0..fdac017fa0b 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -1310,10 +1310,10 @@ export const dict = { "settings.experimental.speechToText.title": "음성 텍스트 변환", "settings.experimental.speechToText.description": "Kilo Gateway를 통해 Kilo 계정을 사용하여 프롬프트 필드에서 음성 입력을 활성화합니다.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Speech to Text를 사용하려면 Kilo 제공자를 활성화하고 로그인하세요. 현재 Speech to Text는 Kilo Gateway에서만 지원됩니다.", - "settings.experimental.speechToTextModel.title": "음성 텍스트 변환 모델", - "settings.experimental.speechToTextModel.description": "음성 입력에 사용할 Kilo Gateway 변환 모델을 선택하세요.", + "settings.models.speechToTextModel.title": "음성 텍스트 변환 모델", + "settings.models.speechToTextModel.description": "음성 입력에 사용할 Kilo Gateway 변환 모델을 선택하세요.", "settings.experimental.continueOnDeny.title": "거부 시 계속", "settings.experimental.continueOnDeny.description": "권한이 거부되면 에이전트 루프 계속", "settings.experimental.mcpTimeout.title": "MCP 타임아웃 (ms)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts index bc8b5c21263..061cfc9f8d7 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts @@ -1323,10 +1323,10 @@ export const dict = { "settings.experimental.speechToText.title": "Spraak naar tekst", "settings.experimental.speechToText.description": "Schakel spraakinvoer in promptvelden in met uw Kilo-account via Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Schakel de Kilo-provider in en meld u aan om Speech to Text te gebruiken. Speech to Text wordt momenteel alleen ondersteund met Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Spraak-naar-tekst-model", - "settings.experimental.speechToTextModel.description": "Kies het Kilo Gateway-transcriptiemodel voor spraakinvoer.", + "settings.models.speechToTextModel.title": "Spraak-naar-tekst-model", + "settings.models.speechToTextModel.description": "Kies het Kilo Gateway-transcriptiemodel voor spraakinvoer.", "settings.experimental.continueOnDeny.title": "Doorgaan bij weigering", "settings.experimental.continueOnDeny.description": "Ga door met de agent loop wanneer een toestemming wordt geweigerd", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index deb8d4abb87..441ccb1f0ae 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -1287,10 +1287,10 @@ export const dict = { "settings.experimental.speechToText.title": "Tale til tekst", "settings.experimental.speechToText.description": "Aktiver taleinndata i prompt-felt ved å bruke din Kilo-konto gjennom Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Aktiver og logg på Kilo-leverandøren for å bruke Speech to Text. Speech to Text støttes for øyeblikket bare med Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Tale-til-tekst-modell", - "settings.experimental.speechToTextModel.description": "Velg Kilo Gateway-transkripsjonsmodellen for taleinndata.", + "settings.models.speechToTextModel.title": "Tale-til-tekst-modell", + "settings.models.speechToTextModel.description": "Velg Kilo Gateway-transkripsjonsmodellen for taleinndata.", "settings.experimental.continueOnDeny.title": "Fortsett ved avvisning", "settings.experimental.continueOnDeny.description": "Fortsett agentløkken når en tillatelse avvises", "settings.experimental.mcpTimeout.title": "MCP-tidsavbrudd (ms)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index b2bf5edb8c3..72b5aa16639 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -1287,10 +1287,10 @@ export const dict = { "settings.experimental.speechToText.title": "Mowa na tekst", "settings.experimental.speechToText.description": "Włącz wprowadzanie głosowe w polach promptów przy użyciu konta Kilo za pośrednictwem Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Włącz i zaloguj się do dostawcy Kilo, aby korzystać ze Speech to Text. Speech to Text jest obecnie obsługiwane tylko z Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Model mowy na tekst", - "settings.experimental.speechToTextModel.description": + "settings.models.speechToTextModel.title": "Model mowy na tekst", + "settings.models.speechToTextModel.description": "Wybierz model transkrypcji Kilo Gateway dla wprowadzania głosowego.", "settings.experimental.continueOnDeny.title": "Kontynuuj przy odmowie", "settings.experimental.continueOnDeny.description": "Kontynuuj pętlę agenta po odmowie uprawnienia", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index 4ca0f12164b..4a7159224a4 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -1327,11 +1327,10 @@ export const dict = { "settings.experimental.speechToText.title": "Речь в текст", "settings.experimental.speechToText.description": "Включите голосовой ввод в полях запросов, используя вашу учетную запись Kilo через Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Включите провайдер Kilo и выполните вход, чтобы использовать Speech to Text. В настоящее время Speech to Text поддерживается только с Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Модель речи в текст", - "settings.experimental.speechToTextModel.description": - "Выберите модель транскрипции Kilo Gateway для голосового ввода.", + "settings.models.speechToTextModel.title": "Модель речи в текст", + "settings.models.speechToTextModel.description": "Выберите модель транскрипции Kilo Gateway для голосового ввода.", "settings.experimental.continueOnDeny.title": "Продолжить при отказе", "settings.experimental.continueOnDeny.description": "Продолжить цикл агента при отказе в разрешении", "settings.experimental.mcpTimeout.title": "Таймаут MCP (мс)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index 7bc0a177cb2..297b79124a0 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -1306,11 +1306,10 @@ export const dict = { "settings.experimental.speechToText.title": "แปลงเสียงเป็นข้อความ", "settings.experimental.speechToText.description": "เปิดใช้งานการป้อนข้อมูลด้วยเสียงในช่องพรอมต์โดยใช้บัญชี Kilo ของคุณผ่าน Kilo Gateway", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "เปิดใช้งานและลงชื่อเข้าใช้ผู้ให้บริการ Kilo เพื่อใช้ Speech to Text ปัจจุบัน Speech to Text รองรับเฉพาะกับ Kilo Gateway เท่านั้น", - "settings.experimental.speechToTextModel.title": "โมเดลแปลงเสียงเป็นข้อความ", - "settings.experimental.speechToTextModel.description": - "เลือกโมเดลการถอดเสียง Kilo Gateway สำหรับการป้อนข้อมูลด้วยเสียง", + "settings.models.speechToTextModel.title": "โมเดลแปลงเสียงเป็นข้อความ", + "settings.models.speechToTextModel.description": "เลือกโมเดลการถอดเสียง Kilo Gateway สำหรับการป้อนข้อมูลด้วยเสียง", "settings.experimental.continueOnDeny.title": "ดำเนินต่อเมื่อถูกปฏิเสธ", "settings.experimental.continueOnDeny.description": "ดำเนินลูปเอเจนต์ต่อเมื่อสิทธิ์ถูกปฏิเสธ", "settings.experimental.mcpTimeout.title": "หมดเวลา MCP (มิลลิวินาที)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts index 13568ff9969..99396b2881f 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts @@ -1316,10 +1316,10 @@ export const dict = { "settings.experimental.speechToText.title": "Sesten metne", "settings.experimental.speechToText.description": "Kilo Gateway üzerinden Kilo hesabınızı kullanarak komut alanlarında sesli girişi etkinleştirin.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Speech to Text kullanmak için Kilo sağlayıcısını etkinleştirin ve giriş yapın. Speech to Text şu anda yalnızca Kilo Gateway ile desteklenmektedir.", - "settings.experimental.speechToTextModel.title": "Sesten metne modeli", - "settings.experimental.speechToTextModel.description": "Sesli giriş için Kilo Gateway transkripsiyon modelini seçin.", + "settings.models.speechToTextModel.title": "Sesten metne modeli", + "settings.models.speechToTextModel.description": "Sesli giriş için Kilo Gateway transkripsiyon modelini seçin.", "settings.experimental.continueOnDeny.title": "Reddetme Durumunda Devam Et", "settings.experimental.continueOnDeny.description": "Bir izin reddedildiğinde ajan döngüsüne devam et", "settings.experimental.mcpTimeout.title": "MCP Zaman Aşımı (ms)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts index f8b2ec4a502..57c05ee0687 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts @@ -1315,11 +1315,10 @@ export const dict = { "settings.experimental.speechToText.title": "Мовлення в текст", "settings.experimental.speechToText.description": "Увімкніть голосове введення в полях запитів, використовуючи ваш обліковий запис Kilo через Kilo Gateway.", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "Увімкніть провайдер Kilo та виконайте вхід, щоб використовувати Speech to Text. Наразі Speech to Text підтримується лише з Kilo Gateway.", - "settings.experimental.speechToTextModel.title": "Модель мовлення в текст", - "settings.experimental.speechToTextModel.description": - "Виберіть модель транскрипції Kilo Gateway для голосового введення.", + "settings.models.speechToTextModel.title": "Модель мовлення в текст", + "settings.models.speechToTextModel.description": "Виберіть модель транскрипції Kilo Gateway для голосового введення.", "settings.experimental.continueOnDeny.title": "Продовжувати при відхиленні", "settings.experimental.continueOnDeny.description": "Продовжувати цикл агента, коли дозвіл відхилено", "settings.experimental.mcpTimeout.title": "Тайм-аут MCP (мс)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index 89fd63765f7..a28cdef048c 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -1286,10 +1286,10 @@ export const dict = { "settings.experimental.codebaseSearch.description": "启用 AI 驱动的自然语言代码库搜索", "settings.experimental.speechToText.title": "语音转文本", "settings.experimental.speechToText.description": "通过 Kilo Gateway 使用您的 Kilo 帐户在提示词字段中启用语音输入。", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "启用并登录 Kilo 提供商以使用 Speech to Text。Speech to Text 目前仅支持通过 Kilo Gateway 使用。", - "settings.experimental.speechToTextModel.title": "语音转文本模型", - "settings.experimental.speechToTextModel.description": "选择用于语音输入的 Kilo Gateway 转录模型。", + "settings.models.speechToTextModel.title": "语音转文本模型", + "settings.models.speechToTextModel.description": "选择用于语音输入的 Kilo Gateway 转录模型。", "settings.experimental.continueOnDeny.title": "拒绝后继续", "settings.experimental.continueOnDeny.description": "权限被拒绝时继续智能体循环", "settings.experimental.mcpTimeout.title": "MCP 超时(毫秒)", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index 31762615e9b..3c60d2557ec 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -1254,10 +1254,10 @@ export const dict = { "settings.experimental.codebaseSearch.description": "啟用 AI 驅動的自然語言程式碼庫搜尋", "settings.experimental.speechToText.title": "語音轉文字", "settings.experimental.speechToText.description": "透過 Kilo Gateway 使用您的 Kilo 帳戶在提示詞欄位中啟用語音輸入。", - "settings.experimental.speechToText.disabledDescription": + "settings.models.speechToText.disabledDescription": "啟用並登入 Kilo 供應商以使用 Speech to Text。Speech to Text 目前僅支援透過 Kilo Gateway 使用。", - "settings.experimental.speechToTextModel.title": "語音轉文字模型", - "settings.experimental.speechToTextModel.description": "選擇用於語音輸入的 Kilo Gateway 轉錄模型。", + "settings.models.speechToTextModel.title": "語音轉文字模型", + "settings.models.speechToTextModel.description": "選擇用於語音輸入的 Kilo Gateway 轉錄模型。", "settings.experimental.continueOnDeny.title": "拒絕後繼續", "settings.experimental.continueOnDeny.description": "權限被拒絕時繼續 Agent 迴圈", "settings.experimental.mcpTimeout.title": "MCP 逾時(毫秒)", diff --git a/packages/kilo-vscode/webview-ui/src/stories/settings.stories.tsx b/packages/kilo-vscode/webview-ui/src/stories/settings.stories.tsx index 3f960e7fa23..755554ec02c 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/settings.stories.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/settings.stories.tsx @@ -84,6 +84,17 @@ export const ModelsAccessibleLabels: Story = { ), } +export const ModelsSpeechToText: Story = { + name: "ModelsTab — speech-to-text model", + render: () => ( + +
+ +
+
+ ), +} + function OpenModelPicker(props: { children: any }) { let ref: HTMLDivElement | undefined onMount(() => { diff --git a/packages/opencode/src/kilocode/server/httpapi/groups/kilo-gateway.ts b/packages/opencode/src/kilocode/server/httpapi/groups/kilo-gateway.ts index 9d51df1aac7..fc1bc59ee9e 100644 --- a/packages/opencode/src/kilocode/server/httpapi/groups/kilo-gateway.ts +++ b/packages/opencode/src/kilocode/server/httpapi/groups/kilo-gateway.ts @@ -33,6 +33,11 @@ export const ProfileWithBalance = Schema.Struct({ currentOrgId: Schema.NullOr(Schema.String), }) +export const AuthStatus = Schema.Struct({ + authenticated: Schema.Boolean, + type: Schema.optional(Schema.Literals(["api", "oauth"])), +}) + export const NotificationAction = Schema.Struct({ actionText: Schema.String, actionURL: Schema.String, @@ -241,6 +246,7 @@ export const CloudSessionData = Schema.Struct({ export const KiloGatewayPaths = { modes: `${root}/modes`, profile: `${root}/profile`, + authStatus: `${root}/auth-status`, fim: `${root}/fim`, edit: `${root}/edit`, audioTranscriptions: `${root}/audio/transcriptions`, @@ -268,6 +274,17 @@ export const KiloGatewayApi = HttpApi.make("kilo") description: "Fetch user profile and organizations from Kilo Gateway", }), ), + HttpApiEndpoint.get("authStatus", KiloGatewayPaths.authStatus, { + query: WorkspaceRoutingQuery, + success: described(AuthStatus, "Kilo authentication status"), + error: HttpApiError.BadRequest, + }).annotateMerge( + OpenApi.annotations({ + identifier: "kilo.authStatus", + summary: "Get Kilo authentication status", + description: "Check whether a locally stored Kilo credential can authenticate Gateway requests", + }), + ), HttpApiEndpoint.get("modes", KiloGatewayPaths.modes, { query: WorkspaceRoutingQuery, success: described(OrganizationModes, "Organization modes list"), diff --git a/packages/opencode/src/kilocode/server/httpapi/handlers/kilo-gateway.ts b/packages/opencode/src/kilocode/server/httpapi/handlers/kilo-gateway.ts index 6e57c9cee7a..f6fa2aa97c3 100644 --- a/packages/opencode/src/kilocode/server/httpapi/handlers/kilo-gateway.ts +++ b/packages/opencode/src/kilocode/server/httpapi/handlers/kilo-gateway.ts @@ -73,6 +73,13 @@ export const kiloGatewayHandlers = HttpApiBuilder.group(InstanceHttpApi, "kilo", return { profile, balance, currentOrgId } }) + const authStatus = Effect.fn("KiloGatewayHttpApi.authStatus")(function* () { + const info = yield* auth.get("kilo").pipe(Effect.mapError(() => new HttpApiError.BadRequest({}))) + const type = getToken(info) && (info?.type === "api" || info?.type === "oauth") ? info.type : undefined + if (!type) return { authenticated: false } + return { authenticated: true, type } + }) + const proxyAuth = Effect.fn("KiloGatewayHttpApi.proxyAuth")(function* () { const info = yield* auth.get("kilo").pipe(Effect.mapError(() => new HttpApiError.Unauthorized({}))) return { @@ -504,6 +511,7 @@ export const kiloGatewayHandlers = HttpApiBuilder.group(InstanceHttpApi, "kilo", return handlers .handle("profile", profile) + .handle("authStatus", authStatus) .handle("modes", modes) .handle("fim", fim) .handle("edit", edit) diff --git a/packages/opencode/test/kilocode/server/httpapi-exercise-scenarios.ts b/packages/opencode/test/kilocode/server/httpapi-exercise-scenarios.ts index 6236f5d8a53..6ac923569fa 100644 --- a/packages/opencode/test/kilocode/server/httpapi-exercise-scenarios.ts +++ b/packages/opencode/test/kilocode/server/httpapi-exercise-scenarios.ts @@ -132,6 +132,11 @@ export const kiloScenarios: Scenario[] = [ http.protected.get("/indexing/models", "indexing.models").json(200, object), http.protected.get("/indexing/warnings", "indexing.warnings").json(200, array), http.protected.get("/kilo/profile", "kilo.profile").probe({ path: "/path" }).status(401), + http.protected.get("/kilo/auth-status", "kilo.authStatus").json(200, (body) => { + object(body) + check(body.authenticated === false, "Kilo auth status should report signed out") + check(body.type === undefined, "Kilo auth status should not expose a credential type while signed out") + }), http.protected.get("/kilo/modes", "kilo.modes").json(200, (body) => { object(body) array(body.modes) diff --git a/packages/opencode/test/kilocode/server/httpapi-public.test.ts b/packages/opencode/test/kilocode/server/httpapi-public.test.ts index 64ffdc1de5b..4f2ddde7980 100644 --- a/packages/opencode/test/kilocode/server/httpapi-public.test.ts +++ b/packages/opencode/test/kilocode/server/httpapi-public.test.ts @@ -17,6 +17,7 @@ type Schema = { items?: Schema properties?: Record type?: string + enum?: string[] minLength?: number maxLength?: number pattern?: string @@ -165,6 +166,12 @@ describe("Kilo PublicApi OpenAPI contract", () => { expect(profile?.balance).toEqual({ anyOf: [expect.objectContaining({ type: "object" }), { type: "null" }] }) expect(profile?.currentOrgId).toEqual({ anyOf: [{ type: "string" }, { type: "null" }] }) + const auth = response(KiloGatewayPaths.authStatus)?.properties + expect(auth).toEqual({ + authenticated: { type: "boolean" }, + type: { type: "string", enum: ["api", "oauth"] }, + }) + const sessions = response(KiloGatewayPaths.cloudSessions)?.properties expect(sessions?.cliSessions?.items?.properties?.title).toEqual({ anyOf: [{ type: "string" }, { type: "null" }], diff --git a/packages/opencode/test/kilocode/server/kilo-gateway-statuses.test.ts b/packages/opencode/test/kilocode/server/kilo-gateway-statuses.test.ts index d3be9a25916..5426a3b105e 100644 --- a/packages/opencode/test/kilocode/server/kilo-gateway-statuses.test.ts +++ b/packages/opencode/test/kilocode/server/kilo-gateway-statuses.test.ts @@ -84,6 +84,17 @@ function post(path: string, body: Record) { } describe("Kilo gateway HttpApi statuses", () => { + it.live("reports locally stored API authentication without a Gateway request", () => + Effect.gen(function* () { + yield* stub(() => Promise.reject(new Error("unexpected Gateway request"))) + + const response = yield* HttpClient.get(KiloGatewayPaths.authStatus) + + expect(response.status).toBe(200) + expect(yield* response.json).toEqual({ authenticated: true, type: "api" }) + }), + ) + it.live("preserves cloud session list rate limits", () => Effect.gen(function* () { yield* stub(() => new Response("rate limited", { status: 429 })) diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index 636cd78b170..dbf279c1093 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -91,6 +91,8 @@ import type { InstanceDisposeResponses, KiloAudioTranscriptionsErrors, KiloAudioTranscriptionsResponses, + KiloAuthStatusErrors, + KiloAuthStatusResponses, KiloClawChatCredentialsResponses, KiloClawStatusErrors, KiloClawStatusResponses, @@ -6523,6 +6525,36 @@ export class Kilo extends HeyApiClient { }) } + /** + * Get Kilo authentication status + * + * Check whether a locally stored Kilo credential can authenticate Gateway requests + */ + public authStatus( + parameters?: { + directory?: string + workspace?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + ], + }, + ], + ) + return (options?.client ?? this.client).get({ + url: "/kilo/auth-status", + ...options, + ...params, + }) + } + /** * Get organization custom modes * diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 90d28d3e8a9..b605d88a2cf 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -8837,6 +8837,37 @@ export type KiloProfileResponses = { export type KiloProfileResponse = KiloProfileResponses[keyof KiloProfileResponses] +export type KiloAuthStatusData = { + body?: never + path?: never + query?: { + directory?: string + workspace?: string + } + url: "/kilo/auth-status" +} + +export type KiloAuthStatusErrors = { + /** + * Bad request + */ + 400: BadRequestError +} + +export type KiloAuthStatusError = KiloAuthStatusErrors[keyof KiloAuthStatusErrors] + +export type KiloAuthStatusResponses = { + /** + * Kilo authentication status + */ + 200: { + authenticated: boolean + type?: "api" | "oauth" + } +} + +export type KiloAuthStatusResponse = KiloAuthStatusResponses[keyof KiloAuthStatusResponses] + export type KiloModesData = { body?: never path?: never diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index bb1370a2899..8243bf7d8e9 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -11382,6 +11382,72 @@ ] } }, + "/kilo/auth-status": { + "get": { + "tags": ["kilo"], + "operationId": "kilo.authStatus", + "parameters": [ + { + "name": "directory", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "workspace", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "responses": { + "200": { + "description": "Kilo authentication status", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "authenticated": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": ["api", "oauth"] + } + }, + "required": ["authenticated"], + "additionalProperties": false, + "description": "Kilo authentication status" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "description": "Check whether a locally stored Kilo credential can authenticate Gateway requests", + "summary": "Get Kilo authentication status", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.kilo.authStatus({\n ...\n})" + } + ] + } + }, "/kilo/modes": { "get": { "tags": ["kilo"], From e50bb7d1d3a1e2e8acec0e2becfb95f515d31bba Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Tue, 16 Jun 2026 14:11:36 +0200 Subject: [PATCH 2/4] refactor(vscode): simplify speech state lookups --- packages/kilo-vscode/src/provider-actions.ts | 11 ++++------- .../tests/unit/provider-actions-save.test.ts | 9 +++++++++ .../webview-ui/src/components/settings/ModelsTab.tsx | 4 ++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/kilo-vscode/src/provider-actions.ts b/packages/kilo-vscode/src/provider-actions.ts index 650d3e1714a..742380b5604 100644 --- a/packages/kilo-vscode/src/provider-actions.ts +++ b/packages/kilo-vscode/src/provider-actions.ts @@ -59,13 +59,10 @@ export async function fetchProviderData(client: KiloClient, dir: string) { .then((r) => r.data ?? {}) .catch(() => ({})) : Promise.resolve({}) - const kiloRequest = - typeof client.kilo?.authStatus === "function" - ? client.kilo - .authStatus({ directory: dir }, { throwOnError: true }) - .then((r) => (r.data?.authenticated ? (r.data.type ?? null) : null)) - .catch(() => null) - : Promise.resolve(null) + const kiloRequest = client.kilo + .authStatus({ directory: dir }, { throwOnError: true }) + .then((r) => (r.data?.authenticated ? (r.data.type ?? null) : null)) + .catch(() => null) const [{ data: response }, authMethods, kiloAuth] = await Promise.all([ client.provider.list({ directory: dir }, { throwOnError: true }), diff --git a/packages/kilo-vscode/tests/unit/provider-actions-save.test.ts b/packages/kilo-vscode/tests/unit/provider-actions-save.test.ts index e80edd36879..a6499bab1c6 100644 --- a/packages/kilo-vscode/tests/unit/provider-actions-save.test.ts +++ b/packages/kilo-vscode/tests/unit/provider-actions-save.test.ts @@ -54,6 +54,9 @@ function createCtx(existing: ExistingGlobal = { disabled_providers: [] }, merged }), auth: async () => ({ data: {} }), }, + kilo: { + authStatus: async () => ({ data: { authenticated: false } }), + }, global: { config: { get: async () => ({ data: existing }), @@ -435,6 +438,9 @@ describe("fetchProviderData", () => { }), auth: async () => ({ data: {} }), }, + kilo: { + authStatus: async () => ({ data: { authenticated: false } }), + }, } as unknown as Parameters[0] const result = await fetchProviderData(client, "/tmp") @@ -518,6 +524,9 @@ describe("fetchProviderData", () => { }), auth: async () => ({ data: {} }), }, + kilo: { + authStatus: async () => ({ data: { authenticated: false } }), + }, } as unknown as Parameters[0] const result = await fetchProviderData(client, "/tmp") diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/ModelsTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/ModelsTab.tsx index 53314e25208..abce3c773a4 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/ModelsTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/ModelsTab.tsx @@ -43,8 +43,8 @@ const ModelsTab: Component = () => { const subagentModel = createMemo(() => parseModelString(config().subagent_model ?? undefined)) const speechModel = createMemo(() => selectedSpeechToTextModel(config())) - const speechOption = createMemo( - () => SPEECH_TO_TEXT_MODEL_OPTIONS.find((item) => item.value === speechModel()) ?? SPEECH_TO_TEXT_MODEL_OPTIONS[0], + const speechOption = createMemo(() => + SPEECH_TO_TEXT_MODEL_OPTIONS.find((item) => item.value === speechModel()), ) const kiloReady = createMemo(() => hasSpeechToTextAccess(config(), provider.authStates())) const variantKey = createMemo(() => config().subagent_model ?? undefined) From ac1f0c8bd90578ee86ee4d0ea372f4ceed548750 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Tue, 16 Jun 2026 14:16:28 +0200 Subject: [PATCH 3/4] chore(vscode): format speech model selector --- .../webview-ui/src/components/settings/ModelsTab.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/ModelsTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/ModelsTab.tsx index abce3c773a4..81f57c39682 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/ModelsTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/ModelsTab.tsx @@ -43,9 +43,7 @@ const ModelsTab: Component = () => { const subagentModel = createMemo(() => parseModelString(config().subagent_model ?? undefined)) const speechModel = createMemo(() => selectedSpeechToTextModel(config())) - const speechOption = createMemo(() => - SPEECH_TO_TEXT_MODEL_OPTIONS.find((item) => item.value === speechModel()), - ) + const speechOption = createMemo(() => SPEECH_TO_TEXT_MODEL_OPTIONS.find((item) => item.value === speechModel())) const kiloReady = createMemo(() => hasSpeechToTextAccess(config(), provider.authStates())) const variantKey = createMemo(() => config().subagent_model ?? undefined) const subagentVariants = createMemo(() => Object.keys(provider.findModel(subagentModel())?.variants ?? {})) From 1bffc5337cb121b96b5a946e0bbeaa08df76e2b9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 16 Jun 2026 12:20:21 +0000 Subject: [PATCH 4/4] chore: update kilo-vscode visual regression baselines --- .../settings/models-accessible-labels-chromium-linux.png | 4 ++-- .../settings/models-autocomplete-open-chromium-linux.png | 4 ++-- .../settings/models-speech-to-text-chromium-linux.png | 3 +++ .../settings/settings-panel-chromium-linux.png | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-speech-to-text-chromium-linux.png diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-accessible-labels-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-accessible-labels-chromium-linux.png index db7441c87c1..34dae072479 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-accessible-labels-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-accessible-labels-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bae54b771e2d7da8c8b1dcab42d9d51662ec888ebb618b24af11e597c79df7b7 -size 37836 +oid sha256:9e041b27abbb19de884e1b928d415d49182872b06018411ed589197424a5ac22 +size 48674 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-autocomplete-open-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-autocomplete-open-chromium-linux.png index db7441c87c1..34dae072479 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-autocomplete-open-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-autocomplete-open-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bae54b771e2d7da8c8b1dcab42d9d51662ec888ebb618b24af11e597c79df7b7 -size 37836 +oid sha256:9e041b27abbb19de884e1b928d415d49182872b06018411ed589197424a5ac22 +size 48674 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-speech-to-text-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-speech-to-text-chromium-linux.png new file mode 100644 index 00000000000..866111072a1 --- /dev/null +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/models-speech-to-text-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ced53d4974eeacc629eede823c7e37191f40ea2816f80f18c1de1a833fbcc614 +size 45341 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/settings-panel-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/settings-panel-chromium-linux.png index 9fb41085b48..545366bac04 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/settings-panel-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/settings-panel-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:57fa5c60dd92a2f4299e58ead8a682c4802de415a496c247af2eba2faf0d63e4 -size 50341 +oid sha256:f4dbd3be2cdf72a789c17076afa73ddeb2eacbe201ace8d8a2657eb95b23a413 +size 53851