refactor: consolidate code action and enhance prompts into unified support prompts system

- Rename codeActionPrompt to supportPrompt for better clarity
- Move enhance prompt functionality into support prompts system
- Add ENHANCE tab alongside other support prompt types
- Update UI to show enhancement configuration in ENHANCE tab
- Update tests to reflect new unified structure

This change simplifies the prompt system by treating enhancement as another type of support prompt rather than a separate system.
This commit is contained in:
sam hoang
2025-01-23 10:46:04 +07:00
parent 22907a0578
commit 55a5a97d8b
5 changed files with 140 additions and 213 deletions

View File

@@ -40,7 +40,7 @@ import { enhancePrompt } from "../../utils/enhance-prompt"
import { getCommitInfo, searchCommits, getWorkingState } from "../../utils/git"
import { ConfigManager } from "../config/ConfigManager"
import { CustomModesManager } from "../config/CustomModesManager"
import { enhance, codeActionPrompt } from "../../shared/support-prompt"
import { supportPrompt } from "../../shared/support-prompt"
import { ACTION_NAMES } from "../CodeActionProvider"
@@ -205,7 +205,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
const { customPrompts } = await visibleProvider.getState()
const prompt = codeActionPrompt.create(promptType, params, customPrompts)
const prompt = supportPrompt.create(promptType, params, customPrompts)
await visibleProvider.initClineWithTask(prompt)
}
@@ -996,16 +996,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
}
}
const getEnhancePrompt = (value: string | PromptComponent | undefined): string => {
if (typeof value === "string") {
return value
}
return enhance.prompt // Use the constant from modes.ts which we know is a string
}
const enhancedPrompt = await enhancePrompt(
configToUse,
message.text,
getEnhancePrompt(customPrompts?.enhance),
supportPrompt.get(customPrompts, "ENHANCE"),
)
await this.postMessageToWebview({
type: "enhancedPrompt",

View File

@@ -1,4 +1,4 @@
import { codeActionPrompt, type CodeActionType } from "../support-prompt"
import { supportPrompt } from "../support-prompt"
describe("Code Action Prompts", () => {
const testFilePath = "test/file.ts"
@@ -6,7 +6,7 @@ describe("Code Action Prompts", () => {
describe("EXPLAIN action", () => {
it("should format explain prompt correctly", () => {
const prompt = codeActionPrompt.create("EXPLAIN", {
const prompt = supportPrompt.create("EXPLAIN", {
filePath: testFilePath,
selectedText: testCode,
})
@@ -21,7 +21,7 @@ describe("Code Action Prompts", () => {
describe("FIX action", () => {
it("should format fix prompt without diagnostics", () => {
const prompt = codeActionPrompt.create("FIX", {
const prompt = supportPrompt.create("FIX", {
filePath: testFilePath,
selectedText: testCode,
})
@@ -45,7 +45,7 @@ describe("Code Action Prompts", () => {
},
]
const prompt = codeActionPrompt.create("FIX", {
const prompt = supportPrompt.create("FIX", {
filePath: testFilePath,
selectedText: testCode,
diagnostics,
@@ -60,7 +60,7 @@ describe("Code Action Prompts", () => {
describe("IMPROVE action", () => {
it("should format improve prompt correctly", () => {
const prompt = codeActionPrompt.create("IMPROVE", {
const prompt = supportPrompt.create("IMPROVE", {
filePath: testFilePath,
selectedText: testCode,
})
@@ -74,10 +74,26 @@ describe("Code Action Prompts", () => {
})
})
describe("ENHANCE action", () => {
it("should format enhance prompt correctly", () => {
const prompt = supportPrompt.create("ENHANCE", {
filePath: testFilePath,
selectedText: testCode,
})
expect(prompt).toBe(
"Generate an enhanced version of this prompt (reply with only the enhanced prompt - no conversation, explanations, lead-in, bullet points, placeholders, or surrounding quotes):",
)
// Verify it ignores parameters since ENHANCE template doesn't use any
expect(prompt).not.toContain(testFilePath)
expect(prompt).not.toContain(testCode)
})
})
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)
const template = supportPrompt.get(undefined, "EXPLAIN")
expect(template).toBe(supportPrompt.default.EXPLAIN)
})
it("should return custom template when provided", () => {
@@ -85,7 +101,7 @@ describe("Code Action Prompts", () => {
const customPrompts = {
EXPLAIN: customTemplate,
}
const template = codeActionPrompt.get(customPrompts, "EXPLAIN")
const template = supportPrompt.get(customPrompts, "EXPLAIN")
expect(template).toBe(customTemplate)
})
@@ -93,8 +109,8 @@ describe("Code Action Prompts", () => {
const customPrompts = {
SOMETHING_ELSE: "Other template",
}
const template = codeActionPrompt.get(customPrompts, "EXPLAIN")
expect(template).toBe(codeActionPrompt.default.EXPLAIN)
const template = supportPrompt.get(customPrompts, "EXPLAIN")
expect(template).toBe(supportPrompt.default.EXPLAIN)
})
})
@@ -105,7 +121,7 @@ describe("Code Action Prompts", () => {
EXPLAIN: customTemplate,
}
const prompt = codeActionPrompt.create(
const prompt = supportPrompt.create(
"EXPLAIN",
{
filePath: testFilePath,
@@ -123,7 +139,7 @@ describe("Code Action Prompts", () => {
EXPLAIN: "Other template",
}
const prompt = codeActionPrompt.create(
const prompt = supportPrompt.create(
"EXPLAIN",
{
filePath: testFilePath,

View File

@@ -1,21 +1,4 @@
// 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
// Support prompts
type PromptParams = Record<string, string | any[]>
const generateDiagnosticText = (diagnostics?: any[]) => {
@@ -41,8 +24,7 @@ export const createPrompt = (template: string, params: PromptParams): string =>
return result
}
const EXPLAIN_TEMPLATE = `
Explain the following code from file path @/\${filePath}:
const EXPLAIN_TEMPLATE = `Explain the following code from file path @/\${filePath}:
\${userInput}
\`\`\`
@@ -55,8 +37,7 @@ Please provide a clear and concise explanation of what this code does, including
3. Important patterns or techniques used
`
const FIX_TEMPLATE = `
Fix any issues in the following code from file path @/\${filePath}
const FIX_TEMPLATE = `Fix any issues in the following code from file path @/\${filePath}
\${diagnosticText}
\${userInput}
@@ -71,8 +52,7 @@ Please:
4. Explain what was fixed and why
`
const IMPROVE_TEMPLATE = `
Improve the following code from file path @/\${filePath}:
const IMPROVE_TEMPLATE = `Improve the following code from file path @/\${filePath}:
\${userInput}
\`\`\`
@@ -88,31 +68,36 @@ Please suggest improvements for:
Provide the improved code along with explanations for each enhancement.
`
const ENHANCE_TEMPLATE =
"Generate an enhanced version of this prompt (reply with only the enhanced prompt - no conversation, explanations, lead-in, bullet points, placeholders, or surrounding quotes):"
// Get template based on prompt type
const defaultTemplates = {
EXPLAIN: EXPLAIN_TEMPLATE,
FIX: FIX_TEMPLATE,
IMPROVE: IMPROVE_TEMPLATE,
ENHANCE: ENHANCE_TEMPLATE,
} as const
type CodeActionType = keyof typeof defaultTemplates
type SupportPromptType = keyof typeof defaultTemplates
export const codeActionPrompt = {
export const supportPrompt = {
default: defaultTemplates,
get: (customPrompts: Record<string, any> | undefined, type: CodeActionType): string => {
get: (customPrompts: Record<string, any> | undefined, type: SupportPromptType): string => {
return customPrompts?.[type] ?? defaultTemplates[type]
},
create: (type: CodeActionType, params: PromptParams, customPrompts?: Record<string, any>): string => {
const template = codeActionPrompt.get(customPrompts, type)
create: (type: SupportPromptType, params: PromptParams, customPrompts?: Record<string, any>): string => {
const template = supportPrompt.get(customPrompts, type)
return createPrompt(template, params)
},
} as const
export type { CodeActionType }
export type { SupportPromptType }
// User-friendly labels for code action types
export const codeActionLabels: Record<CodeActionType, string> = {
// User-friendly labels for support prompt types
export const supportPromptLabels: Record<SupportPromptType, string> = {
FIX: "Fix Issues",
EXPLAIN: "Explain Code",
IMPROVE: "Improve Code",
ENHANCE: "Enhance Prompt",
} as const

View File

@@ -9,12 +9,7 @@ import {
} from "@vscode/webview-ui-toolkit/react"
import { useExtensionState } from "../../context/ExtensionStateContext"
import { Mode, PromptComponent, getRoleDefinition, getAllModes, ModeConfig } from "../../../../src/shared/modes"
import {
enhancePrompt,
codeActionPrompt,
CodeActionType,
codeActionLabels,
} from "../../../../src/shared/support-prompt"
import { supportPrompt, SupportPromptType, supportPromptLabels } from "../../../../src/shared/support-prompt"
import { TOOL_GROUPS, GROUP_DISPLAY_NAMES, ToolGroup } from "../../../../src/shared/tool-groups"
import { vscode } from "../../utils/vscode"
@@ -50,7 +45,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
const [selectedPromptTitle, setSelectedPromptTitle] = useState("")
const [isToolsEditMode, setIsToolsEditMode] = useState(false)
const [isCreateModeDialogOpen, setIsCreateModeDialogOpen] = useState(false)
const [activeCodeActionTab, setActiveCodeActionTab] = useState<CodeActionType>("FIX")
const [activeSupportTab, setActiveSupportTab] = useState<SupportPromptType>("EXPLAIN")
// Direct update functions
const updateAgentPrompt = useCallback(
@@ -255,16 +250,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
return () => window.removeEventListener("message", handler)
}, [])
const updateEnhancePrompt = (value: string | undefined) => {
vscode.postMessage({
type: "updateSupportPrompt",
values: {
enhance: value,
},
})
}
const updateCodeActionPrompt = (type: CodeActionType, value: string | undefined) => {
const updateSupportPrompt = (type: SupportPromptType, value: string | undefined) => {
vscode.postMessage({
type: "updateSupportPrompt",
values: {
@@ -273,14 +259,6 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
})
}
const handleEnhancePromptChange = (e: Event | React.FormEvent<HTMLElement>): void => {
const value = (e as CustomEvent)?.detail?.target?.value || ((e as any).target as HTMLTextAreaElement).value
const trimmedValue = value.trim()
if (trimmedValue !== enhancePrompt.default) {
updateEnhancePrompt(trimmedValue || enhancePrompt.default)
}
}
const handleAgentReset = (modeSlug: string) => {
// Only reset role definition for built-in modes
const existingPrompt = customPrompts?.[modeSlug] as PromptComponent
@@ -290,26 +268,15 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
})
}
const handleEnhanceReset = () => {
vscode.postMessage({
type: "resetSupportPrompt",
text: "enhance",
})
}
const handleCodeActionReset = (type: CodeActionType) => {
const handleSupportReset = (type: SupportPromptType) => {
vscode.postMessage({
type: "resetSupportPrompt",
text: type,
})
}
const getEnhancePromptValue = (): string => {
return enhancePrompt.get(customPrompts)
}
const getCodeActionPromptValue = (type: CodeActionType): string => {
return codeActionPrompt.get(customPrompts, type)
const getSupportPromptValue = (type: SupportPromptType): string => {
return supportPrompt.get(customPrompts, type)
}
const handleTestEnhancement = () => {
@@ -786,7 +753,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
</div>
<div style={{ marginBottom: "20px" }}>
<div style={{ fontWeight: "bold", marginBottom: "12px" }}>Code Action Prompts</div>
<div style={{ fontWeight: "bold", marginBottom: "12px" }}>Support Prompts</div>
<div
style={{
display: "flex",
@@ -798,33 +765,32 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
paddingBottom: "4px",
paddingRight: "20px",
}}>
{Object.keys(codeActionPrompt.default).map((type) => (
{Object.keys(supportPrompt.default).map((type) => (
<button
key={type}
data-testid={`${type}-tab`}
data-active={activeCodeActionTab === type ? "true" : "false"}
onClick={() => setActiveCodeActionTab(type as CodeActionType)}
data-active={activeSupportTab === type ? "true" : "false"}
onClick={() => setActiveSupportTab(type as SupportPromptType)}
style={{
padding: "4px 8px",
border: "none",
background:
activeCodeActionTab === type ? "var(--vscode-button-background)" : "none",
background: activeSupportTab === type ? "var(--vscode-button-background)" : "none",
color:
activeCodeActionTab === type
activeSupportTab === type
? "var(--vscode-button-foreground)"
: "var(--vscode-foreground)",
cursor: "pointer",
opacity: activeCodeActionTab === type ? 1 : 0.8,
opacity: activeSupportTab === type ? 1 : 0.8,
borderRadius: "3px",
fontWeight: "bold",
}}>
{codeActionLabels[type as CodeActionType]}
{supportPromptLabels[type as SupportPromptType]}
</button>
))}
</div>
{/* Show active tab content */}
<div key={activeCodeActionTab}>
<div key={activeSupportTab}>
<div
style={{
display: "flex",
@@ -832,32 +798,17 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
alignItems: "center",
marginBottom: "4px",
}}>
<div style={{ fontWeight: "bold" }}>{activeCodeActionTab} Prompt</div>
<div style={{ fontWeight: "bold" }}>{activeSupportTab} Prompt</div>
<VSCodeButton
appearance="icon"
onClick={() => handleCodeActionReset(activeCodeActionTab)}
title={`Reset ${activeCodeActionTab} prompt to default`}>
onClick={() => handleSupportReset(activeSupportTab)}
title={`Reset ${activeSupportTab} 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>
{activeSupportTab === "ENHANCE" && (
<div>
<div
style={{
color: "var(--vscode-foreground)",
@@ -865,18 +816,15 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
marginBottom: "20px",
marginTop: "5px",
}}>
Use prompt enhancement to get tailored suggestions or improvements for your inputs. This ensures Roo
understands your intent and provides the best possible responses.
Use prompt enhancement to get tailored suggestions or improvements for your inputs.
This ensures Roo understands your intent and provides the best possible responses.
</div>
<div style={{ display: "flex", flexDirection: "column", gap: "20px" }}>
<div>
<div style={{ marginBottom: "12px" }}>
<div style={{ marginBottom: "8px" }}>
<div style={{ fontWeight: "bold", marginBottom: "4px" }}>API Configuration</div>
<div style={{ fontSize: "13px", color: "var(--vscode-descriptionForeground)" }}>
You can select an API configuration to always use for enhancing prompts, or just use
whatever is currently selected
You can select an API configuration to always use for enhancing prompts, or
just use whatever is currently selected
</div>
</div>
<VSCodeDropdown
@@ -899,42 +847,24 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
))}
</VSCodeDropdown>
</div>
</div>
)}
<div style={{ marginBottom: "8px" }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginBottom: "4px",
}}>
<div style={{ fontWeight: "bold" }}>Enhancement Prompt</div>
<div style={{ display: "flex", gap: "8px" }}>
<VSCodeButton
appearance="icon"
onClick={handleEnhanceReset}
title="Revert to default">
<span className="codicon codicon-discard"></span>
</VSCodeButton>
</div>
</div>
<div
style={{
fontSize: "13px",
color: "var(--vscode-descriptionForeground)",
marginBottom: "8px",
}}>
This prompt will be used to refine your input when you hit the sparkle icon in chat.
</div>
</div>
<VSCodeTextArea
value={getEnhancePromptValue()}
onChange={handleEnhancePromptChange}
value={getSupportPromptValue(activeSupportTab)}
onChange={(e) => {
const value =
(e as CustomEvent)?.detail?.target?.value ||
((e as any).target as HTMLTextAreaElement).value
const trimmedValue = value.trim()
updateSupportPrompt(activeSupportTab, trimmedValue || undefined)
}}
rows={4}
resize="vertical"
style={{ width: "100%" }}
/>
{activeSupportTab === "ENHANCE" && (
<div style={{ marginTop: "12px" }}>
<VSCodeTextArea
value={testPrompt}
@@ -961,11 +891,9 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
</VSCodeButton>
</div>
</div>
)}
</div>
</div>
{/* Bottom padding */}
<div style={{ height: "20px" }} />
</div>
{isCreateModeDialogOpen && (

View File

@@ -166,6 +166,10 @@ describe("PromptsView", () => {
it("handles API configuration selection", () => {
renderPromptsView()
// Click the ENHANCE tab first to show the API config dropdown
const enhanceTab = screen.getByTestId("ENHANCE-tab")
fireEvent.click(enhanceTab)
const dropdown = screen.getByTestId("api-config-dropdown")
fireEvent(
dropdown,