2db7c34920
Introduces `ask`, `edit`, `organize`, `research`, and `workflow` modes. Each mode defines its own system prompt, allowed tools, and preview requirements. The active mode can be switched via a dropdown in the chat UI and defaults can be set in plugin settings. Mode selection affects which tools are exposed to the LLM and whether write actions require user preview before execution.
168 lines
5.4 KiB
TypeScript
168 lines
5.4 KiB
TypeScript
import {
|
|
AgentMode,
|
|
ALL_AGENT_MODES,
|
|
DEFAULT_AGENT_MODE,
|
|
AGENT_MODE_CONFIGS,
|
|
getAgentModeLabel,
|
|
modeRequiresPreview,
|
|
getSystemPromptForMode,
|
|
filterToolsForMode,
|
|
} from '../src/agent-modes';
|
|
import { OllamaTool } from '../src/types';
|
|
|
|
describe('Agent Modes', () => {
|
|
const allTools: OllamaTool[] = [
|
|
{
|
|
type: 'function',
|
|
function: {
|
|
name: 'read_vault_file',
|
|
description: 'Read',
|
|
parameters: { type: 'object', properties: {} },
|
|
},
|
|
},
|
|
{
|
|
type: 'function',
|
|
function: {
|
|
name: 'search_vault_files',
|
|
description: 'Search',
|
|
parameters: { type: 'object', properties: {} },
|
|
},
|
|
},
|
|
{
|
|
type: 'function',
|
|
function: {
|
|
name: 'create_note',
|
|
description: 'Create',
|
|
parameters: { type: 'object', properties: {} },
|
|
},
|
|
},
|
|
{
|
|
type: 'function',
|
|
function: {
|
|
name: 'update_frontmatter',
|
|
description: 'Update frontmatter',
|
|
parameters: { type: 'object', properties: {} },
|
|
},
|
|
},
|
|
{
|
|
type: 'function',
|
|
function: {
|
|
name: 'delete_note',
|
|
description: 'Delete',
|
|
parameters: { type: 'object', properties: {} },
|
|
},
|
|
},
|
|
];
|
|
|
|
describe('constants', () => {
|
|
it('should define all expected modes', () => {
|
|
expect(ALL_AGENT_MODES).toEqual(['ask', 'edit', 'organize', 'research', 'workflow']);
|
|
});
|
|
|
|
it('should have default mode ask', () => {
|
|
expect(DEFAULT_AGENT_MODE).toBe('ask');
|
|
});
|
|
});
|
|
|
|
describe('getAgentModeLabel', () => {
|
|
it('should return labels for known modes', () => {
|
|
expect(getAgentModeLabel('ask')).toBe('Ask');
|
|
expect(getAgentModeLabel('edit')).toBe('Edit');
|
|
expect(getAgentModeLabel('organize')).toBe('Organize');
|
|
expect(getAgentModeLabel('research')).toBe('Research');
|
|
expect(getAgentModeLabel('workflow')).toBe('Workflow');
|
|
});
|
|
|
|
it('should fallback to raw mode name for unknown modes', () => {
|
|
expect(getAgentModeLabel('unknown' as AgentMode)).toBe('unknown');
|
|
});
|
|
});
|
|
|
|
describe('modeRequiresPreview', () => {
|
|
it('should require preview for edit and organize', () => {
|
|
expect(modeRequiresPreview('edit')).toBe(true);
|
|
expect(modeRequiresPreview('organize')).toBe(true);
|
|
});
|
|
|
|
it('should not require preview for ask, research, workflow', () => {
|
|
expect(modeRequiresPreview('ask')).toBe(false);
|
|
expect(modeRequiresPreview('research')).toBe(false);
|
|
expect(modeRequiresPreview('workflow')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('getSystemPromptForMode', () => {
|
|
it('should return a non-empty prompt for each mode', () => {
|
|
for (const mode of ALL_AGENT_MODES) {
|
|
const prompt = getSystemPromptForMode(mode);
|
|
expect(typeof prompt).toBe('string');
|
|
expect(prompt.length).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
|
|
it('should fallback to ask prompt for unknown mode', () => {
|
|
const askPrompt = getSystemPromptForMode('ask');
|
|
const fallback = getSystemPromptForMode('unknown' as AgentMode);
|
|
expect(fallback).toBe(askPrompt);
|
|
});
|
|
});
|
|
|
|
describe('filterToolsForMode', () => {
|
|
it('ask mode should only allow read/search tools', () => {
|
|
const filtered = filterToolsForMode(allTools, 'ask');
|
|
const names = filtered.map((t) => t.function.name);
|
|
expect(names).toContain('read_vault_file');
|
|
expect(names).toContain('search_vault_files');
|
|
expect(names).not.toContain('create_note');
|
|
expect(names).not.toContain('delete_note');
|
|
});
|
|
|
|
it('edit mode should allow all tools', () => {
|
|
const filtered = filterToolsForMode(allTools, 'edit');
|
|
const names = filtered.map((t) => t.function.name);
|
|
expect(names).toContain('read_vault_file');
|
|
expect(names).toContain('create_note');
|
|
expect(names).toContain('delete_note');
|
|
});
|
|
|
|
it('organize mode should allow organize tools but not delete', () => {
|
|
const filtered = filterToolsForMode(allTools, 'organize');
|
|
const names = filtered.map((t) => t.function.name);
|
|
expect(names).toContain('read_vault_file');
|
|
expect(names).toContain('search_vault_files');
|
|
expect(names).toContain('update_frontmatter');
|
|
expect(names).not.toContain('delete_note');
|
|
expect(names).not.toContain('create_note');
|
|
});
|
|
|
|
it('research mode should only allow read/search tools', () => {
|
|
const filtered = filterToolsForMode(allTools, 'research');
|
|
const names = filtered.map((t) => t.function.name);
|
|
expect(names).toContain('read_vault_file');
|
|
expect(names).toContain('search_vault_files');
|
|
expect(names).not.toContain('create_note');
|
|
});
|
|
|
|
it('workflow mode should return no tools', () => {
|
|
const filtered = filterToolsForMode(allTools, 'workflow');
|
|
expect(filtered).toHaveLength(0);
|
|
});
|
|
|
|
it('unknown mode should return all tools', () => {
|
|
const filtered = filterToolsForMode(allTools, 'unknown' as AgentMode);
|
|
expect(filtered).toEqual(allTools);
|
|
});
|
|
});
|
|
|
|
describe('AGENT_MODE_CONFIGS', () => {
|
|
it('should have a config for every mode', () => {
|
|
for (const mode of ALL_AGENT_MODES) {
|
|
expect(AGENT_MODE_CONFIGS[mode]).toBeDefined();
|
|
expect(AGENT_MODE_CONFIGS[mode].label).toBeDefined();
|
|
expect(AGENT_MODE_CONFIGS[mode].description).toBeDefined();
|
|
expect(AGENT_MODE_CONFIGS[mode].systemPrompt).toBeDefined();
|
|
}
|
|
});
|
|
});
|
|
});
|