diff --git a/.changeset/copy-tooltip-top.md b/.changeset/copy-tooltip-top.md
new file mode 100644
index 00000000000..ded0f1a640d
--- /dev/null
+++ b/.changeset/copy-tooltip-top.md
@@ -0,0 +1,5 @@
+---
+"@kilocode/kilo-ui": patch
+---
+
+Show the assistant message copy tooltip above the button so it no longer overlaps the thumbs up/down buttons.
diff --git a/.changeset/fresh-snapshot-cli.md b/.changeset/fresh-snapshot-cli.md
new file mode 100644
index 00000000000..4bdd7e6cf27
--- /dev/null
+++ b/.changeset/fresh-snapshot-cli.md
@@ -0,0 +1,5 @@
+---
+"kilo-code": patch
+---
+
+Ensure snapshot installs package a fresh CLI backend so new extension features are available in local VSIX builds.
diff --git a/.changeset/speech-input-gateway.md b/.changeset/speech-input-gateway.md
new file mode 100644
index 00000000000..cf48a6b19bb
--- /dev/null
+++ b/.changeset/speech-input-gateway.md
@@ -0,0 +1,6 @@
+---
+"kilo-code": minor
+"@kilocode/kilo-gateway": minor
+---
+
+Support experimental speech-to-text voice input in VS Code prompt fields through Kilo Gateway.
diff --git a/packages/kilo-gateway/src/server/routes.ts b/packages/kilo-gateway/src/server/routes.ts
index 269427b7f44..f2cd17498fa 100644
--- a/packages/kilo-gateway/src/server/routes.ts
+++ b/packages/kilo-gateway/src/server/routes.ts
@@ -132,6 +132,21 @@ export function createKiloRoutes(deps: KiloRoutesDeps) {
cost: z.number().optional(),
})
+ const TranscriptionResponse = z.object({
+ text: z.string(),
+ usage: z.unknown().optional(),
+ })
+
+ const getProxyAuth = async () => {
+ const auth = await Auth.get("kilo")
+ const token = auth?.type === "api" ? auth.key : auth?.type === "oauth" ? auth.access : undefined
+ return {
+ auth,
+ token,
+ organizationId: auth?.type === "oauth" ? auth.accountId : undefined,
+ }
+ }
+
return new Hono()
.get(
"/profile",
@@ -324,19 +339,16 @@ export function createKiloRoutes(deps: KiloRoutesDeps) {
}),
),
async (c: any) => {
- const auth = await Auth.get("kilo")
+ const proxy = await getProxyAuth()
- if (!auth) {
+ if (!proxy.auth) {
return c.json({ error: "Not authenticated with Kilo Gateway" }, 401)
}
- const token = auth.type === "api" ? auth.key : auth.type === "oauth" ? auth.access : undefined
- if (!token) {
+ if (!proxy.token) {
return c.json({ error: "No valid token found" }, 401)
}
- const organizationId = auth.type === "oauth" ? auth.accountId : undefined
-
const { prefix, suffix, model, maxTokens, temperature } = c.req.valid("json")
const fimModel = model ?? "mistralai/codestral-2501"
const fimMaxTokens = maxTokens ?? 256
@@ -347,8 +359,8 @@ export function createKiloRoutes(deps: KiloRoutesDeps) {
const headers = {
"Content-Type": "application/json",
- Authorization: `Bearer ${token}`,
- ...buildKiloHeaders(undefined, { kilocodeOrganizationId: organizationId }),
+ Authorization: `Bearer ${proxy.token}`,
+ ...buildKiloHeaders(undefined, { kilocodeOrganizationId: proxy.organizationId }),
[HEADER_FEATURE]: "autocomplete",
}
@@ -390,6 +402,66 @@ export function createKiloRoutes(deps: KiloRoutesDeps) {
})
},
)
+ .post(
+ "/audio/transcriptions",
+ describeRoute({
+ summary: "Speech to text transcription",
+ description: "Proxy an audio transcription request to the Kilo Gateway",
+ operationId: "kilo.audio.transcriptions",
+ responses: {
+ 200: {
+ description: "Transcription response",
+ content: {
+ "application/json": {
+ schema: resolver(TranscriptionResponse),
+ },
+ },
+ },
+ ...errors(400, 401),
+ },
+ }),
+ validator(
+ "json",
+ z.object({
+ model: z.string(),
+ input_audio: z.object({
+ data: z.string(),
+ format: z.string(),
+ }),
+ language: z.string().optional(),
+ temperature: z.number().optional(),
+ }),
+ ),
+ async (c: any) => {
+ const proxy = await getProxyAuth()
+ if (!proxy.auth) return c.json({ error: "Not authenticated with Kilo Gateway" }, 401)
+
+ if (!proxy.token) return c.json({ error: "No valid token found" }, 401)
+
+ const body = c.req.valid("json")
+ const headers = {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${proxy.token}`,
+ ...buildKiloHeaders(undefined, { kilocodeOrganizationId: proxy.organizationId }),
+ [HEADER_FEATURE]: "vscode-extension",
+ }
+
+ const response = await fetch(`${KILO_API_BASE}/api/gateway/v1/audio/transcriptions`, {
+ method: "POST",
+ headers,
+ signal: c.req.raw.signal,
+ body: JSON.stringify(body),
+ })
+
+ const text = await response.text()
+ return new Response(text, {
+ status: response.status,
+ headers: {
+ "Content-Type": response.headers.get("Content-Type") ?? "application/json",
+ },
+ })
+ },
+ )
.get(
"/notifications",
describeRoute({
diff --git a/packages/kilo-ui/src/components/message-part.tsx b/packages/kilo-ui/src/components/message-part.tsx
index 759c3d96dff..aa9bbbe086a 100644
--- a/packages/kilo-ui/src/components/message-part.tsx
+++ b/packages/kilo-ui/src/components/message-part.tsx
@@ -1345,7 +1345,7 @@ PART_MAPPING["text"] = function TextPartDisplay(props) {
= {
+ "darwin-x64": "@ffmpeg-installer/darwin-x64@4.1.0",
+ "darwin-arm64": "@ffmpeg-installer/darwin-arm64@4.1.5",
+ "linux-x64": "@ffmpeg-installer/linux-x64@4.1.0",
+ "linux-arm64": "@ffmpeg-installer/linux-arm64@4.1.4",
+ "alpine-x64": "@ffmpeg-installer/linux-x64@4.1.0",
+ "alpine-arm64": "@ffmpeg-installer/linux-arm64@4.1.4",
+ "win32-x64": "@ffmpeg-installer/win32-x64@4.1.0",
+}
+
+export async function ensureFfmpegForTarget(target: string, bin: string): Promise {
+ if (target === "win32-arm64") {
+ console.warn("No Windows ARM64 FFmpeg helper package is available; speech input will use system FFmpeg.")
+ return
+ }
+
+ const spec = packages[target]
+ if (!spec) throw new Error(`No FFmpeg helper package configured for target ${target}`)
+
+ const exe = target.startsWith("win32") ? "ffmpeg.exe" : "ffmpeg"
+ const dest = join(bin, exe)
+ if (existsSync(dest)) return
+
+ const tmp = join(bin, ".ffmpeg-tmp")
+ rmSync(tmp, { recursive: true, force: true })
+ mkdirSync(tmp, { recursive: true })
+
+ try {
+ const packed = await $`npm pack ${spec} --pack-destination ${tmp}`.quiet()
+ const name = packed.text().trim().split(/\s+/).pop()
+ if (!name) throw new Error(`npm pack did not return a tarball for ${spec}`)
+
+ await $`tar -xzf ${join(tmp, name)} -C ${tmp}`.quiet()
+ copyFileSync(join(tmp, "package", exe), dest)
+ if (!target.startsWith("win32")) chmodSync(dest, 0o755)
+ } finally {
+ rmSync(tmp, { recursive: true, force: true })
+ }
+}
+
+export function currentFfmpegTarget(): string {
+ const os = process.platform === "win32" ? "win32" : process.platform
+ const arch = process.arch === "x64" ? "x64" : process.arch === "arm64" ? "arm64" : process.arch
+ return `${os}-${arch}`
+}
diff --git a/packages/kilo-vscode/script/local-bin.ts b/packages/kilo-vscode/script/local-bin.ts
index aeb57e81643..a8d2f669bde 100644
--- a/packages/kilo-vscode/script/local-bin.ts
+++ b/packages/kilo-vscode/script/local-bin.ts
@@ -2,6 +2,7 @@
import { $ } from "bun"
import { join, relative, dirname, basename } from "node:path"
import { chmodSync, statSync, rmSync, readdirSync, existsSync } from "node:fs"
+import { currentFfmpegTarget, ensureFfmpegForTarget } from "./ffmpeg-helper"
const forceRebuild = process.argv.includes("--force")
@@ -158,6 +159,7 @@ async function main() {
log(
`CLI binary already present at ${relative(kiloVscodeDir, targetBinPath)} (${Math.round(st.size / 1024 / 1024)}MB). Use --force to rebuild.`,
)
+ await ensureFfmpegForTarget(currentFfmpegTarget(), targetBinDir)
return
}
@@ -181,6 +183,7 @@ async function main() {
await $`mkdir -p ${targetBinDir}`
await $`cp ${sourceBinPath} ${targetBinPath}`
chmodSync(targetBinPath, 0o755)
+ await ensureFfmpegForTarget(currentFfmpegTarget(), targetBinDir)
// Record the CLI source version so future runs detect when a rebuild is needed
const hash = await cliSourceHash()
diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts
index 0aa9c66aba8..a3ed7bd2215 100644
--- a/packages/kilo-vscode/src/KiloProvider.ts
+++ b/packages/kilo-vscode/src/KiloProvider.ts
@@ -68,10 +68,12 @@ import { handleNetworkEvent, clearNetworkWaits } from "./kilo-provider/network"
import { abortSession } from "./kilo-provider/abort"
import {
buildAutocompleteSettingsMessage,
- routeAutocompleteMessage,
validAutocompleteSetting,
watchAutocompleteConfig,
} from "./services/autocomplete/settings"
+import { validSpeechToTextSetting } from "./speech-to-text/settings"
+import { sendSpeechToTextSettings, watchSpeechToTextConfig } from "./speech-to-text/config"
+import { routeEarlyMessage } from "./kilo-provider/early-message"
import * as ModelState from "./kilo-provider/model-state"
import { handleForkSession } from "./kilo-provider/fork-session"
import { openConfig } from "./kilo-provider/open-config"
@@ -112,7 +114,7 @@ import {
handleQuestionReject,
fetchAndSendPendingQuestions,
} from "./kilo-provider/handlers/question"
-import { fetchAndSendPendingSuggestions, routeSuggestionWebviewMessage } from "./kilo-provider/handlers/suggestion"
+import { fetchAndSendPendingSuggestions } from "./kilo-provider/handlers/suggestion"
import { nativeTitle } from "./kilo-provider/native-tab-title"
import {
@@ -229,6 +231,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
private webviewMessageDisposable: vscode.Disposable | null = null
private autocompleteConfigDisposable: vscode.Disposable | null = null
private telemetryStateDisposable: vscode.Disposable | null = null
+ private speechToTextDisposable: vscode.Disposable | null = null
private viewStateDisposable: vscode.Disposable | null = null
private visibilityDisposable: vscode.Disposable | null = null
private autoApproveBridge: ReturnType | null = null
@@ -592,6 +595,8 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
this.webviewMessageDisposable?.dispose()
this.autocompleteConfigDisposable?.dispose()
this.autocompleteConfigDisposable = watchAutocompleteConfig((msg) => this.postMessage(msg))
+ this.speechToTextDisposable?.dispose()
+ this.speechToTextDisposable = watchSpeechToTextConfig(this)
this.telemetryStateDisposable?.dispose()
this.telemetryStateDisposable = watchTelemetryState((msg) => this.postMessage(msg))
this.webviewMessageDisposable = webview.onDidReceiveMessage(async (message) => {
@@ -604,9 +609,17 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
if (intercepted === null) return
message = intercepted
- await routeSuggestionWebviewMessage(this.questionCtx, message)
- if (await ModelState.handleMessage(message.type, message, this.client, (msg) => this.postMessage(msg))) return
- if (await routeAutocompleteMessage(message, (msg) => this.postMessage(msg))) return
+ if (
+ await routeEarlyMessage(message, {
+ question: this.questionCtx,
+ client: this.client,
+ connection: this.connectionService,
+ dir: this.getWorkspaceDirectory(this.currentSession?.id),
+ post: (msg) => this.postMessage(msg),
+ })
+ ) {
+ return
+ }
if (this.handleEditorOpenMessage(message)) return
if (
await handleSidebarWorktreeMessage(message, {
@@ -1297,6 +1310,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
this.postMessage({ type: "gitStatus", repo: this.cachedGitRepo })
this.sendNotificationSettings()
this.sendTimelineSetting()
+ this.sendSpeechToTextSettings()
this.postMessage({ type: "extensionDataReady" })
if (this.cachedGitRepo) this.startStatsPolling()
@@ -2337,6 +2351,10 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
})
}
+ private sendSpeechToTextSettings(): void {
+ sendSpeechToTextSettings(this)
+ }
+
/** Returns the number of sessions currently in "busy" state. */
private getBusySessionCount(): number {
return getBusySessionCount(this.sessionStatusMap)
@@ -2953,6 +2971,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
private async handleUpdateSetting(key: string, value: unknown): Promise {
const { section, leaf } = buildSettingPath(key)
if (section === "autocomplete" && !validAutocompleteSetting(leaf, value)) return
+ if (section === "speechToText" && !validSpeechToTextSetting(leaf, value)) return
const config = vscode.workspace.getConfiguration(`kilo-code.new${section ? `.${section}` : ""}`)
await config.update(leaf, value, vscode.ConfigurationTarget.Global)
}
@@ -2993,6 +3012,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
// Re-send all settings to the webview so the UI reflects the reset
this.postMessage(buildAutocompleteSettingsMessage())
+ this.sendSpeechToTextSettings()
this.sendBrowserSettings()
this.sendNotificationSettings()
this.sendTimelineSetting()
@@ -3494,6 +3514,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
this.visibilityDisposable?.dispose()
this.webviewMessageDisposable?.dispose()
this.autocompleteConfigDisposable?.dispose()
+ this.speechToTextDisposable?.dispose()
this.telemetryStateDisposable?.dispose()
this.autoApproveBridge?.dispose()
this.streams.dispose()
diff --git a/packages/kilo-vscode/src/kilo-provider/early-message.ts b/packages/kilo-vscode/src/kilo-provider/early-message.ts
new file mode 100644
index 00000000000..74b73a14955
--- /dev/null
+++ b/packages/kilo-vscode/src/kilo-provider/early-message.ts
@@ -0,0 +1,20 @@
+import { routeSuggestionWebviewMessage } from "./handlers/suggestion"
+import * as ModelState from "./model-state"
+import { routeInputToolMessage } from "../services/input-tools"
+import type { KiloConnectionService } from "../services/cli-backend/connection-service"
+import type { SuggestionContext } from "./handlers/suggestion"
+import type { KiloClient } from "@kilocode/sdk/v2/client"
+
+type Ctx = {
+ question: SuggestionContext
+ client: KiloClient | null
+ connection: KiloConnectionService
+ dir: string
+ post: (msg: unknown) => void
+}
+
+export async function routeEarlyMessage(message: { type: string }, ctx: Ctx): Promise {
+ await routeSuggestionWebviewMessage(ctx.question, message)
+ if (await ModelState.handleMessage(message.type, message, ctx.client, ctx.post)) return true
+ return await routeInputToolMessage(message, { connection: ctx.connection, dir: ctx.dir, post: ctx.post })
+}
diff --git a/packages/kilo-vscode/src/services/input-tools.ts b/packages/kilo-vscode/src/services/input-tools.ts
new file mode 100644
index 00000000000..86180d9b50c
--- /dev/null
+++ b/packages/kilo-vscode/src/services/input-tools.ts
@@ -0,0 +1,49 @@
+import type { KiloConnectionService } from "./cli-backend/connection-service"
+import { routeAutocompleteMessage } from "./autocomplete/settings"
+import { buildSpeechToTextSettingsMessage } from "../speech-to-text/settings"
+import { handleSpeechToTextCancel, handleSpeechToTextStart, handleSpeechToTextStop } from "../speech-to-text/handler"
+
+type Msg = {
+ type: string
+ requestId?: string
+ model?: string
+ language?: string
+}
+
+type Ctx = {
+ connection: KiloConnectionService
+ dir: string
+ post: (msg: unknown) => void
+}
+
+export async function routeInputToolMessage(message: Msg, ctx: Ctx): Promise {
+ if (await routeAutocompleteMessage(message, ctx.post)) return true
+
+ if (message.type === "requestSpeechToTextSettings") {
+ ctx.post(buildSpeechToTextSettingsMessage())
+ return true
+ }
+
+ if (message.type === "speechToTextStart") {
+ if (!message.requestId) return true
+ handleSpeechToTextStart(
+ { requestId: message.requestId, model: message.model, language: message.language },
+ ctx.post,
+ )
+ return true
+ }
+
+ if (message.type === "speechToTextStop") {
+ if (!message.requestId) return true
+ handleSpeechToTextStop(ctx.connection, { requestId: message.requestId }, ctx.dir, ctx.post)
+ return true
+ }
+
+ if (message.type === "speechToTextCancel") {
+ if (!message.requestId) return true
+ handleSpeechToTextCancel({ requestId: message.requestId }, ctx.post)
+ return true
+ }
+
+ return false
+}
diff --git a/packages/kilo-vscode/src/speech-to-text/capture.ts b/packages/kilo-vscode/src/speech-to-text/capture.ts
new file mode 100644
index 00000000000..3ae3005601b
--- /dev/null
+++ b/packages/kilo-vscode/src/speech-to-text/capture.ts
@@ -0,0 +1,278 @@
+import { existsSync } from "fs"
+import { readFile, stat, unlink } from "fs/promises"
+import * as os from "os"
+import * as path from "path"
+import type { ChildProcess } from "child_process"
+import { exec, spawn } from "../util/process"
+
+type Input = {
+ requestId: string
+ model: string
+ language?: string
+}
+
+type Recording = Input & {
+ file: string
+ proc: ChildProcess
+ stderr: string[]
+ stopped: boolean
+ exit?: {
+ code: number | null
+ signal: string | null
+ }
+}
+
+type Audio = {
+ data: string
+ format: "wav"
+ model: string
+ language?: string
+}
+
+let active: Recording | undefined
+let starting: string | undefined
+
+export async function startSpeechCapture(input: Input): Promise {
+ if (active || starting) throw new Error("Speech recording is already in progress")
+
+ starting = input.requestId
+ try {
+ const bin = await findFFmpeg()
+ const file = path.join(os.tmpdir(), `kilo-stt-${process.pid}-${Date.now()}.wav`)
+ const state = await startWithArgs(bin, file, input, await inputArgSets(bin))
+ return !state.stopped
+ } finally {
+ if (starting === input.requestId) starting = undefined
+ }
+}
+
+export async function stopSpeechCapture(requestId: string): Promise
-
+
+
+
+
+
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 3ff6d7650bb..27d984c56a0 100644
--- a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx
+++ b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx
@@ -19,8 +19,11 @@ import { useLanguage } from "../../context/language"
import { useVSCode } from "../../context/vscode"
import { useWorktreeMode } from "../../context/worktree-mode"
import { useConfig } from "../../context/config"
+import { useProvider } from "../../context/provider"
import { ModelSelector } from "../shared/ModelSelector"
import { ModeSwitcher } from "../shared/ModeSwitcher"
+import { SpeechToTextButton } from "../speech-to-text/SpeechToTextButton"
+import { canUseSpeechToText, selectedSpeechToTextModel } from "../speech-to-text/availability"
import { ThinkingSelector } from "../shared/ThinkingSelector"
import { useFileMention } from "../../hooks/useFileMention"
import { useTerminalContext } from "../../hooks/useTerminalContext"
@@ -29,11 +32,12 @@ import { hasTerminalMention } from "../../hooks/terminal-context-utils"
import { hasGitChangesMention } from "../../hooks/git-changes-context-utils"
import { useSlashCommand } from "../../hooks/useSlashCommand"
import { useGhostText } from "../../hooks/useGhostText"
+import { useSpeechToText } from "../speech-to-text/useSpeechToText"
import { useImageAttachments, type ImageAttachment } from "../../hooks/useImageAttachments"
import { convertToMentionPath } from "../../utils/path-mentions"
import { usePromptHistory } from "../../hooks/usePromptHistory"
import { WandSparkles } from "@kilocode/kilo-ui/lucide"
-import { fileName, dirName, buildHighlightSegments, atEnd, isPromptBusy } from "./prompt-input-utils"
+import { fileName, dirName, buildHighlightSegments, atEnd, insertSpacedText, isPromptBusy } from "./prompt-input-utils"
import type { ReviewComment, TextPart } from "../../types/messages"
import { formatReviewCommentsMarkdown } from "../../utils/review-comment-markdown"
import { pendingDraftKey, scopeDraftKey, sessionDraftKey } from "../../utils/prompt-drafts"
@@ -66,7 +70,8 @@ export const PromptInput: Component = (props) => {
const session = useSession()
const server = useServer()
const indexing = useIndexing()
- const { features } = useConfig()
+ const { config, features, settings } = useConfig()
+ const provider = useProvider()
const language = useLanguage()
const vscode = useVSCode()
const worktree = useWorktreeMode()
@@ -135,6 +140,7 @@ export const PromptInput: Component = (props) => {
let preEnhanceText: string | null = null
const ghost = useGhostText(vscode, text, () => server.isConnected())
+ const speech = useSpeechToText(vscode, server, language)
const replaceReviewComments = (next: ReviewComment[]) => {
setReviewComments(next)
@@ -325,8 +331,11 @@ export const PromptInput: Component = (props) => {
const isBusy = () => isPromptBusy(session.status(), !!props.suggesting?.(), !!props.questioning?.())
const isDisabled = () => !server.isConnected()
+ const canUseSpeech = () => canUseSpeechToText(settings(), config(), provider.connected(), server.profileData())
+ const speechModel = () => selectedSpeechToTextModel(settings())
const hasInput = () => text().trim().length > 0 || imageAttach.images().length > 0 || reviewComments().length > 0
- const canSend = () => hasInput() && !isDisabled() && !terminal.pending() && !git.pending() && !props.blocked?.()
+ const canSend = () =>
+ hasInput() && !isDisabled() && !speech.active() && !terminal.pending() && !git.pending() && !props.blocked?.()
const showStop = () => isBusy() && !hasInput()
const isAtEnd = () =>
textareaRef ? atEnd(textareaRef.selectionStart, textareaRef.selectionEnd, textareaRef.value.length) : false
@@ -645,6 +654,27 @@ export const PromptInput: Component = (props) => {
vscode.postMessage({ type: "enhancePrompt", text: draft, requestId: `enhance-${draftKey()}-${enhanceCounter}` })
}
+ const insertSpeechText = (value: string) => {
+ const ref = textareaRef
+ const current = text()
+ const start = ref?.selectionStart ?? current.length
+ const end = ref?.selectionEnd ?? start
+ const result = insertSpacedText(current, value, start, end)
+
+ setText(result.text)
+ if (!ref) return
+ ref.value = result.text
+ ref.setSelectionRange(result.pos, result.pos)
+ ref.focus()
+ adjustHeight()
+ syncHighlightScroll()
+ ghost.scheduleRequest(result.text, ref)
+ }
+
+ const startSpeech = () => {
+ speech.start({ model: speechModel(), insert: insertSpeechText })
+ }
+
const handleSend = async () => {
const draft = text().trim()
@@ -676,7 +706,14 @@ export const PromptInput: Component = (props) => {
const pending = reviewComments()
const review = pending.length > 0 ? formatReviewCommentsMarkdown(pending) : ""
const message = draft && review ? `${review}\n\n${draft}` : draft || review
- if ((!message && imgs.length === 0) || isDisabled() || terminal.pending() || git.pending() || props.blocked?.())
+ if (
+ (!message && imgs.length === 0) ||
+ isDisabled() ||
+ speech.active() ||
+ terminal.pending() ||
+ git.pending() ||
+ props.blocked?.()
+ )
return
const mentionFiles = mention.parseFileAttachments(draft)
@@ -1042,6 +1079,9 @@ export const PromptInput: Component = (props) => {
+
+
+
{
- const { config, updateConfig } = useConfig()
+ const { config, settings, updateConfig, updateSetting } = useConfig()
const language = useLanguage()
+ const provider = useProvider()
+ const server = useServer()
const vscode = useVSCode()
const [active, setActive] = createSignal(false)
@@ -39,6 +46,8 @@ const ExperimentalTab: Component = () => {
})
const experimental = createMemo(() => config().experimental ?? {})
+ const kiloReady = createMemo(() => hasSpeechToTextAccess(config(), provider.connected(), server.profileData()))
+ const speechModel = createMemo(() => selectedSpeechToTextModel(settings()))
const updateExperimental = (key: string, value: unknown) => {
updateConfig({
@@ -193,6 +202,42 @@ const ExperimentalTab: Component = () => {
+
+ updateSetting("speechToText.enabled", checked)}
+ disabled={!kiloReady()}
+ hideLabel
+ >
+ {language.t("settings.experimental.speechToText.title")}
+
+
+
+
+
+
void
+ label: (key: string) => string
+}
+
+export const SpeechToTextButton: Component = (props) => {
+ const disabled = () => !!props.disabled
+ const label = () => {
+ if (props.speech.state() === "recording") return props.label("speechToText.tooltip.stop")
+ if (props.speech.state() === "transcribing") return props.label("speechToText.tooltip.transcribing")
+ if (props.speech.state() === "error") return props.speech.error() || props.label("speechToText.tooltip.error")
+ return props.label("speechToText.tooltip.start")
+ }
+
+ const click = () => {
+ if (props.speech.state() === "recording") {
+ props.speech.stop()
+ return
+ }
+ if (props.speech.state() === "transcribing") {
+ props.speech.cancel()
+ return
+ }
+ if (props.speech.state() === "error") {
+ props.speech.clear()
+ return
+ }
+ if (disabled()) return
+ props.start()
+ }
+
+ return (
+
+
+
+ )
+}
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
new file mode 100644
index 00000000000..af0293e2cf6
--- /dev/null
+++ b/packages/kilo-vscode/webview-ui/src/components/speech-to-text/availability.ts
@@ -0,0 +1,23 @@
+import { KILO_PROVIDER_ID } from "../../../../src/shared/provider-model"
+import { getSpeechToTextModel } from "../../../../src/speech-to-text/models"
+
+type Cfg = {
+ disabled_providers?: 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
+}
+
+export function canUseSpeechToText(
+ settings: Record,
+ cfg: Cfg,
+ providers: readonly string[],
+ profile: unknown | null,
+): boolean {
+ return settings["speechToText.enabled"] === true && hasSpeechToTextAccess(cfg, providers, profile)
+}
+
+export function selectedSpeechToTextModel(settings: Record): string {
+ return getSpeechToTextModel(String(settings["speechToText.model"] ?? "")).id
+}
diff --git a/packages/kilo-vscode/webview-ui/src/components/speech-to-text/model-selector.ts b/packages/kilo-vscode/webview-ui/src/components/speech-to-text/model-selector.ts
new file mode 100644
index 00000000000..f91c258cb0a
--- /dev/null
+++ b/packages/kilo-vscode/webview-ui/src/components/speech-to-text/model-selector.ts
@@ -0,0 +1,13 @@
+import { SPEECH_TO_TEXT_MODELS } from "../../../../src/speech-to-text/models"
+
+export type SpeechToTextModelOption = {
+ value: string
+ label: string
+ provider: string
+}
+
+export const SPEECH_TO_TEXT_MODEL_OPTIONS: SpeechToTextModelOption[] = SPEECH_TO_TEXT_MODELS.map((model) => ({
+ value: model.id,
+ label: model.label,
+ provider: model.provider,
+}))
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
new file mode 100644
index 00000000000..31161a38126
--- /dev/null
+++ b/packages/kilo-vscode/webview-ui/src/components/speech-to-text/useSpeechToText.ts
@@ -0,0 +1,167 @@
+import { createSignal, onCleanup } from "solid-js"
+import { showToast } from "@kilocode/kilo-ui/toast"
+import type { Accessor } from "solid-js"
+import type { ExtensionMessage, WebviewMessage } from "../../types/messages"
+
+type VSCode = {
+ postMessage: (message: WebviewMessage) => void
+ onMessage: (handler: (message: ExtensionMessage) => void) => () => void
+}
+
+type Server = {
+ profileData: Accessor
+ goToLogin: () => void
+}
+
+type Lang = {
+ t: (key: string) => string
+}
+
+export type SpeechState = "idle" | "recording" | "transcribing" | "error"
+
+export type InsertTranscript = (text: string) => void
+
+type StartOptions = {
+ model: string
+ insert: InsertTranscript
+}
+
+export type SpeechToText = {
+ state: Accessor
+ error: Accessor
+ active: Accessor
+ start: (opts: StartOptions) => void
+ stop: () => void
+ cancel: () => void
+ clear: () => void
+}
+
+export function useSpeechToText(vscode: VSCode, server: Server, lang: Lang): SpeechToText {
+ const [state, setState] = createSignal("idle")
+ const [error, setError] = createSignal()
+ const active = () => state() === "recording" || state() === "transcribing"
+ const prefix = globalThis.crypto?.randomUUID?.() ?? `stt-${Math.random().toString(36).slice(2)}`
+
+ let request = ""
+ let counter = 0
+ let insert: InsertTranscript | undefined
+
+ const unsub = vscode.onMessage((msg) => {
+ if (!isSpeechMessage(msg)) return
+ if (msg.requestId !== request) return
+
+ if (msg.type === "speechToTextStarted") {
+ setState("recording")
+ return
+ }
+
+ if (msg.type === "speechToTextCancelled") {
+ cleanup()
+ setState("idle")
+ setError(undefined)
+ return
+ }
+
+ if (msg.type === "speechToTextError") {
+ fail(msg.error)
+ return
+ }
+
+ const text = msg.text.trim()
+ if (!text) {
+ fail(lang.t("speechToText.error.emptyTranscript"))
+ return
+ }
+
+ insert?.(text)
+ cleanup()
+ setState("idle")
+ setError(undefined)
+ })
+
+ onCleanup(() => {
+ unsub()
+ cancel()
+ })
+
+ function start(opts: StartOptions) {
+ if (active()) return
+ 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")
+ vscode.postMessage({
+ type: "speechToTextStart",
+ requestId: request,
+ model: opts.model,
+ language: langCode(),
+ })
+ }
+
+ function stop() {
+ if (state() !== "recording") return
+ setState("transcribing")
+ vscode.postMessage({ type: "speechToTextStop", requestId: request })
+ }
+
+ function cancel() {
+ if (request && active()) vscode.postMessage({ type: "speechToTextCancel", requestId: request })
+ cleanup()
+ setState("idle")
+ setError(undefined)
+ }
+
+ function clear() {
+ if (state() !== "error") return
+ cleanup()
+ setState("idle")
+ setError(undefined)
+ }
+
+ function fail(message: string, toast = true) {
+ cleanup()
+ setState("error")
+ setError(message)
+ if (toast) showToast({ variant: "error", title: lang.t("speechToText.error.title"), description: message })
+ }
+
+ function cleanup() {
+ request = ""
+ insert = undefined
+ }
+
+ return { state, error, active, start, stop, cancel, clear }
+}
+
+function isSpeechMessage(
+ msg: ExtensionMessage,
+): msg is Extract<
+ ExtensionMessage,
+ { type: "speechToTextStarted" | "speechToTextCancelled" | "speechToTextResult" | "speechToTextError" }
+> {
+ return (
+ msg.type === "speechToTextStarted" ||
+ msg.type === "speechToTextCancelled" ||
+ msg.type === "speechToTextResult" ||
+ msg.type === "speechToTextError"
+ )
+}
+
+function langCode() {
+ return (navigator.language || "en").split("-")[0] || "en"
+}
diff --git a/packages/kilo-vscode/webview-ui/src/context/config.tsx b/packages/kilo-vscode/webview-ui/src/context/config.tsx
index c2eeaa0214b..346f88b169f 100644
--- a/packages/kilo-vscode/webview-ui/src/context/config.tsx
+++ b/packages/kilo-vscode/webview-ui/src/context/config.tsx
@@ -72,14 +72,19 @@ export const ConfigProvider: ParentComponent = (props) => {
// a configLoaded message that arrives before the DOM mount.
const unsubscribe = vscode.onMessage((message: ExtensionMessage) => {
if (message.type === "autocompleteSettingsLoaded") {
- const patch = {
+ mergeSettings({
"autocomplete.enableAutoTrigger": message.settings.enableAutoTrigger,
"autocomplete.enableSmartInlineTaskKeybinding": message.settings.enableSmartInlineTaskKeybinding,
"autocomplete.enableChatAutocomplete": message.settings.enableChatAutocomplete,
"autocomplete.model": message.settings.model,
- }
- setSavedSettings((prev) => ({ ...prev, ...patch }))
- setSettings((prev) => ({ ...prev, ...patch, ...settingsDraft() }))
+ })
+ return
+ }
+ if (message.type === "speechToTextSettingsLoaded") {
+ mergeSettings({
+ "speechToText.enabled": message.settings.enabled,
+ "speechToText.model": message.settings.model,
+ })
return
}
if (message.type === "configLoaded") {
@@ -142,15 +147,24 @@ export const ConfigProvider: ParentComponent = (props) => {
onCleanup(unsubscribe)
+ function mergeSettings(patch: Record) {
+ setSavedSettings((prev) => ({ ...prev, ...patch }))
+ setSettings((prev) => ({ ...prev, ...patch, ...settingsDraft() }))
+ }
+
+ const requestInitialData = () => {
+ vscode.postMessage({ type: "requestConfig" })
+ vscode.postMessage({ type: "requestAutocompleteSettings" })
+ vscode.postMessage({ type: "requestSpeechToTextSettings" })
+ }
+
// Request config immediately; if the extension's httpClient is not yet ready,
// extensionDataReady will fire once initialization completes and we retry once.
- vscode.postMessage({ type: "requestConfig" })
- vscode.postMessage({ type: "requestAutocompleteSettings" })
+ requestInitialData()
const fallback = setTimeout(() => {
if (loading()) {
- vscode.postMessage({ type: "requestConfig" })
- vscode.postMessage({ type: "requestAutocompleteSettings" })
+ requestInitialData()
}
}, 3000)
@@ -159,8 +173,7 @@ export const ConfigProvider: ParentComponent = (props) => {
unsubReady()
clearTimeout(fallback)
if (loading()) {
- vscode.postMessage({ type: "requestConfig" })
- vscode.postMessage({ type: "requestAutocompleteSettings" })
+ requestInitialData()
}
})
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts
index 5e5a7986ad1..d2dc0c3988d 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts
@@ -278,6 +278,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"زر «حسّن الموجه» يطوّر موجهك بإضافة سياق أو توضيح أو إعادة صياغة. جرّب اكتب موجه هنا ثم اضغط الزر مرة ثانية وشوف النتيجة.",
+ "speechToText.tooltip.start": "بدء الإدخال الصوتي",
+ "speechToText.tooltip.stop": "إيقاف التسجيل",
+ "speechToText.tooltip.transcribing": "جاري تحويل الصوت إلى نص... انقر للإلغاء.",
+ "speechToText.tooltip.error": "فشل الإدخال الصوتي. انقر للمسح.",
+ "speechToText.error.title": "فشل الإدخال الصوتي",
+ "speechToText.error.loginRequired": "قم بتسجيل الدخول إلى Kilo لاستخدام الإدخال الصوتي.",
+ "speechToText.error.permission": "تم رفض إذن الوصول إلى الميكروفون.",
+ "speechToText.error.microphone": "تعذر بدء تشغيل الميكروفون.",
+ "speechToText.error.recording": "فشل التسجيل.",
+ "speechToText.error.emptyRecording": "لم يتم تسجيل أي صوت.",
+ "speechToText.error.emptyTranscript": "لم يتم اكتشاف أي كلام.",
+ "speechToText.error.encoding": "تعذر تشفير التسجيل.",
+ "speechToText.toast.transcribed": "تم إدراج النص المنسوخ",
+
"prompt.toast.pasteUnsupported.title": "لصق غير مدعوم",
"prompt.toast.pasteUnsupported.description": "يمكن لصق الصور أو ملفات PDF فقط هنا.",
"prompt.toast.modelAgentRequired.title": "حدد وكيلاً ونموذجاً",
@@ -1212,6 +1226,13 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "أداة Agent Manager",
"settings.experimental.agentManagerTool.description":
"السماح للوكلاء ببدء جلسات Agent Manager المحلية وجلسات worktree من استدعاء أداة",
+ "settings.experimental.speechToText.title": "تحويل الصوت إلى نص",
+ "settings.experimental.speechToText.description":
+ "تمكين الإدخال الصوتي في حقول المطالبة باستخدام حساب Kilo الخاص بك من خلال Kilo Gateway.",
+ "settings.experimental.speechToText.disabledDescription":
+ "قم بتمكين وتسجيل الدخول إلى Kilo provider لاستخدام الإدخال الصوتي في حقول المطالبة.",
+ "settings.experimental.speechToTextModel.title": "نموذج تحويل الصوت إلى نص",
+ "settings.experimental.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 a07f8ee6645..85d42ea5dee 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts
@@ -282,6 +282,20 @@ export const dict = {
"O botão 'Aprimorar prompt' ajuda a melhorar seu pedido fornecendo contexto adicional, esclarecimentos ou reformulações. Tente digitar um pedido aqui e clique no botão novamente para ver como funciona.",
"prompt.action.indexing": "Configurações de indexação",
+ "speechToText.tooltip.start": "Iniciar entrada de voz",
+ "speechToText.tooltip.stop": "Parar gravação",
+ "speechToText.tooltip.transcribing": "Transcrevendo... Clique para cancelar.",
+ "speechToText.tooltip.error": "Falha na entrada de voz. Clique para limpar.",
+ "speechToText.error.title": "Falha na entrada de voz",
+ "speechToText.error.loginRequired": "Faça login no Kilo para usar a entrada de voz.",
+ "speechToText.error.permission": "A permissão do microfone foi negada.",
+ "speechToText.error.microphone": "Não foi possível iniciar o microfone.",
+ "speechToText.error.recording": "A gravação falhou.",
+ "speechToText.error.emptyRecording": "Nenhum áudio foi gravado.",
+ "speechToText.error.emptyTranscript": "Nenhuma fala foi detectada.",
+ "speechToText.error.encoding": "Não foi possível codificar a gravação.",
+ "speechToText.toast.transcribed": "Transcrição inserida",
+
"prompt.toast.pasteUnsupported.title": "Colagem não suportada",
"prompt.toast.pasteUnsupported.description": "Somente imagens ou PDFs podem ser colados aqui.",
"prompt.toast.modelAgentRequired.title": "Selecione um agente e modelo",
@@ -1241,6 +1255,14 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Ferramenta Agent Manager",
"settings.experimental.agentManagerTool.description":
"Permitir que agentes iniciem sessões locais e sessões worktree do Agent Manager a partir de uma chamada de ferramenta",
+ "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":
+ "Ative e faça login no Kilo provider para usar a entrada de voz nos campos de prompt.",
+ "settings.experimental.speechToTextModel.title": "Modelo de fala para texto",
+ "settings.experimental.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",
"settings.experimental.mcpTimeout.title": "Tempo limite MCP (ms)",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts
index 9efd0465abd..566e6ef1917 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts
@@ -282,6 +282,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"Dugme 'Poboljšaj prompt' pomaže poboljšati vaš zahtjev pružajući dodatni kontekst, pojašnjenje ili preformulaciju. Pokušajte upisati zahtjev ovdje i ponovo kliknite na dugme da vidite kako funkcioniše.",
+ "speechToText.tooltip.start": "Započni glasovni unos",
+ "speechToText.tooltip.stop": "Zaustavi snimanje",
+ "speechToText.tooltip.transcribing": "Prepisivanje... Kliknite da otkažete.",
+ "speechToText.tooltip.error": "Glasovni unos nije uspio. Kliknite da očistite.",
+ "speechToText.error.title": "Glasovni unos nije uspio",
+ "speechToText.error.loginRequired": "Prijavite se na Kilo da koristite glasovni unos.",
+ "speechToText.error.permission": "Dozvola za mikrofon je odbijena.",
+ "speechToText.error.microphone": "Nije moguće pokrenuti mikrofon.",
+ "speechToText.error.recording": "Snimanje nije uspjelo.",
+ "speechToText.error.emptyRecording": "Zvuk nije snimljen.",
+ "speechToText.error.emptyTranscript": "Govor nije otkriven.",
+ "speechToText.error.encoding": "Nije moguće kodirati snimak.",
+ "speechToText.toast.transcribed": "Prijepis ubačen",
+
"prompt.toast.pasteUnsupported.title": "Nepodržano lijepljenje",
"prompt.toast.pasteUnsupported.description": "Ovdje se mogu zalijepiti samo slike ili PDF-ovi.",
"prompt.toast.modelAgentRequired.title": "Odaberi agenta i model",
@@ -1241,6 +1255,14 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Agent Manager alat",
"settings.experimental.agentManagerTool.description":
"Dozvoli agentima da pokreću lokalne Agent Manager sesije i worktree sesije iz poziva alata",
+ "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":
+ "Omogućite i prijavite se na Kilo provider da koristite glasovni unos u poljima za promptove.",
+ "settings.experimental.speechToTextModel.title": "Model govora u tekst",
+ "settings.experimental.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 20433ae49e7..11be8693f0b 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts
@@ -281,6 +281,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"Knappen 'Forbedr prompt' hjælper med at forbedre din forespørgsel ved at give ekstra kontekst, præcisering eller omformulering. Prøv at skrive en forespørgsel her og klik på knappen igen for at se hvordan det virker.",
+ "speechToText.tooltip.start": "Start stemmeinput",
+ "speechToText.tooltip.stop": "Stop optagelse",
+ "speechToText.tooltip.transcribing": "Transskriberer... Klik for at annullere.",
+ "speechToText.tooltip.error": "Stemmeinput mislykkedes. Klik for at rydde.",
+ "speechToText.error.title": "Stemmeinput mislykkedes",
+ "speechToText.error.loginRequired": "Log ind på Kilo for at bruge stemmeinput.",
+ "speechToText.error.permission": "Mikrofontilladelse blev nægtet.",
+ "speechToText.error.microphone": "Kunne ikke starte mikrofonen.",
+ "speechToText.error.recording": "Optagelse mislykkedes.",
+ "speechToText.error.emptyRecording": "Ingen lyd blev optaget.",
+ "speechToText.error.emptyTranscript": "Ingen tale blev registreret.",
+ "speechToText.error.encoding": "Kunne ikke kode optagelsen.",
+ "speechToText.toast.transcribed": "Transskription indsat",
+
"prompt.toast.pasteUnsupported.title": "Ikke understøttet indsæt",
"prompt.toast.pasteUnsupported.description": "Kun billeder eller PDF'er kan indsættes her.",
"prompt.toast.modelAgentRequired.title": "Vælg en agent og model",
@@ -1234,6 +1248,13 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Agent Manager-værktøj",
"settings.experimental.agentManagerTool.description":
"Tillad agenter at starte lokale Agent Manager-sessioner og worktree-sessioner fra et værktøjskald",
+ "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":
+ "Aktivér og log ind på Kilo provider for at bruge stemmeinput i prompt-felter.",
+ "settings.experimental.speechToTextModel.title": "Model til tale til tekst",
+ "settings.experimental.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 2753c763c31..75adb9802bb 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts
@@ -285,6 +285,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"Die Schaltfläche 'Prompt verbessern' hilft, deine Anfrage durch zusätzlichen Kontext, Klarstellungen oder Umformulierungen zu verbessern. Versuche, hier eine Anfrage einzugeben und klicke erneut auf die Schaltfläche, um zu sehen, wie es funktioniert.",
+ "speechToText.tooltip.start": "Spracheingabe starten",
+ "speechToText.tooltip.stop": "Aufnahme beenden",
+ "speechToText.tooltip.transcribing": "Transkribieren... Zum Abbrechen klicken.",
+ "speechToText.tooltip.error": "Spracheingabe fehlgeschlagen. Zum Löschen klicken.",
+ "speechToText.error.title": "Spracheingabe fehlgeschlagen",
+ "speechToText.error.loginRequired": "Melden Sie sich bei Kilo an, um die Spracheingabe zu verwenden.",
+ "speechToText.error.permission": "Mikrofonberechtigung wurde verweigert.",
+ "speechToText.error.microphone": "Mikrofon konnte nicht gestartet werden.",
+ "speechToText.error.recording": "Aufnahme fehlgeschlagen.",
+ "speechToText.error.emptyRecording": "Es wurde kein Audio aufgenommen.",
+ "speechToText.error.emptyTranscript": "Es wurde keine Sprache erkannt.",
+ "speechToText.error.encoding": "Aufnahme konnte nicht codiert werden.",
+ "speechToText.toast.transcribed": "Transkription eingefügt",
+
"prompt.toast.pasteUnsupported.title": "Nicht unterstütztes Einfügen",
"prompt.toast.pasteUnsupported.description": "Hier können nur Bilder oder PDFs eingefügt werden.",
"prompt.toast.modelAgentRequired.title": "Wählen Sie einen Agenten und ein Modell",
@@ -1256,6 +1270,14 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Agent Manager-Werkzeug",
"settings.experimental.agentManagerTool.description":
"Agenten erlauben, lokale Agent Manager-Sitzungen und Worktree-Sitzungen per Werkzeugaufruf zu starten",
+ "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":
+ "Aktivieren Sie Kilo provider und melden Sie sich an, um die Spracheingabe in Prompt-Feldern zu verwenden.",
+ "settings.experimental.speechToTextModel.title": "Sprache-zu-Text-Modell",
+ "settings.experimental.speechToTextModel.description":
+ "Wählen Sie das Kilo Gateway-Transkriptionsmodell für die Spracheingabe.",
"settings.experimental.continueOnDeny.title": "Bei Ablehnung fortfahren",
"settings.experimental.continueOnDeny.description":
"Agent-Schleife fortsetzen, wenn eine Berechtigung abgelehnt wird",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts
index 807482293f0..aaf39dbf892 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts
@@ -280,6 +280,19 @@ export const dict = {
"prompt.action.resetModel": "Reset model to default",
"prompt.action.enhanceDescription":
"The 'Enhance Prompt' button helps improve your prompt by providing additional context, clarification, or rephrasing. Try typing a prompt in here and clicking the button again to see how it works.",
+ "speechToText.tooltip.start": "Start voice input",
+ "speechToText.tooltip.stop": "Stop recording",
+ "speechToText.tooltip.transcribing": "Transcribing... Click to cancel.",
+ "speechToText.tooltip.error": "Speech input failed. Click to clear.",
+ "speechToText.error.title": "Speech input failed",
+ "speechToText.error.loginRequired": "Sign in to Kilo to use speech input.",
+ "speechToText.error.permission": "Microphone permission was denied.",
+ "speechToText.error.microphone": "Could not start the microphone.",
+ "speechToText.error.recording": "Recording failed.",
+ "speechToText.error.emptyRecording": "No audio was recorded.",
+ "speechToText.error.emptyTranscript": "No speech was detected.",
+ "speechToText.error.encoding": "Could not encode the recording.",
+ "speechToText.toast.transcribed": "Transcription inserted",
"prompt.toast.pasteUnsupported.title": "Unsupported paste",
"prompt.toast.pasteUnsupported.description": "Only images or PDFs can be pasted here.",
@@ -1225,6 +1238,13 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Agent Manager Tool",
"settings.experimental.agentManagerTool.description":
"Allow agents to start Agent Manager local sessions and worktree sessions from a tool call",
+ "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":
+ "Enable and sign in to the Kilo provider to use voice input in prompt fields.",
+ "settings.experimental.speechToTextModel.title": "Speech to Text Model",
+ "settings.experimental.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 ffb8cddae5a..3e875cc6362 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts
@@ -283,6 +283,20 @@ export const dict = {
"El botón 'Mejorar el mensaje' ayuda a mejorar tu petición proporcionando contexto adicional, aclaraciones o reformulaciones. Intenta escribir una petición aquí y haz clic en el botón nuevamente para ver cómo funciona.",
"prompt.action.indexing": "Configuración de indexación",
+ "speechToText.tooltip.start": "Iniciar entrada de voz",
+ "speechToText.tooltip.stop": "Detener grabación",
+ "speechToText.tooltip.transcribing": "Transcribiendo... Haz clic para cancelar.",
+ "speechToText.tooltip.error": "Falló la entrada de voz. Haz clic para borrar.",
+ "speechToText.error.title": "Falló la entrada de voz",
+ "speechToText.error.loginRequired": "Inicia sesión en Kilo para usar la entrada de voz.",
+ "speechToText.error.permission": "Se denegó el permiso del micrófono.",
+ "speechToText.error.microphone": "No se pudo iniciar el micrófono.",
+ "speechToText.error.recording": "La grabación falló.",
+ "speechToText.error.emptyRecording": "No se grabó ningún audio.",
+ "speechToText.error.emptyTranscript": "No se detectó voz.",
+ "speechToText.error.encoding": "No se pudo codificar la grabación.",
+ "speechToText.toast.transcribed": "Transcripción insertada",
+
"prompt.toast.pasteUnsupported.title": "Pegado no soportado",
"prompt.toast.pasteUnsupported.description": "Solo se pueden pegar imágenes o PDFs aquí.",
"prompt.toast.modelAgentRequired.title": "Selecciona un agente y modelo",
@@ -1248,6 +1262,14 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Herramienta Agent Manager",
"settings.experimental.agentManagerTool.description":
"Permitir que los agentes inicien sesiones locales y sesiones de worktree de Agent Manager desde una llamada de herramienta",
+ "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":
+ "Habilita e inicia sesión en Kilo provider para usar la entrada de voz en los campos de prompt.",
+ "settings.experimental.speechToTextModel.title": "Modelo de voz a texto",
+ "settings.experimental.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",
"settings.experimental.mcpTimeout.title": "Tiempo de espera MCP (ms)",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts
index f557dbc72c6..b06fc1d6ff5 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts
@@ -284,6 +284,20 @@ export const dict = {
"Le bouton 'Améliorer la requête' aide à améliorer votre demande en fournissant un contexte supplémentaire, des clarifications ou des reformulations. Essayez de taper une demande ici et cliquez à nouveau sur le bouton pour voir comment cela fonctionne.",
"prompt.action.indexing": "Paramètres d'indexation",
+ "speechToText.tooltip.start": "Démarrer la saisie vocale",
+ "speechToText.tooltip.stop": "Arrêter l'enregistrement",
+ "speechToText.tooltip.transcribing": "Transcription en cours... Cliquez pour annuler.",
+ "speechToText.tooltip.error": "La saisie vocale a échoué. Cliquez pour effacer.",
+ "speechToText.error.title": "La saisie vocale a échoué",
+ "speechToText.error.loginRequired": "Connectez-vous à Kilo pour utiliser la saisie vocale.",
+ "speechToText.error.permission": "L'autorisation du microphone a été refusée.",
+ "speechToText.error.microphone": "Impossible de démarrer le microphone.",
+ "speechToText.error.recording": "L'enregistrement a échoué.",
+ "speechToText.error.emptyRecording": "Aucun son n'a été enregistré.",
+ "speechToText.error.emptyTranscript": "Aucune voix n'a été détectée.",
+ "speechToText.error.encoding": "Impossible d'encoder l'enregistrement.",
+ "speechToText.toast.transcribed": "Transcription insérée",
+
"prompt.toast.pasteUnsupported.title": "Collage non supporté",
"prompt.toast.pasteUnsupported.description": "Seules les images ou les PDF peuvent être collés ici.",
"prompt.toast.modelAgentRequired.title": "Sélectionnez un agent et un modèle",
@@ -1260,6 +1274,14 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Outil Agent Manager",
"settings.experimental.agentManagerTool.description":
"Autoriser les agents à démarrer des sessions locales Agent Manager et des sessions worktree depuis un appel d'outil",
+ "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":
+ "Activez Kilo provider et connectez-vous pour utiliser la saisie vocale dans les champs de prompt.",
+ "settings.experimental.speechToTextModel.title": "Modèle de transcription vocale",
+ "settings.experimental.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":
"Continuer la boucle de l'agent lorsqu'une autorisation est refusée",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts
index 8354dc6dd07..41f791fd1a0 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts
@@ -279,6 +279,20 @@ export const dict = {
"「プロンプトを強化」ボタンは、追加コンテキスト、説明、または言い換えを提供することで、リクエストを改善します。ここにリクエストを入力し、ボタンを再度クリックして動作を確認してください。",
"prompt.action.indexing": "インデックス設定",
+ "speechToText.tooltip.start": "音声入力を開始",
+ "speechToText.tooltip.stop": "録音を停止",
+ "speechToText.tooltip.transcribing": "文字起こし中... クリックしてキャンセル。",
+ "speechToText.tooltip.error": "音声入力に失敗しました。クリックしてクリア。",
+ "speechToText.error.title": "音声入力に失敗しました",
+ "speechToText.error.loginRequired": "音声入力を使用するにはKiloにサインインしてください。",
+ "speechToText.error.permission": "マイクの許可が拒否されました。",
+ "speechToText.error.microphone": "マイクを起動できませんでした。",
+ "speechToText.error.recording": "録音に失敗しました。",
+ "speechToText.error.emptyRecording": "音声が録音されていません。",
+ "speechToText.error.emptyTranscript": "音声が検出されませんでした。",
+ "speechToText.error.encoding": "録音をエンコードできませんでした。",
+ "speechToText.toast.transcribed": "文字起こしを挿入しました",
+
"prompt.toast.pasteUnsupported.title": "サポートされていない貼り付け",
"prompt.toast.pasteUnsupported.description": "ここでは画像またはPDFのみ貼り付け可能です。",
"prompt.toast.modelAgentRequired.title": "エージェントとモデルを選択",
@@ -1229,6 +1243,13 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Agent Manager ツール",
"settings.experimental.agentManagerTool.description":
"エージェントがツール呼び出しから Agent Manager のローカルセッションとワークツリーセッションを開始できるようにする",
+ "settings.experimental.speechToText.title": "音声認識",
+ "settings.experimental.speechToText.description":
+ "Kilo Gateway経由でKiloアカウントを使用して、プロンプトフィールドでの音声入力を有効にします。",
+ "settings.experimental.speechToText.disabledDescription":
+ "プロンプトフィールドで音声入力を使用するには、Kilo providerを有効にしてサインインしてください。",
+ "settings.experimental.speechToTextModel.title": "音声認識モデル",
+ "settings.experimental.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 01e5ece527b..77f8e454a33 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts
@@ -281,6 +281,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"'프롬프트 향상' 버튼은 추가 컨텍스트, 명확화 또는 재구성을 제공하여 요청을 개선합니다. 여기에 요청을 입력한 다음 버튼을 다시 클릭하여 작동 방식을 확인해보세요.",
+ "speechToText.tooltip.start": "음성 입력 시작",
+ "speechToText.tooltip.stop": "녹음 중지",
+ "speechToText.tooltip.transcribing": "변환 중... 취소하려면 클릭하세요.",
+ "speechToText.tooltip.error": "음성 입력에 실패했습니다. 지우려면 클릭하세요.",
+ "speechToText.error.title": "음성 입력 실패",
+ "speechToText.error.loginRequired": "음성 입력을 사용하려면 Kilo에 로그인하세요.",
+ "speechToText.error.permission": "마이크 권한이 거부되었습니다.",
+ "speechToText.error.microphone": "마이크를 시작할 수 없습니다.",
+ "speechToText.error.recording": "녹음에 실패했습니다.",
+ "speechToText.error.emptyRecording": "녹음된 오디오가 없습니다.",
+ "speechToText.error.emptyTranscript": "음성이 감지되지 않았습니다.",
+ "speechToText.error.encoding": "녹음을 인코딩할 수 없습니다.",
+ "speechToText.toast.transcribed": "변환 텍스트 삽입됨",
+
"prompt.toast.pasteUnsupported.title": "지원되지 않는 붙여넣기",
"prompt.toast.pasteUnsupported.description": "이미지나 PDF만 붙여넣을 수 있습니다.",
"prompt.toast.modelAgentRequired.title": "에이전트 및 모델 선택",
@@ -1223,6 +1237,13 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Agent Manager 도구",
"settings.experimental.agentManagerTool.description":
"에이전트가 도구 호출로 Agent Manager 로컬 세션 및 워크트리 세션을 시작하도록 허용",
+ "settings.experimental.speechToText.title": "음성 텍스트 변환",
+ "settings.experimental.speechToText.description":
+ "Kilo Gateway를 통해 Kilo 계정을 사용하여 프롬프트 필드에서 음성 입력을 활성화합니다.",
+ "settings.experimental.speechToText.disabledDescription":
+ "프롬프트 필드에서 음성 입력을 사용하려면 Kilo provider를 활성화하고 로그인하세요.",
+ "settings.experimental.speechToTextModel.title": "음성 텍스트 변환 모델",
+ "settings.experimental.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 19f2d8c8351..8e67956970d 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts
@@ -283,6 +283,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"De knop 'Prompt verbeteren' helpt je prompt te verbeteren door extra context, verduidelijking of herformulering te bieden. Typ hier een prompt en klik nogmaals op de knop om te zien hoe het werkt.",
+ "speechToText.tooltip.start": "Spraakinvoer starten",
+ "speechToText.tooltip.stop": "Opname stoppen",
+ "speechToText.tooltip.transcribing": "Transcriberen... Klik om te annuleren.",
+ "speechToText.tooltip.error": "Spraakinvoer mislukt. Klik om te wissen.",
+ "speechToText.error.title": "Spraakinvoer mislukt",
+ "speechToText.error.loginRequired": "Meld u aan bij Kilo om spraakinvoer te gebruiken.",
+ "speechToText.error.permission": "Microfoontoegang is geweigerd.",
+ "speechToText.error.microphone": "Kon de microfoon niet starten.",
+ "speechToText.error.recording": "Opname mislukt.",
+ "speechToText.error.emptyRecording": "Er is geen audio opgenomen.",
+ "speechToText.error.emptyTranscript": "Er is geen spraak gedetecteerd.",
+ "speechToText.error.encoding": "Kon de opname niet coderen.",
+ "speechToText.toast.transcribed": "Transcriptie ingevoegd",
+
"prompt.toast.pasteUnsupported.title": "Plakken niet ondersteund",
"prompt.toast.pasteUnsupported.description": "Hier kunnen alleen afbeeldingen of PDF's worden geplakt.",
"prompt.toast.modelAgentRequired.title": "Selecteer een agent en model",
@@ -1240,6 +1254,13 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Agent Manager-tool",
"settings.experimental.agentManagerTool.description":
"Sta agents toe om lokale Agent Manager-sessies en worktree-sessies te starten vanuit een tool call",
+ "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":
+ "Schakel Kilo provider in en meld u aan om spraakinvoer in promptvelden te gebruiken.",
+ "settings.experimental.speechToTextModel.title": "Spraak-naar-tekst-model",
+ "settings.experimental.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 0c2be64ddc6..de692b32a7a 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts
@@ -285,6 +285,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"Knappen 'Forbedre prompt' hjelper med å forbedre forespørselen din ved å gi ekstra kontekst, avklaring eller omformulering. Prøv å skrive en forespørsel her og klikk på knappen igjen for å se hvordan det fungerer.",
+ "speechToText.tooltip.start": "Start taleinndata",
+ "speechToText.tooltip.stop": "Stopp opptak",
+ "speechToText.tooltip.transcribing": "Transkriberer... Klikk for å avbryte.",
+ "speechToText.tooltip.error": "Taleinndata mislyktes. Klikk for å tømme.",
+ "speechToText.error.title": "Taleinndata mislyktes",
+ "speechToText.error.loginRequired": "Logg på Kilo for å bruke taleinndata.",
+ "speechToText.error.permission": "Mikrofontillatelse ble nektet.",
+ "speechToText.error.microphone": "Kunne ikke starte mikrofonen.",
+ "speechToText.error.recording": "Opptak mislyktes.",
+ "speechToText.error.emptyRecording": "Ingen lyd ble tatt opp.",
+ "speechToText.error.emptyTranscript": "Ingen tale ble oppdaget.",
+ "speechToText.error.encoding": "Kunne ikke kode opptaket.",
+ "speechToText.toast.transcribed": "Transkripsjon satt inn",
+
"prompt.toast.pasteUnsupported.title": "Liming ikke støttet",
"prompt.toast.pasteUnsupported.description": "Kun bilder eller PDF-er kan limes inn her.",
"prompt.toast.modelAgentRequired.title": "Velg en agent og modell",
@@ -1200,6 +1214,13 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Agent Manager-verktøy",
"settings.experimental.agentManagerTool.description":
"Tillat agenter å starte lokale Agent Manager-økter og worktree-økter fra et verktøykall",
+ "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":
+ "Aktiver Kilo provider og logg på for å bruke taleinndata i prompt-felt.",
+ "settings.experimental.speechToTextModel.title": "Tale-til-tekst-modell",
+ "settings.experimental.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 63289102089..3dff2197358 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts
@@ -282,6 +282,20 @@ export const dict = {
"Przycisk 'Ulepsz podpowiedź' pomaga ulepszyć Twoją prośbę, dostarczając dodatkowy kontekst, wyjaśnienia lub przeformułowania. Spróbuj wpisać prośbę tutaj i kliknij przycisk ponownie, aby zobaczyć, jak to działa.",
"prompt.action.indexing": "Ustawienia indeksowania",
+ "speechToText.tooltip.start": "Rozpocznij wprowadzanie głosowe",
+ "speechToText.tooltip.stop": "Zatrzymaj nagrywanie",
+ "speechToText.tooltip.transcribing": "Transkrybowanie... Kliknij, aby anulować.",
+ "speechToText.tooltip.error": "Wprowadzanie głosowe nie powiodło się. Kliknij, aby wyczyścić.",
+ "speechToText.error.title": "Wprowadzanie głosowe nie powiodło się",
+ "speechToText.error.loginRequired": "Zaloguj się do Kilo, aby korzystać z wprowadzania głosowego.",
+ "speechToText.error.permission": "Odmówiono dostępu do mikrofonu.",
+ "speechToText.error.microphone": "Nie udało się uruchomić mikrofonu.",
+ "speechToText.error.recording": "Nagrywanie nie powiodło się.",
+ "speechToText.error.emptyRecording": "Nie nagrano żadnego dźwięku.",
+ "speechToText.error.emptyTranscript": "Nie wykryto mowy.",
+ "speechToText.error.encoding": "Nie udało się zakodować nagrania.",
+ "speechToText.toast.transcribed": "Wstawiono transkrypcję",
+
"prompt.toast.pasteUnsupported.title": "Nieobsługiwane wklejanie",
"prompt.toast.pasteUnsupported.description": "Tylko obrazy lub pliki PDF mogą być tutaj wklejane.",
"prompt.toast.modelAgentRequired.title": "Wybierz agenta i model",
@@ -1199,6 +1213,14 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Narzędzie Agent Manager",
"settings.experimental.agentManagerTool.description":
"Zezwól agentom na uruchamianie lokalnych sesji Agent Manager i sesji worktree z wywołania narzędzia",
+ "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":
+ "Włącz Kilo provider i zaloguj się, aby korzystać z wprowadzania głosowego w polach promptów.",
+ "settings.experimental.speechToTextModel.title": "Model mowy na tekst",
+ "settings.experimental.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",
"settings.experimental.mcpTimeout.title": "Limit czasu MCP (ms)",
diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts
index ae20ef5057f..ec455981d62 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts
@@ -280,6 +280,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"Кнопка 'Улучшить запрос' помогает сделать ваш запрос лучше, предоставляя дополнительный контекст, уточнения или переформулировку. Попробуйте ввести запрос и снова нажать кнопку, чтобы увидеть, как это работает.",
+ "speechToText.tooltip.start": "Начать голосовой ввод",
+ "speechToText.tooltip.stop": "Остановить запись",
+ "speechToText.tooltip.transcribing": "Распознавание... Нажмите для отмены.",
+ "speechToText.tooltip.error": "Ошибка голосового ввода. Нажмите, чтобы очистить.",
+ "speechToText.error.title": "Ошибка голосового ввода",
+ "speechToText.error.loginRequired": "Войдите в Kilo, чтобы использовать голосовой ввод.",
+ "speechToText.error.permission": "В доступе к микрофону отказано.",
+ "speechToText.error.microphone": "Не удалось запустить микрофон.",
+ "speechToText.error.recording": "Ошибка записи.",
+ "speechToText.error.emptyRecording": "Звук не был записан.",
+ "speechToText.error.emptyTranscript": "Речь не обнаружена.",
+ "speechToText.error.encoding": "Не удалось закодировать запись.",
+ "speechToText.toast.transcribed": "Транскрипция вставлена",
+
"prompt.toast.pasteUnsupported.title": "Неподдерживаемая вставка",
"prompt.toast.pasteUnsupported.description": "Сюда можно вставлять только изображения или PDF.",
"prompt.toast.modelAgentRequired.title": "Выберите агента и модель",
@@ -1237,6 +1251,14 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Инструмент Agent Manager",
"settings.experimental.agentManagerTool.description":
"Разрешить агентам запускать локальные сеансы Agent Manager и сеансы worktree через вызов инструмента",
+ "settings.experimental.speechToText.title": "Речь в текст",
+ "settings.experimental.speechToText.description":
+ "Включите голосовой ввод в полях запросов, используя вашу учетную запись Kilo через Kilo Gateway.",
+ "settings.experimental.speechToText.disabledDescription":
+ "Включите Kilo provider и войдите в него, чтобы использовать голосовой ввод в полях запросов.",
+ "settings.experimental.speechToTextModel.title": "Модель речи в текст",
+ "settings.experimental.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 c29a61c2b27..47e94e2c208 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts
@@ -280,6 +280,20 @@ export const dict = {
"ปุ่ม 'ปรับปรุงพรอมต์' ช่วยปรับปรุงพรอมต์ของคุณโดยให้บริบทเพิ่มเติม ชี้แจง หรือเขียนใหม่ ลองพิมพ์พรอมต์ที่นี่และคลิกปุ่มอีกครั้งเพื่อดูว่ามันทำงานอย่างไร",
"prompt.action.indexing": "การตั้งค่าการสร้างดัชนี",
+ "speechToText.tooltip.start": "เริ่มการป้อนข้อมูลด้วยเสียง",
+ "speechToText.tooltip.stop": "หยุดบันทึก",
+ "speechToText.tooltip.transcribing": "กำลังถอดเสียง... คลิกเพื่อยกเลิก",
+ "speechToText.tooltip.error": "การป้อนข้อมูลด้วยเสียงล้มเหลว คลิกเพื่อล้าง",
+ "speechToText.error.title": "การป้อนข้อมูลด้วยเสียงล้มเหลว",
+ "speechToText.error.loginRequired": "ลงชื่อเข้าใช้ Kilo เพื่อใช้การป้อนข้อมูลด้วยเสียง",
+ "speechToText.error.permission": "การอนุญาตเข้าถึงไมโครโฟนถูกปฏิเสธ",
+ "speechToText.error.microphone": "ไม่สามารถเริ่มต้นไมโครโฟนได้",
+ "speechToText.error.recording": "การบันทึกล้มเหลว",
+ "speechToText.error.emptyRecording": "ไม่มีการบันทึกเสียง",
+ "speechToText.error.emptyTranscript": "ตรวจไม่พบเสียงพูด",
+ "speechToText.error.encoding": "ไม่สามารถเข้ารหัสการบันทึกได้",
+ "speechToText.toast.transcribed": "แทรกข้อความที่ถอดเสียงแล้ว",
+
"prompt.toast.pasteUnsupported.title": "การวางไม่รองรับ",
"prompt.toast.pasteUnsupported.description": "สามารถวางรูปภาพหรือ PDF เท่านั้น",
"prompt.toast.modelAgentRequired.title": "เลือกเอเจนต์และโมเดล",
@@ -1220,6 +1234,14 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "เครื่องมือ Agent Manager",
"settings.experimental.agentManagerTool.description":
"อนุญาตให้เอเจนต์เริ่มเซสชัน Agent Manager ในเครื่องและเซสชัน worktree จากการเรียกเครื่องมือ",
+ "settings.experimental.speechToText.title": "แปลงเสียงเป็นข้อความ",
+ "settings.experimental.speechToText.description":
+ "เปิดใช้งานการป้อนข้อมูลด้วยเสียงในช่องพรอมต์โดยใช้บัญชี Kilo ของคุณผ่าน Kilo Gateway",
+ "settings.experimental.speechToText.disabledDescription":
+ "เปิดใช้งานและลงชื่อเข้าใช้ Kilo provider เพื่อใช้การป้อนข้อมูลด้วยเสียงในช่องพรอมต์",
+ "settings.experimental.speechToTextModel.title": "โมเดลแปลงเสียงเป็นข้อความ",
+ "settings.experimental.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 de26b4a0573..0c1736f0b45 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts
@@ -280,6 +280,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"'Komutu Geliştir' düğmesi, ek bağlam, açıklama veya yeniden ifadelendirme sağlayarak komutunuzu iyileştirmeye yardımcı olur. Buraya bir komut yazıp düğmeye tekrar tıklayarak nasıl çalıştığını görebilirsiniz.",
+ "speechToText.tooltip.start": "Sesli girişi başlat",
+ "speechToText.tooltip.stop": "Kaydı durdur",
+ "speechToText.tooltip.transcribing": "Metne dönüştürülüyor... İptal etmek için tıklayın.",
+ "speechToText.tooltip.error": "Sesli giriş başarısız oldu. Temizlemek için tıklayın.",
+ "speechToText.error.title": "Sesli giriş başarısız oldu",
+ "speechToText.error.loginRequired": "Sesli girişi kullanmak için Kilo'ya giriş yapın.",
+ "speechToText.error.permission": "Mikrofon izni reddedildi.",
+ "speechToText.error.microphone": "Mikrofon başlatılamadı.",
+ "speechToText.error.recording": "Kayıt başarısız oldu.",
+ "speechToText.error.emptyRecording": "Hiçbir ses kaydedilmedi.",
+ "speechToText.error.emptyTranscript": "Hiçbir konuşma algılanmadı.",
+ "speechToText.error.encoding": "Kayıt kodlanamadı.",
+ "speechToText.toast.transcribed": "Döküm eklendi",
+
"prompt.toast.pasteUnsupported.title": "Desteklenmeyen yapıştırma",
"prompt.toast.pasteUnsupported.description": "Buraya sadece görsel veya PDF yapıştırılabilir.",
"prompt.toast.modelAgentRequired.title": "Bir ajan ve model seçin",
@@ -1233,6 +1247,13 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Agent Manager Aracı",
"settings.experimental.agentManagerTool.description":
"Ajanların bir araç çağrısından Agent Manager yerel oturumları ve worktree oturumları başlatmasına izin ver",
+ "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":
+ "Komut alanlarında sesli girişi kullanmak için Kilo provider'ı etkinleştirin ve giriş yapın.",
+ "settings.experimental.speechToTextModel.title": "Sesten metne modeli",
+ "settings.experimental.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 bcfe2046569..6ca7663b7d0 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts
@@ -282,6 +282,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"Кнопка 'Покращити запит' допомагає вдосконалити ваш запит, надаючи додатковий контекст, уточнення або перефразування. Введіть запит тут і натисніть кнопку ще раз, щоб побачити, як це працює.",
+ "speechToText.tooltip.start": "Почати голосове введення",
+ "speechToText.tooltip.stop": "Зупинити запис",
+ "speechToText.tooltip.transcribing": "Транскрибування... Натисніть, щоб скасувати.",
+ "speechToText.tooltip.error": "Помилка голосового введення. Натисніть, щоб очистити.",
+ "speechToText.error.title": "Помилка голосового введення",
+ "speechToText.error.loginRequired": "Увійдіть до Kilo, щоб використовувати голосове введення.",
+ "speechToText.error.permission": "Доступ до мікрофона заборонено.",
+ "speechToText.error.microphone": "Не вдалося запустити мікрофон.",
+ "speechToText.error.recording": "Помилка запису.",
+ "speechToText.error.emptyRecording": "Аудіо не записано.",
+ "speechToText.error.emptyTranscript": "Мовлення не виявлено.",
+ "speechToText.error.encoding": "Не вдалося закодувати запис.",
+ "speechToText.toast.transcribed": "Транскрипцію вставлено",
+
"prompt.toast.pasteUnsupported.title": "Вставка не підтримується",
"prompt.toast.pasteUnsupported.description": "Сюди можна вставляти лише зображення або PDF.",
"prompt.toast.modelAgentRequired.title": "Виберіть агента і модель",
@@ -1233,6 +1247,14 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Інструмент Agent Manager",
"settings.experimental.agentManagerTool.description":
"Дозволити агентам запускати локальні сесії Agent Manager і сесії worktree через виклик інструмента",
+ "settings.experimental.speechToText.title": "Мовлення в текст",
+ "settings.experimental.speechToText.description":
+ "Увімкніть голосове введення в полях запитів, використовуючи ваш обліковий запис Kilo через Kilo Gateway.",
+ "settings.experimental.speechToText.disabledDescription":
+ "Увімкніть Kilo provider і увійдіть, щоб використовувати голосове введення в полях запитів.",
+ "settings.experimental.speechToTextModel.title": "Модель мовлення в текст",
+ "settings.experimental.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 0aa747f2a36..c5024648aa3 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts
@@ -279,6 +279,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"'增强提示'按钮通过提供额外上下文、澄清或重新表述来帮助改进您的请求。尝试在此处输入请求,然后再次点击按钮查看其工作原理。",
+ "speechToText.tooltip.start": "开始语音输入",
+ "speechToText.tooltip.stop": "停止录音",
+ "speechToText.tooltip.transcribing": "正在转录... 点击取消。",
+ "speechToText.tooltip.error": "语音输入失败。点击清除。",
+ "speechToText.error.title": "语音输入失败",
+ "speechToText.error.loginRequired": "登录 Kilo 以使用语音输入。",
+ "speechToText.error.permission": "麦克风权限被拒绝。",
+ "speechToText.error.microphone": "无法启动麦克风。",
+ "speechToText.error.recording": "录音失败。",
+ "speechToText.error.emptyRecording": "未录制任何音频。",
+ "speechToText.error.emptyTranscript": "未检测到语音。",
+ "speechToText.error.encoding": "无法编码录音。",
+ "speechToText.toast.transcribed": "已插入转录文本",
+
"prompt.toast.pasteUnsupported.title": "不支持的粘贴",
"prompt.toast.pasteUnsupported.description": "这里只能粘贴图片或 PDF 文件。",
"prompt.toast.modelAgentRequired.title": "请选择智能体和模型",
@@ -1202,6 +1216,11 @@ export const dict = {
"settings.experimental.codebaseSearch.description": "启用 AI 驱动的自然语言代码库搜索",
"settings.experimental.agentManagerTool.title": "Agent Manager 工具",
"settings.experimental.agentManagerTool.description": "允许智能体通过工具调用启动 Agent Manager 本地会话和工作树会话",
+ "settings.experimental.speechToText.title": "语音转文本",
+ "settings.experimental.speechToText.description": "通过 Kilo Gateway 使用您的 Kilo 帐户在提示词字段中启用语音输入。",
+ "settings.experimental.speechToText.disabledDescription": "启用并登录 Kilo provider 以在提示词字段中使用语音输入。",
+ "settings.experimental.speechToTextModel.title": "语音转文本模型",
+ "settings.experimental.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 2f28047d674..2cd8ed1cc6f 100644
--- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts
+++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts
@@ -278,6 +278,20 @@ export const dict = {
"prompt.action.enhanceDescription":
"「強化提示詞」按鈕可透過提供額外內容、說明或改寫來協助改善提示詞。試著在這裡輸入提示詞,再點選一次按鈕以了解其運作方式。",
+ "speechToText.tooltip.start": "開始語音輸入",
+ "speechToText.tooltip.stop": "停止錄音",
+ "speechToText.tooltip.transcribing": "正在轉錄... 點擊取消。",
+ "speechToText.tooltip.error": "語音輸入失敗。點擊清除。",
+ "speechToText.error.title": "語音輸入失敗",
+ "speechToText.error.loginRequired": "登入 Kilo 以使用語音輸入。",
+ "speechToText.error.permission": "麥克風權限被拒絕。",
+ "speechToText.error.microphone": "無法啟動麥克風。",
+ "speechToText.error.recording": "錄音失敗。",
+ "speechToText.error.emptyRecording": "未錄製任何音訊。",
+ "speechToText.error.emptyTranscript": "未偵測到語音。",
+ "speechToText.error.encoding": "無法編碼錄音。",
+ "speechToText.toast.transcribed": "已插入轉錄文字",
+
"prompt.toast.pasteUnsupported.title": "不支援的貼上",
"prompt.toast.pasteUnsupported.description": "這裡只能貼上圖片或 PDF 檔案。",
"prompt.toast.modelAgentRequired.title": "請選擇 Agent 和模型",
@@ -1171,6 +1185,11 @@ export const dict = {
"settings.experimental.agentManagerTool.title": "Agent Manager 工具",
"settings.experimental.agentManagerTool.description":
"允許 Agent 透過工具呼叫啟動 Agent Manager 本機工作階段和工作樹工作階段",
+ "settings.experimental.speechToText.title": "語音轉文字",
+ "settings.experimental.speechToText.description": "透過 Kilo Gateway 使用您的 Kilo 帳戶在提示詞欄位中啟用語音輸入。",
+ "settings.experimental.speechToText.disabledDescription": "啟用並登入 Kilo provider 以在提示詞欄位中使用語音輸入。",
+ "settings.experimental.speechToTextModel.title": "語音轉文字模型",
+ "settings.experimental.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/styles/prompt-input.css b/packages/kilo-vscode/webview-ui/src/styles/prompt-input.css
index 99b98ef7329..2a158d5e475 100644
--- a/packages/kilo-vscode/webview-ui/src/styles/prompt-input.css
+++ b/packages/kilo-vscode/webview-ui/src/styles/prompt-input.css
@@ -563,6 +563,54 @@
box-shadow: 0 0 0 1px var(--surface-base, var(--vscode-editor-background));
}
+.prompt-speech-button {
+ position: relative;
+}
+
+.prompt-speech-button--recording {
+ color: var(--vscode-errorForeground, #f48771);
+
+ [data-slot="icon-svg"] {
+ color: currentColor !important;
+ }
+
+ .prompt-speech-icon {
+ animation: prompt-speech-recording-pulse 1.1s ease-in-out infinite;
+ }
+}
+
+.prompt-speech-button--recording::after {
+ content: "";
+ position: absolute;
+ right: 4px;
+ top: 4px;
+ width: 5px;
+ height: 5px;
+ border-radius: 999px;
+ background: currentColor;
+ box-shadow: 0 0 0 2px var(--surface-base, var(--vscode-editor-background));
+}
+
+.prompt-speech-button--error {
+ color: var(--vscode-charts-yellow, #cca700);
+
+ [data-slot="icon-svg"] {
+ color: currentColor !important;
+ }
+}
+
+@keyframes prompt-speech-recording-pulse {
+ 0%,
+ 100% {
+ opacity: 1;
+ transform: scale(1);
+ }
+ 50% {
+ opacity: 0.72;
+ transform: scale(0.94);
+ }
+}
+
/* ============================================
Enhance Prompt Spinner
============================================ */
diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts
index a7718ae35e4..76671975e38 100644
--- a/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts
+++ b/packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts
@@ -333,12 +333,43 @@ export interface AutocompleteSettingsLoadedMessage {
}
}
+export interface SpeechToTextSettingsLoadedMessage {
+ type: "speechToTextSettingsLoaded"
+ settings: {
+ enabled: boolean
+ model: string
+ }
+}
+
export interface ChatCompletionResultMessage {
type: "chatCompletionResult"
text: string
requestId: string
}
+export interface SpeechToTextResultMessage {
+ type: "speechToTextResult"
+ text: string
+ requestId: string
+}
+
+export interface SpeechToTextStartedMessage {
+ type: "speechToTextStarted"
+ requestId: string
+}
+
+export interface SpeechToTextCancelledMessage {
+ type: "speechToTextCancelled"
+ requestId: string
+}
+
+export interface SpeechToTextErrorMessage {
+ type: "speechToTextError"
+ error: string
+ code?: string
+ requestId: string
+}
+
export interface FileSearchItem {
path: string
type: "file" | "folder" | "opened-file"
@@ -929,7 +960,12 @@ export type ExtensionMessage =
| SkillsLoadedMessage
| CommandsLoadedMessage
| AutocompleteSettingsLoadedMessage
+ | SpeechToTextSettingsLoadedMessage
| ChatCompletionResultMessage
+ | SpeechToTextStartedMessage
+ | SpeechToTextCancelledMessage
+ | SpeechToTextResultMessage
+ | SpeechToTextErrorMessage
| FileSearchResultMessage
| TerminalContextResultMessage
| TerminalContextErrorMessage
diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts
index 51c37652c15..42907697a2e 100644
--- a/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts
+++ b/packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts
@@ -322,12 +322,33 @@ export interface RequestAutocompleteSettingsMessage {
type: "requestAutocompleteSettings"
}
+export interface RequestSpeechToTextSettingsMessage {
+ type: "requestSpeechToTextSettings"
+}
+
export interface RequestChatCompletionMessage {
type: "requestChatCompletion"
text: string
requestId: string
}
+export interface SpeechToTextStartMessage {
+ type: "speechToTextStart"
+ requestId: string
+ model: string
+ language?: string
+}
+
+export interface SpeechToTextStopMessage {
+ type: "speechToTextStop"
+ requestId: string
+}
+
+export interface SpeechToTextCancelMessage {
+ type: "speechToTextCancel"
+ requestId: string
+}
+
export interface RequestFileSearchMessage {
type: "requestFileSearch"
query: string
@@ -1077,7 +1098,11 @@ export type WebviewMessage =
| DeleteSessionRequest
| RenameSessionRequest
| RequestAutocompleteSettingsMessage
+ | RequestSpeechToTextSettingsMessage
| RequestChatCompletionMessage
+ | SpeechToTextStartMessage
+ | SpeechToTextStopMessage
+ | SpeechToTextCancelMessage
| RequestFileSearchMessage
| RequestTerminalContextMessage
| RequestGitChangesContextMessage
diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts
index 85965622358..199053fd00d 100644
--- a/packages/sdk/js/src/v2/gen/sdk.gen.ts
+++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts
@@ -62,6 +62,8 @@ import type {
GlobalUpgradeResponses,
IndexingStatusResponses,
InstanceDisposeResponses,
+ KiloAudioTranscriptionsErrors,
+ KiloAudioTranscriptionsResponses,
KiloClawChatCredentialsResponses,
KiloClawStatusResponses,
KiloCloudSessionGetErrors,
@@ -5745,6 +5747,58 @@ export class Organization extends HeyApiClient {
}
}
+export class Audio extends HeyApiClient {
+ /**
+ * Speech to text transcription
+ *
+ * Proxy an audio transcription request to the Kilo Gateway
+ */
+ public transcriptions(
+ parameters?: {
+ directory?: string
+ workspace?: string
+ model?: string
+ input_audio?: {
+ data: string
+ format: string
+ }
+ language?: string
+ temperature?: number
+ },
+ options?: Options,
+ ) {
+ const params = buildClientParams(
+ [parameters],
+ [
+ {
+ args: [
+ { in: "query", key: "directory" },
+ { in: "query", key: "workspace" },
+ { in: "body", key: "model" },
+ { in: "body", key: "input_audio" },
+ { in: "body", key: "language" },
+ { in: "body", key: "temperature" },
+ ],
+ },
+ ],
+ )
+ return (options?.client ?? this.client).post<
+ KiloAudioTranscriptionsResponses,
+ KiloAudioTranscriptionsErrors,
+ ThrowOnError
+ >({
+ url: "/kilo/audio/transcriptions",
+ ...options,
+ ...params,
+ headers: {
+ "Content-Type": "application/json",
+ ...options?.headers,
+ ...params.headers,
+ },
+ })
+ }
+}
+
export class Session3 extends HeyApiClient {
/**
* Get cloud session
@@ -6066,6 +6120,11 @@ export class Kilo extends HeyApiClient {
return (this._organization ??= new Organization({ client: this.client }))
}
+ private _audio?: Audio
+ get audio(): Audio {
+ return (this._audio ??= new Audio({ client: this.client }))
+ }
+
private _cloud?: Cloud
get cloud(): Cloud {
return (this._cloud ??= new Cloud({ client: this.client }))
diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts
index ce8f77317e9..7ec2e38bb27 100644
--- a/packages/sdk/js/src/v2/gen/types.gen.ts
+++ b/packages/sdk/js/src/v2/gen/types.gen.ts
@@ -7247,6 +7247,45 @@ export type KiloFimResponses = {
export type KiloFimResponse = KiloFimResponses[keyof KiloFimResponses]
+export type KiloAudioTranscriptionsData = {
+ body?: {
+ model: string
+ input_audio: {
+ data: string
+ format: string
+ }
+ language?: string
+ temperature?: number
+ }
+ path?: never
+ query?: {
+ directory?: string
+ workspace?: string
+ }
+ url: "/kilo/audio/transcriptions"
+}
+
+export type KiloAudioTranscriptionsErrors = {
+ /**
+ * Bad request
+ */
+ 400: BadRequestError
+}
+
+export type KiloAudioTranscriptionsError = KiloAudioTranscriptionsErrors[keyof KiloAudioTranscriptionsErrors]
+
+export type KiloAudioTranscriptionsResponses = {
+ /**
+ * Transcription response
+ */
+ 200: {
+ text: string
+ usage?: unknown
+ }
+}
+
+export type KiloAudioTranscriptionsResponse = KiloAudioTranscriptionsResponses[keyof KiloAudioTranscriptionsResponses]
+
export type KiloNotificationsData = {
body?: never
path?: never