diff --git a/CHANGELOG.md b/CHANGELOG.md index cb5ece2792..ac0ca40cf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ All notable changes to the "claude-dev" extension will be documented in this fil ## [1.1.1] -- Added the ability to choose other Claude models (+ GPT-4o, DeepSeek, and Mistral if you use OpenRouter) +- Adds option to choose other Claude models (+ GPT-4o, DeepSeek, and Mistral if you use OpenRouter) +- Adds option to add custom instructions to the end of the system prompt ## [1.1.0] diff --git a/src/ClaudeDev.ts b/src/ClaudeDev.ts index 1a72bfaf28..4b095623a2 100644 --- a/src/ClaudeDev.ts +++ b/src/ClaudeDev.ts @@ -235,6 +235,7 @@ type ToolResponse = string | Array { try { - return await this.api.createMessage(SYSTEM_PROMPT(), this.apiConversationHistory, tools) + let systemPrompt = SYSTEM_PROMPT() + if (this.customInstructions && this.customInstructions.trim()) { + systemPrompt += ` +==== + +USER'S CUSTOM INSTRUCTIONS + +The following additional instructions are provided by the user. They should be followed and given precedence in case of conflicts with previous instructions. + +${this.customInstructions.trim()} +` + } + return await this.api.createMessage(systemPrompt, this.apiConversationHistory, tools) } catch (error) { const { response } = await this.ask( "api_req_failed", diff --git a/src/providers/ClaudeDevProvider.ts b/src/providers/ClaudeDevProvider.ts index 5a45caf852..e102eb6956 100644 --- a/src/providers/ClaudeDevProvider.ts +++ b/src/providers/ClaudeDevProvider.ts @@ -11,7 +11,13 @@ https://github.com/KumarVariable/vscode-extension-sidebar-html/blob/master/src/c */ type SecretKey = "apiKey" | "openRouterApiKey" | "awsAccessKey" | "awsSecretKey" -type GlobalStateKey = "apiProvider" | "apiModelId" | "awsRegion" | "maxRequestsPerTask" | "lastShownAnnouncementId" +type GlobalStateKey = + | "apiProvider" + | "apiModelId" + | "awsRegion" + | "maxRequestsPerTask" + | "lastShownAnnouncementId" + | "customInstructions" export class ClaudeDevProvider implements vscode.WebviewViewProvider { public static readonly sideBarId = "claude-dev.SidebarProvider" // used in package.json as the view's id. This value cannot be changed due to how vscode caches views based on their id, and updating the id would break existing instances of the extension. @@ -132,8 +138,8 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider { async initClaudeDevWithTask(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 { maxRequestsPerTask, apiConfiguration } = await this.getState() - this.claudeDev = new ClaudeDev(this, apiConfiguration, maxRequestsPerTask, task, images) + const { maxRequestsPerTask, apiConfiguration, customInstructions } = await this.getState() + this.claudeDev = new ClaudeDev(this, apiConfiguration, maxRequestsPerTask, customInstructions, task, images) } // Send any JSON serializable data to the react app @@ -280,6 +286,12 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider { this.claudeDev?.updateMaxRequestsPerTask(result) await this.postStateToWebview() break + case "customInstructions": + // User may be clearing the field + await this.updateGlobalState("customInstructions", message.text || undefined) + this.claudeDev?.updateCustomInstructions(message.text || undefined) + await this.postStateToWebview() + break case "askResponse": this.claudeDev?.handleWebviewAskResponse(message.askResponse!, message.text, message.images) break @@ -309,13 +321,15 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider { } async postStateToWebview() { - const { apiConfiguration, maxRequestsPerTask, lastShownAnnouncementId } = await this.getState() + const { apiConfiguration, maxRequestsPerTask, lastShownAnnouncementId, customInstructions } = + await this.getState() this.postMessageToWebview({ type: "state", state: { version: this.context.extension?.packageJSON?.version ?? "", apiConfiguration, maxRequestsPerTask, + customInstructions, themeName: vscode.workspace.getConfiguration("workbench").get("colorTheme"), claudeMessages: this.claudeDev?.claudeMessages || [], shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId, @@ -420,6 +434,7 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider { awsRegion, maxRequestsPerTask, lastShownAnnouncementId, + customInstructions, ] = await Promise.all([ this.getGlobalState("apiProvider") as Promise, this.getGlobalState("apiModelId") as Promise, @@ -430,6 +445,7 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider { this.getGlobalState("awsRegion") as Promise, this.getGlobalState("maxRequestsPerTask") as Promise, this.getGlobalState("lastShownAnnouncementId") as Promise, + this.getGlobalState("customInstructions") as Promise, ]) return { apiConfiguration: { @@ -443,6 +459,7 @@ export class ClaudeDevProvider implements vscode.WebviewViewProvider { }, maxRequestsPerTask, lastShownAnnouncementId, + customInstructions, } } diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 0ac3d10b23..2527ff752a 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -15,6 +15,7 @@ export interface ExtensionState { version: string apiConfiguration?: ApiConfiguration maxRequestsPerTask?: number + customInstructions?: string themeName?: string claudeMessages: ClaudeMessage[] shouldShowAnnouncement: boolean diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index d8dee185d8..86e0aca500 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -4,6 +4,7 @@ export interface WebviewMessage { type: | "apiConfiguration" | "maxRequestsPerTask" + | "customInstructions" | "webviewDidLaunch" | "newTask" | "askResponse" diff --git a/webview-ui/src/App.tsx b/webview-ui/src/App.tsx index 74ed94adca..f8cbd30ae1 100644 --- a/webview-ui/src/App.tsx +++ b/webview-ui/src/App.tsx @@ -22,6 +22,7 @@ const App: React.FC = () => { const [version, setVersion] = useState("") const [apiConfiguration, setApiConfiguration] = useState(undefined) const [maxRequestsPerTask, setMaxRequestsPerTask] = useState("") + const [customInstructions, setCustomInstructions] = useState("") const [vscodeThemeName, setVscodeThemeName] = useState(undefined) const [claudeMessages, setClaudeMessages] = useState([]) const [showAnnouncement, setShowAnnouncement] = useState(false) @@ -44,6 +45,7 @@ const App: React.FC = () => { setMaxRequestsPerTask( message.state!.maxRequestsPerTask !== undefined ? message.state!.maxRequestsPerTask.toString() : "" ) + setCustomInstructions(message.state!.customInstructions || "") setVscodeThemeName(message.state!.themeName) setClaudeMessages(message.state!.claudeMessages) // don't update showAnnouncement to false if shouldShowAnnouncement is false @@ -90,6 +92,8 @@ const App: React.FC = () => { setApiConfiguration={setApiConfiguration} maxRequestsPerTask={maxRequestsPerTask} setMaxRequestsPerTask={setMaxRequestsPerTask} + customInstructions={customInstructions} + setCustomInstructions={setCustomInstructions} onDone={() => setShowSettings(false)} /> )} diff --git a/webview-ui/src/components/Announcement.tsx b/webview-ui/src/components/Announcement.tsx index 4e5d759d12..ece8654349 100644 --- a/webview-ui/src/components/Announcement.tsx +++ b/webview-ui/src/components/Announcement.tsx @@ -35,6 +35,10 @@ const Announcement = ({ version, hideAnnouncement }: AnnouncementProps) => { Added a settings option to choose other Claude models (+ GPT-4o, DeepSeek, and Mistral if you use OpenRouter) +
  • + You can now add custom instructions to the end of the system prompt (e.g. "Always use Python", + "Speak in Spanish") +
  • Improved support for running interactive terminal commands and long-running processes like servers
  • diff --git a/webview-ui/src/components/SettingsView.tsx b/webview-ui/src/components/SettingsView.tsx index 32199abc79..37d44bc940 100644 --- a/webview-ui/src/components/SettingsView.tsx +++ b/webview-ui/src/components/SettingsView.tsx @@ -1,4 +1,4 @@ -import { VSCodeButton, VSCodeLink, VSCodeTextField } from "@vscode/webview-ui-toolkit/react" +import { VSCodeButton, VSCodeLink, VSCodeTextArea, VSCodeTextField } from "@vscode/webview-ui-toolkit/react" import React, { useEffect, useState } from "react" import { ApiConfiguration } from "../../../src/shared/api" import { validateApiConfiguration, validateMaxRequestsPerTask } from "../utils/validate" @@ -11,6 +11,8 @@ type SettingsViewProps = { setApiConfiguration: React.Dispatch> maxRequestsPerTask: string setMaxRequestsPerTask: React.Dispatch> + customInstructions: string + setCustomInstructions: React.Dispatch> onDone: () => void } @@ -20,6 +22,8 @@ const SettingsView = ({ setApiConfiguration, maxRequestsPerTask, setMaxRequestsPerTask, + customInstructions, + setCustomInstructions, onDone, }: SettingsViewProps) => { const [apiErrorMessage, setApiErrorMessage] = useState(undefined) @@ -35,6 +39,7 @@ const SettingsView = ({ if (!apiValidationResult && !maxRequestsValidationResult) { vscode.postMessage({ type: "apiConfiguration", apiConfiguration }) vscode.postMessage({ type: "maxRequestsPerTask", text: maxRequestsPerTask }) + vscode.postMessage({ type: "customInstructions", text: customInstructions }) onDone() } } @@ -102,7 +107,28 @@ const SettingsView = ({ )} -
    +
    + setCustomInstructions(e.target?.value || "")}> + Custom Instructions + +

    + These instructions are added to the end of the system prompt sent with every request. +

    +
    + +