Refactor modes

This commit is contained in:
Matt Rubens
2025-01-17 01:12:06 -05:00
parent b35206bc9d
commit 72fe12d096
39 changed files with 909 additions and 4310 deletions

View File

@@ -1,20 +1,15 @@
import { isToolAllowedForMode, validateToolUse } from '../mode-validator'
import { codeMode, architectMode, askMode } from '../prompts/system'
import { CODE_ALLOWED_TOOLS, READONLY_ALLOWED_TOOLS, ToolName } from '../tool-lists'
import { Mode, isToolAllowedForMode, TestToolName, getModeConfig, modes } from '../../shared/modes';
import { validateToolUse } from '../mode-validator';
// For testing purposes, we need to handle the 'unknown_tool' case
type TestToolName = ToolName | 'unknown_tool';
// Helper function to safely cast string to TestToolName for testing
function asTestTool(str: string): TestToolName {
return str as TestToolName;
}
const asTestTool = (tool: string): TestToolName => tool as TestToolName;
const [codeMode, architectMode, askMode] = modes.map(mode => mode.slug);
describe('mode-validator', () => {
describe('isToolAllowedForMode', () => {
describe('code mode', () => {
it('allows all code mode tools', () => {
CODE_ALLOWED_TOOLS.forEach(tool => {
const mode = getModeConfig(codeMode);
mode.tools.forEach(([tool]) => {
expect(isToolAllowedForMode(tool, codeMode)).toBe(true)
})
})
@@ -25,64 +20,33 @@ describe('mode-validator', () => {
})
describe('architect mode', () => {
it('allows only read-only and MCP tools', () => {
// Test allowed tools
READONLY_ALLOWED_TOOLS.forEach(tool => {
it('allows configured tools', () => {
const mode = getModeConfig(architectMode);
mode.tools.forEach(([tool]) => {
expect(isToolAllowedForMode(tool, architectMode)).toBe(true)
})
// Test specific disallowed tools that we know are in CODE_ALLOWED_TOOLS but not in READONLY_ALLOWED_TOOLS
const disallowedTools = ['execute_command', 'write_to_file', 'apply_diff'] as const;
disallowedTools.forEach(tool => {
expect(isToolAllowedForMode(tool as ToolName, architectMode)).toBe(false)
})
})
})
describe('ask mode', () => {
it('allows only read-only and MCP tools', () => {
// Test allowed tools
READONLY_ALLOWED_TOOLS.forEach(tool => {
it('allows configured tools', () => {
const mode = getModeConfig(askMode);
mode.tools.forEach(([tool]) => {
expect(isToolAllowedForMode(tool, askMode)).toBe(true)
})
// Test specific disallowed tools that we know are in CODE_ALLOWED_TOOLS but not in READONLY_ALLOWED_TOOLS
const disallowedTools = ['execute_command', 'write_to_file', 'apply_diff'] as const;
disallowedTools.forEach(tool => {
expect(isToolAllowedForMode(tool as ToolName, askMode)).toBe(false)
})
})
})
})
describe('validateToolUse', () => {
it('throws error for disallowed tools in architect mode', () => {
expect(() => validateToolUse('write_to_file' as ToolName, architectMode)).toThrow(
'Tool "write_to_file" is not allowed in architect mode.'
expect(() => validateToolUse('unknown_tool', 'architect')).toThrow(
'Tool "unknown_tool" is not allowed in architect mode.'
)
})
it('throws error for disallowed tools in ask mode', () => {
expect(() => validateToolUse('execute_command' as ToolName, askMode)).toThrow(
'Tool "execute_command" is not allowed in ask mode.'
)
})
it('throws error for unknown tools in code mode', () => {
expect(() => validateToolUse(asTestTool('unknown_tool'), codeMode)).toThrow(
'Tool "unknown_tool" is not allowed in code mode.'
)
})
it('does not throw for allowed tools', () => {
// Code mode
expect(() => validateToolUse('write_to_file' as ToolName, codeMode)).not.toThrow()
// Architect mode
expect(() => validateToolUse('read_file' as ToolName, architectMode)).not.toThrow()
// Ask mode
expect(() => validateToolUse('browser_action' as ToolName, askMode)).not.toThrow()
it('does not throw for allowed tools in architect mode', () => {
expect(() => validateToolUse('read_file', 'architect')).not.toThrow()
})
})
})