snow-ai 0.3.36 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/codebaseIndexAgent.js +1 -0
- package/dist/agents/codebaseReviewAgent.d.ts +61 -0
- package/dist/agents/codebaseReviewAgent.js +301 -0
- package/dist/agents/promptOptimizeAgent.d.ts +54 -0
- package/dist/agents/promptOptimizeAgent.js +268 -0
- package/dist/api/anthropic.js +1 -0
- package/dist/api/chat.js +1 -0
- package/dist/api/embedding.js +1 -0
- package/dist/api/gemini.js +2 -1
- package/dist/api/responses.js +1 -0
- package/dist/api/systemPrompt.d.ts +1 -5
- package/dist/api/systemPrompt.js +168 -100
- package/dist/app.js +14 -6
- package/dist/cli.js +1 -1
- package/dist/hooks/useCommandPanel.js +48 -46
- package/dist/hooks/useConversation.d.ts +2 -1
- package/dist/hooks/useConversation.js +116 -30
- package/dist/hooks/useGlobalExit.js +4 -2
- package/dist/hooks/useStreamingState.d.ts +9 -0
- package/dist/hooks/useStreamingState.js +3 -0
- package/dist/i18n/I18nContext.d.ts +14 -0
- package/dist/i18n/I18nContext.js +24 -0
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/lang/en.d.ts +2 -0
- package/dist/i18n/lang/en.js +483 -0
- package/dist/i18n/lang/es.d.ts +2 -0
- package/dist/i18n/lang/es.js +483 -0
- package/dist/i18n/lang/ja.d.ts +2 -0
- package/dist/i18n/lang/ja.js +483 -0
- package/dist/i18n/lang/ko.d.ts +2 -0
- package/dist/i18n/lang/ko.js +483 -0
- package/dist/i18n/lang/zh-TW.d.ts +2 -0
- package/dist/i18n/lang/zh-TW.js +483 -0
- package/dist/i18n/lang/zh.d.ts +2 -0
- package/dist/i18n/lang/zh.js +483 -0
- package/dist/i18n/translations.d.ts +2 -0
- package/dist/i18n/translations.js +14 -0
- package/dist/i18n/types.d.ts +459 -0
- package/dist/i18n/types.js +1 -0
- package/dist/mcp/aceCodeSearch.d.ts +17 -48
- package/dist/mcp/aceCodeSearch.js +24 -56
- package/dist/mcp/bash.js +8 -1
- package/dist/mcp/codebaseSearch.d.ts +1 -1
- package/dist/mcp/codebaseSearch.js +159 -30
- package/dist/mcp/filesystem.d.ts +3 -80
- package/dist/mcp/filesystem.js +23 -103
- package/dist/mcp/subagent.d.ts +2 -1
- package/dist/mcp/subagent.js +54 -5
- package/dist/ui/components/ChatInput.js +22 -25
- package/dist/ui/components/CommandPanel.d.ts +1 -1
- package/dist/ui/components/CommandPanel.js +20 -13
- package/dist/ui/components/DiffViewer.d.ts +1 -1
- package/dist/ui/components/DiffViewer.js +101 -91
- package/dist/ui/components/FileList.js +22 -11
- package/dist/ui/components/HelpPanel.js +47 -21
- package/dist/ui/components/Menu.js +6 -2
- package/dist/ui/components/MessageList.d.ts +6 -0
- package/dist/ui/components/MessageList.js +1 -1
- package/dist/ui/components/ToolConfirmation.d.ts +4 -1
- package/dist/ui/components/ToolConfirmation.js +28 -2
- package/dist/ui/components/ToolResultPreview.d.ts +2 -1
- package/dist/ui/components/ToolResultPreview.js +41 -25
- package/dist/ui/pages/ChatScreen.js +177 -56
- package/dist/ui/pages/CodeBaseConfigScreen.js +54 -30
- package/dist/ui/pages/ConfigScreen.js +138 -98
- package/dist/ui/pages/CustomHeadersScreen.js +75 -69
- package/dist/ui/pages/LanguageSettingsScreen.d.ts +7 -0
- package/dist/ui/pages/LanguageSettingsScreen.js +89 -0
- package/dist/ui/pages/ProxyConfigScreen.js +27 -23
- package/dist/ui/pages/SensitiveCommandConfigScreen.js +32 -25
- package/dist/ui/pages/SubAgentConfigScreen.js +88 -75
- package/dist/ui/pages/SystemPromptConfigScreen.js +31 -26
- package/dist/ui/pages/WelcomeScreen.js +40 -26
- package/dist/utils/apiConfig.d.ts +2 -0
- package/dist/utils/codebaseConfig.d.ts +1 -5
- package/dist/utils/codebaseConfig.js +2 -10
- package/dist/utils/codebaseSearchEvents.d.ts +16 -0
- package/dist/utils/codebaseSearchEvents.js +13 -0
- package/dist/utils/commands/agent.js +2 -2
- package/dist/utils/commands/init.js +1 -1
- package/dist/utils/configManager.js +26 -5
- package/dist/utils/contextCompressor.js +1 -1
- package/dist/utils/languageConfig.d.ts +21 -0
- package/dist/utils/languageConfig.js +61 -0
- package/dist/utils/mcpToolsManager.js +0 -9
- package/dist/utils/notebookManager.js +11 -4
- package/dist/utils/sessionConverter.js +13 -3
- package/dist/utils/sessionManager.d.ts +1 -0
- package/dist/utils/subAgentConfig.d.ts +10 -5
- package/dist/utils/subAgentConfig.js +112 -19
- package/dist/utils/subAgentExecutor.d.ts +9 -1
- package/dist/utils/subAgentExecutor.js +122 -9
- package/dist/utils/toolExecutor.d.ts +2 -1
- package/dist/utils/toolExecutor.js +1 -2
- package/dist/utils/usageLogger.js +18 -3
- package/package.json +2 -1
|
@@ -4,7 +4,8 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, unlink
|
|
|
4
4
|
import { loadConfig, saveConfig } from './apiConfig.js';
|
|
5
5
|
const CONFIG_DIR = join(homedir(), '.snow');
|
|
6
6
|
const PROFILES_DIR = join(CONFIG_DIR, 'profiles');
|
|
7
|
-
const ACTIVE_PROFILE_FILE = join(CONFIG_DIR, 'active-profile.
|
|
7
|
+
const ACTIVE_PROFILE_FILE = join(CONFIG_DIR, 'active-profile.json');
|
|
8
|
+
const LEGACY_ACTIVE_PROFILE_FILE = join(CONFIG_DIR, 'active-profile.txt');
|
|
8
9
|
const LEGACY_CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
9
10
|
/**
|
|
10
11
|
* Ensure the profiles directory exists
|
|
@@ -22,12 +23,29 @@ function ensureProfilesDirectory() {
|
|
|
22
23
|
*/
|
|
23
24
|
export function getActiveProfileName() {
|
|
24
25
|
ensureProfilesDirectory();
|
|
26
|
+
// Auto-migrate from legacy .txt format to new .json format
|
|
27
|
+
if (!existsSync(ACTIVE_PROFILE_FILE) &&
|
|
28
|
+
existsSync(LEGACY_ACTIVE_PROFILE_FILE)) {
|
|
29
|
+
try {
|
|
30
|
+
const legacyProfileName = readFileSync(LEGACY_ACTIVE_PROFILE_FILE, 'utf8').trim();
|
|
31
|
+
const profileName = legacyProfileName || 'default';
|
|
32
|
+
// Save in new JSON format
|
|
33
|
+
setActiveProfileName(profileName);
|
|
34
|
+
// Delete old .txt file
|
|
35
|
+
unlinkSync(LEGACY_ACTIVE_PROFILE_FILE);
|
|
36
|
+
return profileName;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// If migration fails, continue with default
|
|
40
|
+
}
|
|
41
|
+
}
|
|
25
42
|
if (!existsSync(ACTIVE_PROFILE_FILE)) {
|
|
26
43
|
return 'default';
|
|
27
44
|
}
|
|
28
45
|
try {
|
|
29
|
-
const
|
|
30
|
-
|
|
46
|
+
const fileContent = readFileSync(ACTIVE_PROFILE_FILE, 'utf8').trim();
|
|
47
|
+
const data = JSON.parse(fileContent);
|
|
48
|
+
return data.activeProfile || 'default';
|
|
31
49
|
}
|
|
32
50
|
catch {
|
|
33
51
|
return 'default';
|
|
@@ -39,7 +57,8 @@ export function getActiveProfileName() {
|
|
|
39
57
|
function setActiveProfileName(profileName) {
|
|
40
58
|
ensureProfilesDirectory();
|
|
41
59
|
try {
|
|
42
|
-
|
|
60
|
+
const data = { activeProfile: profileName };
|
|
61
|
+
writeFileSync(ACTIVE_PROFILE_FILE, JSON.stringify(data, null, 2), 'utf8');
|
|
43
62
|
}
|
|
44
63
|
catch (error) {
|
|
45
64
|
throw new Error(`Failed to set active profile: ${error}`);
|
|
@@ -180,7 +199,9 @@ export function switchProfile(profileName) {
|
|
|
180
199
|
export function createProfile(profileName, config) {
|
|
181
200
|
ensureProfilesDirectory();
|
|
182
201
|
// Validate profile name
|
|
183
|
-
if (!profileName.trim() ||
|
|
202
|
+
if (!profileName.trim() ||
|
|
203
|
+
profileName.includes('/') ||
|
|
204
|
+
profileName.includes('\\')) {
|
|
184
205
|
throw new Error('Invalid profile name');
|
|
185
206
|
}
|
|
186
207
|
const profilePath = getProfilePath(profileName);
|
|
@@ -104,7 +104,7 @@ function prepareMessagesForCompression(conversationMessages, customSystemPrompt)
|
|
|
104
104
|
if (customSystemPrompt) {
|
|
105
105
|
// If custom system prompt exists: custom as system, default as first user message
|
|
106
106
|
messages.push({ role: 'system', content: customSystemPrompt });
|
|
107
|
-
messages.push({
|
|
107
|
+
// messages.push({role: 'user', content: getSystemPrompt()});
|
|
108
108
|
}
|
|
109
109
|
else {
|
|
110
110
|
// No custom system prompt: default as system
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type Language = 'en' | 'zh' | 'zh-TW' | 'ja' | 'ko' | 'es';
|
|
2
|
+
interface LanguageConfig {
|
|
3
|
+
language: Language;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Load language configuration from file system
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadLanguageConfig(): LanguageConfig;
|
|
9
|
+
/**
|
|
10
|
+
* Save language configuration to file system
|
|
11
|
+
*/
|
|
12
|
+
export declare function saveLanguageConfig(config: LanguageConfig): void;
|
|
13
|
+
/**
|
|
14
|
+
* Get current language setting
|
|
15
|
+
*/
|
|
16
|
+
export declare function getCurrentLanguage(): Language;
|
|
17
|
+
/**
|
|
18
|
+
* Set language and persist to file system
|
|
19
|
+
*/
|
|
20
|
+
export declare function setCurrentLanguage(language: Language): void;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { homedir } from 'os';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
4
|
+
const CONFIG_DIR = join(homedir(), '.snow');
|
|
5
|
+
const LANGUAGE_CONFIG_FILE = join(CONFIG_DIR, 'language.json');
|
|
6
|
+
const DEFAULT_CONFIG = {
|
|
7
|
+
language: 'en',
|
|
8
|
+
};
|
|
9
|
+
function ensureConfigDirectory() {
|
|
10
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
11
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Load language configuration from file system
|
|
16
|
+
*/
|
|
17
|
+
export function loadLanguageConfig() {
|
|
18
|
+
ensureConfigDirectory();
|
|
19
|
+
if (!existsSync(LANGUAGE_CONFIG_FILE)) {
|
|
20
|
+
saveLanguageConfig(DEFAULT_CONFIG);
|
|
21
|
+
return DEFAULT_CONFIG;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const configData = readFileSync(LANGUAGE_CONFIG_FILE, 'utf-8');
|
|
25
|
+
const config = JSON.parse(configData);
|
|
26
|
+
return {
|
|
27
|
+
...DEFAULT_CONFIG,
|
|
28
|
+
...config,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
// If config file is corrupted, return default config
|
|
33
|
+
return DEFAULT_CONFIG;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Save language configuration to file system
|
|
38
|
+
*/
|
|
39
|
+
export function saveLanguageConfig(config) {
|
|
40
|
+
ensureConfigDirectory();
|
|
41
|
+
try {
|
|
42
|
+
const configData = JSON.stringify(config, null, 2);
|
|
43
|
+
writeFileSync(LANGUAGE_CONFIG_FILE, configData, 'utf-8');
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.error('Failed to save language config:', error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get current language setting
|
|
51
|
+
*/
|
|
52
|
+
export function getCurrentLanguage() {
|
|
53
|
+
const config = loadLanguageConfig();
|
|
54
|
+
return config.language;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Set language and persist to file system
|
|
58
|
+
*/
|
|
59
|
+
export function setCurrentLanguage(language) {
|
|
60
|
+
saveLanguageConfig({ language });
|
|
61
|
+
}
|
|
@@ -703,15 +703,6 @@ export async function executeMCPTool(toolName, args, abortSignal, onTokenUpdate)
|
|
|
703
703
|
return await filesystemService.getFileContent(args.filePath, args.startLine, args.endLine);
|
|
704
704
|
case 'create':
|
|
705
705
|
return await filesystemService.createFile(args.filePath, args.content, args.createDirectories);
|
|
706
|
-
case 'delete':
|
|
707
|
-
// Support both filePath (legacy) and filePaths (new) parameters
|
|
708
|
-
const pathsToDelete = args.filePaths || args.filePath;
|
|
709
|
-
if (!pathsToDelete) {
|
|
710
|
-
throw new Error('Missing required parameter: filePath or filePaths');
|
|
711
|
-
}
|
|
712
|
-
return await filesystemService.deleteFile(pathsToDelete);
|
|
713
|
-
case 'list':
|
|
714
|
-
return await filesystemService.listFiles(args.dirPath);
|
|
715
706
|
case 'exists':
|
|
716
707
|
return await filesystemService.exists(args.filePath);
|
|
717
708
|
case 'info':
|
|
@@ -60,8 +60,13 @@ function normalizePath(filePath) {
|
|
|
60
60
|
if (path.isAbsolute(filePath)) {
|
|
61
61
|
return path.relative(projectRoot, filePath).replace(/\\/g, '/');
|
|
62
62
|
}
|
|
63
|
-
//
|
|
64
|
-
|
|
63
|
+
// 已经是相对路径,规范化斜杠并移除 ./ 前缀
|
|
64
|
+
let normalized = filePath.replace(/\\/g, '/');
|
|
65
|
+
// 移除开头的 ./ 前缀
|
|
66
|
+
if (normalized.startsWith('./')) {
|
|
67
|
+
normalized = normalized.substring(2);
|
|
68
|
+
}
|
|
69
|
+
return normalized;
|
|
65
70
|
}
|
|
66
71
|
/**
|
|
67
72
|
* 添加备忘录
|
|
@@ -103,8 +108,10 @@ export function addNotebook(filePath, note) {
|
|
|
103
108
|
export function queryNotebook(filePathPattern = '', topN = 10) {
|
|
104
109
|
const data = readNotebookData();
|
|
105
110
|
const results = [];
|
|
106
|
-
//
|
|
107
|
-
const normalizedPattern = filePathPattern
|
|
111
|
+
// 规范化搜索模式(移除 ./ 前缀等)
|
|
112
|
+
const normalizedPattern = filePathPattern
|
|
113
|
+
? normalizePath(filePathPattern).toLowerCase()
|
|
114
|
+
: '';
|
|
108
115
|
// 遍历所有文件路径
|
|
109
116
|
for (const [filePath, entries] of Object.entries(data)) {
|
|
110
117
|
// 如果没有指定模式,或者文件路径包含模式
|
|
@@ -36,7 +36,7 @@ export function convertSessionMessagesToUI(sessionMessages) {
|
|
|
36
36
|
name: toolCall.function.name,
|
|
37
37
|
arguments: toolArgs,
|
|
38
38
|
},
|
|
39
|
-
toolDisplay
|
|
39
|
+
// Don't include toolDisplay for sub-agent tools to avoid showing parameters
|
|
40
40
|
toolCallId: toolCall.id,
|
|
41
41
|
toolPending: false,
|
|
42
42
|
subAgentInternal: true,
|
|
@@ -154,8 +154,18 @@ export function convertSessionMessagesToUI(sessionMessages) {
|
|
|
154
154
|
// Handle regular tool result messages (non-subagent)
|
|
155
155
|
if (msg.role === 'tool' && msg.tool_call_id && !msg.subAgentInternal) {
|
|
156
156
|
const isError = msg.content.startsWith('Error:');
|
|
157
|
-
const
|
|
158
|
-
const
|
|
157
|
+
const isRejectedWithReply = msg.content.includes('Tool execution rejected by user:');
|
|
158
|
+
const statusIcon = isError || isRejectedWithReply ? '✗' : '✓';
|
|
159
|
+
let statusText = '';
|
|
160
|
+
if (isError) {
|
|
161
|
+
statusText = `\n └─ ${msg.content}`;
|
|
162
|
+
}
|
|
163
|
+
else if (isRejectedWithReply) {
|
|
164
|
+
// Extract rejection reason
|
|
165
|
+
const reason = msg.content.split('Tool execution rejected by user:')[1]?.trim() ||
|
|
166
|
+
'';
|
|
167
|
+
statusText = reason ? `\n └─ Rejection reason: ${reason}` : '';
|
|
168
|
+
}
|
|
159
169
|
// Find tool name and args from previous assistant message
|
|
160
170
|
let toolName = 'tool';
|
|
161
171
|
let toolArgs = {};
|
|
@@ -6,24 +6,29 @@ export interface SubAgent {
|
|
|
6
6
|
tools: string[];
|
|
7
7
|
createdAt: string;
|
|
8
8
|
updatedAt: string;
|
|
9
|
+
builtin?: boolean;
|
|
9
10
|
}
|
|
10
11
|
export interface SubAgentsConfig {
|
|
11
12
|
agents: SubAgent[];
|
|
12
13
|
}
|
|
13
14
|
/**
|
|
14
|
-
* Get
|
|
15
|
+
* Get user-configured sub-agents only (exported for MCP tool generation)
|
|
16
|
+
*/
|
|
17
|
+
export declare function getUserSubAgents(): SubAgent[];
|
|
18
|
+
/**
|
|
19
|
+
* Get all sub-agents (built-in + user-configured)
|
|
15
20
|
*/
|
|
16
21
|
export declare function getSubAgents(): SubAgent[];
|
|
17
22
|
/**
|
|
18
|
-
* Get a sub-agent by ID
|
|
23
|
+
* Get a sub-agent by ID (checks both built-in and user-configured)
|
|
19
24
|
*/
|
|
20
25
|
export declare function getSubAgent(id: string): SubAgent | null;
|
|
21
26
|
/**
|
|
22
|
-
* Create a new sub-agent
|
|
27
|
+
* Create a new sub-agent (user-configured only)
|
|
23
28
|
*/
|
|
24
29
|
export declare function createSubAgent(name: string, description: string, tools: string[], role?: string): SubAgent;
|
|
25
30
|
/**
|
|
26
|
-
* Update an existing sub-agent
|
|
31
|
+
* Update an existing sub-agent (only user-configured agents can be updated)
|
|
27
32
|
*/
|
|
28
33
|
export declare function updateSubAgent(id: string, updates: {
|
|
29
34
|
name?: string;
|
|
@@ -32,7 +37,7 @@ export declare function updateSubAgent(id: string, updates: {
|
|
|
32
37
|
tools?: string[];
|
|
33
38
|
}): SubAgent | null;
|
|
34
39
|
/**
|
|
35
|
-
* Delete a sub-agent
|
|
40
|
+
* Delete a sub-agent (only user-configured agents can be deleted)
|
|
36
41
|
*/
|
|
37
42
|
export declare function deleteSubAgent(id: string): boolean;
|
|
38
43
|
/**
|
|
@@ -3,6 +3,77 @@ import { join } from 'path';
|
|
|
3
3
|
import { homedir } from 'os';
|
|
4
4
|
const CONFIG_DIR = join(homedir(), '.snow');
|
|
5
5
|
const SUB_AGENTS_CONFIG_FILE = join(CONFIG_DIR, 'sub-agents.json');
|
|
6
|
+
/**
|
|
7
|
+
* Built-in sub-agents (hardcoded, always available)
|
|
8
|
+
*/
|
|
9
|
+
const BUILTIN_AGENTS = [
|
|
10
|
+
{
|
|
11
|
+
id: 'agent_explore',
|
|
12
|
+
name: 'Explore Agent',
|
|
13
|
+
description: 'Specialized for quickly exploring and understanding codebases. Excels at searching code, finding definitions, analyzing code structure and dependencies. Read-only operations.',
|
|
14
|
+
role: 'You are a specialized code exploration agent. Your task is to help users understand codebase structure, locate specific code, and analyze dependencies. Use search and analysis tools to explore code, but do not modify any files or execute commands. Focus on code discovery and understanding.',
|
|
15
|
+
tools: [
|
|
16
|
+
'filesystem-read',
|
|
17
|
+
'ace-find_definition',
|
|
18
|
+
'ace-find_references',
|
|
19
|
+
'ace-semantic_search',
|
|
20
|
+
'ace-text_search',
|
|
21
|
+
'ace-file_outline',
|
|
22
|
+
'codebase-search',
|
|
23
|
+
'websearch-search',
|
|
24
|
+
'websearch-fetch',
|
|
25
|
+
],
|
|
26
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
27
|
+
updatedAt: '2024-01-01T00:00:00.000Z',
|
|
28
|
+
builtin: true,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'agent_plan',
|
|
32
|
+
name: 'Plan Agent',
|
|
33
|
+
description: 'Specialized for planning complex tasks. Analyzes requirements, explores code, identifies relevant files, and creates detailed implementation plans. Read-only operations.',
|
|
34
|
+
role: 'You are a specialized task planning agent. Your task is to analyze user requirements, explore existing codebase, identify relevant files and dependencies, and then create detailed implementation plans. Use search and analysis tools to gather information, check diagnostics to understand current state, but do not execute actual modifications. Output clear step-by-step plans including files to modify, suggested implementation approaches, and important considerations.',
|
|
35
|
+
tools: [
|
|
36
|
+
'filesystem-read',
|
|
37
|
+
'ace-find_definition',
|
|
38
|
+
'ace-find_references',
|
|
39
|
+
'ace-semantic_search',
|
|
40
|
+
'ace-text_search',
|
|
41
|
+
'ace-file_outline',
|
|
42
|
+
'ide-get_diagnostics',
|
|
43
|
+
'codebase-search',
|
|
44
|
+
'websearch-search',
|
|
45
|
+
'websearch-fetch',
|
|
46
|
+
],
|
|
47
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
48
|
+
updatedAt: '2024-01-01T00:00:00.000Z',
|
|
49
|
+
builtin: true,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'agent_general',
|
|
53
|
+
name: 'General Purpose Agent',
|
|
54
|
+
description: 'General-purpose multi-step task execution agent. Has complete tool access for searching, modifying files, and executing commands. Best for complex tasks requiring actual operations.',
|
|
55
|
+
role: 'You are a general-purpose task execution agent. You can perform various complex multi-step tasks, including searching code, modifying files, executing commands, etc. When given a task, systematically break it down and execute. You have access to all tools and should select appropriate tools as needed to complete tasks efficiently.',
|
|
56
|
+
tools: [
|
|
57
|
+
'filesystem-read',
|
|
58
|
+
'filesystem-create',
|
|
59
|
+
'filesystem-edit',
|
|
60
|
+
'filesystem-edit_search',
|
|
61
|
+
'terminal-execute',
|
|
62
|
+
'ace-find_definition',
|
|
63
|
+
'ace-find_references',
|
|
64
|
+
'ace-semantic_search',
|
|
65
|
+
'ace-text_search',
|
|
66
|
+
'ace-file_outline',
|
|
67
|
+
'websearch-search',
|
|
68
|
+
'websearch-fetch',
|
|
69
|
+
'ide-get_diagnostics',
|
|
70
|
+
'codebase-search',
|
|
71
|
+
],
|
|
72
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
73
|
+
updatedAt: '2024-01-01T00:00:00.000Z',
|
|
74
|
+
builtin: true,
|
|
75
|
+
},
|
|
76
|
+
];
|
|
6
77
|
function ensureConfigDirectory() {
|
|
7
78
|
if (!existsSync(CONFIG_DIR)) {
|
|
8
79
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
@@ -12,9 +83,9 @@ function generateId() {
|
|
|
12
83
|
return `agent_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
13
84
|
}
|
|
14
85
|
/**
|
|
15
|
-
* Get
|
|
86
|
+
* Get user-configured sub-agents only (exported for MCP tool generation)
|
|
16
87
|
*/
|
|
17
|
-
export function
|
|
88
|
+
export function getUserSubAgents() {
|
|
18
89
|
try {
|
|
19
90
|
ensureConfigDirectory();
|
|
20
91
|
if (!existsSync(SUB_AGENTS_CONFIG_FILE)) {
|
|
@@ -30,19 +101,29 @@ export function getSubAgents() {
|
|
|
30
101
|
}
|
|
31
102
|
}
|
|
32
103
|
/**
|
|
33
|
-
* Get
|
|
104
|
+
* Get all sub-agents (built-in + user-configured)
|
|
105
|
+
*/
|
|
106
|
+
export function getSubAgents() {
|
|
107
|
+
const userAgents = getUserSubAgents();
|
|
108
|
+
// Return built-in agents first, then user-configured agents
|
|
109
|
+
return [...BUILTIN_AGENTS, ...userAgents];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get a sub-agent by ID (checks both built-in and user-configured)
|
|
34
113
|
*/
|
|
35
114
|
export function getSubAgent(id) {
|
|
36
115
|
const agents = getSubAgents();
|
|
37
116
|
return agents.find(agent => agent.id === id) || null;
|
|
38
117
|
}
|
|
39
118
|
/**
|
|
40
|
-
* Save
|
|
119
|
+
* Save user-configured sub-agents only (never saves built-in agents)
|
|
41
120
|
*/
|
|
42
121
|
function saveSubAgents(agents) {
|
|
43
122
|
try {
|
|
44
123
|
ensureConfigDirectory();
|
|
45
|
-
|
|
124
|
+
// Filter out built-in agents (should never be saved to config)
|
|
125
|
+
const userAgents = agents.filter(agent => !agent.builtin);
|
|
126
|
+
const config = { agents: userAgents };
|
|
46
127
|
const configData = JSON.stringify(config, null, 2);
|
|
47
128
|
writeFileSync(SUB_AGENTS_CONFIG_FILE, configData, 'utf8');
|
|
48
129
|
}
|
|
@@ -51,10 +132,10 @@ function saveSubAgents(agents) {
|
|
|
51
132
|
}
|
|
52
133
|
}
|
|
53
134
|
/**
|
|
54
|
-
* Create a new sub-agent
|
|
135
|
+
* Create a new sub-agent (user-configured only)
|
|
55
136
|
*/
|
|
56
137
|
export function createSubAgent(name, description, tools, role) {
|
|
57
|
-
const
|
|
138
|
+
const userAgents = getUserSubAgents();
|
|
58
139
|
const now = new Date().toISOString();
|
|
59
140
|
const newAgent = {
|
|
60
141
|
id: generateId(),
|
|
@@ -64,21 +145,27 @@ export function createSubAgent(name, description, tools, role) {
|
|
|
64
145
|
tools,
|
|
65
146
|
createdAt: now,
|
|
66
147
|
updatedAt: now,
|
|
148
|
+
builtin: false,
|
|
67
149
|
};
|
|
68
|
-
|
|
69
|
-
saveSubAgents(
|
|
150
|
+
userAgents.push(newAgent);
|
|
151
|
+
saveSubAgents(userAgents);
|
|
70
152
|
return newAgent;
|
|
71
153
|
}
|
|
72
154
|
/**
|
|
73
|
-
* Update an existing sub-agent
|
|
155
|
+
* Update an existing sub-agent (only user-configured agents can be updated)
|
|
74
156
|
*/
|
|
75
157
|
export function updateSubAgent(id, updates) {
|
|
76
|
-
|
|
77
|
-
const
|
|
158
|
+
// Prevent updating built-in agents
|
|
159
|
+
const agent = getSubAgent(id);
|
|
160
|
+
if (agent?.builtin) {
|
|
161
|
+
throw new Error('Cannot update built-in agents');
|
|
162
|
+
}
|
|
163
|
+
const userAgents = getUserSubAgents();
|
|
164
|
+
const index = userAgents.findIndex(agent => agent.id === id);
|
|
78
165
|
if (index === -1) {
|
|
79
166
|
return null;
|
|
80
167
|
}
|
|
81
|
-
const existingAgent =
|
|
168
|
+
const existingAgent = userAgents[index];
|
|
82
169
|
if (!existingAgent) {
|
|
83
170
|
return null;
|
|
84
171
|
}
|
|
@@ -90,18 +177,24 @@ export function updateSubAgent(id, updates) {
|
|
|
90
177
|
tools: updates.tools ?? existingAgent.tools,
|
|
91
178
|
createdAt: existingAgent.createdAt,
|
|
92
179
|
updatedAt: new Date().toISOString(),
|
|
180
|
+
builtin: false,
|
|
93
181
|
};
|
|
94
|
-
|
|
95
|
-
saveSubAgents(
|
|
182
|
+
userAgents[index] = updatedAgent;
|
|
183
|
+
saveSubAgents(userAgents);
|
|
96
184
|
return updatedAgent;
|
|
97
185
|
}
|
|
98
186
|
/**
|
|
99
|
-
* Delete a sub-agent
|
|
187
|
+
* Delete a sub-agent (only user-configured agents can be deleted)
|
|
100
188
|
*/
|
|
101
189
|
export function deleteSubAgent(id) {
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
if (
|
|
190
|
+
// Prevent deleting built-in agents
|
|
191
|
+
const agent = getSubAgent(id);
|
|
192
|
+
if (agent?.builtin) {
|
|
193
|
+
throw new Error('Cannot delete built-in agents');
|
|
194
|
+
}
|
|
195
|
+
const userAgents = getUserSubAgents();
|
|
196
|
+
const filteredAgents = userAgents.filter(agent => agent.id !== id);
|
|
197
|
+
if (filteredAgents.length === userAgents.length) {
|
|
105
198
|
return false; // Agent not found
|
|
106
199
|
}
|
|
107
200
|
saveSubAgents(filteredAgents);
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
+
import type { ConfirmationResult } from '../ui/components/ToolConfirmation.js';
|
|
1
2
|
export interface SubAgentMessage {
|
|
2
3
|
type: 'sub_agent_message';
|
|
3
4
|
agentId: string;
|
|
4
5
|
agentName: string;
|
|
5
6
|
message: any;
|
|
6
7
|
}
|
|
8
|
+
export interface TokenUsage {
|
|
9
|
+
inputTokens: number;
|
|
10
|
+
outputTokens: number;
|
|
11
|
+
cacheCreationInputTokens?: number;
|
|
12
|
+
cacheReadInputTokens?: number;
|
|
13
|
+
}
|
|
7
14
|
export interface SubAgentResult {
|
|
8
15
|
success: boolean;
|
|
9
16
|
result: string;
|
|
10
17
|
error?: string;
|
|
18
|
+
usage?: TokenUsage;
|
|
11
19
|
}
|
|
12
20
|
export interface ToolConfirmationCallback {
|
|
13
|
-
(toolName: string, toolArgs: any): Promise<
|
|
21
|
+
(toolName: string, toolArgs: any): Promise<ConfirmationResult>;
|
|
14
22
|
}
|
|
15
23
|
export interface ToolApprovalChecker {
|
|
16
24
|
(toolName: string): boolean;
|