diff --git a/.changeset/chatty-parks-cross.md b/.changeset/chatty-parks-cross.md new file mode 100644 index 0000000000..eb2aad302c --- /dev/null +++ b/.changeset/chatty-parks-cross.md @@ -0,0 +1,5 @@ +--- +"kilo-code": minor +--- + +Allow creating a profile for autocomplete to choose any model for autocomplete diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index dccde7afee..ba950a74cf 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -13,6 +13,7 @@ export * from "./mcp.js" export * from "./message.js" export * from "./mode.js" export * from "./model.js" +export * from "./profile-type.js" // kilocode_change export * from "./provider-settings.js" export * from "./single-file-read-models.js" export * from "./task.js" diff --git a/packages/types/src/profile-type.ts b/packages/types/src/profile-type.ts new file mode 100644 index 0000000000..cb1f216bc0 --- /dev/null +++ b/packages/types/src/profile-type.ts @@ -0,0 +1,12 @@ +// kilocode_change new file +import { z } from "zod" + +/** + * Profile Type System + */ + +export const profileTypes = ["chat", "autocomplete"] as const +export const profileTypeSchema = z.enum(profileTypes) +export type ProfileType = z.infer + +export const DEFAULT_PROFILE_TYPE: ProfileType = "chat" \ No newline at end of file diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 5ef923a0f6..cc943fef71 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -2,6 +2,7 @@ import { z } from "zod" import { modelInfoSchema, reasoningEffortWithMinimalSchema, verbosityLevelsSchema, serviceTierSchema } from "./model.js" import { codebaseIndexProviderSchema } from "./codebase-index.js" +import { profileTypeSchema } from "./profile-type.js" // kilocode_change import { anthropicModels, bedrockModels, @@ -172,6 +173,7 @@ export const providerSettingsEntrySchema = z.object({ name: z.string(), apiProvider: providerNamesSchema.optional(), modelId: z.string().optional(), + profileType: profileTypeSchema.optional(), // kilocode_change - autocomplete profile type system }) export type ProviderSettingsEntry = z.infer @@ -181,6 +183,7 @@ export type ProviderSettingsEntry = z.infer */ const baseProviderSettingsSchema = z.object({ + profileType: profileTypeSchema.optional(), // kilocode_change - autocomplete profile type system includeMaxTokens: z.boolean().optional(), diffEnabled: z.boolean().optional(), todoListEnabled: z.boolean().optional(), diff --git a/src/core/config/ProviderSettingsManager.ts b/src/core/config/ProviderSettingsManager.ts index 3e1408bf68..2fb356f721 100644 --- a/src/core/config/ProviderSettingsManager.ts +++ b/src/core/config/ProviderSettingsManager.ts @@ -12,11 +12,13 @@ import { getModelId, type ProviderName, type RooModelId, + type ProfileType, // kilocode_change - autocomplete profile type system } from "@roo-code/types" import { TelemetryService } from "@roo-code/telemetry" import { Mode, modes } from "../../shared/modes" import { migrateMorphApiKey } from "./kilocode/migrateMorphApiKey" +import { t } from "../../i18n" // kilocode_change - autocomplete profile type system // Type-safe model migrations mapping type ModelMigrations = { @@ -369,6 +371,7 @@ export class ProviderSettingsManager { id: apiConfig.id || "", apiProvider: apiConfig.apiProvider, modelId: this.cleanModelId(getModelId(apiConfig)), + profileType: apiConfig.profileType, // kilocode_change - autocomplete profile type system })) }) } catch (error) { @@ -376,6 +379,30 @@ export class ProviderSettingsManager { } } + // kilocode_change start - autocomplete profile type system + /** + * Validate that only one autocomplete profile exists + */ + private async validateAutocompleteConstraint( + profiles: ProviderProfiles, + newProfileName: string, + newProfileType?: ProfileType, + ): Promise { + if (newProfileType !== "autocomplete") { + return // No constraint for non-autocomplete profiles + } + + const autocompleteProfiles = Object.entries(profiles.apiConfigs).filter( + ([name, config]) => config.profileType === "autocomplete" && name !== newProfileName, + ) + + if (autocompleteProfiles.length > 0) { + const existingName = autocompleteProfiles[0][0] + throw new Error(t("settings:providers.autocomplete.onlyOneAllowed", { existingName })) + } + } + // kilocode_change end + /** * Save a config with the given name. * Preserves the ID from the input 'config' object if it exists, @@ -385,6 +412,10 @@ export class ProviderSettingsManager { try { return await this.lock(async () => { const providerProfiles = await this.load() + + // kilocode_change - autocomplete profile type system + await this.validateAutocompleteConstraint(providerProfiles, name, config.profileType) + // Preserve the existing ID if this is an update to an existing config. const existingId = providerProfiles.apiConfigs[name]?.id const id = config.id || existingId || this.generateId() diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 48199607af..368179c85f 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -2105,6 +2105,9 @@ export const webviewMessageHandler = async ( if (organizationChanged) { await provider.postStateToWebview() } + + // kilocode_change: Reload ghost model when API provider settings change + vscode.commands.executeCommand("kilo-code.ghost.reload") } // kilocode_change end: check for kilocodeToken change to remove organizationId and fetch organization modes break @@ -2129,6 +2132,9 @@ export const webviewMessageHandler = async ( // Re-activate to update the global settings related to the // currently activated provider profile. await provider.activateProviderProfile({ name: newName }) + + // kilocode_change: Reload ghost model when API provider settings change + vscode.commands.executeCommand("kilo-code.ghost.reload") } catch (error) { provider.log( `Error rename api configuration: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`, @@ -2188,6 +2194,9 @@ export const webviewMessageHandler = async ( try { await provider.providerSettingsManager.deleteConfig(oldName) await provider.activateProviderProfile({ name: newName }) + + // kilocode_change: Reload ghost model when API provider settings change + vscode.commands.executeCommand("kilo-code.ghost.reload") } catch (error) { provider.log( `Error delete api configuration: ${JSON.stringify(error, Object.getOwnPropertyNames(error), 2)}`, diff --git a/src/i18n/locales/ar/kilocode.json b/src/i18n/locales/ar/kilocode.json index 6561fecf2b..8bd8f8cecb 100644 --- a/src/i18n/locales/ar/kilocode.json +++ b/src/i18n/locales/ar/kilocode.json @@ -105,6 +105,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "الإكمال التلقائي: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (معطل)", @@ -112,7 +113,10 @@ "lastCompletion": "آخر اقتراح:", "sessionTotal": "إجمالي تكلفة الجلسة:", "provider": "المزود:", - "model": "النموذج:" + "model": "النموذج:", + "profile": "الملف الشخصي: ", + "defaultProfile": "افتراضي", + "autocompleteLabel": "(الإكمال التلقائي)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/ca/kilocode.json b/src/i18n/locales/ca/kilocode.json index 0dfd6d09c3..a82edc6114 100644 --- a/src/i18n/locales/ca/kilocode.json +++ b/src/i18n/locales/ca/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Autocompletat: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (desactivat)", @@ -108,7 +109,10 @@ "lastCompletion": "Últim suggeriment:", "sessionTotal": "Cost total de la sessió:", "provider": "Proveïdor:", - "model": "Model:" + "model": "Model:", + "profile": "Perfil: ", + "defaultProfile": "Per defecte", + "autocompleteLabel": "(Autocompletat)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/cs/kilocode.json b/src/i18n/locales/cs/kilocode.json index 040a72d20e..9928f019df 100644 --- a/src/i18n/locales/cs/kilocode.json +++ b/src/i18n/locales/cs/kilocode.json @@ -107,6 +107,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Automatické dokončování: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (zakázáno)", @@ -114,7 +115,10 @@ "lastCompletion": "Poslední návrh:", "sessionTotal": "Celkové náklady relace:", "provider": "Poskytovatel:", - "model": "Model:" + "model": "Model:", + "profile": "Profil: ", + "defaultProfile": "Výchozí", + "autocompleteLabel": "(Automatické dokončování)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/de/kilocode.json b/src/i18n/locales/de/kilocode.json index f3778e6f0d..58de456d7e 100644 --- a/src/i18n/locales/de/kilocode.json +++ b/src/i18n/locales/de/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Autovervollständigung: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (deaktiviert)", @@ -108,7 +109,10 @@ "lastCompletion": "Letzter Vorschlag:", "sessionTotal": "Sitzungsgesamtkosten:", "provider": "Anbieter:", - "model": "Modell:" + "model": "Modell:", + "profile": "Profil: ", + "defaultProfile": "Standard", + "autocompleteLabel": "(Autovervollständigung)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/en/kilocode.json b/src/i18n/locales/en/kilocode.json index 01c202eb07..8cae3f6a9f 100644 --- a/src/i18n/locales/en/kilocode.json +++ b/src/i18n/locales/en/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Autocomplete: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (disabled)", @@ -108,7 +109,10 @@ "lastCompletion": "Last suggestion:", "sessionTotal": "Session total cost:", "provider": "Provider:", - "model": "Model:" + "model": "Model:", + "profile": "Profile: ", + "defaultProfile": "Default", + "autocompleteLabel": "(Autocomplete)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/es/kilocode.json b/src/i18n/locales/es/kilocode.json index edfebc6773..c321834b08 100644 --- a/src/i18n/locales/es/kilocode.json +++ b/src/i18n/locales/es/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Autocompletado: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (deshabilitado)", @@ -108,7 +109,10 @@ "lastCompletion": "Última sugerencia:", "sessionTotal": "Costo total de la sesión:", "provider": "Proveedor:", - "model": "Modelo:" + "model": "Modelo:", + "profile": "Perfil: ", + "defaultProfile": "Predeterminado", + "autocompleteLabel": "(Autocompletado)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/fr/kilocode.json b/src/i18n/locales/fr/kilocode.json index d7b8280902..729cc1ea2a 100644 --- a/src/i18n/locales/fr/kilocode.json +++ b/src/i18n/locales/fr/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Autocomplétion : ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (désactivé)", @@ -108,7 +109,10 @@ "lastCompletion": "Dernière suggestion :", "sessionTotal": "Coût total de la session :", "provider": "Fournisseur:", - "model": "Modèle :" + "model": "Modèle :", + "profile": "Profil : ", + "defaultProfile": "Par défaut", + "autocompleteLabel": "(Autocomplétion)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/hi/kilocode.json b/src/i18n/locales/hi/kilocode.json index c1f32270c0..2a4e771c3f 100644 --- a/src/i18n/locales/hi/kilocode.json +++ b/src/i18n/locales/hi/kilocode.json @@ -107,6 +107,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "ऑटोकम्पलीट: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (अक्षम)", @@ -114,7 +115,10 @@ "lastCompletion": "अंतिम सुझाव:", "sessionTotal": "सत्र की कुल लागत:", "provider": "प्रदाता:", - "model": "मॉडल:" + "model": "मॉडल:", + "profile": "प्रोफ़ाइल: ", + "defaultProfile": "डिफ़ॉल्ट", + "autocompleteLabel": "(ऑटोकम्पलीट)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/id/kilocode.json b/src/i18n/locales/id/kilocode.json index 946e5b0752..69185b6acf 100644 --- a/src/i18n/locales/id/kilocode.json +++ b/src/i18n/locales/id/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Pelengkapan Otomatis: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (dinonaktifkan)", @@ -108,7 +109,10 @@ "lastCompletion": "Saran terakhir:", "sessionTotal": "Total biaya sesi:", "provider": "Penyedia:", - "model": "Model:" + "model": "Model:", + "profile": "Profil: ", + "defaultProfile": "Default", + "autocompleteLabel": "(Pelengkapan Otomatis)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/it/kilocode.json b/src/i18n/locales/it/kilocode.json index 331ba8e73e..b9a2e66edc 100644 --- a/src/i18n/locales/it/kilocode.json +++ b/src/i18n/locales/it/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Autocompletamento: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (disabilitato)", @@ -108,7 +109,10 @@ "lastCompletion": "Ultimo suggerimento:", "sessionTotal": "Costo totale della sessione:", "provider": "Provider:", - "model": "Modello:" + "model": "Modello:", + "profile": "Profilo: ", + "defaultProfile": "Predefinito", + "autocompleteLabel": "(Autocompletamento)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/ja/kilocode.json b/src/i18n/locales/ja/kilocode.json index ee4ba9572c..ade87daeab 100644 --- a/src/i18n/locales/ja/kilocode.json +++ b/src/i18n/locales/ja/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "オートコンプリート: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete(無効)", @@ -108,7 +109,10 @@ "lastCompletion": "最後の提案:", "sessionTotal": "セッション合計コスト:", "provider": "プロバイダー:", - "model": "モデル:" + "model": "モデル:", + "profile": "プロファイル: ", + "defaultProfile": "デフォルト", + "autocompleteLabel": "(オートコンプリート)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/ko/kilocode.json b/src/i18n/locales/ko/kilocode.json index ebfb88e7aa..c0c4b3a01b 100644 --- a/src/i18n/locales/ko/kilocode.json +++ b/src/i18n/locales/ko/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "자동 완성: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (비활성화됨)", @@ -108,7 +109,10 @@ "lastCompletion": "마지막 제안:", "sessionTotal": "세션 총 비용:", "provider": "제공업체:", - "model": "모델:" + "model": "모델:", + "profile": "프로필: ", + "defaultProfile": "기본값", + "autocompleteLabel": "(자동 완성)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/nl/kilocode.json b/src/i18n/locales/nl/kilocode.json index 3b5be1f3dc..8d2f41fdc6 100644 --- a/src/i18n/locales/nl/kilocode.json +++ b/src/i18n/locales/nl/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Automatisch aanvullen: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (uitgeschakeld)", @@ -108,7 +109,10 @@ "lastCompletion": "Laatste suggestie:", "sessionTotal": "Totale sessiekosten:", "provider": "Provider:", - "model": "Model:" + "model": "Model:", + "profile": "Profiel: ", + "defaultProfile": "Standaard", + "autocompleteLabel": "(Automatisch aanvullen)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/pl/kilocode.json b/src/i18n/locales/pl/kilocode.json index 1e5837a232..3c89acd1d2 100644 --- a/src/i18n/locales/pl/kilocode.json +++ b/src/i18n/locales/pl/kilocode.json @@ -107,6 +107,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Autouzupełnianie: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (wyłączone)", @@ -114,7 +115,10 @@ "lastCompletion": "Ostatnia sugestia:", "sessionTotal": "Całkowity koszt sesji:", "provider": "Dostawca:", - "model": "Model:" + "model": "Model:", + "profile": "Profil: ", + "defaultProfile": "Domyślny", + "autocompleteLabel": "(Autouzupełnianie)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/pt-BR/kilocode.json b/src/i18n/locales/pt-BR/kilocode.json index e958631eca..353b5033f1 100644 --- a/src/i18n/locales/pt-BR/kilocode.json +++ b/src/i18n/locales/pt-BR/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Autocompletar: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (desabilitado)", @@ -108,7 +109,10 @@ "lastCompletion": "Última sugestão:", "sessionTotal": "Custo total da sessão:", "provider": "Provedor:", - "model": "Modelo:" + "model": "Modelo:", + "profile": "Perfil: ", + "defaultProfile": "Padrão", + "autocompleteLabel": "(Autocompletar)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/ru/kilocode.json b/src/i18n/locales/ru/kilocode.json index 3e43f4a4f1..13fab7fc46 100644 --- a/src/i18n/locales/ru/kilocode.json +++ b/src/i18n/locales/ru/kilocode.json @@ -96,6 +96,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Автодополнение: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (отключено)", @@ -103,7 +104,10 @@ "lastCompletion": "Последнее предложение:", "sessionTotal": "Общая стоимость сессии:", "provider": "Провайдер:", - "model": "Модель:" + "model": "Модель:", + "profile": "Профиль: ", + "defaultProfile": "По умолчанию", + "autocompleteLabel": "(Автодополнение)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/th/kilocode.json b/src/i18n/locales/th/kilocode.json index 551cb3fb9c..757db690c4 100644 --- a/src/i18n/locales/th/kilocode.json +++ b/src/i18n/locales/th/kilocode.json @@ -107,6 +107,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "เติมข้อความอัตโนมัติ: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (ปิดใช้งาน)", @@ -114,7 +115,10 @@ "lastCompletion": "คำแนะนำล่าสุด:", "sessionTotal": "ค่าใช้จ่ายรวมของเซสชัน:", "provider": "ผู้ให้บริการ:", - "model": "โมเดล:" + "model": "โมเดล:", + "profile": "โปรไฟล์: ", + "defaultProfile": "ค่าเริ่มต้น", + "autocompleteLabel": "(เติมข้อความอัตโนมัติ)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/tr/kilocode.json b/src/i18n/locales/tr/kilocode.json index ca1e828b8b..9c93a9646a 100644 --- a/src/i18n/locales/tr/kilocode.json +++ b/src/i18n/locales/tr/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Otomatik Tamamlama: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (devre dışı)", @@ -108,7 +109,10 @@ "lastCompletion": "Son öneri:", "sessionTotal": "Oturum toplam maliyeti:", "provider": "Sağlayıcı:", - "model": "Model:" + "model": "Model:", + "profile": "Profil: ", + "defaultProfile": "Varsayılan", + "autocompleteLabel": "(Otomatik Tamamlama)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/uk/kilocode.json b/src/i18n/locales/uk/kilocode.json index 09c054b510..38bbb6c240 100644 --- a/src/i18n/locales/uk/kilocode.json +++ b/src/i18n/locales/uk/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Автодоповнення: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (вимкнено)", @@ -108,7 +109,10 @@ "lastCompletion": "Остання пропозиція:", "sessionTotal": "Загальна вартість сесії:", "provider": "Провайдер:", - "model": "Модель:" + "model": "Модель:", + "profile": "Профіль: ", + "defaultProfile": "За замовчуванням", + "autocompleteLabel": "(Автодоповнення)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/vi/kilocode.json b/src/i18n/locales/vi/kilocode.json index c4c2e4e8df..badb8d08fc 100644 --- a/src/i18n/locales/vi/kilocode.json +++ b/src/i18n/locales/vi/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "Tự động hoàn thành: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete (đã tắt)", @@ -108,7 +109,10 @@ "lastCompletion": "Gợi ý cuối cùng:", "sessionTotal": "Tổng chi phí phiên:", "provider": "Nhà cung cấp:", - "model": "Mô hình:" + "model": "Mô hình:", + "profile": "Hồ sơ: ", + "defaultProfile": "Mặc định", + "autocompleteLabel": "(Tự động hoàn thành)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/zh-CN/kilocode.json b/src/i18n/locales/zh-CN/kilocode.json index 025bc82141..dc6b25d213 100644 --- a/src/i18n/locales/zh-CN/kilocode.json +++ b/src/i18n/locales/zh-CN/kilocode.json @@ -107,6 +107,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "自动补全: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete(已禁用)", @@ -114,7 +115,10 @@ "lastCompletion": "最后建议:", "sessionTotal": "会话总费用:", "provider": "提供商:", - "model": "模型:" + "model": "模型:", + "profile": "配置: ", + "defaultProfile": "默认", + "autocompleteLabel": "(自动补全)" }, "cost": { "zero": "$0.00", diff --git a/src/i18n/locales/zh-TW/kilocode.json b/src/i18n/locales/zh-TW/kilocode.json index b00551bc71..2bc0d40b6d 100644 --- a/src/i18n/locales/zh-TW/kilocode.json +++ b/src/i18n/locales/zh-TW/kilocode.json @@ -101,6 +101,7 @@ "enabled": "$(sparkle) Kilo Code Autocomplete", "disabled": "$(circle-slash) Kilo Code Autocomplete", "warning": "$(warning) Kilo Code Autocomplete", + "autocompletePrefix": "自動完成: ", "tooltip": { "basic": "Kilo Code Autocomplete", "disabled": "Kilo Code Autocomplete(已停用)", @@ -108,7 +109,10 @@ "lastCompletion": "最後建議:", "sessionTotal": "工作階段總費用:", "provider": "提供者:", - "model": "模型:" + "model": "模型:", + "profile": "設定檔: ", + "defaultProfile": "預設", + "autocompleteLabel": "(自動完成)" }, "cost": { "zero": "$0.00", diff --git a/src/services/ghost/GhostModel.ts b/src/services/ghost/GhostModel.ts index a69f82e668..465679e60f 100644 --- a/src/services/ghost/GhostModel.ts +++ b/src/services/ghost/GhostModel.ts @@ -11,6 +11,8 @@ import { ApiStreamChunk } from "../../api/transform/stream" export class GhostModel { private apiHandler: ApiHandler | null = null + private profileName: string | null = null + private profileType: string | null = null public loaded = false constructor(apiHandler: ApiHandler | null = null) { @@ -21,6 +23,8 @@ export class GhostModel { } private cleanup(): void { this.apiHandler = null + this.profileName = null + this.profileType = null this.loaded = false } @@ -32,7 +36,18 @@ export class GhostModel { this.cleanup() - // Check providers in order, but skip unusable ones (e.g., kilocode with zero balance) + // First, try to find a profile specifically marked as autocomplete + const autocompleteProfile = profiles.find((x) => x.profileType === "autocomplete") + if (autocompleteProfile && autocompleteProfile.apiProvider) { + const provider = autocompleteProfile.apiProvider as keyof typeof AUTOCOMPLETE_PROVIDER_MODELS + if (supportedProviders.includes(provider)) { + await this.loadProfile(providerSettingsManager, autocompleteProfile, provider) + this.loaded = true + return true + } + } + + // Fallback: Check providers in order, but skip unusable ones (e.g., kilocode with zero balance) for (const provider of supportedProviders) { const selectedProfile = profiles.find( (x): x is typeof x & { apiProvider: string } => x?.apiProvider === provider, @@ -41,7 +56,7 @@ export class GhostModel { const isUsable = await defaultProviderUsabilityChecker(provider, providerSettingsManager) if (!isUsable) continue - this.loadProfile(providerSettingsManager, selectedProfile, provider) + await this.loadProfile(providerSettingsManager, selectedProfile, provider) this.loaded = true return true } @@ -60,10 +75,19 @@ export class GhostModel { id: selectedProfile.id, }) - this.apiHandler = buildApiHandler({ - ...profile, - [modelIdKeysByProvider[provider]]: AUTOCOMPLETE_PROVIDER_MODELS[provider], - }) + this.profileName = selectedProfile.name || null + this.profileType = selectedProfile.profileType || null + + const isExplicitAutocompleteProfile = selectedProfile.profileType === "autocomplete" + + this.apiHandler = buildApiHandler( + isExplicitAutocompleteProfile + ? profile + : { + ...profile, + [modelIdKeysByProvider[provider]]: AUTOCOMPLETE_PROVIDER_MODELS[provider], + }, + ) if (this.apiHandler instanceof OpenRouterHandler) { await this.apiHandler.fetchModel() @@ -149,4 +173,16 @@ export class GhostModel { public hasValidCredentials(): boolean { return this.apiHandler !== null && this.loaded } + + public getProfileName(): string | null { + return this.profileName + } + + public getProfileType(): string | null { + return this.profileType + } + + public isAutocompleteProfile(): boolean { + return this.profileType === "autocomplete" + } } diff --git a/src/services/ghost/GhostServiceManager.ts b/src/services/ghost/GhostServiceManager.ts index d40a4b4dba..407902137e 100644 --- a/src/services/ghost/GhostServiceManager.ts +++ b/src/services/ghost/GhostServiceManager.ts @@ -366,6 +366,8 @@ export class GhostServiceManager { enabled: this.settings?.enableAutoTrigger, model: this.getCurrentModelName(), provider: this.getCurrentProviderName(), + profileName: this.model.getProfileName(), // kilocode_change - autocomplete profile type system + isAutocompleteProfile: this.model.isAutocompleteProfile(), // kilocode_change - autocomplete profile type system hasValidToken: this.hasValidApiToken(), totalSessionCost: this.sessionCost, lastCompletionCost: this.lastCompletionCost, diff --git a/src/services/ghost/GhostStatusBar.ts b/src/services/ghost/GhostStatusBar.ts index 6b53674966..b2c2956a34 100644 --- a/src/services/ghost/GhostStatusBar.ts +++ b/src/services/ghost/GhostStatusBar.ts @@ -5,6 +5,8 @@ interface GhostStatusBarStateProps { enabled?: boolean model?: string provider?: string + profileName?: string | null + isAutocompleteProfile?: boolean hasValidToken?: boolean totalSessionCost?: number lastCompletionCost?: number @@ -15,6 +17,8 @@ export class GhostStatusBar { enabled: boolean model: string provider: string + profileName: string | null + isAutocompleteProfile: boolean hasValidToken: boolean totalSessionCost?: number lastCompletionCost?: number @@ -24,6 +28,8 @@ export class GhostStatusBar { this.enabled = params.enabled || false this.model = params.model || "default" this.provider = params.provider || "default" + this.profileName = params.profileName || null + this.isAutocompleteProfile = params.isAutocompleteProfile || false this.hasValidToken = params.hasValidToken || false this.totalSessionCost = params.totalSessionCost this.lastCompletionCost = params.lastCompletionCost @@ -59,6 +65,9 @@ export class GhostStatusBar { this.enabled = params.enabled !== undefined ? params.enabled : this.enabled this.model = params.model !== undefined ? params.model : this.model this.provider = params.provider !== undefined ? params.provider : this.provider + this.profileName = params.profileName !== undefined ? params.profileName : this.profileName + this.isAutocompleteProfile = + params.isAutocompleteProfile !== undefined ? params.isAutocompleteProfile : this.isAutocompleteProfile this.hasValidToken = params.hasValidToken !== undefined ? params.hasValidToken : this.hasValidToken this.totalSessionCost = params.totalSessionCost !== undefined ? params.totalSessionCost : this.totalSessionCost this.lastCompletionCost = @@ -76,14 +85,33 @@ export class GhostStatusBar { private renderDefault() { const totalCostFormatted = this.humanFormatCost(this.totalSessionCost || 0) const lastCompletionCostFormatted = this.lastCompletionCost?.toFixed(5) || 0 - this.statusBar.text = `${t("kilocode:ghost.statusBar.enabled")} (${totalCostFormatted})` - this.statusBar.tooltip = `\ -${t("kilocode:ghost.statusBar.tooltip.basic")} -• ${t("kilocode:ghost.statusBar.tooltip.lastCompletion")} $${lastCompletionCostFormatted} -• ${t("kilocode:ghost.statusBar.tooltip.sessionTotal")} ${totalCostFormatted} -• ${t("kilocode:ghost.statusBar.tooltip.provider")} ${this.provider} -• ${t("kilocode:ghost.statusBar.tooltip.model")} ${this.model}\ -` + + let statusText = t("kilocode:ghost.statusBar.enabled") + if (this.isAutocompleteProfile && this.profileName) { + statusText = `$(sparkle) ${t("kilocode:ghost.statusBar.autocompletePrefix")}${this.profileName}` + } else if (this.profileName) { + statusText = `$(sparkle) ${this.profileName}` + } + this.statusBar.text = `${statusText} (${totalCostFormatted})` + + let tooltipLines = [t("kilocode:ghost.statusBar.tooltip.basic")] + + if (this.isAutocompleteProfile) { + tooltipLines.push( + `• ${t("kilocode:ghost.statusBar.tooltip.profile")}${this.profileName || t("kilocode:ghost.statusBar.tooltip.defaultProfile")} ${t("kilocode:ghost.statusBar.tooltip.autocompleteLabel")}`, + ) + } else if (this.profileName) { + tooltipLines.push(`• ${t("kilocode:ghost.statusBar.tooltip.profile")}${this.profileName}`) + } + + tooltipLines.push( + `• ${t("kilocode:ghost.statusBar.tooltip.lastCompletion")} $${lastCompletionCostFormatted}`, + `• ${t("kilocode:ghost.statusBar.tooltip.sessionTotal")} ${totalCostFormatted}`, + `• ${t("kilocode:ghost.statusBar.tooltip.provider")} ${this.provider}`, + `• ${t("kilocode:ghost.statusBar.tooltip.model")} ${this.model}`, + ) + + this.statusBar.tooltip = tooltipLines.join("\n") } public render() { diff --git a/src/services/ghost/__tests__/GhostModel.spec.ts b/src/services/ghost/__tests__/GhostModel.spec.ts index 8e8dfee7bf..e8a39df645 100644 --- a/src/services/ghost/__tests__/GhostModel.spec.ts +++ b/src/services/ghost/__tests__/GhostModel.spec.ts @@ -321,5 +321,237 @@ describe("GhostModel", () => { expect(providerName).toBeTruthy() expect(typeof providerName).toBe("string") }) + + describe("profile information", () => { + it("returns null for profile name when no profile is loaded", () => { + const model = new GhostModel() + expect(model.getProfileName()).toBeNull() + }) + + it("returns null for profile type when no profile is loaded", () => { + const model = new GhostModel() + expect(model.getProfileType()).toBeNull() + }) + + it("returns false for isAutocompleteProfile when no profile is loaded", () => { + const model = new GhostModel() + expect(model.isAutocompleteProfile()).toBe(false) + }) + + it("stores and returns profile name after loading", async () => { + const supportedProviders = Object.keys(AUTOCOMPLETE_PROVIDER_MODELS) + const profiles = [ + { + id: "1", + name: "My Autocomplete Profile", + apiProvider: supportedProviders[0], + profileType: "autocomplete", + }, + ] as any + + vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) + vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ + id: "1", + name: "My Autocomplete Profile", + apiProvider: supportedProviders[0], + profileType: "autocomplete", + mistralApiKey: "test-key", + } as any) + + const model = new GhostModel() + await model.reload(mockProviderSettingsManager) + + expect(model.getProfileName()).toBe("My Autocomplete Profile") + }) + + it("stores and returns profile type after loading", async () => { + const supportedProviders = Object.keys(AUTOCOMPLETE_PROVIDER_MODELS) + const profiles = [ + { id: "1", name: "My Profile", apiProvider: supportedProviders[0], profileType: "autocomplete" }, + ] as any + + vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) + vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ + id: "1", + name: "My Profile", + apiProvider: supportedProviders[0], + profileType: "autocomplete", + mistralApiKey: "test-key", + } as any) + + const model = new GhostModel() + await model.reload(mockProviderSettingsManager) + + expect(model.getProfileType()).toBe("autocomplete") + }) + + it("returns true for isAutocompleteProfile when autocomplete profile is loaded", async () => { + const supportedProviders = Object.keys(AUTOCOMPLETE_PROVIDER_MODELS) + const profiles = [ + { id: "1", name: "My Profile", apiProvider: supportedProviders[0], profileType: "autocomplete" }, + ] as any + + vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) + vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ + id: "1", + name: "My Profile", + apiProvider: supportedProviders[0], + profileType: "autocomplete", + mistralApiKey: "test-key", + } as any) + + const model = new GhostModel() + await model.reload(mockProviderSettingsManager) + + expect(model.isAutocompleteProfile()).toBe(true) + }) + + it("returns false for isAutocompleteProfile when non-autocomplete profile is loaded", async () => { + const supportedProviders = Object.keys(AUTOCOMPLETE_PROVIDER_MODELS) + const profiles = [ + { id: "1", name: "My Profile", apiProvider: supportedProviders[0], profileType: "chat" }, + ] as any + + vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) + vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ + id: "1", + name: "My Profile", + apiProvider: supportedProviders[0], + profileType: "chat", + mistralApiKey: "test-key", + } as any) + + const model = new GhostModel() + await model.reload(mockProviderSettingsManager) + + expect(model.isAutocompleteProfile()).toBe(false) + }) + + it("clears profile information on cleanup", async () => { + const supportedProviders = Object.keys(AUTOCOMPLETE_PROVIDER_MODELS) + const profiles = [ + { id: "1", name: "My Profile", apiProvider: supportedProviders[0], profileType: "autocomplete" }, + ] as any + + vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) + vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ + id: "1", + name: "My Profile", + apiProvider: supportedProviders[0], + profileType: "autocomplete", + mistralApiKey: "test-key", + } as any) + + const model = new GhostModel() + await model.reload(mockProviderSettingsManager) + + expect(model.getProfileName()).toBe("My Profile") + expect(model.getProfileType()).toBe("autocomplete") + + // Reload with empty profiles to trigger cleanup + vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue([]) + await model.reload(mockProviderSettingsManager) + + expect(model.getProfileName()).toBeNull() + expect(model.getProfileType()).toBeNull() + }) + }) + }) + + describe("loadProfile model override behavior", () => { + it("should not override model for explicit autocomplete profiles", async () => { + const supportedProviders = Object.keys(AUTOCOMPLETE_PROVIDER_MODELS) + const provider = supportedProviders[0] as keyof typeof AUTOCOMPLETE_PROVIDER_MODELS + const customModelId = "custom-autocomplete-model" + + const autocompleteProfile = { + id: "1", + name: "My Autocomplete Profile", + apiProvider: provider, + profileType: "autocomplete", + } as any + + // Mock getProfile to return a profile with a custom model + // For mistral provider, the model key is apiModelId + vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ + id: "1", + name: "My Autocomplete Profile", + apiProvider: provider, + profileType: "autocomplete", + mistralApiKey: "test-key", + apiModelId: customModelId, // Custom model set by user + } as any) + + const model = new GhostModel() + await model.loadProfile(mockProviderSettingsManager, autocompleteProfile, provider) + + // The model should use the custom model from the profile, not the default autocomplete model + const modelName = model.getModelName() + expect(modelName).toBe(customModelId) + expect(modelName).not.toBe(AUTOCOMPLETE_PROVIDER_MODELS[provider]) + }) + + it("should override model for automatically detected profiles", async () => { + const supportedProviders = Object.keys(AUTOCOMPLETE_PROVIDER_MODELS) + const provider = supportedProviders[0] as keyof typeof AUTOCOMPLETE_PROVIDER_MODELS + const customModelId = "custom-chat-model" + + const chatProfile = { + id: "1", + name: "My Chat Profile", + apiProvider: provider, + profileType: "chat", // Not an autocomplete profile + } as any + + // Mock getProfile to return a profile with a custom model + // For mistral provider, the model key is apiModelId + vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ + id: "1", + name: "My Chat Profile", + apiProvider: provider, + profileType: "chat", + mistralApiKey: "test-key", + apiModelId: customModelId, // Custom model set by user + } as any) + + const model = new GhostModel() + await model.loadProfile(mockProviderSettingsManager, chatProfile, provider) + + // The model should be overridden with the default autocomplete model + const modelName = model.getModelName() + expect(modelName).toBe(AUTOCOMPLETE_PROVIDER_MODELS[provider]) + expect(modelName).not.toBe(customModelId) + }) + + it("should override model for profiles without profileType", async () => { + const supportedProviders = Object.keys(AUTOCOMPLETE_PROVIDER_MODELS) + const provider = supportedProviders[0] as keyof typeof AUTOCOMPLETE_PROVIDER_MODELS + const customModelId = "custom-model" + + const genericProfile = { + id: "1", + name: "My Generic Profile", + apiProvider: provider, + // No profileType specified + } as any + + // Mock getProfile to return a profile with a custom model + // For mistral provider, the model key is apiModelId + vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ + id: "1", + name: "My Generic Profile", + apiProvider: provider, + mistralApiKey: "test-key", + apiModelId: customModelId, // Custom model set by user + } as any) + + const model = new GhostModel() + await model.loadProfile(mockProviderSettingsManager, genericProfile, provider) + + // The model should be overridden with the default autocomplete model + const modelName = model.getModelName() + expect(modelName).toBe(AUTOCOMPLETE_PROVIDER_MODELS[provider]) + expect(modelName).not.toBe(customModelId) + }) }) }) diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index 84c5e00c46..4a795af5b0 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -6,6 +6,7 @@ import { mentionRegex, mentionRegexGlobal, unescapeSpaces } from "@roo/context-m import { WebviewMessage } from "@roo/WebviewMessage" import { Mode, getAllModes } from "@roo/modes" import { ExtensionMessage } from "@roo/ExtensionMessage" +import type { ProfileType } from "@roo-code/types" // kilocode_change - autocomplete profile type system import { vscode } from "@/utils/vscode" import { useExtensionState } from "@/context/ExtensionStateContext" @@ -114,14 +115,28 @@ export const ChatTextArea = forwardRef( clineMessages, } = useExtensionState() + // kilocode_change start - autocomplete profile type system + // Filter out autocomplete profiles - only show chat profiles in the chat interface + const chatProfiles = useMemo(() => { + return ( + listApiConfigMeta?.filter((config) => { + const profileType = (config as { profileType?: ProfileType }).profileType + return profileType !== "autocomplete" + }) ?? [] + ) + }, [listApiConfigMeta]) + // kilocode_change end + + // kilocode_change start - autocomplete profile type system // Find the ID and display text for the currently selected API configuration const { currentConfigId, displayName } = useMemo(() => { - const currentConfig = listApiConfigMeta?.find((config) => config.name === currentApiConfigName) + const currentConfig = chatProfiles?.find((config) => config.name === currentApiConfigName) return { currentConfigId: currentConfig?.id || "", displayName: currentApiConfigName || "", // Use the name directly for display } - }, [listApiConfigMeta, currentApiConfigName]) + }, [chatProfiles, currentApiConfigName]) + // kilocode_change end const [gitCommits, setGitCommits] = useState([]) const [showDropdown, setShowDropdown] = useState(false) @@ -1115,7 +1130,7 @@ export const ChatTextArea = forwardRef( // Helper function to get API config dropdown options // kilocode_change: unused const _getApiConfigOptions = useMemo(() => { - const pinnedConfigs = (listApiConfigMeta || []) + const pinnedConfigs = (chatProfiles || []) // kilocode_change - autocomplete profile type system .filter((config) => pinnedApiConfigs && pinnedApiConfigs[config.id]) .map((config) => ({ value: config.id, @@ -1126,7 +1141,7 @@ export const ChatTextArea = forwardRef( })) .sort((a, b) => a.label.localeCompare(b.label)) - const unpinnedConfigs = (listApiConfigMeta || []) + const unpinnedConfigs = (chatProfiles || []) // kilocode_change - autocomplete profile type system .filter((config) => !pinnedApiConfigs || !pinnedApiConfigs[config.id]) .map((config) => ({ value: config.id, @@ -1162,7 +1177,7 @@ export const ChatTextArea = forwardRef( type: DropdownOptionType.ACTION, }, ] - }, [listApiConfigMeta, pinnedApiConfigs, t]) + }, [chatProfiles, pinnedApiConfigs, t]) // kilocode_change - autocomplete profile type system // Helper function to handle API config change // kilocode_change: unused @@ -1186,7 +1201,7 @@ export const ChatTextArea = forwardRef( return label } - const config = listApiConfigMeta?.find((c) => c.id === value) + const config = chatProfiles?.find((c) => c.id === value) // kilocode_change - autocomplete profile type system const isCurrentConfig = config?.name === currentApiConfigName return ( @@ -1228,7 +1243,7 @@ export const ChatTextArea = forwardRef( ) }, - [listApiConfigMeta, currentApiConfigName, t, togglePinnedApiConfig], + [chatProfiles, currentApiConfigName, t, togglePinnedApiConfig], // kilocode_change - autocomplete profile type system ) // Helper function to render the text area section @@ -1610,7 +1625,7 @@ export const ChatTextArea = forwardRef( currentConfigId={currentConfigId} currentApiConfigName={currentApiConfigName} displayName={displayName} - listApiConfigMeta={listApiConfigMeta} + listApiConfigMeta={chatProfiles} // kilocode_change - autocomplete profile type system pinnedApiConfigs={pinnedApiConfigs} togglePinnedApiConfig={togglePinnedApiConfig} selectApiConfigDisabled={selectApiConfigDisabled} diff --git a/webview-ui/src/components/chat/__tests__/ChatTextArea.autocomplete-profile-filtering.spec.tsx b/webview-ui/src/components/chat/__tests__/ChatTextArea.autocomplete-profile-filtering.spec.tsx new file mode 100644 index 0000000000..380d6bd30b --- /dev/null +++ b/webview-ui/src/components/chat/__tests__/ChatTextArea.autocomplete-profile-filtering.spec.tsx @@ -0,0 +1,153 @@ +import { defaultModeSlug } from "@roo/modes" + +import { render, screen } from "@src/utils/test-utils" +import { useExtensionState } from "@src/context/ExtensionStateContext" + +import { ChatTextArea } from "../ChatTextArea" + +vi.mock("@src/utils/vscode", () => ({ + vscode: { + postMessage: vi.fn(), + }, +})) + +vi.mock("@src/components/common/CodeBlock") +vi.mock("@src/components/common/MarkdownBlock") + +// Mock ExtensionStateContext +vi.mock("@src/context/ExtensionStateContext") + +vi.mock("@tanstack/react-query", () => ({ + useQuery: vi.fn(() => ({ data: { historyItems: [] } })), +})) + +vi.mock("@src/components/ui/hooks/useSelectedModel", () => ({ + useSelectedModel: vi.fn(() => ({ + id: "mock-model-id", + provider: "mock-provider", + })), +})) + +describe("ChatTextArea - autocomplete profile filtering", () => { + const defaultProps = { + inputValue: "", + setInputValue: vi.fn(), + onSend: vi.fn(), + sendingDisabled: false, + selectApiConfigDisabled: false, + onSelectImages: vi.fn(), + shouldDisableImages: false, + placeholderText: "Type a message...", + selectedImages: [], + setSelectedImages: vi.fn(), + onHeightChange: vi.fn(), + mode: defaultModeSlug, + setMode: vi.fn(), + modeShortcutText: "(⌘. for next mode)", + } + + beforeEach(() => { + vi.clearAllMocks() + }) + + it("should filter out autocomplete profiles from the profile list", () => { + const mockListApiConfigMeta = [ + { id: "1", name: "Chat Profile 1", profileType: "chat" }, + { id: "2", name: "Autocomplete Profile", profileType: "autocomplete" }, + { id: "3", name: "Chat Profile 2", profileType: "chat" }, + { id: "4", name: "Profile Without Type" }, // No profileType defaults to chat + ] + + ;(useExtensionState as ReturnType).mockReturnValue({ + filePaths: [], + openedTabs: [], + listApiConfigMeta: mockListApiConfigMeta, + currentApiConfigName: "Chat Profile 1", + taskHistory: [], + cwd: "/test/workspace", + }) + + render() + + // The KiloProfileSelector should only receive chat profiles + // We can verify this by checking that autocomplete profiles are not in the DOM + // Note: KiloProfileSelector hides when there's only 1 profile, so we need at least 2 chat profiles + expect(screen.queryByText("Autocomplete Profile")).not.toBeInTheDocument() + }) + + it("should include profiles without profileType (defaults to chat)", () => { + const mockListApiConfigMeta = [ + { id: "1", name: "Chat Profile 1", profileType: "chat" }, + { id: "2", name: "Profile Without Type" }, // No profileType + { id: "3", name: "Autocomplete Profile", profileType: "autocomplete" }, + ] + + ;(useExtensionState as ReturnType).mockReturnValue({ + filePaths: [], + openedTabs: [], + listApiConfigMeta: mockListApiConfigMeta, + currentApiConfigName: "Chat Profile 1", + pinnedApiConfigs: {}, + taskHistory: [], + cwd: "/test/workspace", + }) + + render() + + // Profile without type should be included (defaults to chat) + // Autocomplete profile should be filtered out + expect(screen.queryByText("Autocomplete Profile")).not.toBeInTheDocument() + }) + + it("should handle empty profile list gracefully", () => { + ;(useExtensionState as ReturnType).mockReturnValue({ + filePaths: [], + openedTabs: [], + listApiConfigMeta: [], + currentApiConfigName: "", + taskHistory: [], + cwd: "/test/workspace", + }) + + expect(() => { + render() + }).not.toThrow() + }) + + it("should handle undefined listApiConfigMeta gracefully", () => { + ;(useExtensionState as ReturnType).mockReturnValue({ + filePaths: [], + openedTabs: [], + listApiConfigMeta: undefined, + currentApiConfigName: "", + taskHistory: [], + cwd: "/test/workspace", + }) + + expect(() => { + render() + }).not.toThrow() + }) + + it("should filter autocomplete profiles when all profiles are autocomplete", () => { + const mockListApiConfigMeta = [ + { id: "1", name: "Autocomplete Profile 1", profileType: "autocomplete" }, + { id: "2", name: "Autocomplete Profile 2", profileType: "autocomplete" }, + ] + + ;(useExtensionState as ReturnType).mockReturnValue({ + filePaths: [], + openedTabs: [], + listApiConfigMeta: mockListApiConfigMeta, + currentApiConfigName: "Autocomplete Profile 1", + taskHistory: [], + cwd: "/test/workspace", + }) + + render() + + // All profiles are autocomplete, so none should be shown + expect(screen.queryByText("Autocomplete Profile 1")).not.toBeInTheDocument() + expect(screen.queryByText("Autocomplete Profile 2")).not.toBeInTheDocument() + }) +}) diff --git a/webview-ui/src/components/kilocode/settings/GhostServiceSettings.tsx b/webview-ui/src/components/kilocode/settings/GhostServiceSettings.tsx index 6f68aba88d..7c9ef78c49 100644 --- a/webview-ui/src/components/kilocode/settings/GhostServiceSettings.tsx +++ b/webview-ui/src/components/kilocode/settings/GhostServiceSettings.tsx @@ -155,6 +155,9 @@ export const GhostServiceSettingsView = ({ {t("kilocode:ghost.settings.noModelConfigured")} )} +
+ {t("kilocode:ghost.settings.configureAutocompleteProfile")} +
diff --git a/webview-ui/src/components/kilocode/settings/__tests__/GhostServiceSettings.spec.tsx b/webview-ui/src/components/kilocode/settings/__tests__/GhostServiceSettings.spec.tsx index 5036b32d25..d6d971b71b 100644 --- a/webview-ui/src/components/kilocode/settings/__tests__/GhostServiceSettings.spec.tsx +++ b/webview-ui/src/components/kilocode/settings/__tests__/GhostServiceSettings.spec.tsx @@ -207,6 +207,7 @@ describe("GhostServiceSettingsView", () => { expect(screen.getByText(/openrouter/)).toBeInTheDocument() expect(screen.getAllByText(/kilocode:ghost.settings.model/).length).toBeGreaterThan(0) expect(screen.getByText(/openai\/gpt-4o-mini/)).toBeInTheDocument() + expect(screen.getByText(/kilocode:ghost.settings.configureAutocompleteProfile/)).toBeInTheDocument() }) it("displays error message when provider and model are not configured", () => { @@ -219,6 +220,7 @@ describe("GhostServiceSettingsView", () => { }) expect(screen.getByText(/kilocode:ghost.settings.noModelConfigured/)).toBeInTheDocument() + expect(screen.getByText(/kilocode:ghost.settings.configureAutocompleteProfile/)).toBeInTheDocument() }) it("displays error message when only provider is missing", () => { @@ -231,6 +233,7 @@ describe("GhostServiceSettingsView", () => { }) expect(screen.getByText(/kilocode:ghost.settings.noModelConfigured/)).toBeInTheDocument() + expect(screen.getByText(/kilocode:ghost.settings.configureAutocompleteProfile/)).toBeInTheDocument() }) it("displays error message when only model is missing", () => { @@ -243,5 +246,6 @@ describe("GhostServiceSettingsView", () => { }) expect(screen.getByText(/kilocode:ghost.settings.noModelConfigured/)).toBeInTheDocument() + expect(screen.getByText(/kilocode:ghost.settings.configureAutocompleteProfile/)).toBeInTheDocument() }) }) diff --git a/webview-ui/src/components/settings/ApiConfigManager.tsx b/webview-ui/src/components/settings/ApiConfigManager.tsx index 366f7a81e7..c6972da570 100644 --- a/webview-ui/src/components/settings/ApiConfigManager.tsx +++ b/webview-ui/src/components/settings/ApiConfigManager.tsx @@ -2,7 +2,7 @@ import { memo, useEffect, useRef, useState } from "react" import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react" import { AlertTriangle } from "lucide-react" -import type { ProviderSettingsEntry, OrganizationAllowList } from "@roo-code/types" +import type { ProviderSettingsEntry, OrganizationAllowList, ProfileType } from "@roo-code/types" // kilocode_change - autocomplete profile type system import { useAppTranslation } from "@/i18n/TranslationContext" import { @@ -14,6 +14,13 @@ import { DialogTitle, StandardTooltip, SearchableSelect, + // kilocode_change start - autocomplete profile type system + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectItem, + // kilocode_change end } from "@/components/ui" interface ApiConfigManagerProps { @@ -23,7 +30,7 @@ interface ApiConfigManagerProps { onSelectConfig: (configName: string) => void onDeleteConfig: (configName: string) => void onRenameConfig: (oldName: string, newName: string) => void - onUpsertConfig: (configName: string) => void + onUpsertConfig: (configName: string, profileType?: ProfileType) => void // kilocode_change - autocomplete profile type system } const ApiConfigManager = ({ @@ -41,6 +48,7 @@ const ApiConfigManager = ({ const [isCreating, setIsCreating] = useState(false) const [inputValue, setInputValue] = useState("") const [newProfileName, setNewProfileName] = useState("") + const [newProfileType, setNewProfileType] = useState("chat") // kilocode_change - autocomplete profile type system const [error, setError] = useState(null) const inputRef = useRef(null) const newProfileInputRef = useRef(null) @@ -87,6 +95,7 @@ const ApiConfigManager = ({ const resetCreateState = () => { setIsCreating(false) setNewProfileName("") + setNewProfileType("chat") // kilocode_change - autocomplete profile type system setError(null) } @@ -167,7 +176,7 @@ const ApiConfigManager = ({ return } - onUpsertConfig(trimmedValue) + onUpsertConfig(trimmedValue, newProfileType) // kilocode_change - autocomplete profile type system resetCreateState() } @@ -239,9 +248,17 @@ const ApiConfigManager = ({ onValueChange={handleSelectConfig} options={listApiConfigMeta.map((config) => { const valid = isProfileValid(config) + // kilocode_change start - autocomplete profile type system + const profileType = config.profileType || "chat" + const label = + profileType === "autocomplete" + ? `${config.name} ${t("settings:providers.autocompleteLabel")}` + : config.name + return { value: config.name, - label: config.name, + label: label, + // kilocode_change end disabled: !valid, icon: !valid ? ( @@ -312,26 +329,56 @@ const ApiConfigManager = ({ aria-labelledby="new-profile-title"> {t("settings:providers.newProfile")} - { - const target = e as { target: { value: string } } - setNewProfileName(target.target.value) - setError(null) - }} - placeholder={t("settings:providers.enterProfileName")} - data-testid="new-profile-input" - style={{ width: "100%" }} - onKeyDown={(e: unknown) => { - const event = e as { key: string } - if (event.key === "Enter" && newProfileName.trim()) { - handleNewProfileSave() - } else if (event.key === "Escape") { - resetCreateState() - } - }} - /> + {/* kilocode_change start - autocomplete profile type system */} +
+
+ + { + const target = e as { target: { value: string } } + setNewProfileName(target.target.value) + setError(null) + }} + placeholder={t("settings:providers.enterProfileName")} + data-testid="new-profile-input" + style={{ width: "100%" }} + onKeyDown={(e: unknown) => { + const event = e as { key: string } + if (event.key === "Enter" && newProfileName.trim()) { + handleNewProfileSave() + } else if (event.key === "Escape") { + resetCreateState() + } + }} + /> +
+
+ + +

+ {t("settings:providers.profileTypeDescription")} +

+
+
+ {/* kilocode_change end */} {error && (

{error} diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index 99cc3bf704..ca11672f8d 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -472,6 +472,26 @@ const ApiOptions = ({ return (

+ {/* kilocode_change start - autocomplete profile type system */} + {/* Profile Type Display (read-only for existing profiles) */} +
+ +
+ {apiConfiguration.profileType === "autocomplete" + ? t("settings:providers.profileTypeAutocomplete") + : t("settings:providers.profileTypeChat")} + {apiConfiguration.profileType === "autocomplete" && ( + + {t("settings:providers.autocompleteLabel")} + + )} +
+
+ {t("settings:providers.profileTypeDescription")} +
+
+ {/* kilocode_change end */} +
diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index e9d7e39231..d24260786b 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -33,7 +33,7 @@ import { // kilocode_change import { ensureBodyPointerEventsRestored } from "@/utils/fixPointerEvents" -import type { ProviderSettings, ExperimentId, TelemetrySetting } from "@roo-code/types" +import type { ProviderSettings, ExperimentId, TelemetrySetting, ProfileType } from "@roo-code/types" // kilocode_change - autocomplete profile type system import { vscode } from "@src/utils/vscode" import { cn } from "@src/lib/utils" @@ -776,13 +776,18 @@ const SettingsView = forwardRef(({ onDone, t }) prevApiConfigName.current = newName }} - onUpsertConfig={(configName: string) => + // kilocode_change start - autocomplete profile type system + onUpsertConfig={(configName: string, profileType?: ProfileType) => vscode.postMessage({ type: "upsertApiConfiguration", text: configName, - apiConfiguration, + apiConfiguration: { + ...apiConfiguration, + profileType: profileType || "chat", + }, }) } + // kilocode_change end /> ({ {children}
), - // Keep old components for backward compatibility - Select: ({ value, onValueChange }: any) => ( + // kilocode_change start - autocomplete profile type system + Select: ({ value, onValueChange, children }: any) => ( ), + // kilocode_change end SelectTrigger: ({ children }: any) =>
{children}
, SelectValue: ({ children }: any) =>
{children}
, SelectContent: ({ children }: any) =>
{children}
, @@ -156,7 +156,7 @@ describe("ApiConfigManager", () => { const createButton = screen.getByText("settings:providers.createProfile") fireEvent.click(createButton) - expect(mockOnUpsertConfig).toHaveBeenCalledWith("New Profile") + expect(mockOnUpsertConfig).toHaveBeenCalledWith("New Profile", "chat") // kilocode_change - autocomplete profile type system }) it("shows error when creating profile with existing name", () => { @@ -205,8 +205,9 @@ describe("ApiConfigManager", () => { const renameButton = screen.getByTestId("rename-profile-button") fireEvent.click(renameButton) - // Find input and enter new name - const input = screen.getByDisplayValue("Default Config") + // Find input in rename form specifically + const renameForm = getRenameForm() + const input = within(renameForm).getByDisplayValue("Default Config") fireEvent.input(input, { target: { value: "New Name" } }) // Save @@ -223,8 +224,9 @@ describe("ApiConfigManager", () => { const renameButton = screen.getByTestId("rename-profile-button") fireEvent.click(renameButton) - // Find input and enter existing name - const input = screen.getByDisplayValue("Default Config") + // Find input in rename form and enter existing name + const renameForm = getRenameForm() + const input = within(renameForm).getByDisplayValue("Default Config") fireEvent.input(input, { target: { value: "Another Config" } }) // Save to trigger validation @@ -232,7 +234,6 @@ describe("ApiConfigManager", () => { fireEvent.click(saveButton) // Verify error message - const renameForm = getRenameForm() const errorMessage = within(renameForm).getByTestId("error-message") expect(errorMessage).toHaveTextContent("settings:providers.nameExists") expect(mockOnRenameConfig).not.toHaveBeenCalled() @@ -245,8 +246,9 @@ describe("ApiConfigManager", () => { const renameButton = screen.getByTestId("rename-profile-button") fireEvent.click(renameButton) - // Find input and enter empty name - const input = screen.getByDisplayValue("Default Config") + // Find input in rename form and enter empty name + const renameForm = getRenameForm() + const input = within(renameForm).getByDisplayValue("Default Config") fireEvent.input(input, { target: { value: " " } }) // Verify save button is disabled @@ -291,8 +293,9 @@ describe("ApiConfigManager", () => { const renameButton = screen.getByTestId("rename-profile-button") fireEvent.click(renameButton) - // Find input and enter new name - const input = screen.getByDisplayValue("Default Config") + // Find input in rename form and enter new name + const renameForm = getRenameForm() + const input = within(renameForm).getByDisplayValue("Default Config") fireEvent.input(input, { target: { value: "New Name" } }) // Cancel @@ -318,7 +321,7 @@ describe("ApiConfigManager", () => { // Test Enter key fireEvent.input(input, { target: { value: "New Profile" } }) fireEvent.keyDown(input, { key: "Enter" }) - expect(mockOnUpsertConfig).toHaveBeenCalledWith("New Profile") + expect(mockOnUpsertConfig).toHaveBeenCalledWith("New Profile", "chat") // kilocode_change - autocomplete profile type system // Test Escape key fireEvent.keyDown(input, { key: "Escape" }) @@ -332,7 +335,8 @@ describe("ApiConfigManager", () => { const renameButton = screen.getByTestId("rename-profile-button") fireEvent.click(renameButton) - const input = screen.getByDisplayValue("Default Config") + const renameForm = getRenameForm() + const input = within(renameForm).getByDisplayValue("Default Config") // Test Enter key fireEvent.input(input, { target: { value: "New Name" } }) diff --git a/webview-ui/src/i18n/locales/ar/kilocode.json b/webview-ui/src/i18n/locales/ar/kilocode.json index 775790e4a7..b19c35cc3d 100644 --- a/webview-ui/src/i18n/locales/ar/kilocode.json +++ b/webview-ui/src/i18n/locales/ar/kilocode.json @@ -232,6 +232,7 @@ }, "keybindingNotFound": "غير موجود", "noModelConfigured": "لم يتم العثور على نموذج إكمال تلقائي مناسب. يرجى تكوين مزود في إعدادات API.", + "configureAutocompleteProfile": "استخدم أي نموذج بالانتقال إلى الملفات الشخصية وتكوين ملف شخصي من نوع الإكمال التلقائي.", "model": "النموذج", "provider": "المزود" } diff --git a/webview-ui/src/i18n/locales/ar/settings.json b/webview-ui/src/i18n/locales/ar/settings.json index 09ca94d130..08ae6667ab 100644 --- a/webview-ui/src/i18n/locales/ar/settings.json +++ b/webview-ui/src/i18n/locales/ar/settings.json @@ -548,6 +548,15 @@ "roo": { "authenticatedMessage": "تم التوثيق بأمان عبر حساب Roo Code Cloud.", "connectButton": "اتصل بـ Roo Code Cloud" + }, + "profileName": "اسم الملف الشخصي", + "profileType": "نوع الملف الشخصي", + "profileTypeChat": "محادثة", + "profileTypeAutocomplete": "الإكمال التلقائي", + "profileTypeDescription": "تُستخدم ملفات المحادثة للمحادثات. يُسمح بملف إكمال تلقائي واحد فقط.", + "autocompleteLabel": "(الإكمال التلقائي)", + "autocomplete": { + "onlyOneAllowed": "يُسمح بملف إكمال تلقائي واحد فقط. الملف الشخصي \"{{existingName}}\" مُكوّن بالفعل للإكمال التلقائي. يرجى تغيير نوعه أولاً أو حذفه." } }, "contextWindow": { diff --git a/webview-ui/src/i18n/locales/ca/kilocode.json b/webview-ui/src/i18n/locales/ca/kilocode.json index 912fa47729..2679a5eed6 100644 --- a/webview-ui/src/i18n/locales/ca/kilocode.json +++ b/webview-ui/src/i18n/locales/ca/kilocode.json @@ -223,6 +223,7 @@ }, "keybindingNotFound": "no trobat", "noModelConfigured": "No s'ha trobat cap model d'autocompletat adequat. Configura un proveïdor a la configuració de l'API.", + "configureAutocompleteProfile": "Utilitza qualsevol model anant a perfils i configurant un Perfil del Tipus de Perfil Autocompletat.", "model": "Model", "provider": "Proveïdor" } diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 4f3dcfdeba..30a3c3be17 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -515,6 +515,15 @@ "description": "Aquest proveïdor utilitza l'autenticació OAuth del servei Qwen i no requereix claus d'API.", "instructions": "Si us plau, seguiu la documentació oficial per obtenir el fitxer d'autorització i col·locar-lo a la ruta especificada.", "setupLink": "Documentació oficial de Qwen" + }, + "profileName": "Nom del perfil", + "profileType": "Tipus de perfil", + "profileTypeChat": "Xat", + "profileTypeAutocomplete": "Autocompletat", + "profileTypeDescription": "Els perfils de xat s'utilitzen per a converses. Només es permet un perfil d'autocompletat.", + "autocompleteLabel": "(Autocompletat)", + "autocomplete": { + "onlyOneAllowed": "Només es permet un perfil d'autocompletat. El perfil \"{{existingName}}\" ja està configurat per a autocompletat. Si us plau, canvia el seu tipus primer o elimina'l." } }, "browser": { diff --git a/webview-ui/src/i18n/locales/cs/kilocode.json b/webview-ui/src/i18n/locales/cs/kilocode.json index 7369c30e49..0b79b2a07c 100644 --- a/webview-ui/src/i18n/locales/cs/kilocode.json +++ b/webview-ui/src/i18n/locales/cs/kilocode.json @@ -237,6 +237,7 @@ }, "keybindingNotFound": "nenalezeno", "noModelConfigured": "Nebyl nalezen žádný vhodný model pro automatické dokončování. Nakonfiguruj prosím poskytovatele v nastavení API.", + "configureAutocompleteProfile": "Použij libovolný model tak, že přejdeš do profilů a nakonfiguruješ Profil typu Automatické dokončování.", "model": "Model", "provider": "Poskytovatel" } diff --git a/webview-ui/src/i18n/locales/cs/settings.json b/webview-ui/src/i18n/locales/cs/settings.json index 5740102c21..c860ca841c 100644 --- a/webview-ui/src/i18n/locales/cs/settings.json +++ b/webview-ui/src/i18n/locales/cs/settings.json @@ -548,6 +548,15 @@ "description": "Tento poskytovatel používá OAuth autentizaci ze služby Qwen a nevyžaduje klíče API.", "instructions": "Postupujte prosím podle oficiální dokumentace pro získání autorizačního souboru a umístěte jej do zadané cesty.", "setupLink": "Oficiální dokumentace Qwen" + }, + "profileName": "Název profilu", + "profileType": "Typ profilu", + "profileTypeChat": "Chat", + "profileTypeAutocomplete": "Automatické dokončování", + "profileTypeDescription": "Profily chatu se používají pro konverzace. Je povolen pouze jeden profil automatického dokončování.", + "autocompleteLabel": "(Automatické dokončování)", + "autocomplete": { + "onlyOneAllowed": "Je povolen pouze jeden profil automatického dokončování. Profil \"{{existingName}}\" je již nakonfigurován pro automatické dokončování. Nejprve změň jeho typ nebo ho smaž." } }, "contextWindow": { diff --git a/webview-ui/src/i18n/locales/de/kilocode.json b/webview-ui/src/i18n/locales/de/kilocode.json index e22476aca0..3e2cd64e2d 100644 --- a/webview-ui/src/i18n/locales/de/kilocode.json +++ b/webview-ui/src/i18n/locales/de/kilocode.json @@ -230,7 +230,8 @@ "description": "Brauchst du eine schnelle Korrektur, Vervollständigung oder Refaktorierung? Kilo wird den umgebenden Kontext nutzen, um sofortige Verbesserungen anzubieten und dich im Flow zu halten. Tastenkombination bearbeiten" }, "keybindingNotFound": "nicht gefunden", - "noModelConfigured": "Kein geeignetes Autocomplete-Modell gefunden. Bitte konfiguriere einen Provider in den API-Einstellungen." + "noModelConfigured": "Kein geeignetes Autocomplete-Modell gefunden. Bitte konfiguriere einen Provider in den API-Einstellungen.", + "configureAutocompleteProfile": "Verwende ein beliebiges Modell, indem du zu Profilen gehst und ein Profil vom Profiltyp Autocomplete konfigurierst." } }, "virtualProvider": { diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 854700f23b..b1ca99716c 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -245,6 +245,15 @@ "searchProviderPlaceholder": "Suchanbieter durchsuchen", "noProviderMatchFound": "Keine Anbieter gefunden", "noMatchFound": "Keine passenden Profile gefunden", + "profileName": "Profilname", + "profileType": "Profiltyp", + "profileTypeChat": "Chat", + "profileTypeAutocomplete": "Autovervollständigung", + "profileTypeDescription": "Chat-Profile werden für Unterhaltungen verwendet. Es ist nur ein Autovervollständigungsprofil erlaubt.", + "autocompleteLabel": "(Autovervollständigung)", + "autocomplete": { + "onlyOneAllowed": "Es ist nur ein Autovervollständigungsprofil erlaubt. Das Profil \"{{existingName}}\" ist bereits für Autovervollständigung konfiguriert. Bitte ändere zuerst seinen Typ oder lösche es." + }, "vscodeLmDescription": "Die VS Code Language Model API ermöglicht das Ausführen von Modellen, die von anderen VS Code-Erweiterungen bereitgestellt werden (einschließlich, aber nicht beschränkt auf GitHub Copilot). Der einfachste Weg, um zu starten, besteht darin, die Erweiterungen Copilot und Copilot Chat aus dem VS Code Marketplace zu installieren.", "awsCustomArnUse": "Gib eine gültige Amazon Bedrock ARN für das Modell ein, das du verwenden möchtest. Formatbeispiele:", "awsCustomArnDesc": "Stelle sicher, dass die Region in der ARN mit Ihrer oben ausgewählten AWS-Region übereinstimmt.", diff --git a/webview-ui/src/i18n/locales/en/kilocode.json b/webview-ui/src/i18n/locales/en/kilocode.json index 84d5ccdd8b..16e8017487 100644 --- a/webview-ui/src/i18n/locales/en/kilocode.json +++ b/webview-ui/src/i18n/locales/en/kilocode.json @@ -244,7 +244,8 @@ "description": "Need a quick fix, completion, or refactor? Kilo will use the surrounding context to offer immediate improvements, keeping you in the flow. Edit shortcut" }, "keybindingNotFound": "not found", - "noModelConfigured": "No suitable autocomplete model found. Please configure a provider in the API settings." + "noModelConfigured": "No suitable autocomplete model found. Please configure a provider in the API settings.", + "configureAutocompleteProfile": "Use any model by going to profiles and configuring a Profile of the Profile Type Autocomplete." } }, "virtualProvider": { diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 9dc0a05c78..6c7d576ea7 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -250,6 +250,15 @@ "searchProviderPlaceholder": "Search providers", "noProviderMatchFound": "No providers found", "noMatchFound": "No matching profiles found", + "profileName": "Profile Name", + "profileType": "Profile Type", + "profileTypeChat": "Chat", + "profileTypeAutocomplete": "Autocomplete", + "profileTypeDescription": "Chat profiles are used for conversations. Only one autocomplete profile is allowed.", + "autocompleteLabel": "(Autocomplete)", + "autocomplete": { + "onlyOneAllowed": "Only one autocomplete profile is allowed. Profile \"{{existingName}}\" is already configured for autocomplete. Please change its type first or delete it." + }, "vscodeLmDescription": " The VS Code Language Model API allows you to run models provided by other VS Code extensions (including but not limited to GitHub Copilot). The easiest way to get started is to install the Copilot and Copilot Chat extensions from the VS Code Marketplace.", "awsCustomArnUse": "Enter a valid Amazon Bedrock ARN for the model you want to use. Format examples:", "awsCustomArnDesc": "Make sure the region in the ARN matches your selected AWS Region above.", diff --git a/webview-ui/src/i18n/locales/es/kilocode.json b/webview-ui/src/i18n/locales/es/kilocode.json index 807a79fbe6..3bbdb09390 100644 --- a/webview-ui/src/i18n/locales/es/kilocode.json +++ b/webview-ui/src/i18n/locales/es/kilocode.json @@ -230,6 +230,7 @@ }, "keybindingNotFound": "no encontrado", "noModelConfigured": "No se encontró ningún modelo de autocompletado adecuado. Por favor, configura un proveedor en la configuración de API.", + "configureAutocompleteProfile": "Usa cualquier modelo yendo a perfiles y configurando un Perfil del Tipo de Perfil Autocompletado.", "model": "Modelo", "provider": "Proveedor" } diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 6c4406cbc4..8ce2c593d1 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -245,6 +245,15 @@ "searchProviderPlaceholder": "Buscar proveedores", "noProviderMatchFound": "No se encontraron proveedores", "noMatchFound": "No se encontraron perfiles coincidentes", + "profileName": "Nombre del perfil", + "profileType": "Tipo de perfil", + "profileTypeChat": "Chat", + "profileTypeAutocomplete": "Autocompletado", + "profileTypeDescription": "Los perfiles de chat se usan para conversaciones. Solo se permite un perfil de autocompletado.", + "autocompleteLabel": "(Autocompletado)", + "autocomplete": { + "onlyOneAllowed": "Solo se permite un perfil de autocompletado. El perfil \"{{existingName}}\" ya está configurado para autocompletado. Por favor, cambia su tipo primero o elimínalo." + }, "vscodeLmDescription": "La API del Modelo de Lenguaje de VS Code le permite ejecutar modelos proporcionados por otras extensiones de VS Code (incluido, entre otros, GitHub Copilot). La forma más sencilla de empezar es instalar las extensiones Copilot y Copilot Chat desde el VS Code Marketplace.", "awsCustomArnUse": "Ingrese un ARN de Amazon Bedrock válido para el modelo que desea utilizar. Ejemplos de formato:", "awsCustomArnDesc": "Asegúrese de que la región en el ARN coincida con la región de AWS seleccionada anteriormente.", diff --git a/webview-ui/src/i18n/locales/fr/kilocode.json b/webview-ui/src/i18n/locales/fr/kilocode.json index 3cf14ae8e6..428121a45a 100644 --- a/webview-ui/src/i18n/locales/fr/kilocode.json +++ b/webview-ui/src/i18n/locales/fr/kilocode.json @@ -237,6 +237,7 @@ }, "keybindingNotFound": "introuvable", "noModelConfigured": "Aucun modèle d'autocomplétion approprié trouvé. Configure un fournisseur dans les paramètres API.", + "configureAutocompleteProfile": "Utilise n'importe quel modèle en allant dans les profils et en configurant un Profil du Type de Profil Autocomplétion.", "model": "Modèle", "provider": "Fournisseur" } diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 599a9d6ab4..9393e4daf0 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -245,6 +245,15 @@ "searchProviderPlaceholder": "Rechercher des fournisseurs", "noProviderMatchFound": "Aucun fournisseur trouvé", "noMatchFound": "Aucun profil correspondant trouvé", + "profileName": "Nom du profil", + "profileType": "Type de profil", + "profileTypeChat": "Chat", + "profileTypeAutocomplete": "Autocomplétion", + "profileTypeDescription": "Les profils de chat sont utilisés pour les conversations. Un seul profil d'autocomplétion est autorisé.", + "autocompleteLabel": "(Autocomplétion)", + "autocomplete": { + "onlyOneAllowed": "Un seul profil d'autocomplétion est autorisé. Le profil \"{{existingName}}\" est déjà configuré pour l'autocomplétion. Veuillez d'abord changer son type ou le supprimer." + }, "vscodeLmDescription": "L'API du modèle de langage VS Code vous permet d'exécuter des modèles fournis par d'autres extensions VS Code (y compris, mais sans s'y limiter, GitHub Copilot). Le moyen le plus simple de commencer est d'installer les extensions Copilot et Copilot Chat depuis le VS Code Marketplace.", "awsCustomArnUse": "Entrez un ARN Amazon Bedrock valide pour le modèle que vous souhaitez utiliser. Exemples de format :", "awsCustomArnDesc": "Assurez-vous que la région dans l'ARN correspond à la région AWS sélectionnée ci-dessus.", diff --git a/webview-ui/src/i18n/locales/hi/kilocode.json b/webview-ui/src/i18n/locales/hi/kilocode.json index d850cf958a..f7970a6b26 100644 --- a/webview-ui/src/i18n/locales/hi/kilocode.json +++ b/webview-ui/src/i18n/locales/hi/kilocode.json @@ -223,6 +223,7 @@ }, "keybindingNotFound": "नहीं मिला", "noModelConfigured": "कोई उपयुक्त ऑटोकम्पलीट मॉडल नहीं मिला। कृपया API सेटिंग्स में एक प्रदाता कॉन्फ़िगर करें।", + "configureAutocompleteProfile": "प्रोफाइल में जाकर और ऑटोकम्पलीट प्रोफाइल टाइप की एक प्रोफाइल कॉन्फ़िगर करके किसी भी मॉडल का उपयोग करें।", "model": "मॉडल", "provider": "प्रदाता" } diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index fc56ff78d2..73562a7447 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -515,6 +515,15 @@ "description": "यह प्रदाता Qwen सेवा से OAuth प्रमाणीकरण का उपयोग करता है और API कुंजियों की आवश्यकता नहीं है।", "instructions": "कृपया प्राधिकरण फ़ाइल प्राप्त करने और इसे निर्दिष्ट पथ में रखने के लिए आधिकारिक दस्तावेज़ीकरण का पालन करें।", "setupLink": "Qwen आधिकारिक दस्तावेज़ीकरण" + }, + "profileName": "प्रोफ़ाइल नाम", + "profileType": "प्रोफ़ाइल प्रकार", + "profileTypeChat": "चैट", + "profileTypeAutocomplete": "ऑटोकम्पलीट", + "profileTypeDescription": "चैट प्रोफ़ाइल बातचीत के लिए उपयोग की जाती हैं। केवल एक ऑटोकम्पलीट प्रोफ़ाइल की अनुमति है।", + "autocompleteLabel": "(ऑटोकम्पलीट)", + "autocomplete": { + "onlyOneAllowed": "केवल एक ऑटोकम्पलीट प्रोफ़ाइल की अनुमति है। प्रोफ़ाइल \"{{existingName}}\" पहले से ही ऑटोकम्पलीट के लिए कॉन्फ़िगर है। कृपया पहले इसका प्रकार बदलें या इसे हटाएं।" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/id/kilocode.json b/webview-ui/src/i18n/locales/id/kilocode.json index 4d1727c2c8..0ed538429d 100644 --- a/webview-ui/src/i18n/locales/id/kilocode.json +++ b/webview-ui/src/i18n/locales/id/kilocode.json @@ -223,6 +223,7 @@ }, "keybindingNotFound": "tidak ditemukan", "noModelConfigured": "Tidak ditemukan model autocomplete yang sesuai. Silakan konfigurasi penyedia di pengaturan API.", + "configureAutocompleteProfile": "Gunakan model apa pun dengan pergi ke profil dan mengonfigurasi Profil dengan Tipe Profil Autocomplete.", "model": "Model", "provider": "Penyedia" } diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 26989e5a18..c3930d3722 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -515,6 +515,15 @@ "description": "Provider ini menggunakan autentikasi OAuth dari layanan Qwen dan tidak memerlukan kunci API.", "instructions": "Silakan ikuti dokumentasi resmi untuk mendapatkan file otorisasi dan tempatkan di jalur yang ditentukan.", "setupLink": "Dokumentasi Resmi Qwen" + }, + "profileName": "Nama Profil", + "profileType": "Jenis Profil", + "profileTypeChat": "Chat", + "profileTypeAutocomplete": "Pelengkapan Otomatis", + "profileTypeDescription": "Profil chat digunakan untuk percakapan. Hanya satu profil pelengkapan otomatis yang diizinkan.", + "autocompleteLabel": "(Pelengkapan Otomatis)", + "autocomplete": { + "onlyOneAllowed": "Hanya satu profil pelengkapan otomatis yang diizinkan. Profil \"{{existingName}}\" sudah dikonfigurasi untuk pelengkapan otomatis. Silakan ubah jenisnya terlebih dahulu atau hapus." } }, "browser": { diff --git a/webview-ui/src/i18n/locales/it/kilocode.json b/webview-ui/src/i18n/locales/it/kilocode.json index 4fdf3b4ef0..f54fb04ef7 100644 --- a/webview-ui/src/i18n/locales/it/kilocode.json +++ b/webview-ui/src/i18n/locales/it/kilocode.json @@ -230,6 +230,7 @@ }, "keybindingNotFound": "non trovato", "noModelConfigured": "Nessun modello di autocompletamento adatto trovato. Configura un provider nelle impostazioni API.", + "configureAutocompleteProfile": "Usa qualsiasi modello andando nei profili e configurando un Profilo del Tipo di Profilo Autocompletamento.", "model": "Modello", "provider": "Provider" } diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index ae4ac99f4e..c97e2c5909 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -246,6 +246,15 @@ "noMatchFound": "Nessun profilo corrispondente trovato", "searchProviderPlaceholder": "Cerca fornitori", "noProviderMatchFound": "Nessun fornitore trovato", + "profileName": "Nome profilo", + "profileType": "Tipo di profilo", + "profileTypeChat": "Chat", + "profileTypeAutocomplete": "Autocompletamento", + "profileTypeDescription": "I profili chat sono usati per le conversazioni. È consentito un solo profilo di autocompletamento.", + "autocompleteLabel": "(Autocompletamento)", + "autocomplete": { + "onlyOneAllowed": "È consentito un solo profilo di autocompletamento. Il profilo \"{{existingName}}\" è già configurato per l'autocompletamento. Per favore, cambia prima il suo tipo o eliminalo." + }, "vscodeLmDescription": "L'API del Modello di Linguaggio di VS Code consente di eseguire modelli forniti da altre estensioni di VS Code (incluso, ma non limitato a, GitHub Copilot). Il modo più semplice per iniziare è installare le estensioni Copilot e Copilot Chat dal VS Code Marketplace.", "awsCustomArnUse": "Inserisci un ARN Amazon Bedrock valido per il modello che desideri utilizzare. Esempi di formato:", "awsCustomArnDesc": "Assicurati che la regione nell'ARN corrisponda alla regione AWS selezionata sopra.", diff --git a/webview-ui/src/i18n/locales/ja/kilocode.json b/webview-ui/src/i18n/locales/ja/kilocode.json index 4b40bcf11d..99c1dee900 100644 --- a/webview-ui/src/i18n/locales/ja/kilocode.json +++ b/webview-ui/src/i18n/locales/ja/kilocode.json @@ -237,6 +237,7 @@ }, "keybindingNotFound": "見つかりません", "noModelConfigured": "適切なオートコンプリートモデルが見つかりませんでした。API設定でプロバイダーを設定してください。", + "configureAutocompleteProfile": "プロファイルに移動し、プロファイルタイプがオートコンプリートのプロファイルを設定することで、任意のモデルを使用できます。", "model": "モデル", "provider": "プロバイダー" } diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 5c9a8d5658..f4bde068c9 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -516,6 +516,15 @@ "description": "このプロバイダーはQwenサービスからのOAuth認証を使用し、APIキーは必要ありません。", "instructions": "認証ファイルを取得して指定されたパスに配置するには、公式ドキュメントに従ってください。", "setupLink": "Qwen公式ドキュメント" + }, + "profileName": "プロファイル名", + "profileType": "プロファイルタイプ", + "profileTypeChat": "チャット", + "profileTypeAutocomplete": "オートコンプリート", + "profileTypeDescription": "チャットプロファイルは会話に使用されます。オートコンプリートプロファイルは1つのみ許可されます。", + "autocompleteLabel": "(オートコンプリート)", + "autocomplete": { + "onlyOneAllowed": "オートコンプリートプロファイルは1つのみ許可されます。プロファイル「{{existingName}}」は既にオートコンプリート用に設定されています。まずそのタイプを変更するか、削除してください。" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/ko/kilocode.json b/webview-ui/src/i18n/locales/ko/kilocode.json index f76501c026..488ef86e05 100644 --- a/webview-ui/src/i18n/locales/ko/kilocode.json +++ b/webview-ui/src/i18n/locales/ko/kilocode.json @@ -237,6 +237,7 @@ }, "keybindingNotFound": "찾을 수 없음", "noModelConfigured": "적합한 자동완성 모델을 찾을 수 없습니다. API 설정에서 제공자를 구성하세요.", + "configureAutocompleteProfile": "프로필로 이동하여 프로필 유형이 자동완성인 프로필을 구성하면 모든 모델을 사용할 수 있습니다.", "model": "모델", "provider": "제공자" } diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 39a17812ac..5f044a3c94 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -515,6 +515,15 @@ "description": "이 공급자는 Qwen 서비스의 OAuth 인증을 사용하며 API 키가 필요하지 않습니다.", "instructions": "공식 문서에 따라 인증 파일을 얻어 지정된 경로에 배치하세요.", "setupLink": "Qwen 공식 문서" + }, + "profileName": "프로필 이름", + "profileType": "프로필 유형", + "profileTypeChat": "채팅", + "profileTypeAutocomplete": "자동 완성", + "profileTypeDescription": "채팅 프로필은 대화에 사용됩니다. 자동 완성 프로필은 하나만 허용됩니다.", + "autocompleteLabel": "(자동 완성)", + "autocomplete": { + "onlyOneAllowed": "자동 완성 프로필은 하나만 허용됩니다. 프로필 \"{{existingName}}\"이(가) 이미 자동 완성용으로 구성되어 있습니다. 먼저 유형을 변경하거나 삭제하세요." } }, "browser": { diff --git a/webview-ui/src/i18n/locales/nl/kilocode.json b/webview-ui/src/i18n/locales/nl/kilocode.json index 05963baef1..583263b1aa 100644 --- a/webview-ui/src/i18n/locales/nl/kilocode.json +++ b/webview-ui/src/i18n/locales/nl/kilocode.json @@ -237,6 +237,7 @@ }, "keybindingNotFound": "niet gevonden", "noModelConfigured": "Geen geschikt autocomplete-model gevonden. Configureer een provider in de API-instellingen.", + "configureAutocompleteProfile": "Gebruik elk model door naar profielen te gaan en een Profiel van het Profieltype Autocomplete te configureren.", "model": "Model", "provider": "Provider" } diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 0d9473cb60..6c2fe5b969 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -515,6 +515,15 @@ "description": "Deze provider gebruikt OAuth-authenticatie van de Qwen-service en vereist geen API-sleutels.", "instructions": "Volg de officiële documentatie om het autorisatiebestand te verkrijgen en plaats het in het opgegeven pad.", "setupLink": "Qwen Officiële Documentatie" + }, + "profileName": "Profielnaam", + "profileType": "Profieltype", + "profileTypeChat": "Chat", + "profileTypeAutocomplete": "Automatisch aanvullen", + "profileTypeDescription": "Chatprofielen worden gebruikt voor gesprekken. Er is slechts één automatisch aanvullen profiel toegestaan.", + "autocompleteLabel": "(Automatisch aanvullen)", + "autocomplete": { + "onlyOneAllowed": "Er is slechts één automatisch aanvullen profiel toegestaan. Profiel \"{{existingName}}\" is al geconfigureerd voor automatisch aanvullen. Wijzig eerst het type of verwijder het." } }, "browser": { diff --git a/webview-ui/src/i18n/locales/pl/kilocode.json b/webview-ui/src/i18n/locales/pl/kilocode.json index b0c91af396..ac121f9965 100644 --- a/webview-ui/src/i18n/locales/pl/kilocode.json +++ b/webview-ui/src/i18n/locales/pl/kilocode.json @@ -230,6 +230,7 @@ }, "keybindingNotFound": "nie znaleziono", "noModelConfigured": "Nie znaleziono odpowiedniego modelu autouzupełniania. Skonfiguruj dostawcę w ustawieniach API.", + "configureAutocompleteProfile": "Użyj dowolnego modelu, przechodząc do profili i konfigurując Profil typu Autouzupełnianie.", "model": "Model", "provider": "Dostawca" } diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index f4ecfc0a16..13cac43675 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -515,6 +515,15 @@ "description": "Ten dostawca używa uwierzytelniania OAuth z usługi Qwen i nie wymaga kluczy API.", "instructions": "Postępuj zgodnie z oficjalną dokumentacją, aby uzyskać plik autoryzacji i umieścić go w określonej ścieżce.", "setupLink": "Oficjalna dokumentacja Qwen" + }, + "profileName": "Nazwa profilu", + "profileType": "Typ profilu", + "profileTypeChat": "Czat", + "profileTypeAutocomplete": "Autouzupełnianie", + "profileTypeDescription": "Profile czatu są używane do rozmów. Dozwolony jest tylko jeden profil autouzupełniania.", + "autocompleteLabel": "(Autouzupełnianie)", + "autocomplete": { + "onlyOneAllowed": "Dozwolony jest tylko jeden profil autouzupełniania. Profil \"{{existingName}}\" jest już skonfigurowany do autouzupełniania. Najpierw zmień jego typ lub usuń go." } }, "browser": { diff --git a/webview-ui/src/i18n/locales/pt-BR/kilocode.json b/webview-ui/src/i18n/locales/pt-BR/kilocode.json index 033330ba25..1c87883ebc 100644 --- a/webview-ui/src/i18n/locales/pt-BR/kilocode.json +++ b/webview-ui/src/i18n/locales/pt-BR/kilocode.json @@ -230,6 +230,7 @@ }, "keybindingNotFound": "não encontrado", "noModelConfigured": "Nenhum modelo de autocompletar adequado encontrado. Configure um provedor nas configurações da API.", + "configureAutocompleteProfile": "Use qualquer modelo indo para perfis e configurando um Perfil do Tipo de Perfil Autocompletar.", "model": "Modelo", "provider": "Provedor" } diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index f5ed3bc7b0..4562aaee97 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -515,6 +515,15 @@ "description": "Este provedor usa autenticação OAuth do serviço Qwen e não requer chaves de API.", "instructions": "Siga a documentação oficial para obter o arquivo de autorização e colocá-lo no caminho especificado.", "setupLink": "Documentação Oficial do Qwen" + }, + "profileName": "Nome do perfil", + "profileType": "Tipo de perfil", + "profileTypeChat": "Chat", + "profileTypeAutocomplete": "Autocompletar", + "profileTypeDescription": "Perfis de chat são usados para conversas. Apenas um perfil de autocompletar é permitido.", + "autocompleteLabel": "(Autocompletar)", + "autocomplete": { + "onlyOneAllowed": "Apenas um perfil de autocompletar é permitido. O perfil \"{{existingName}}\" já está configurado para autocompletar. Por favor, mude seu tipo primeiro ou delete-o." } }, "browser": { diff --git a/webview-ui/src/i18n/locales/ru/kilocode.json b/webview-ui/src/i18n/locales/ru/kilocode.json index 7244993cca..024ac5fd38 100644 --- a/webview-ui/src/i18n/locales/ru/kilocode.json +++ b/webview-ui/src/i18n/locales/ru/kilocode.json @@ -230,6 +230,7 @@ }, "keybindingNotFound": "не найдено", "noModelConfigured": "Подходящая модель автодополнения не найдена. Настрой провайдера в настройках API.", + "configureAutocompleteProfile": "Используй любую модель, перейдя в профили и настроив Профиль типа Автодополнение.", "model": "Модель", "provider": "Провайдер" } diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 18788a16eb..338dcf1d07 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -515,6 +515,15 @@ "description": "Этот провайдер использует OAuth-аутентификацию из сервиса Qwen и не требует API-ключей.", "instructions": "Пожалуйста, следуйте официальной документации для получения файла авторизации и размещения его по указанному пути.", "setupLink": "Официальная документация Qwen" + }, + "profileName": "Имя профиля", + "profileType": "Тип профиля", + "profileTypeChat": "Чат", + "profileTypeAutocomplete": "Автодополнение", + "profileTypeDescription": "Профили чата используются для разговоров. Разрешён только один профиль автодополнения.", + "autocompleteLabel": "(Автодополнение)", + "autocomplete": { + "onlyOneAllowed": "Разрешён только один профиль автодополнения. Профиль \"{{existingName}}\" уже настроен для автодополнения. Пожалуйста, сначала измени его тип или удали его." } }, "browser": { diff --git a/webview-ui/src/i18n/locales/th/kilocode.json b/webview-ui/src/i18n/locales/th/kilocode.json index ea09e44f77..608365fc68 100644 --- a/webview-ui/src/i18n/locales/th/kilocode.json +++ b/webview-ui/src/i18n/locales/th/kilocode.json @@ -237,6 +237,7 @@ }, "keybindingNotFound": "ไม่พบ", "noModelConfigured": "ไม่พบโมเดลเติมข้อความอัตโนมัติที่เหมาะสม กรุณาตั้งค่าผู้ให้บริการในการตั้งค่า API", + "configureAutocompleteProfile": "ใช้โมเดลใดก็ได้โดยไปที่โปรไฟล์และตั้งค่าโปรไฟล์ประเภทเติมข้อความอัตโนมัติ", "model": "โมเดล", "provider": "ผู้ให้บริการ" } diff --git a/webview-ui/src/i18n/locales/th/settings.json b/webview-ui/src/i18n/locales/th/settings.json index ca46ae0986..820c2b8dbb 100644 --- a/webview-ui/src/i18n/locales/th/settings.json +++ b/webview-ui/src/i18n/locales/th/settings.json @@ -533,6 +533,15 @@ "roo": { "authenticatedMessage": "ยืนยันตัวตนอย่างปลอดภัยผ่านบัญชี Roo Code Cloud ของคุณ", "connectButton": "เชื่อมต่อกับ Roo Code Cloud" + }, + "profileName": "ชื่อโปรไฟล์", + "profileType": "ประเภทโปรไฟล์", + "profileTypeChat": "แชท", + "profileTypeAutocomplete": "เติมข้อความอัตโนมัติ", + "profileTypeDescription": "โปรไฟล์แชทใช้สำหรับการสนทนา อนุญาตให้มีโปรไฟล์เติมข้อความอัตโนมัติเพียงหนึ่งโปรไฟล์เท่านั้น", + "autocompleteLabel": "(เติมข้อความอัตโนมัติ)", + "autocomplete": { + "onlyOneAllowed": "อนุญาตให้มีโปรไฟล์เติมข้อความอัตโนมัติเพียงหนึ่งโปรไฟล์เท่านั้น โปรไฟล์ \"{{existingName}}\" ถูกกำหนดค่าสำหรับเติมข้อความอัตโนมัติแล้ว กรุณาเปลี่ยนประเภทก่อนหรือลบออก" } }, "contextWindow": { diff --git a/webview-ui/src/i18n/locales/tr/kilocode.json b/webview-ui/src/i18n/locales/tr/kilocode.json index aef21c76f4..c4a9b6673a 100644 --- a/webview-ui/src/i18n/locales/tr/kilocode.json +++ b/webview-ui/src/i18n/locales/tr/kilocode.json @@ -230,6 +230,7 @@ }, "keybindingNotFound": "bulunamadı", "noModelConfigured": "Uygun otomatik tamamlama modeli bulunamadı. Lütfen API ayarlarında bir sağlayıcı yapılandır.", + "configureAutocompleteProfile": "Profillere giderek ve Otomatik Tamamlama Profil Türünde bir Profil yapılandırarak herhangi bir model kullan.", "model": "Model", "provider": "Sağlayıcı" } diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 261473ecdb..ebe2239441 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -516,6 +516,15 @@ "description": "Bu sağlayıcı Qwen hizmetinden OAuth kimlik doğrulaması kullanır ve API anahtarları gerektirmez.", "instructions": "Yetkilendirme dosyasını almak ve belirtilen yola yerleştirmek için lütfen resmi belgeleri takip edin.", "setupLink": "Qwen Resmi Belgeleri" + }, + "profileName": "Profil Adı", + "profileType": "Profil Türü", + "profileTypeChat": "Sohbet", + "profileTypeAutocomplete": "Otomatik Tamamlama", + "profileTypeDescription": "Sohbet profilleri konuşmalar için kullanılır. Yalnızca bir otomatik tamamlama profiline izin verilir.", + "autocompleteLabel": "(Otomatik Tamamlama)", + "autocomplete": { + "onlyOneAllowed": "Yalnızca bir otomatik tamamlama profiline izin verilir. \"{{existingName}}\" profili zaten otomatik tamamlama için yapılandırılmış. Lütfen önce türünü değiştir veya sil." } }, "browser": { diff --git a/webview-ui/src/i18n/locales/uk/kilocode.json b/webview-ui/src/i18n/locales/uk/kilocode.json index 24b58bd6df..dbb8653448 100644 --- a/webview-ui/src/i18n/locales/uk/kilocode.json +++ b/webview-ui/src/i18n/locales/uk/kilocode.json @@ -237,6 +237,7 @@ }, "keybindingNotFound": "не знайдено", "noModelConfigured": "Не знайдено відповідної моделі автодоповнення. Налаштуй провайдера в налаштуваннях API.", + "configureAutocompleteProfile": "Використовуй будь-яку модель, перейшовши до профілів і налаштувавши Профіль типу Автодоповнення.", "model": "Модель", "provider": "Провайдер" } diff --git a/webview-ui/src/i18n/locales/uk/settings.json b/webview-ui/src/i18n/locales/uk/settings.json index 84ea84b87a..545c3e71f9 100644 --- a/webview-ui/src/i18n/locales/uk/settings.json +++ b/webview-ui/src/i18n/locales/uk/settings.json @@ -543,6 +543,15 @@ "description": "Цей провайдер використовує OAuth-аутентифікацію від сервісу Qwen і не потребує API-ключів.", "instructions": "Будь ласка, дотримуйтесь офіційної документації для отримання файлу авторизації та розміщення його за вказаним шляхом.", "setupLink": "Офіційна документація Qwen" + }, + "profileName": "Назва профілю", + "profileType": "Тип профілю", + "profileTypeChat": "Чат", + "profileTypeAutocomplete": "Автодоповнення", + "profileTypeDescription": "Профілі чату використовуються для розмов. Дозволено лише один профіль автодоповнення.", + "autocompleteLabel": "(Автодоповнення)", + "autocomplete": { + "onlyOneAllowed": "Дозволено лише один профіль автодоповнення. Профіль \"{{existingName}}\" вже налаштовано для автодоповнення. Будь ласка, спочатку зміни його тип або видали його." } }, "contextWindow": { diff --git a/webview-ui/src/i18n/locales/vi/kilocode.json b/webview-ui/src/i18n/locales/vi/kilocode.json index f116dee12d..a991f3b6d9 100644 --- a/webview-ui/src/i18n/locales/vi/kilocode.json +++ b/webview-ui/src/i18n/locales/vi/kilocode.json @@ -230,6 +230,7 @@ }, "keybindingNotFound": "không tìm thấy", "noModelConfigured": "Không tìm thấy mô hình tự động hoàn thành phù hợp. Vui lòng cấu hình nhà cung cấp trong cài đặt API.", + "configureAutocompleteProfile": "Sử dụng bất kỳ mô hình nào bằng cách vào hồ sơ và cấu hình Hồ sơ có Loại Hồ sơ là Tự động hoàn thành.", "model": "Mô hình", "provider": "Nhà cung cấp" } diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index b28be64f98..6be0dbeb31 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -515,6 +515,15 @@ "description": "Nhà cung cấp này sử dụng xác thực OAuth từ dịch vụ Qwen và không yêu cầu khóa API.", "instructions": "Vui lòng làm theo tài liệu chính thức để lấy tệp ủy quyền và đặt nó trong đường dẫn được chỉ định.", "setupLink": "Tài liệu chính thức Qwen" + }, + "profileName": "Tên hồ sơ", + "profileType": "Loại hồ sơ", + "profileTypeChat": "Trò chuyện", + "profileTypeAutocomplete": "Tự động hoàn thành", + "profileTypeDescription": "Hồ sơ trò chuyện được sử dụng cho các cuộc hội thoại. Chỉ cho phép một hồ sơ tự động hoàn thành.", + "autocompleteLabel": "(Tự động hoàn thành)", + "autocomplete": { + "onlyOneAllowed": "Chỉ cho phép một hồ sơ tự động hoàn thành. Hồ sơ \"{{existingName}}\" đã được cấu hình cho tự động hoàn thành. Vui lòng thay đổi loại của nó trước hoặc xóa nó." } }, "browser": { diff --git a/webview-ui/src/i18n/locales/zh-CN/kilocode.json b/webview-ui/src/i18n/locales/zh-CN/kilocode.json index 8c5dda2952..43c48bdf73 100644 --- a/webview-ui/src/i18n/locales/zh-CN/kilocode.json +++ b/webview-ui/src/i18n/locales/zh-CN/kilocode.json @@ -237,6 +237,7 @@ }, "keybindingNotFound": "未找到", "noModelConfigured": "未找到合适的自动补全模型。请在 API 设置中配置提供商。", + "configureAutocompleteProfile": "前往配置文件并配置自动补全类型的配置文件即可使用任意模型。", "model": "模型", "provider": "提供商" } diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 3b0acf1936..c8a89e43d5 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -516,6 +516,15 @@ "description": "此提供商使用 Qwen 服务的 OAuth 身份验证,不需要 API 密钥。", "instructions": "请按照官方文档获取授权文件并将其放置在指定路径中。", "setupLink": "Qwen 官方文档" + }, + "profileName": "配置名称", + "profileType": "配置类型", + "profileTypeChat": "对话", + "profileTypeAutocomplete": "自动补全", + "profileTypeDescription": "对话配置用于会话。只允许一个自动补全配置。", + "autocompleteLabel": "(自动补全)", + "autocomplete": { + "onlyOneAllowed": "只允许一个自动补全配置。配置「{{existingName}}」已配置为自动补全。请先更改其类型或删除它。" } }, "browser": { diff --git a/webview-ui/src/i18n/locales/zh-TW/kilocode.json b/webview-ui/src/i18n/locales/zh-TW/kilocode.json index 5af732561e..03e69bc60e 100644 --- a/webview-ui/src/i18n/locales/zh-TW/kilocode.json +++ b/webview-ui/src/i18n/locales/zh-TW/kilocode.json @@ -232,6 +232,7 @@ }, "keybindingNotFound": "未找到", "noModelConfigured": "找不到合適的自動補全模型。請在 API 設定中配置提供者。", + "configureAutocompleteProfile": "前往設定檔並設定自動補全類型的設定檔即可使用任意模型。", "model": "模型", "provider": "供應商" } diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index d6252ae9ff..d9188c62f1 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -516,6 +516,15 @@ "description": "此供應商使用 Qwen 服務的 OAuth 身份驗證,不需要 API 金鑰。", "instructions": "請依照官方文件取得授權檔案並放置在指定路徑。", "setupLink": "Qwen 官方文件" + }, + "profileName": "設定檔名稱", + "profileType": "設定檔類型", + "profileTypeChat": "對話", + "profileTypeAutocomplete": "自動完成", + "profileTypeDescription": "對話設定檔用於交談。只允許一個自動完成設定檔。", + "autocompleteLabel": "(自動完成)", + "autocomplete": { + "onlyOneAllowed": "只允許一個自動完成設定檔。設定檔「{{existingName}}」已設定為自動完成。請先變更其類型或刪除它。" } }, "browser": {