@corbat-tech/coco 2.22.2 → 2.23.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.
- package/README.md +110 -372
- package/dist/cli/index.js +216 -68
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +109 -54
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1792,6 +1792,7 @@ var init_openai = __esm({
|
|
|
1792
1792
|
requestParams
|
|
1793
1793
|
);
|
|
1794
1794
|
const toolCallBuilders = /* @__PURE__ */ new Map();
|
|
1795
|
+
let lastToolCallKey = null;
|
|
1795
1796
|
const streamTimeout = this.config.timeout ?? 12e4;
|
|
1796
1797
|
let lastActivityTime = Date.now();
|
|
1797
1798
|
const timeoutController = new AbortController();
|
|
@@ -1841,9 +1842,9 @@ var init_openai = __esm({
|
|
|
1841
1842
|
}
|
|
1842
1843
|
if (delta?.tool_calls) {
|
|
1843
1844
|
for (const toolCallDelta of delta.tool_calls) {
|
|
1844
|
-
const
|
|
1845
|
-
if (!toolCallBuilders.has(
|
|
1846
|
-
toolCallBuilders.set(
|
|
1845
|
+
const key = typeof toolCallDelta.index === "number" ? `index:${toolCallDelta.index}` : typeof toolCallDelta.id === "string" && toolCallDelta.id.length > 0 ? `id:${toolCallDelta.id}` : toolCallBuilders.size === 1 ? Array.from(toolCallBuilders.keys())[0] ?? `fallback:${toolCallBuilders.size}` : lastToolCallKey ?? `fallback:${toolCallBuilders.size}`;
|
|
1846
|
+
if (!toolCallBuilders.has(key)) {
|
|
1847
|
+
toolCallBuilders.set(key, {
|
|
1847
1848
|
id: toolCallDelta.id ?? "",
|
|
1848
1849
|
name: toolCallDelta.function?.name ?? "",
|
|
1849
1850
|
arguments: ""
|
|
@@ -1856,7 +1857,8 @@ var init_openai = __esm({
|
|
|
1856
1857
|
}
|
|
1857
1858
|
};
|
|
1858
1859
|
}
|
|
1859
|
-
const builder = toolCallBuilders.get(
|
|
1860
|
+
const builder = toolCallBuilders.get(key);
|
|
1861
|
+
lastToolCallKey = key;
|
|
1860
1862
|
if (toolCallDelta.id) {
|
|
1861
1863
|
builder.id = toolCallDelta.id;
|
|
1862
1864
|
}
|
|
@@ -2444,6 +2446,7 @@ var init_openai = __esm({
|
|
|
2444
2446
|
requestParams
|
|
2445
2447
|
);
|
|
2446
2448
|
const fnCallBuilders = /* @__PURE__ */ new Map();
|
|
2449
|
+
const outputIndexToBuilderKey = /* @__PURE__ */ new Map();
|
|
2447
2450
|
const streamTimeout = this.config.timeout ?? 12e4;
|
|
2448
2451
|
let lastActivityTime = Date.now();
|
|
2449
2452
|
const timeoutController = new AbortController();
|
|
@@ -2473,8 +2476,11 @@ var init_openai = __esm({
|
|
|
2473
2476
|
fnCallBuilders.set(itemKey, {
|
|
2474
2477
|
callId: fc.call_id,
|
|
2475
2478
|
name: fc.name,
|
|
2476
|
-
arguments: ""
|
|
2479
|
+
arguments: fc.arguments ?? ""
|
|
2477
2480
|
});
|
|
2481
|
+
if (typeof event.output_index === "number") {
|
|
2482
|
+
outputIndexToBuilderKey.set(event.output_index, itemKey);
|
|
2483
|
+
}
|
|
2478
2484
|
yield {
|
|
2479
2485
|
type: "tool_use_start",
|
|
2480
2486
|
toolCall: { id: fc.call_id, name: fc.name }
|
|
@@ -2483,7 +2489,9 @@ var init_openai = __esm({
|
|
|
2483
2489
|
break;
|
|
2484
2490
|
case "response.function_call_arguments.delta":
|
|
2485
2491
|
{
|
|
2486
|
-
const
|
|
2492
|
+
const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
|
|
2493
|
+
if (!builderKey) break;
|
|
2494
|
+
const builder = fnCallBuilders.get(builderKey);
|
|
2487
2495
|
if (builder) {
|
|
2488
2496
|
builder.arguments += event.delta;
|
|
2489
2497
|
}
|
|
@@ -2491,17 +2499,22 @@ var init_openai = __esm({
|
|
|
2491
2499
|
break;
|
|
2492
2500
|
case "response.function_call_arguments.done":
|
|
2493
2501
|
{
|
|
2494
|
-
const
|
|
2502
|
+
const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
|
|
2503
|
+
if (!builderKey) break;
|
|
2504
|
+
const builder = fnCallBuilders.get(builderKey);
|
|
2495
2505
|
if (builder) {
|
|
2496
2506
|
yield {
|
|
2497
2507
|
type: "tool_use_end",
|
|
2498
2508
|
toolCall: {
|
|
2499
2509
|
id: builder.callId,
|
|
2500
2510
|
name: builder.name,
|
|
2501
|
-
input: this.parseResponsesArguments(event.arguments)
|
|
2511
|
+
input: this.parseResponsesArguments(event.arguments ?? builder.arguments)
|
|
2502
2512
|
}
|
|
2503
2513
|
};
|
|
2504
|
-
fnCallBuilders.delete(
|
|
2514
|
+
fnCallBuilders.delete(builderKey);
|
|
2515
|
+
for (const [idx, key] of outputIndexToBuilderKey.entries()) {
|
|
2516
|
+
if (key === builderKey) outputIndexToBuilderKey.delete(idx);
|
|
2517
|
+
}
|
|
2505
2518
|
}
|
|
2506
2519
|
}
|
|
2507
2520
|
break;
|
|
@@ -4640,6 +4653,7 @@ var init_codex = __esm({
|
|
|
4640
4653
|
let outputTokens = 0;
|
|
4641
4654
|
const toolCalls = [];
|
|
4642
4655
|
const fnCallBuilders = /* @__PURE__ */ new Map();
|
|
4656
|
+
const outputIndexToBuilderKey = /* @__PURE__ */ new Map();
|
|
4643
4657
|
await this.readSSEStream(response, (event) => {
|
|
4644
4658
|
if (event.id) responseId = event.id;
|
|
4645
4659
|
switch (event.type) {
|
|
@@ -4656,25 +4670,35 @@ var init_codex = __esm({
|
|
|
4656
4670
|
fnCallBuilders.set(itemKey, {
|
|
4657
4671
|
callId: item.call_id,
|
|
4658
4672
|
name: item.name,
|
|
4659
|
-
arguments: ""
|
|
4673
|
+
arguments: item.arguments ?? ""
|
|
4660
4674
|
});
|
|
4675
|
+
if (typeof event.output_index === "number") {
|
|
4676
|
+
outputIndexToBuilderKey.set(event.output_index, itemKey);
|
|
4677
|
+
}
|
|
4661
4678
|
}
|
|
4662
4679
|
break;
|
|
4663
4680
|
}
|
|
4664
4681
|
case "response.function_call_arguments.delta": {
|
|
4665
|
-
const
|
|
4682
|
+
const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
|
|
4683
|
+
if (!builderKey) break;
|
|
4684
|
+
const builder = fnCallBuilders.get(builderKey);
|
|
4666
4685
|
if (builder) builder.arguments += event.delta ?? "";
|
|
4667
4686
|
break;
|
|
4668
4687
|
}
|
|
4669
4688
|
case "response.function_call_arguments.done": {
|
|
4670
|
-
const
|
|
4689
|
+
const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
|
|
4690
|
+
if (!builderKey) break;
|
|
4691
|
+
const builder = fnCallBuilders.get(builderKey);
|
|
4671
4692
|
if (builder) {
|
|
4672
4693
|
toolCalls.push({
|
|
4673
4694
|
id: builder.callId,
|
|
4674
4695
|
name: builder.name,
|
|
4675
|
-
input: parseArguments(event.arguments)
|
|
4696
|
+
input: parseArguments(event.arguments ?? builder.arguments)
|
|
4676
4697
|
});
|
|
4677
|
-
fnCallBuilders.delete(
|
|
4698
|
+
fnCallBuilders.delete(builderKey);
|
|
4699
|
+
for (const [idx, key] of outputIndexToBuilderKey.entries()) {
|
|
4700
|
+
if (key === builderKey) outputIndexToBuilderKey.delete(idx);
|
|
4701
|
+
}
|
|
4678
4702
|
}
|
|
4679
4703
|
break;
|
|
4680
4704
|
}
|
|
@@ -4787,6 +4811,7 @@ var init_codex = __esm({
|
|
|
4787
4811
|
const decoder = new TextDecoder();
|
|
4788
4812
|
let buffer = "";
|
|
4789
4813
|
const fnCallBuilders = /* @__PURE__ */ new Map();
|
|
4814
|
+
const outputIndexToBuilderKey = /* @__PURE__ */ new Map();
|
|
4790
4815
|
let lastActivityTime = Date.now();
|
|
4791
4816
|
const timeoutController = new AbortController();
|
|
4792
4817
|
const timeoutInterval = setInterval(() => {
|
|
@@ -4825,8 +4850,11 @@ var init_codex = __esm({
|
|
|
4825
4850
|
fnCallBuilders.set(itemKey, {
|
|
4826
4851
|
callId: item.call_id,
|
|
4827
4852
|
name: item.name,
|
|
4828
|
-
arguments: ""
|
|
4853
|
+
arguments: item.arguments ?? ""
|
|
4829
4854
|
});
|
|
4855
|
+
if (typeof event.output_index === "number") {
|
|
4856
|
+
outputIndexToBuilderKey.set(event.output_index, itemKey);
|
|
4857
|
+
}
|
|
4830
4858
|
yield {
|
|
4831
4859
|
type: "tool_use_start",
|
|
4832
4860
|
toolCall: { id: item.call_id, name: item.name }
|
|
@@ -4835,14 +4863,18 @@ var init_codex = __esm({
|
|
|
4835
4863
|
break;
|
|
4836
4864
|
}
|
|
4837
4865
|
case "response.function_call_arguments.delta": {
|
|
4838
|
-
const
|
|
4866
|
+
const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
|
|
4867
|
+
if (!builderKey) break;
|
|
4868
|
+
const builder = fnCallBuilders.get(builderKey);
|
|
4839
4869
|
if (builder) {
|
|
4840
4870
|
builder.arguments += event.delta ?? "";
|
|
4841
4871
|
}
|
|
4842
4872
|
break;
|
|
4843
4873
|
}
|
|
4844
4874
|
case "response.function_call_arguments.done": {
|
|
4845
|
-
const
|
|
4875
|
+
const builderKey = (event.item_id && fnCallBuilders.has(event.item_id) ? event.item_id : null) ?? (typeof event.output_index === "number" ? outputIndexToBuilderKey.get(event.output_index) ?? null : null) ?? (fnCallBuilders.size === 1 ? Array.from(fnCallBuilders.keys())[0] : null);
|
|
4876
|
+
if (!builderKey) break;
|
|
4877
|
+
const builder = fnCallBuilders.get(builderKey);
|
|
4846
4878
|
if (builder) {
|
|
4847
4879
|
yield {
|
|
4848
4880
|
type: "tool_use_end",
|
|
@@ -4852,7 +4884,10 @@ var init_codex = __esm({
|
|
|
4852
4884
|
input: parseArguments(event.arguments ?? builder.arguments)
|
|
4853
4885
|
}
|
|
4854
4886
|
};
|
|
4855
|
-
fnCallBuilders.delete(
|
|
4887
|
+
fnCallBuilders.delete(builderKey);
|
|
4888
|
+
for (const [idx, key] of outputIndexToBuilderKey.entries()) {
|
|
4889
|
+
if (key === builderKey) outputIndexToBuilderKey.delete(idx);
|
|
4890
|
+
}
|
|
4856
4891
|
}
|
|
4857
4892
|
break;
|
|
4858
4893
|
}
|
|
@@ -5243,8 +5278,8 @@ var init_gemini = __esm({
|
|
|
5243
5278
|
const { history, lastMessage } = this.convertMessages(messages);
|
|
5244
5279
|
const chat = model.startChat({ history });
|
|
5245
5280
|
const result = await chat.sendMessageStream(lastMessage);
|
|
5246
|
-
const emittedToolCalls = /* @__PURE__ */ new Set();
|
|
5247
5281
|
let streamStopReason;
|
|
5282
|
+
let streamToolCallCounter = 0;
|
|
5248
5283
|
for await (const chunk of result.stream) {
|
|
5249
5284
|
const text13 = chunk.text();
|
|
5250
5285
|
if (text13) {
|
|
@@ -5259,30 +5294,23 @@ var init_gemini = __esm({
|
|
|
5259
5294
|
for (const part of candidate.content.parts) {
|
|
5260
5295
|
if ("functionCall" in part && part.functionCall) {
|
|
5261
5296
|
const funcCall = part.functionCall;
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
}
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
}
|
|
5280
|
-
};
|
|
5281
|
-
yield {
|
|
5282
|
-
type: "tool_use_end",
|
|
5283
|
-
toolCall
|
|
5284
|
-
};
|
|
5285
|
-
}
|
|
5297
|
+
streamToolCallCounter++;
|
|
5298
|
+
const toolCall = {
|
|
5299
|
+
id: `gemini_call_${streamToolCallCounter}`,
|
|
5300
|
+
name: funcCall.name,
|
|
5301
|
+
input: funcCall.args ?? {}
|
|
5302
|
+
};
|
|
5303
|
+
yield {
|
|
5304
|
+
type: "tool_use_start",
|
|
5305
|
+
toolCall: {
|
|
5306
|
+
id: toolCall.id,
|
|
5307
|
+
name: toolCall.name
|
|
5308
|
+
}
|
|
5309
|
+
};
|
|
5310
|
+
yield {
|
|
5311
|
+
type: "tool_use_end",
|
|
5312
|
+
toolCall
|
|
5313
|
+
};
|
|
5286
5314
|
}
|
|
5287
5315
|
}
|
|
5288
5316
|
}
|
|
@@ -5357,13 +5385,13 @@ var init_gemini = __esm({
|
|
|
5357
5385
|
* Convert messages to Gemini format
|
|
5358
5386
|
*/
|
|
5359
5387
|
convertMessages(messages) {
|
|
5388
|
+
const toolNameByUseId = this.buildToolUseNameMap(messages);
|
|
5389
|
+
const conversation = messages.filter((m) => m.role !== "system");
|
|
5360
5390
|
const history = [];
|
|
5361
5391
|
let lastUserMessage = "";
|
|
5362
|
-
for (
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
}
|
|
5366
|
-
const parts = this.convertContent(msg.content);
|
|
5392
|
+
for (let i = 0; i < conversation.length; i++) {
|
|
5393
|
+
const msg = conversation[i];
|
|
5394
|
+
const isLastMessage = i === conversation.length - 1;
|
|
5367
5395
|
if (msg.role === "user") {
|
|
5368
5396
|
if (Array.isArray(msg.content) && msg.content[0]?.type === "tool_result") {
|
|
5369
5397
|
const functionResponses = [];
|
|
@@ -5372,23 +5400,49 @@ var init_gemini = __esm({
|
|
|
5372
5400
|
const toolResult = block;
|
|
5373
5401
|
functionResponses.push({
|
|
5374
5402
|
functionResponse: {
|
|
5375
|
-
name
|
|
5376
|
-
//
|
|
5403
|
+
// Gemini expects the function name in functionResponse.name.
|
|
5404
|
+
// Recover it from prior assistant tool_use blocks when possible.
|
|
5405
|
+
name: toolNameByUseId.get(toolResult.tool_use_id) ?? toolResult.tool_use_id,
|
|
5377
5406
|
response: { result: toolResult.content }
|
|
5378
5407
|
}
|
|
5379
5408
|
});
|
|
5380
5409
|
}
|
|
5381
5410
|
}
|
|
5382
|
-
|
|
5411
|
+
if (isLastMessage) {
|
|
5412
|
+
lastUserMessage = functionResponses;
|
|
5413
|
+
} else {
|
|
5414
|
+
history.push({ role: "user", parts: functionResponses });
|
|
5415
|
+
}
|
|
5383
5416
|
} else {
|
|
5384
|
-
|
|
5417
|
+
const parts = this.convertContent(msg.content);
|
|
5418
|
+
if (isLastMessage) {
|
|
5419
|
+
lastUserMessage = parts;
|
|
5420
|
+
} else {
|
|
5421
|
+
history.push({ role: "user", parts });
|
|
5422
|
+
}
|
|
5385
5423
|
}
|
|
5386
5424
|
} else if (msg.role === "assistant") {
|
|
5425
|
+
const parts = this.convertContent(msg.content);
|
|
5387
5426
|
history.push({ role: "model", parts });
|
|
5388
5427
|
}
|
|
5389
5428
|
}
|
|
5390
5429
|
return { history, lastMessage: lastUserMessage };
|
|
5391
5430
|
}
|
|
5431
|
+
/**
|
|
5432
|
+
* Build a map from tool_use IDs to function names from assistant history.
|
|
5433
|
+
*/
|
|
5434
|
+
buildToolUseNameMap(messages) {
|
|
5435
|
+
const map = /* @__PURE__ */ new Map();
|
|
5436
|
+
for (const msg of messages) {
|
|
5437
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.content)) continue;
|
|
5438
|
+
for (const block of msg.content) {
|
|
5439
|
+
if (block.type === "tool_use") {
|
|
5440
|
+
map.set(block.id, block.name);
|
|
5441
|
+
}
|
|
5442
|
+
}
|
|
5443
|
+
}
|
|
5444
|
+
return map;
|
|
5445
|
+
}
|
|
5392
5446
|
/**
|
|
5393
5447
|
* Convert content to Gemini parts
|
|
5394
5448
|
*/
|
|
@@ -5465,14 +5519,15 @@ var init_gemini = __esm({
|
|
|
5465
5519
|
let textContent = "";
|
|
5466
5520
|
const toolCalls = [];
|
|
5467
5521
|
if (candidate?.content?.parts) {
|
|
5522
|
+
let toolIndex = 0;
|
|
5468
5523
|
for (const part of candidate.content.parts) {
|
|
5469
5524
|
if ("text" in part && part.text) {
|
|
5470
5525
|
textContent += part.text;
|
|
5471
5526
|
}
|
|
5472
5527
|
if ("functionCall" in part && part.functionCall) {
|
|
5528
|
+
toolIndex++;
|
|
5473
5529
|
toolCalls.push({
|
|
5474
|
-
id:
|
|
5475
|
-
// Use name as ID for Gemini
|
|
5530
|
+
id: `gemini_call_${toolIndex}`,
|
|
5476
5531
|
name: part.functionCall.name,
|
|
5477
5532
|
input: part.functionCall.args ?? {}
|
|
5478
5533
|
});
|
|
@@ -9617,7 +9672,15 @@ Responses are short and direct by default. Lead with the answer or action, not r
|
|
|
9617
9672
|
|
|
9618
9673
|
## File Changes
|
|
9619
9674
|
|
|
9620
|
-
**Never output raw diff or unified diff format in your responses.** Use edit_file and write_file to make changes \u2014 Coco renders a visual diff automatically.
|
|
9675
|
+
**Never output raw diff or unified diff format in your responses.** Use edit_file and write_file to make changes \u2014 Coco renders a visual diff automatically.
|
|
9676
|
+
|
|
9677
|
+
## Output Discipline
|
|
9678
|
+
|
|
9679
|
+
**NEVER echo file contents in your responses.** When you read a file, extract only the specific information needed \u2014 do NOT reprint whole files, functions, or large excerpts. The terminal shows which files you read and their line counts \u2014 the user does not need to see the content again.
|
|
9680
|
+
|
|
9681
|
+
**During tool-calling iterations, keep text minimal.** A single short orienting line before tool calls is acceptable. Do NOT explain every step, narrate what you are about to do, or produce paragraphs between tool calls. Reserve explanatory text for your final response after all tools have completed.
|
|
9682
|
+
|
|
9683
|
+
**Code blocks in responses are expensive.** Only include a code block when the user explicitly asks to see code, or when the code IS the deliverable (e.g., a script to paste in a terminal). Never include a code block to "show your work" when you can write the file directly instead.`;
|
|
9621
9684
|
SHELL_METACHARACTERS = /[;|&`$(){}<>!\n\\'"]/;
|
|
9622
9685
|
SAFE_COMMAND_VALIDATORS = {
|
|
9623
9686
|
git: (args) => {
|
|
@@ -31538,6 +31601,15 @@ async function selectModelInteractively(models, currentModelId) {
|
|
|
31538
31601
|
renderMenu();
|
|
31539
31602
|
});
|
|
31540
31603
|
}
|
|
31604
|
+
async function persistModelPreference(provider, model) {
|
|
31605
|
+
try {
|
|
31606
|
+
await saveProviderPreference(provider, model);
|
|
31607
|
+
} catch (error) {
|
|
31608
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
31609
|
+
console.log(chalk2.yellow(`\u26A0 Could not persist model preference: ${reason}`));
|
|
31610
|
+
console.log(chalk2.dim(" Model changed for this session only.\n"));
|
|
31611
|
+
}
|
|
31612
|
+
}
|
|
31541
31613
|
var modelCommand = {
|
|
31542
31614
|
name: "model",
|
|
31543
31615
|
aliases: ["m"],
|
|
@@ -31586,7 +31658,7 @@ var modelCommand = {
|
|
|
31586
31658
|
return false;
|
|
31587
31659
|
}
|
|
31588
31660
|
session.config.provider.model = selectedModel;
|
|
31589
|
-
await
|
|
31661
|
+
await persistModelPreference(currentProvider, selectedModel);
|
|
31590
31662
|
const modelInfo2 = providerDef.models.find((m) => m.id === selectedModel);
|
|
31591
31663
|
console.log(chalk2.green(`\u2713 Switched to ${modelInfo2?.name ?? selectedModel}
|
|
31592
31664
|
`));
|
|
@@ -31608,7 +31680,7 @@ var modelCommand = {
|
|
|
31608
31680
|
if (!foundInProvider) {
|
|
31609
31681
|
console.log(chalk2.yellow(`Model "${newModel}" not in known list, setting anyway...`));
|
|
31610
31682
|
session.config.provider.model = newModel;
|
|
31611
|
-
await
|
|
31683
|
+
await persistModelPreference(currentProvider, newModel);
|
|
31612
31684
|
console.log(chalk2.green(`\u2713 Model set to: ${newModel}
|
|
31613
31685
|
`));
|
|
31614
31686
|
return false;
|
|
@@ -31623,7 +31695,7 @@ var modelCommand = {
|
|
|
31623
31695
|
return false;
|
|
31624
31696
|
}
|
|
31625
31697
|
session.config.provider.model = newModel;
|
|
31626
|
-
await
|
|
31698
|
+
await persistModelPreference(currentProvider, newModel);
|
|
31627
31699
|
const modelInfo = providerDef.models.find((m) => m.id === newModel);
|
|
31628
31700
|
console.log(chalk2.green(`\u2713 Switched to ${modelInfo?.name ?? newModel}
|
|
31629
31701
|
`));
|
|
@@ -47052,6 +47124,8 @@ var streamingIndicatorInterval = null;
|
|
|
47052
47124
|
var streamingIndicatorFrame = 0;
|
|
47053
47125
|
var STREAMING_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
47054
47126
|
var getTerminalWidth2 = () => process.stdout.columns || 80;
|
|
47127
|
+
var MAX_STREAMING_CODE_LINES = 50;
|
|
47128
|
+
var STREAMING_CODE_HEAD_LINES = 40;
|
|
47055
47129
|
function startStreamingIndicator() {
|
|
47056
47130
|
if (streamingIndicatorActive) return;
|
|
47057
47131
|
streamingIndicatorActive = true;
|
|
@@ -47375,11 +47449,17 @@ function renderSimpleCodeBlock(lang, lines, blockId) {
|
|
|
47375
47449
|
const isDiff = lang === "diff" || !lang && looksLikeDiff(lines);
|
|
47376
47450
|
const title = lang || "Code";
|
|
47377
47451
|
console.log(chalk2.dim(`${title} \xB7 #${blockId}`));
|
|
47452
|
+
let displayLines = lines;
|
|
47453
|
+
let truncatedCount = 0;
|
|
47454
|
+
if (!isDiff && lines.length > MAX_STREAMING_CODE_LINES) {
|
|
47455
|
+
displayLines = lines.slice(0, STREAMING_CODE_HEAD_LINES);
|
|
47456
|
+
truncatedCount = lines.length - STREAMING_CODE_HEAD_LINES;
|
|
47457
|
+
}
|
|
47378
47458
|
const bgDel = chalk2.bgRgb(80, 20, 20);
|
|
47379
47459
|
const bgAdd = chalk2.bgRgb(20, 60, 20);
|
|
47380
47460
|
let oldLineNo = 0;
|
|
47381
47461
|
let newLineNo = 0;
|
|
47382
|
-
for (const line of
|
|
47462
|
+
for (const line of displayLines) {
|
|
47383
47463
|
if (isDiff) {
|
|
47384
47464
|
const hunkMatch = line.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
|
47385
47465
|
if (hunkMatch) {
|
|
@@ -47407,6 +47487,9 @@ function renderSimpleCodeBlock(lang, lines, blockId) {
|
|
|
47407
47487
|
}
|
|
47408
47488
|
}
|
|
47409
47489
|
}
|
|
47490
|
+
if (truncatedCount > 0) {
|
|
47491
|
+
console.log(chalk2.dim(` \u2026 ${truncatedCount} more lines \xB7 /copy ${blockId} for full content`));
|
|
47492
|
+
}
|
|
47410
47493
|
console.log(chalk2.dim(` #${blockId} \xB7 /copy ${blockId}`));
|
|
47411
47494
|
}
|
|
47412
47495
|
function formatDiffLineNo(line, oldLineNo, newLineNo) {
|
|
@@ -50058,6 +50141,8 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
50058
50141
|
const maxIterations = session.config.agent.maxToolIterations;
|
|
50059
50142
|
const toolErrorCounts = /* @__PURE__ */ new Map();
|
|
50060
50143
|
const MAX_CONSECUTIVE_TOOL_ERRORS = 3;
|
|
50144
|
+
const ITERATION_LIMIT_WARNING_RATIO = 0.75;
|
|
50145
|
+
const ITERATION_LIMIT_SUMMARY_PROMPT = `[System: You have now used all allowed iterations and tool calls are no longer available. Write your final response immediately: (1) briefly state what was completed, (2) describe what still needs to be done, (3) give specific next steps so the user can continue. Be concise and direct.]`;
|
|
50061
50146
|
const INLINE_RESULT_MAX_CHARS = 8e3;
|
|
50062
50147
|
const INLINE_RESULT_HEAD_CHARS = 6500;
|
|
50063
50148
|
const INLINE_RESULT_TAIL_CHARS = 1e3;
|
|
@@ -50072,6 +50157,8 @@ ${tail}`;
|
|
|
50072
50157
|
}
|
|
50073
50158
|
while (iteration < maxIterations) {
|
|
50074
50159
|
iteration++;
|
|
50160
|
+
const isLastIteration = iteration === maxIterations;
|
|
50161
|
+
const iterationTextChunks = [];
|
|
50075
50162
|
if (options.signal?.aborted) {
|
|
50076
50163
|
return abortReturn();
|
|
50077
50164
|
}
|
|
@@ -50099,7 +50186,7 @@ ${tail}`;
|
|
|
50099
50186
|
}
|
|
50100
50187
|
responseContent += chunk.text;
|
|
50101
50188
|
finalContent += chunk.text;
|
|
50102
|
-
|
|
50189
|
+
iterationTextChunks.push(chunk);
|
|
50103
50190
|
}
|
|
50104
50191
|
if (chunk.type === "tool_use_start" && chunk.toolCall) {
|
|
50105
50192
|
flushLineBuffer();
|
|
@@ -50176,6 +50263,11 @@ ${tail}`;
|
|
|
50176
50263
|
error: errorMsg
|
|
50177
50264
|
};
|
|
50178
50265
|
}
|
|
50266
|
+
if (collectedToolCalls.length === 0) {
|
|
50267
|
+
for (const bufferedChunk of iterationTextChunks) {
|
|
50268
|
+
options.onStream?.(bufferedChunk);
|
|
50269
|
+
}
|
|
50270
|
+
}
|
|
50179
50271
|
const inputText = messages.map((m) => {
|
|
50180
50272
|
if (typeof m.content === "string") return m.content;
|
|
50181
50273
|
try {
|
|
@@ -50351,10 +50443,20 @@ ${tail}`;
|
|
|
50351
50443
|
});
|
|
50352
50444
|
const declineReason = declinedTools.get(toolCall.id);
|
|
50353
50445
|
if (declineReason) {
|
|
50446
|
+
let skipContent;
|
|
50447
|
+
if (declineReason === "User declined") {
|
|
50448
|
+
skipContent = "The user explicitly declined this tool call. You MUST find a different approach \u2014 do not retry the same action or parameters.";
|
|
50449
|
+
} else if (declineReason.toLowerCase().includes("timeout") || declineReason.toLowerCase().includes("timed out")) {
|
|
50450
|
+
skipContent = `Tool execution timed out: ${declineReason}. Try a simpler or faster alternative, or break the task into smaller steps.`;
|
|
50451
|
+
} else if (declineReason.toLowerCase().includes("abort")) {
|
|
50452
|
+
skipContent = "Tool execution was cancelled.";
|
|
50453
|
+
} else {
|
|
50454
|
+
skipContent = `Tool execution was skipped: ${declineReason}`;
|
|
50455
|
+
}
|
|
50354
50456
|
toolResults.push({
|
|
50355
50457
|
type: "tool_result",
|
|
50356
50458
|
tool_use_id: toolCall.id,
|
|
50357
|
-
content:
|
|
50459
|
+
content: skipContent,
|
|
50358
50460
|
is_error: true
|
|
50359
50461
|
});
|
|
50360
50462
|
continue;
|
|
@@ -50408,6 +50510,28 @@ ${tail}`;
|
|
|
50408
50510
|
}
|
|
50409
50511
|
}
|
|
50410
50512
|
}
|
|
50513
|
+
if (toolResults.length > 0) {
|
|
50514
|
+
const warningThreshold = Math.ceil(maxIterations * ITERATION_LIMIT_WARNING_RATIO);
|
|
50515
|
+
const lastIdx = toolResults.length - 1;
|
|
50516
|
+
const last = toolResults[lastIdx];
|
|
50517
|
+
if (isLastIteration && !stuckInErrorLoop) {
|
|
50518
|
+
toolResults[lastIdx] = {
|
|
50519
|
+
...last,
|
|
50520
|
+
content: typeof last.content === "string" ? last.content + `
|
|
50521
|
+
|
|
50522
|
+
${ITERATION_LIMIT_SUMMARY_PROMPT}` : ITERATION_LIMIT_SUMMARY_PROMPT
|
|
50523
|
+
};
|
|
50524
|
+
} else if (iteration === warningThreshold) {
|
|
50525
|
+
const remaining = maxIterations - iteration;
|
|
50526
|
+
const warning = `
|
|
50527
|
+
|
|
50528
|
+
[System: Iteration budget warning \u2014 ${iteration} of ${maxIterations} iterations used, ${remaining} remaining. Begin wrapping up your task. Prioritize the most critical remaining steps.]`;
|
|
50529
|
+
toolResults[lastIdx] = {
|
|
50530
|
+
...last,
|
|
50531
|
+
content: typeof last.content === "string" ? last.content + warning : warning
|
|
50532
|
+
};
|
|
50533
|
+
}
|
|
50534
|
+
}
|
|
50411
50535
|
const assistantContent = response.content ? [{ type: "text", text: response.content }, ...toolUses] : toolUses;
|
|
50412
50536
|
addMessage(session, {
|
|
50413
50537
|
role: "assistant",
|
|
@@ -50452,14 +50576,38 @@ ${tail}`;
|
|
|
50452
50576
|
}
|
|
50453
50577
|
break;
|
|
50454
50578
|
}
|
|
50455
|
-
|
|
50456
|
-
|
|
50457
|
-
|
|
50579
|
+
if (isLastIteration && toolResults.length > 0) {
|
|
50580
|
+
let summaryThinkingEnded = false;
|
|
50581
|
+
options.onThinkingStart?.();
|
|
50582
|
+
try {
|
|
50583
|
+
const finalMessages = getConversationContext(session, toolRegistry);
|
|
50584
|
+
for await (const chunk of provider.streamWithTools(finalMessages, {
|
|
50585
|
+
tools: [],
|
|
50586
|
+
maxTokens: session.config.provider.maxTokens,
|
|
50587
|
+
signal: options.signal
|
|
50588
|
+
})) {
|
|
50589
|
+
if (options.signal?.aborted) break;
|
|
50590
|
+
if (chunk.type === "text" && chunk.text) {
|
|
50591
|
+
if (!summaryThinkingEnded) {
|
|
50592
|
+
options.onThinkingEnd?.();
|
|
50593
|
+
summaryThinkingEnded = true;
|
|
50594
|
+
}
|
|
50595
|
+
finalContent += chunk.text;
|
|
50596
|
+
options.onStream?.(chunk);
|
|
50597
|
+
}
|
|
50598
|
+
if (chunk.type === "done") break;
|
|
50599
|
+
}
|
|
50600
|
+
} catch {
|
|
50601
|
+
const notice = `
|
|
50458
50602
|
|
|
50459
|
-
|
|
50460
|
-
|
|
50461
|
-
|
|
50462
|
-
|
|
50603
|
+
I have reached the maximum iteration limit (${maxIterations}). The task may be incomplete. Type "continue" to give me more iterations, or describe what you'd like me to focus on next.`;
|
|
50604
|
+
finalContent += notice;
|
|
50605
|
+
options.onStream?.({ type: "text", text: notice });
|
|
50606
|
+
} finally {
|
|
50607
|
+
if (!summaryThinkingEnded) options.onThinkingEnd?.();
|
|
50608
|
+
}
|
|
50609
|
+
break;
|
|
50610
|
+
}
|
|
50463
50611
|
}
|
|
50464
50612
|
options.onStream?.({ type: "done" });
|
|
50465
50613
|
return {
|