coder-agent 2.6.1 → 2.6.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 +100 -5
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -276,6 +276,104 @@ 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
|
+
const processChunk = (chunk) => {
|
|
288
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
289
|
+
const lines = buffer.split("\n");
|
|
290
|
+
buffer = lines.pop() || "";
|
|
291
|
+
for (const line of lines) {
|
|
292
|
+
const trimmed = line.trim();
|
|
293
|
+
if (!trimmed)
|
|
294
|
+
continue;
|
|
295
|
+
if (trimmed === "data: [DONE]")
|
|
296
|
+
break;
|
|
297
|
+
if (trimmed.startsWith("data: ")) {
|
|
298
|
+
try {
|
|
299
|
+
const parsed = JSON.parse(trimmed.slice(6));
|
|
300
|
+
const choice = parsed.choices?.[0];
|
|
301
|
+
if (!choice)
|
|
302
|
+
continue;
|
|
303
|
+
const content = choice.delta?.content;
|
|
304
|
+
if (content) {
|
|
305
|
+
accumulatedContent += content;
|
|
306
|
+
if (!silent) {
|
|
307
|
+
process.stdout.write(content);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const toolCalls = choice.delta?.tool_calls;
|
|
311
|
+
if (toolCalls) {
|
|
312
|
+
for (const tc of toolCalls) {
|
|
313
|
+
const idx = tc.index ?? 0;
|
|
314
|
+
if (!accumulatedToolCalls[idx]) {
|
|
315
|
+
accumulatedToolCalls[idx] = {
|
|
316
|
+
id: tc.id || "",
|
|
317
|
+
type: "function",
|
|
318
|
+
function: { name: "", arguments: "" }
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
if (tc.id)
|
|
322
|
+
accumulatedToolCalls[idx].id = tc.id;
|
|
323
|
+
if (tc.function?.name) {
|
|
324
|
+
accumulatedToolCalls[idx].function.name += tc.function.name;
|
|
325
|
+
}
|
|
326
|
+
if (tc.function?.arguments) {
|
|
327
|
+
accumulatedToolCalls[idx].function.arguments += tc.function.arguments;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
catch (e) {
|
|
333
|
+
// Ignore partial JSON parse errors
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
const bodyStream = res.body;
|
|
339
|
+
if (bodyStream && typeof bodyStream[Symbol.asyncIterator] === "function") {
|
|
340
|
+
for await (const chunk of bodyStream) {
|
|
341
|
+
if (signal?.aborted) {
|
|
342
|
+
const abortErr = new Error("The user aborted a request.");
|
|
343
|
+
abortErr.name = "AbortError";
|
|
344
|
+
throw abortErr;
|
|
345
|
+
}
|
|
346
|
+
processChunk(chunk);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
else if (bodyStream && typeof bodyStream.getReader === "function") {
|
|
350
|
+
const reader = bodyStream.getReader();
|
|
351
|
+
while (true) {
|
|
352
|
+
if (signal?.aborted) {
|
|
353
|
+
const abortErr = new Error("The user aborted a request.");
|
|
354
|
+
abortErr.name = "AbortError";
|
|
355
|
+
throw abortErr;
|
|
356
|
+
}
|
|
357
|
+
const { done, value } = await reader.read();
|
|
358
|
+
if (done)
|
|
359
|
+
break;
|
|
360
|
+
if (value)
|
|
361
|
+
processChunk(value);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
const finalResponse = {
|
|
365
|
+
choices: [
|
|
366
|
+
{
|
|
367
|
+
message: {
|
|
368
|
+
role: "assistant",
|
|
369
|
+
content: accumulatedContent,
|
|
370
|
+
tool_calls: accumulatedToolCalls.length > 0 ? accumulatedToolCalls.filter(Boolean) : undefined
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
]
|
|
374
|
+
};
|
|
375
|
+
return { data: finalResponse, modelUsed: currentModel };
|
|
376
|
+
}
|
|
279
377
|
const data = await res.json();
|
|
280
378
|
return { data, modelUsed: currentModel };
|
|
281
379
|
}
|
|
@@ -451,6 +549,7 @@ export class Agent {
|
|
|
451
549
|
tools: TOOL_DEFINITIONS,
|
|
452
550
|
tool_choice: "auto",
|
|
453
551
|
temperature: 0.2,
|
|
552
|
+
stream: true,
|
|
454
553
|
}, 3, 1500, signal);
|
|
455
554
|
stopSpinner();
|
|
456
555
|
if (signal?.aborted) {
|
|
@@ -560,11 +659,7 @@ export class Agent {
|
|
|
560
659
|
console.log(chalk.dim('─') + ' ' + chalk.dim(`${modifiedFiles.size} file(s) modified`));
|
|
561
660
|
}
|
|
562
661
|
// ── Phase 3: Final Agent Response ───────────────────────────────────────
|
|
563
|
-
|
|
564
|
-
if (cleanContent) {
|
|
565
|
-
console.log(formatResponseText(cleanContent));
|
|
566
|
-
console.log(""); // one trailing blank line
|
|
567
|
-
}
|
|
662
|
+
// Content has already been streamed in real-time.
|
|
568
663
|
if (iterations >= MAX_ITERATIONS) {
|
|
569
664
|
console.log(chalk.hex('#ff453a')('✕ error'));
|
|
570
665
|
console.log(chalk.dim(' Max tool iterations reached.'));
|