@corbat-tech/coco 2.23.1 → 2.24.0
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/cli/index.js +533 -213
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +548 -204
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/cli/index.js
CHANGED
|
@@ -1425,6 +1425,150 @@ var init_anthropic = __esm({
|
|
|
1425
1425
|
};
|
|
1426
1426
|
}
|
|
1427
1427
|
});
|
|
1428
|
+
function getSingleBuilderKey(builders) {
|
|
1429
|
+
return builders.size === 1 ? Array.from(builders.keys())[0] ?? null : null;
|
|
1430
|
+
}
|
|
1431
|
+
function parseToolCallArguments(args, providerName) {
|
|
1432
|
+
try {
|
|
1433
|
+
return args ? JSON.parse(args) : {};
|
|
1434
|
+
} catch {
|
|
1435
|
+
try {
|
|
1436
|
+
if (args) {
|
|
1437
|
+
const repaired = jsonrepair(args);
|
|
1438
|
+
return JSON.parse(repaired);
|
|
1439
|
+
}
|
|
1440
|
+
} catch {
|
|
1441
|
+
console.error(`[${providerName}] Cannot parse tool arguments: ${args.slice(0, 200)}`);
|
|
1442
|
+
}
|
|
1443
|
+
return {};
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
var ChatToolCallAssembler, ResponsesToolCallAssembler;
|
|
1447
|
+
var init_tool_call_normalizer = __esm({
|
|
1448
|
+
"src/providers/tool-call-normalizer.ts"() {
|
|
1449
|
+
ChatToolCallAssembler = class {
|
|
1450
|
+
builders = /* @__PURE__ */ new Map();
|
|
1451
|
+
lastBuilderKey = null;
|
|
1452
|
+
consume(delta) {
|
|
1453
|
+
const key = typeof delta.index === "number" ? `index:${delta.index}` : typeof delta.id === "string" && delta.id.length > 0 ? `id:${delta.id}` : getSingleBuilderKey(this.builders) ?? this.lastBuilderKey ?? `fallback:${this.builders.size}`;
|
|
1454
|
+
let started;
|
|
1455
|
+
if (!this.builders.has(key)) {
|
|
1456
|
+
const initialId = delta.id ?? "";
|
|
1457
|
+
const initialName = delta.function?.name ?? "";
|
|
1458
|
+
this.builders.set(key, { id: initialId, name: initialName, arguments: "" });
|
|
1459
|
+
started = {
|
|
1460
|
+
id: initialId || void 0,
|
|
1461
|
+
name: initialName || void 0
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
const builder = this.builders.get(key);
|
|
1465
|
+
this.lastBuilderKey = key;
|
|
1466
|
+
if (delta.id) {
|
|
1467
|
+
builder.id = delta.id;
|
|
1468
|
+
}
|
|
1469
|
+
if (delta.function?.name) {
|
|
1470
|
+
builder.name = delta.function.name;
|
|
1471
|
+
}
|
|
1472
|
+
const text13 = delta.function?.arguments ?? "";
|
|
1473
|
+
if (!text13) return { started };
|
|
1474
|
+
builder.arguments += text13;
|
|
1475
|
+
return {
|
|
1476
|
+
started,
|
|
1477
|
+
argumentDelta: {
|
|
1478
|
+
id: builder.id,
|
|
1479
|
+
name: builder.name,
|
|
1480
|
+
text: text13
|
|
1481
|
+
}
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
finalizeAll(providerName) {
|
|
1485
|
+
const result = [];
|
|
1486
|
+
for (const builder of this.builders.values()) {
|
|
1487
|
+
result.push({
|
|
1488
|
+
id: builder.id,
|
|
1489
|
+
name: builder.name,
|
|
1490
|
+
input: parseToolCallArguments(builder.arguments, providerName)
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
this.builders.clear();
|
|
1494
|
+
this.lastBuilderKey = null;
|
|
1495
|
+
return result;
|
|
1496
|
+
}
|
|
1497
|
+
};
|
|
1498
|
+
ResponsesToolCallAssembler = class {
|
|
1499
|
+
builders = /* @__PURE__ */ new Map();
|
|
1500
|
+
outputIndexToBuilderKey = /* @__PURE__ */ new Map();
|
|
1501
|
+
onOutputItemAdded(event) {
|
|
1502
|
+
const item = event.item;
|
|
1503
|
+
if (!item || item.type !== "function_call") return null;
|
|
1504
|
+
const callId = item.call_id ?? "";
|
|
1505
|
+
const itemKey = item.id ?? callId;
|
|
1506
|
+
this.builders.set(itemKey, {
|
|
1507
|
+
callId,
|
|
1508
|
+
name: item.name ?? "",
|
|
1509
|
+
arguments: item.arguments ?? ""
|
|
1510
|
+
});
|
|
1511
|
+
if (typeof event.output_index === "number") {
|
|
1512
|
+
this.outputIndexToBuilderKey.set(event.output_index, itemKey);
|
|
1513
|
+
}
|
|
1514
|
+
return {
|
|
1515
|
+
id: callId,
|
|
1516
|
+
name: item.name ?? ""
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1519
|
+
onArgumentsDelta(event) {
|
|
1520
|
+
const builderKey = this.resolveBuilderKey(event.item_id, event.output_index);
|
|
1521
|
+
if (!builderKey) return;
|
|
1522
|
+
const builder = this.builders.get(builderKey);
|
|
1523
|
+
if (!builder) return;
|
|
1524
|
+
builder.arguments += event.delta ?? "";
|
|
1525
|
+
}
|
|
1526
|
+
onArgumentsDone(event, providerName) {
|
|
1527
|
+
const builderKey = this.resolveBuilderKey(event.item_id, event.output_index);
|
|
1528
|
+
if (!builderKey) return null;
|
|
1529
|
+
const builder = this.builders.get(builderKey);
|
|
1530
|
+
if (!builder) return null;
|
|
1531
|
+
const toolCall = {
|
|
1532
|
+
id: builder.callId,
|
|
1533
|
+
name: builder.name,
|
|
1534
|
+
input: parseToolCallArguments(event.arguments ?? builder.arguments, providerName)
|
|
1535
|
+
};
|
|
1536
|
+
this.deleteBuilder(builderKey);
|
|
1537
|
+
return toolCall;
|
|
1538
|
+
}
|
|
1539
|
+
finalizeAll(providerName) {
|
|
1540
|
+
const calls = [];
|
|
1541
|
+
for (const builder of this.builders.values()) {
|
|
1542
|
+
calls.push({
|
|
1543
|
+
id: builder.callId,
|
|
1544
|
+
name: builder.name,
|
|
1545
|
+
input: parseToolCallArguments(builder.arguments, providerName)
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
this.builders.clear();
|
|
1549
|
+
this.outputIndexToBuilderKey.clear();
|
|
1550
|
+
return calls;
|
|
1551
|
+
}
|
|
1552
|
+
resolveBuilderKey(itemId, outputIndex) {
|
|
1553
|
+
if (itemId && this.builders.has(itemId)) {
|
|
1554
|
+
return itemId;
|
|
1555
|
+
}
|
|
1556
|
+
if (typeof outputIndex === "number") {
|
|
1557
|
+
return this.outputIndexToBuilderKey.get(outputIndex) ?? null;
|
|
1558
|
+
}
|
|
1559
|
+
return getSingleBuilderKey(this.builders);
|
|
1560
|
+
}
|
|
1561
|
+
deleteBuilder(builderKey) {
|
|
1562
|
+
this.builders.delete(builderKey);
|
|
1563
|
+
for (const [idx, key] of this.outputIndexToBuilderKey.entries()) {
|
|
1564
|
+
if (key === builderKey) {
|
|
1565
|
+
this.outputIndexToBuilderKey.delete(idx);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1428
1572
|
function needsResponsesApi(model) {
|
|
1429
1573
|
return model.includes("codex") || model.startsWith("gpt-5") || model.startsWith("o4-") || model === "o3";
|
|
1430
1574
|
}
|
|
@@ -1464,6 +1608,7 @@ var init_openai = __esm({
|
|
|
1464
1608
|
"src/providers/openai.ts"() {
|
|
1465
1609
|
init_errors();
|
|
1466
1610
|
init_retry();
|
|
1611
|
+
init_tool_call_normalizer();
|
|
1467
1612
|
DEFAULT_MODEL2 = "gpt-5.4-codex";
|
|
1468
1613
|
CONTEXT_WINDOWS2 = {
|
|
1469
1614
|
// OpenAI models
|
|
@@ -1791,8 +1936,7 @@ var init_openai = __esm({
|
|
|
1791
1936
|
const stream = await this.client.chat.completions.create(
|
|
1792
1937
|
requestParams
|
|
1793
1938
|
);
|
|
1794
|
-
const
|
|
1795
|
-
let lastToolCallKey = null;
|
|
1939
|
+
const toolCallAssembler = new ChatToolCallAssembler();
|
|
1796
1940
|
const streamTimeout = this.config.timeout ?? 12e4;
|
|
1797
1941
|
let lastActivityTime = Date.now();
|
|
1798
1942
|
const timeoutController = new AbortController();
|
|
@@ -1806,30 +1950,6 @@ var init_openai = __esm({
|
|
|
1806
1950
|
timeoutController.signal.addEventListener("abort", () => stream.controller.abort(), {
|
|
1807
1951
|
once: true
|
|
1808
1952
|
});
|
|
1809
|
-
const providerName = this.name;
|
|
1810
|
-
const parseArguments2 = (builder) => {
|
|
1811
|
-
let input = {};
|
|
1812
|
-
try {
|
|
1813
|
-
input = builder.arguments ? JSON.parse(builder.arguments) : {};
|
|
1814
|
-
} catch (error) {
|
|
1815
|
-
console.warn(
|
|
1816
|
-
`[${providerName}] Failed to parse tool call arguments for ${builder.name}: ${builder.arguments?.slice(0, 300)}`
|
|
1817
|
-
);
|
|
1818
|
-
try {
|
|
1819
|
-
if (builder.arguments) {
|
|
1820
|
-
const repaired = jsonrepair(builder.arguments);
|
|
1821
|
-
input = JSON.parse(repaired);
|
|
1822
|
-
console.log(`[${providerName}] \u2713 Successfully repaired JSON for ${builder.name}`);
|
|
1823
|
-
}
|
|
1824
|
-
} catch {
|
|
1825
|
-
console.error(
|
|
1826
|
-
`[${providerName}] Cannot repair JSON for ${builder.name}, using empty object`
|
|
1827
|
-
);
|
|
1828
|
-
console.error(`[${providerName}] Original error:`, error);
|
|
1829
|
-
}
|
|
1830
|
-
}
|
|
1831
|
-
return input;
|
|
1832
|
-
};
|
|
1833
1953
|
try {
|
|
1834
1954
|
let streamStopReason;
|
|
1835
1955
|
for await (const chunk of stream) {
|
|
@@ -1842,38 +1962,31 @@ var init_openai = __esm({
|
|
|
1842
1962
|
}
|
|
1843
1963
|
if (delta?.tool_calls) {
|
|
1844
1964
|
for (const toolCallDelta of delta.tool_calls) {
|
|
1845
|
-
const
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
name: toolCallDelta.function?.name ??
|
|
1850
|
-
arguments:
|
|
1851
|
-
}
|
|
1965
|
+
const consumed = toolCallAssembler.consume({
|
|
1966
|
+
index: toolCallDelta.index,
|
|
1967
|
+
id: toolCallDelta.id ?? void 0,
|
|
1968
|
+
function: {
|
|
1969
|
+
name: toolCallDelta.function?.name ?? void 0,
|
|
1970
|
+
arguments: toolCallDelta.function?.arguments ?? void 0
|
|
1971
|
+
}
|
|
1972
|
+
});
|
|
1973
|
+
if (consumed.started) {
|
|
1852
1974
|
yield {
|
|
1853
1975
|
type: "tool_use_start",
|
|
1854
1976
|
toolCall: {
|
|
1855
|
-
id:
|
|
1856
|
-
name:
|
|
1977
|
+
id: consumed.started.id,
|
|
1978
|
+
name: consumed.started.name
|
|
1857
1979
|
}
|
|
1858
1980
|
};
|
|
1859
1981
|
}
|
|
1860
|
-
|
|
1861
|
-
lastToolCallKey = key;
|
|
1862
|
-
if (toolCallDelta.id) {
|
|
1863
|
-
builder.id = toolCallDelta.id;
|
|
1864
|
-
}
|
|
1865
|
-
if (toolCallDelta.function?.name) {
|
|
1866
|
-
builder.name = toolCallDelta.function.name;
|
|
1867
|
-
}
|
|
1868
|
-
if (toolCallDelta.function?.arguments) {
|
|
1869
|
-
builder.arguments += toolCallDelta.function.arguments;
|
|
1982
|
+
if (consumed.argumentDelta) {
|
|
1870
1983
|
yield {
|
|
1871
1984
|
type: "tool_use_delta",
|
|
1872
1985
|
toolCall: {
|
|
1873
|
-
id:
|
|
1874
|
-
name:
|
|
1986
|
+
id: consumed.argumentDelta.id,
|
|
1987
|
+
name: consumed.argumentDelta.name
|
|
1875
1988
|
},
|
|
1876
|
-
text:
|
|
1989
|
+
text: consumed.argumentDelta.text
|
|
1877
1990
|
};
|
|
1878
1991
|
}
|
|
1879
1992
|
}
|
|
@@ -1882,27 +1995,26 @@ var init_openai = __esm({
|
|
|
1882
1995
|
if (finishReason) {
|
|
1883
1996
|
streamStopReason = this.mapFinishReason(finishReason);
|
|
1884
1997
|
}
|
|
1885
|
-
if (finishReason
|
|
1886
|
-
for (const
|
|
1998
|
+
if (finishReason) {
|
|
1999
|
+
for (const toolCall of toolCallAssembler.finalizeAll(this.name)) {
|
|
1887
2000
|
yield {
|
|
1888
2001
|
type: "tool_use_end",
|
|
1889
2002
|
toolCall: {
|
|
1890
|
-
id:
|
|
1891
|
-
name:
|
|
1892
|
-
input:
|
|
2003
|
+
id: toolCall.id,
|
|
2004
|
+
name: toolCall.name,
|
|
2005
|
+
input: toolCall.input
|
|
1893
2006
|
}
|
|
1894
2007
|
};
|
|
1895
2008
|
}
|
|
1896
|
-
toolCallBuilders.clear();
|
|
1897
2009
|
}
|
|
1898
2010
|
}
|
|
1899
|
-
for (const
|
|
2011
|
+
for (const toolCall of toolCallAssembler.finalizeAll(this.name)) {
|
|
1900
2012
|
yield {
|
|
1901
2013
|
type: "tool_use_end",
|
|
1902
2014
|
toolCall: {
|
|
1903
|
-
id:
|
|
1904
|
-
name:
|
|
1905
|
-
input:
|
|
2015
|
+
id: toolCall.id,
|
|
2016
|
+
name: toolCall.name,
|
|
2017
|
+
input: toolCall.input
|
|
1906
2018
|
}
|
|
1907
2019
|
};
|
|
1908
2020
|
}
|
|
@@ -2339,7 +2451,7 @@ var init_openai = __esm({
|
|
|
2339
2451
|
toolCalls.push({
|
|
2340
2452
|
id: item.call_id,
|
|
2341
2453
|
name: item.name,
|
|
2342
|
-
input:
|
|
2454
|
+
input: parseToolCallArguments(item.arguments, this.name)
|
|
2343
2455
|
});
|
|
2344
2456
|
}
|
|
2345
2457
|
}
|
|
@@ -2445,8 +2557,7 @@ var init_openai = __esm({
|
|
|
2445
2557
|
const stream = await this.client.responses.create(
|
|
2446
2558
|
requestParams
|
|
2447
2559
|
);
|
|
2448
|
-
const
|
|
2449
|
-
const outputIndexToBuilderKey = /* @__PURE__ */ new Map();
|
|
2560
|
+
const toolCallAssembler = new ResponsesToolCallAssembler();
|
|
2450
2561
|
const streamTimeout = this.config.timeout ?? 12e4;
|
|
2451
2562
|
let lastActivityTime = Date.now();
|
|
2452
2563
|
const timeoutController = new AbortController();
|
|
@@ -2470,67 +2581,66 @@ var init_openai = __esm({
|
|
|
2470
2581
|
yield { type: "text", text: event.delta };
|
|
2471
2582
|
break;
|
|
2472
2583
|
case "response.output_item.added":
|
|
2473
|
-
|
|
2474
|
-
const
|
|
2475
|
-
const
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2584
|
+
{
|
|
2585
|
+
const item = event.item;
|
|
2586
|
+
const start = toolCallAssembler.onOutputItemAdded({
|
|
2587
|
+
output_index: event.output_index,
|
|
2588
|
+
item: {
|
|
2589
|
+
type: item.type,
|
|
2590
|
+
id: item.id,
|
|
2591
|
+
call_id: item.call_id,
|
|
2592
|
+
name: item.name,
|
|
2593
|
+
arguments: item.arguments
|
|
2594
|
+
}
|
|
2480
2595
|
});
|
|
2481
|
-
if (
|
|
2482
|
-
outputIndexToBuilderKey.set(event.output_index, itemKey);
|
|
2483
|
-
}
|
|
2596
|
+
if (!start) break;
|
|
2484
2597
|
yield {
|
|
2485
2598
|
type: "tool_use_start",
|
|
2486
|
-
toolCall: { id:
|
|
2599
|
+
toolCall: { id: start.id, name: start.name }
|
|
2487
2600
|
};
|
|
2488
2601
|
}
|
|
2489
2602
|
break;
|
|
2490
2603
|
case "response.function_call_arguments.delta":
|
|
2491
|
-
{
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
builder.arguments += event.delta;
|
|
2497
|
-
}
|
|
2498
|
-
}
|
|
2604
|
+
toolCallAssembler.onArgumentsDelta({
|
|
2605
|
+
item_id: event.item_id,
|
|
2606
|
+
output_index: event.output_index,
|
|
2607
|
+
delta: event.delta
|
|
2608
|
+
});
|
|
2499
2609
|
break;
|
|
2500
2610
|
case "response.function_call_arguments.done":
|
|
2501
2611
|
{
|
|
2502
|
-
const
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2612
|
+
const toolCall = toolCallAssembler.onArgumentsDone(
|
|
2613
|
+
{
|
|
2614
|
+
item_id: event.item_id,
|
|
2615
|
+
output_index: event.output_index,
|
|
2616
|
+
arguments: event.arguments
|
|
2617
|
+
},
|
|
2618
|
+
this.name
|
|
2619
|
+
);
|
|
2620
|
+
if (toolCall) {
|
|
2506
2621
|
yield {
|
|
2507
2622
|
type: "tool_use_end",
|
|
2508
2623
|
toolCall: {
|
|
2509
|
-
id:
|
|
2510
|
-
name:
|
|
2511
|
-
input:
|
|
2624
|
+
id: toolCall.id,
|
|
2625
|
+
name: toolCall.name,
|
|
2626
|
+
input: toolCall.input
|
|
2512
2627
|
}
|
|
2513
2628
|
};
|
|
2514
|
-
fnCallBuilders.delete(builderKey);
|
|
2515
|
-
for (const [idx, key] of outputIndexToBuilderKey.entries()) {
|
|
2516
|
-
if (key === builderKey) outputIndexToBuilderKey.delete(idx);
|
|
2517
|
-
}
|
|
2518
2629
|
}
|
|
2519
2630
|
}
|
|
2520
2631
|
break;
|
|
2521
2632
|
case "response.completed":
|
|
2522
2633
|
{
|
|
2523
|
-
for (const
|
|
2634
|
+
for (const toolCall of toolCallAssembler.finalizeAll(this.name)) {
|
|
2524
2635
|
yield {
|
|
2525
2636
|
type: "tool_use_end",
|
|
2526
2637
|
toolCall: {
|
|
2527
|
-
id:
|
|
2528
|
-
name:
|
|
2529
|
-
input:
|
|
2638
|
+
id: toolCall.id,
|
|
2639
|
+
name: toolCall.name,
|
|
2640
|
+
input: toolCall.input
|
|
2530
2641
|
}
|
|
2531
2642
|
};
|
|
2532
2643
|
}
|
|
2533
|
-
fnCallBuilders.clear();
|
|
2534
2644
|
const hasToolCalls = event.response.output.some(
|
|
2535
2645
|
(i) => i.type === "function_call"
|
|
2536
2646
|
);
|
|
@@ -2650,24 +2760,6 @@ var init_openai = __esm({
|
|
|
2650
2760
|
strict: false
|
|
2651
2761
|
}));
|
|
2652
2762
|
}
|
|
2653
|
-
/**
|
|
2654
|
-
* Parse tool call arguments with jsonrepair fallback (Responses API)
|
|
2655
|
-
*/
|
|
2656
|
-
parseResponsesArguments(args) {
|
|
2657
|
-
try {
|
|
2658
|
-
return args ? JSON.parse(args) : {};
|
|
2659
|
-
} catch {
|
|
2660
|
-
try {
|
|
2661
|
-
if (args) {
|
|
2662
|
-
const repaired = jsonrepair(args);
|
|
2663
|
-
return JSON.parse(repaired);
|
|
2664
|
-
}
|
|
2665
|
-
} catch {
|
|
2666
|
-
console.error(`[${this.name}] Cannot parse tool arguments: ${args.slice(0, 200)}`);
|
|
2667
|
-
}
|
|
2668
|
-
return {};
|
|
2669
|
-
}
|
|
2670
|
-
}
|
|
2671
2763
|
};
|
|
2672
2764
|
}
|
|
2673
2765
|
});
|
|
@@ -4296,6 +4388,8 @@ var init_auth = __esm({
|
|
|
4296
4388
|
init_gcloud();
|
|
4297
4389
|
}
|
|
4298
4390
|
});
|
|
4391
|
+
|
|
4392
|
+
// src/providers/codex.ts
|
|
4299
4393
|
function parseJwtClaims(token) {
|
|
4300
4394
|
const parts = token.split(".");
|
|
4301
4395
|
if (parts.length !== 3 || !parts[1]) return void 0;
|
|
@@ -4311,21 +4405,6 @@ function extractAccountId(accessToken) {
|
|
|
4311
4405
|
const auth = claims["https://api.openai.com/auth"];
|
|
4312
4406
|
return claims["chatgpt_account_id"] || auth?.["chatgpt_account_id"] || claims["organizations"]?.[0]?.id;
|
|
4313
4407
|
}
|
|
4314
|
-
function parseArguments(args) {
|
|
4315
|
-
try {
|
|
4316
|
-
return args ? JSON.parse(args) : {};
|
|
4317
|
-
} catch {
|
|
4318
|
-
try {
|
|
4319
|
-
if (args) {
|
|
4320
|
-
const repaired = jsonrepair(args);
|
|
4321
|
-
return JSON.parse(repaired);
|
|
4322
|
-
}
|
|
4323
|
-
} catch {
|
|
4324
|
-
console.error(`[Codex] Cannot parse tool arguments: ${args.slice(0, 200)}`);
|
|
4325
|
-
}
|
|
4326
|
-
return {};
|
|
4327
|
-
}
|
|
4328
|
-
}
|
|
4329
4408
|
function createCodexProvider(config) {
|
|
4330
4409
|
const provider = new CodexProvider();
|
|
4331
4410
|
if (config) {
|
|
@@ -4340,6 +4419,7 @@ var init_codex = __esm({
|
|
|
4340
4419
|
init_errors();
|
|
4341
4420
|
init_auth();
|
|
4342
4421
|
init_retry();
|
|
4422
|
+
init_tool_call_normalizer();
|
|
4343
4423
|
CODEX_API_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
|
|
4344
4424
|
DEFAULT_MODEL3 = "gpt-5.4-codex";
|
|
4345
4425
|
CONTEXT_WINDOWS3 = {
|
|
@@ -4652,8 +4732,7 @@ var init_codex = __esm({
|
|
|
4652
4732
|
let inputTokens = 0;
|
|
4653
4733
|
let outputTokens = 0;
|
|
4654
4734
|
const toolCalls = [];
|
|
4655
|
-
const
|
|
4656
|
-
const outputIndexToBuilderKey = /* @__PURE__ */ new Map();
|
|
4735
|
+
const toolCallAssembler = new ResponsesToolCallAssembler();
|
|
4657
4736
|
await this.readSSEStream(response, (event) => {
|
|
4658
4737
|
if (event.id) responseId = event.id;
|
|
4659
4738
|
switch (event.type) {
|
|
@@ -4664,41 +4743,35 @@ var init_codex = __esm({
|
|
|
4664
4743
|
content = event.text ?? content;
|
|
4665
4744
|
break;
|
|
4666
4745
|
case "response.output_item.added": {
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
callId: item.call_id,
|
|
4672
|
-
name: item.name,
|
|
4673
|
-
arguments: item.arguments ?? ""
|
|
4674
|
-
});
|
|
4675
|
-
if (typeof event.output_index === "number") {
|
|
4676
|
-
outputIndexToBuilderKey.set(event.output_index, itemKey);
|
|
4677
|
-
}
|
|
4678
|
-
}
|
|
4746
|
+
toolCallAssembler.onOutputItemAdded({
|
|
4747
|
+
output_index: event.output_index,
|
|
4748
|
+
item: event.item
|
|
4749
|
+
});
|
|
4679
4750
|
break;
|
|
4680
4751
|
}
|
|
4681
4752
|
case "response.function_call_arguments.delta": {
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4753
|
+
toolCallAssembler.onArgumentsDelta({
|
|
4754
|
+
item_id: event.item_id,
|
|
4755
|
+
output_index: event.output_index,
|
|
4756
|
+
delta: event.delta
|
|
4757
|
+
});
|
|
4686
4758
|
break;
|
|
4687
4759
|
}
|
|
4688
4760
|
case "response.function_call_arguments.done": {
|
|
4689
|
-
const
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4761
|
+
const toolCall = toolCallAssembler.onArgumentsDone(
|
|
4762
|
+
{
|
|
4763
|
+
item_id: event.item_id,
|
|
4764
|
+
output_index: event.output_index,
|
|
4765
|
+
arguments: event.arguments
|
|
4766
|
+
},
|
|
4767
|
+
this.name
|
|
4768
|
+
);
|
|
4769
|
+
if (toolCall) {
|
|
4693
4770
|
toolCalls.push({
|
|
4694
|
-
id:
|
|
4695
|
-
name:
|
|
4696
|
-
input:
|
|
4771
|
+
id: toolCall.id,
|
|
4772
|
+
name: toolCall.name,
|
|
4773
|
+
input: toolCall.input
|
|
4697
4774
|
});
|
|
4698
|
-
fnCallBuilders.delete(builderKey);
|
|
4699
|
-
for (const [idx, key] of outputIndexToBuilderKey.entries()) {
|
|
4700
|
-
if (key === builderKey) outputIndexToBuilderKey.delete(idx);
|
|
4701
|
-
}
|
|
4702
4775
|
}
|
|
4703
4776
|
break;
|
|
4704
4777
|
}
|
|
@@ -4709,14 +4782,13 @@ var init_codex = __esm({
|
|
|
4709
4782
|
inputTokens = usage.input_tokens ?? 0;
|
|
4710
4783
|
outputTokens = usage.output_tokens ?? 0;
|
|
4711
4784
|
}
|
|
4712
|
-
for (const
|
|
4785
|
+
for (const toolCall of toolCallAssembler.finalizeAll(this.name)) {
|
|
4713
4786
|
toolCalls.push({
|
|
4714
|
-
id:
|
|
4715
|
-
name:
|
|
4716
|
-
input:
|
|
4787
|
+
id: toolCall.id,
|
|
4788
|
+
name: toolCall.name,
|
|
4789
|
+
input: toolCall.input
|
|
4717
4790
|
});
|
|
4718
4791
|
}
|
|
4719
|
-
fnCallBuilders.clear();
|
|
4720
4792
|
break;
|
|
4721
4793
|
}
|
|
4722
4794
|
}
|
|
@@ -4810,8 +4882,7 @@ var init_codex = __esm({
|
|
|
4810
4882
|
const reader = response.body.getReader();
|
|
4811
4883
|
const decoder = new TextDecoder();
|
|
4812
4884
|
let buffer = "";
|
|
4813
|
-
const
|
|
4814
|
-
const outputIndexToBuilderKey = /* @__PURE__ */ new Map();
|
|
4885
|
+
const toolCallAssembler = new ResponsesToolCallAssembler();
|
|
4815
4886
|
let lastActivityTime = Date.now();
|
|
4816
4887
|
const timeoutController = new AbortController();
|
|
4817
4888
|
const timeoutInterval = setInterval(() => {
|
|
@@ -4844,65 +4915,58 @@ var init_codex = __esm({
|
|
|
4844
4915
|
yield { type: "text", text: event.delta ?? "" };
|
|
4845
4916
|
break;
|
|
4846
4917
|
case "response.output_item.added": {
|
|
4847
|
-
const
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
name: item.name,
|
|
4853
|
-
arguments: item.arguments ?? ""
|
|
4854
|
-
});
|
|
4855
|
-
if (typeof event.output_index === "number") {
|
|
4856
|
-
outputIndexToBuilderKey.set(event.output_index, itemKey);
|
|
4857
|
-
}
|
|
4918
|
+
const start = toolCallAssembler.onOutputItemAdded({
|
|
4919
|
+
output_index: event.output_index,
|
|
4920
|
+
item: event.item
|
|
4921
|
+
});
|
|
4922
|
+
if (start) {
|
|
4858
4923
|
yield {
|
|
4859
4924
|
type: "tool_use_start",
|
|
4860
|
-
toolCall: { id:
|
|
4925
|
+
toolCall: { id: start.id, name: start.name }
|
|
4861
4926
|
};
|
|
4862
4927
|
}
|
|
4863
4928
|
break;
|
|
4864
4929
|
}
|
|
4865
4930
|
case "response.function_call_arguments.delta": {
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
}
|
|
4931
|
+
toolCallAssembler.onArgumentsDelta({
|
|
4932
|
+
item_id: event.item_id,
|
|
4933
|
+
output_index: event.output_index,
|
|
4934
|
+
delta: event.delta
|
|
4935
|
+
});
|
|
4872
4936
|
break;
|
|
4873
4937
|
}
|
|
4874
4938
|
case "response.function_call_arguments.done": {
|
|
4875
|
-
const
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4939
|
+
const toolCall = toolCallAssembler.onArgumentsDone(
|
|
4940
|
+
{
|
|
4941
|
+
item_id: event.item_id,
|
|
4942
|
+
output_index: event.output_index,
|
|
4943
|
+
arguments: event.arguments
|
|
4944
|
+
},
|
|
4945
|
+
this.name
|
|
4946
|
+
);
|
|
4947
|
+
if (toolCall) {
|
|
4879
4948
|
yield {
|
|
4880
4949
|
type: "tool_use_end",
|
|
4881
4950
|
toolCall: {
|
|
4882
|
-
id:
|
|
4883
|
-
name:
|
|
4884
|
-
input:
|
|
4951
|
+
id: toolCall.id,
|
|
4952
|
+
name: toolCall.name,
|
|
4953
|
+
input: toolCall.input
|
|
4885
4954
|
}
|
|
4886
4955
|
};
|
|
4887
|
-
fnCallBuilders.delete(builderKey);
|
|
4888
|
-
for (const [idx, key] of outputIndexToBuilderKey.entries()) {
|
|
4889
|
-
if (key === builderKey) outputIndexToBuilderKey.delete(idx);
|
|
4890
|
-
}
|
|
4891
4956
|
}
|
|
4892
4957
|
break;
|
|
4893
4958
|
}
|
|
4894
4959
|
case "response.completed": {
|
|
4895
|
-
for (const
|
|
4960
|
+
for (const toolCall of toolCallAssembler.finalizeAll(this.name)) {
|
|
4896
4961
|
yield {
|
|
4897
4962
|
type: "tool_use_end",
|
|
4898
4963
|
toolCall: {
|
|
4899
|
-
id:
|
|
4900
|
-
name:
|
|
4901
|
-
input:
|
|
4964
|
+
id: toolCall.id,
|
|
4965
|
+
name: toolCall.name,
|
|
4966
|
+
input: toolCall.input
|
|
4902
4967
|
}
|
|
4903
4968
|
};
|
|
4904
4969
|
}
|
|
4905
|
-
fnCallBuilders.clear();
|
|
4906
4970
|
const resp = event.response;
|
|
4907
4971
|
const output = resp?.output ?? [];
|
|
4908
4972
|
const hasToolCalls = output.some((i) => i.type === "function_call");
|
|
@@ -6123,6 +6187,154 @@ var init_fallback = __esm({
|
|
|
6123
6187
|
}
|
|
6124
6188
|
});
|
|
6125
6189
|
|
|
6190
|
+
// src/providers/resilient.ts
|
|
6191
|
+
function sleep2(ms) {
|
|
6192
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
6193
|
+
}
|
|
6194
|
+
function computeRetryDelay(attempt, config) {
|
|
6195
|
+
const exp = config.initialDelayMs * Math.pow(config.backoffMultiplier, attempt);
|
|
6196
|
+
const capped = Math.min(exp, config.maxDelayMs);
|
|
6197
|
+
const jitter = capped * config.jitterFactor * (Math.random() * 2 - 1);
|
|
6198
|
+
return Math.max(0, Math.min(capped + jitter, config.maxDelayMs));
|
|
6199
|
+
}
|
|
6200
|
+
function getDefaultResilienceConfig(providerId) {
|
|
6201
|
+
if (providerId === "ollama" || providerId === "lmstudio") {
|
|
6202
|
+
return {
|
|
6203
|
+
retry: {
|
|
6204
|
+
maxRetries: 1,
|
|
6205
|
+
initialDelayMs: 300,
|
|
6206
|
+
maxDelayMs: 1500
|
|
6207
|
+
},
|
|
6208
|
+
streamRetry: {
|
|
6209
|
+
maxRetries: 0
|
|
6210
|
+
},
|
|
6211
|
+
circuitBreaker: {
|
|
6212
|
+
failureThreshold: 3,
|
|
6213
|
+
resetTimeout: 1e4
|
|
6214
|
+
}
|
|
6215
|
+
};
|
|
6216
|
+
}
|
|
6217
|
+
return {
|
|
6218
|
+
retry: {
|
|
6219
|
+
maxRetries: 3,
|
|
6220
|
+
initialDelayMs: 1e3,
|
|
6221
|
+
maxDelayMs: 3e4
|
|
6222
|
+
},
|
|
6223
|
+
streamRetry: {
|
|
6224
|
+
maxRetries: 1,
|
|
6225
|
+
initialDelayMs: 500,
|
|
6226
|
+
maxDelayMs: 5e3
|
|
6227
|
+
},
|
|
6228
|
+
circuitBreaker: {
|
|
6229
|
+
failureThreshold: 5,
|
|
6230
|
+
resetTimeout: 3e4
|
|
6231
|
+
}
|
|
6232
|
+
};
|
|
6233
|
+
}
|
|
6234
|
+
function createResilientProvider(provider, config) {
|
|
6235
|
+
return new ResilientProvider(provider, config ?? getDefaultResilienceConfig(provider.id));
|
|
6236
|
+
}
|
|
6237
|
+
var DEFAULT_STREAM_RETRY, ResilientProvider;
|
|
6238
|
+
var init_resilient = __esm({
|
|
6239
|
+
"src/providers/resilient.ts"() {
|
|
6240
|
+
init_retry();
|
|
6241
|
+
init_circuit_breaker();
|
|
6242
|
+
DEFAULT_STREAM_RETRY = {
|
|
6243
|
+
maxRetries: 1,
|
|
6244
|
+
initialDelayMs: 500,
|
|
6245
|
+
maxDelayMs: 5e3,
|
|
6246
|
+
backoffMultiplier: 2,
|
|
6247
|
+
jitterFactor: 0.1
|
|
6248
|
+
};
|
|
6249
|
+
ResilientProvider = class {
|
|
6250
|
+
id;
|
|
6251
|
+
name;
|
|
6252
|
+
provider;
|
|
6253
|
+
breaker;
|
|
6254
|
+
retryConfig;
|
|
6255
|
+
streamRetryConfig;
|
|
6256
|
+
constructor(provider, config = {}) {
|
|
6257
|
+
this.provider = provider;
|
|
6258
|
+
this.id = provider.id;
|
|
6259
|
+
this.name = provider.name;
|
|
6260
|
+
this.retryConfig = { ...DEFAULT_RETRY_CONFIG, ...config.retry };
|
|
6261
|
+
this.streamRetryConfig = { ...DEFAULT_STREAM_RETRY, ...config.streamRetry };
|
|
6262
|
+
this.breaker = new CircuitBreaker(
|
|
6263
|
+
{ ...DEFAULT_CIRCUIT_BREAKER_CONFIG, ...config.circuitBreaker },
|
|
6264
|
+
provider.id
|
|
6265
|
+
);
|
|
6266
|
+
}
|
|
6267
|
+
async initialize(config) {
|
|
6268
|
+
await this.provider.initialize(config);
|
|
6269
|
+
}
|
|
6270
|
+
async chat(messages, options) {
|
|
6271
|
+
return this.breaker.execute(
|
|
6272
|
+
() => withRetry(() => this.provider.chat(messages, options), this.retryConfig)
|
|
6273
|
+
);
|
|
6274
|
+
}
|
|
6275
|
+
async chatWithTools(messages, options) {
|
|
6276
|
+
return this.breaker.execute(
|
|
6277
|
+
() => withRetry(() => this.provider.chatWithTools(messages, options), this.retryConfig)
|
|
6278
|
+
);
|
|
6279
|
+
}
|
|
6280
|
+
async *stream(messages, options) {
|
|
6281
|
+
yield* this.streamWithPolicy(() => this.provider.stream(messages, options));
|
|
6282
|
+
}
|
|
6283
|
+
async *streamWithTools(messages, options) {
|
|
6284
|
+
yield* this.streamWithPolicy(() => this.provider.streamWithTools(messages, options));
|
|
6285
|
+
}
|
|
6286
|
+
countTokens(text13) {
|
|
6287
|
+
return this.provider.countTokens(text13);
|
|
6288
|
+
}
|
|
6289
|
+
getContextWindow() {
|
|
6290
|
+
return this.provider.getContextWindow();
|
|
6291
|
+
}
|
|
6292
|
+
async isAvailable() {
|
|
6293
|
+
try {
|
|
6294
|
+
return await this.breaker.execute(() => this.provider.isAvailable());
|
|
6295
|
+
} catch (error) {
|
|
6296
|
+
if (error instanceof CircuitOpenError) {
|
|
6297
|
+
return false;
|
|
6298
|
+
}
|
|
6299
|
+
return false;
|
|
6300
|
+
}
|
|
6301
|
+
}
|
|
6302
|
+
getCircuitState() {
|
|
6303
|
+
return this.breaker.getState();
|
|
6304
|
+
}
|
|
6305
|
+
resetCircuit() {
|
|
6306
|
+
this.breaker.reset();
|
|
6307
|
+
}
|
|
6308
|
+
async *streamWithPolicy(createStream) {
|
|
6309
|
+
let attempt = 0;
|
|
6310
|
+
while (attempt <= this.streamRetryConfig.maxRetries) {
|
|
6311
|
+
if (this.breaker.isOpen()) {
|
|
6312
|
+
throw new CircuitOpenError(this.id, 0);
|
|
6313
|
+
}
|
|
6314
|
+
let emittedChunk = false;
|
|
6315
|
+
try {
|
|
6316
|
+
for await (const chunk of createStream()) {
|
|
6317
|
+
emittedChunk = true;
|
|
6318
|
+
yield chunk;
|
|
6319
|
+
}
|
|
6320
|
+
this.breaker.recordSuccess();
|
|
6321
|
+
return;
|
|
6322
|
+
} catch (error) {
|
|
6323
|
+
this.breaker.recordFailure();
|
|
6324
|
+
const shouldRetry = !emittedChunk && attempt < this.streamRetryConfig.maxRetries && isRetryableError(error);
|
|
6325
|
+
if (!shouldRetry) {
|
|
6326
|
+
throw error;
|
|
6327
|
+
}
|
|
6328
|
+
const delay = computeRetryDelay(attempt, this.streamRetryConfig);
|
|
6329
|
+
await sleep2(delay);
|
|
6330
|
+
attempt++;
|
|
6331
|
+
}
|
|
6332
|
+
}
|
|
6333
|
+
}
|
|
6334
|
+
};
|
|
6335
|
+
}
|
|
6336
|
+
});
|
|
6337
|
+
|
|
6126
6338
|
// src/config/env.ts
|
|
6127
6339
|
var env_exports = {};
|
|
6128
6340
|
__export(env_exports, {
|
|
@@ -6526,6 +6738,7 @@ __export(providers_exports, {
|
|
|
6526
6738
|
MODEL_PRICING: () => MODEL_PRICING,
|
|
6527
6739
|
OpenAIProvider: () => OpenAIProvider,
|
|
6528
6740
|
ProviderFallback: () => ProviderFallback,
|
|
6741
|
+
ResilientProvider: () => ResilientProvider,
|
|
6529
6742
|
createAnthropicProvider: () => createAnthropicProvider,
|
|
6530
6743
|
createCircuitBreaker: () => createCircuitBreaker,
|
|
6531
6744
|
createCodexProvider: () => createCodexProvider,
|
|
@@ -6536,10 +6749,12 @@ __export(providers_exports, {
|
|
|
6536
6749
|
createOpenAIProvider: () => createOpenAIProvider,
|
|
6537
6750
|
createProvider: () => createProvider,
|
|
6538
6751
|
createProviderFallback: () => createProviderFallback,
|
|
6752
|
+
createResilientProvider: () => createResilientProvider,
|
|
6539
6753
|
createRetryableMethod: () => createRetryableMethod,
|
|
6540
6754
|
estimateCost: () => estimateCost,
|
|
6541
6755
|
formatCost: () => formatCost,
|
|
6542
6756
|
getDefaultProvider: () => getDefaultProvider2,
|
|
6757
|
+
getDefaultResilienceConfig: () => getDefaultResilienceConfig,
|
|
6543
6758
|
getModelPricing: () => getModelPricing,
|
|
6544
6759
|
hasKnownPricing: () => hasKnownPricing,
|
|
6545
6760
|
isRetryableError: () => isRetryableError,
|
|
@@ -6575,12 +6790,10 @@ async function createProvider(type, config = {}) {
|
|
|
6575
6790
|
break;
|
|
6576
6791
|
case "kimi":
|
|
6577
6792
|
provider = createKimiProvider(mergedConfig);
|
|
6578
|
-
|
|
6579
|
-
return provider;
|
|
6793
|
+
break;
|
|
6580
6794
|
case "kimi-code":
|
|
6581
6795
|
provider = createKimiCodeProvider(mergedConfig);
|
|
6582
|
-
|
|
6583
|
-
return provider;
|
|
6796
|
+
break;
|
|
6584
6797
|
case "lmstudio":
|
|
6585
6798
|
provider = new OpenAIProvider("lmstudio", "LM Studio");
|
|
6586
6799
|
mergedConfig.baseUrl = mergedConfig.baseUrl ?? "http://localhost:1234/v1";
|
|
@@ -6625,7 +6838,10 @@ async function createProvider(type, config = {}) {
|
|
|
6625
6838
|
});
|
|
6626
6839
|
}
|
|
6627
6840
|
await provider.initialize(mergedConfig);
|
|
6628
|
-
|
|
6841
|
+
const resilienceEnabled = !["0", "false", "off"].includes(
|
|
6842
|
+
(process.env["COCO_PROVIDER_RESILIENCE"] ?? "1").toLowerCase()
|
|
6843
|
+
);
|
|
6844
|
+
return resilienceEnabled ? createResilientProvider(provider) : provider;
|
|
6629
6845
|
}
|
|
6630
6846
|
async function getDefaultProvider2(config = {}) {
|
|
6631
6847
|
const { getDefaultProvider: getEnvProvider } = await Promise.resolve().then(() => (init_env(), env_exports));
|
|
@@ -6679,6 +6895,7 @@ var init_providers = __esm({
|
|
|
6679
6895
|
init_pricing();
|
|
6680
6896
|
init_circuit_breaker();
|
|
6681
6897
|
init_fallback();
|
|
6898
|
+
init_resilient();
|
|
6682
6899
|
init_copilot();
|
|
6683
6900
|
init_anthropic();
|
|
6684
6901
|
init_openai();
|
|
@@ -6687,6 +6904,7 @@ var init_providers = __esm({
|
|
|
6687
6904
|
init_copilot2();
|
|
6688
6905
|
init_errors();
|
|
6689
6906
|
init_env();
|
|
6907
|
+
init_resilient();
|
|
6690
6908
|
}
|
|
6691
6909
|
});
|
|
6692
6910
|
|
|
@@ -9449,7 +9667,7 @@ async function checkAndCompactContext(session, provider, signal, toolRegistry) {
|
|
|
9449
9667
|
session.contextManager.setUsedTokens(result.compactedTokens);
|
|
9450
9668
|
}
|
|
9451
9669
|
return result;
|
|
9452
|
-
} catch
|
|
9670
|
+
} catch {
|
|
9453
9671
|
return null;
|
|
9454
9672
|
}
|
|
9455
9673
|
}
|
|
@@ -10553,6 +10771,34 @@ function isAbortError(error, signal) {
|
|
|
10553
10771
|
if (error.message.endsWith("Request was aborted.")) return true;
|
|
10554
10772
|
return false;
|
|
10555
10773
|
}
|
|
10774
|
+
function classifyAgentLoopError(error, signal) {
|
|
10775
|
+
if (isAbortError(error, signal)) {
|
|
10776
|
+
return {
|
|
10777
|
+
kind: "abort",
|
|
10778
|
+
message: "Request was aborted.",
|
|
10779
|
+
original: error
|
|
10780
|
+
};
|
|
10781
|
+
}
|
|
10782
|
+
if (isNonRetryableProviderError(error)) {
|
|
10783
|
+
return {
|
|
10784
|
+
kind: "provider_non_retryable",
|
|
10785
|
+
message: error instanceof Error ? error.message : String(error),
|
|
10786
|
+
original: error
|
|
10787
|
+
};
|
|
10788
|
+
}
|
|
10789
|
+
if (error instanceof ProviderError) {
|
|
10790
|
+
return {
|
|
10791
|
+
kind: "provider_retryable",
|
|
10792
|
+
message: error.message,
|
|
10793
|
+
original: error
|
|
10794
|
+
};
|
|
10795
|
+
}
|
|
10796
|
+
return {
|
|
10797
|
+
kind: "unexpected",
|
|
10798
|
+
message: error instanceof Error ? error.message : String(error),
|
|
10799
|
+
original: error
|
|
10800
|
+
};
|
|
10801
|
+
}
|
|
10556
10802
|
function isNonRetryableProviderError(error) {
|
|
10557
10803
|
if (error instanceof ProviderError) {
|
|
10558
10804
|
const code = error.statusCode;
|
|
@@ -19103,7 +19349,7 @@ async function runCIChecks(ctx) {
|
|
|
19103
19349
|
cwd: ctx.cwd
|
|
19104
19350
|
});
|
|
19105
19351
|
if (result.checks.length === 0) {
|
|
19106
|
-
await
|
|
19352
|
+
await sleep3(pollMs);
|
|
19107
19353
|
continue;
|
|
19108
19354
|
}
|
|
19109
19355
|
if (result.allPassed) {
|
|
@@ -19153,7 +19399,7 @@ async function runCIChecks(ctx) {
|
|
|
19153
19399
|
spinner18.message(`CI: ${passed}/${result.checks.length} passed, ${pending} pending...`);
|
|
19154
19400
|
} catch {
|
|
19155
19401
|
}
|
|
19156
|
-
await
|
|
19402
|
+
await sleep3(pollMs);
|
|
19157
19403
|
}
|
|
19158
19404
|
spinner18.stop("CI check timeout");
|
|
19159
19405
|
const action = await p26.select({
|
|
@@ -19178,7 +19424,7 @@ async function runCIChecks(ctx) {
|
|
|
19178
19424
|
durationMs: performance.now() - start
|
|
19179
19425
|
};
|
|
19180
19426
|
}
|
|
19181
|
-
function
|
|
19427
|
+
function sleep3(ms) {
|
|
19182
19428
|
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
19183
19429
|
}
|
|
19184
19430
|
var init_ci_checks = __esm({
|
|
@@ -50116,6 +50362,60 @@ function extractDeniedPath(error) {
|
|
|
50116
50362
|
// src/cli/repl/agent-loop.ts
|
|
50117
50363
|
init_allow_path_prompt();
|
|
50118
50364
|
init_error_resilience();
|
|
50365
|
+
|
|
50366
|
+
// src/cli/repl/turn-quality.ts
|
|
50367
|
+
function clamp(value, min, max) {
|
|
50368
|
+
return Math.max(min, Math.min(max, value));
|
|
50369
|
+
}
|
|
50370
|
+
function computeTurnQualityMetrics(input) {
|
|
50371
|
+
const executedToolCalls = input.executedTools.length;
|
|
50372
|
+
const successfulToolCalls = input.executedTools.filter((t) => t.result.success).length;
|
|
50373
|
+
const failedToolCalls = executedToolCalls - successfulToolCalls;
|
|
50374
|
+
let score = 100;
|
|
50375
|
+
if (input.hadError) score -= 25;
|
|
50376
|
+
if (executedToolCalls > 0) {
|
|
50377
|
+
const failureRatio = failedToolCalls / executedToolCalls;
|
|
50378
|
+
score -= Math.round(failureRatio * 35);
|
|
50379
|
+
}
|
|
50380
|
+
if (input.maxIterations > 0) {
|
|
50381
|
+
const iterationRatio = input.iterationsUsed / input.maxIterations;
|
|
50382
|
+
if (iterationRatio > 0.8) score -= 10;
|
|
50383
|
+
if (iterationRatio >= 1) score -= 10;
|
|
50384
|
+
}
|
|
50385
|
+
score += Math.min(input.repeatedOutputsSuppressed * 2, 8);
|
|
50386
|
+
return {
|
|
50387
|
+
score: clamp(score, 0, 100),
|
|
50388
|
+
iterationsUsed: input.iterationsUsed,
|
|
50389
|
+
maxIterations: input.maxIterations,
|
|
50390
|
+
executedToolCalls,
|
|
50391
|
+
successfulToolCalls,
|
|
50392
|
+
failedToolCalls,
|
|
50393
|
+
hadError: input.hadError,
|
|
50394
|
+
repeatedOutputsSuppressed: input.repeatedOutputsSuppressed
|
|
50395
|
+
};
|
|
50396
|
+
}
|
|
50397
|
+
var RepeatedOutputSuppressor = class {
|
|
50398
|
+
seen = /* @__PURE__ */ new Map();
|
|
50399
|
+
transform(toolName, content) {
|
|
50400
|
+
const fingerprint = this.fingerprint(toolName, content);
|
|
50401
|
+
const count = this.seen.get(fingerprint) ?? 0;
|
|
50402
|
+
this.seen.set(fingerprint, count + 1);
|
|
50403
|
+
if (count === 0) {
|
|
50404
|
+
return { content, suppressed: false };
|
|
50405
|
+
}
|
|
50406
|
+
return {
|
|
50407
|
+
content: `[Repeated tool output suppressed: '${toolName}' produced the same output as before (occurrence ${count + 1}). If needed, re-run with different inputs.]`,
|
|
50408
|
+
suppressed: true
|
|
50409
|
+
};
|
|
50410
|
+
}
|
|
50411
|
+
fingerprint(toolName, content) {
|
|
50412
|
+
const head = content.slice(0, 200);
|
|
50413
|
+
const tail = content.slice(-200);
|
|
50414
|
+
return `${toolName}|${content.length}|${head}|${tail}`;
|
|
50415
|
+
}
|
|
50416
|
+
};
|
|
50417
|
+
|
|
50418
|
+
// src/cli/repl/agent-loop.ts
|
|
50119
50419
|
async function executeAgentTurn(session, userMessage, provider, toolRegistry, options = {}) {
|
|
50120
50420
|
resetLineBuffer();
|
|
50121
50421
|
const messageSnapshot = session.messages.length;
|
|
@@ -50124,12 +50424,23 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
50124
50424
|
let totalInputTokens = 0;
|
|
50125
50425
|
let totalOutputTokens = 0;
|
|
50126
50426
|
let finalContent = "";
|
|
50427
|
+
let hadTurnError = false;
|
|
50428
|
+
let repeatedOutputsSuppressed = 0;
|
|
50429
|
+
const repeatedOutputSuppressor = new RepeatedOutputSuppressor();
|
|
50430
|
+
const buildQualityMetrics = () => computeTurnQualityMetrics({
|
|
50431
|
+
iterationsUsed: iteration,
|
|
50432
|
+
maxIterations,
|
|
50433
|
+
executedTools,
|
|
50434
|
+
hadError: hadTurnError,
|
|
50435
|
+
repeatedOutputsSuppressed
|
|
50436
|
+
});
|
|
50127
50437
|
const abortReturn = () => {
|
|
50128
50438
|
session.messages.length = messageSnapshot;
|
|
50129
50439
|
return {
|
|
50130
50440
|
content: finalContent,
|
|
50131
50441
|
toolCalls: executedTools,
|
|
50132
50442
|
usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens },
|
|
50443
|
+
quality: buildQualityMetrics(),
|
|
50133
50444
|
aborted: true,
|
|
50134
50445
|
partialContent: finalContent || void 0,
|
|
50135
50446
|
abortReason: "user_cancel"
|
|
@@ -50243,13 +50554,15 @@ ${tail}`;
|
|
|
50243
50554
|
options.onThinkingEnd?.();
|
|
50244
50555
|
thinkingEnded = true;
|
|
50245
50556
|
}
|
|
50246
|
-
|
|
50557
|
+
const classification = classifyAgentLoopError(streamError, options.signal);
|
|
50558
|
+
if (classification.kind === "abort") {
|
|
50247
50559
|
return abortReturn();
|
|
50248
50560
|
}
|
|
50249
|
-
if (
|
|
50250
|
-
throw
|
|
50561
|
+
if (classification.kind === "provider_non_retryable") {
|
|
50562
|
+
throw classification.original;
|
|
50251
50563
|
}
|
|
50252
|
-
|
|
50564
|
+
hadTurnError = true;
|
|
50565
|
+
const errorMsg = classification.message;
|
|
50253
50566
|
addMessage(session, {
|
|
50254
50567
|
role: "assistant",
|
|
50255
50568
|
content: `[Error during streaming: ${errorMsg}]`
|
|
@@ -50258,6 +50571,7 @@ ${tail}`;
|
|
|
50258
50571
|
content: finalContent || `[Error: ${errorMsg}]`,
|
|
50259
50572
|
toolCalls: executedTools,
|
|
50260
50573
|
usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens },
|
|
50574
|
+
quality: buildQualityMetrics(),
|
|
50261
50575
|
aborted: false,
|
|
50262
50576
|
partialContent: finalContent || void 0,
|
|
50263
50577
|
error: errorMsg
|
|
@@ -50463,10 +50777,15 @@ ${tail}`;
|
|
|
50463
50777
|
}
|
|
50464
50778
|
const executedCall = executedTools.find((e) => e.id === toolCall.id);
|
|
50465
50779
|
if (executedCall) {
|
|
50780
|
+
const truncatedOutput = truncateInlineResult(executedCall.result.output, toolCall.name);
|
|
50781
|
+
const transformedOutput = repeatedOutputSuppressor.transform(toolCall.name, truncatedOutput);
|
|
50782
|
+
if (transformedOutput.suppressed) {
|
|
50783
|
+
repeatedOutputsSuppressed++;
|
|
50784
|
+
}
|
|
50466
50785
|
toolResults.push({
|
|
50467
50786
|
type: "tool_result",
|
|
50468
50787
|
tool_use_id: toolCall.id,
|
|
50469
|
-
content:
|
|
50788
|
+
content: transformedOutput.content,
|
|
50470
50789
|
is_error: !executedCall.result.success
|
|
50471
50790
|
});
|
|
50472
50791
|
} else {
|
|
@@ -50614,6 +50933,7 @@ I have reached the maximum iteration limit (${maxIterations}). The task may be i
|
|
|
50614
50933
|
content: finalContent,
|
|
50615
50934
|
toolCalls: executedTools,
|
|
50616
50935
|
usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens },
|
|
50936
|
+
quality: buildQualityMetrics(),
|
|
50617
50937
|
aborted: false
|
|
50618
50938
|
};
|
|
50619
50939
|
}
|