@xagent-ai/cli 1.1.1 → 1.2.1

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.
Files changed (74) hide show
  1. package/README.md +1 -1
  2. package/README_CN.md +1 -1
  3. package/dist/agents.js +164 -164
  4. package/dist/agents.js.map +1 -1
  5. package/dist/ai-client.d.ts +3 -0
  6. package/dist/ai-client.d.ts.map +1 -1
  7. package/dist/ai-client.js +115 -25
  8. package/dist/ai-client.js.map +1 -1
  9. package/dist/auth.js +4 -4
  10. package/dist/auth.js.map +1 -1
  11. package/dist/cli.js +184 -1
  12. package/dist/cli.js.map +1 -1
  13. package/dist/config.js +3 -3
  14. package/dist/config.js.map +1 -1
  15. package/dist/memory.d.ts +5 -1
  16. package/dist/memory.d.ts.map +1 -1
  17. package/dist/memory.js +77 -37
  18. package/dist/memory.js.map +1 -1
  19. package/dist/remote-ai-client.d.ts +1 -8
  20. package/dist/remote-ai-client.d.ts.map +1 -1
  21. package/dist/remote-ai-client.js +55 -61
  22. package/dist/remote-ai-client.js.map +1 -1
  23. package/dist/retry.d.ts +35 -0
  24. package/dist/retry.d.ts.map +1 -0
  25. package/dist/retry.js +166 -0
  26. package/dist/retry.js.map +1 -0
  27. package/dist/session.d.ts +0 -5
  28. package/dist/session.d.ts.map +1 -1
  29. package/dist/session.js +186 -164
  30. package/dist/session.js.map +1 -1
  31. package/dist/slash-commands.d.ts +1 -0
  32. package/dist/slash-commands.d.ts.map +1 -1
  33. package/dist/slash-commands.js +91 -9
  34. package/dist/slash-commands.js.map +1 -1
  35. package/dist/smart-approval.d.ts.map +1 -1
  36. package/dist/smart-approval.js +5 -4
  37. package/dist/smart-approval.js.map +1 -1
  38. package/dist/system-prompt-generator.d.ts.map +1 -1
  39. package/dist/system-prompt-generator.js +149 -139
  40. package/dist/system-prompt-generator.js.map +1 -1
  41. package/dist/theme.d.ts +48 -0
  42. package/dist/theme.d.ts.map +1 -1
  43. package/dist/theme.js +254 -0
  44. package/dist/theme.js.map +1 -1
  45. package/dist/tools/edit-diff.d.ts +32 -0
  46. package/dist/tools/edit-diff.d.ts.map +1 -0
  47. package/dist/tools/edit-diff.js +185 -0
  48. package/dist/tools/edit-diff.js.map +1 -0
  49. package/dist/tools/edit.d.ts +11 -0
  50. package/dist/tools/edit.d.ts.map +1 -0
  51. package/dist/tools/edit.js +129 -0
  52. package/dist/tools/edit.js.map +1 -0
  53. package/dist/tools.d.ts +19 -5
  54. package/dist/tools.d.ts.map +1 -1
  55. package/dist/tools.js +979 -631
  56. package/dist/tools.js.map +1 -1
  57. package/dist/types.d.ts +1 -0
  58. package/dist/types.d.ts.map +1 -1
  59. package/package.json +3 -2
  60. package/src/agents.ts +504 -504
  61. package/src/ai-client.ts +133 -31
  62. package/src/auth.ts +4 -4
  63. package/src/cli.ts +195 -1
  64. package/src/config.ts +3 -3
  65. package/src/memory.ts +83 -42
  66. package/src/remote-ai-client.ts +69 -76
  67. package/src/retry.ts +217 -0
  68. package/src/session.ts +1733 -1844
  69. package/src/slash-commands.ts +98 -9
  70. package/src/smart-approval.ts +626 -625
  71. package/src/system-prompt-generator.ts +853 -843
  72. package/src/theme.ts +284 -0
  73. package/src/tools.ts +3889 -3483
  74. package/src/types.ts +1 -0
package/dist/session.js CHANGED
@@ -21,7 +21,7 @@ import { getConversationManager } from './conversation.js';
21
21
  import { getSessionManager } from './session-manager.js';
22
22
  import { SlashCommandHandler, parseInput } from './slash-commands.js';
23
23
  import { SystemPromptGenerator } from './system-prompt-generator.js';
24
- import { theme, icons, colors, styleHelpers, renderMarkdown } from './theme.js';
24
+ import { theme, icons, colors, styleHelpers, renderMarkdown, renderDiff, renderLines } from './theme.js';
25
25
  import { getCancellationManager } from './cancellation.js';
26
26
  import { getContextCompressor } from './context-compressor.js';
27
27
  import { getLogger } from './logger.js';
@@ -66,6 +66,11 @@ export class InteractiveSession {
66
66
  // Register /clear callback, clear local conversation when clearing dialogue
67
67
  this.slashCommandHandler.setClearCallback(() => {
68
68
  this.conversation = [];
69
+ this.toolCalls = [];
70
+ this.currentTaskId = null;
71
+ this.taskCompleted = false;
72
+ this.isFirstApiCall = true;
73
+ this.slashCommandHandler.setConversationHistory([]);
69
74
  });
70
75
  // Register MCP update callback, update system prompt
71
76
  this.slashCommandHandler.setSystemPromptUpdateCallback(async () => {
@@ -117,8 +122,8 @@ export class InteractiveSession {
117
122
  console.log('');
118
123
  console.log(colors.gradient('╔════════════════════════════════════════════════════════════╗'));
119
124
  console.log(colors.gradient('║') + ' '.repeat(58) + colors.gradient(' ║'));
120
- console.log(' '.repeat(14) + '🤖 ' + colors.gradient('XAGENT CLI') + ' '.repeat(32) + colors.gradient(' ║'));
121
- console.log(' '.repeat(17) + colors.textMuted(`v${packageJson.version}`) + ' '.repeat(36) + colors.gradient(' ║'));
125
+ console.log(colors.gradient('║') + ' '.repeat(13) + '🤖 ' + colors.gradient('XAGENT CLI') + ' '.repeat(32) + colors.gradient(' ║'));
126
+ console.log(colors.gradient('║') + ' '.repeat(16) + colors.textMuted(`v${packageJson.version}`) + ' '.repeat(36) + colors.gradient(' ║'));
122
127
  console.log(colors.gradient('║') + ' '.repeat(58) + colors.gradient(' ║'));
123
128
  console.log(colors.gradient('╚════════════════════════════════════════════════════════════╝'));
124
129
  console.log(colors.textMuted(' AI-powered command-line assistant'));
@@ -167,7 +172,7 @@ export class InteractiveSession {
167
172
  if (authConfig.apiKey && selectedAuthType === AuthType.OAUTH_XAGENT) {
168
173
  clearInterval(spinnerInterval);
169
174
  process.stdout.write('\r' + ' '.repeat(50) + '\r'); // Clear the line
170
- const baseUrl = authConfig.xagentApiBaseUrl || 'https://154.8.140.52:443';
175
+ const baseUrl = authConfig.xagentApiBaseUrl || 'https://www.xagent-colife.net';
171
176
  let isValid = await this.validateToken(baseUrl, authConfig.apiKey);
172
177
  // Try refresh token if validation failed
173
178
  if (!isValid && authConfig.refreshToken) {
@@ -190,8 +195,8 @@ export class InteractiveSession {
190
195
  }
191
196
  if (!isValid) {
192
197
  console.log('');
193
- console.log(colors.warning('⚠️ Authentication expired or invalid'));
194
- console.log(colors.info('Please log in again to continue.'));
198
+ console.log(colors.warning('Your xAgent session has expired or is not configured'));
199
+ console.log(colors.info('Please select an authentication method to continue.'));
195
200
  console.log('');
196
201
  // Clear invalid credentials and persist
197
202
  // Note: Do NOT overwrite selectedAuthType - let user re-select their preferred auth method
@@ -242,7 +247,7 @@ export class InteractiveSession {
242
247
  logger.debug('[SESSION] Final selectedAuthType:', String(selectedAuthType));
243
248
  logger.debug('[SESSION] Creating RemoteAIClient?', String(selectedAuthType === AuthType.OAUTH_XAGENT));
244
249
  if (selectedAuthType === AuthType.OAUTH_XAGENT) {
245
- const webBaseUrl = authConfig.xagentApiBaseUrl || 'https://154.8.140.52:443';
250
+ const webBaseUrl = authConfig.xagentApiBaseUrl || 'https://www.xagent-colife.net';
246
251
  // In OAuth XAGENT mode, we still pass apiKey (can be empty or used for other purposes)
247
252
  this.remoteAIClient = new RemoteAIClient(authConfig.apiKey || '', webBaseUrl, authConfig.showAIDebugInfo);
248
253
  logger.debug('[DEBUG Initialize] RemoteAIClient created successfully');
@@ -372,11 +377,14 @@ export class InteractiveSession {
372
377
  process.exit(1);
373
378
  }
374
379
  const authConfig = authService.getAuthConfig();
375
- // VLM configuration is optional - skip for now, can be configured later with /vlm command
376
- console.log('');
377
- console.log(colors.info(`${icons.info} VLM configuration is optional.`));
378
- console.log(colors.info(`You can configure it later using the /vlm command if needed.`));
379
- console.log('');
380
+ // VLM configuration is optional - only show for non-OAuth (local) mode
381
+ // Remote mode uses backend VLM configuration
382
+ if (authType !== AuthType.OAUTH_XAGENT) {
383
+ console.log('');
384
+ console.log(colors.info(`${icons.info} VLM configuration is optional.`));
385
+ console.log(colors.info(`You can configure it later using the /vlm command if needed.`));
386
+ console.log('');
387
+ }
380
388
  // Save LLM config only, skip VLM for now
381
389
  await this.configManager.setAuthConfig(authConfig);
382
390
  }
@@ -776,11 +784,7 @@ export class InteractiveSession {
776
784
  const enhancedSystemPrompt = await systemPromptGenerator.generateEnhancedSystemPrompt(baseSystemPrompt);
777
785
  const messages = [
778
786
  { role: 'system', content: `${enhancedSystemPrompt}\n\n${memory}`, timestamp: Date.now() },
779
- ...this.conversation.map(msg => ({
780
- role: msg.role,
781
- content: msg.content,
782
- timestamp: msg.timestamp
783
- }))
787
+ ...this.conversation
784
788
  ];
785
789
  const operationId = `ai-response-${Date.now()}`;
786
790
  const response = await this.cancellationManager.withCancellation(chatCompletion(messages, {
@@ -920,11 +924,7 @@ export class InteractiveSession {
920
924
  // Build messages with system prompt (与本地模式一致)
921
925
  const messages = [
922
926
  { role: 'system', content: `${enhancedSystemPrompt}\n\n${memory}`, timestamp: Date.now() },
923
- ...this.conversation.map(msg => ({
924
- role: msg.role,
925
- content: msg.content,
926
- timestamp: msg.timestamp
927
- }))
927
+ ...this.conversation
928
928
  ];
929
929
  // Call unified LLM API with cancellation support
930
930
  const operationId = `remote-ai-response-${Date.now()}`;
@@ -973,7 +973,10 @@ export class InteractiveSession {
973
973
  });
974
974
  // Handle tool calls
975
975
  if (toolCalls.length > 0) {
976
- await this.handleRemoteToolCalls(toolCalls);
976
+ await this.handleToolCalls(toolCalls, async () => {
977
+ // Remote mode continuation: reuse existing taskId
978
+ await this.generateRemoteResponse(0, this.currentTaskId || undefined);
979
+ });
977
980
  }
978
981
  // Checkpoint support (consistent with local mode)
979
982
  if (this.checkpointManager.isEnabled()) {
@@ -1027,9 +1030,9 @@ export class InteractiveSession {
1027
1030
  });
1028
1031
  // Reinitialize RemoteAIClient with new token
1029
1032
  if (authConfig.apiKey) {
1030
- const webBaseUrl = authConfig.xagentApiBaseUrl || 'https://154.8.140.52:443';
1033
+ const webBaseUrl = authConfig.xagentApiBaseUrl || 'https://www.xagent-colife.net';
1031
1034
  logger.debug('[DEBUG generateRemoteResponse] Reinitializing RemoteAIClient with new token');
1032
- const newWebBaseUrl = authConfig.xagentApiBaseUrl || 'https://154.8.140.52:443';
1035
+ const newWebBaseUrl = authConfig.xagentApiBaseUrl || 'https://www.xagent-colife.net';
1033
1036
  this.remoteAIClient = new RemoteAIClient(authConfig.apiKey, newWebBaseUrl, authConfig.showAIDebugInfo);
1034
1037
  }
1035
1038
  else {
@@ -1050,7 +1053,7 @@ export class InteractiveSession {
1050
1053
  return;
1051
1054
  }
1052
1055
  }
1053
- async handleToolCalls(toolCalls) {
1056
+ async handleToolCalls(toolCalls, onComplete) {
1054
1057
  // Mark that tool execution is in progress
1055
1058
  this._isOperationInProgress = true;
1056
1059
  const toolRegistry = getToolRegistry();
@@ -1066,7 +1069,7 @@ export class InteractiveSession {
1066
1069
  catch (e) {
1067
1070
  parsedParams = params;
1068
1071
  }
1069
- return { name, params: parsedParams, index };
1072
+ return { name, params: parsedParams, index, id: toolCall.id };
1070
1073
  });
1071
1074
  // Display all tool calls info
1072
1075
  for (const { name, params } of preparedToolCalls) {
@@ -1084,6 +1087,7 @@ export class InteractiveSession {
1084
1087
  // Execute all tools in parallel
1085
1088
  const results = await toolRegistry.executeAll(preparedToolCalls.map(tc => ({ name: tc.name, params: tc.params })), this.executionMode);
1086
1089
  // Process results and maintain order
1090
+ let hasError = false;
1087
1091
  for (const { tool, result, error } of results) {
1088
1092
  const toolCall = preparedToolCalls.find(tc => tc.name === tool);
1089
1093
  if (!toolCall)
@@ -1095,11 +1099,13 @@ export class InteractiveSession {
1095
1099
  if (error === 'Operation cancelled by user') {
1096
1100
  return;
1097
1101
  }
1102
+ hasError = true;
1098
1103
  console.log('');
1099
1104
  console.log(`${indent}${colors.error(`${icons.cross} Tool Error: ${error}`)}`);
1100
1105
  this.conversation.push({
1101
1106
  role: 'tool',
1102
1107
  content: JSON.stringify({ error }),
1108
+ tool_call_id: toolCall.id,
1103
1109
  timestamp: Date.now()
1104
1110
  });
1105
1111
  }
@@ -1109,6 +1115,22 @@ export class InteractiveSession {
1109
1115
  const displayIndent = isGuiSubagent ? indent + ' ' : indent;
1110
1116
  // Always show details for todo tools so users can see their task lists
1111
1117
  const isTodoTool = tool === 'todo_write' || tool === 'todo_read';
1118
+ // Special handling for edit tool with diff
1119
+ const isEditTool = tool === 'edit';
1120
+ const hasDiff = isEditTool && result?.diff;
1121
+ // Special handling for Write tool with file preview
1122
+ const isWriteTool = tool === 'Write';
1123
+ const hasFilePreview = isWriteTool && result?.preview;
1124
+ // Special handling for DeleteFile tool
1125
+ const isDeleteTool = tool === 'DeleteFile';
1126
+ const hasDeleteInfo = isDeleteTool && result?.filePath;
1127
+ // Special handling for task tool (subagent)
1128
+ const isTaskTool = tool === 'task' && params?.subagent_type;
1129
+ // Check if tool is an MCP wrapper tool by looking up in tool registry
1130
+ const { getToolRegistry } = await import('./tools.js');
1131
+ const toolRegistry = getToolRegistry();
1132
+ const toolDef = toolRegistry.get(tool);
1133
+ const isMcpTool = toolDef && toolDef._isMcpTool === true;
1112
1134
  if (isTodoTool) {
1113
1135
  console.log('');
1114
1136
  console.log(`${displayIndent}${colors.success(`${icons.check} Todo List:`)}`);
@@ -1118,6 +1140,113 @@ export class InteractiveSession {
1118
1140
  console.log(`${displayIndent}${colors.textDim(result.message)}`);
1119
1141
  }
1120
1142
  }
1143
+ else if (hasDiff) {
1144
+ // Show edit result with diff
1145
+ console.log('');
1146
+ const diffOutput = renderDiff(result.diff);
1147
+ const indentedDiff = diffOutput.split('\n').map(line => `${displayIndent} ${line}`).join('\n');
1148
+ console.log(`${indentedDiff}`);
1149
+ }
1150
+ else if (hasFilePreview) {
1151
+ // Show new file content in diff-like style
1152
+ console.log('');
1153
+ console.log(`${displayIndent}${colors.success(`${icons.file} ${result.filePath}`)}`);
1154
+ console.log(`${displayIndent}${colors.textDim(` ${result.lineCount} lines`)}`);
1155
+ console.log('');
1156
+ console.log(renderLines(result.preview, { maxLines: 10, indent: displayIndent + ' ' }));
1157
+ }
1158
+ else if (hasDeleteInfo) {
1159
+ // Show DeleteFile result
1160
+ console.log('');
1161
+ console.log(`${displayIndent}${colors.success(`${icons.check} Deleted: ${result.filePath}`)}`);
1162
+ }
1163
+ else if (isTaskTool) {
1164
+ // Special handling for task tool (subagent) - show friendly summary
1165
+ console.log('');
1166
+ const subagentType = params.subagent_type;
1167
+ const subagentName = params.description || (params.prompt ? params.prompt.substring(0, 50).replace(/\n/g, ' ') : 'Unknown task');
1168
+ if (result?.success) {
1169
+ console.log(`${displayIndent}${colors.success(`${icons.check} ${subagentType}: Completed`)}`);
1170
+ console.log(`${displayIndent}${colors.textDim(` Task: ${subagentName}`)}`);
1171
+ if (result.message) {
1172
+ console.log(`${displayIndent}${colors.textDim(` ${result.message}`)}`);
1173
+ }
1174
+ }
1175
+ else if (result?.cancelled) {
1176
+ console.log(`${displayIndent}${colors.warning(`${icons.cross} ${subagentType}: Cancelled`)}`);
1177
+ console.log(`${displayIndent}${colors.textDim(` Task: ${subagentName}`)}`);
1178
+ }
1179
+ else {
1180
+ console.log(`${displayIndent}${colors.error(`${icons.cross} ${subagentType}: Failed`)}`);
1181
+ console.log(`${displayIndent}${colors.textDim(` Task: ${subagentName}`)}`);
1182
+ if (result?.message) {
1183
+ console.log(`${displayIndent}${colors.textDim(` ${result.message}`)}`);
1184
+ }
1185
+ }
1186
+ }
1187
+ else if (isMcpTool) {
1188
+ // Special handling for MCP tools - show friendly summary
1189
+ console.log('');
1190
+ // Extract server name and tool name from tool name (format: serverName__toolName)
1191
+ let serverName = 'MCP';
1192
+ let toolDisplayName = tool;
1193
+ if (tool.includes('__')) {
1194
+ const parts = tool.split('__');
1195
+ serverName = parts[0];
1196
+ toolDisplayName = parts.slice(1).join('__');
1197
+ }
1198
+ // Try to extract meaningful content from MCP result
1199
+ let summary = '';
1200
+ if (result?.content && Array.isArray(result.content) && result.content.length > 0) {
1201
+ const firstBlock = result.content[0];
1202
+ if (firstBlock?.type === 'text' && firstBlock?.text) {
1203
+ const text = firstBlock.text;
1204
+ if (typeof text === 'string') {
1205
+ // Detect HTML content
1206
+ if (text.trim().startsWith('<!DOCTYPE') || text.trim().startsWith('<html')) {
1207
+ summary = '[HTML content fetched]';
1208
+ }
1209
+ else {
1210
+ // Try to parse if it's JSON
1211
+ try {
1212
+ const parsed = JSON.parse(text);
1213
+ if (Array.isArray(parsed) && parsed.length > 0 && parsed[0]?.title) {
1214
+ // Search results format
1215
+ summary = `Found ${parsed.length} result(s)`;
1216
+ }
1217
+ else if (parsed?.message) {
1218
+ summary = parsed.message;
1219
+ }
1220
+ else if (typeof parsed === 'string') {
1221
+ summary = parsed.substring(0, 100);
1222
+ }
1223
+ }
1224
+ catch {
1225
+ // Not JSON, use as-is with truncation
1226
+ summary = text.substring(0, 100);
1227
+ }
1228
+ }
1229
+ }
1230
+ }
1231
+ }
1232
+ else if (result?.message) {
1233
+ summary = result.message;
1234
+ }
1235
+ if (result?.success !== false) {
1236
+ console.log(`${displayIndent}${colors.success(`${icons.check} ${serverName}: Success`)}`);
1237
+ console.log(`${displayIndent}${colors.textDim(` Tool: ${toolDisplayName}`)}`);
1238
+ if (summary) {
1239
+ console.log(`${displayIndent}${colors.textDim(` ${summary}`)}`);
1240
+ }
1241
+ }
1242
+ else {
1243
+ console.log(`${displayIndent}${colors.error(`${icons.cross} ${serverName}: Failed`)}`);
1244
+ console.log(`${displayIndent}${colors.textDim(` Tool: ${toolDisplayName}`)}`);
1245
+ if (result?.message || result?.error) {
1246
+ console.log(`${displayIndent}${colors.textDim(` ${result?.message || result?.error}`)}`);
1247
+ }
1248
+ }
1249
+ }
1121
1250
  else if (showToolDetails) {
1122
1251
  console.log('');
1123
1252
  console.log(`${displayIndent}${colors.success(`${icons.check} Tool Result:`)}`);
@@ -1128,7 +1257,12 @@ export class InteractiveSession {
1128
1257
  console.log(`${displayIndent}${colors.error(`${icons.cross} ${result.message || 'Failed'}`)}`);
1129
1258
  }
1130
1259
  else if (result) {
1131
- console.log(`${displayIndent}${colors.success(`${icons.check} Completed`)}`);
1260
+ // Show brief preview by default (consistent with subagent behavior)
1261
+ const resultPreview = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
1262
+ const truncatedPreview = resultPreview.length > 200 ? resultPreview.substring(0, 200) + '...' : resultPreview;
1263
+ // Indent the preview
1264
+ const indentedPreview = truncatedPreview.split('\n').map(line => `${displayIndent} ${line}`).join('\n');
1265
+ console.log(`${indentedPreview}`);
1132
1266
  }
1133
1267
  else {
1134
1268
  console.log(`${displayIndent}${colors.textDim('(no result)')}`);
@@ -1152,13 +1286,13 @@ export class InteractiveSession {
1152
1286
  this.conversation.push({
1153
1287
  role: 'tool',
1154
1288
  content: JSON.stringify(result),
1289
+ tool_call_id: toolCall.id,
1155
1290
  timestamp: Date.now()
1156
1291
  });
1157
1292
  }
1158
1293
  }
1159
1294
  // Logic: Only skip returning results to main agent when user explicitly cancelled (ESC)
1160
1295
  // For all other cases (success, failure, errors), always return results for further processing
1161
- const guiSubagentFailed = preparedToolCalls.some(tc => tc.name === 'task' && tc.params?.subagent_type === 'gui-subagent');
1162
1296
  const guiSubagentCancelled = preparedToolCalls.some(tc => tc.name === 'task' && tc.params?.subagent_type === 'gui-subagent' && results.some(r => r.tool === 'task' && r.result?.cancelled === true));
1163
1297
  // If GUI agent was cancelled by user, don't continue generating response
1164
1298
  // This avoids wasting API calls and tokens on cancelled tasks
@@ -1168,9 +1302,27 @@ export class InteractiveSession {
1168
1302
  this._isOperationInProgress = false;
1169
1303
  return;
1170
1304
  }
1171
- // For all other cases (GUI success/failure, other tool errors), return results to main agent
1172
- // This allows main agent to decide how to handle failures (retry, fallback, user notification, etc.)
1173
- await this.generateResponse();
1305
+ // Handle errors and completion based on whether onComplete callback is provided
1306
+ if (hasError) {
1307
+ this._isOperationInProgress = false;
1308
+ if (onComplete) {
1309
+ // Remote mode: callback handles error state (throws to mark task cancelled)
1310
+ throw new Error('Tool execution failed');
1311
+ }
1312
+ else {
1313
+ // Local mode: throw error to mark task as cancelled
1314
+ throw new Error('Tool execution failed');
1315
+ }
1316
+ }
1317
+ // Continue based on mode
1318
+ if (onComplete) {
1319
+ // Remote mode: use provided callback
1320
+ await onComplete();
1321
+ }
1322
+ else {
1323
+ // Local mode: default behavior
1324
+ await this.generateResponse();
1325
+ }
1174
1326
  }
1175
1327
  /**
1176
1328
  * Get user-friendly description for tool
@@ -1182,10 +1334,10 @@ export class InteractiveSession {
1182
1334
  'Grep': (p) => `Search text: "${p.pattern}"`,
1183
1335
  'Bash': (p) => `Execute command: ${this.truncateCommand(p.command)}`,
1184
1336
  'ListDirectory': (p) => `List directory: ${this.truncatePath(p.path || '.')}`,
1185
- 'SearchCodebase': (p) => `Search files: ${p.pattern}`,
1337
+ 'SearchFiles': (p) => `Search files: ${p.pattern}`,
1186
1338
  'DeleteFile': (p) => `Delete file: ${this.truncatePath(p.filePath)}`,
1187
1339
  'CreateDirectory': (p) => `Create directory: ${this.truncatePath(p.dirPath)}`,
1188
- 'replace': (p) => `Replace text: ${this.truncatePath(p.file_path)}`,
1340
+ 'edit': (p) => `Edit text: ${this.truncatePath(p.file_path)}`,
1189
1341
  'web_search': (p) => `Web search: "${p.query}"`,
1190
1342
  'todo_write': () => `Update todo list`,
1191
1343
  'todo_read': () => `Read todo list`,
@@ -1205,136 +1357,6 @@ export class InteractiveSession {
1205
1357
  const getDescription = descriptions[toolName];
1206
1358
  return getDescription ? getDescription(params) : `Execute tool: ${toolName}`;
1207
1359
  }
1208
- /**
1209
- * Handle tool calls for remote AI mode
1210
- * Executes tools and then continues the conversation with results
1211
- */
1212
- async handleRemoteToolCalls(toolCalls) {
1213
- // Mark that tool execution is in progress
1214
- this._isOperationInProgress = true;
1215
- const toolRegistry = getToolRegistry();
1216
- const showToolDetails = this.configManager.get('showToolDetails') || false;
1217
- const indent = this.getIndent();
1218
- // Prepare all tool calls
1219
- const preparedToolCalls = toolCalls.map((toolCall, index) => {
1220
- const { name, arguments: params } = toolCall.function;
1221
- let parsedParams;
1222
- try {
1223
- parsedParams = typeof params === 'string' ? JSON.parse(params) : params;
1224
- }
1225
- catch (e) {
1226
- parsedParams = params;
1227
- }
1228
- return { name, params: parsedParams, index };
1229
- });
1230
- // Display all tool calls info
1231
- for (const { name, params } of preparedToolCalls) {
1232
- if (showToolDetails) {
1233
- console.log('');
1234
- console.log(`${indent}${colors.warning(`${icons.tool} Tool Call: ${name}`)}`);
1235
- console.log(`${indent}${colors.textDim(JSON.stringify(params, null, 2))}`);
1236
- }
1237
- else {
1238
- const toolDescription = this.getToolDescription(name, params);
1239
- console.log('');
1240
- console.log(`${indent}${colors.textMuted(`${icons.loading} ${toolDescription}`)}`);
1241
- }
1242
- }
1243
- // Execute all tools in parallel
1244
- const results = await toolRegistry.executeAll(preparedToolCalls.map(tc => ({ name: tc.name, params: tc.params })), this.executionMode);
1245
- // Process results and maintain order
1246
- let hasError = false;
1247
- for (const { tool, result, error } of results) {
1248
- const toolCall = preparedToolCalls.find(tc => tc.name === tool);
1249
- if (!toolCall)
1250
- continue;
1251
- const { params } = toolCall;
1252
- if (error) {
1253
- // Clear the operation flag
1254
- this._isOperationInProgress = false;
1255
- if (error === 'Operation cancelled by user') {
1256
- return;
1257
- }
1258
- hasError = true;
1259
- console.log('');
1260
- console.log(`${indent}${colors.error(`${icons.cross} Tool Error: ${error}`)}`);
1261
- this.conversation.push({
1262
- role: 'tool',
1263
- content: JSON.stringify({ error }),
1264
- timestamp: Date.now()
1265
- });
1266
- }
1267
- else {
1268
- // Use correct indent for gui-subagent tasks
1269
- const isGuiSubagent = tool === 'task' && params?.subagent_type === 'gui-subagent';
1270
- const displayIndent = isGuiSubagent ? indent + ' ' : indent;
1271
- // Always show details for todo tools so users can see their task lists
1272
- const isTodoTool = tool === 'todo_write' || tool === 'todo_read';
1273
- if (isTodoTool) {
1274
- console.log('');
1275
- console.log(`${displayIndent}${colors.success(`${icons.check} Todo List:`)}`);
1276
- console.log(this.renderTodoList(result.todos || result.todos, displayIndent));
1277
- // Show summary if available
1278
- if (result.message) {
1279
- console.log(`${displayIndent}${colors.textDim(result.message)}`);
1280
- }
1281
- }
1282
- else if (showToolDetails) {
1283
- console.log('');
1284
- console.log(`${displayIndent}${colors.success(`${icons.check} Tool Result:`)}`);
1285
- console.log(`${displayIndent}${colors.textDim(JSON.stringify(result, null, 2))}`);
1286
- }
1287
- else if (result.success === false) {
1288
- // GUI task or other tool failed
1289
- console.log(`${displayIndent}${colors.error(`${icons.cross} ${result.message || 'Failed'}`)}`);
1290
- }
1291
- else {
1292
- console.log(`${displayIndent}${colors.success(`${icons.check} Completed`)}`);
1293
- }
1294
- const toolCallRecord = {
1295
- tool,
1296
- params,
1297
- result,
1298
- timestamp: Date.now()
1299
- };
1300
- this.toolCalls.push(toolCallRecord);
1301
- // Record tool output to session manager
1302
- await this.sessionManager.addOutput({
1303
- role: 'tool',
1304
- content: JSON.stringify(result),
1305
- toolName: tool,
1306
- toolParams: params,
1307
- toolResult: result,
1308
- timestamp: Date.now()
1309
- });
1310
- this.conversation.push({
1311
- role: 'tool',
1312
- content: JSON.stringify(result),
1313
- timestamp: Date.now()
1314
- });
1315
- }
1316
- }
1317
- // Logic: Only skip returning results to main agent when user explicitly cancelled (ESC)
1318
- // For all other cases (success, failure, errors), always return results for further processing
1319
- const guiSubagentFailed = preparedToolCalls.some(tc => tc.name === 'task' && tc.params?.subagent_type === 'gui-subagent');
1320
- const guiSubagentCancelled = preparedToolCalls.some(tc => tc.name === 'task' && tc.params?.subagent_type === 'gui-subagent' && results.some(r => r.tool === 'task' && r.result?.cancelled === true));
1321
- // If GUI agent was cancelled by user, don't continue generating response
1322
- // This avoids wasting API calls and tokens on cancelled tasks
1323
- if (guiSubagentCancelled) {
1324
- console.log('');
1325
- console.log(`${indent}${colors.textMuted('GUI task cancelled by user')}`);
1326
- this._isOperationInProgress = false;
1327
- return;
1328
- }
1329
- // If any tool call failed, throw error to mark task as cancelled
1330
- if (hasError) {
1331
- throw new Error('Tool execution failed');
1332
- }
1333
- // For all other cases (GUI success/failure, other tool errors), return results to main agent
1334
- // This allows main agent to decide how to handle failures (retry, fallback, user notification, etc.)
1335
- // Reuse existing taskId instead of generating new one
1336
- await this.generateRemoteResponse(0, this.currentTaskId || undefined);
1337
- }
1338
1360
  /**
1339
1361
  * Truncate path for display
1340
1362
  */