snow-ai 0.2.18 → 0.2.19
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/api/systemPrompt.d.ts +1 -1
- package/dist/api/systemPrompt.js +87 -25
- package/dist/hooks/useConversation.js +5 -2
- package/dist/mcp/aceCodeSearch.d.ts +314 -0
- package/dist/mcp/aceCodeSearch.js +822 -0
- package/dist/mcp/filesystem.d.ts +65 -77
- package/dist/mcp/filesystem.js +286 -144
- package/dist/ui/components/DiffViewer.d.ts +2 -1
- package/dist/ui/components/DiffViewer.js +33 -16
- package/dist/ui/components/ToolConfirmation.js +9 -0
- package/dist/ui/components/ToolResultPreview.js +146 -24
- package/dist/ui/pages/ChatScreen.js +6 -1
- package/dist/utils/mcpToolsManager.js +54 -9
- package/dist/utils/sessionConverter.js +8 -2
- package/package.json +1 -1
|
@@ -15,12 +15,15 @@ export default function ToolResultPreview({ toolName, result, maxLines = 5 }) {
|
|
|
15
15
|
else if (toolName === 'filesystem-list') {
|
|
16
16
|
return renderListPreview(data, maxLines);
|
|
17
17
|
}
|
|
18
|
-
else if (toolName === 'filesystem-search') {
|
|
19
|
-
return renderSearchPreview(data, maxLines);
|
|
20
|
-
}
|
|
21
18
|
else if (toolName === 'filesystem-create' || toolName === 'filesystem-write') {
|
|
22
19
|
return renderCreatePreview(data);
|
|
23
20
|
}
|
|
21
|
+
else if (toolName === 'filesystem-edit_search') {
|
|
22
|
+
return renderEditSearchPreview(data);
|
|
23
|
+
}
|
|
24
|
+
else if (toolName.startsWith('ace-')) {
|
|
25
|
+
return renderACEPreview(toolName, data, maxLines);
|
|
26
|
+
}
|
|
24
27
|
else {
|
|
25
28
|
// Generic preview for unknown tools
|
|
26
29
|
return renderGenericPreview(data, maxLines);
|
|
@@ -66,29 +69,133 @@ function renderListPreview(data, maxLines) {
|
|
|
66
69
|
files.length,
|
|
67
70
|
" items)"))));
|
|
68
71
|
}
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
function renderACEPreview(toolName, data, maxLines) {
|
|
73
|
+
// Handle ace-text-search results
|
|
74
|
+
if (toolName === 'ace-text-search' || toolName === 'ace_text_search') {
|
|
75
|
+
if (!data || data.length === 0) {
|
|
76
|
+
return (React.createElement(Box, { marginLeft: 2 },
|
|
77
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "\u2514\u2500 No matches found")));
|
|
78
|
+
}
|
|
79
|
+
const results = Array.isArray(data) ? data : [];
|
|
80
|
+
const previewMatches = results.slice(0, maxLines);
|
|
81
|
+
const hasMore = results.length > maxLines;
|
|
82
|
+
return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
|
|
83
|
+
previewMatches.map((match, idx) => (React.createElement(Text, { key: idx, color: "gray", dimColor: true },
|
|
84
|
+
idx === previewMatches.length - 1 && !hasMore ? '└─ ' : '├─ ',
|
|
85
|
+
match.filePath,
|
|
86
|
+
":",
|
|
87
|
+
match.line,
|
|
88
|
+
" - ",
|
|
89
|
+
match.content.slice(0, 60),
|
|
90
|
+
match.content.length > 60 ? '...' : ''))),
|
|
91
|
+
hasMore && (React.createElement(Text, { color: "gray", dimColor: true },
|
|
92
|
+
"\u2514\u2500 ... (",
|
|
93
|
+
results.length - maxLines,
|
|
94
|
+
" more matches)"))));
|
|
95
|
+
}
|
|
96
|
+
// Handle ace-search-symbols results
|
|
97
|
+
if (toolName === 'ace-search-symbols' || toolName === 'ace_search_symbols') {
|
|
98
|
+
const symbols = data.symbols || [];
|
|
99
|
+
if (symbols.length === 0) {
|
|
100
|
+
return (React.createElement(Box, { marginLeft: 2 },
|
|
101
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "\u2514\u2500 No symbols found")));
|
|
102
|
+
}
|
|
103
|
+
const previewSymbols = symbols.slice(0, maxLines);
|
|
104
|
+
const hasMore = symbols.length > maxLines;
|
|
105
|
+
return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
|
|
106
|
+
previewSymbols.map((symbol, idx) => (React.createElement(Text, { key: idx, color: "gray", dimColor: true },
|
|
107
|
+
idx === previewSymbols.length - 1 && !hasMore ? '└─ ' : '├─ ',
|
|
108
|
+
symbol.type,
|
|
109
|
+
" ",
|
|
110
|
+
symbol.name,
|
|
111
|
+
" - ",
|
|
112
|
+
symbol.filePath,
|
|
113
|
+
":",
|
|
114
|
+
symbol.line))),
|
|
115
|
+
hasMore && (React.createElement(Text, { color: "gray", dimColor: true },
|
|
116
|
+
"\u2514\u2500 ... (",
|
|
117
|
+
data.totalResults - maxLines,
|
|
118
|
+
" more symbols)"))));
|
|
119
|
+
}
|
|
120
|
+
// Handle ace-find-references results
|
|
121
|
+
if (toolName === 'ace-find-references' || toolName === 'ace_find_references') {
|
|
122
|
+
const references = Array.isArray(data) ? data : [];
|
|
123
|
+
if (references.length === 0) {
|
|
124
|
+
return (React.createElement(Box, { marginLeft: 2 },
|
|
125
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "\u2514\u2500 No references found")));
|
|
126
|
+
}
|
|
127
|
+
const previewRefs = references.slice(0, maxLines);
|
|
128
|
+
const hasMore = references.length > maxLines;
|
|
129
|
+
return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
|
|
130
|
+
previewRefs.map((ref, idx) => (React.createElement(Text, { key: idx, color: "gray", dimColor: true },
|
|
131
|
+
idx === previewRefs.length - 1 && !hasMore ? '└─ ' : '├─ ',
|
|
132
|
+
ref.referenceType,
|
|
133
|
+
" - ",
|
|
134
|
+
ref.filePath,
|
|
135
|
+
":",
|
|
136
|
+
ref.line))),
|
|
137
|
+
hasMore && (React.createElement(Text, { color: "gray", dimColor: true },
|
|
138
|
+
"\u2514\u2500 ... (",
|
|
139
|
+
references.length - maxLines,
|
|
140
|
+
" more references)"))));
|
|
141
|
+
}
|
|
142
|
+
// Handle ace-find-definition result
|
|
143
|
+
if (toolName === 'ace-find-definition' || toolName === 'ace_find_definition') {
|
|
144
|
+
if (!data) {
|
|
145
|
+
return (React.createElement(Box, { marginLeft: 2 },
|
|
146
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "\u2514\u2500 Definition not found")));
|
|
147
|
+
}
|
|
148
|
+
return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
|
|
72
149
|
React.createElement(Text, { color: "gray", dimColor: true },
|
|
73
|
-
"\u2514\u2500
|
|
74
|
-
data.
|
|
75
|
-
"
|
|
150
|
+
"\u2514\u2500 ",
|
|
151
|
+
data.type,
|
|
152
|
+
" ",
|
|
153
|
+
data.name,
|
|
154
|
+
" - ",
|
|
155
|
+
data.filePath,
|
|
156
|
+
":",
|
|
157
|
+
data.line)));
|
|
76
158
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
159
|
+
// Handle ace-file-outline result
|
|
160
|
+
if (toolName === 'ace-file-outline' || toolName === 'ace_file_outline') {
|
|
161
|
+
const symbols = Array.isArray(data) ? data : [];
|
|
162
|
+
if (symbols.length === 0) {
|
|
163
|
+
return (React.createElement(Box, { marginLeft: 2 },
|
|
164
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "\u2514\u2500 No symbols in file")));
|
|
165
|
+
}
|
|
166
|
+
const previewSymbols = symbols.slice(0, maxLines);
|
|
167
|
+
const hasMore = symbols.length > maxLines;
|
|
168
|
+
return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
|
|
169
|
+
previewSymbols.map((symbol, idx) => (React.createElement(Text, { key: idx, color: "gray", dimColor: true },
|
|
170
|
+
idx === previewSymbols.length - 1 && !hasMore ? '└─ ' : '├─ ',
|
|
171
|
+
symbol.type,
|
|
172
|
+
" ",
|
|
173
|
+
symbol.name,
|
|
174
|
+
" (line ",
|
|
175
|
+
symbol.line,
|
|
176
|
+
")"))),
|
|
177
|
+
hasMore && (React.createElement(Text, { color: "gray", dimColor: true },
|
|
178
|
+
"\u2514\u2500 ... (",
|
|
179
|
+
symbols.length - maxLines,
|
|
180
|
+
" more symbols)"))));
|
|
181
|
+
}
|
|
182
|
+
// Handle ace-semantic-search result
|
|
183
|
+
if (toolName === 'ace-semantic-search' || toolName === 'ace_semantic_search') {
|
|
184
|
+
const totalResults = (data.symbols?.length || 0) + (data.references?.length || 0);
|
|
185
|
+
if (totalResults === 0) {
|
|
186
|
+
return (React.createElement(Box, { marginLeft: 2 },
|
|
187
|
+
React.createElement(Text, { color: "gray", dimColor: true }, "\u2514\u2500 No results found")));
|
|
188
|
+
}
|
|
189
|
+
return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
|
|
190
|
+
React.createElement(Text, { color: "gray", dimColor: true },
|
|
191
|
+
"\u251C\u2500 Symbols: ",
|
|
192
|
+
data.symbols?.length || 0),
|
|
193
|
+
React.createElement(Text, { color: "gray", dimColor: true },
|
|
194
|
+
"\u2514\u2500 References: ",
|
|
195
|
+
data.references?.length || 0)));
|
|
196
|
+
}
|
|
197
|
+
// Generic ACE tool preview
|
|
198
|
+
return renderGenericPreview(data, maxLines);
|
|
92
199
|
}
|
|
93
200
|
function renderCreatePreview(data) {
|
|
94
201
|
// Simple success message for create/write operations
|
|
@@ -97,6 +204,21 @@ function renderCreatePreview(data) {
|
|
|
97
204
|
"\u2514\u2500 ",
|
|
98
205
|
data.message || data)));
|
|
99
206
|
}
|
|
207
|
+
function renderEditSearchPreview(data) {
|
|
208
|
+
// For edit_search, show only key metadata, exclude searchContent and replaceContent
|
|
209
|
+
return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
|
|
210
|
+
data.message && (React.createElement(Text, { color: "gray", dimColor: true },
|
|
211
|
+
"\u251C\u2500 ",
|
|
212
|
+
data.message)),
|
|
213
|
+
data.matchLocation && (React.createElement(Text, { color: "gray", dimColor: true },
|
|
214
|
+
"\u251C\u2500 Match: lines ",
|
|
215
|
+
data.matchLocation.startLine,
|
|
216
|
+
"-",
|
|
217
|
+
data.matchLocation.endLine)),
|
|
218
|
+
data.totalLines && (React.createElement(Text, { color: "gray", dimColor: true },
|
|
219
|
+
"\u2514\u2500 Total lines: ",
|
|
220
|
+
data.totalLines))));
|
|
221
|
+
}
|
|
100
222
|
function renderGenericPreview(data, maxLines) {
|
|
101
223
|
// For unknown tool types, show first few properties
|
|
102
224
|
const entries = Object.entries(data).slice(0, maxLines);
|
|
@@ -493,7 +493,12 @@ export default function ChatScreen({}) {
|
|
|
493
493
|
message.toolCall.name === 'filesystem-edit' &&
|
|
494
494
|
message.toolCall.arguments.oldContent &&
|
|
495
495
|
message.toolCall.arguments.newContent && (React.createElement(Box, { marginTop: 1 },
|
|
496
|
-
React.createElement(DiffViewer, { oldContent: message.toolCall.arguments.oldContent, newContent: message.toolCall.arguments.newContent, filename: message.toolCall.arguments.filename, completeOldContent: message.toolCall.arguments.completeOldContent, completeNewContent: message.toolCall.arguments.completeNewContent }))),
|
|
496
|
+
React.createElement(DiffViewer, { oldContent: message.toolCall.arguments.oldContent, newContent: message.toolCall.arguments.newContent, filename: message.toolCall.arguments.filename, completeOldContent: message.toolCall.arguments.completeOldContent, completeNewContent: message.toolCall.arguments.completeNewContent, startLineNumber: message.toolCall.arguments.contextStartLine }))),
|
|
497
|
+
message.toolCall &&
|
|
498
|
+
message.toolCall.name === 'filesystem-edit_search' &&
|
|
499
|
+
message.toolCall.arguments.oldContent &&
|
|
500
|
+
message.toolCall.arguments.newContent && (React.createElement(Box, { marginTop: 1 },
|
|
501
|
+
React.createElement(DiffViewer, { oldContent: message.toolCall.arguments.oldContent, newContent: message.toolCall.arguments.newContent, filename: message.toolCall.arguments.filename, completeOldContent: message.toolCall.arguments.completeOldContent, completeNewContent: message.toolCall.arguments.completeNewContent, startLineNumber: message.toolCall.arguments.contextStartLine }))),
|
|
497
502
|
message.toolCall &&
|
|
498
503
|
message.toolCall.name === 'terminal-execute' &&
|
|
499
504
|
message.toolCall.arguments.command && (React.createElement(Box, { marginTop: 1, flexDirection: "column" },
|
|
@@ -5,6 +5,7 @@ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
|
5
5
|
import { getMCPConfig } from './apiConfig.js';
|
|
6
6
|
import { mcpTools as filesystemTools } from '../mcp/filesystem.js';
|
|
7
7
|
import { mcpTools as terminalTools } from '../mcp/bash.js';
|
|
8
|
+
import { mcpTools as aceCodeSearchTools } from '../mcp/aceCodeSearch.js';
|
|
8
9
|
import { TodoService } from '../mcp/todo.js';
|
|
9
10
|
import { sessionManager } from './sessionManager.js';
|
|
10
11
|
import { logger } from './logger.js';
|
|
@@ -130,6 +131,28 @@ async function refreshToolsCache() {
|
|
|
130
131
|
},
|
|
131
132
|
});
|
|
132
133
|
}
|
|
134
|
+
// Add built-in ACE Code Search tools (always available)
|
|
135
|
+
const aceServiceTools = aceCodeSearchTools.map(tool => ({
|
|
136
|
+
name: tool.name.replace('ace_', ''),
|
|
137
|
+
description: tool.description,
|
|
138
|
+
inputSchema: tool.inputSchema,
|
|
139
|
+
}));
|
|
140
|
+
servicesInfo.push({
|
|
141
|
+
serviceName: 'ace',
|
|
142
|
+
tools: aceServiceTools,
|
|
143
|
+
isBuiltIn: true,
|
|
144
|
+
connected: true,
|
|
145
|
+
});
|
|
146
|
+
for (const tool of aceCodeSearchTools) {
|
|
147
|
+
allTools.push({
|
|
148
|
+
type: 'function',
|
|
149
|
+
function: {
|
|
150
|
+
name: `ace-${tool.name.replace('ace_', '')}`,
|
|
151
|
+
description: tool.description,
|
|
152
|
+
parameters: tool.inputSchema,
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
}
|
|
133
156
|
// Add user-configured MCP server tools (probe for availability but don't maintain connections)
|
|
134
157
|
try {
|
|
135
158
|
const mcpConfig = getMCPConfig();
|
|
@@ -413,6 +436,10 @@ export async function executeMCPTool(toolName, args) {
|
|
|
413
436
|
serviceName = 'terminal';
|
|
414
437
|
actualToolName = toolName.substring('terminal-'.length);
|
|
415
438
|
}
|
|
439
|
+
else if (toolName.startsWith('ace-')) {
|
|
440
|
+
serviceName = 'ace';
|
|
441
|
+
actualToolName = toolName.substring('ace-'.length);
|
|
442
|
+
}
|
|
416
443
|
else {
|
|
417
444
|
// Check configured MCP services
|
|
418
445
|
try {
|
|
@@ -460,15 +487,8 @@ export async function executeMCPTool(toolName, args) {
|
|
|
460
487
|
return await filesystemService.getFileInfo(args.filePath);
|
|
461
488
|
case 'edit':
|
|
462
489
|
return await filesystemService.editFile(args.filePath, args.startLine, args.endLine, args.newContent, args.contextLines);
|
|
463
|
-
case '
|
|
464
|
-
|
|
465
|
-
const validSearchModes = ['text', 'regex'];
|
|
466
|
-
let searchMode = 'text';
|
|
467
|
-
if (args.searchMode && validSearchModes.includes(args.searchMode)) {
|
|
468
|
-
searchMode = args.searchMode;
|
|
469
|
-
}
|
|
470
|
-
return await filesystemService.searchCode(args.query, args.dirPath, args.fileExtensions, args.caseSensitive, args.maxResults, searchMode);
|
|
471
|
-
}
|
|
490
|
+
case 'edit_search':
|
|
491
|
+
return await filesystemService.editFileBySearch(args.filePath, args.searchContent, args.replaceContent, args.occurrence, args.contextLines);
|
|
472
492
|
default:
|
|
473
493
|
throw new Error(`Unknown filesystem tool: ${actualToolName}`);
|
|
474
494
|
}
|
|
@@ -483,6 +503,31 @@ export async function executeMCPTool(toolName, args) {
|
|
|
483
503
|
throw new Error(`Unknown terminal tool: ${actualToolName}`);
|
|
484
504
|
}
|
|
485
505
|
}
|
|
506
|
+
else if (serviceName === 'ace') {
|
|
507
|
+
// Handle built-in ACE Code Search tools (no connection needed)
|
|
508
|
+
const { aceCodeSearchService } = await import('../mcp/aceCodeSearch.js');
|
|
509
|
+
switch (actualToolName) {
|
|
510
|
+
case 'search_symbols':
|
|
511
|
+
return await aceCodeSearchService.searchSymbols(args.query, args.symbolType, args.language, args.maxResults);
|
|
512
|
+
case 'find_definition':
|
|
513
|
+
return await aceCodeSearchService.findDefinition(args.symbolName, args.contextFile);
|
|
514
|
+
case 'find_references':
|
|
515
|
+
return await aceCodeSearchService.findReferences(args.symbolName, args.maxResults);
|
|
516
|
+
case 'semantic_search':
|
|
517
|
+
return await aceCodeSearchService.semanticSearch(args.query, args.searchType, args.language, args.maxResults);
|
|
518
|
+
case 'file_outline':
|
|
519
|
+
return await aceCodeSearchService.getFileOutline(args.filePath);
|
|
520
|
+
case 'text_search':
|
|
521
|
+
return await aceCodeSearchService.textSearch(args.pattern, args.fileGlob, args.isRegex, args.maxResults);
|
|
522
|
+
case 'index_stats':
|
|
523
|
+
return aceCodeSearchService.getIndexStats();
|
|
524
|
+
case 'clear_cache':
|
|
525
|
+
aceCodeSearchService.clearCache();
|
|
526
|
+
return { message: 'ACE Code Search cache cleared successfully' };
|
|
527
|
+
default:
|
|
528
|
+
throw new Error(`Unknown ACE tool: ${actualToolName}`);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
486
531
|
else {
|
|
487
532
|
// Handle user-configured MCP service tools - connect only when needed
|
|
488
533
|
const mcpConfig = getMCPConfig();
|
|
@@ -41,9 +41,9 @@ export function convertSessionMessagesToUI(sessionMessages) {
|
|
|
41
41
|
// Get the tool result for this tool call
|
|
42
42
|
const toolResult = toolResultsMap.get(toolCall.id);
|
|
43
43
|
const isError = toolResult?.startsWith('Error:') || false;
|
|
44
|
-
// For filesystem-edit, try to extract diff data from result
|
|
44
|
+
// For filesystem-edit and filesystem-edit_search, try to extract diff data from result
|
|
45
45
|
let editDiffData;
|
|
46
|
-
if (toolCall.function.name === 'filesystem-edit' &&
|
|
46
|
+
if ((toolCall.function.name === 'filesystem-edit' || toolCall.function.name === 'filesystem-edit_search') &&
|
|
47
47
|
toolResult &&
|
|
48
48
|
!isError) {
|
|
49
49
|
try {
|
|
@@ -53,10 +53,16 @@ export function convertSessionMessagesToUI(sessionMessages) {
|
|
|
53
53
|
oldContent: resultData.oldContent,
|
|
54
54
|
newContent: resultData.newContent,
|
|
55
55
|
filename: toolArgs.filePath,
|
|
56
|
+
completeOldContent: resultData.completeOldContent,
|
|
57
|
+
completeNewContent: resultData.completeNewContent,
|
|
58
|
+
contextStartLine: resultData.contextStartLine
|
|
56
59
|
};
|
|
57
60
|
// Merge diff data into toolArgs for DiffViewer
|
|
58
61
|
toolArgs.oldContent = resultData.oldContent;
|
|
59
62
|
toolArgs.newContent = resultData.newContent;
|
|
63
|
+
toolArgs.completeOldContent = resultData.completeOldContent;
|
|
64
|
+
toolArgs.completeNewContent = resultData.completeNewContent;
|
|
65
|
+
toolArgs.contextStartLine = resultData.contextStartLine;
|
|
60
66
|
}
|
|
61
67
|
}
|
|
62
68
|
catch (e) {
|