@defai.digital/ax-cli 4.3.6 → 4.3.9

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 (93) hide show
  1. package/README.md +113 -36
  2. package/dist/agent/subagent-types.js +15 -14
  3. package/dist/agent/subagent-types.js.map +1 -1
  4. package/dist/checkpoint/manager.js +10 -5
  5. package/dist/checkpoint/manager.js.map +1 -1
  6. package/dist/checkpoint/storage.js.map +1 -1
  7. package/dist/checkpoint/types.d.ts +1 -1
  8. package/dist/commands/doctor.js.map +1 -1
  9. package/dist/commands/mcp.js.map +1 -1
  10. package/dist/commands/memory.js +12 -11
  11. package/dist/commands/memory.js.map +1 -1
  12. package/dist/commands/models.js +67 -22
  13. package/dist/commands/models.js.map +1 -1
  14. package/dist/commands/plan.js +18 -32
  15. package/dist/commands/plan.js.map +1 -1
  16. package/dist/commands/status.js +9 -5
  17. package/dist/commands/status.js.map +1 -1
  18. package/dist/commands/templates.js +7 -6
  19. package/dist/commands/templates.js.map +1 -1
  20. package/dist/commands/update.js +30 -28
  21. package/dist/commands/update.js.map +1 -1
  22. package/dist/commands/usage.js +135 -16
  23. package/dist/commands/usage.js.map +1 -1
  24. package/dist/constants.d.ts +17 -0
  25. package/dist/constants.js +21 -0
  26. package/dist/constants.js.map +1 -1
  27. package/dist/hooks/manager.js +4 -0
  28. package/dist/hooks/manager.js.map +1 -1
  29. package/dist/index.js +19 -6
  30. package/dist/index.js.map +1 -1
  31. package/dist/llm/client.d.ts +11 -1
  32. package/dist/llm/client.js +48 -19
  33. package/dist/llm/client.js.map +1 -1
  34. package/dist/llm/tools.js +6 -5
  35. package/dist/llm/tools.js.map +1 -1
  36. package/dist/llm/types.d.ts +34 -10
  37. package/dist/llm/types.js +8 -1
  38. package/dist/llm/types.js.map +1 -1
  39. package/dist/mcp/automatosx-loader.d.ts +4 -4
  40. package/dist/mcp/automatosx-loader.js +2 -1
  41. package/dist/mcp/automatosx-loader.js.map +1 -1
  42. package/dist/mcp/client-v2.d.ts +4 -2
  43. package/dist/mcp/client-v2.js +30 -16
  44. package/dist/mcp/client-v2.js.map +1 -1
  45. package/dist/mcp/client.d.ts +2 -2
  46. package/dist/mcp/config-detector.d.ts +6 -6
  47. package/dist/mcp/config-detector.js +25 -20
  48. package/dist/mcp/config-detector.js.map +1 -1
  49. package/dist/mcp/config-migrator.d.ts +6 -6
  50. package/dist/mcp/config-migrator.js +14 -12
  51. package/dist/mcp/config-migrator.js.map +1 -1
  52. package/dist/mcp/error-formatter.d.ts +1 -1
  53. package/dist/mcp/error-formatter.js.map +1 -1
  54. package/dist/mcp/health.js.map +1 -1
  55. package/dist/mcp/invariants.d.ts +1 -1
  56. package/dist/mcp/invariants.js.map +1 -1
  57. package/dist/mcp/reconnection.js +41 -38
  58. package/dist/mcp/reconnection.js.map +1 -1
  59. package/dist/mcp/registry.js.map +1 -1
  60. package/dist/mcp/type-safety.d.ts +4 -15
  61. package/dist/mcp/type-safety.js +0 -12
  62. package/dist/mcp/type-safety.js.map +1 -1
  63. package/dist/memory/context-generator.js +19 -9
  64. package/dist/memory/context-generator.js.map +1 -1
  65. package/dist/planner/plan-storage.js +22 -29
  66. package/dist/planner/plan-storage.js.map +1 -1
  67. package/dist/provider/config.d.ts +58 -0
  68. package/dist/provider/config.js +180 -7
  69. package/dist/provider/config.js.map +1 -1
  70. package/dist/schemas/yaml-schemas.d.ts +34 -0
  71. package/dist/schemas/yaml-schemas.js +34 -0
  72. package/dist/schemas/yaml-schemas.js.map +1 -1
  73. package/dist/sdk/index.js.map +1 -1
  74. package/dist/sdk/testing.d.ts +16 -18
  75. package/dist/sdk/testing.js +0 -22
  76. package/dist/sdk/testing.js.map +1 -1
  77. package/dist/tools/ax-agent.js +4 -0
  78. package/dist/tools/ax-agent.js.map +1 -1
  79. package/dist/tools/priority-registry.d.ts +124 -0
  80. package/dist/tools/priority-registry.js +401 -0
  81. package/dist/tools/priority-registry.js.map +1 -0
  82. package/dist/tools/priority.d.ts +158 -0
  83. package/dist/tools/priority.js +350 -0
  84. package/dist/tools/priority.js.map +1 -0
  85. package/dist/ui/hooks/use-input-handler.js +101 -32
  86. package/dist/ui/hooks/use-input-handler.js.map +1 -1
  87. package/dist/utils/config-loader.d.ts +17 -0
  88. package/dist/utils/config-loader.js.map +1 -1
  89. package/dist/utils/history-manager.js +7 -5
  90. package/dist/utils/history-manager.js.map +1 -1
  91. package/dist/utils/settings-manager.js +4 -1
  92. package/dist/utils/settings-manager.js.map +1 -1
  93. package/package.json +1 -1
@@ -0,0 +1,350 @@
1
+ /**
2
+ * Tool Priority System
3
+ *
4
+ * Defines priority levels and capability types for intelligent tool selection.
5
+ * When multiple tools can handle the same task, the system prefers higher-priority tools.
6
+ *
7
+ * Priority Order:
8
+ * 1. Native API capabilities (e.g., Grok's built-in search)
9
+ * 2. Provider-specific MCP (e.g., Z.AI MCP for GLM)
10
+ * 3. Domain-specific MCP (e.g., Figma MCP for design)
11
+ * 4. Official MCP servers
12
+ * 5. Community MCP servers
13
+ * 6. General-purpose MCP (e.g., AutomatosX)
14
+ * 7. Built-in tools (fallback)
15
+ */
16
+ /**
17
+ * Priority levels for tool selection
18
+ * Higher values = higher priority = preferred tool
19
+ */
20
+ export var ToolPriority;
21
+ (function (ToolPriority) {
22
+ /** Built into provider API (highest priority) */
23
+ ToolPriority[ToolPriority["NATIVE_API"] = 100] = "NATIVE_API";
24
+ /** Provider-specific MCP (e.g., Z.AI for GLM) */
25
+ ToolPriority[ToolPriority["PROVIDER_MCP"] = 80] = "PROVIDER_MCP";
26
+ /** Domain-specific MCP (e.g., Figma for design) */
27
+ ToolPriority[ToolPriority["DOMAIN_SPECIFIC"] = 60] = "DOMAIN_SPECIFIC";
28
+ /** Official MCP servers (e.g., @modelcontextprotocol/*) */
29
+ ToolPriority[ToolPriority["OFFICIAL_MCP"] = 40] = "OFFICIAL_MCP";
30
+ /** Community MCP servers */
31
+ ToolPriority[ToolPriority["COMMUNITY_MCP"] = 20] = "COMMUNITY_MCP";
32
+ /** General-purpose MCP (e.g., AutomatosX) */
33
+ ToolPriority[ToolPriority["GENERAL_MCP"] = 10] = "GENERAL_MCP";
34
+ /** Built-in ax-cli tools (fallback) */
35
+ ToolPriority[ToolPriority["BUILTIN_TOOL"] = 5] = "BUILTIN_TOOL";
36
+ })(ToolPriority || (ToolPriority = {}));
37
+ /**
38
+ * Priority boost applied when a server has affinity for the current provider.
39
+ * This ensures provider-affinity servers beat same-level servers without affinity.
40
+ */
41
+ export const PROVIDER_AFFINITY_BOOST = 10;
42
+ /**
43
+ * Minimum priority difference required to consider a capability superseded.
44
+ * Prevents minor priority differences from hiding useful tools.
45
+ */
46
+ export const SUPERSEDE_THRESHOLD = 15;
47
+ /**
48
+ * Delimiters used to separate base names from variant suffixes.
49
+ * e.g., 'grok-beta' uses '-', 'automatosx_glm' uses '_'
50
+ */
51
+ export const VARIANT_DELIMITERS = ['-', '_'];
52
+ /**
53
+ * Prefix used for virtual native capability tool names.
54
+ * e.g., 'native_web-search' represents Grok's native search capability
55
+ */
56
+ export const NATIVE_CAPABILITY_PREFIX = 'native_';
57
+ /**
58
+ * Check if a name starts with a base name followed by a variant delimiter.
59
+ * Used to match variant names like 'grok-beta' to base name 'grok'.
60
+ *
61
+ * @param fullName - The full name to check (e.g., 'grok-beta')
62
+ * @param baseName - The base name to match against (e.g., 'grok')
63
+ * @returns True if fullName is a variant of baseName
64
+ */
65
+ export function isVariantOf(fullName, baseName) {
66
+ return VARIANT_DELIMITERS.some(delimiter => fullName.startsWith(baseName + delimiter));
67
+ }
68
+ /**
69
+ * Native capabilities built into provider APIs
70
+ * These don't require MCP - they're part of the API itself
71
+ */
72
+ export const PROVIDER_NATIVE_CAPABILITIES = {
73
+ grok: ['web-search'], // Grok has native live search via API
74
+ glm: [], // GLM uses Z.AI MCP for web search
75
+ claude: [], // Claude has no native search in API
76
+ openai: [], // OpenAI standard API has no search
77
+ gemini: ['web-search'], // Gemini has grounding/search
78
+ };
79
+ /**
80
+ * Known MCP server capability registry
81
+ * Add new servers here as they become available
82
+ */
83
+ export const MCP_CAPABILITY_REGISTRY = [
84
+ // ========================================
85
+ // Z.AI MCP Servers (Provider-specific for GLM)
86
+ // ========================================
87
+ {
88
+ serverName: 'zai-web-search',
89
+ capabilities: ['web-search'],
90
+ priority: ToolPriority.PROVIDER_MCP,
91
+ providerAffinity: ['glm'],
92
+ },
93
+ {
94
+ serverName: 'zai-web-reader',
95
+ capabilities: ['web-fetch'],
96
+ priority: ToolPriority.PROVIDER_MCP,
97
+ providerAffinity: ['glm'],
98
+ },
99
+ {
100
+ serverName: 'zai-vision',
101
+ capabilities: ['vision'],
102
+ priority: ToolPriority.PROVIDER_MCP,
103
+ providerAffinity: ['glm'],
104
+ },
105
+ // ========================================
106
+ // Domain-Specific MCPs
107
+ // ========================================
108
+ {
109
+ serverName: 'figma',
110
+ capabilities: ['design-figma', 'design-general'],
111
+ priority: ToolPriority.DOMAIN_SPECIFIC,
112
+ },
113
+ // ========================================
114
+ // Official MCP Servers
115
+ // ========================================
116
+ {
117
+ serverName: 'github',
118
+ capabilities: ['git-operations'],
119
+ priority: ToolPriority.OFFICIAL_MCP,
120
+ isOfficial: true,
121
+ },
122
+ {
123
+ serverName: 'postgres',
124
+ capabilities: ['database'],
125
+ priority: ToolPriority.OFFICIAL_MCP,
126
+ isOfficial: true,
127
+ },
128
+ {
129
+ serverName: 'sqlite',
130
+ capabilities: ['database'],
131
+ priority: ToolPriority.OFFICIAL_MCP,
132
+ isOfficial: true,
133
+ },
134
+ {
135
+ serverName: 'puppeteer',
136
+ // Note: Puppeteer is primarily for browser automation and testing.
137
+ // It can fetch web content but via a full browser, which is heavyweight.
138
+ // Don't mark as 'web-fetch' to avoid superseding lightweight HTTP fetchers.
139
+ capabilities: ['testing'],
140
+ priority: ToolPriority.OFFICIAL_MCP,
141
+ isOfficial: true,
142
+ },
143
+ // ========================================
144
+ // Community MCPs
145
+ // ========================================
146
+ {
147
+ serverName: 'vercel',
148
+ capabilities: ['deployment'],
149
+ priority: ToolPriority.COMMUNITY_MCP,
150
+ },
151
+ {
152
+ serverName: 'netlify',
153
+ capabilities: ['deployment'],
154
+ priority: ToolPriority.COMMUNITY_MCP,
155
+ },
156
+ {
157
+ serverName: 'supabase',
158
+ capabilities: ['database'],
159
+ priority: ToolPriority.COMMUNITY_MCP,
160
+ },
161
+ {
162
+ serverName: 'firebase',
163
+ capabilities: ['database', 'deployment'],
164
+ priority: ToolPriority.COMMUNITY_MCP,
165
+ },
166
+ {
167
+ serverName: 'sentry',
168
+ capabilities: ['monitoring'],
169
+ priority: ToolPriority.COMMUNITY_MCP,
170
+ },
171
+ // ========================================
172
+ // General-Purpose MCPs (lowest priority)
173
+ // ========================================
174
+ {
175
+ serverName: 'automatosx',
176
+ capabilities: ['web-search', 'web-fetch', 'memory', 'agent-delegation'],
177
+ priority: ToolPriority.GENERAL_MCP,
178
+ },
179
+ ];
180
+ /**
181
+ * Cached lowercase server name index for O(1) exact lookups.
182
+ * Maps lowercase server name to its MCPCapabilityMapping.
183
+ */
184
+ const serverNameIndex = new Map(MCP_CAPABILITY_REGISTRY.map(mapping => [mapping.serverName.toLowerCase(), mapping]));
185
+ /**
186
+ * Pre-computed lowercase server names sorted by length (longest first).
187
+ * Used for efficient variant matching.
188
+ */
189
+ const sortedServerNames = MCP_CAPABILITY_REGISTRY
190
+ .map(mapping => mapping.serverName.toLowerCase())
191
+ .sort((a, b) => b.length - a.length);
192
+ /**
193
+ * Pre-computed capability to servers index for O(1) capability lookups.
194
+ * Maps capability to array of servers that provide it.
195
+ */
196
+ const capabilityIndex = new Map();
197
+ for (const mapping of MCP_CAPABILITY_REGISTRY) {
198
+ for (const capability of mapping.capabilities) {
199
+ let servers = capabilityIndex.get(capability);
200
+ if (!servers) {
201
+ servers = [];
202
+ capabilityIndex.set(capability, servers);
203
+ }
204
+ servers.push(mapping);
205
+ }
206
+ }
207
+ /**
208
+ * Get capability mapping for a server by name.
209
+ * Supports exact matches and variant matches (e.g., 'automatosx-glm' matches 'automatosx').
210
+ * Case-insensitive matching for robustness.
211
+ *
212
+ * @param serverName - The server name to look up (may include variant suffix)
213
+ * @returns The capability mapping, or undefined if not found
214
+ */
215
+ export function getServerCapabilityMapping(serverName) {
216
+ const normalizedName = serverName.toLowerCase();
217
+ // O(1) exact match lookup
218
+ const exactMatch = serverNameIndex.get(normalizedName);
219
+ if (exactMatch) {
220
+ return exactMatch;
221
+ }
222
+ // Variant match - find longest matching base name
223
+ for (const baseName of sortedServerNames) {
224
+ if (isVariantOf(normalizedName, baseName)) {
225
+ return serverNameIndex.get(baseName);
226
+ }
227
+ }
228
+ return undefined;
229
+ }
230
+ /**
231
+ * List of known provider names derived from PROVIDER_NATIVE_CAPABILITIES.
232
+ * Used for flexible provider name matching.
233
+ */
234
+ const KNOWN_PROVIDERS = Object.keys(PROVIDER_NATIVE_CAPABILITIES);
235
+ /**
236
+ * Get the base provider name from a potentially variant provider string.
237
+ * e.g., 'grok-beta' -> 'grok', 'glm-4' -> 'glm', 'openai' -> 'openai'
238
+ *
239
+ * @param providerName - The provider name (may include variant suffix)
240
+ * @returns The base provider name, or undefined if not recognized
241
+ */
242
+ function getBaseProviderName(providerName) {
243
+ const normalizedName = providerName.toLowerCase();
244
+ for (const knownProvider of KNOWN_PROVIDERS) {
245
+ if (normalizedName === knownProvider || isVariantOf(normalizedName, knownProvider)) {
246
+ return knownProvider;
247
+ }
248
+ }
249
+ return undefined;
250
+ }
251
+ /**
252
+ * Check if a provider has native support for a capability.
253
+ * Supports provider variants (e.g., 'grok-beta' matches 'grok' native capabilities)
254
+ *
255
+ * @param providerName - The provider name (may include variant suffix)
256
+ * @param capability - The capability to check
257
+ * @returns True if the provider natively supports the capability
258
+ */
259
+ export function hasNativeCapability(providerName, capability) {
260
+ const baseProvider = getBaseProviderName(providerName);
261
+ if (!baseProvider) {
262
+ return false;
263
+ }
264
+ return PROVIDER_NATIVE_CAPABILITIES[baseProvider].includes(capability);
265
+ }
266
+ /**
267
+ * Check if a provider matches a base provider name.
268
+ * e.g., 'grok-beta' matches 'grok', 'glm-4' matches 'glm'
269
+ *
270
+ * @param providerName - The provider name to check (may include variant suffix)
271
+ * @param baseProvider - The base provider to match against
272
+ * @returns True if the provider matches the base provider
273
+ */
274
+ export function providerMatches(providerName, baseProvider) {
275
+ return getBaseProviderName(providerName) === baseProvider;
276
+ }
277
+ /**
278
+ * Get the priority for a server, considering provider affinity.
279
+ *
280
+ * @param serverName - The MCP server name
281
+ * @param providerName - Optional provider name for affinity boosting
282
+ * @returns The priority value (higher = more preferred)
283
+ */
284
+ export function getServerPriority(serverName, providerName) {
285
+ const mapping = getServerCapabilityMapping(serverName);
286
+ if (!mapping) {
287
+ // Unknown server - assign community priority
288
+ return ToolPriority.COMMUNITY_MCP;
289
+ }
290
+ // Boost priority if this server has affinity for the current provider
291
+ if (providerName && mapping.providerAffinity?.some(affinity => providerMatches(providerName, affinity))) {
292
+ return mapping.priority + PROVIDER_AFFINITY_BOOST;
293
+ }
294
+ return mapping.priority;
295
+ }
296
+ /**
297
+ * Check if a server should be preferred for a given capability and provider.
298
+ *
299
+ * A server is preferred if:
300
+ * 1. The provider does NOT have native support for this capability, AND
301
+ * 2. Either:
302
+ * a. It has provider affinity for the current provider, OR
303
+ * b. It has the highest priority among all servers providing this capability
304
+ *
305
+ * Note: If the provider has native capability support, NO MCP server should be preferred.
306
+ *
307
+ * @param serverName - The MCP server name
308
+ * @param capability - The capability to check
309
+ * @param providerName - The current provider name
310
+ * @returns True if the server should be preferred for this capability
311
+ */
312
+ export function shouldPreferServer(serverName, capability, providerName) {
313
+ const mapping = getServerCapabilityMapping(serverName);
314
+ if (!mapping)
315
+ return false;
316
+ // Check if server provides this capability
317
+ if (!mapping.capabilities.includes(capability))
318
+ return false;
319
+ // If the provider has native support for this capability, no MCP server should be preferred
320
+ if (hasNativeCapability(providerName, capability)) {
321
+ return false;
322
+ }
323
+ // Check if server has affinity for this provider
324
+ if (mapping.providerAffinity?.some(affinity => providerMatches(providerName, affinity))) {
325
+ return true;
326
+ }
327
+ // Even without affinity, check if this server has the highest priority for this capability
328
+ const serversForCapability = getServersForCapability(capability, providerName);
329
+ const topServer = serversForCapability[0];
330
+ if (topServer && topServer.serverName.toLowerCase() === serverName.toLowerCase()) {
331
+ return true;
332
+ }
333
+ return false;
334
+ }
335
+ /**
336
+ * Get all servers that provide a given capability, sorted by priority.
337
+ *
338
+ * @param capability - The capability to search for
339
+ * @param providerName - Optional provider name for affinity-based priority boosting
340
+ * @returns Array of server mappings sorted by priority (highest first)
341
+ */
342
+ export function getServersForCapability(capability, providerName) {
343
+ const servers = capabilityIndex.get(capability);
344
+ if (!servers?.length) {
345
+ return [];
346
+ }
347
+ // Clone and sort to avoid mutating the cached array
348
+ return [...servers].sort((a, b) => getServerPriority(b.serverName, providerName) - getServerPriority(a.serverName, providerName));
349
+ }
350
+ //# sourceMappingURL=priority.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"priority.js","sourceRoot":"","sources":["../../src/tools/priority.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ import { getSettingsManager } from "../../utils/settings-manager.js";
9
9
  import { ProjectAnalyzer } from "../../utils/project-analyzer.js";
10
10
  import { InstructionGenerator } from "../../utils/instruction-generator.js";
11
11
  import { getUsageTracker } from "../../utils/usage-tracker.js";
12
+ import { getActiveProvider } from "../../provider/config.js";
12
13
  import { getHistoryManager } from "../../utils/history-manager.js";
13
14
  import { handleRewindCommand, handleCheckpointsCommand, handleCheckpointCleanCommand } from "../../commands/rewind.js";
14
15
  import { handlePlansCommand, handlePlanCommand, handlePhasesCommand, handlePauseCommand, handleResumeCommand, handleSkipPhaseCommand, handleAbandonCommand, handleResumableCommand, } from "../../commands/plan.js";
@@ -550,7 +551,7 @@ onLargePaste, onPasteTruncated, onKeyboardHelp, onMcpDashboardToggle, onThinking
550
551
  if (trimmedInput === "/retry") {
551
552
  // Find the last user message index and re-send it
552
553
  // Use findLastIndex instead of reverse().find() + lastIndexOf() to avoid object reference issues
553
- const lastUserIndex = chatHistory.findLastIndex(entry => entry.type === "user");
554
+ const lastUserIndex = chatHistory.findLastIndex((entry) => entry.type === "user");
554
555
  if (lastUserIndex >= 0 && chatHistory[lastUserIndex]?.content) {
555
556
  // Store the message content and history state before clearing
556
557
  const messageToRetry = chatHistory[lastUserIndex].content;
@@ -562,9 +563,13 @@ onLargePaste, onPasteTruncated, onKeyboardHelp, onMcpDashboardToggle, onThinking
562
563
  // Track timeout for cleanup on unmount
563
564
  retryTimeoutRef.current = setTimeout(() => {
564
565
  retryTimeoutRef.current = null;
565
- // Call async function and handle promise rejection
566
- handleInputSubmit(messageToRetry).catch(() => {
567
- // Restore history if retry fails
566
+ // BUG FIX: Properly handle async errors with explicit Promise chain
567
+ // The catch must be attached immediately to prevent unhandled rejection
568
+ void handleInputSubmit(messageToRetry).catch((error) => {
569
+ // Log error for debugging, then restore history
570
+ if (process.env.DEBUG || process.env.AX_DEBUG) {
571
+ console.error('Retry failed:', error);
572
+ }
568
573
  setChatHistory(historyBackup);
569
574
  });
570
575
  }, 50);
@@ -798,9 +803,14 @@ Examples:
798
803
  if (trimmedInput === "/usage") {
799
804
  const tracker = getUsageTracker();
800
805
  const stats = tracker.getSessionStats();
801
- let usageContent = "📊 **API Usage & Limits (Z.AI)**\n\n";
806
+ const provider = getActiveProvider();
807
+ const isGrok = provider.name === 'grok';
808
+ const currentModel = getSettingsManager().getCurrentModel() || provider.defaultModel;
809
+ const providerName = isGrok ? 'xAI (Grok)' : 'Z.AI (GLM)';
810
+ let usageContent = `📊 **API Usage & Limits (${providerName})**\n\n`;
802
811
  // Session statistics
803
812
  usageContent += "**📱 Current Session:**\n";
813
+ usageContent += ` • Model: ${currentModel}\n`;
804
814
  if (stats.totalRequests === 0) {
805
815
  usageContent += " No API requests made yet. Ask me something to start tracking!\n";
806
816
  }
@@ -819,29 +829,87 @@ Examples:
819
829
  }
820
830
  }
821
831
  }
822
- // Z.AI account information
823
- usageContent += `\n**🔑 Z.AI Account Usage & Limits:**\n`;
824
- usageContent += ` ⚠️ API does not provide programmatic access to usage data\n`;
825
- usageContent += `\n **Check your account:**\n`;
826
- usageContent += ` Billing & Usage: https://z.ai/manage-apikey/billing\n`;
827
- usageContent += ` • Rate Limits: https://z.ai/manage-apikey/rate-limits\n`;
828
- usageContent += ` • API Keys: https://z.ai/manage-apikey/apikey-list\n`;
829
- usageContent += `\n**ℹ️ Notes:**\n`;
830
- usageContent += ` • Billing reflects previous day (n-1) consumption\n`;
831
- usageContent += ` • Current day usage may not be immediately visible\n`;
832
- usageContent += ` • Cached content: 1/5 of original price\n`;
833
- usageContent += `\n**💰 GLM-4.6 Pricing:**\n`;
834
- usageContent += ` • Input: $0.11 per 1M tokens\n`;
835
- usageContent += ` • Output: $0.28 per 1M tokens\n`;
836
- if (stats.totalRequests > 0) {
837
- // Calculate estimated cost for this session
838
- const inputCost = (stats.totalPromptTokens / 1000000) * 0.11;
839
- const outputCost = (stats.totalCompletionTokens / 1000000) * 0.28;
840
- const totalCost = inputCost + outputCost;
841
- usageContent += `\n**💵 Estimated Session Cost:**\n`;
842
- usageContent += ` • Input: $${inputCost.toFixed(6)} (${stats.totalPromptTokens.toLocaleString()} tokens)\n`;
843
- usageContent += ` • Output: $${outputCost.toFixed(6)} (${stats.totalCompletionTokens.toLocaleString()} tokens)\n`;
844
- usageContent += ` • **Total: ~$${totalCost.toFixed(6)}**\n`;
832
+ if (isGrok) {
833
+ // xAI/Grok account information
834
+ usageContent += `\n**🔑 xAI Account Usage & Limits:**\n`;
835
+ usageContent += ` ⚠️ API does not provide programmatic access to usage data\n`;
836
+ usageContent += `\n **Check your account:**\n`;
837
+ usageContent += ` • Usage Explorer: https://console.x.ai\n`;
838
+ usageContent += ` • Billing & Team: https://console.x.ai/team\n`;
839
+ usageContent += ` • API Keys: https://console.x.ai/api-keys\n`;
840
+ usageContent += `\n**ℹ️ Notes:**\n`;
841
+ usageContent += ` • Usage is tracked in real-time on the xAI console\n`;
842
+ usageContent += ` • Cached input tokens: 75% discount\n`;
843
+ // Grok pricing based on model
844
+ const modelLower = currentModel.toLowerCase();
845
+ if (modelLower.includes('grok-4.1-fast')) {
846
+ usageContent += `\n**💰 Grok 4.1 Fast Pricing:**\n`;
847
+ usageContent += ` • Input: $0.20 per 1M tokens\n`;
848
+ usageContent += ` • Output: $0.50 per 1M tokens\n`;
849
+ }
850
+ else if (modelLower.includes('grok-4')) {
851
+ usageContent += `\n**💰 Grok 4 Pricing:**\n`;
852
+ usageContent += ` • Input: $3.00 per 1M tokens\n`;
853
+ usageContent += ` • Output: $15.00 per 1M tokens\n`;
854
+ usageContent += ` • Cached: $0.75 per 1M tokens\n`;
855
+ }
856
+ else if (modelLower.includes('grok-3-mini')) {
857
+ usageContent += `\n**💰 Grok 3 Mini Pricing:**\n`;
858
+ usageContent += ` • Input: $0.30 per 1M tokens\n`;
859
+ usageContent += ` • Output: $0.50 per 1M tokens\n`;
860
+ }
861
+ else {
862
+ usageContent += `\n**💰 Grok 3 Pricing:**\n`;
863
+ usageContent += ` • Input: $3.00 per 1M tokens\n`;
864
+ usageContent += ` • Output: $15.00 per 1M tokens\n`;
865
+ usageContent += ` • Cached: $0.75 per 1M tokens\n`;
866
+ }
867
+ if (stats.totalRequests > 0) {
868
+ // Calculate estimated cost based on model
869
+ let inputRate = 3.0, outputRate = 15.0;
870
+ if (modelLower.includes('grok-4.1-fast')) {
871
+ inputRate = 0.20;
872
+ outputRate = 0.50;
873
+ }
874
+ else if (modelLower.includes('grok-3-mini')) {
875
+ inputRate = 0.30;
876
+ outputRate = 0.50;
877
+ }
878
+ const inputCost = (stats.totalPromptTokens / 1000000) * inputRate;
879
+ const outputCost = (stats.totalCompletionTokens / 1000000) * outputRate;
880
+ const totalCost = inputCost + outputCost;
881
+ usageContent += `\n**💵 Estimated Session Cost:**\n`;
882
+ usageContent += ` • Input: $${inputCost.toFixed(6)} (${stats.totalPromptTokens.toLocaleString()} tokens)\n`;
883
+ usageContent += ` • Output: $${outputCost.toFixed(6)} (${stats.totalCompletionTokens.toLocaleString()} tokens)\n`;
884
+ usageContent += ` • **Total: ~$${totalCost.toFixed(6)}**\n`;
885
+ }
886
+ }
887
+ else {
888
+ // Z.AI/GLM account information
889
+ usageContent += `\n**🔑 Z.AI Account Usage & Limits:**\n`;
890
+ usageContent += ` ⚠️ API does not provide programmatic access to usage data\n`;
891
+ usageContent += `\n **Check your account:**\n`;
892
+ usageContent += ` • Billing & Usage: https://z.ai/manage-apikey/billing\n`;
893
+ usageContent += ` • Rate Limits: https://z.ai/manage-apikey/rate-limits\n`;
894
+ usageContent += ` • API Keys: https://z.ai/manage-apikey/apikey-list\n`;
895
+ usageContent += `\n**ℹ️ Notes:**\n`;
896
+ usageContent += ` • Billing reflects previous day (n-1) consumption\n`;
897
+ usageContent += ` • Current day usage may not be immediately visible\n`;
898
+ usageContent += ` • Cached content: 1/5 of original price\n`;
899
+ usageContent += `\n**💰 GLM-4.6 Pricing:**\n`;
900
+ usageContent += ` • Input: $2.00 per 1M tokens\n`;
901
+ usageContent += ` • Output: $10.00 per 1M tokens\n`;
902
+ usageContent += ` • Cached: $0.50 per 1M tokens\n`;
903
+ if (stats.totalRequests > 0) {
904
+ // Calculate estimated cost for this session
905
+ const inputCost = (stats.totalPromptTokens / 1000000) * 2.0;
906
+ const outputCost = (stats.totalCompletionTokens / 1000000) * 10.0;
907
+ const totalCost = inputCost + outputCost;
908
+ usageContent += `\n**💵 Estimated Session Cost:**\n`;
909
+ usageContent += ` • Input: $${inputCost.toFixed(6)} (${stats.totalPromptTokens.toLocaleString()} tokens)\n`;
910
+ usageContent += ` • Output: $${outputCost.toFixed(6)} (${stats.totalCompletionTokens.toLocaleString()} tokens)\n`;
911
+ usageContent += ` • **Total: ~$${totalCost.toFixed(6)}**\n`;
912
+ }
845
913
  }
846
914
  const usageEntry = {
847
915
  type: "assistant",
@@ -862,7 +930,7 @@ Examples:
862
930
  };
863
931
  setChatHistory((prev) => [...prev, doctorEntry]);
864
932
  // Execute doctor command asynchronously (non-blocking)
865
- void (async () => {
933
+ (async () => {
866
934
  try {
867
935
  const { exec } = await import("child_process");
868
936
  const { promisify } = await import("util");
@@ -1033,7 +1101,7 @@ Examples:
1033
1101
  };
1034
1102
  setChatHistory((prev) => [...prev, userEntry]);
1035
1103
  // Execute the prompt asynchronously
1036
- void (async () => {
1104
+ (async () => {
1037
1105
  try {
1038
1106
  const manager = getMCPManager();
1039
1107
  const v2 = manager.getV2Instance();
@@ -1871,7 +1939,8 @@ Respond with ONLY the commit message, no additional text.`;
1871
1939
  "mv",
1872
1940
  "rm",
1873
1941
  ];
1874
- const firstWord = trimmedInput.split(" ")[0];
1942
+ // BUG FIX: Added fallback for empty input to prevent undefined access
1943
+ const firstWord = trimmedInput.split(" ")[0] || "";
1875
1944
  if (directBashCommands.includes(firstWord)) {
1876
1945
  const userEntry = {
1877
1946
  type: "user",
@@ -1942,7 +2011,7 @@ Respond with ONLY the commit message, no additional text.`;
1942
2011
  const imageInfo = imageResult.images.map((img, i) => formatAttachmentForDisplay(img, i + 1)).join('\n');
1943
2012
  const infoEntry = {
1944
2013
  type: "assistant",
1945
- content: `📷 Processing ${imageResult.images.length} image(s):\n${imageInfo}\n\n*Using glm-4.5v for vision analysis*`,
2014
+ content: `📷 Processing ${imageResult.images.length} image(s):\n${imageInfo}\n\n*Auto-switching to vision model for analysis*`,
1946
2015
  timestamp: new Date(),
1947
2016
  };
1948
2017
  setChatHistory((prev) => [...prev, infoEntry]);