minovative-mind-cli 2.8.0 → 2.8.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.
@@ -26,7 +26,7 @@ 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, isByokEnabled } from '../utils/config.js';
29
+ import { GEMINI_MODELS, isByokEnabled, TPM_COOLING_DELAYS } from '../utils/config.js';
30
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';
@@ -317,6 +317,8 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
317
317
  inputHandler.start(spinner);
318
318
  changeLogger.startChangeSet(userInput);
319
319
  let finalInput = userInput;
320
+ // Inter-turn cooling-off delay to allow API token buckets to settle before running intent routing
321
+ await new Promise((resolve) => setTimeout(resolve, TPM_COOLING_DELAYS.INTER_TURN_MS));
320
322
  // Stage 0: Summarize chat history if length threshold is met
321
323
  if (!cachedContextResult) {
322
324
  const isDebug = isDebugOn();
@@ -359,6 +361,8 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
359
361
  toolLogs.forEach((log) => p.log.step(log));
360
362
  spinner.start(`šŸ” Context gathered successfully.`);
361
363
  }
364
+ // Post-investigation cooling-off delay to allow API Tokens-Per-Minute (TPM) sliding window to settle
365
+ await new Promise((resolve) => setTimeout(resolve, TPM_COOLING_DELAYS.POST_INVESTIGATION_MS));
362
366
  }
363
367
  let latestUsage = undefined;
364
368
  // Collect any inputs that were queued while the Context Agent was investigating
@@ -481,7 +485,8 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
481
485
  modifiedFiles.forEach((file) => p.log.message(` ${pc.dim('•')} ${file}`));
482
486
  }
483
487
  else {
484
- summaryMsg = 'Generation was stopped by the user before completion. No code files were modified before stopping.';
488
+ summaryMsg =
489
+ 'Generation was stopped by the user before completion. No code files were modified before stopping.';
485
490
  p.log.warn(pc.yellow('\nāš ļø Generation stopped by user before completion (no files were modified).'));
486
491
  }
487
492
  chat.addTurn({
@@ -657,8 +662,7 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
657
662
  const turnDuration = ((turnEndTime - turnStartTime) / 1000).toFixed(1);
658
663
  p.log.info(`${pc.dim('Generated in')} ${pc.cyan(turnDuration + 's')}`);
659
664
  // Check if generation was stopped by user
660
- const isStopped = finalText.includes('Generation stopped') ||
661
- finalText.includes('[Generation stopped');
665
+ const isStopped = finalText.includes('Generation stopped') || finalText.includes('[Generation stopped');
662
666
  if (isStopped) {
663
667
  const currentChanges = changeLogger.getCurrentChangeSet()?.changes || [];
664
668
  const modifiedFiles = currentChanges
@@ -672,7 +676,8 @@ export async function executeSingleTurn(workspaceRoot, userInput, chat, inputHan
672
676
  modifiedFiles.forEach((file) => p.log.message(` ${pc.dim('•')} ${file}`));
673
677
  }
674
678
  else {
675
- summaryMsg = 'Generation was stopped by the user before completion. No code files were modified before stopping.';
679
+ summaryMsg =
680
+ 'Generation was stopped by the user before completion. No code files were modified before stopping.';
676
681
  p.log.warn(pc.yellow('\nāš ļø Generation stopped by user before completion (no files were modified).'));
677
682
  }
678
683
  chat.addTurn({
@@ -25,6 +25,7 @@ import { InvestigationAgentRunner } from './investigationAgent.js';
25
25
  import { readFile } from '../agent-tools.js';
26
26
  import { buildDependencyGraph } from '../../utils/dependencyTracer.js';
27
27
  import { debugLog } from '../../utils/logger.js';
28
+ import { TPM_COOLING_DELAYS } from '../../utils/config.js';
28
29
  // ─── Constants ───────────────────────────────────────────────────────
29
30
  /** Maximum total relevant files across all agents after merge. */
30
31
  const MAX_TOTAL_FILES = 30;
@@ -57,6 +58,8 @@ export class InvestigationOrchestrator {
57
58
  const agents = agentAssignments.map((assignment) => new InvestigationAgentRunner(assignment.agentLabel, assignment.domains, workspaceRoot, readCache, projectTree, projectType));
58
59
  // 3. Run all agents in parallel
59
60
  const startTime = Date.now();
61
+ // Cooling-off pause to prevent burst 429 errors when initiating parallel agent dispatch
62
+ await new Promise((resolve) => setTimeout(resolve, TPM_COOLING_DELAYS.PARALLEL_DISPATCH_MS));
60
63
  // Limit parallel investigation agents to 2 to avoid Vertex AI RESOURCE_EXHAUSTED errors
61
64
  const MAX_CONCURRENT = 2;
62
65
  const results = [];
@@ -41,7 +41,7 @@ let globalSessionAccumulatedUsage = {
41
41
  totalTokenCount: 0,
42
42
  creditsUsed: 0,
43
43
  remainingBalance: undefined,
44
- modelsUsed: {}
44
+ modelsUsed: {},
45
45
  };
46
46
  export function getAndResetTurnUsage() {
47
47
  const current = { ...globalSessionAccumulatedUsage };
@@ -52,7 +52,7 @@ export function getAndResetTurnUsage() {
52
52
  totalTokenCount: 0,
53
53
  creditsUsed: 0,
54
54
  remainingBalance: undefined,
55
- modelsUsed: {}
55
+ modelsUsed: {},
56
56
  };
57
57
  return current;
58
58
  }
@@ -117,6 +117,7 @@ export class ProxyClient {
117
117
  if ((response.status === 429 || response.status === 503) && attempt < MAX_RETRIES) {
118
118
  const exponentialDelay = Math.min(MAX_DELAY_MS, BASE_DELAY_MS * Math.pow(2, attempt));
119
119
  const delayTime = Math.round(exponentialDelay * (0.5 + Math.random() * 0.5));
120
+ process.stdout.write('\n');
120
121
  console.warn(`Rate limit or service unavailable hit (${response.status}). Retrying in ${(delayTime / 1000).toFixed(1)}s... (Attempt ${attempt + 1}/${MAX_RETRIES})`);
121
122
  await delay(delayTime, abortSignal);
122
123
  attempt++;
@@ -198,7 +199,7 @@ export class ProxyClient {
198
199
  collector?.accumulateUsage({
199
200
  promptTokens: data.usage.promptTokens || 0,
200
201
  candidatesTokens: data.usage.candidatesTokens || 0,
201
- cachedTokens: data.usage.cachedTokens || 0
202
+ cachedTokens: data.usage.cachedTokens || 0,
202
203
  });
203
204
  globalSessionAccumulatedUsage.promptTokens += data.usage.promptTokens || 0;
204
205
  globalSessionAccumulatedUsage.candidatesTokens += data.usage.candidatesTokens || 0;
@@ -209,7 +210,8 @@ export class ProxyClient {
209
210
  if (data.usage.remainingBalance !== undefined) {
210
211
  globalSessionAccumulatedUsage.remainingBalance = data.usage.remainingBalance;
211
212
  }
212
- globalSessionAccumulatedUsage.modelsUsed[modelName] = (globalSessionAccumulatedUsage.modelsUsed[modelName] || 0) + 1;
213
+ globalSessionAccumulatedUsage.modelsUsed[modelName] =
214
+ (globalSessionAccumulatedUsage.modelsUsed[modelName] || 0) + 1;
213
215
  }
214
216
  if (data.groundingMetadata) {
215
217
  groundingMetadata = data.groundingMetadata;
@@ -236,6 +238,7 @@ export class ProxyClient {
236
238
  if (attempt < MAX_RETRIES) {
237
239
  const exponentialDelay = Math.min(MAX_DELAY_MS, BASE_DELAY_MS * Math.pow(2, attempt));
238
240
  const delayTime = Math.round(exponentialDelay * (0.5 + Math.random() * 0.5));
241
+ process.stdout.write('\n');
239
242
  console.warn(`Rate limit or service unavailable hit during stream. Retrying in ${(delayTime / 1000).toFixed(1)}s... (Attempt ${attempt + 1}/${MAX_RETRIES})`);
240
243
  await delay(delayTime, abortSignal);
241
244
  attempt++;
@@ -25,6 +25,19 @@ export declare const GEMINI_MODELS: {
25
25
  export declare const DEFAULT_MODEL: "auto";
26
26
  /** Maximum tokens the model can output per response. */
27
27
  export declare const MAX_OUTPUT_TOKENS = 60000;
28
+ /**
29
+ * Rate limit & Tokens-Per-Minute (TPM) cooling-off delays (in milliseconds).
30
+ * Prevents transient 429 / 503 rate-limit errors by giving the API 60-second
31
+ * rolling token window time to settle during key agent transitions.
32
+ */
33
+ export declare const TPM_COOLING_DELAYS: {
34
+ /** Pause before running initial intent routing between turns */
35
+ readonly INTER_TURN_MS: 1000;
36
+ /** Pause before dispatching parallel sub-agent investigations simultaneously */
37
+ readonly PARALLEL_DISPATCH_MS: 1000;
38
+ /** Pause after context gathering completes before starting the execution stream */
39
+ readonly POST_INVESTIGATION_MS: 3000;
40
+ };
28
41
  /**
29
42
  * Checks if BYOK is currently enabled for the user.
30
43
  */
@@ -25,6 +25,19 @@ export const GEMINI_MODELS = {
25
25
  export const DEFAULT_MODEL = GEMINI_MODELS.AUTO;
26
26
  /** Maximum tokens the model can output per response. */
27
27
  export const MAX_OUTPUT_TOKENS = 60_000;
28
+ /**
29
+ * Rate limit & Tokens-Per-Minute (TPM) cooling-off delays (in milliseconds).
30
+ * Prevents transient 429 / 503 rate-limit errors by giving the API 60-second
31
+ * rolling token window time to settle during key agent transitions.
32
+ */
33
+ export const TPM_COOLING_DELAYS = {
34
+ /** Pause before running initial intent routing between turns */
35
+ INTER_TURN_MS: 1000,
36
+ /** Pause before dispatching parallel sub-agent investigations simultaneously */
37
+ PARALLEL_DISPATCH_MS: 1000,
38
+ /** Pause after context gathering completes before starting the execution stream */
39
+ POST_INVESTIGATION_MS: 3000,
40
+ };
28
41
  /**
29
42
  * Checks if BYOK is currently enabled for the user.
30
43
  */
@@ -65,5 +65,5 @@
65
65
  ]
66
66
  }
67
67
  },
68
- "version": "2.8.0"
68
+ "version": "2.8.1"
69
69
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "minovative-mind-cli",
3
3
  "description": "An automated AI agent powered by Vertex AI that helps you write software",
4
- "version": "2.8.0",
4
+ "version": "2.8.1",
5
5
  "author": "Daniel Ward",
6
6
  "bin": {
7
7
  "minovative-mind-cli": "bin/run.js"
@@ -78,9 +78,8 @@
78
78
  "scripts": {
79
79
  "build": "shx rm -rf dist tsconfig.tsbuildinfo && tsc -b",
80
80
  "prepare": "npm run build",
81
- "lint": "eslint",
81
+ "lint": "eslint src/ test/",
82
82
  "postpack": "shx rm -f oclif.manifest.json",
83
- "posttest": "npm run lint",
84
83
  "prepack": "npm run build && oclif manifest && oclif readme --no-source-links",
85
84
  "test": "mocha --forbid-only \"test/**/*.test.ts\"",
86
85
  "version": "oclif readme --no-source-links && git add README.md"