refactor: consolidate prompt functionality into support-prompt module

- Move code action prompts from core/prompts to shared/support-prompt
- Migrate enhance prompt functionality from modes to support-prompt
- Add UI for managing code action prompts in PromptsView
- Update types and interfaces for better prompt management
This commit is contained in:
sam hoang
2025-01-23 00:31:43 +07:00
parent 7845791720
commit 22907a0578
9 changed files with 467 additions and 268 deletions

View File

@@ -1,76 +0,0 @@
import { explainCodePrompt, fixCodePrompt, improveCodePrompt } from '../code-actions';
describe('Code Action Prompts', () => {
const testFilePath = 'test/file.ts';
const testCode = 'function test() { return true; }';
describe('explainCodePrompt', () => {
it('should format explain prompt correctly', () => {
const prompt = explainCodePrompt({
filePath: testFilePath,
selectedText: testCode
});
expect(prompt).toContain(`@/${testFilePath}`);
expect(prompt).toContain(testCode);
expect(prompt).toContain('purpose and functionality');
expect(prompt).toContain('Key components');
expect(prompt).toContain('Important patterns');
});
});
describe('fixCodePrompt', () => {
it('should format fix prompt without diagnostics', () => {
const prompt = fixCodePrompt({
filePath: testFilePath,
selectedText: testCode
});
expect(prompt).toContain(`@/${testFilePath}`);
expect(prompt).toContain(testCode);
expect(prompt).toContain('Address all detected problems');
expect(prompt).not.toContain('Current problems detected');
});
it('should format fix prompt with diagnostics', () => {
const diagnostics = [
{
source: 'eslint',
message: 'Missing semicolon',
code: 'semi'
},
{
message: 'Unused variable',
severity: 1
}
];
const prompt = fixCodePrompt({
filePath: testFilePath,
selectedText: testCode,
diagnostics
});
expect(prompt).toContain('Current problems detected:');
expect(prompt).toContain('[eslint] Missing semicolon (semi)');
expect(prompt).toContain('[Error] Unused variable');
expect(prompt).toContain(testCode);
});
});
describe('improveCodePrompt', () => {
it('should format improve prompt correctly', () => {
const prompt = improveCodePrompt({
filePath: testFilePath,
selectedText: testCode
});
expect(prompt).toContain(`@/${testFilePath}`);
expect(prompt).toContain(testCode);
expect(prompt).toContain('Code readability');
expect(prompt).toContain('Performance optimization');
expect(prompt).toContain('Best practices');
expect(prompt).toContain('Error handling');
});
});
});

View File

@@ -1,87 +0,0 @@
type PromptParams = Record<string, string | any[]>;
const generateDiagnosticText = (diagnostics?: any[]) => {
if (!diagnostics?.length) return '';
return `\nCurrent problems detected:\n${diagnostics.map(d =>
`- [${d.source || 'Error'}] ${d.message}${d.code ? ` (${d.code})` : ''}`
).join('\n')}`;
};
export const createPrompt = (template: string, params: PromptParams): string => {
let result = template;
for (const [key, value] of Object.entries(params)) {
if (key === 'diagnostics') {
result = result.replaceAll('${diagnosticText}', generateDiagnosticText(value as any[]));
} else {
result = result.replaceAll(`\${${key}}`, value as string);
}
}
// Replace any remaining user_input placeholders with empty string
result = result.replaceAll('${userInput}', '');
return result;
};
export const EXPLAIN_TEMPLATE = `
Explain the following code from file path @/\${filePath}:
\${userInput}
\`\`\`
\${selectedText}
\`\`\`
Please provide a clear and concise explanation of what this code does, including:
1. The purpose and functionality
2. Key components and their interactions
3. Important patterns or techniques used
`;
export const FIX_TEMPLATE = `
Fix any issues in the following code from file path @/\${filePath}
\${diagnosticText}
\${userInput}
\`\`\`
\${selectedText}
\`\`\`
Please:
1. Address all detected problems listed above (if any)
2. Identify any other potential bugs or issues
3. Provide corrected code
4. Explain what was fixed and why
`;
export const IMPROVE_TEMPLATE = `
Improve the following code from file path @/\${filePath}:
\${userInput}
\`\`\`
\${selectedText}
\`\`\`
Please suggest improvements for:
1. Code readability and maintainability
2. Performance optimization
3. Best practices and patterns
4. Error handling and edge cases
Provide the improved code along with explanations for each enhancement.
`;
export const explainCodePrompt = (params: PromptParams) =>
createPrompt(EXPLAIN_TEMPLATE, params);
export const fixCodePrompt = (params: PromptParams) =>
createPrompt(FIX_TEMPLATE, params);
export const improveCodePrompt = (params: PromptParams) =>
createPrompt(IMPROVE_TEMPLATE, params);
// Get template based on prompt type
export const defaultTemplates = {
'EXPLAIN': EXPLAIN_TEMPLATE,
'FIX': FIX_TEMPLATE,
'IMPROVE': IMPROVE_TEMPLATE
}

View File

@@ -1,4 +1,5 @@
import { Anthropic } from "@anthropic-ai/sdk" import { Anthropic } from "@anthropic-ai/sdk"
import delay from "delay"
import axios from "axios" import axios from "axios"
import fs from "fs/promises" import fs from "fs/promises"
import os from "os" import os from "os"
@@ -23,7 +24,6 @@ import {
modes, modes,
CustomPrompts, CustomPrompts,
PromptComponent, PromptComponent,
enhance,
ModeConfig, ModeConfig,
defaultModeSlug, defaultModeSlug,
getModeBySlug, getModeBySlug,
@@ -40,10 +40,7 @@ import { enhancePrompt } from "../../utils/enhance-prompt"
import { getCommitInfo, searchCommits, getWorkingState } from "../../utils/git" import { getCommitInfo, searchCommits, getWorkingState } from "../../utils/git"
import { ConfigManager } from "../config/ConfigManager" import { ConfigManager } from "../config/ConfigManager"
import { CustomModesManager } from "../config/CustomModesManager" import { CustomModesManager } from "../config/CustomModesManager"
import { import { enhance, codeActionPrompt } from "../../shared/support-prompt"
defaultTemplates,
createPrompt
} from "../prompts/code-actions"
import { ACTION_NAMES } from "../CodeActionProvider" import { ACTION_NAMES } from "../CodeActionProvider"
@@ -189,17 +186,27 @@ export class ClineProvider implements vscode.WebviewViewProvider {
public static async handleCodeAction( public static async handleCodeAction(
promptType: keyof typeof ACTION_NAMES, promptType: keyof typeof ACTION_NAMES,
params: Record<string, string | any[]> params: Record<string, string | any[]>,
): Promise<void> { ): Promise<void> {
const visibleProvider = ClineProvider.getVisibleInstance() let visibleProvider = ClineProvider.getVisibleInstance()
// If no visible provider, try to show the sidebar view
if (!visibleProvider) {
await vscode.commands.executeCommand("roo-cline.SidebarProvider.focus")
// Wait briefly for the view to become visible
await delay(100)
visibleProvider = ClineProvider.getVisibleInstance()
}
// If still no visible provider, return
if (!visibleProvider) { if (!visibleProvider) {
return return
} }
const { utilPrompt } = await visibleProvider.getState() const { customPrompts } = await visibleProvider.getState()
const prompt = codeActionPrompt.create(promptType, params, customPrompts)
const template = utilPrompt?.[promptType] ?? defaultTemplates[promptType]
const prompt = createPrompt(template, params)
await visibleProvider.initClineWithTask(prompt) await visibleProvider.initClineWithTask(prompt)
} }
@@ -297,7 +304,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
experimentalDiffStrategy, experimentalDiffStrategy,
} = await this.getState() } = await this.getState()
const modePrompt = customPrompts?.[mode] const modePrompt = customPrompts?.[mode] as PromptComponent
const effectiveInstructions = [globalInstructions, modePrompt?.customInstructions].filter(Boolean).join("\n\n") const effectiveInstructions = [globalInstructions, modePrompt?.customInstructions].filter(Boolean).join("\n\n")
this.cline = new Cline( this.cline = new Cline(
@@ -325,7 +332,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
experimentalDiffStrategy, experimentalDiffStrategy,
} = await this.getState() } = await this.getState()
const modePrompt = customPrompts?.[mode] const modePrompt = customPrompts?.[mode] as PromptComponent
const effectiveInstructions = [globalInstructions, modePrompt?.customInstructions].filter(Boolean).join("\n\n") const effectiveInstructions = [globalInstructions, modePrompt?.customInstructions].filter(Boolean).join("\n\n")
this.cline = new Cline( this.cline = new Cline(
@@ -804,29 +811,49 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.postStateToWebview() await this.postStateToWebview()
break break
case "updateEnhancedPrompt": case "updateSupportPrompt":
try {
if (Object.keys(message?.values ?? {}).length === 0) {
return
}
const existingPrompts = (await this.getGlobalState("customPrompts")) || {} const existingPrompts = (await this.getGlobalState("customPrompts")) || {}
const updatedPrompts = { const updatedPrompts = {
...existingPrompts, ...existingPrompts,
enhance: message.text, ...message.values,
} }
await this.updateGlobalState("customPrompts", updatedPrompts) await this.updateGlobalState("customPrompts", updatedPrompts)
await this.postStateToWebview()
// Get current state and explicitly include customPrompts } catch (error) {
const currentState = await this.getState() console.error("Error update support prompt:", error)
vscode.window.showErrorMessage("Failed to update support prompt")
const stateWithPrompts = { }
...currentState, break
customPrompts: updatedPrompts, case "resetSupportPrompt":
try {
if (!message?.text) {
return
} }
// Post state with prompts const existingPrompts = ((await this.getGlobalState("customPrompts")) || {}) as Record<
this.view?.webview.postMessage({ string,
type: "state", any
state: stateWithPrompts, >
})
const updatedPrompts = {
...existingPrompts,
}
updatedPrompts[message.text] = undefined
await this.updateGlobalState("customPrompts", updatedPrompts)
await this.postStateToWebview()
} catch (error) {
console.error("Error reset support prompt:", error)
vscode.window.showErrorMessage("Failed to reset support prompt")
}
break break
case "updatePrompt": case "updatePrompt":
if (message.promptMode && message.customPrompt !== undefined) { if (message.promptMode && message.customPrompt !== undefined) {

View File

@@ -6,7 +6,6 @@ import { ClineProvider } from "./core/webview/ClineProvider"
import { createClineAPI } from "./exports" import { createClineAPI } from "./exports"
import "./utils/path" // necessary to have access to String.prototype.toPosix import "./utils/path" // necessary to have access to String.prototype.toPosix
import { ACTION_NAMES, CodeActionProvider } from "./core/CodeActionProvider" import { ACTION_NAMES, CodeActionProvider } from "./core/CodeActionProvider"
import { explainCodePrompt, fixCodePrompt, improveCodePrompt } from "./core/prompts/code-actions"
import { DIFF_VIEW_URI_SCHEME } from "./integrations/editor/DiffViewProvider" import { DIFF_VIEW_URI_SCHEME } from "./integrations/editor/DiffViewProvider"
/* /*
@@ -162,14 +161,10 @@ export function activate(context: vscode.ExtensionContext) {
// Register code actions provider // Register code actions provider
context.subscriptions.push( context.subscriptions.push(
vscode.languages.registerCodeActionsProvider( vscode.languages.registerCodeActionsProvider({ pattern: "**/*" }, new CodeActionProvider(), {
{ pattern: "**/*" }, providedCodeActionKinds: CodeActionProvider.providedCodeActionKinds,
new CodeActionProvider(), }),
{
providedCodeActionKinds: CodeActionProvider.providedCodeActionKinds
}
) )
);
// Helper function to handle code actions // Helper function to handle code actions
const registerCodeAction = ( const registerCodeAction = (
@@ -177,51 +172,54 @@ export function activate(context: vscode.ExtensionContext) {
command: string, command: string,
promptType: keyof typeof ACTION_NAMES, promptType: keyof typeof ACTION_NAMES,
inputPrompt: string, inputPrompt: string,
inputPlaceholder: string inputPlaceholder: string,
) => { ) => {
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand(command, async (filePath: string, selectedText: string, diagnostics?: any[]) => { vscode.commands.registerCommand(
command,
async (filePath: string, selectedText: string, diagnostics?: any[]) => {
const userInput = await vscode.window.showInputBox({ const userInput = await vscode.window.showInputBox({
prompt: inputPrompt, prompt: inputPrompt,
placeHolder: inputPlaceholder placeHolder: inputPlaceholder,
}); })
const params = { const params = {
filePath, filePath,
selectedText, selectedText,
...(diagnostics ? { diagnostics } : {}), ...(diagnostics ? { diagnostics } : {}),
...(userInput ? { userInput } : {}) ...(userInput ? { userInput } : {}),
}; }
await ClineProvider.handleCodeAction(promptType, params); await ClineProvider.handleCodeAction(promptType, params)
}) },
); ),
}; )
}
// Register code action commands // Register code action commands
registerCodeAction( registerCodeAction(
context, context,
"roo-cline.explainCode", "roo-cline.explainCode",
'EXPLAIN', "EXPLAIN",
"Any specific questions about this code?", "Any specific questions about this code?",
"E.g. How does the error handling work?" "E.g. How does the error handling work?",
); )
registerCodeAction( registerCodeAction(
context, context,
"roo-cline.fixCode", "roo-cline.fixCode",
'FIX', "FIX",
"Any specific concerns about fixing this code?", "Any specific concerns about fixing this code?",
"E.g. Maintain backward compatibility" "E.g. Maintain backward compatibility",
); )
registerCodeAction( registerCodeAction(
context, context,
"roo-cline.improveCode", "roo-cline.improveCode",
'IMPROVE', "IMPROVE",
"Any specific aspects you want to improve?", "Any specific aspects you want to improve?",
"E.g. Focus on performance optimization" "E.g. Focus on performance optimization",
); )
return createClineAPI(outputChannel, sidebarProvider) return createClineAPI(outputChannel, sidebarProvider)
} }

View File

@@ -68,7 +68,8 @@ export interface WebviewMessage {
| "requestVsCodeLmModels" | "requestVsCodeLmModels"
| "mode" | "mode"
| "updatePrompt" | "updatePrompt"
| "updateEnhancedPrompt" | "updateSupportPrompt"
| "resetSupportPrompt"
| "getSystemPrompt" | "getSystemPrompt"
| "systemPrompt" | "systemPrompt"
| "enhancementApiConfigId" | "enhancementApiConfigId"

View File

@@ -0,0 +1,138 @@
import { codeActionPrompt, type CodeActionType } from "../support-prompt"
describe("Code Action Prompts", () => {
const testFilePath = "test/file.ts"
const testCode = "function test() { return true; }"
describe("EXPLAIN action", () => {
it("should format explain prompt correctly", () => {
const prompt = codeActionPrompt.create("EXPLAIN", {
filePath: testFilePath,
selectedText: testCode,
})
expect(prompt).toContain(`@/${testFilePath}`)
expect(prompt).toContain(testCode)
expect(prompt).toContain("purpose and functionality")
expect(prompt).toContain("Key components")
expect(prompt).toContain("Important patterns")
})
})
describe("FIX action", () => {
it("should format fix prompt without diagnostics", () => {
const prompt = codeActionPrompt.create("FIX", {
filePath: testFilePath,
selectedText: testCode,
})
expect(prompt).toContain(`@/${testFilePath}`)
expect(prompt).toContain(testCode)
expect(prompt).toContain("Address all detected problems")
expect(prompt).not.toContain("Current problems detected")
})
it("should format fix prompt with diagnostics", () => {
const diagnostics = [
{
source: "eslint",
message: "Missing semicolon",
code: "semi",
},
{
message: "Unused variable",
severity: 1,
},
]
const prompt = codeActionPrompt.create("FIX", {
filePath: testFilePath,
selectedText: testCode,
diagnostics,
})
expect(prompt).toContain("Current problems detected:")
expect(prompt).toContain("[eslint] Missing semicolon (semi)")
expect(prompt).toContain("[Error] Unused variable")
expect(prompt).toContain(testCode)
})
})
describe("IMPROVE action", () => {
it("should format improve prompt correctly", () => {
const prompt = codeActionPrompt.create("IMPROVE", {
filePath: testFilePath,
selectedText: testCode,
})
expect(prompt).toContain(`@/${testFilePath}`)
expect(prompt).toContain(testCode)
expect(prompt).toContain("Code readability")
expect(prompt).toContain("Performance optimization")
expect(prompt).toContain("Best practices")
expect(prompt).toContain("Error handling")
})
})
describe("get template", () => {
it("should return default template when no custom prompts provided", () => {
const template = codeActionPrompt.get(undefined, "EXPLAIN")
expect(template).toBe(codeActionPrompt.default.EXPLAIN)
})
it("should return custom template when provided", () => {
const customTemplate = "Custom template for explaining code"
const customPrompts = {
EXPLAIN: customTemplate,
}
const template = codeActionPrompt.get(customPrompts, "EXPLAIN")
expect(template).toBe(customTemplate)
})
it("should return default template when custom prompts does not include type", () => {
const customPrompts = {
SOMETHING_ELSE: "Other template",
}
const template = codeActionPrompt.get(customPrompts, "EXPLAIN")
expect(template).toBe(codeActionPrompt.default.EXPLAIN)
})
})
describe("create with custom prompts", () => {
it("should use custom template when provided", () => {
const customTemplate = "Custom template for ${filePath}"
const customPrompts = {
EXPLAIN: customTemplate,
}
const prompt = codeActionPrompt.create(
"EXPLAIN",
{
filePath: testFilePath,
selectedText: testCode,
},
customPrompts,
)
expect(prompt).toContain(`Custom template for ${testFilePath}`)
expect(prompt).not.toContain("purpose and functionality")
})
it("should use default template when custom prompts does not include type", () => {
const customPrompts = {
EXPLAIN: "Other template",
}
const prompt = codeActionPrompt.create(
"EXPLAIN",
{
filePath: testFilePath,
selectedText: testCode,
},
customPrompts,
)
expect(prompt).toContain("Other template")
})
})
})

View File

@@ -12,6 +12,16 @@ export type ModeConfig = {
groups: readonly ToolGroup[] // Now uses groups instead of tools array groups: readonly ToolGroup[] // Now uses groups instead of tools array
} }
// Mode-specific prompts only
export type PromptComponent = {
roleDefinition?: string
customInstructions?: string
}
export type CustomPrompts = {
[key: string]: PromptComponent | undefined | string
}
// Helper to get all tools for a mode // Helper to get all tools for a mode
export function getToolsForMode(groups: readonly ToolGroup[]): string[] { export function getToolsForMode(groups: readonly ToolGroup[]): string[] {
const tools = new Set<string>() const tools = new Set<string>()
@@ -130,33 +140,6 @@ export function isToolAllowedForMode(
return mode.groups.some((group) => TOOL_GROUPS[group].includes(tool as string)) return mode.groups.some((group) => TOOL_GROUPS[group].includes(tool as string))
} }
export type PromptComponent = {
roleDefinition?: string
customInstructions?: string
}
// Mode-specific prompts only
export type CustomPrompts = {
[key: string]: PromptComponent | undefined
}
// Separate enhance prompt type and definition
export type EnhanceConfig = {
prompt: string
}
export const enhance: EnhanceConfig = {
prompt: "Generate an enhanced version of this prompt (reply with only the enhanced prompt - no conversation, explanations, lead-in, bullet points, placeholders, or surrounding quotes):",
} as const
// Completely separate enhance prompt handling
export const enhancePrompt = {
default: enhance.prompt,
get: (customPrompts: Record<string, any> | undefined): string => {
return customPrompts?.enhance ?? enhance.prompt
},
} as const
// Create the mode-specific default prompts // Create the mode-specific default prompts
export const defaultPrompts: Readonly<CustomPrompts> = Object.freeze( export const defaultPrompts: Readonly<CustomPrompts> = Object.freeze(
Object.fromEntries(modes.map((mode) => [mode.slug, { roleDefinition: mode.roleDefinition }])), Object.fromEntries(modes.map((mode) => [mode.slug, { roleDefinition: mode.roleDefinition }])),

View File

@@ -0,0 +1,118 @@
// Separate enhance prompt type and definition
export type EnhanceConfig = {
prompt: string
}
export const enhance: EnhanceConfig = {
prompt: "Generate an enhanced version of this prompt (reply with only the enhanced prompt - no conversation, explanations, lead-in, bullet points, placeholders, or surrounding quotes):",
} as const
// Completely separate enhance prompt handling
export const enhancePrompt = {
default: enhance.prompt,
get: (customPrompts: Record<string, any> | undefined): string => {
return customPrompts?.enhance ?? enhance.prompt
},
} as const
// Code action prompts
type PromptParams = Record<string, string | any[]>
const generateDiagnosticText = (diagnostics?: any[]) => {
if (!diagnostics?.length) return ""
return `\nCurrent problems detected:\n${diagnostics
.map((d) => `- [${d.source || "Error"}] ${d.message}${d.code ? ` (${d.code})` : ""}`)
.join("\n")}`
}
export const createPrompt = (template: string, params: PromptParams): string => {
let result = template
for (const [key, value] of Object.entries(params)) {
if (key === "diagnostics") {
result = result.replaceAll("${diagnosticText}", generateDiagnosticText(value as any[]))
} else {
result = result.replaceAll(`\${${key}}`, value as string)
}
}
// Replace any remaining user_input placeholders with empty string
result = result.replaceAll("${userInput}", "")
return result
}
const EXPLAIN_TEMPLATE = `
Explain the following code from file path @/\${filePath}:
\${userInput}
\`\`\`
\${selectedText}
\`\`\`
Please provide a clear and concise explanation of what this code does, including:
1. The purpose and functionality
2. Key components and their interactions
3. Important patterns or techniques used
`
const FIX_TEMPLATE = `
Fix any issues in the following code from file path @/\${filePath}
\${diagnosticText}
\${userInput}
\`\`\`
\${selectedText}
\`\`\`
Please:
1. Address all detected problems listed above (if any)
2. Identify any other potential bugs or issues
3. Provide corrected code
4. Explain what was fixed and why
`
const IMPROVE_TEMPLATE = `
Improve the following code from file path @/\${filePath}:
\${userInput}
\`\`\`
\${selectedText}
\`\`\`
Please suggest improvements for:
1. Code readability and maintainability
2. Performance optimization
3. Best practices and patterns
4. Error handling and edge cases
Provide the improved code along with explanations for each enhancement.
`
// Get template based on prompt type
const defaultTemplates = {
EXPLAIN: EXPLAIN_TEMPLATE,
FIX: FIX_TEMPLATE,
IMPROVE: IMPROVE_TEMPLATE,
} as const
type CodeActionType = keyof typeof defaultTemplates
export const codeActionPrompt = {
default: defaultTemplates,
get: (customPrompts: Record<string, any> | undefined, type: CodeActionType): string => {
return customPrompts?.[type] ?? defaultTemplates[type]
},
create: (type: CodeActionType, params: PromptParams, customPrompts?: Record<string, any>): string => {
const template = codeActionPrompt.get(customPrompts, type)
return createPrompt(template, params)
},
} as const
export type { CodeActionType }
// User-friendly labels for code action types
export const codeActionLabels: Record<CodeActionType, string> = {
FIX: "Fix Issues",
EXPLAIN: "Explain Code",
IMPROVE: "Improve Code",
} as const

View File

@@ -8,14 +8,14 @@ import {
VSCodeCheckbox, VSCodeCheckbox,
} from "@vscode/webview-ui-toolkit/react" } from "@vscode/webview-ui-toolkit/react"
import { useExtensionState } from "../../context/ExtensionStateContext" import { useExtensionState } from "../../context/ExtensionStateContext"
import { Mode, PromptComponent, getRoleDefinition, getAllModes, ModeConfig } from "../../../../src/shared/modes"
import { import {
Mode,
PromptComponent,
getRoleDefinition,
getAllModes,
ModeConfig,
enhancePrompt, enhancePrompt,
} from "../../../../src/shared/modes" codeActionPrompt,
CodeActionType,
codeActionLabels,
} from "../../../../src/shared/support-prompt"
import { TOOL_GROUPS, GROUP_DISPLAY_NAMES, ToolGroup } from "../../../../src/shared/tool-groups" import { TOOL_GROUPS, GROUP_DISPLAY_NAMES, ToolGroup } from "../../../../src/shared/tool-groups"
import { vscode } from "../../utils/vscode" import { vscode } from "../../utils/vscode"
@@ -50,11 +50,12 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
const [selectedPromptTitle, setSelectedPromptTitle] = useState("") const [selectedPromptTitle, setSelectedPromptTitle] = useState("")
const [isToolsEditMode, setIsToolsEditMode] = useState(false) const [isToolsEditMode, setIsToolsEditMode] = useState(false)
const [isCreateModeDialogOpen, setIsCreateModeDialogOpen] = useState(false) const [isCreateModeDialogOpen, setIsCreateModeDialogOpen] = useState(false)
const [activeCodeActionTab, setActiveCodeActionTab] = useState<CodeActionType>("FIX")
// Direct update functions // Direct update functions
const updateAgentPrompt = useCallback( const updateAgentPrompt = useCallback(
(mode: Mode, promptData: PromptComponent) => { (mode: Mode, promptData: PromptComponent) => {
const existingPrompt = customPrompts?.[mode] const existingPrompt = customPrompts?.[mode] as PromptComponent
const updatedPrompt = { ...existingPrompt, ...promptData } const updatedPrompt = { ...existingPrompt, ...promptData }
// Only include properties that differ from defaults // Only include properties that differ from defaults
@@ -256,8 +257,19 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
const updateEnhancePrompt = (value: string | undefined) => { const updateEnhancePrompt = (value: string | undefined) => {
vscode.postMessage({ vscode.postMessage({
type: "updateEnhancedPrompt", type: "updateSupportPrompt",
text: value, values: {
enhance: value,
},
})
}
const updateCodeActionPrompt = (type: CodeActionType, value: string | undefined) => {
vscode.postMessage({
type: "updateSupportPrompt",
values: {
[type]: value,
},
}) })
} }
@@ -271,7 +283,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
const handleAgentReset = (modeSlug: string) => { const handleAgentReset = (modeSlug: string) => {
// Only reset role definition for built-in modes // Only reset role definition for built-in modes
const existingPrompt = customPrompts?.[modeSlug] const existingPrompt = customPrompts?.[modeSlug] as PromptComponent
updateAgentPrompt(modeSlug, { updateAgentPrompt(modeSlug, {
...existingPrompt, ...existingPrompt,
roleDefinition: undefined, roleDefinition: undefined,
@@ -279,13 +291,27 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
} }
const handleEnhanceReset = () => { const handleEnhanceReset = () => {
updateEnhancePrompt(undefined) vscode.postMessage({
type: "resetSupportPrompt",
text: "enhance",
})
}
const handleCodeActionReset = (type: CodeActionType) => {
vscode.postMessage({
type: "resetSupportPrompt",
text: type,
})
} }
const getEnhancePromptValue = (): string => { const getEnhancePromptValue = (): string => {
return enhancePrompt.get(customPrompts) return enhancePrompt.get(customPrompts)
} }
const getCodeActionPromptValue = (type: CodeActionType): string => {
return codeActionPrompt.get(customPrompts, type)
}
const handleTestEnhancement = () => { const handleTestEnhancement = () => {
if (!testPrompt.trim()) return if (!testPrompt.trim()) return
@@ -563,7 +589,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
<VSCodeTextArea <VSCodeTextArea
value={(() => { value={(() => {
const customMode = findModeBySlug(mode, customModes) const customMode = findModeBySlug(mode, customModes)
const prompt = customPrompts?.[mode] const prompt = customPrompts?.[mode] as PromptComponent
return customMode?.roleDefinition ?? prompt?.roleDefinition ?? getRoleDefinition(mode) return customMode?.roleDefinition ?? prompt?.roleDefinition ?? getRoleDefinition(mode)
})()} })()}
onChange={(e) => { onChange={(e) => {
@@ -680,7 +706,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
<VSCodeTextArea <VSCodeTextArea
value={(() => { value={(() => {
const customMode = findModeBySlug(mode, customModes) const customMode = findModeBySlug(mode, customModes)
const prompt = customPrompts?.[mode] const prompt = customPrompts?.[mode] as PromptComponent
return customMode?.customInstructions ?? prompt?.customInstructions ?? "" return customMode?.customInstructions ?? prompt?.customInstructions ?? ""
})()} })()}
onChange={(e) => { onChange={(e) => {
@@ -696,7 +722,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
}) })
} else { } else {
// For built-in modes, update the prompts // For built-in modes, update the prompts
const existingPrompt = customPrompts?.[mode] const existingPrompt = customPrompts?.[mode] as PromptComponent
updateAgentPrompt(mode, { updateAgentPrompt(mode, {
...existingPrompt, ...existingPrompt,
customInstructions: value.trim() || undefined, customInstructions: value.trim() || undefined,
@@ -759,6 +785,77 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
</VSCodeButton> </VSCodeButton>
</div> </div>
<div style={{ marginBottom: "20px" }}>
<div style={{ fontWeight: "bold", marginBottom: "12px" }}>Code Action Prompts</div>
<div
style={{
display: "flex",
gap: "16px",
alignItems: "center",
marginBottom: "12px",
overflowX: "auto",
flexWrap: "nowrap",
paddingBottom: "4px",
paddingRight: "20px",
}}>
{Object.keys(codeActionPrompt.default).map((type) => (
<button
key={type}
data-testid={`${type}-tab`}
data-active={activeCodeActionTab === type ? "true" : "false"}
onClick={() => setActiveCodeActionTab(type as CodeActionType)}
style={{
padding: "4px 8px",
border: "none",
background:
activeCodeActionTab === type ? "var(--vscode-button-background)" : "none",
color:
activeCodeActionTab === type
? "var(--vscode-button-foreground)"
: "var(--vscode-foreground)",
cursor: "pointer",
opacity: activeCodeActionTab === type ? 1 : 0.8,
borderRadius: "3px",
fontWeight: "bold",
}}>
{codeActionLabels[type as CodeActionType]}
</button>
))}
</div>
{/* Show active tab content */}
<div key={activeCodeActionTab}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: "4px",
}}>
<div style={{ fontWeight: "bold" }}>{activeCodeActionTab} Prompt</div>
<VSCodeButton
appearance="icon"
onClick={() => handleCodeActionReset(activeCodeActionTab)}
title={`Reset ${activeCodeActionTab} prompt to default`}>
<span className="codicon codicon-discard"></span>
</VSCodeButton>
</div>
<VSCodeTextArea
value={getCodeActionPromptValue(activeCodeActionTab)}
onChange={(e) => {
const value =
(e as CustomEvent)?.detail?.target?.value ||
((e as any).target as HTMLTextAreaElement).value
const trimmedValue = value.trim()
updateCodeActionPrompt(activeCodeActionTab, trimmedValue || undefined)
}}
rows={4}
resize="vertical"
style={{ width: "100%" }}
/>
</div>
</div>
<h3 style={{ color: "var(--vscode-foreground)", margin: "40px 0 20px 0" }}>Prompt Enhancement</h3> <h3 style={{ color: "var(--vscode-foreground)", margin: "40px 0 20px 0" }}>Prompt Enhancement</h3>
<div <div