coder-agent 2.9.1 → 2.9.2

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 (2) hide show
  1. package/dist/agent.js +22 -61
  2. package/package.json +1 -1
package/dist/agent.js CHANGED
@@ -337,53 +337,6 @@ async function callGeminiAPIWithRotation(apiKey, params, maxRetries = 3, initial
337
337
  let buffer = "";
338
338
  let accumulatedContent = "";
339
339
  let accumulatedToolCalls = [];
340
- let typewriterQueue = [];
341
- let typewriterActive = false;
342
- let resolveTypewriterFinished = null;
343
- const pushToTypewriter = (text) => {
344
- typewriterQueue.push(...text.split(""));
345
- if (!typewriterActive) {
346
- typewriterActive = true;
347
- runTypewriterLoop();
348
- }
349
- };
350
- const runTypewriterLoop = async () => {
351
- while (typewriterQueue.length > 0) {
352
- const len = typewriterQueue.length;
353
- let batchSize = 1;
354
- let delay = 15; // default smooth delay
355
- if (len > 80) {
356
- batchSize = 8;
357
- delay = 1;
358
- }
359
- else if (len > 40) {
360
- batchSize = 4;
361
- delay = 2;
362
- }
363
- else if (len > 20) {
364
- batchSize = 2;
365
- delay = 5;
366
- }
367
- else if (len > 10) {
368
- batchSize = 1;
369
- delay = 8;
370
- }
371
- const chars = typewriterQueue.splice(0, batchSize).join("");
372
- accumulatedContent += chars;
373
- const maxLen = (process.stdout.columns || 80) - 20;
374
- let display = accumulatedContent.replace(/\r?\n/g, " ");
375
- if (display.length > maxLen) {
376
- display = "..." + display.slice(-maxLen + 3);
377
- }
378
- updateSpinner(chalk.dim("thinking: ") + chalk.gray(display));
379
- await new Promise((resolve) => setTimeout(resolve, delay));
380
- }
381
- typewriterActive = false;
382
- if (resolveTypewriterFinished) {
383
- resolveTypewriterFinished();
384
- resolveTypewriterFinished = null;
385
- }
386
- };
387
340
  const processChunk = (chunk) => {
388
341
  buffer += decoder.decode(chunk, { stream: true });
389
342
  const lines = buffer.split("\n");
@@ -402,11 +355,14 @@ async function callGeminiAPIWithRotation(apiKey, params, maxRetries = 3, initial
402
355
  continue;
403
356
  const content = choice.delta?.content;
404
357
  if (content) {
358
+ accumulatedContent += content;
405
359
  if (!silent) {
406
- pushToTypewriter(content);
407
- }
408
- else {
409
- accumulatedContent += content;
360
+ const maxLen = (process.stdout.columns || 80) - 20;
361
+ let display = accumulatedContent.replace(/\r?\n/g, " ");
362
+ if (display.length > maxLen) {
363
+ display = "..." + display.slice(-maxLen + 3);
364
+ }
365
+ updateSpinner(chalk.dim("thinking: ") + chalk.gray(display));
410
366
  }
411
367
  }
412
368
  const toolCalls = choice.delta?.tool_calls;
@@ -473,11 +429,14 @@ async function callGeminiAPIWithRotation(apiKey, params, maxRetries = 3, initial
473
429
  if (choice) {
474
430
  const content = choice.delta?.content;
475
431
  if (content) {
432
+ accumulatedContent += content;
476
433
  if (!silent) {
477
- pushToTypewriter(content);
478
- }
479
- else {
480
- accumulatedContent += content;
434
+ const maxLen = (process.stdout.columns || 80) - 20;
435
+ let display = accumulatedContent.replace(/\r?\n/g, " ");
436
+ if (display.length > maxLen) {
437
+ display = "..." + display.slice(-maxLen + 3);
438
+ }
439
+ updateSpinner(chalk.dim("thinking: ") + chalk.gray(display));
481
440
  }
482
441
  }
483
442
  const toolCalls = choice.delta?.tool_calls;
@@ -507,12 +466,6 @@ async function callGeminiAPIWithRotation(apiKey, params, maxRetries = 3, initial
507
466
  }
508
467
  buffer = "";
509
468
  }
510
- // Wait for the typewriter to finish writing before returning
511
- if (typewriterActive && !silent) {
512
- await new Promise((resolve) => {
513
- resolveTypewriterFinished = resolve;
514
- });
515
- }
516
469
  if (!silent) {
517
470
  stopSpinner();
518
471
  if (accumulatedToolCalls.length === 0 && accumulatedContent.trim() !== "") {
@@ -672,6 +625,7 @@ export class Agent {
672
625
  const MAX_ITERATIONS = 12;
673
626
  let waitCount = 0;
674
627
  let emptyResponseRetries = 0;
628
+ let loopInterventions = 0;
675
629
  const MAX_WAITS = 3;
676
630
  const modifiedFiles = new Set();
677
631
  let cleanContent = "";
@@ -841,6 +795,11 @@ export class Agent {
841
795
  const currentKey = `${normalizeContentForLoopCheck(msg.content || "")}|${normalizeToolCallsForLoopCheck(toolCalls)}`;
842
796
  const tempHistory = [...stateHistory, currentKey];
843
797
  if (hasRepeatingCycle(tempHistory)) {
798
+ loopInterventions++;
799
+ if (loopInterventions >= 2) {
800
+ console.log(chalk.hex('#ff453a')('\n✕ Loop intervention failed: Coder is stuck in an execution loop. Exiting to prompt.'));
801
+ break;
802
+ }
844
803
  const warningMessage = `⚠️ [LOOP DETECTED] You are repeating the exact same thoughts or tool calls. Please break out of this loop. Do not repeat the same actions. Re-evaluate your strategy, look at a different file, run a different command, or ask the user for clarification if you cannot proceed.`;
845
804
  console.log(chalk.hex('#ff9f0a')('\n⚠ Loop detected! Intervening to break the loop...'));
846
805
  this.memory.add({
@@ -851,6 +810,8 @@ export class Agent {
851
810
  }
852
811
  else {
853
812
  stateHistory.push(currentKey);
813
+ if (loopInterventions > 0)
814
+ loopInterventions = 0;
854
815
  }
855
816
  if (iterations < MAX_ITERATIONS) {
856
817
  console.log(chalk.dim('\n' + '─'.repeat(48) + '\n'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coder-agent",
3
- "version": "2.9.1",
3
+ "version": "2.9.2",
4
4
  "description": "CLI coding agent powered by Google Gemini",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",