coder-agent 2.9.0 → 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.
- package/dist/agent.js +22 -61
- package/dist/config.js +2 -2
- package/dist/index.js +4 -1
- 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
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
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
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
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/dist/config.js
CHANGED
|
@@ -59,7 +59,7 @@ export async function getStoredApiKey() {
|
|
|
59
59
|
}
|
|
60
60
|
export async function saveApiKey(apiKey) {
|
|
61
61
|
const config = await readConfig();
|
|
62
|
-
config.geminiApiKey = apiKey;
|
|
62
|
+
config.geminiApiKey = apiKey.trim();
|
|
63
63
|
await writeConfig(config);
|
|
64
64
|
}
|
|
65
65
|
export async function getStoredModel() {
|
|
@@ -77,7 +77,7 @@ export async function getStoredGeminiApiKey() {
|
|
|
77
77
|
}
|
|
78
78
|
export async function saveGeminiApiKey(geminiApiKey) {
|
|
79
79
|
const config = await readConfig();
|
|
80
|
-
config.geminiApiKey = geminiApiKey;
|
|
80
|
+
config.geminiApiKey = geminiApiKey.trim();
|
|
81
81
|
await writeConfig(config);
|
|
82
82
|
}
|
|
83
83
|
export async function getLastUsedInfo() {
|
package/dist/index.js
CHANGED
|
@@ -162,7 +162,10 @@ async function main() {
|
|
|
162
162
|
// Load stored settings
|
|
163
163
|
const storedKey = await getStoredApiKey();
|
|
164
164
|
const envKey = process.env.GEMINI_API_KEY || process.env.GROQ_API_KEY;
|
|
165
|
-
let apiKey = envKey || storedKey;
|
|
165
|
+
let apiKey = (envKey || storedKey || "").trim();
|
|
166
|
+
if ((apiKey.startsWith('"') && apiKey.endsWith('"')) || (apiKey.startsWith("'") && apiKey.endsWith("'"))) {
|
|
167
|
+
apiKey = apiKey.slice(1, -1).trim();
|
|
168
|
+
}
|
|
166
169
|
const storedModel = await getStoredModel();
|
|
167
170
|
let defaultModel = "gemini-2.5-flash";
|
|
168
171
|
if (storedModel && VALID_MODELS.includes(storedModel)) {
|