minovative-mind-cli 2.13.3 β 2.13.5
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/README.md +1 -2
- package/dist/commands/chat.d.ts +1 -1
- package/dist/commands/chat.js +1 -2
- package/dist/services/agent/slashCommands.js +0 -16
- package/dist/services/agent/types.d.ts +0 -4
- package/dist/services/agent.d.ts +1 -7
- package/dist/services/agent.js +68 -205
- package/dist/services/ai.d.ts +6 -6
- package/dist/services/ai.js +19 -14
- package/dist/services/contextAgent.js +42 -30
- package/dist/services/orchestration/investigationAgent.js +40 -6
- package/dist/services/orchestration/messageBus.d.ts +1 -1
- package/dist/services/orchestration/messageBus.js +2 -8
- package/dist/services/orchestration/readCache.d.ts +34 -12
- package/dist/services/orchestration/readCache.js +75 -17
- package/dist/services/orchestration/scopedTools.d.ts +4 -2
- package/dist/services/orchestration/scopedTools.js +105 -50
- package/dist/services/orchestration/subAgent.d.ts +1 -0
- package/dist/services/orchestration/subAgent.js +24 -2
- package/dist/services/swebench/sweBenchRunnerService.js +1 -1
- package/dist/utils/localSyntaxValidator.d.ts +29 -2
- package/dist/utils/localSyntaxValidator.js +143 -78
- package/dist/utils/systemPrompts.d.ts +1 -2
- package/dist/utils/systemPrompts.js +6 -34
- package/oclif.manifest.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -137,7 +137,6 @@ Background tasks automatically route to dedicated auxiliary models with native `
|
|
|
137
137
|
| `/config-key` | Configure custom Google AI Studio API key (BYOK mode) |
|
|
138
138
|
| `/profile` | View, inspect, delete, or reset global adaptive persona memory and AI side-notes |
|
|
139
139
|
| `/models` | Hot-swap the active model |
|
|
140
|
-
| `/plan` | Toggle plan mode to review implementation strategies |
|
|
141
140
|
| `/paste` | Multi-line input mode (cancel with Ctrl+C) |
|
|
142
141
|
| `/clear` | Clear conversation history |
|
|
143
142
|
| `/debug` | Expose internal agent diagnostics |
|
|
@@ -165,7 +164,7 @@ Minovative Mind CLI doesn't restrict you to a single repository. You can logical
|
|
|
165
164
|
|
|
166
165
|
## π Supported Languages
|
|
167
166
|
|
|
168
|
-
Minovative Mind CLI fundamentally supports **ALL programming languages** for chat, code generation,
|
|
167
|
+
Minovative Mind CLI fundamentally supports **ALL programming languages** for chat, code generation, and execution, as it relies on Gemini's vast training data.
|
|
169
168
|
|
|
170
169
|
However, the PCV engine features deep, context-aware analysis across **12 major programming language families**. Our core advanced enginesβ**Smart Dependency Tracing**, **Property-Based & Mutation Verification**, **Performance Auditing** (across 9 language families), and **Ephemeral Analysis Scripts**βprovide tailored support depending on the language's syntax and runtime model:
|
|
171
170
|
|
package/dist/commands/chat.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { Command } from '@oclif/core';
|
|
|
9
9
|
export default class DefaultCommand extends Command {
|
|
10
10
|
/**
|
|
11
11
|
* The description displayed in the CLI help output.
|
|
12
|
-
* Details all supported slash commands (/config-key, /profile, /paste, /
|
|
12
|
+
* Details all supported slash commands (/config-key, /profile, /paste, /clear, /models,
|
|
13
13
|
* /debug, /auto-approve, /sub-agents, /stats, /revert, /chats, /workspaces, /commit)
|
|
14
14
|
* along with interactive chat controls.
|
|
15
15
|
*/
|
package/dist/commands/chat.js
CHANGED
|
@@ -18,7 +18,7 @@ import { optimizeWorkspaceIDESettings } from '../services/ideOptimization.js';
|
|
|
18
18
|
export default class DefaultCommand extends Command {
|
|
19
19
|
/**
|
|
20
20
|
* The description displayed in the CLI help output.
|
|
21
|
-
* Details all supported slash commands (/config-key, /profile, /paste, /
|
|
21
|
+
* Details all supported slash commands (/config-key, /profile, /paste, /clear, /models,
|
|
22
22
|
* /debug, /auto-approve, /sub-agents, /stats, /revert, /chats, /workspaces, /commit)
|
|
23
23
|
* along with interactive chat controls.
|
|
24
24
|
*/
|
|
@@ -28,7 +28,6 @@ Inside the chat session, you can use the following commands in the slash menu:
|
|
|
28
28
|
/config-key - BYOK β Configure, clear, or view status of custom Google AI Studio API key
|
|
29
29
|
/profile - View, inspect, delete, or reset global adaptive persona memory and AI side-notes
|
|
30
30
|
/paste - Enter multi-line paste mode for long code snippets and prompts
|
|
31
|
-
/plan - Toggle plan mode to review step-by-step implementation strategies
|
|
32
31
|
/clear - Clear conversation history, reset terminal screen, and display logo
|
|
33
32
|
/models - Select or hot-swap the active Gemini model for the session
|
|
34
33
|
/debug - Toggle internal agent telemetry, diagnostic logging, and execution state
|
|
@@ -27,7 +27,6 @@ import { loadUserProfile, deleteSideNote, clearUserProfile, getUserProfilePath,
|
|
|
27
27
|
* - `/config-key` : Configure, validate, toggle, or clear Bring Your Own Key (BYOK) Google AI Studio API credentials.
|
|
28
28
|
* - `/profile` : View, inspect, delete, or reset global adaptive persona memory and AI side-notes.
|
|
29
29
|
* - `/paste` : Enter multi-line paste mode using EOF tracking (`Ctrl+D` submission).
|
|
30
|
-
* - `/plan` : Toggle AI step-by-step implementation planning mode.
|
|
31
30
|
* - `/clear` : Clear conversation history, wipe terminal screen, and reset CLI header.
|
|
32
31
|
* - `/models` : Hot-swap the active generative AI model (Gemini 3.1 Pro, Gemini 3.7 Flash, Gemini 3.6 Flash, Gemini 3.5 Flash-Lite, Auto routing).
|
|
33
32
|
* - `/debug` : Toggle internal agent telemetry and diagnostic logging.
|
|
@@ -75,19 +74,6 @@ export async function handleSlashCommand(command, context) {
|
|
|
75
74
|
return { shouldContinue: true, isRawPasteMode: false };
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
|
-
/**
|
|
79
|
-
* `/plan` - Toggles step-by-step AI implementation planning mode.
|
|
80
|
-
*/
|
|
81
|
-
if (lowerCommand === '/plan') {
|
|
82
|
-
const newPlanMode = !context.isPlanMode;
|
|
83
|
-
if (newPlanMode) {
|
|
84
|
-
p.log.info(pc.cyan('Plan mode enabled. The AI will formulate a step-by-step plan instead of executing code. Type /plan again to exit.'));
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
p.log.info(pc.cyan('Plan mode disabled. Returning to normal execution.'));
|
|
88
|
-
}
|
|
89
|
-
return { shouldContinue: true, isPlanModeOverride: newPlanMode };
|
|
90
|
-
}
|
|
91
77
|
/**
|
|
92
78
|
* `/clear` - Resets chat conversation history, clears the terminal screen, and reprints CLI header.
|
|
93
79
|
*/
|
|
@@ -226,14 +212,12 @@ export async function handleSlashCommand(command, context) {
|
|
|
226
212
|
}
|
|
227
213
|
const autoApprove = getApprovalMode() === 'skip-all' ? 'Enabled' : 'Disabled';
|
|
228
214
|
const subAgents = isSubAgentsEnabled() ? 'Enabled' : 'Disabled';
|
|
229
|
-
const planMode = context.isPlanMode ? 'Enabled' : 'Disabled';
|
|
230
215
|
const byokEnabled = (await isByokEnabled()) ? 'Enabled' : 'Disabled';
|
|
231
216
|
p.log.step(pc.magenta('π Session Statistics & Status'));
|
|
232
217
|
console.log(pc.dim('----------------------------------------'));
|
|
233
218
|
console.log(`${pc.bold('AI Model:')} ${pc.cyan(displayModel)}`);
|
|
234
219
|
console.log(`${pc.bold('Auto-Approve:')} ${autoApprove === 'Enabled' ? pc.green(autoApprove) : pc.yellow(autoApprove)}`);
|
|
235
220
|
console.log(`${pc.bold('Sub-Agents:')} ${subAgents === 'Enabled' ? pc.green(subAgents) : pc.yellow(subAgents)}`);
|
|
236
|
-
console.log(`${pc.bold('Plan Mode:')} ${planMode === 'Enabled' ? pc.green(planMode) : pc.yellow(planMode)}`);
|
|
237
221
|
console.log(`${pc.bold('BYOK:')} ${byokEnabled === 'Enabled' ? pc.green(byokEnabled) : pc.yellow(byokEnabled)}`);
|
|
238
222
|
const debugMode = isDebugOn() ? 'Enabled' : 'Disabled';
|
|
239
223
|
console.log(`${pc.bold('Debug Log:')} ${debugMode === 'Enabled' ? pc.green(debugMode) : pc.yellow(debugMode)}`);
|
|
@@ -21,8 +21,6 @@ export interface SlashCommandContext {
|
|
|
21
21
|
version: string;
|
|
22
22
|
/** Flag indicating whether raw paste mode is currently enabled. */
|
|
23
23
|
isRawPasteMode: boolean;
|
|
24
|
-
/** Flag indicating whether step-by-step implementation planning mode is currently active. */
|
|
25
|
-
isPlanMode: boolean;
|
|
26
24
|
/** Session state tracking tokens, credits, usage metadata, and model turn counts. */
|
|
27
25
|
chatSessionState: {
|
|
28
26
|
id: string;
|
|
@@ -46,6 +44,4 @@ export interface SlashCommandResult {
|
|
|
46
44
|
userInputOverride?: string;
|
|
47
45
|
/** Optional override flag to enable or disable raw paste mode. */
|
|
48
46
|
isRawPasteMode?: boolean;
|
|
49
|
-
/** Optional override flag to enable or disable implementation planning mode. */
|
|
50
|
-
isPlanModeOverride?: boolean;
|
|
51
47
|
}
|
package/dist/services/agent.d.ts
CHANGED
|
@@ -92,9 +92,6 @@ export declare function startAgentLoop(workspaceRoot: string, version: string):
|
|
|
92
92
|
* @param chat - The active ProxyChatSession instance maintaining message history.
|
|
93
93
|
* @param inputHandler - The AsyncInputHandler instance for managing keyboard interrupts and queueing.
|
|
94
94
|
* @param chatSessionState - Object tracking session statistics, token counts, credit usage, and model metrics.
|
|
95
|
-
* @param isPlanMode - Flag indicating whether plan mode (read-only architecture planning) is active.
|
|
96
|
-
* @param cachedContextResult - Optional pre-gathered context result to bypass duplicate investigation turns.
|
|
97
|
-
* @returns An object containing optional plan mode actions or context results, or void.
|
|
98
95
|
*/
|
|
99
96
|
export declare function executeSingleTurn(workspaceRoot: string, userInput: string, chat: any, inputHandler: AsyncInputHandler, chatSessionState: {
|
|
100
97
|
id: string;
|
|
@@ -106,10 +103,7 @@ export declare function executeSingleTurn(workspaceRoot: string, userInput: stri
|
|
|
106
103
|
latestUsageMetadata?: any;
|
|
107
104
|
previousUsageMetadata?: any;
|
|
108
105
|
modelUsageCounts?: Record<string, number>;
|
|
109
|
-
}
|
|
110
|
-
planModeReturn?: string;
|
|
111
|
-
contextResult?: any;
|
|
112
|
-
} | void>;
|
|
106
|
+
}): Promise<void>;
|
|
113
107
|
/**
|
|
114
108
|
* Raw chat history entry count threshold to trigger chat history summarization.
|
|
115
109
|
* 2 entries = 1 complete conversational user/model turn.
|
package/dist/services/agent.js
CHANGED
|
@@ -25,8 +25,8 @@ import { renderTerminalMarkdown } from '../utils/terminal.js';
|
|
|
25
25
|
const execAsync = promisify(exec);
|
|
26
26
|
import { debugLog, isDebugOn } from '../utils/logger.js';
|
|
27
27
|
import { ensureProjectStorage, ensureIgnored, readCache, writeCache, invalidateCacheForDependents, } from '../utils/projectStorage.js';
|
|
28
|
-
import { GEMINI_MODELS,
|
|
29
|
-
import { createSharedChatSession, getGeneralChatConfig, getPlanExecutionConfig, compressTextUsingFlashLite, generateChatTitle, getGlobalActiveModel,
|
|
28
|
+
import { GEMINI_MODELS, TPM_COOLING_DELAYS } from '../utils/config.js';
|
|
29
|
+
import { createSharedChatSession, getGeneralChatConfig, getPlanExecutionConfig, compressTextUsingFlashLite, generateChatTitle, getGlobalActiveModel, summarizeChatHistory, } from './ai.js';
|
|
30
30
|
import { getAndResetTurnUsage } from './proxyClient.js';
|
|
31
31
|
import { changeLogger } from './changeLogger.js';
|
|
32
32
|
import { chatHistoryService } from './chatHistoryService.js';
|
|
@@ -130,7 +130,6 @@ export async function startAgentLoop(workspaceRoot, version) {
|
|
|
130
130
|
chat.setSessionInfo(chatSessionState.id, workspaceRoot);
|
|
131
131
|
const sessionInputHistory = [];
|
|
132
132
|
let isRawPasteMode = false;
|
|
133
|
-
let isPlanMode = false;
|
|
134
133
|
// Hook process.stdin.emit to intercept fast stream inputs.
|
|
135
134
|
// When large buffers containing newlines arrive rapidly, we interpret them as a clipboard paste,
|
|
136
135
|
// sanitizing and collapsing them to prevent premature command line submission.
|
|
@@ -165,7 +164,7 @@ export async function startAgentLoop(workspaceRoot, version) {
|
|
|
165
164
|
}
|
|
166
165
|
inputHandler.stop();
|
|
167
166
|
// Input collection (delegated to a helper function to avoid nested loop warning)
|
|
168
|
-
const { userInput: rawInput, canceled } = await collectUserInput(sessionInputHistory
|
|
167
|
+
const { userInput: rawInput, canceled } = await collectUserInput(sessionInputHistory);
|
|
169
168
|
if (canceled) {
|
|
170
169
|
p.outro(pc.green('Goodbye! Happy coding. π'));
|
|
171
170
|
return;
|
|
@@ -180,11 +179,6 @@ export async function startAgentLoop(workspaceRoot, version) {
|
|
|
180
179
|
message: 'Command Menu',
|
|
181
180
|
options: [
|
|
182
181
|
{ value: '/models', label: '/models', hint: 'Change the active AI model' },
|
|
183
|
-
{
|
|
184
|
-
value: '/plan',
|
|
185
|
-
label: '/plan',
|
|
186
|
-
hint: `Toggle plan mode (build a plan without executing) ${isPlanMode ? pc.green('(ON)') : pc.red('(OFF)')}`,
|
|
187
|
-
},
|
|
188
182
|
{ value: '/paste', label: '/paste', hint: 'Paste large text directly into the CLI (Press Ctrl+D to submit)' },
|
|
189
183
|
{ value: '/clear', label: '/clear', hint: 'Clear chat session history' },
|
|
190
184
|
{
|
|
@@ -244,16 +238,12 @@ export async function startAgentLoop(workspaceRoot, version) {
|
|
|
244
238
|
workspaceRoot,
|
|
245
239
|
version,
|
|
246
240
|
isRawPasteMode,
|
|
247
|
-
isPlanMode,
|
|
248
241
|
chatSessionState,
|
|
249
242
|
};
|
|
250
243
|
const slashResult = await handleSlashCommand(userInput, slashCtx);
|
|
251
244
|
if (slashResult.isRawPasteMode !== undefined) {
|
|
252
245
|
isRawPasteMode = slashResult.isRawPasteMode;
|
|
253
246
|
}
|
|
254
|
-
if (slashResult.isPlanModeOverride !== undefined) {
|
|
255
|
-
isPlanMode = slashResult.isPlanModeOverride;
|
|
256
|
-
}
|
|
257
247
|
if (slashResult.userInputOverride !== undefined) {
|
|
258
248
|
userInput = slashResult.userInputOverride;
|
|
259
249
|
}
|
|
@@ -262,32 +252,7 @@ export async function startAgentLoop(workspaceRoot, version) {
|
|
|
262
252
|
}
|
|
263
253
|
}
|
|
264
254
|
// βββ Main Execution Cycle ββββββββββββββββββββββββββββββββββββββββ
|
|
265
|
-
|
|
266
|
-
let cachedContextResult = null;
|
|
267
|
-
while (true) {
|
|
268
|
-
const execResult = await executeSingleTurn(workspaceRoot, currentInput, chat, inputHandler, chatSessionState, isPlanMode, cachedContextResult);
|
|
269
|
-
const planModeReturn = execResult?.planModeReturn;
|
|
270
|
-
const contextResult = execResult?.contextResult;
|
|
271
|
-
if (isPlanMode && planModeReturn) {
|
|
272
|
-
if (planModeReturn === 'proceed') {
|
|
273
|
-
isPlanMode = false;
|
|
274
|
-
currentInput = 'Please execute the plan we just finalized.';
|
|
275
|
-
cachedContextResult = contextResult;
|
|
276
|
-
p.log.info(pc.cyan('Proceeding with execution...'));
|
|
277
|
-
continue;
|
|
278
|
-
}
|
|
279
|
-
else if (planModeReturn === 'edit') {
|
|
280
|
-
p.log.info(pc.cyan('Please provide additional instructions to revise the plan.'));
|
|
281
|
-
break;
|
|
282
|
-
}
|
|
283
|
-
else if (planModeReturn === 'exit') {
|
|
284
|
-
isPlanMode = false;
|
|
285
|
-
p.log.info(pc.cyan('Exited plan mode. Returning to normal chat.'));
|
|
286
|
-
break;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
break;
|
|
290
|
-
}
|
|
255
|
+
await executeSingleTurn(workspaceRoot, userInput, chat, inputHandler, chatSessionState);
|
|
291
256
|
}
|
|
292
257
|
}
|
|
293
258
|
/**
|
|
@@ -301,11 +266,8 @@ export async function startAgentLoop(workspaceRoot, version) {
|
|
|
301
266
|
* @param chat - The active ProxyChatSession instance maintaining message history.
|
|
302
267
|
* @param inputHandler - The AsyncInputHandler instance for managing keyboard interrupts and queueing.
|
|
303
268
|
* @param chatSessionState - Object tracking session statistics, token counts, credit usage, and model metrics.
|
|
304
|
-
* @param isPlanMode - Flag indicating whether plan mode (read-only architecture planning) is active.
|
|
305
|
-
* @param cachedContextResult - Optional pre-gathered context result to bypass duplicate investigation turns.
|
|
306
|
-
* @returns An object containing optional plan mode actions or context results, or void.
|
|
307
269
|
*/
|
|
308
|
-
export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHandler, chatSessionState
|
|
270
|
+
export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHandler, chatSessionState) {
|
|
309
271
|
return runWithAgentId('main', async () => {
|
|
310
272
|
const { resetTurnAccumulator } = await import('./metrics.js');
|
|
311
273
|
resetTurnAccumulator();
|
|
@@ -324,71 +286,67 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
324
286
|
if (ac.signal.aborted)
|
|
325
287
|
return;
|
|
326
288
|
// Stage 0: Summarize chat history if length threshold is met
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
spinner.stop();
|
|
338
|
-
}
|
|
289
|
+
const isDebug = isDebugOn();
|
|
290
|
+
if (!inputHandler.isCurrentlyPrompting() && !isDebug) {
|
|
291
|
+
spinner.start('Checking conversation history...');
|
|
292
|
+
}
|
|
293
|
+
const historySummarized = await summarizeHistoryIfNeeded(chat, ac.signal);
|
|
294
|
+
if (historySummarized) {
|
|
295
|
+
debugLog('Chat history was summarized and compressed prior to context investigation.');
|
|
296
|
+
}
|
|
297
|
+
if (!inputHandler.isCurrentlyPrompting() && !isDebug) {
|
|
298
|
+
spinner.stop();
|
|
339
299
|
}
|
|
340
300
|
if (ac.signal.aborted)
|
|
341
301
|
return;
|
|
342
302
|
// Stage 1: Gather Workspace Context and route intentions
|
|
343
303
|
spinner.start('π Investigating workspace...');
|
|
344
|
-
let gatherRes = { targetAgent: 'EXECUTE', chainedMessages: []
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
spinner.message(`π Investigating workspace... ${pc.dim(msg)}`);
|
|
355
|
-
}
|
|
356
|
-
}, (toolMsg, label) => {
|
|
357
|
-
const formattedLog = `${pc.dim(`[${label}]`)} ${toolMsg}`;
|
|
358
|
-
toolLogs.push(formattedLog);
|
|
359
|
-
if (!inputHandler.isCurrentlyPrompting()) {
|
|
360
|
-
spinner.message(`π Investigating workspace... ${formattedLog}`);
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
catch (gatherErr) {
|
|
365
|
-
spinner.stop();
|
|
366
|
-
process.stdout.write('\x1b[2K\r');
|
|
367
|
-
if (ac.signal.aborted || gatherErr?.name === 'AbortError' || gatherErr?.message?.includes('abort')) {
|
|
368
|
-
return;
|
|
304
|
+
let gatherRes = { targetAgent: 'EXECUTE', chainedMessages: [] };
|
|
305
|
+
const collector = getMetricCollector();
|
|
306
|
+
if (collector)
|
|
307
|
+
collector.startTimer('contextGather');
|
|
308
|
+
const chatHistory = chat.getRecentHistory(3);
|
|
309
|
+
const toolLogs = [];
|
|
310
|
+
try {
|
|
311
|
+
gatherRes = await gatherContext(workspaceRoot, userInput, chatHistory, inputHandler, ac.signal, (msg) => {
|
|
312
|
+
if (!inputHandler.isCurrentlyPrompting()) {
|
|
313
|
+
spinner.message(`π Investigating workspace... ${pc.dim(msg)}`);
|
|
369
314
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
toolLogs.forEach((log) => p.log.step(log));
|
|
383
|
-
spinner.start(`π Context gathered successfully.`);
|
|
384
|
-
}
|
|
385
|
-
// Post-investigation cooling-off delay to allow API Tokens-Per-Minute (TPM) sliding window to settle
|
|
386
|
-
await new Promise((resolve) => setTimeout(resolve, TPM_COOLING_DELAYS.POST_INVESTIGATION_MS));
|
|
387
|
-
if (ac.signal.aborted) {
|
|
388
|
-
spinner.stop();
|
|
389
|
-
process.stdout.write('\x1b[2K\r');
|
|
315
|
+
}, (toolMsg, label) => {
|
|
316
|
+
const formattedLog = `${pc.dim(`[${label}]`)} ${toolMsg}`;
|
|
317
|
+
toolLogs.push(formattedLog);
|
|
318
|
+
if (!inputHandler.isCurrentlyPrompting()) {
|
|
319
|
+
spinner.message(`π Investigating workspace... ${formattedLog}`);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
catch (gatherErr) {
|
|
324
|
+
spinner.stop();
|
|
325
|
+
process.stdout.write('\x1b[2K\r');
|
|
326
|
+
if (ac.signal.aborted || gatherErr?.name === 'AbortError' || gatherErr?.message?.includes('abort')) {
|
|
390
327
|
return;
|
|
391
328
|
}
|
|
329
|
+
throw gatherErr;
|
|
330
|
+
}
|
|
331
|
+
if (collector)
|
|
332
|
+
collector.stopTimer('contextGather');
|
|
333
|
+
if (ac.signal.aborted) {
|
|
334
|
+
spinner.stop();
|
|
335
|
+
process.stdout.write('\x1b[2K\r');
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
// Print all collected logs at once to prevent flickering, while spinner is stopped
|
|
339
|
+
if (toolLogs.length > 0) {
|
|
340
|
+
spinner.stop();
|
|
341
|
+
toolLogs.forEach((log) => p.log.step(log));
|
|
342
|
+
spinner.start(`π Context gathered successfully.`);
|
|
343
|
+
}
|
|
344
|
+
// Post-investigation cooling-off delay to allow API Tokens-Per-Minute (TPM) sliding window to settle
|
|
345
|
+
await new Promise((resolve) => setTimeout(resolve, TPM_COOLING_DELAYS.POST_INVESTIGATION_MS));
|
|
346
|
+
if (ac.signal.aborted) {
|
|
347
|
+
spinner.stop();
|
|
348
|
+
process.stdout.write('\x1b[2K\r');
|
|
349
|
+
return;
|
|
392
350
|
}
|
|
393
351
|
let latestUsage = undefined;
|
|
394
352
|
// Collect any inputs that were queued while the Context Agent was investigating
|
|
@@ -427,21 +385,12 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
427
385
|
}
|
|
428
386
|
// Hot-swap the underlying LLM system instruction context depending on intent (conversational vs execution)
|
|
429
387
|
debugLog(`Intent Router output: original targetAgent = ${gatherRes.targetAgent}, effective = ${effectiveTargetAgent}`);
|
|
430
|
-
|
|
431
|
-
if (isPlanMode) {
|
|
432
|
-
const { getPlanModeConfig } = await import('./ai.js');
|
|
433
|
-
config = getPlanModeConfig();
|
|
434
|
-
}
|
|
435
|
-
else {
|
|
436
|
-
config = effectiveTargetAgent === 'CHAT' ? getGeneralChatConfig() : getPlanExecutionConfig();
|
|
437
|
-
}
|
|
388
|
+
const config = effectiveTargetAgent === 'CHAT' ? getGeneralChatConfig() : getPlanExecutionConfig();
|
|
438
389
|
let dynamicSystemInstruction = config.systemInstruction;
|
|
439
390
|
// Inject gathered workspace directories, dependency configurations, and matching search patterns
|
|
440
391
|
if (gatherRes.contextResult) {
|
|
441
392
|
// Compress each relevant file individually using helper to avoid nested loop warning
|
|
442
|
-
|
|
443
|
-
gatherRes.contextResult.relevantFiles = await compressContextFiles(workspaceRoot, gatherRes.contextResult, ac.signal);
|
|
444
|
-
}
|
|
393
|
+
gatherRes.contextResult.relevantFiles = await compressContextFiles(workspaceRoot, gatherRes.contextResult, ac.signal);
|
|
445
394
|
// Assemble the final context injection string
|
|
446
395
|
const contextInjection = buildContextInjection(gatherRes.contextResult);
|
|
447
396
|
debugLog(`Final compressed context injection size: ${contextInjection.length} chars`);
|
|
@@ -510,7 +459,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
510
459
|
gitBranch = stdout.trim();
|
|
511
460
|
}
|
|
512
461
|
catch { }
|
|
513
|
-
if (
|
|
462
|
+
if (effectiveTargetAgent === 'EXECUTE' && isSubAgentsEnabled()) {
|
|
514
463
|
spinner.stop(); // Clear the spinner before delegating
|
|
515
464
|
inputHandler.clearSpinner(); // Prevent prompt from reviving the old spinner
|
|
516
465
|
process.stdout.write('\x1b[2K\r');
|
|
@@ -673,7 +622,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
673
622
|
const calls = result.response.functionCalls();
|
|
674
623
|
debugLog(`Initial functionCalls: ${calls && calls.length > 0 ? JSON.stringify(calls) : 'None'}`);
|
|
675
624
|
// Stage 2: Recursive Tool Loops and Automated Self-Correction (delegated to a helper function to avoid nested loop warning)
|
|
676
|
-
const correctionRes = await executeSelfCorrectionLoop(chat, result, workspaceRoot, inputHandler, effectiveTargetAgent, ac.signal, spinner, userInput
|
|
625
|
+
const correctionRes = await executeSelfCorrectionLoop(chat, result, workspaceRoot, inputHandler, effectiveTargetAgent, ac.signal, spinner, userInput);
|
|
677
626
|
const finalText = correctionRes.finalText;
|
|
678
627
|
inputHandler.stop();
|
|
679
628
|
// Update latest usage metadata to reflect all completed turns
|
|
@@ -685,8 +634,9 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
685
634
|
if (modifiedFiles.length > 0) {
|
|
686
635
|
await invalidateCacheForDependents(workspaceRoot, modifiedFiles);
|
|
687
636
|
}
|
|
637
|
+
let cleanFinalText = '';
|
|
688
638
|
if (finalText) {
|
|
689
|
-
|
|
639
|
+
cleanFinalText = finalText.replace(/\[TASK_FINISHED\]/g, '').trim();
|
|
690
640
|
if (cleanFinalText) {
|
|
691
641
|
console.log(`\n${pc.blue('β')} ${pc.bold('Minovative Mind')} ${pc.dim(`(${chat.getModel()})`)}\n`);
|
|
692
642
|
console.log(renderTerminalMarkdown(cleanFinalText));
|
|
@@ -824,93 +774,6 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
824
774
|
})
|
|
825
775
|
.catch((e) => debugLog('Failed to auto-save session: ' + e));
|
|
826
776
|
}
|
|
827
|
-
let planModeReturn = undefined;
|
|
828
|
-
if (isPlanMode && finalText && finalText !== '[Generation stopped.]') {
|
|
829
|
-
inputHandler.stop(); // MUST stop the async input handler before showing an interactive prompt, or it will intercept stdin and freeze/duplicate
|
|
830
|
-
// Ensure the terminal has fully scrolled and there is a clean line break
|
|
831
|
-
console.log('\n');
|
|
832
|
-
// Small delay to allow stdout to flush and terminal to finish scrolling from the markdown output
|
|
833
|
-
// This prevents @clack/prompts from miscalculating the cursor position and duplicating the prompt on arrow keys
|
|
834
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
835
|
-
while (true) {
|
|
836
|
-
const currentModel = getGlobalActiveModel();
|
|
837
|
-
const planAction = await p['select']({
|
|
838
|
-
message: 'Plan generated. What would you like to do?',
|
|
839
|
-
options: [
|
|
840
|
-
{ value: 'proceed', label: 'Proceed with plan', hint: 'Executes the generated plan immediately' },
|
|
841
|
-
{ value: 'edit', label: 'Edit plan', hint: 'Provide additional feedback to revise the plan' },
|
|
842
|
-
{
|
|
843
|
-
value: 'choose_model',
|
|
844
|
-
label: 'Choose AI model',
|
|
845
|
-
hint: `Change the active AI model (Current: ${currentModel})`,
|
|
846
|
-
},
|
|
847
|
-
{ value: 'exit', label: 'Exit plan mode', hint: 'Return to normal chat without executing' },
|
|
848
|
-
],
|
|
849
|
-
});
|
|
850
|
-
if (planAction === 'choose_model') {
|
|
851
|
-
const byokEnabled = await isByokEnabled();
|
|
852
|
-
const options = [
|
|
853
|
-
// {
|
|
854
|
-
// value: 'claude-opus-5',
|
|
855
|
-
// label: 'Claude 5 Opus',
|
|
856
|
-
// hint: 'For hardcore & complex problems',
|
|
857
|
-
// },
|
|
858
|
-
{
|
|
859
|
-
value: 'gemini-3.1-pro-preview',
|
|
860
|
-
label: 'Gemini 3.1 Pro',
|
|
861
|
-
hint: 'For hardcore & complex problems',
|
|
862
|
-
},
|
|
863
|
-
// {
|
|
864
|
-
// value: 'claude-sonnet-5',
|
|
865
|
-
// label: 'Claude 5 Sonnet',
|
|
866
|
-
// hint: 'Best for raw speed and cost efficiency',
|
|
867
|
-
// },
|
|
868
|
-
{
|
|
869
|
-
value: 'gemini-3.7-flash',
|
|
870
|
-
label: 'Gemini 3.7 Flash',
|
|
871
|
-
hint: 'Next-gen reasoning, speed & balanced performance',
|
|
872
|
-
},
|
|
873
|
-
{
|
|
874
|
-
value: 'gemini-3.6-flash',
|
|
875
|
-
label: 'Gemini 3.6 Flash',
|
|
876
|
-
hint: 'Everyday coding β fast and accurate',
|
|
877
|
-
},
|
|
878
|
-
{
|
|
879
|
-
value: 'gemini-3.5-flash-lite',
|
|
880
|
-
label: 'Gemini 3.5 Flash-Lite',
|
|
881
|
-
hint: 'Best for raw speed and cost efficiency',
|
|
882
|
-
},
|
|
883
|
-
{
|
|
884
|
-
value: 'auto',
|
|
885
|
-
label: 'Auto (Flash-Lite / Flash)',
|
|
886
|
-
hint: 'Dynamically routes between Gemini 3.5 Flash-Lite and Gemini 3.7 Flash based on prompt complexity',
|
|
887
|
-
},
|
|
888
|
-
].filter((o) => !(byokEnabled && o.value.includes('claude')));
|
|
889
|
-
const selectedModel = await p['select']({
|
|
890
|
-
message: `Select AI Model (Current: ${pc.cyan(currentModel)})`,
|
|
891
|
-
initialValue: currentModel,
|
|
892
|
-
options: options,
|
|
893
|
-
});
|
|
894
|
-
if (!p.isCancel(selectedModel)) {
|
|
895
|
-
chat.setModel(selectedModel);
|
|
896
|
-
setGlobalActiveModel(selectedModel);
|
|
897
|
-
p.log.success(`Model successfully switched to ${pc.cyan(selectedModel)}`);
|
|
898
|
-
}
|
|
899
|
-
continue;
|
|
900
|
-
}
|
|
901
|
-
if (p.isCancel(planAction) || planAction === 'exit') {
|
|
902
|
-
planModeReturn = 'exit';
|
|
903
|
-
}
|
|
904
|
-
else if (planAction === 'edit') {
|
|
905
|
-
planModeReturn = 'edit';
|
|
906
|
-
}
|
|
907
|
-
else if (planAction === 'proceed') {
|
|
908
|
-
planModeReturn = 'proceed';
|
|
909
|
-
}
|
|
910
|
-
break;
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
return { planModeReturn, contextResult: gatherRes.contextResult };
|
|
914
777
|
}
|
|
915
778
|
catch (err) {
|
|
916
779
|
if (ac.signal.aborted || err?.name === 'AbortError' || err?.message?.includes('abort')) {
|
|
@@ -931,12 +794,12 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
931
794
|
}
|
|
932
795
|
});
|
|
933
796
|
}
|
|
934
|
-
async function collectUserInput(history
|
|
797
|
+
async function collectUserInput(history) {
|
|
935
798
|
let lines = [];
|
|
936
799
|
let isMultiLine = false;
|
|
937
800
|
while (true) {
|
|
938
801
|
const userInputRaw = await historyText({
|
|
939
|
-
message: isMultiLine ? ' ' :
|
|
802
|
+
message: isMultiLine ? ' ' : pc.magenta('β―'),
|
|
940
803
|
placeholder: isMultiLine ? '' : 'Use ' + String.fromCharCode(92) + ' for new lines',
|
|
941
804
|
history,
|
|
942
805
|
});
|
|
@@ -1075,7 +938,7 @@ export async function summarizeHistoryIfNeeded(chat, abortSignal) {
|
|
|
1075
938
|
}
|
|
1076
939
|
return false;
|
|
1077
940
|
}
|
|
1078
|
-
async function executeSelfCorrectionLoop(chat, initialResult, workspaceRoot, inputHandler, effectiveTargetAgent, signal, spinner, originalUserInput
|
|
941
|
+
async function executeSelfCorrectionLoop(chat, initialResult, workspaceRoot, inputHandler, effectiveTargetAgent, signal, spinner, originalUserInput) {
|
|
1079
942
|
let correctionAttempts = 0;
|
|
1080
943
|
const MAX_CORRECTIONS = 5;
|
|
1081
944
|
let result = initialResult;
|
|
@@ -1141,7 +1004,7 @@ async function executeSelfCorrectionLoop(chat, initialResult, workspaceRoot, inp
|
|
|
1141
1004
|
}
|
|
1142
1005
|
previousChangeCount = currentChanges.length;
|
|
1143
1006
|
// βββ Tool-Based Intent Verification βββββββββββββββββββββββββββββββββ
|
|
1144
|
-
if (effectiveTargetAgent === 'EXECUTE' && !intentVerified
|
|
1007
|
+
if (effectiveTargetAgent === 'EXECUTE' && !intentVerified) {
|
|
1145
1008
|
if (!currentText.includes('[TASK_FINISHED]')) {
|
|
1146
1009
|
p.log.warn(pc.yellow('AI paused execution without calling finish_task. Prompting to continue or finish...'));
|
|
1147
1010
|
const finishReminder = `SYSTEM CHECK: You stopped without calling the \`finish_task\` tool.
|
package/dist/services/ai.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Content, type FunctionCall } from '@google/generative-ai';
|
|
2
|
+
export declare function getMultiWorkspaceBlock(): string;
|
|
2
3
|
export declare function setModelOverride(agent: 'context' | 'execution', overrideStr: string): void;
|
|
3
4
|
export declare function clearModelOverrides(): void;
|
|
4
5
|
export declare function setGlobalActiveModel(model: string): void;
|
|
@@ -9,11 +10,14 @@ export declare class ProxyChatSession {
|
|
|
9
10
|
private modelName;
|
|
10
11
|
private systemInstruction;
|
|
11
12
|
private tools;
|
|
13
|
+
private toolConfig?;
|
|
12
14
|
private generationConfig;
|
|
13
15
|
private latestUsageMetadata;
|
|
14
|
-
constructor(modelName: string, systemInstruction: string, tools: any[], generationConfig: any);
|
|
16
|
+
constructor(modelName: string, systemInstruction: string, tools: any[], generationConfig: any, toolConfig?: any);
|
|
15
17
|
getLatestUsageMetadata(): any;
|
|
16
|
-
setAgentConfig(systemInstruction: string, tools: any[]): void;
|
|
18
|
+
setAgentConfig(systemInstruction: string, tools: any[], toolConfig?: any): void;
|
|
19
|
+
setToolConfig(toolConfig?: any): void;
|
|
20
|
+
getToolConfig(): any;
|
|
17
21
|
setModel(modelName: string): void;
|
|
18
22
|
getModel(): string;
|
|
19
23
|
clearHistory(): void;
|
|
@@ -91,10 +95,6 @@ export declare function getPlanExecutionConfig(): {
|
|
|
91
95
|
functionDeclarations: import("@google/generative-ai").FunctionDeclaration[];
|
|
92
96
|
}[];
|
|
93
97
|
};
|
|
94
|
-
export declare function getPlanModeConfig(): {
|
|
95
|
-
systemInstruction: string;
|
|
96
|
-
tools: never[];
|
|
97
|
-
};
|
|
98
98
|
/**
|
|
99
99
|
* Compresses a large string of text using Gemini Flash.
|
|
100
100
|
* Used for shrinking context payloads to prevent OOM/choking.
|