minovative-mind-cli 2.5.2 → 2.6.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.
- package/README.md +29 -26
- package/dist/commands/chat.js +2 -2
- package/dist/services/agent/inputHandler.d.ts +9 -0
- package/dist/services/agent/inputHandler.js +34 -0
- package/dist/services/agent/slashCommands.js +105 -29
- package/dist/services/agent/syntaxAgent.d.ts +40 -0
- package/dist/services/agent/syntaxAgent.js +237 -23
- package/dist/services/agent/toolLoop.js +10 -1
- package/dist/services/agent/types.d.ts +1 -0
- package/dist/services/agent-tools.d.ts +156 -1
- package/dist/services/agent-tools.js +259 -67
- package/dist/services/agent.d.ts +74 -0
- package/dist/services/agent.js +193 -31
- package/dist/services/ai.d.ts +5 -0
- package/dist/services/ai.js +80 -87
- package/dist/services/chatHistoryService.d.ts +11 -0
- package/dist/services/chatHistoryService.js +20 -1
- package/dist/services/contextAgent.d.ts +1 -1
- package/dist/services/contextAgent.js +9 -29
- package/dist/services/orchestration/investigationAgent.d.ts +2 -1
- package/dist/services/orchestration/investigationAgent.js +7 -2
- package/dist/services/orchestration/investigationOrchestrator.d.ts +1 -1
- package/dist/services/orchestration/investigationOrchestrator.js +13 -2
- package/dist/services/orchestration/orchestrator.js +21 -4
- package/dist/services/orchestration/subAgent.d.ts +2 -1
- package/dist/services/orchestration/subAgent.js +12 -6
- package/dist/utils/analysisRunner.d.ts +27 -4
- package/dist/utils/analysisRunner.js +100 -20
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.js +2 -0
- package/dist/utils/fuzzyMatch.d.ts +32 -0
- package/dist/utils/fuzzyMatch.js +215 -27
- package/dist/utils/localSyntaxValidator.d.ts +2 -2
- package/dist/utils/localSyntaxValidator.js +280 -81
- package/dist/utils/performanceAuditor.d.ts +2 -7
- package/dist/utils/performanceAuditor.js +541 -89
- package/dist/utils/projectStorage.js +9 -0
- package/dist/utils/systemPrompts.d.ts +3 -2
- package/dist/utils/systemPrompts.js +29 -5
- package/oclif.manifest.json +2 -2
- package/package.json +1 -1
package/dist/services/agent.d.ts
CHANGED
|
@@ -48,13 +48,61 @@ export { AsyncInputHandler } from './agent/inputHandler.js';
|
|
|
48
48
|
* @param workspaceRoot - The relative or absolute path representing the active workspace environment.
|
|
49
49
|
* @param version - The Semantic Version string of the active tool distribution.
|
|
50
50
|
*/
|
|
51
|
+
/**
|
|
52
|
+
* Starts and orchestrates the primary interactive command-line interface (REPL) loop.
|
|
53
|
+
*
|
|
54
|
+
* This is the central control loop of the CLI application. It runs indefinitely until
|
|
55
|
+
* the user explicitly issues an exit directive (e.g., typing "exit", "quit", `/` command menu selections,
|
|
56
|
+
* or using keyboard breaks like Ctrl+C).
|
|
57
|
+
*
|
|
58
|
+
* ### Architectural Pipeline:
|
|
59
|
+
* 1. **User Input Collection**:
|
|
60
|
+
* - Captures multiline text strings by checking for trailing backslash characters (`\`).
|
|
61
|
+
* - Prevents visual terminal glitches during multi-line typing on varying themes.
|
|
62
|
+
* - Automatically handles command menu redirection when users enter a forward slash (`/`).
|
|
63
|
+
* - Intercepts and filters OS clipboard paste buffers to allow inserting massive scripts cleanly.
|
|
64
|
+
*
|
|
65
|
+
* 2. **Slash Commands Processing**:
|
|
66
|
+
* - Delegated to `handleSlashCommand` within `src/services/agent/slashCommands.ts`.
|
|
67
|
+
*
|
|
68
|
+
* 3. **Workspace Context Gathering & Intention Routing**:
|
|
69
|
+
* - Leverages the Context Agent (`gatherContext`) to perform exploratory scans of the active repository.
|
|
70
|
+
* - Identifies user intention to hot-swap system prompt strategies (`CHAT` for conversational assistance vs. `EXECUTE` for multi-turn modifications).
|
|
71
|
+
* - Compresses gathered repo structures and file contents using high-speed Flash-Lite engines to respect context boundaries and budget costs.
|
|
72
|
+
*
|
|
73
|
+
* 4. **Model Execution & Self-Correction Feedback Loop**:
|
|
74
|
+
* - Passes the target request to Gemini alongside compressed workspace injections.
|
|
75
|
+
* - Recursively processes tool invocations via `processResponse`.
|
|
76
|
+
* - Runs static validation checks (`verifyChangedFiles`) against mutated files to check for compiler/linter bugs.
|
|
77
|
+
* - If files fail validation, enters a self-healing loop by submitting raw diagnostic errors directly back to the AI for remediation.
|
|
78
|
+
*
|
|
79
|
+
* @param workspaceRoot - The relative or absolute path representing the active workspace environment.
|
|
80
|
+
* @param version - The Semantic Version string of the active tool distribution.
|
|
81
|
+
* @returns A promise that resolves when the agent loop terminates.
|
|
82
|
+
*/
|
|
51
83
|
export declare function startAgentLoop(workspaceRoot: string, version: string): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Executes a single conversational or execution turn with the AI agent.
|
|
86
|
+
*
|
|
87
|
+
* Handles context gathering, model routing (Auto vs Flash vs Flash-Lite), orchestrator delegation
|
|
88
|
+
* (if sub-agents are active), tool execution loops, verification, and session auto-saving.
|
|
89
|
+
*
|
|
90
|
+
* @param workspaceRoot - The absolute or relative path to the root of the active workspace.
|
|
91
|
+
* @param userInput - The prompt or instruction entered by the user.
|
|
92
|
+
* @param chat - The active ProxyChatSession instance maintaining message history.
|
|
93
|
+
* @param inputHandler - The AsyncInputHandler instance for managing keyboard interrupts and queueing.
|
|
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
|
+
*/
|
|
52
99
|
export declare function executeSingleTurn(workspaceRoot: string, userInput: string, chat: any, inputHandler: AsyncInputHandler, chatSessionState: {
|
|
53
100
|
id: string;
|
|
54
101
|
title: string;
|
|
55
102
|
totalTokens: number;
|
|
56
103
|
totalInputTokens: number;
|
|
57
104
|
totalOutputTokens: number;
|
|
105
|
+
totalCreditsUsed: number;
|
|
58
106
|
latestUsageMetadata?: any;
|
|
59
107
|
previousUsageMetadata?: any;
|
|
60
108
|
modelUsageCounts?: Record<string, number>;
|
|
@@ -62,3 +110,29 @@ export declare function executeSingleTurn(workspaceRoot: string, userInput: stri
|
|
|
62
110
|
planModeReturn?: string;
|
|
63
111
|
contextResult?: any;
|
|
64
112
|
} | void>;
|
|
113
|
+
/**
|
|
114
|
+
* Raw chat history entry count threshold to trigger chat history summarization.
|
|
115
|
+
* 12 entries = 6 conversational user/model turns.
|
|
116
|
+
*/
|
|
117
|
+
export declare const HISTORY_SUMMARIZATION_THRESHOLD = 12;
|
|
118
|
+
/**
|
|
119
|
+
* Checks and summarizes older chat history entries if the active session's history
|
|
120
|
+
* exceeds HISTORY_SUMMARIZATION_THRESHOLD entries.
|
|
121
|
+
*
|
|
122
|
+
* Preserves the most recent 4 entries (2 turns) intact for conversational continuity,
|
|
123
|
+
* replacing all preceding turns with a single summarized pair in the chat history.
|
|
124
|
+
*
|
|
125
|
+
* @param chat - The active ProxyChatSession instance.
|
|
126
|
+
* @returns True if history was summarized and updated; false otherwise.
|
|
127
|
+
*/
|
|
128
|
+
/**
|
|
129
|
+
* Summarizes older chat history entries if the active session's history
|
|
130
|
+
* exceeds {@link HISTORY_SUMMARIZATION_THRESHOLD} entries.
|
|
131
|
+
*
|
|
132
|
+
* Preserves the most recent 4 entries (2 turns) intact for conversational continuity,
|
|
133
|
+
* replacing all preceding turns with a single summarized pair in the chat history.
|
|
134
|
+
*
|
|
135
|
+
* @param chat - The active ProxyChatSession instance.
|
|
136
|
+
* @returns A promise resolving to true if history was summarized and updated; false otherwise.
|
|
137
|
+
*/
|
|
138
|
+
export declare function summarizeHistoryIfNeeded(chat: any): Promise<boolean>;
|
package/dist/services/agent.js
CHANGED
|
@@ -26,8 +26,8 @@ import { markedTerminal } from 'marked-terminal';
|
|
|
26
26
|
const execAsync = promisify(exec);
|
|
27
27
|
import { debugLog, isDebugOn } from '../utils/logger.js';
|
|
28
28
|
import { ensureProjectStorage, ensureIgnored, readCache, writeCache, invalidateCacheForDependents, } from '../utils/projectStorage.js';
|
|
29
|
-
import { GEMINI_MODELS } from '../utils/config.js';
|
|
30
|
-
import { createSharedChatSession, getGeneralChatConfig, getPlanExecutionConfig, compressTextUsingFlashLite, generateChatTitle, getGlobalActiveModel, setGlobalActiveModel, } from './ai.js';
|
|
29
|
+
import { GEMINI_MODELS, isByokEnabled } from '../utils/config.js';
|
|
30
|
+
import { createSharedChatSession, getGeneralChatConfig, getPlanExecutionConfig, compressTextUsingFlashLite, generateChatTitle, getGlobalActiveModel, setGlobalActiveModel, summarizeChatHistory, } from './ai.js';
|
|
31
31
|
import { getAndResetTurnUsage } from './proxyClient.js';
|
|
32
32
|
import { changeLogger } from './changeLogger.js';
|
|
33
33
|
import { chatHistoryService } from './chatHistoryService.js';
|
|
@@ -77,6 +77,38 @@ export { AsyncInputHandler } from './agent/inputHandler.js';
|
|
|
77
77
|
* @param workspaceRoot - The relative or absolute path representing the active workspace environment.
|
|
78
78
|
* @param version - The Semantic Version string of the active tool distribution.
|
|
79
79
|
*/
|
|
80
|
+
/**
|
|
81
|
+
* Starts and orchestrates the primary interactive command-line interface (REPL) loop.
|
|
82
|
+
*
|
|
83
|
+
* This is the central control loop of the CLI application. It runs indefinitely until
|
|
84
|
+
* the user explicitly issues an exit directive (e.g., typing "exit", "quit", `/` command menu selections,
|
|
85
|
+
* or using keyboard breaks like Ctrl+C).
|
|
86
|
+
*
|
|
87
|
+
* ### Architectural Pipeline:
|
|
88
|
+
* 1. **User Input Collection**:
|
|
89
|
+
* - Captures multiline text strings by checking for trailing backslash characters (`\`).
|
|
90
|
+
* - Prevents visual terminal glitches during multi-line typing on varying themes.
|
|
91
|
+
* - Automatically handles command menu redirection when users enter a forward slash (`/`).
|
|
92
|
+
* - Intercepts and filters OS clipboard paste buffers to allow inserting massive scripts cleanly.
|
|
93
|
+
*
|
|
94
|
+
* 2. **Slash Commands Processing**:
|
|
95
|
+
* - Delegated to `handleSlashCommand` within `src/services/agent/slashCommands.ts`.
|
|
96
|
+
*
|
|
97
|
+
* 3. **Workspace Context Gathering & Intention Routing**:
|
|
98
|
+
* - Leverages the Context Agent (`gatherContext`) to perform exploratory scans of the active repository.
|
|
99
|
+
* - Identifies user intention to hot-swap system prompt strategies (`CHAT` for conversational assistance vs. `EXECUTE` for multi-turn modifications).
|
|
100
|
+
* - Compresses gathered repo structures and file contents using high-speed Flash-Lite engines to respect context boundaries and budget costs.
|
|
101
|
+
*
|
|
102
|
+
* 4. **Model Execution & Self-Correction Feedback Loop**:
|
|
103
|
+
* - Passes the target request to Gemini alongside compressed workspace injections.
|
|
104
|
+
* - Recursively processes tool invocations via `processResponse`.
|
|
105
|
+
* - Runs static validation checks (`verifyChangedFiles`) against mutated files to check for compiler/linter bugs.
|
|
106
|
+
* - If files fail validation, enters a self-healing loop by submitting raw diagnostic errors directly back to the AI for remediation.
|
|
107
|
+
*
|
|
108
|
+
* @param workspaceRoot - The relative or absolute path representing the active workspace environment.
|
|
109
|
+
* @param version - The Semantic Version string of the active tool distribution.
|
|
110
|
+
* @returns A promise that resolves when the agent loop terminates.
|
|
111
|
+
*/
|
|
80
112
|
export async function startAgentLoop(workspaceRoot, version) {
|
|
81
113
|
// Initialize project-level storage and ensure it is safely ignored from version control
|
|
82
114
|
ensureProjectStorage(workspaceRoot);
|
|
@@ -92,6 +124,7 @@ export async function startAgentLoop(workspaceRoot, version) {
|
|
|
92
124
|
totalTokens: 0,
|
|
93
125
|
totalInputTokens: 0,
|
|
94
126
|
totalOutputTokens: 0,
|
|
127
|
+
totalCreditsUsed: 0,
|
|
95
128
|
modelUsageCounts: {},
|
|
96
129
|
};
|
|
97
130
|
chat.setSessionInfo(chatSessionState.id, workspaceRoot);
|
|
@@ -114,6 +147,8 @@ export async function startAgentLoop(workspaceRoot, version) {
|
|
|
114
147
|
}
|
|
115
148
|
return originalEmit(event, ...args);
|
|
116
149
|
};
|
|
150
|
+
// Add space at the bottom to prevent terminal UI flickering when the cursor is at the absolute bottom
|
|
151
|
+
process.stdout.write('\n\n\n\x1b[3A');
|
|
117
152
|
console.log(pc.dim('\nType your coding request below. Type "exit" or "quit" to leave.\n'));
|
|
118
153
|
while (true) {
|
|
119
154
|
if (chat.getRawHistory().length === 0 && chatSessionState.title !== '') {
|
|
@@ -122,6 +157,7 @@ export async function startAgentLoop(workspaceRoot, version) {
|
|
|
122
157
|
chatSessionState.totalTokens = 0;
|
|
123
158
|
chatSessionState.totalInputTokens = 0;
|
|
124
159
|
chatSessionState.totalOutputTokens = 0;
|
|
160
|
+
chatSessionState.totalCreditsUsed = 0;
|
|
125
161
|
chatSessionState.modelUsageCounts = {};
|
|
126
162
|
chatSessionState.latestUsageMetadata = undefined;
|
|
127
163
|
chatSessionState.previousUsageMetadata = undefined;
|
|
@@ -171,7 +207,7 @@ export async function startAgentLoop(workspaceRoot, version) {
|
|
|
171
207
|
label: '/workspaces',
|
|
172
208
|
hint: 'Manage external workspaces for cross-project development',
|
|
173
209
|
},
|
|
174
|
-
{ value: '/config-key', label: '/config-key', hint: 'BYOK
|
|
210
|
+
{ value: '/config-key', label: '/config-key', hint: 'BYOK — Use your own Google AI Studio API key' },
|
|
175
211
|
{ value: '/stats', label: '/stats', hint: 'View current session statistics and configuration' },
|
|
176
212
|
{ value: '/commit', label: '/commit', hint: 'Auto-commit changes with AI message' },
|
|
177
213
|
{ value: '/revert', label: '/revert', hint: 'Undo last change' },
|
|
@@ -253,6 +289,21 @@ export async function startAgentLoop(workspaceRoot, version) {
|
|
|
253
289
|
}
|
|
254
290
|
}
|
|
255
291
|
}
|
|
292
|
+
/**
|
|
293
|
+
* Executes a single conversational or execution turn with the AI agent.
|
|
294
|
+
*
|
|
295
|
+
* Handles context gathering, model routing (Auto vs Flash vs Flash-Lite), orchestrator delegation
|
|
296
|
+
* (if sub-agents are active), tool execution loops, verification, and session auto-saving.
|
|
297
|
+
*
|
|
298
|
+
* @param workspaceRoot - The absolute or relative path to the root of the active workspace.
|
|
299
|
+
* @param userInput - The prompt or instruction entered by the user.
|
|
300
|
+
* @param chat - The active ProxyChatSession instance maintaining message history.
|
|
301
|
+
* @param inputHandler - The AsyncInputHandler instance for managing keyboard interrupts and queueing.
|
|
302
|
+
* @param chatSessionState - Object tracking session statistics, token counts, credit usage, and model metrics.
|
|
303
|
+
* @param isPlanMode - Flag indicating whether plan mode (read-only architecture planning) is active.
|
|
304
|
+
* @param cachedContextResult - Optional pre-gathered context result to bypass duplicate investigation turns.
|
|
305
|
+
* @returns An object containing optional plan mode actions or context results, or void.
|
|
306
|
+
*/
|
|
256
307
|
export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHandler, chatSessionState, isPlanMode, cachedContextResult) {
|
|
257
308
|
return runWithAgentId('main', async () => {
|
|
258
309
|
const { resetTurnAccumulator } = await import('./metrics.js');
|
|
@@ -265,6 +316,20 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
265
316
|
inputHandler.start(spinner);
|
|
266
317
|
changeLogger.startChangeSet(userInput);
|
|
267
318
|
let finalInput = userInput;
|
|
319
|
+
// Stage 0: Summarize chat history if length threshold is met
|
|
320
|
+
if (!cachedContextResult) {
|
|
321
|
+
const isDebug = isDebugOn();
|
|
322
|
+
if (!inputHandler.isCurrentlyPrompting() && !isDebug) {
|
|
323
|
+
spinner.start('Checking conversation history...');
|
|
324
|
+
}
|
|
325
|
+
const historySummarized = await summarizeHistoryIfNeeded(chat);
|
|
326
|
+
if (historySummarized) {
|
|
327
|
+
debugLog('Chat history was summarized and compressed prior to context investigation.');
|
|
328
|
+
}
|
|
329
|
+
if (!inputHandler.isCurrentlyPrompting() && !isDebug) {
|
|
330
|
+
spinner.stop();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
268
333
|
// Stage 1: Gather Workspace Context and route intentions
|
|
269
334
|
spinner.start('🔍 Investigating workspace...');
|
|
270
335
|
let gatherRes = { targetAgent: 'EXECUTE', chainedMessages: [], contextResult: cachedContextResult || null };
|
|
@@ -273,13 +338,26 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
273
338
|
if (collector)
|
|
274
339
|
collector.startTimer('contextGather');
|
|
275
340
|
const chatHistory = chat.getRecentHistory(3);
|
|
341
|
+
const toolLogs = [];
|
|
276
342
|
gatherRes = await gatherContext(workspaceRoot, userInput, chatHistory, inputHandler, ac.signal, (msg) => {
|
|
277
343
|
if (!inputHandler.isCurrentlyPrompting()) {
|
|
278
344
|
spinner.message(`🔍 Investigating workspace... ${pc.dim(msg)}`);
|
|
279
345
|
}
|
|
346
|
+
}, (toolMsg, label) => {
|
|
347
|
+
const formattedLog = `${pc.dim(`[${label}]`)} ${toolMsg}`;
|
|
348
|
+
toolLogs.push(formattedLog);
|
|
349
|
+
if (!inputHandler.isCurrentlyPrompting()) {
|
|
350
|
+
spinner.message(`🔍 Investigating workspace... ${formattedLog}`);
|
|
351
|
+
}
|
|
280
352
|
});
|
|
281
353
|
if (collector)
|
|
282
354
|
collector.stopTimer('contextGather');
|
|
355
|
+
// Print all collected logs at once to prevent flickering, while spinner is stopped
|
|
356
|
+
if (toolLogs.length > 0) {
|
|
357
|
+
spinner.stop();
|
|
358
|
+
toolLogs.forEach(log => p.log.step(log));
|
|
359
|
+
spinner.start(`🔍 Context gathered successfully.`);
|
|
360
|
+
}
|
|
283
361
|
}
|
|
284
362
|
let latestUsage = undefined;
|
|
285
363
|
// Collect any inputs that were queued while the Context Agent was investigating
|
|
@@ -379,6 +457,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
379
457
|
catch { }
|
|
380
458
|
if (!isPlanMode && effectiveTargetAgent === 'EXECUTE' && isSubAgentsEnabled()) {
|
|
381
459
|
spinner.stop(); // Clear the spinner before delegating
|
|
460
|
+
inputHandler.clearSpinner(); // Prevent prompt from reviving the old spinner
|
|
382
461
|
process.stdout.write('\x1b[2K\r');
|
|
383
462
|
const orchestrator = new Orchestrator(workspaceRoot, chatSessionState.id, inputHandler);
|
|
384
463
|
const handledByOrchestrator = await orchestrator.runOrchestration(finalInput, dynamicSystemInstruction, ac.signal);
|
|
@@ -413,6 +492,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
413
492
|
chatSessionState.totalTokens += usage.totalTokenCount;
|
|
414
493
|
chatSessionState.totalInputTokens += (usage.promptTokens || 0) + (usage.cachedTokens || 0);
|
|
415
494
|
chatSessionState.totalOutputTokens += usage.candidatesTokens || 0;
|
|
495
|
+
chatSessionState.totalCreditsUsed += usage.creditsUsed || 0;
|
|
416
496
|
if (usage.cachedTokens && usage.cachedTokens > 0) {
|
|
417
497
|
const totalInputTokens = (usage.promptTokens || 0) + usage.cachedTokens;
|
|
418
498
|
const percentSaved = totalInputTokens > 0 ? Math.round((usage.cachedTokens / totalInputTokens) * 100) : 0;
|
|
@@ -459,6 +539,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
459
539
|
totalTokens: chatSessionState.totalTokens,
|
|
460
540
|
totalInputTokens: chatSessionState.totalInputTokens,
|
|
461
541
|
totalOutputTokens: chatSessionState.totalOutputTokens,
|
|
542
|
+
totalCreditsUsed: chatSessionState.totalCreditsUsed,
|
|
462
543
|
gitBranch: gitBranch || undefined,
|
|
463
544
|
autoApprove: getApprovalMode() === 'skip-all',
|
|
464
545
|
subAgents: isSubAgentsEnabled(),
|
|
@@ -559,6 +640,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
559
640
|
chatSessionState.totalTokens += usage.totalTokenCount || 0;
|
|
560
641
|
chatSessionState.totalInputTokens += (usage.promptTokens || 0) + (usage.cachedTokens || 0);
|
|
561
642
|
chatSessionState.totalOutputTokens += usage.candidatesTokens || 0;
|
|
643
|
+
chatSessionState.totalCreditsUsed += usage.creditsUsed || 0;
|
|
562
644
|
}
|
|
563
645
|
// Auto-save chat history
|
|
564
646
|
const history = chat.getRawHistory();
|
|
@@ -579,6 +661,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
579
661
|
totalTokens: chatSessionState.totalTokens,
|
|
580
662
|
totalInputTokens: chatSessionState.totalInputTokens,
|
|
581
663
|
totalOutputTokens: chatSessionState.totalOutputTokens,
|
|
664
|
+
totalCreditsUsed: chatSessionState.totalCreditsUsed,
|
|
582
665
|
gitBranch: gitBranch || undefined,
|
|
583
666
|
autoApprove: getApprovalMode() === 'skip-all',
|
|
584
667
|
subAgents: isSubAgentsEnabled(),
|
|
@@ -603,6 +686,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
603
686
|
totalTokens: chatSessionState.totalTokens,
|
|
604
687
|
totalInputTokens: chatSessionState.totalInputTokens,
|
|
605
688
|
totalOutputTokens: chatSessionState.totalOutputTokens,
|
|
689
|
+
totalCreditsUsed: chatSessionState.totalCreditsUsed,
|
|
606
690
|
gitBranch: gitBranch || undefined,
|
|
607
691
|
autoApprove: getApprovalMode() === 'skip-all',
|
|
608
692
|
subAgents: isSubAgentsEnabled(),
|
|
@@ -636,31 +720,43 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
|
|
|
636
720
|
],
|
|
637
721
|
});
|
|
638
722
|
if (planAction === 'choose_model') {
|
|
723
|
+
const byokEnabled = await isByokEnabled();
|
|
724
|
+
const options = [
|
|
725
|
+
// {
|
|
726
|
+
// value: 'claude-opus-5',
|
|
727
|
+
// label: 'Claude 5 Opus',
|
|
728
|
+
// hint: 'For hardcore & complex problems',
|
|
729
|
+
// },
|
|
730
|
+
{
|
|
731
|
+
value: 'gemini-3.1-pro-preview',
|
|
732
|
+
label: 'Gemini 3.1 Pro',
|
|
733
|
+
hint: 'For hardcore & complex problems',
|
|
734
|
+
},
|
|
735
|
+
// {
|
|
736
|
+
// value: 'claude-sonnet-5',
|
|
737
|
+
// label: 'Claude 5 Sonnet',
|
|
738
|
+
// hint: 'Best for raw speed and cost efficiency',
|
|
739
|
+
// },
|
|
740
|
+
{
|
|
741
|
+
value: 'gemini-3.6-flash',
|
|
742
|
+
label: 'Gemini 3.6 Flash',
|
|
743
|
+
hint: 'Balanced performance & fast',
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
value: 'gemini-3.5-flash-lite',
|
|
747
|
+
label: 'Gemini 3.5 Flash-Lite',
|
|
748
|
+
hint: 'Best for raw speed and cost efficiency',
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
value: 'auto',
|
|
752
|
+
label: 'Auto (Flash-Lite / Flash)',
|
|
753
|
+
hint: 'Dynamically routes between Gemini 3.5 Flash-Lite and Gemini 3.6 based on prompt complexity',
|
|
754
|
+
},
|
|
755
|
+
].filter(o => !(byokEnabled && o.value.includes('claude')));
|
|
639
756
|
const selectedModel = await p['select']({
|
|
640
757
|
message: `Select AI Model (Current: ${pc.cyan(currentModel)})`,
|
|
641
758
|
initialValue: currentModel,
|
|
642
|
-
options:
|
|
643
|
-
{
|
|
644
|
-
value: 'gemini-3.1-pro-preview',
|
|
645
|
-
label: 'Gemini 3.1 Pro',
|
|
646
|
-
hint: 'The Pro model for complex logic',
|
|
647
|
-
},
|
|
648
|
-
{
|
|
649
|
-
value: 'gemini-3.6-flash',
|
|
650
|
-
label: 'Gemini 3.6 Flash',
|
|
651
|
-
hint: 'Balanced performance',
|
|
652
|
-
},
|
|
653
|
-
{
|
|
654
|
-
value: 'gemini-3.5-flash-lite',
|
|
655
|
-
label: 'Gemini 3.5 Flash-Lite',
|
|
656
|
-
hint: 'Best for speed and cost efficiency',
|
|
657
|
-
},
|
|
658
|
-
{
|
|
659
|
-
value: 'auto',
|
|
660
|
-
label: 'Auto (Flash-Lite / Flash)',
|
|
661
|
-
hint: 'Dynamically routes between Gemini 3.5 Flash-Lite and Gemini 3.6 based on prompt complexity',
|
|
662
|
-
},
|
|
663
|
-
],
|
|
759
|
+
options: options,
|
|
664
760
|
});
|
|
665
761
|
if (!p.isCancel(selectedModel)) {
|
|
666
762
|
chat.setModel(selectedModel);
|
|
@@ -704,7 +800,7 @@ async function collectUserInput(history, isPlanMode) {
|
|
|
704
800
|
while (true) {
|
|
705
801
|
const userInputRaw = await historyText({
|
|
706
802
|
message: isMultiLine ? ' ' : isPlanMode ? pc.cyan('(Plan Mode) ❯') : pc.magenta('❯'),
|
|
707
|
-
placeholder: isMultiLine ? '' : 'Use
|
|
803
|
+
placeholder: isMultiLine ? '' : 'Use ' + String.fromCharCode(92) + ' for new lines',
|
|
708
804
|
history,
|
|
709
805
|
});
|
|
710
806
|
if (p.isCancel(userInputRaw)) {
|
|
@@ -720,7 +816,7 @@ async function collectUserInput(history, isPlanMode) {
|
|
|
720
816
|
}
|
|
721
817
|
let line = (userInputRaw || '');
|
|
722
818
|
// Require a space before the backslash to prevent Windows directory paths (e.g., C:\foo\) from triggering multiline
|
|
723
|
-
if (line.trimEnd().endsWith('
|
|
819
|
+
if (line.trimEnd().endsWith(' ' + String.fromCharCode(92))) {
|
|
724
820
|
const cleanLine = line.trimEnd().slice(0, -2);
|
|
725
821
|
lines.push(cleanLine);
|
|
726
822
|
isMultiLine = true;
|
|
@@ -782,6 +878,64 @@ async function compressContextFiles(workspaceRoot, contextResult) {
|
|
|
782
878
|
}
|
|
783
879
|
return compressedFiles;
|
|
784
880
|
}
|
|
881
|
+
/**
|
|
882
|
+
* Raw chat history entry count threshold to trigger chat history summarization.
|
|
883
|
+
* 12 entries = 6 conversational user/model turns.
|
|
884
|
+
*/
|
|
885
|
+
export const HISTORY_SUMMARIZATION_THRESHOLD = 12;
|
|
886
|
+
/**
|
|
887
|
+
* Checks and summarizes older chat history entries if the active session's history
|
|
888
|
+
* exceeds HISTORY_SUMMARIZATION_THRESHOLD entries.
|
|
889
|
+
*
|
|
890
|
+
* Preserves the most recent 4 entries (2 turns) intact for conversational continuity,
|
|
891
|
+
* replacing all preceding turns with a single summarized pair in the chat history.
|
|
892
|
+
*
|
|
893
|
+
* @param chat - The active ProxyChatSession instance.
|
|
894
|
+
* @returns True if history was summarized and updated; false otherwise.
|
|
895
|
+
*/
|
|
896
|
+
/**
|
|
897
|
+
* Summarizes older chat history entries if the active session's history
|
|
898
|
+
* exceeds {@link HISTORY_SUMMARIZATION_THRESHOLD} entries.
|
|
899
|
+
*
|
|
900
|
+
* Preserves the most recent 4 entries (2 turns) intact for conversational continuity,
|
|
901
|
+
* replacing all preceding turns with a single summarized pair in the chat history.
|
|
902
|
+
*
|
|
903
|
+
* @param chat - The active ProxyChatSession instance.
|
|
904
|
+
* @returns A promise resolving to true if history was summarized and updated; false otherwise.
|
|
905
|
+
*/
|
|
906
|
+
export async function summarizeHistoryIfNeeded(chat) {
|
|
907
|
+
const history = chat.getRawHistory();
|
|
908
|
+
if (!history || history.length < HISTORY_SUMMARIZATION_THRESHOLD) {
|
|
909
|
+
return false;
|
|
910
|
+
}
|
|
911
|
+
try {
|
|
912
|
+
// Keep the most recent 4 entries (2 full user/model turns) intact
|
|
913
|
+
const recentCount = 4;
|
|
914
|
+
const olderHistory = history.slice(0, history.length - recentCount);
|
|
915
|
+
const recentHistory = history.slice(history.length - recentCount);
|
|
916
|
+
debugLog(`Summarizing ${olderHistory.length} older chat history entries...`);
|
|
917
|
+
const summaryText = await summarizeChatHistory(olderHistory);
|
|
918
|
+
if (summaryText && summaryText.trim().length > 0) {
|
|
919
|
+
const summaryContent = [
|
|
920
|
+
{
|
|
921
|
+
role: 'user',
|
|
922
|
+
parts: [{ text: `[PREVIOUS CONVERSATION SUMMARY]:\n${summaryText.trim()}` }],
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
role: 'model',
|
|
926
|
+
parts: [{ text: 'Understood. I have reviewed and absorbed the summary of our preceding conversation.' }],
|
|
927
|
+
},
|
|
928
|
+
];
|
|
929
|
+
chat.loadRawHistory([...summaryContent, ...recentHistory]);
|
|
930
|
+
debugLog(`Chat history compressed successfully from ${history.length} to ${summaryContent.length + recentHistory.length} entries.`);
|
|
931
|
+
return true;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
catch (error) {
|
|
935
|
+
debugLog(`Failed to summarize chat history: ${error?.message || error}`);
|
|
936
|
+
}
|
|
937
|
+
return false;
|
|
938
|
+
}
|
|
785
939
|
async function executeSelfCorrectionLoop(chat, initialResult, workspaceRoot, inputHandler, effectiveTargetAgent, signal, spinner, originalUserInput, isPlanMode) {
|
|
786
940
|
let correctionAttempts = 0;
|
|
787
941
|
const MAX_CORRECTIONS = 5;
|
|
@@ -795,16 +949,24 @@ async function executeSelfCorrectionLoop(chat, initialResult, workspaceRoot, inp
|
|
|
795
949
|
if (finalText === '[Generation stopped by user]')
|
|
796
950
|
break;
|
|
797
951
|
const historyLengthBefore = chat.getRawHistory().length;
|
|
798
|
-
|
|
952
|
+
const currentText = await processResponse(chat, result, workspaceRoot, inputHandler, agentState, signal);
|
|
799
953
|
const historyLengthAfter = chat.getRawHistory().length;
|
|
800
954
|
const usedTools = historyLengthAfter > historyLengthBefore;
|
|
801
|
-
debugLog(`processResponse returned
|
|
802
|
-
if (
|
|
955
|
+
debugLog(`processResponse returned text (length ${currentText.length}): "${currentText.substring(0, 10)}..."`);
|
|
956
|
+
if (currentText === '[Generation stopped by user]') {
|
|
957
|
+
finalText = currentText;
|
|
803
958
|
break;
|
|
804
959
|
}
|
|
805
|
-
if (
|
|
960
|
+
if (currentText.startsWith('[The AI repeatedly returned empty responses')) {
|
|
961
|
+
finalText = currentText;
|
|
806
962
|
break;
|
|
807
963
|
}
|
|
964
|
+
if (correctionAttempts === 0) {
|
|
965
|
+
finalText = currentText;
|
|
966
|
+
}
|
|
967
|
+
else if (currentText && !currentText.includes('[INTENT_VERIFIED]')) {
|
|
968
|
+
finalText += '\n\n### Subsequent Fixes:\n' + currentText;
|
|
969
|
+
}
|
|
808
970
|
const currentChanges = changeLogger.getCurrentChangeSet()?.changes || [];
|
|
809
971
|
// If the correction cycle is active but no new changes were registered, the model gave up
|
|
810
972
|
if (isFixingCodeError && currentChanges.length <= previousChangeCount && !usedTools) {
|
package/dist/services/ai.d.ts
CHANGED
|
@@ -88,6 +88,11 @@ export declare function createIntentRouterSession(): any;
|
|
|
88
88
|
export declare function createExecutionComplexitySession(): any;
|
|
89
89
|
export declare function createInvestigationComplexitySession(): any;
|
|
90
90
|
export declare function createWebSearchAgentSession(): any;
|
|
91
|
+
export declare function createHistorySummarizerSession(): any;
|
|
92
|
+
/**
|
|
93
|
+
* Summarizes an array of Content history entries using Gemini Flash Lite.
|
|
94
|
+
*/
|
|
95
|
+
export declare function summarizeChatHistory(history: Content[]): Promise<string>;
|
|
91
96
|
/**
|
|
92
97
|
* Generates a concise title for a chat session based on the user's first message.
|
|
93
98
|
*/
|