From 971489990cc310904ad51d6a01c684ae460d63e5 Mon Sep 17 00:00:00 2001 From: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com> Date: Mon, 27 Jan 2025 20:15:35 -0800 Subject: [PATCH] Fix language persistence across sessions; update system prompt for non-english languages --- src/core/Cline.ts | 18 +++++++++++++-- src/core/prompts/system.ts | 10 +++++++- src/core/webview/ClineProvider.ts | 23 ++++++++++++++++--- src/shared/WebviewMessage.ts | 1 + .../components/settings/LanguageOptions.tsx | 7 +++++- 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 947a5fae6f..6c0f6beff3 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -75,6 +75,7 @@ export class Cline { browserSession: BrowserSession private didEditFile: boolean = false customInstructions?: string + localeLanguage?: string autoApprovalSettings: AutoApprovalSettings private browserSettings: BrowserSettings private chatSettings: ChatSettings @@ -119,6 +120,7 @@ export class Cline { browserSettings: BrowserSettings, chatSettings: ChatSettings, customInstructions?: string, + localeLanguage?: string, task?: string, images?: string[], historyItem?: HistoryItem, @@ -130,6 +132,7 @@ export class Cline { this.browserSession = new BrowserSession(provider.context, browserSettings) this.diffViewProvider = new DiffViewProvider(cwd) this.customInstructions = customInstructions + this.localeLanguage = localeLanguage this.autoApprovalSettings = autoApprovalSettings this.browserSettings = browserSettings this.chatSettings = chatSettings @@ -1212,6 +1215,13 @@ export class Cline { this.browserSettings, ) + let userSelectedNonEnglishLanguage: string | undefined + // While we check vscode for preferred language, it's likely not giving us one of the language options + console.log("this.localeLanguage", this.localeLanguage) + if (this.localeLanguage && this.localeLanguage !== "en") { + userSelectedNonEnglishLanguage = this.localeLanguage + } + let settingsCustomInstructions = this.customInstructions?.trim() const clineRulesFilePath = path.resolve(cwd, GlobalFileNames.clineRules) let clineRulesFileInstructions: string | undefined @@ -1226,9 +1236,13 @@ export class Cline { } } - if (settingsCustomInstructions || clineRulesFileInstructions) { + if (settingsCustomInstructions || clineRulesFileInstructions || userSelectedNonEnglishLanguage) { // altering the system prompt mid-task will break the prompt cache, but in the grand scheme this will not change often so it's better to not pollute user messages with it the way we have to with - systemPrompt += addUserInstructions(settingsCustomInstructions, clineRulesFileInstructions) + systemPrompt += addUserInstructions( + settingsCustomInstructions, + clineRulesFileInstructions, + userSelectedNonEnglishLanguage, + ) } // If the previous API request's total token usage is close to the context window, truncate the conversation history to free up space for the new request diff --git a/src/core/prompts/system.ts b/src/core/prompts/system.ts index 3c26f70d75..8ef7d89a9c 100644 --- a/src/core/prompts/system.ts +++ b/src/core/prompts/system.ts @@ -957,8 +957,16 @@ You accomplish a given task iteratively, breaking it down into clear steps and w 4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. \`open index.html\` to show the website you've built. 5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.` -export function addUserInstructions(settingsCustomInstructions?: string, clineRulesFileInstructions?: string) { +export function addUserInstructions( + settingsCustomInstructions?: string, + clineRulesFileInstructions?: string, + chosenLanguage?: string, +) { let customInstructions = "" + if (chosenLanguage) { + // Will only be provided for non-english languages + customInstructions += `Speak in this language: ${chosenLanguage}.` + "\n\n" + } if (settingsCustomInstructions) { customInstructions += settingsCustomInstructions + "\n\n" } diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 4021d6bccf..3f1acb9a2d 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -244,7 +244,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { async initClineWithTask(task?: string, images?: string[]) { await this.clearTask() // ensures that an exising task doesn't exist before starting a new one, although this shouldn't be possible since user must clear task before starting a new one - const { apiConfiguration, customInstructions, autoApprovalSettings, browserSettings, chatSettings } = + const { apiConfiguration, customInstructions, localeLanguage, autoApprovalSettings, browserSettings, chatSettings } = await this.getState() this.cline = new Cline( this, @@ -253,6 +253,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { browserSettings, chatSettings, customInstructions, + localeLanguage, task, images, ) @@ -260,7 +261,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { async initClineWithHistoryItem(historyItem: HistoryItem) { await this.clearTask() - const { apiConfiguration, customInstructions, autoApprovalSettings, browserSettings, chatSettings } = + const { apiConfiguration, customInstructions, localeLanguage, autoApprovalSettings, browserSettings, chatSettings } = await this.getState() this.cline = new Cline( this, @@ -269,6 +270,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { browserSettings, chatSettings, customInstructions, + localeLanguage, undefined, undefined, historyItem, @@ -677,6 +679,10 @@ export class ClineProvider implements vscode.WebviewViewProvider { } break } + case "changeLanguage": { + await this.updateLocaleLanguage(message.text) + break + } case "restartMcpServer": { try { await this.mcpHub?.restartConnection(message.text!) @@ -770,6 +776,14 @@ export class ClineProvider implements vscode.WebviewViewProvider { await this.postStateToWebview() } + async updateLocaleLanguage(language?: string) { + await this.updateGlobalState("localeLanguage", language || undefined) + if (this.cline) { + this.cline.localeLanguage = language || undefined + } + await this.postStateToWebview() + } + // MCP async getDocumentsPath(): Promise { @@ -1184,6 +1198,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { browserSettings, chatSettings, userInfo, + localeLanguage, } = await this.getState() const authToken = await this.getSecret("authToken") @@ -1200,7 +1215,8 @@ export class ClineProvider implements vscode.WebviewViewProvider { autoApprovalSettings, browserSettings, chatSettings, - localeLanguage: vscode.env.language, + // FIXME: the vscode.env.language doesn't translate to the language specifiers we use in i18n. We need to know what values vscode uses and transform. For now this will always just lead to defaulting to English (see i18n.ts) + localeLanguage: localeLanguage || vscode.env.language, isLoggedIn: !!authToken, userInfo, } @@ -1382,6 +1398,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { autoApprovalSettings: autoApprovalSettings || DEFAULT_AUTO_APPROVAL_SETTINGS, // default value can be 0 or empty string browserSettings: browserSettings || DEFAULT_BROWSER_SETTINGS, chatSettings: chatSettings || DEFAULT_CHAT_SETTINGS, + localeLanguage, userInfo, } } diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index a18a3c405a..bf20145498 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -42,6 +42,7 @@ export interface WebviewMessage { | "accountLoginClicked" | "accountLogoutClicked" | "subscribeEmail" + | "changeLanguage" // | "relaunchChromeDebugMode" text?: string disabled?: boolean diff --git a/webview-ui/src/components/settings/LanguageOptions.tsx b/webview-ui/src/components/settings/LanguageOptions.tsx index 8d66231728..f06b4fa5d1 100644 --- a/webview-ui/src/components/settings/LanguageOptions.tsx +++ b/webview-ui/src/components/settings/LanguageOptions.tsx @@ -1,13 +1,18 @@ import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react" import { memo } from "react" import { useTranslation } from "react-i18next" +import { vscode } from "../../utils/vscode" const LanguageOptions = () => { const { t, i18n } = useTranslation("translation", { keyPrefix: "settingsView", useSuspense: false }) const changeLanguage = (e: any) => { const language = e.target.value - i18n.changeLanguage(language) + // i18n.changeLanguage(language) + vscode.postMessage({ + type: "changeLanguage", + text: language, + }) } return (