modes.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import { TOOL_GROUPS, ToolGroup, ALWAYS_AVAILABLE_TOOLS } from "./tool-groups"
  2. // Mode types
  3. export type Mode = string
  4. // Mode configuration type
  5. export type ModeConfig = {
  6. slug: string
  7. name: string
  8. roleDefinition: string
  9. customInstructions?: string
  10. groups: readonly ToolGroup[] // Now uses groups instead of tools array
  11. }
  12. // Mode-specific prompts only
  13. export type PromptComponent = {
  14. roleDefinition?: string
  15. customInstructions?: string
  16. }
  17. export type CustomModePrompts = {
  18. [key: string]: PromptComponent | undefined
  19. }
  20. // Helper to get all tools for a mode
  21. export function getToolsForMode(groups: readonly ToolGroup[]): string[] {
  22. const tools = new Set<string>()
  23. // Add tools from each group
  24. groups.forEach((group) => {
  25. TOOL_GROUPS[group].forEach((tool) => tools.add(tool))
  26. })
  27. // Always add required tools
  28. ALWAYS_AVAILABLE_TOOLS.forEach((tool) => tools.add(tool))
  29. return Array.from(tools)
  30. }
  31. // Main modes configuration as an ordered array
  32. export const modes: readonly ModeConfig[] = [
  33. {
  34. slug: "code",
  35. name: "Code",
  36. roleDefinition:
  37. "You are Roo, a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.",
  38. groups: ["read", "edit", "browser", "command", "mcp"],
  39. },
  40. {
  41. slug: "architect",
  42. name: "Architect",
  43. roleDefinition:
  44. "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.",
  45. groups: ["read", "browser", "mcp"],
  46. },
  47. {
  48. slug: "ask",
  49. name: "Ask",
  50. roleDefinition:
  51. "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.",
  52. groups: ["read", "browser", "mcp"],
  53. },
  54. ] as const
  55. // Export the default mode slug
  56. export const defaultModeSlug = modes[0].slug
  57. // Helper functions
  58. export function getModeBySlug(slug: string, customModes?: ModeConfig[]): ModeConfig | undefined {
  59. // Check custom modes first
  60. const customMode = customModes?.find((mode) => mode.slug === slug)
  61. if (customMode) {
  62. return customMode
  63. }
  64. // Then check built-in modes
  65. return modes.find((mode) => mode.slug === slug)
  66. }
  67. export function getModeConfig(slug: string, customModes?: ModeConfig[]): ModeConfig {
  68. const mode = getModeBySlug(slug, customModes)
  69. if (!mode) {
  70. throw new Error(`No mode found for slug: ${slug}`)
  71. }
  72. return mode
  73. }
  74. // Get all available modes, with custom modes overriding built-in modes
  75. export function getAllModes(customModes?: ModeConfig[]): ModeConfig[] {
  76. if (!customModes?.length) {
  77. return [...modes]
  78. }
  79. // Start with built-in modes
  80. const allModes = [...modes]
  81. // Process custom modes
  82. customModes.forEach((customMode) => {
  83. const index = allModes.findIndex((mode) => mode.slug === customMode.slug)
  84. if (index !== -1) {
  85. // Override existing mode
  86. allModes[index] = customMode
  87. } else {
  88. // Add new mode
  89. allModes.push(customMode)
  90. }
  91. })
  92. return allModes
  93. }
  94. // Check if a mode is custom or an override
  95. export function isCustomMode(slug: string, customModes?: ModeConfig[]): boolean {
  96. return !!customModes?.some((mode) => mode.slug === slug)
  97. }
  98. export function isToolAllowedForMode(
  99. tool: string,
  100. modeSlug: string,
  101. customModes: ModeConfig[],
  102. toolRequirements?: Record<string, boolean>,
  103. ): boolean {
  104. // Always allow these tools
  105. if (ALWAYS_AVAILABLE_TOOLS.includes(tool as any)) {
  106. return true
  107. }
  108. // Check tool requirements if any exist
  109. if (toolRequirements && tool in toolRequirements) {
  110. if (!toolRequirements[tool]) {
  111. return false
  112. }
  113. }
  114. const mode = getModeBySlug(modeSlug, customModes)
  115. if (!mode) {
  116. return false
  117. }
  118. // Check if tool is in any of the mode's groups
  119. return mode.groups.some((group) => TOOL_GROUPS[group].includes(tool as string))
  120. }
  121. // Create the mode-specific default prompts
  122. export const defaultPrompts: Readonly<CustomModePrompts> = Object.freeze(
  123. Object.fromEntries(modes.map((mode) => [mode.slug, { roleDefinition: mode.roleDefinition }])),
  124. )
  125. // Helper function to safely get role definition
  126. export function getRoleDefinition(modeSlug: string, customModes?: ModeConfig[]): string {
  127. const mode = getModeBySlug(modeSlug, customModes)
  128. if (!mode) {
  129. console.warn(`No mode found for slug: ${modeSlug}`)
  130. return ""
  131. }
  132. return mode.roleDefinition
  133. }