coder-agent 2.6.1 → 2.6.3
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 +147 -5
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -276,6 +276,151 @@ async function callGeminiAPIWithRotation(apiKey, params, maxRetries = 3, initial
|
|
|
276
276
|
err.status = res.status;
|
|
277
277
|
throw err;
|
|
278
278
|
}
|
|
279
|
+
if (params.stream) {
|
|
280
|
+
const decoder = new TextDecoder();
|
|
281
|
+
let buffer = "";
|
|
282
|
+
let accumulatedContent = "";
|
|
283
|
+
let accumulatedToolCalls = [];
|
|
284
|
+
if (!silent) {
|
|
285
|
+
stopSpinner();
|
|
286
|
+
}
|
|
287
|
+
let typewriterQueue = [];
|
|
288
|
+
let typewriterActive = false;
|
|
289
|
+
let resolveTypewriterFinished = null;
|
|
290
|
+
const pushToTypewriter = (text) => {
|
|
291
|
+
typewriterQueue.push(...text.split(""));
|
|
292
|
+
if (!typewriterActive) {
|
|
293
|
+
typewriterActive = true;
|
|
294
|
+
runTypewriterLoop();
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
const runTypewriterLoop = async () => {
|
|
298
|
+
while (typewriterQueue.length > 0) {
|
|
299
|
+
const len = typewriterQueue.length;
|
|
300
|
+
let batchSize = 1;
|
|
301
|
+
let delay = 15; // default smooth delay
|
|
302
|
+
if (len > 80) {
|
|
303
|
+
batchSize = 8;
|
|
304
|
+
delay = 1;
|
|
305
|
+
}
|
|
306
|
+
else if (len > 40) {
|
|
307
|
+
batchSize = 4;
|
|
308
|
+
delay = 2;
|
|
309
|
+
}
|
|
310
|
+
else if (len > 20) {
|
|
311
|
+
batchSize = 2;
|
|
312
|
+
delay = 5;
|
|
313
|
+
}
|
|
314
|
+
else if (len > 10) {
|
|
315
|
+
batchSize = 1;
|
|
316
|
+
delay = 8;
|
|
317
|
+
}
|
|
318
|
+
const chars = typewriterQueue.splice(0, batchSize).join("");
|
|
319
|
+
process.stdout.write(chars);
|
|
320
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
321
|
+
}
|
|
322
|
+
typewriterActive = false;
|
|
323
|
+
if (resolveTypewriterFinished) {
|
|
324
|
+
resolveTypewriterFinished();
|
|
325
|
+
resolveTypewriterFinished = null;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
const processChunk = (chunk) => {
|
|
329
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
330
|
+
const lines = buffer.split("\n");
|
|
331
|
+
buffer = lines.pop() || "";
|
|
332
|
+
for (const line of lines) {
|
|
333
|
+
const trimmed = line.trim();
|
|
334
|
+
if (!trimmed)
|
|
335
|
+
continue;
|
|
336
|
+
if (trimmed === "data: [DONE]")
|
|
337
|
+
break;
|
|
338
|
+
if (trimmed.startsWith("data: ")) {
|
|
339
|
+
try {
|
|
340
|
+
const parsed = JSON.parse(trimmed.slice(6));
|
|
341
|
+
const choice = parsed.choices?.[0];
|
|
342
|
+
if (!choice)
|
|
343
|
+
continue;
|
|
344
|
+
const content = choice.delta?.content;
|
|
345
|
+
if (content) {
|
|
346
|
+
accumulatedContent += content;
|
|
347
|
+
if (!silent) {
|
|
348
|
+
pushToTypewriter(content);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const toolCalls = choice.delta?.tool_calls;
|
|
352
|
+
if (toolCalls) {
|
|
353
|
+
for (const tc of toolCalls) {
|
|
354
|
+
const idx = tc.index ?? 0;
|
|
355
|
+
if (!accumulatedToolCalls[idx]) {
|
|
356
|
+
accumulatedToolCalls[idx] = {
|
|
357
|
+
id: tc.id || "",
|
|
358
|
+
type: "function",
|
|
359
|
+
function: { name: "", arguments: "" }
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
if (tc.id)
|
|
363
|
+
accumulatedToolCalls[idx].id = tc.id;
|
|
364
|
+
if (tc.function?.name) {
|
|
365
|
+
accumulatedToolCalls[idx].function.name += tc.function.name;
|
|
366
|
+
}
|
|
367
|
+
if (tc.function?.arguments) {
|
|
368
|
+
accumulatedToolCalls[idx].function.arguments += tc.function.arguments;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
catch (e) {
|
|
374
|
+
// Ignore partial JSON parse errors
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
const bodyStream = res.body;
|
|
380
|
+
if (bodyStream && typeof bodyStream[Symbol.asyncIterator] === "function") {
|
|
381
|
+
for await (const chunk of bodyStream) {
|
|
382
|
+
if (signal?.aborted) {
|
|
383
|
+
const abortErr = new Error("The user aborted a request.");
|
|
384
|
+
abortErr.name = "AbortError";
|
|
385
|
+
throw abortErr;
|
|
386
|
+
}
|
|
387
|
+
processChunk(chunk);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
else if (bodyStream && typeof bodyStream.getReader === "function") {
|
|
391
|
+
const reader = bodyStream.getReader();
|
|
392
|
+
while (true) {
|
|
393
|
+
if (signal?.aborted) {
|
|
394
|
+
const abortErr = new Error("The user aborted a request.");
|
|
395
|
+
abortErr.name = "AbortError";
|
|
396
|
+
throw abortErr;
|
|
397
|
+
}
|
|
398
|
+
const { done, value } = await reader.read();
|
|
399
|
+
if (done)
|
|
400
|
+
break;
|
|
401
|
+
if (value)
|
|
402
|
+
processChunk(value);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
// Wait for the typewriter to finish writing before returning
|
|
406
|
+
if (typewriterActive && !silent) {
|
|
407
|
+
await new Promise((resolve) => {
|
|
408
|
+
resolveTypewriterFinished = resolve;
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
const finalResponse = {
|
|
412
|
+
choices: [
|
|
413
|
+
{
|
|
414
|
+
message: {
|
|
415
|
+
role: "assistant",
|
|
416
|
+
content: accumulatedContent,
|
|
417
|
+
tool_calls: accumulatedToolCalls.length > 0 ? accumulatedToolCalls.filter(Boolean) : undefined
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
]
|
|
421
|
+
};
|
|
422
|
+
return { data: finalResponse, modelUsed: currentModel };
|
|
423
|
+
}
|
|
279
424
|
const data = await res.json();
|
|
280
425
|
return { data, modelUsed: currentModel };
|
|
281
426
|
}
|
|
@@ -451,6 +596,7 @@ export class Agent {
|
|
|
451
596
|
tools: TOOL_DEFINITIONS,
|
|
452
597
|
tool_choice: "auto",
|
|
453
598
|
temperature: 0.2,
|
|
599
|
+
stream: true,
|
|
454
600
|
}, 3, 1500, signal);
|
|
455
601
|
stopSpinner();
|
|
456
602
|
if (signal?.aborted) {
|
|
@@ -560,11 +706,7 @@ export class Agent {
|
|
|
560
706
|
console.log(chalk.dim('─') + ' ' + chalk.dim(`${modifiedFiles.size} file(s) modified`));
|
|
561
707
|
}
|
|
562
708
|
// ── Phase 3: Final Agent Response ───────────────────────────────────────
|
|
563
|
-
|
|
564
|
-
if (cleanContent) {
|
|
565
|
-
console.log(formatResponseText(cleanContent));
|
|
566
|
-
console.log(""); // one trailing blank line
|
|
567
|
-
}
|
|
709
|
+
// Content has already been streamed in real-time.
|
|
568
710
|
if (iterations >= MAX_ITERATIONS) {
|
|
569
711
|
console.log(chalk.hex('#ff453a')('✕ error'));
|
|
570
712
|
console.log(chalk.dim(' Max tool iterations reached.'));
|