From f86e96d15712dab872d3616877cb80d12c557261 Mon Sep 17 00:00:00 2001 From: sam hoang Date: Fri, 24 Jan 2025 01:46:33 +0700 Subject: [PATCH] refactor: separate mode and support prompts - Rename customPrompts to customModePrompts for mode-specific prompts - Add new customSupportPrompts type for support action prompts - Update types to be more specific (CustomModePrompts and CustomSupportPrompts) - Fix all related tests and component implementations --- src/core/Cline.ts | 4 +- src/core/prompts/__tests__/system.test.ts | 32 ++++----- src/core/prompts/system.ts | 6 +- src/core/webview/ClineProvider.ts | 68 +++++++++++-------- .../webview/__tests__/ClineProvider.test.ts | 30 ++++---- src/shared/ExtensionMessage.ts | 6 +- src/shared/__tests__/support-prompts.test.ts | 16 ++--- src/shared/modes.ts | 6 +- src/shared/support-prompt.ts | 12 ++-- .../chat/__tests__/AutoApproveMenu.test.tsx | 7 +- .../src/components/prompts/PromptsView.tsx | 17 ++--- .../prompts/__tests__/PromptsView.test.tsx | 2 +- .../src/context/ExtensionStateContext.tsx | 12 ++-- 13 files changed, 119 insertions(+), 99 deletions(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 5f8af77..0e2872b 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -809,7 +809,7 @@ export class Cline { }) } - const { browserViewportSize, mode, customPrompts, preferredLanguage } = + const { browserViewportSize, mode, customModePrompts, preferredLanguage } = (await this.providerRef.deref()?.getState()) ?? {} const { customModes } = (await this.providerRef.deref()?.getState()) ?? {} const systemPrompt = await (async () => { @@ -825,7 +825,7 @@ export class Cline { this.diffStrategy, browserViewportSize, mode, - customPrompts, + customModePrompts, customModes, this.customInstructions, preferredLanguage, diff --git a/src/core/prompts/__tests__/system.test.ts b/src/core/prompts/__tests__/system.test.ts index 6ecf7ef..4138d11 100644 --- a/src/core/prompts/__tests__/system.test.ts +++ b/src/core/prompts/__tests__/system.test.ts @@ -162,7 +162,7 @@ describe("SYSTEM_PROMPT", () => { undefined, // diffStrategy undefined, // browserViewportSize defaultModeSlug, // mode - undefined, // customPrompts + undefined, // customModePrompts undefined, // customModes ) @@ -178,7 +178,7 @@ describe("SYSTEM_PROMPT", () => { undefined, // diffStrategy "1280x800", // browserViewportSize defaultModeSlug, // mode - undefined, // customPrompts + undefined, // customModePrompts undefined, // customModes ) @@ -196,7 +196,7 @@ describe("SYSTEM_PROMPT", () => { undefined, // diffStrategy undefined, // browserViewportSize defaultModeSlug, // mode - undefined, // customPrompts + undefined, // customModePrompts undefined, // customModes ) @@ -212,7 +212,7 @@ describe("SYSTEM_PROMPT", () => { undefined, // diffStrategy undefined, // browserViewportSize defaultModeSlug, // mode - undefined, // customPrompts + undefined, // customModePrompts undefined, // customModes ) @@ -228,7 +228,7 @@ describe("SYSTEM_PROMPT", () => { undefined, // diffStrategy "900x600", // different viewport size defaultModeSlug, // mode - undefined, // customPrompts + undefined, // customModePrompts undefined, // customModes ) @@ -244,7 +244,7 @@ describe("SYSTEM_PROMPT", () => { new SearchReplaceDiffStrategy(), // Use actual diff strategy from the codebase undefined, // browserViewportSize defaultModeSlug, // mode - undefined, // customPrompts + undefined, // customModePrompts undefined, // customModes undefined, // globalCustomInstructions undefined, // preferredLanguage @@ -264,7 +264,7 @@ describe("SYSTEM_PROMPT", () => { new SearchReplaceDiffStrategy(), // Use actual diff strategy from the codebase undefined, // browserViewportSize defaultModeSlug, // mode - undefined, // customPrompts + undefined, // customModePrompts undefined, // customModes undefined, // globalCustomInstructions undefined, // preferredLanguage @@ -284,7 +284,7 @@ describe("SYSTEM_PROMPT", () => { new SearchReplaceDiffStrategy(), // Use actual diff strategy from the codebase undefined, // browserViewportSize defaultModeSlug, // mode - undefined, // customPrompts + undefined, // customModePrompts undefined, // customModes undefined, // globalCustomInstructions undefined, // preferredLanguage @@ -304,7 +304,7 @@ describe("SYSTEM_PROMPT", () => { undefined, // diffStrategy undefined, // browserViewportSize defaultModeSlug, // mode - undefined, // customPrompts + undefined, // customModePrompts undefined, // customModes undefined, // globalCustomInstructions "Spanish", // preferredLanguage @@ -334,7 +334,7 @@ describe("SYSTEM_PROMPT", () => { undefined, // diffStrategy undefined, // browserViewportSize "custom-mode", // mode - undefined, // customPrompts + undefined, // customModePrompts customModes, // customModes "Global instructions", // globalCustomInstructions ) @@ -351,7 +351,7 @@ describe("SYSTEM_PROMPT", () => { }) it("should use promptComponent roleDefinition when available", async () => { - const customPrompts = { + const customModePrompts = { [defaultModeSlug]: { roleDefinition: "Custom prompt role definition", customInstructions: "Custom prompt instructions", @@ -366,7 +366,7 @@ describe("SYSTEM_PROMPT", () => { undefined, undefined, defaultModeSlug, - customPrompts, + customModePrompts, undefined, ) @@ -377,7 +377,7 @@ describe("SYSTEM_PROMPT", () => { }) it("should fallback to modeConfig roleDefinition when promptComponent has no roleDefinition", async () => { - const customPrompts = { + const customModePrompts = { [defaultModeSlug]: { customInstructions: "Custom prompt instructions", // No roleDefinition provided @@ -392,7 +392,7 @@ describe("SYSTEM_PROMPT", () => { undefined, undefined, defaultModeSlug, - customPrompts, + customModePrompts, undefined, ) @@ -432,7 +432,7 @@ describe("addCustomInstructions", () => { undefined, // diffStrategy undefined, // browserViewportSize "architect", // mode - undefined, // customPrompts + undefined, // customModePrompts undefined, // customModes ) @@ -448,7 +448,7 @@ describe("addCustomInstructions", () => { undefined, // diffStrategy undefined, // browserViewportSize "ask", // mode - undefined, // customPrompts + undefined, // customModePrompts undefined, // customModes ) diff --git a/src/core/prompts/system.ts b/src/core/prompts/system.ts index 2546adc..b77d243 100644 --- a/src/core/prompts/system.ts +++ b/src/core/prompts/system.ts @@ -1,7 +1,7 @@ import { Mode, modes, - CustomPrompts, + CustomModePrompts, PromptComponent, getRoleDefinition, defaultModeSlug, @@ -97,7 +97,7 @@ export const SYSTEM_PROMPT = async ( diffStrategy?: DiffStrategy, browserViewportSize?: string, mode: Mode = defaultModeSlug, - customPrompts?: CustomPrompts, + customModePrompts?: CustomModePrompts, customModes?: ModeConfig[], globalCustomInstructions?: string, preferredLanguage?: string, @@ -115,7 +115,7 @@ export const SYSTEM_PROMPT = async ( } // Check if it's a custom mode - const promptComponent = getPromptComponent(customPrompts?.[mode]) + const promptComponent = getPromptComponent(customModePrompts?.[mode]) // Get full mode config from custom modes or fall back to built-in modes const currentMode = getModeBySlug(mode, customModes) || modes.find((m) => m.slug === mode) || modes[0] diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 797def3..1cf7028 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -22,7 +22,7 @@ import { WebviewMessage } from "../../shared/WebviewMessage" import { Mode, modes, - CustomPrompts, + CustomModePrompts, PromptComponent, ModeConfig, defaultModeSlug, @@ -40,7 +40,7 @@ import { singleCompletionHandler } from "../../utils/single-completion-handler" import { getCommitInfo, searchCommits, getWorkingState } from "../../utils/git" import { ConfigManager } from "../config/ConfigManager" import { CustomModesManager } from "../config/CustomModesManager" -import { supportPrompt } from "../../shared/support-prompt" +import { CustomSupportPrompts, supportPrompt } from "../../shared/support-prompt" import { ACTION_NAMES } from "../CodeActionProvider" @@ -111,7 +111,8 @@ type GlobalStateKey = | "vsCodeLmModelSelector" | "mode" | "modeApiConfigs" - | "customPrompts" + | "customModePrompts" + | "customSupportPrompts" | "enhancementApiConfigId" | "experimentalDiffStrategy" | "autoApprovalEnabled" @@ -203,9 +204,9 @@ export class ClineProvider implements vscode.WebviewViewProvider { return } - const { customPrompts } = await visibleProvider.getState() + const { customSupportPrompts } = await visibleProvider.getState() - const prompt = supportPrompt.create(promptType, params, customPrompts) + const prompt = supportPrompt.create(promptType, params, customSupportPrompts) await visibleProvider.initClineWithTask(prompt) } @@ -296,7 +297,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { await this.clearTask() const { apiConfiguration, - customPrompts, + customModePrompts, diffEnabled, fuzzyMatchThreshold, mode, @@ -304,7 +305,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { experimentalDiffStrategy, } = await this.getState() - const modePrompt = customPrompts?.[mode] as PromptComponent + const modePrompt = customModePrompts?.[mode] as PromptComponent const effectiveInstructions = [globalInstructions, modePrompt?.customInstructions].filter(Boolean).join("\n\n") this.cline = new Cline( @@ -324,7 +325,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { await this.clearTask() const { apiConfiguration, - customPrompts, + customModePrompts, diffEnabled, fuzzyMatchThreshold, mode, @@ -332,7 +333,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { experimentalDiffStrategy, } = await this.getState() - const modePrompt = customPrompts?.[mode] as PromptComponent + const modePrompt = customModePrompts?.[mode] as PromptComponent const effectiveInstructions = [globalInstructions, modePrompt?.customInstructions].filter(Boolean).join("\n\n") this.cline = new Cline( @@ -817,14 +818,14 @@ export class ClineProvider implements vscode.WebviewViewProvider { return } - const existingPrompts = (await this.getGlobalState("customPrompts")) || {} + const existingPrompts = (await this.getGlobalState("customSupportPrompts")) || {} const updatedPrompts = { ...existingPrompts, ...message.values, } - await this.updateGlobalState("customPrompts", updatedPrompts) + await this.updateGlobalState("customSupportPrompts", updatedPrompts) await this.postStateToWebview() } catch (error) { console.error("Error update support prompt:", error) @@ -837,10 +838,8 @@ export class ClineProvider implements vscode.WebviewViewProvider { return } - const existingPrompts = ((await this.getGlobalState("customPrompts")) || {}) as Record< - string, - any - > + const existingPrompts = ((await this.getGlobalState("customSupportPrompts")) || + {}) as Record const updatedPrompts = { ...existingPrompts, @@ -848,7 +847,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { updatedPrompts[message.text] = undefined - await this.updateGlobalState("customPrompts", updatedPrompts) + await this.updateGlobalState("customSupportPrompts", updatedPrompts) await this.postStateToWebview() } catch (error) { console.error("Error reset support prompt:", error) @@ -857,21 +856,21 @@ export class ClineProvider implements vscode.WebviewViewProvider { break case "updatePrompt": if (message.promptMode && message.customPrompt !== undefined) { - const existingPrompts = (await this.getGlobalState("customPrompts")) || {} + const existingPrompts = (await this.getGlobalState("customModePrompts")) || {} const updatedPrompts = { ...existingPrompts, [message.promptMode]: message.customPrompt, } - await this.updateGlobalState("customPrompts", updatedPrompts) + await this.updateGlobalState("customModePrompts", updatedPrompts) - // Get current state and explicitly include customPrompts + // Get current state and explicitly include customModePrompts const currentState = await this.getState() const stateWithPrompts = { ...currentState, - customPrompts: updatedPrompts, + customModePrompts: updatedPrompts, } // Post state with prompts @@ -981,8 +980,12 @@ export class ClineProvider implements vscode.WebviewViewProvider { case "enhancePrompt": if (message.text) { try { - const { apiConfiguration, customPrompts, listApiConfigMeta, enhancementApiConfigId } = - await this.getState() + const { + apiConfiguration, + customSupportPrompts, + listApiConfigMeta, + enhancementApiConfigId, + } = await this.getState() // Try to get enhancement config first, fall back to current config let configToUse: ApiConfiguration = apiConfiguration @@ -1003,7 +1006,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { { userInput: message.text, }, - customPrompts, + customSupportPrompts, ), ) @@ -1024,7 +1027,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { try { const { apiConfiguration, - customPrompts, + customModePrompts, customInstructions, preferredLanguage, browserViewportSize, @@ -1054,7 +1057,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { diffStrategy, browserViewportSize ?? "900x600", mode, - customPrompts, + customModePrompts, customModes, customInstructions, preferredLanguage, @@ -1802,7 +1805,8 @@ export class ClineProvider implements vscode.WebviewViewProvider { currentApiConfigName, listApiConfigMeta, mode, - customPrompts, + customModePrompts, + customSupportPrompts, enhancementApiConfigId, experimentalDiffStrategy, autoApprovalEnabled, @@ -1841,7 +1845,8 @@ export class ClineProvider implements vscode.WebviewViewProvider { currentApiConfigName: currentApiConfigName ?? "default", listApiConfigMeta: listApiConfigMeta ?? [], mode: mode ?? defaultModeSlug, - customPrompts: customPrompts ?? {}, + customModePrompts: customModePrompts ?? {}, + customSupportPrompts: customSupportPrompts ?? {}, enhancementApiConfigId, experimentalDiffStrategy: experimentalDiffStrategy ?? false, autoApprovalEnabled: autoApprovalEnabled ?? false, @@ -1961,7 +1966,8 @@ export class ClineProvider implements vscode.WebviewViewProvider { vsCodeLmModelSelector, mode, modeApiConfigs, - customPrompts, + customModePrompts, + customSupportPrompts, enhancementApiConfigId, experimentalDiffStrategy, autoApprovalEnabled, @@ -2026,7 +2032,8 @@ export class ClineProvider implements vscode.WebviewViewProvider { this.getGlobalState("vsCodeLmModelSelector") as Promise, this.getGlobalState("mode") as Promise, this.getGlobalState("modeApiConfigs") as Promise | undefined>, - this.getGlobalState("customPrompts") as Promise, + this.getGlobalState("customModePrompts") as Promise, + this.getGlobalState("customSupportPrompts") as Promise, this.getGlobalState("enhancementApiConfigId") as Promise, this.getGlobalState("experimentalDiffStrategy") as Promise, this.getGlobalState("autoApprovalEnabled") as Promise, @@ -2137,7 +2144,8 @@ export class ClineProvider implements vscode.WebviewViewProvider { currentApiConfigName: currentApiConfigName ?? "default", listApiConfigMeta: listApiConfigMeta ?? [], modeApiConfigs: modeApiConfigs ?? ({} as Record), - customPrompts: customPrompts ?? {}, + customModePrompts: customModePrompts ?? {}, + customSupportPrompts: customSupportPrompts ?? {}, enhancementApiConfigId, experimentalDiffStrategy: experimentalDiffStrategy ?? false, autoApprovalEnabled: autoApprovalEnabled ?? false, diff --git a/src/core/webview/__tests__/ClineProvider.test.ts b/src/core/webview/__tests__/ClineProvider.test.ts index 63dc2d5..cd1f295 100644 --- a/src/core/webview/__tests__/ClineProvider.test.ts +++ b/src/core/webview/__tests__/ClineProvider.test.ts @@ -555,7 +555,7 @@ describe("ClineProvider", () => { architect: "existing architect prompt", } ;(mockContext.globalState.get as jest.Mock).mockImplementation((key: string) => { - if (key === "customPrompts") { + if (key === "customModePrompts") { return existingPrompts } return undefined @@ -569,7 +569,7 @@ describe("ClineProvider", () => { }) // Verify state was updated correctly - expect(mockContext.globalState.update).toHaveBeenCalledWith("customPrompts", { + expect(mockContext.globalState.update).toHaveBeenCalledWith("customModePrompts", { ...existingPrompts, code: "new code prompt", }) @@ -579,7 +579,7 @@ describe("ClineProvider", () => { expect.objectContaining({ type: "state", state: expect.objectContaining({ - customPrompts: { + customModePrompts: { ...existingPrompts, code: "new code prompt", }, @@ -588,17 +588,17 @@ describe("ClineProvider", () => { ) }) - test("customPrompts defaults to empty object", async () => { - // Mock globalState.get to return undefined for customPrompts + test("customModePrompts defaults to empty object", async () => { + // Mock globalState.get to return undefined for customModePrompts ;(mockContext.globalState.get as jest.Mock).mockImplementation((key: string) => { - if (key === "customPrompts") { + if (key === "customModePrompts") { return undefined } return null }) const state = await provider.getState() - expect(state.customPrompts).toEqual({}) + expect(state.customModePrompts).toEqual({}) }) test("uses mode-specific custom instructions in Cline initialization", async () => { @@ -611,7 +611,7 @@ describe("ClineProvider", () => { jest.spyOn(provider, "getState").mockResolvedValue({ apiConfiguration: mockApiConfig, - customPrompts: { + customModePrompts: { code: { customInstructions: modeCustomInstructions }, }, mode: "code", @@ -651,7 +651,7 @@ describe("ClineProvider", () => { }, } mockContext.globalState.get = jest.fn((key: string) => { - if (key === "customPrompts") { + if (key === "customModePrompts") { return existingPrompts } return undefined @@ -668,7 +668,7 @@ describe("ClineProvider", () => { }) // Verify state was updated correctly - expect(mockContext.globalState.update).toHaveBeenCalledWith("customPrompts", { + expect(mockContext.globalState.update).toHaveBeenCalledWith("customModePrompts", { code: { roleDefinition: "Code role", customInstructions: "New instructions", @@ -978,7 +978,7 @@ describe("ClineProvider", () => { apiModelId: "test-model", openRouterModelInfo: { supportsComputerUse: true }, }, - customPrompts: {}, + customModePrompts: {}, mode: "code", mcpEnabled: false, browserViewportSize: "900x600", @@ -1007,7 +1007,7 @@ describe("ClineProvider", () => { }), "900x600", // browserViewportSize "code", // mode - {}, // customPrompts + {}, // customModePrompts {}, // customModes undefined, // effectiveInstructions undefined, // preferredLanguage @@ -1027,7 +1027,7 @@ describe("ClineProvider", () => { apiModelId: "test-model", openRouterModelInfo: { supportsComputerUse: true }, }, - customPrompts: {}, + customModePrompts: {}, mode: "code", mcpEnabled: false, browserViewportSize: "900x600", @@ -1056,7 +1056,7 @@ describe("ClineProvider", () => { }), "900x600", // browserViewportSize "code", // mode - {}, // customPrompts + {}, // customModePrompts {}, // customModes undefined, // effectiveInstructions undefined, // preferredLanguage @@ -1071,7 +1071,7 @@ describe("ClineProvider", () => { apiProvider: "openrouter", openRouterModelInfo: { supportsComputerUse: true }, }, - customPrompts: { + customModePrompts: { architect: { customInstructions: "Architect mode instructions" }, }, mode: "architect", diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 3bcd8a0..ed5d78c 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -4,7 +4,8 @@ import { ApiConfiguration, ApiProvider, ModelInfo } from "./api" import { HistoryItem } from "./HistoryItem" import { McpServer } from "./mcp" import { GitCommit } from "../utils/git" -import { Mode, CustomPrompts, ModeConfig } from "./modes" +import { Mode, CustomModePrompts, ModeConfig } from "./modes" +import { CustomSupportPrompts } from "./support-prompt" export interface LanguageModelChatSelector { vendor?: string @@ -82,7 +83,8 @@ export interface ExtensionState { currentApiConfigName?: string listApiConfigMeta?: ApiConfigMeta[] customInstructions?: string - customPrompts?: CustomPrompts + customModePrompts?: CustomModePrompts + customSupportPrompts?: CustomSupportPrompts alwaysAllowReadOnly?: boolean alwaysAllowWrite?: boolean alwaysAllowExecute?: boolean diff --git a/src/shared/__tests__/support-prompts.test.ts b/src/shared/__tests__/support-prompts.test.ts index cd27a38..edee6c2 100644 --- a/src/shared/__tests__/support-prompts.test.ts +++ b/src/shared/__tests__/support-prompts.test.ts @@ -97,18 +97,18 @@ describe("Code Action Prompts", () => { it("should return custom template when provided", () => { const customTemplate = "Custom template for explaining code" - const customPrompts = { + const customSupportPrompts = { EXPLAIN: customTemplate, } - const template = supportPrompt.get(customPrompts, "EXPLAIN") + const template = supportPrompt.get(customSupportPrompts, "EXPLAIN") expect(template).toBe(customTemplate) }) it("should return default template when custom prompts does not include type", () => { - const customPrompts = { + const customSupportPrompts = { SOMETHING_ELSE: "Other template", } - const template = supportPrompt.get(customPrompts, "EXPLAIN") + const template = supportPrompt.get(customSupportPrompts, "EXPLAIN") expect(template).toBe(supportPrompt.default.EXPLAIN) }) }) @@ -116,7 +116,7 @@ describe("Code Action Prompts", () => { describe("create with custom prompts", () => { it("should use custom template when provided", () => { const customTemplate = "Custom template for ${filePath}" - const customPrompts = { + const customSupportPrompts = { EXPLAIN: customTemplate, } @@ -126,7 +126,7 @@ describe("Code Action Prompts", () => { filePath: testFilePath, selectedText: testCode, }, - customPrompts, + customSupportPrompts, ) expect(prompt).toContain(`Custom template for ${testFilePath}`) @@ -134,7 +134,7 @@ describe("Code Action Prompts", () => { }) it("should use default template when custom prompts does not include type", () => { - const customPrompts = { + const customSupportPrompts = { EXPLAIN: "Other template", } @@ -144,7 +144,7 @@ describe("Code Action Prompts", () => { filePath: testFilePath, selectedText: testCode, }, - customPrompts, + customSupportPrompts, ) expect(prompt).toContain("Other template") diff --git a/src/shared/modes.ts b/src/shared/modes.ts index 451e661..5b3358b 100644 --- a/src/shared/modes.ts +++ b/src/shared/modes.ts @@ -18,8 +18,8 @@ export type PromptComponent = { customInstructions?: string } -export type CustomPrompts = { - [key: string]: PromptComponent | undefined | string +export type CustomModePrompts = { + [key: string]: PromptComponent | undefined } // Helper to get all tools for a mode @@ -141,7 +141,7 @@ export function isToolAllowedForMode( } // Create the mode-specific default prompts -export const defaultPrompts: Readonly = Object.freeze( +export const defaultPrompts: Readonly = Object.freeze( Object.fromEntries(modes.map((mode) => [mode.slug, { roleDefinition: mode.roleDefinition }])), ) diff --git a/src/shared/support-prompt.ts b/src/shared/support-prompt.ts index 715d8c6..9f18b1a 100644 --- a/src/shared/support-prompt.ts +++ b/src/shared/support-prompt.ts @@ -84,11 +84,11 @@ type SupportPromptType = keyof typeof defaultTemplates export const supportPrompt = { default: defaultTemplates, - get: (customPrompts: Record | undefined, type: SupportPromptType): string => { - return customPrompts?.[type] ?? defaultTemplates[type] + get: (customSupportPrompts: Record | undefined, type: SupportPromptType): string => { + return customSupportPrompts?.[type] ?? defaultTemplates[type] }, - create: (type: SupportPromptType, params: PromptParams, customPrompts?: Record): string => { - const template = supportPrompt.get(customPrompts, type) + create: (type: SupportPromptType, params: PromptParams, customSupportPrompts?: Record): string => { + const template = supportPrompt.get(customSupportPrompts, type) return createPrompt(template, params) }, } as const @@ -102,3 +102,7 @@ export const supportPromptLabels: Record = { IMPROVE: "Improve Code", ENHANCE: "Enhance Prompt", } as const + +export type CustomSupportPrompts = { + [key: string]: string | undefined +} diff --git a/webview-ui/src/components/chat/__tests__/AutoApproveMenu.test.tsx b/webview-ui/src/components/chat/__tests__/AutoApproveMenu.test.tsx index 76ee929..510b5b2 100644 --- a/webview-ui/src/components/chat/__tests__/AutoApproveMenu.test.tsx +++ b/webview-ui/src/components/chat/__tests__/AutoApproveMenu.test.tsx @@ -1,7 +1,7 @@ import { render, fireEvent, screen } from "@testing-library/react" import { useExtensionState } from "../../../context/ExtensionStateContext" import AutoApproveMenu from "../AutoApproveMenu" -import { codeMode, defaultPrompts } from "../../../../../src/shared/modes" +import { defaultModeSlug, defaultPrompts } from "../../../../../src/shared/modes" // Mock the ExtensionStateContext hook jest.mock("../../../context/ExtensionStateContext") @@ -29,8 +29,9 @@ describe("AutoApproveMenu", () => { requestDelaySeconds: 5, currentApiConfigName: "default", listApiConfigMeta: [], - mode: codeMode, - customPrompts: defaultPrompts, + mode: defaultModeSlug, + customModePrompts: defaultPrompts, + customSupportPrompts: {}, enhancementApiConfigId: "", didHydrateState: true, showWelcome: false, diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index 6f5085a..c2f3cad 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -23,7 +23,8 @@ type PromptsViewProps = { const PromptsView = ({ onDone }: PromptsViewProps) => { const { - customPrompts, + customModePrompts, + customSupportPrompts, listApiConfigMeta, enhancementApiConfigId, setEnhancementApiConfigId, @@ -50,7 +51,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { // Direct update functions const updateAgentPrompt = useCallback( (mode: Mode, promptData: PromptComponent) => { - const existingPrompt = customPrompts?.[mode] as PromptComponent + const existingPrompt = customModePrompts?.[mode] as PromptComponent const updatedPrompt = { ...existingPrompt, ...promptData } // Only include properties that differ from defaults @@ -64,7 +65,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { customPrompt: updatedPrompt, }) }, - [customPrompts], + [customModePrompts], ) const updateCustomMode = useCallback((slug: string, modeConfig: ModeConfig) => { @@ -261,7 +262,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { const handleAgentReset = (modeSlug: string) => { // Only reset role definition for built-in modes - const existingPrompt = customPrompts?.[modeSlug] as PromptComponent + const existingPrompt = customModePrompts?.[modeSlug] as PromptComponent updateAgentPrompt(modeSlug, { ...existingPrompt, roleDefinition: undefined, @@ -276,7 +277,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { } const getSupportPromptValue = (type: SupportPromptType): string => { - return supportPrompt.get(customPrompts, type) + return supportPrompt.get(customSupportPrompts, type) } const handleTestEnhancement = () => { @@ -556,7 +557,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { { const customMode = findModeBySlug(mode, customModes) - const prompt = customPrompts?.[mode] as PromptComponent + const prompt = customModePrompts?.[mode] as PromptComponent return customMode?.roleDefinition ?? prompt?.roleDefinition ?? getRoleDefinition(mode) })()} onChange={(e) => { @@ -673,7 +674,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { { const customMode = findModeBySlug(mode, customModes) - const prompt = customPrompts?.[mode] as PromptComponent + const prompt = customModePrompts?.[mode] as PromptComponent return customMode?.customInstructions ?? prompt?.customInstructions ?? "" })()} onChange={(e) => { @@ -689,7 +690,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { }) } else { // For built-in modes, update the prompts - const existingPrompt = customPrompts?.[mode] as PromptComponent + const existingPrompt = customModePrompts?.[mode] as PromptComponent updateAgentPrompt(mode, { ...existingPrompt, customInstructions: value.trim() || undefined, diff --git a/webview-ui/src/components/prompts/__tests__/PromptsView.test.tsx b/webview-ui/src/components/prompts/__tests__/PromptsView.test.tsx index 93e8698..95437a4 100644 --- a/webview-ui/src/components/prompts/__tests__/PromptsView.test.tsx +++ b/webview-ui/src/components/prompts/__tests__/PromptsView.test.tsx @@ -12,7 +12,7 @@ jest.mock("../../../utils/vscode", () => ({ })) const mockExtensionState = { - customPrompts: {}, + customModePrompts: {}, listApiConfigMeta: [ { id: "config1", name: "Config 1" }, { id: "config2", name: "Config 2" }, diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index ea00a0c..2d9fda0 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -14,7 +14,8 @@ import { convertTextMateToHljs } from "../utils/textMateToHljs" import { findLastIndex } from "../../../src/shared/array" import { McpServer } from "../../../src/shared/mcp" import { checkExistKey } from "../../../src/shared/checkExistApiConfig" -import { Mode, CustomPrompts, defaultModeSlug, defaultPrompts, ModeConfig } from "../../../src/shared/modes" +import { Mode, CustomModePrompts, defaultModeSlug, defaultPrompts, ModeConfig } from "../../../src/shared/modes" +import { CustomSupportPrompts } from "../../../src/shared/support-prompt" export interface ExtensionStateContextType extends ExtensionState { didHydrateState: boolean @@ -57,7 +58,8 @@ export interface ExtensionStateContextType extends ExtensionState { onUpdateApiConfig: (apiConfig: ApiConfiguration) => void mode: Mode setMode: (value: Mode) => void - setCustomPrompts: (value: CustomPrompts) => void + setCustomModePrompts: (value: CustomModePrompts) => void + setCustomSupportPrompts: (value: CustomSupportPrompts) => void enhancementApiConfigId?: string setEnhancementApiConfigId: (value: string) => void experimentalDiffStrategy: boolean @@ -93,7 +95,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode currentApiConfigName: "default", listApiConfigMeta: [], mode: defaultModeSlug, - customPrompts: defaultPrompts, + customModePrompts: defaultPrompts, + customSupportPrompts: {}, enhancementApiConfigId: "", experimentalDiffStrategy: false, autoApprovalEnabled: false, @@ -270,7 +273,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setListApiConfigMeta, onUpdateApiConfig, setMode: (value: Mode) => setState((prevState) => ({ ...prevState, mode: value })), - setCustomPrompts: (value) => setState((prevState) => ({ ...prevState, customPrompts: value })), + setCustomModePrompts: (value) => setState((prevState) => ({ ...prevState, customModePrompts: value })), + setCustomSupportPrompts: (value) => setState((prevState) => ({ ...prevState, customSupportPrompts: value })), setEnhancementApiConfigId: (value) => setState((prevState) => ({ ...prevState, enhancementApiConfigId: value })), setExperimentalDiffStrategy: (value) =>