mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-22 13:21:07 -05:00
Merge remote-tracking branch 'origin/main' into aws-profile-support
This commit is contained in:
@@ -4,7 +4,15 @@ import { ApiConfiguration, ApiProvider, ModelInfo } from "./api"
|
||||
import { HistoryItem } from "./HistoryItem"
|
||||
import { McpServer } from "./mcp"
|
||||
import { GitCommit } from "../utils/git"
|
||||
import { Mode, CustomPrompts } from "./modes"
|
||||
import { Mode, CustomModePrompts, ModeConfig } from "./modes"
|
||||
import { CustomSupportPrompts } from "./support-prompt"
|
||||
|
||||
export interface LanguageModelChatSelector {
|
||||
vendor?: string
|
||||
family?: string
|
||||
version?: string
|
||||
id?: string
|
||||
}
|
||||
|
||||
// webview will hold state
|
||||
export interface ExtensionMessage {
|
||||
@@ -31,6 +39,8 @@ export interface ExtensionMessage {
|
||||
| "updatePrompt"
|
||||
| "systemPrompt"
|
||||
| "autoApprovalEnabled"
|
||||
| "updateCustomMode"
|
||||
| "deleteCustomMode"
|
||||
text?: string
|
||||
action?:
|
||||
| "chatButtonClicked"
|
||||
@@ -54,6 +64,8 @@ export interface ExtensionMessage {
|
||||
commits?: GitCommit[]
|
||||
listApiConfig?: ApiConfigMeta[]
|
||||
mode?: Mode
|
||||
customMode?: ModeConfig
|
||||
slug?: string
|
||||
}
|
||||
|
||||
export interface ApiConfigMeta {
|
||||
@@ -71,7 +83,8 @@ export interface ExtensionState {
|
||||
currentApiConfigName?: string
|
||||
listApiConfigMeta?: ApiConfigMeta[]
|
||||
customInstructions?: string
|
||||
customPrompts?: CustomPrompts
|
||||
customModePrompts?: CustomModePrompts
|
||||
customSupportPrompts?: CustomSupportPrompts
|
||||
alwaysAllowReadOnly?: boolean
|
||||
alwaysAllowWrite?: boolean
|
||||
alwaysAllowExecute?: boolean
|
||||
@@ -96,6 +109,8 @@ export interface ExtensionState {
|
||||
enhancementApiConfigId?: string
|
||||
experimentalDiffStrategy?: boolean
|
||||
autoApprovalEnabled?: boolean
|
||||
customModes: ModeConfig[]
|
||||
toolRequirements?: Record<string, boolean> // Map of tool names to their requirements (e.g. {"apply_diff": true} if diffEnabled)
|
||||
}
|
||||
|
||||
export interface ClineMessage {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ApiConfiguration, ApiProvider } from "./api"
|
||||
import { Mode, PromptComponent } from "./modes"
|
||||
import { Mode, PromptComponent, ModeConfig } from "./modes"
|
||||
|
||||
export type PromptMode = Mode | "enhance"
|
||||
|
||||
@@ -68,12 +68,17 @@ export interface WebviewMessage {
|
||||
| "requestVsCodeLmModels"
|
||||
| "mode"
|
||||
| "updatePrompt"
|
||||
| "updateEnhancedPrompt"
|
||||
| "updateSupportPrompt"
|
||||
| "resetSupportPrompt"
|
||||
| "getSystemPrompt"
|
||||
| "systemPrompt"
|
||||
| "enhancementApiConfigId"
|
||||
| "experimentalDiffStrategy"
|
||||
| "autoApprovalEnabled"
|
||||
| "updateCustomMode"
|
||||
| "deleteCustomMode"
|
||||
| "setopenAiCustomModelInfo"
|
||||
| "openCustomModesSettings"
|
||||
text?: string
|
||||
disabled?: boolean
|
||||
askResponse?: ClineAskResponse
|
||||
@@ -92,6 +97,8 @@ export interface WebviewMessage {
|
||||
dataUrls?: string[]
|
||||
values?: Record<string, any>
|
||||
query?: string
|
||||
slug?: string
|
||||
modeConfig?: ModeConfig
|
||||
}
|
||||
|
||||
export type ClineAskResponse = "yesButtonClicked" | "noButtonClicked" | "messageResponse"
|
||||
|
||||
153
src/shared/__tests__/support-prompts.test.ts
Normal file
153
src/shared/__tests__/support-prompts.test.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { supportPrompt } 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 = supportPrompt.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 = supportPrompt.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 = supportPrompt.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 = supportPrompt.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("ENHANCE action", () => {
|
||||
it("should format enhance prompt correctly", () => {
|
||||
const prompt = supportPrompt.create("ENHANCE", {
|
||||
userInput: "test",
|
||||
})
|
||||
|
||||
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):\n\ntest",
|
||||
)
|
||||
// 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 = supportPrompt.get(undefined, "EXPLAIN")
|
||||
expect(template).toBe(supportPrompt.default.EXPLAIN)
|
||||
})
|
||||
|
||||
it("should return custom template when provided", () => {
|
||||
const customTemplate = "Custom template for explaining code"
|
||||
const customSupportPrompts = {
|
||||
EXPLAIN: customTemplate,
|
||||
}
|
||||
const template = supportPrompt.get(customSupportPrompts, "EXPLAIN")
|
||||
expect(template).toBe(customTemplate)
|
||||
})
|
||||
|
||||
it("should return default template when custom prompts does not include type", () => {
|
||||
const customSupportPrompts = {
|
||||
SOMETHING_ELSE: "Other template",
|
||||
}
|
||||
const template = supportPrompt.get(customSupportPrompts, "EXPLAIN")
|
||||
expect(template).toBe(supportPrompt.default.EXPLAIN)
|
||||
})
|
||||
})
|
||||
|
||||
describe("create with custom prompts", () => {
|
||||
it("should use custom template when provided", () => {
|
||||
const customTemplate = "Custom template for ${filePath}"
|
||||
const customSupportPrompts = {
|
||||
EXPLAIN: customTemplate,
|
||||
}
|
||||
|
||||
const prompt = supportPrompt.create(
|
||||
"EXPLAIN",
|
||||
{
|
||||
filePath: testFilePath,
|
||||
selectedText: testCode,
|
||||
},
|
||||
customSupportPrompts,
|
||||
)
|
||||
|
||||
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 customSupportPrompts = {
|
||||
EXPLAIN: "Other template",
|
||||
}
|
||||
|
||||
const prompt = supportPrompt.create(
|
||||
"EXPLAIN",
|
||||
{
|
||||
filePath: testFilePath,
|
||||
selectedText: testCode,
|
||||
},
|
||||
customSupportPrompts,
|
||||
)
|
||||
|
||||
expect(prompt).toContain("Other template")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -40,6 +40,8 @@ export interface ApiHandlerOptions {
|
||||
openAiBaseUrl?: string
|
||||
openAiApiKey?: string
|
||||
openAiModelId?: string
|
||||
openAiCustomModelInfo?: ModelInfo
|
||||
openAiUseAzure?: boolean
|
||||
ollamaModelId?: string
|
||||
ollamaBaseUrl?: string
|
||||
lmStudioModelId?: string
|
||||
@@ -236,6 +238,15 @@ export const bedrockModels = {
|
||||
inputPrice: 0.25,
|
||||
outputPrice: 1.25,
|
||||
},
|
||||
"meta.llama3-3-70b-instruct-v1:0": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsComputerUse: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.72,
|
||||
outputPrice: 0.72,
|
||||
},
|
||||
"meta.llama3-2-90b-instruct-v1:0": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 128_000,
|
||||
@@ -413,8 +424,16 @@ export const openAiModelInfoSaneDefaults: ModelInfo = {
|
||||
// Gemini
|
||||
// https://ai.google.dev/gemini-api/docs/models/gemini
|
||||
export type GeminiModelId = keyof typeof geminiModels
|
||||
export const geminiDefaultModelId: GeminiModelId = "gemini-2.0-flash-thinking-exp-1219"
|
||||
export const geminiDefaultModelId: GeminiModelId = "gemini-2.0-flash-thinking-exp-01-21"
|
||||
export const geminiModels = {
|
||||
"gemini-2.0-flash-thinking-exp-01-21": {
|
||||
maxTokens: 65_536,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
},
|
||||
"gemini-2.0-flash-thinking-exp-1219": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 32_767,
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
// Tool options for specific tools
|
||||
export type ToolOptions = {
|
||||
string: readonly string[]
|
||||
}
|
||||
|
||||
// Tool configuration tuple type
|
||||
export type ToolConfig = readonly [string] | readonly [string, ToolOptions]
|
||||
import { TOOL_GROUPS, ToolGroup, ALWAYS_AVAILABLE_TOOLS } from "./tool-groups"
|
||||
|
||||
// Mode types
|
||||
export type Mode = string
|
||||
@@ -14,17 +8,34 @@ export type ModeConfig = {
|
||||
slug: string
|
||||
name: string
|
||||
roleDefinition: string
|
||||
tools: readonly ToolConfig[]
|
||||
customInstructions?: string
|
||||
groups: readonly ToolGroup[] // Now uses groups instead of tools array
|
||||
}
|
||||
|
||||
// Separate enhance prompt type and definition
|
||||
export type EnhanceConfig = {
|
||||
prompt: string
|
||||
// Mode-specific prompts only
|
||||
export type PromptComponent = {
|
||||
roleDefinition?: string
|
||||
customInstructions?: 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
|
||||
export type CustomModePrompts = {
|
||||
[key: string]: PromptComponent | undefined
|
||||
}
|
||||
|
||||
// Helper to get all tools for a mode
|
||||
export function getToolsForMode(groups: readonly ToolGroup[]): string[] {
|
||||
const tools = new Set<string>()
|
||||
|
||||
// Add tools from each group
|
||||
groups.forEach((group) => {
|
||||
TOOL_GROUPS[group].forEach((tool) => tools.add(tool))
|
||||
})
|
||||
|
||||
// Always add required tools
|
||||
ALWAYS_AVAILABLE_TOOLS.forEach((tool) => tools.add(tool))
|
||||
|
||||
return Array.from(tools)
|
||||
}
|
||||
|
||||
// Main modes configuration as an ordered array
|
||||
export const modes: readonly ModeConfig[] = [
|
||||
@@ -32,55 +43,22 @@ export const modes: readonly ModeConfig[] = [
|
||||
slug: "code",
|
||||
name: "Code",
|
||||
roleDefinition:
|
||||
"You are Cline, a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.",
|
||||
tools: [
|
||||
["execute_command"],
|
||||
["read_file"],
|
||||
["write_to_file"],
|
||||
["apply_diff"],
|
||||
["search_files"],
|
||||
["list_files"],
|
||||
["list_code_definition_names"],
|
||||
["browser_action"],
|
||||
["use_mcp_tool"],
|
||||
["access_mcp_resource"],
|
||||
["ask_followup_question"],
|
||||
["attempt_completion"],
|
||||
] as const,
|
||||
"You are Roo, a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.",
|
||||
groups: ["read", "edit", "browser", "command", "mcp"],
|
||||
},
|
||||
{
|
||||
slug: "architect",
|
||||
name: "Architect",
|
||||
roleDefinition:
|
||||
"You are Cline, a software architecture expert specializing in analyzing codebases, identifying patterns, and providing high-level technical guidance. You excel at understanding complex systems, evaluating architectural decisions, and suggesting improvements while maintaining a read-only approach to the codebase. Make sure to help the user come up with a solid implementation plan for their project and don't rush to switch to implementing code.",
|
||||
tools: [
|
||||
["read_file"],
|
||||
["search_files"],
|
||||
["list_files"],
|
||||
["list_code_definition_names"],
|
||||
["browser_action"],
|
||||
["use_mcp_tool"],
|
||||
["access_mcp_resource"],
|
||||
["ask_followup_question"],
|
||||
["attempt_completion"],
|
||||
] as const,
|
||||
"You are Roo, a software architecture expert specializing in analyzing codebases, identifying patterns, and providing high-level technical guidance. You excel at understanding complex systems, evaluating architectural decisions, and suggesting improvements while maintaining a read-only approach to the codebase. Make sure to help the user come up with a solid implementation plan for their project and don't rush to switch to implementing code.",
|
||||
groups: ["read", "browser", "mcp"],
|
||||
},
|
||||
{
|
||||
slug: "ask",
|
||||
name: "Ask",
|
||||
roleDefinition:
|
||||
"You are Cline, a knowledgeable technical assistant focused on answering questions and providing information about software development, technology, and related topics. You can analyze code, explain concepts, and access external resources while maintaining a read-only approach to the codebase. Make sure to answer the user's questions and don't rush to switch to implementing code.",
|
||||
tools: [
|
||||
["read_file"],
|
||||
["search_files"],
|
||||
["list_files"],
|
||||
["list_code_definition_names"],
|
||||
["browser_action"],
|
||||
["use_mcp_tool"],
|
||||
["access_mcp_resource"],
|
||||
["ask_followup_question"],
|
||||
["attempt_completion"],
|
||||
] as const,
|
||||
"You are Roo, a knowledgeable technical assistant focused on answering questions and providing information about software development, technology, and related topics. You can analyze code, explain concepts, and access external resources while maintaining a read-only approach to the codebase. Make sure to answer the user's questions and don't rush to switch to implementing code.",
|
||||
groups: ["read", "browser", "mcp"],
|
||||
},
|
||||
] as const
|
||||
|
||||
@@ -88,65 +66,91 @@ export const modes: readonly ModeConfig[] = [
|
||||
export const defaultModeSlug = modes[0].slug
|
||||
|
||||
// Helper functions
|
||||
export function getModeBySlug(slug: string): ModeConfig | undefined {
|
||||
export function getModeBySlug(slug: string, customModes?: ModeConfig[]): ModeConfig | undefined {
|
||||
// Check custom modes first
|
||||
const customMode = customModes?.find((mode) => mode.slug === slug)
|
||||
if (customMode) {
|
||||
return customMode
|
||||
}
|
||||
// Then check built-in modes
|
||||
return modes.find((mode) => mode.slug === slug)
|
||||
}
|
||||
|
||||
export function getModeConfig(slug: string): ModeConfig {
|
||||
const mode = getModeBySlug(slug)
|
||||
export function getModeConfig(slug: string, customModes?: ModeConfig[]): ModeConfig {
|
||||
const mode = getModeBySlug(slug, customModes)
|
||||
if (!mode) {
|
||||
throw new Error(`No mode found for slug: ${slug}`)
|
||||
}
|
||||
return mode
|
||||
}
|
||||
|
||||
// Derive tool names from the modes configuration
|
||||
export type ToolName = (typeof modes)[number]["tools"][number][0]
|
||||
export type TestToolName = ToolName | "unknown_tool"
|
||||
|
||||
export function isToolAllowedForMode(tool: TestToolName, modeSlug: string): boolean {
|
||||
if (tool === "unknown_tool") {
|
||||
return false
|
||||
// Get all available modes, with custom modes overriding built-in modes
|
||||
export function getAllModes(customModes?: ModeConfig[]): ModeConfig[] {
|
||||
if (!customModes?.length) {
|
||||
return [...modes]
|
||||
}
|
||||
const mode = getModeBySlug(modeSlug)
|
||||
|
||||
// Start with built-in modes
|
||||
const allModes = [...modes]
|
||||
|
||||
// Process custom modes
|
||||
customModes.forEach((customMode) => {
|
||||
const index = allModes.findIndex((mode) => mode.slug === customMode.slug)
|
||||
if (index !== -1) {
|
||||
// Override existing mode
|
||||
allModes[index] = customMode
|
||||
} else {
|
||||
// Add new mode
|
||||
allModes.push(customMode)
|
||||
}
|
||||
})
|
||||
|
||||
return allModes
|
||||
}
|
||||
|
||||
// Check if a mode is custom or an override
|
||||
export function isCustomMode(slug: string, customModes?: ModeConfig[]): boolean {
|
||||
return !!customModes?.some((mode) => mode.slug === slug)
|
||||
}
|
||||
|
||||
export function isToolAllowedForMode(
|
||||
tool: string,
|
||||
modeSlug: string,
|
||||
customModes: ModeConfig[],
|
||||
toolRequirements?: Record<string, boolean>,
|
||||
): boolean {
|
||||
// Always allow these tools
|
||||
if (ALWAYS_AVAILABLE_TOOLS.includes(tool as any)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check tool requirements if any exist
|
||||
if (toolRequirements && tool in toolRequirements) {
|
||||
if (!toolRequirements[tool]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const mode = getModeBySlug(modeSlug, customModes)
|
||||
if (!mode) {
|
||||
return false
|
||||
}
|
||||
return mode.tools.some(([toolName]) => toolName === tool)
|
||||
|
||||
// Check if tool is in any of the mode's groups
|
||||
return mode.groups.some((group) => TOOL_GROUPS[group].includes(tool as string))
|
||||
}
|
||||
|
||||
export function getToolOptions(tool: ToolName, modeSlug: string): ToolOptions | undefined {
|
||||
const mode = getModeBySlug(modeSlug)
|
||||
if (!mode) {
|
||||
return undefined
|
||||
}
|
||||
const toolConfig = mode.tools.find(([toolName]) => toolName === tool)
|
||||
return toolConfig?.[1]
|
||||
}
|
||||
|
||||
export type PromptComponent = {
|
||||
roleDefinition?: string
|
||||
customInstructions?: string
|
||||
}
|
||||
|
||||
export type CustomPrompts = {
|
||||
[key: string]: PromptComponent | string | undefined
|
||||
}
|
||||
|
||||
// Create the defaultPrompts object with the correct type
|
||||
export const defaultPrompts: CustomPrompts = {
|
||||
...Object.fromEntries(modes.map((mode) => [mode.slug, { roleDefinition: mode.roleDefinition }])),
|
||||
enhance: enhance.prompt,
|
||||
} as const
|
||||
// Create the mode-specific default prompts
|
||||
export const defaultPrompts: Readonly<CustomModePrompts> = Object.freeze(
|
||||
Object.fromEntries(modes.map((mode) => [mode.slug, { roleDefinition: mode.roleDefinition }])),
|
||||
)
|
||||
|
||||
// Helper function to safely get role definition
|
||||
export function getRoleDefinition(modeSlug: string): string {
|
||||
const prompt = defaultPrompts[modeSlug]
|
||||
if (!prompt || typeof prompt === "string") {
|
||||
throw new Error(`Invalid mode slug: ${modeSlug}`)
|
||||
export function getRoleDefinition(modeSlug: string, customModes?: ModeConfig[]): string {
|
||||
const mode = getModeBySlug(modeSlug, customModes)
|
||||
if (!mode) {
|
||||
console.warn(`No mode found for slug: ${modeSlug}`)
|
||||
return ""
|
||||
}
|
||||
if (!prompt.roleDefinition) {
|
||||
throw new Error(`No role definition found for mode: ${modeSlug}`)
|
||||
}
|
||||
return prompt.roleDefinition
|
||||
return mode.roleDefinition
|
||||
}
|
||||
|
||||
123
src/shared/support-prompt.ts
Normal file
123
src/shared/support-prompt.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
// Support 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
|
||||
}
|
||||
|
||||
interface SupportPromptConfig {
|
||||
label: string
|
||||
description: string
|
||||
template: string
|
||||
}
|
||||
|
||||
const supportPromptConfigs: Record<string, SupportPromptConfig> = {
|
||||
ENHANCE: {
|
||||
label: "Enhance Prompt",
|
||||
description:
|
||||
"Use prompt enhancement to get tailored suggestions or improvements for your inputs. This ensures Roo understands your intent and provides the best possible responses. Available via the ✨ icon in chat.",
|
||||
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):
|
||||
|
||||
\${userInput}`,
|
||||
},
|
||||
EXPLAIN: {
|
||||
label: "Explain Code",
|
||||
description:
|
||||
"Get detailed explanations of code snippets, functions, or entire files. Useful for understanding complex code or learning new patterns. Available in the editor context menu (right-click on selected code).",
|
||||
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`,
|
||||
},
|
||||
FIX: {
|
||||
label: "Fix Issues",
|
||||
description:
|
||||
"Get help identifying and resolving bugs, errors, or code quality issues. Provides step-by-step guidance for fixing problems. Available in the editor context menu (right-click on selected code).",
|
||||
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`,
|
||||
},
|
||||
IMPROVE: {
|
||||
label: "Improve Code",
|
||||
description:
|
||||
"Receive suggestions for code optimization, better practices, and architectural improvements while maintaining functionality. Available in the editor context menu (right-click on selected code).",
|
||||
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.`,
|
||||
},
|
||||
} as const
|
||||
|
||||
type SupportPromptType = keyof typeof supportPromptConfigs
|
||||
|
||||
export const supportPrompt = {
|
||||
default: Object.fromEntries(Object.entries(supportPromptConfigs).map(([key, config]) => [key, config.template])),
|
||||
get: (customSupportPrompts: Record<string, any> | undefined, type: SupportPromptType): string => {
|
||||
return customSupportPrompts?.[type] ?? supportPromptConfigs[type].template
|
||||
},
|
||||
create: (type: SupportPromptType, params: PromptParams, customSupportPrompts?: Record<string, any>): string => {
|
||||
const template = supportPrompt.get(customSupportPrompts, type)
|
||||
return createPrompt(template, params)
|
||||
},
|
||||
} as const
|
||||
|
||||
export type { SupportPromptType }
|
||||
|
||||
// Expose labels and descriptions for UI
|
||||
export const supportPromptLabels = Object.fromEntries(
|
||||
Object.entries(supportPromptConfigs).map(([key, config]) => [key, config.label]),
|
||||
) as Record<SupportPromptType, string>
|
||||
|
||||
export const supportPromptDescriptions = Object.fromEntries(
|
||||
Object.entries(supportPromptConfigs).map(([key, config]) => [key, config.description]),
|
||||
) as Record<SupportPromptType, string>
|
||||
|
||||
export type CustomSupportPrompts = {
|
||||
[key: string]: string | undefined
|
||||
}
|
||||
53
src/shared/tool-groups.ts
Normal file
53
src/shared/tool-groups.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
// Define tool group values
|
||||
export type ToolGroupValues = readonly string[]
|
||||
|
||||
// Map of tool slugs to their display names
|
||||
export const TOOL_DISPLAY_NAMES = {
|
||||
execute_command: "run commands",
|
||||
read_file: "read files",
|
||||
write_to_file: "write files",
|
||||
apply_diff: "apply changes",
|
||||
search_files: "search files",
|
||||
list_files: "list files",
|
||||
list_code_definition_names: "list definitions",
|
||||
browser_action: "use a browser",
|
||||
use_mcp_tool: "use mcp tools",
|
||||
access_mcp_resource: "access mcp resources",
|
||||
ask_followup_question: "ask questions",
|
||||
attempt_completion: "complete tasks",
|
||||
} as const
|
||||
|
||||
// Define available tool groups
|
||||
export const TOOL_GROUPS: Record<string, ToolGroupValues> = {
|
||||
read: ["read_file", "search_files", "list_files", "list_code_definition_names"],
|
||||
edit: ["write_to_file", "apply_diff"],
|
||||
browser: ["browser_action"],
|
||||
command: ["execute_command"],
|
||||
mcp: ["use_mcp_tool", "access_mcp_resource"],
|
||||
}
|
||||
|
||||
export type ToolGroup = keyof typeof TOOL_GROUPS
|
||||
|
||||
// Tools that are always available to all modes
|
||||
export const ALWAYS_AVAILABLE_TOOLS = ["ask_followup_question", "attempt_completion"] as const
|
||||
|
||||
// Tool name types for type safety
|
||||
export type ToolName = keyof typeof TOOL_DISPLAY_NAMES
|
||||
|
||||
// Tool helper functions
|
||||
export function getToolName(toolConfig: string | readonly [ToolName, ...any[]]): ToolName {
|
||||
return typeof toolConfig === "string" ? (toolConfig as ToolName) : toolConfig[0]
|
||||
}
|
||||
|
||||
export function getToolOptions(toolConfig: string | readonly [ToolName, ...any[]]): any {
|
||||
return typeof toolConfig === "string" ? undefined : toolConfig[1]
|
||||
}
|
||||
|
||||
// Display names for groups in UI
|
||||
export const GROUP_DISPLAY_NAMES: Record<ToolGroup, string> = {
|
||||
read: "Read Files",
|
||||
edit: "Edit Files",
|
||||
browser: "Use Browser",
|
||||
command: "Run Commands",
|
||||
mcp: "Use MCP",
|
||||
}
|
||||
Reference in New Issue
Block a user