@anthonyhaussman/opencode-agy-auth 1.0.11-alpha.4 → 1.0.11-beta.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/index.js CHANGED
@@ -1285,1142 +1285,6 @@ function getLatestSignature(sessionId) {
1285
1285
  return void 0;
1286
1286
  }
1287
1287
 
1288
- // src/sdk/request/turn-state-tracker.ts
1289
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, renameSync as renameSync2, unlinkSync as unlinkSync2 } from "fs";
1290
- import { join as join2, dirname as dirname2 } from "path";
1291
- import { homedir as homedir2, tmpdir as tmpdir2 } from "os";
1292
-
1293
- // src/sdk/request/thinking.ts
1294
- import { createHash as createHash2 } from "crypto";
1295
- function createSignatureStore() {
1296
- const store = /* @__PURE__ */ new Map();
1297
- return {
1298
- get: (key) => store.get(key),
1299
- set: (key, value) => {
1300
- store.set(key, value);
1301
- },
1302
- has: (key) => store.has(key),
1303
- delete: (key) => {
1304
- store.delete(key);
1305
- }
1306
- };
1307
- }
1308
- function createThoughtBuffer() {
1309
- const buffer = /* @__PURE__ */ new Map();
1310
- return {
1311
- get: (index) => buffer.get(index),
1312
- set: (index, text) => {
1313
- buffer.set(index, text);
1314
- },
1315
- clear: () => buffer.clear()
1316
- };
1317
- }
1318
- var defaultSignatureStore = createSignatureStore();
1319
- var THINKING_HASH_HEX_LEN = 16;
1320
- function hashString(str) {
1321
- return createHash2("sha256").update(str, "utf8").digest("hex").slice(0, THINKING_HASH_HEX_LEN);
1322
- }
1323
- function isThinkingPart(part) {
1324
- if (!part || typeof part !== "object") return false;
1325
- return part.thought === true || part.type === "thinking" || part.type === "redacted_thinking";
1326
- }
1327
- function isFunctionResponsePart(part) {
1328
- return part && typeof part === "object" && "functionResponse" in part;
1329
- }
1330
- function isFunctionCallPart(part) {
1331
- return part && typeof part === "object" && "functionCall" in part;
1332
- }
1333
- function isToolResultMessage(msg) {
1334
- if (!msg || msg.role !== "user") return false;
1335
- const parts = msg.parts || [];
1336
- return parts.some(isFunctionResponsePart);
1337
- }
1338
- function messageHasThinking(msg) {
1339
- if (!msg || typeof msg !== "object") return false;
1340
- if (Array.isArray(msg.parts)) {
1341
- return msg.parts.some(isThinkingPart);
1342
- }
1343
- if (Array.isArray(msg.content)) {
1344
- return msg.content.some(
1345
- (block) => block?.type === "thinking" || block?.type === "redacted_thinking"
1346
- );
1347
- }
1348
- return false;
1349
- }
1350
- function messageHasToolCalls(msg) {
1351
- if (!msg || typeof msg !== "object") return false;
1352
- if (Array.isArray(msg.parts)) {
1353
- return msg.parts.some(isFunctionCallPart);
1354
- }
1355
- if (Array.isArray(msg.content)) {
1356
- return msg.content.some((block) => block?.type === "tool_use");
1357
- }
1358
- return false;
1359
- }
1360
- function analyzeConversationState(contents) {
1361
- const state = {
1362
- inToolLoop: false,
1363
- turnStartIdx: -1,
1364
- turnHasThinking: false,
1365
- lastModelIdx: -1,
1366
- lastModelHasThinking: false,
1367
- lastModelHasToolCalls: false
1368
- };
1369
- if (!Array.isArray(contents) || contents.length === 0) {
1370
- return state;
1371
- }
1372
- let lastRealUserIdx = -1;
1373
- for (let i = 0; i < contents.length; i++) {
1374
- const msg = contents[i];
1375
- if (msg?.role === "user" && !isToolResultMessage(msg)) {
1376
- lastRealUserIdx = i;
1377
- }
1378
- }
1379
- for (let i = 0; i < contents.length; i++) {
1380
- const msg = contents[i];
1381
- const role = msg?.role;
1382
- if (role === "model" || role === "assistant") {
1383
- const hasThinking = messageHasThinking(msg);
1384
- const hasToolCalls = messageHasToolCalls(msg);
1385
- if (i > lastRealUserIdx && state.turnStartIdx === -1) {
1386
- state.turnStartIdx = i;
1387
- state.turnHasThinking = hasThinking;
1388
- }
1389
- state.lastModelIdx = i;
1390
- state.lastModelHasToolCalls = hasToolCalls;
1391
- state.lastModelHasThinking = hasThinking;
1392
- }
1393
- }
1394
- if (contents.length > 0) {
1395
- const lastMsg = contents[contents.length - 1];
1396
- if (lastMsg?.role === "user" && isToolResultMessage(lastMsg)) {
1397
- state.inToolLoop = true;
1398
- }
1399
- }
1400
- return state;
1401
- }
1402
- function countTrailingToolResults(contents) {
1403
- let count = 0;
1404
- for (let i = contents.length - 1; i >= 0; i--) {
1405
- const msg = contents[i];
1406
- if (msg?.role === "user") {
1407
- const parts = msg.parts || [];
1408
- const functionResponses = parts.filter(isFunctionResponsePart);
1409
- if (functionResponses.length > 0) {
1410
- count += functionResponses.length;
1411
- } else {
1412
- break;
1413
- }
1414
- } else if (msg?.role === "model" || msg?.role === "assistant") {
1415
- break;
1416
- }
1417
- }
1418
- return count;
1419
- }
1420
- function closeToolLoopForThinking(contents) {
1421
- const strippedContents = contents;
1422
- const toolResultCount = countTrailingToolResults(strippedContents);
1423
- let syntheticModelContent;
1424
- if (toolResultCount === 0) {
1425
- syntheticModelContent = "[Processing prev ctx.]";
1426
- } else if (toolResultCount === 1) {
1427
- syntheticModelContent = "[Tool exec completed.]";
1428
- } else {
1429
- syntheticModelContent = `[${toolResultCount} tool executions completed.]`;
1430
- }
1431
- const syntheticModel = {
1432
- role: "model",
1433
- parts: [{ text: syntheticModelContent }]
1434
- };
1435
- const syntheticUser = {
1436
- role: "user",
1437
- parts: [{ text: "[Continue]" }]
1438
- };
1439
- return [...strippedContents, syntheticModel, syntheticUser];
1440
- }
1441
- function deduplicateThinkingText(response, sentBuffer, displayedThinkingHashes) {
1442
- if (!response || typeof response !== "object") return response;
1443
- const resp = response;
1444
- if (Array.isArray(resp.candidates)) {
1445
- const newCandidates = resp.candidates.map((candidate, index) => {
1446
- const cand = candidate;
1447
- if (!cand?.content) return candidate;
1448
- const content = cand.content;
1449
- if (!Array.isArray(content.parts)) return candidate;
1450
- const newParts = content.parts.map((part) => {
1451
- const p = part;
1452
- if (p.thought === true || p.type === "thinking") {
1453
- const fullText = p.text || p.thinking || "";
1454
- if (displayedThinkingHashes) {
1455
- const hash2 = hashString(fullText);
1456
- if (displayedThinkingHashes.has(hash2)) {
1457
- sentBuffer.set(index, fullText);
1458
- return null;
1459
- }
1460
- displayedThinkingHashes.add(hash2);
1461
- }
1462
- const sentText = sentBuffer.get(index) ?? "";
1463
- if (fullText.startsWith(sentText)) {
1464
- const delta = fullText.slice(sentText.length);
1465
- sentBuffer.set(index, fullText);
1466
- if (delta) {
1467
- return { ...p, text: delta, thinking: delta };
1468
- }
1469
- return null;
1470
- }
1471
- sentBuffer.set(index, fullText);
1472
- return part;
1473
- }
1474
- return part;
1475
- });
1476
- const filteredParts = newParts.filter((p) => p !== null);
1477
- return {
1478
- ...cand,
1479
- content: { ...content, parts: filteredParts }
1480
- };
1481
- });
1482
- return { ...resp, candidates: newCandidates };
1483
- }
1484
- if (Array.isArray(resp.content)) {
1485
- let thinkingIndex = 0;
1486
- const newContent = resp.content.map((block) => {
1487
- const b = block;
1488
- if (b?.type === "thinking") {
1489
- const fullText = b.thinking || b.text || "";
1490
- if (displayedThinkingHashes) {
1491
- const hash2 = hashString(fullText);
1492
- if (displayedThinkingHashes.has(hash2)) {
1493
- sentBuffer.set(thinkingIndex, fullText);
1494
- thinkingIndex++;
1495
- return null;
1496
- }
1497
- displayedThinkingHashes.add(hash2);
1498
- }
1499
- const sentText = sentBuffer.get(thinkingIndex) ?? "";
1500
- if (fullText.startsWith(sentText)) {
1501
- const delta = fullText.slice(sentText.length);
1502
- sentBuffer.set(thinkingIndex, fullText);
1503
- thinkingIndex++;
1504
- if (delta) {
1505
- return { ...b, thinking: delta, text: delta };
1506
- }
1507
- return null;
1508
- }
1509
- sentBuffer.set(thinkingIndex, fullText);
1510
- thinkingIndex++;
1511
- return block;
1512
- }
1513
- return block;
1514
- });
1515
- const filteredContent = newContent.filter((b) => b !== null);
1516
- if (filteredContent.length === 0) {
1517
- return { ...resp, content: [] };
1518
- }
1519
- return { ...resp, content: filteredContent };
1520
- }
1521
- return response;
1522
- }
1523
- function cacheThinkingSignaturesFromResponse(response, signatureSessionKey, signatureStore, thoughtBuffer, onCacheSignature) {
1524
- if (!response || typeof response !== "object") return;
1525
- const resp = response;
1526
- if (Array.isArray(resp.candidates)) {
1527
- resp.candidates.forEach((candidate, index) => {
1528
- const cand = candidate;
1529
- if (!cand?.content) return;
1530
- const content = cand.content;
1531
- if (!Array.isArray(content.parts)) return;
1532
- content.parts.forEach((part) => {
1533
- const p = part;
1534
- if (p.thought === true || p.type === "thinking") {
1535
- const text = p.text || p.thinking || "";
1536
- if (text) {
1537
- const current = thoughtBuffer.get(index) ?? "";
1538
- thoughtBuffer.set(index, current + text);
1539
- }
1540
- }
1541
- if (p.thoughtSignature) {
1542
- const fullText = thoughtBuffer.get(index) ?? "";
1543
- if (fullText) {
1544
- const signature = p.thoughtSignature;
1545
- onCacheSignature?.(signatureSessionKey, fullText, signature);
1546
- signatureStore.set(signatureSessionKey, { text: fullText, signature });
1547
- }
1548
- }
1549
- });
1550
- });
1551
- }
1552
- if (Array.isArray(resp.content)) {
1553
- const CLAUDE_BUFFER_KEY = 0;
1554
- resp.content.forEach((block) => {
1555
- const b = block;
1556
- if (b?.type === "thinking") {
1557
- const text = b.thinking || b.text || "";
1558
- if (text) {
1559
- const current = thoughtBuffer.get(CLAUDE_BUFFER_KEY) ?? "";
1560
- thoughtBuffer.set(CLAUDE_BUFFER_KEY, current + text);
1561
- }
1562
- }
1563
- if (b?.signature) {
1564
- const fullText = thoughtBuffer.get(CLAUDE_BUFFER_KEY) ?? "";
1565
- if (fullText) {
1566
- const signature = b.signature;
1567
- onCacheSignature?.(signatureSessionKey, fullText, signature);
1568
- signatureStore.set(signatureSessionKey, { text: fullText, signature });
1569
- }
1570
- }
1571
- });
1572
- }
1573
- }
1574
- function transformSseEvent(eventText, signatureStore, thoughtBuffer, sentThinkingBuffer, callbacks, options, debugState) {
1575
- const dataLines = [];
1576
- const lines = eventText.split(/\r?\n/);
1577
- let isDataEvent = false;
1578
- for (const line of lines) {
1579
- if (line.startsWith("data:")) {
1580
- isDataEvent = true;
1581
- dataLines.push(line.slice(5).trim());
1582
- }
1583
- }
1584
- if (!isDataEvent) {
1585
- return eventText;
1586
- }
1587
- const jsonString = dataLines.join("\n").trim();
1588
- if (!jsonString) {
1589
- return eventText;
1590
- }
1591
- try {
1592
- const parsed = JSON.parse(jsonString);
1593
- if (parsed && typeof parsed === "object" && parsed.response !== void 0) {
1594
- if (options.cacheSignatures && options.signatureSessionKey) {
1595
- cacheThinkingSignaturesFromResponse(
1596
- parsed.response,
1597
- options.signatureSessionKey,
1598
- signatureStore,
1599
- thoughtBuffer,
1600
- callbacks.onCacheSignature
1601
- );
1602
- }
1603
- let response = deduplicateThinkingText(
1604
- parsed.response,
1605
- sentThinkingBuffer,
1606
- options.displayedThinkingHashes
1607
- );
1608
- if (options.debugText && callbacks.onInjectDebug && !debugState.injected) {
1609
- response = callbacks.onInjectDebug(response, options.debugText);
1610
- debugState.injected = true;
1611
- }
1612
- const transformed = callbacks.transformThinkingParts ? callbacks.transformThinkingParts(response) : response;
1613
- return `data: ${JSON.stringify(transformed)}`;
1614
- }
1615
- } catch (_) {
1616
- }
1617
- return eventText;
1618
- }
1619
- function createStreamingTransformer(signatureStore, callbacks, options = {}) {
1620
- const decoder2 = new TextDecoder();
1621
- const encoder2 = new TextEncoder();
1622
- let buffer = "";
1623
- const thoughtBuffer = createThoughtBuffer();
1624
- const sentThinkingBuffer = createThoughtBuffer();
1625
- const debugState = { injected: false };
1626
- let hasSeenUsageMetadata = false;
1627
- let streamHasThinking = false;
1628
- let streamHasToolCalls = false;
1629
- const displayedThinkingHashes = options.displayedThinkingHashes ?? /* @__PURE__ */ new Set();
1630
- const mergedOptions = { ...options, displayedThinkingHashes };
1631
- return new TransformStream({
1632
- transform(chunk, controller) {
1633
- buffer += decoder2.decode(chunk, { stream: true });
1634
- const events = buffer.split(/\r?\n\r?\n/);
1635
- buffer = events.pop() || "";
1636
- for (const event of events) {
1637
- if (!event.trim()) continue;
1638
- if (event.includes("usageMetadata")) {
1639
- hasSeenUsageMetadata = true;
1640
- }
1641
- if (!streamHasThinking) {
1642
- streamHasThinking = event.includes('"thought":true') || event.includes('"type":"thinking"');
1643
- }
1644
- if (!streamHasToolCalls) {
1645
- streamHasToolCalls = event.includes('"functionCall"');
1646
- }
1647
- const transformedEvent = transformSseEvent(
1648
- event,
1649
- signatureStore,
1650
- thoughtBuffer,
1651
- sentThinkingBuffer,
1652
- callbacks,
1653
- mergedOptions,
1654
- debugState
1655
- );
1656
- controller.enqueue(encoder2.encode(transformedEvent + "\n\n"));
1657
- }
1658
- },
1659
- flush(controller) {
1660
- buffer += decoder2.decode();
1661
- if (buffer.trim()) {
1662
- if (buffer.includes("usageMetadata")) {
1663
- hasSeenUsageMetadata = true;
1664
- }
1665
- if (!streamHasThinking) {
1666
- streamHasThinking = buffer.includes('"thought":true') || buffer.includes('"type":"thinking"');
1667
- }
1668
- if (!streamHasToolCalls) {
1669
- streamHasToolCalls = buffer.includes('"functionCall"');
1670
- }
1671
- const transformedEvent = transformSseEvent(
1672
- buffer,
1673
- signatureStore,
1674
- thoughtBuffer,
1675
- sentThinkingBuffer,
1676
- callbacks,
1677
- mergedOptions,
1678
- debugState
1679
- );
1680
- controller.enqueue(encoder2.encode(transformedEvent + "\n\n"));
1681
- }
1682
- if (!hasSeenUsageMetadata) {
1683
- const syntheticUsage = {
1684
- candidates: [
1685
- {
1686
- finishReason: "STOP"
1687
- }
1688
- ],
1689
- usageMetadata: {
1690
- promptTokenCount: 0,
1691
- candidatesTokenCount: 0,
1692
- totalTokenCount: 0
1693
- }
1694
- };
1695
- controller.enqueue(encoder2.encode(`data: ${JSON.stringify(syntheticUsage)}
1696
-
1697
- `));
1698
- }
1699
- if (callbacks.onTurnStateUpdate && options.signatureSessionKey) {
1700
- callbacks.onTurnStateUpdate(options.signatureSessionKey, {
1701
- turnHasThinking: streamHasThinking,
1702
- lastModelHasToolCalls: streamHasToolCalls
1703
- });
1704
- }
1705
- }
1706
- });
1707
- }
1708
-
1709
- // src/sdk/request/turn-state-tracker.ts
1710
- var WRITE_THROTTLE_MS = 5e3;
1711
- function getConfigDir2() {
1712
- const platform2 = process.platform;
1713
- if (platform2 === "win32") {
1714
- return join2(process.env.APPDATA || join2(homedir2(), "AppData", "Roaming"), "opencode");
1715
- }
1716
- const xdgConfig = process.env.XDG_CONFIG_HOME || join2(homedir2(), ".config");
1717
- return join2(xdgConfig, "opencode");
1718
- }
1719
- function getTurnStateFilePath() {
1720
- return join2(getConfigDir2(), "antigravity-turn-states.json");
1721
- }
1722
- function loadTurnStatesFromDisk() {
1723
- const result = /* @__PURE__ */ new Map();
1724
- try {
1725
- const filePath = getTurnStateFilePath();
1726
- if (!existsSync2(filePath)) {
1727
- return result;
1728
- }
1729
- const content = readFileSync2(filePath, "utf-8");
1730
- const data = JSON.parse(content);
1731
- if (data.version !== "1.0") {
1732
- return result;
1733
- }
1734
- const now = Date.now();
1735
- const maxAge = 24 * 60 * 60 * 1e3;
1736
- for (const [key, record2] of Object.entries(data.entries)) {
1737
- if (record2.state && typeof record2.state === "object" && now - record2.updatedAt < maxAge) {
1738
- result.set(key, record2);
1739
- }
1740
- }
1741
- } catch {
1742
- }
1743
- return result;
1744
- }
1745
- function saveTurnStatesToDisk(entries) {
1746
- try {
1747
- const filePath = getTurnStateFilePath();
1748
- const dir = dirname2(filePath);
1749
- if (!existsSync2(dir)) {
1750
- mkdirSync2(dir, { recursive: true });
1751
- }
1752
- const now = Date.now();
1753
- const maxAge = 24 * 60 * 60 * 1e3;
1754
- const serializable = {};
1755
- for (const [key, record2] of entries.entries()) {
1756
- if (now - record2.updatedAt < maxAge) {
1757
- serializable[key] = record2;
1758
- }
1759
- }
1760
- const data = {
1761
- version: "1.0",
1762
- entries: serializable,
1763
- updatedAt: now
1764
- };
1765
- const tmpPath = join2(tmpdir2(), `antigravity-turn-states-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
1766
- writeFileSync2(tmpPath, JSON.stringify(data), "utf-8");
1767
- try {
1768
- renameSync2(tmpPath, filePath);
1769
- } catch {
1770
- writeFileSync2(filePath, readFileSync2(tmpPath));
1771
- try {
1772
- unlinkSync2(tmpPath);
1773
- } catch {
1774
- }
1775
- }
1776
- return true;
1777
- } catch {
1778
- return false;
1779
- }
1780
- }
1781
- var TurnStateTracker = class {
1782
- entries = /* @__PURE__ */ new Map();
1783
- dirty = false;
1784
- lastWriteTime = 0;
1785
- writeTimer = null;
1786
- diskEnabled;
1787
- constructor(diskEnabled = true) {
1788
- this.diskEnabled = diskEnabled;
1789
- if (diskEnabled) {
1790
- this.entries = loadTurnStatesFromDisk();
1791
- }
1792
- }
1793
- getState(sessionId) {
1794
- const record2 = this.entries.get(sessionId);
1795
- if (!record2) return void 0;
1796
- return record2.state;
1797
- }
1798
- needsThinkingRecovery(sessionId) {
1799
- const state = this.entries.get(sessionId);
1800
- if (!state) return false;
1801
- return state.state.inToolLoop && !state.state.turnHasThinking;
1802
- }
1803
- updateAfterResponse(sessionId, newState) {
1804
- this.entries.set(sessionId, { state: newState, updatedAt: Date.now() });
1805
- this.dirty = true;
1806
- this.scheduleThrottledWrite();
1807
- }
1808
- recoverFromContents(sessionId, contents) {
1809
- const fullState = analyzeConversationState(contents);
1810
- const turnState = {
1811
- inToolLoop: fullState.inToolLoop,
1812
- turnHasThinking: fullState.turnHasThinking,
1813
- lastModelHasThinking: fullState.lastModelHasThinking,
1814
- lastModelHasToolCalls: fullState.lastModelHasToolCalls
1815
- };
1816
- this.entries.set(sessionId, { state: turnState, updatedAt: Date.now() });
1817
- this.dirty = true;
1818
- this.scheduleThrottledWrite();
1819
- return turnState;
1820
- }
1821
- clear(sessionId) {
1822
- this.entries.delete(sessionId);
1823
- this.dirty = true;
1824
- this.scheduleThrottledWrite();
1825
- }
1826
- shutdown() {
1827
- this.clearWriteTimer();
1828
- if (this.dirty && this.diskEnabled) {
1829
- saveTurnStatesToDisk(this.entries);
1830
- this.dirty = false;
1831
- }
1832
- }
1833
- scheduleThrottledWrite() {
1834
- if (!this.diskEnabled) return;
1835
- if (this.writeTimer) {
1836
- return;
1837
- }
1838
- const elapsed = Date.now() - this.lastWriteTime;
1839
- const remaining = Math.max(0, WRITE_THROTTLE_MS - elapsed);
1840
- this.writeTimer = setTimeout(() => {
1841
- this.writeTimer = null;
1842
- this.lastWriteTime = Date.now();
1843
- if (this.dirty) {
1844
- this.dirty = false;
1845
- saveTurnStatesToDisk(this.entries);
1846
- }
1847
- }, remaining);
1848
- if (this.writeTimer && typeof this.writeTimer === "object" && "unref" in this.writeTimer) {
1849
- this.writeTimer.unref();
1850
- }
1851
- }
1852
- clearWriteTimer() {
1853
- if (this.writeTimer) {
1854
- clearTimeout(this.writeTimer);
1855
- this.writeTimer = null;
1856
- }
1857
- }
1858
- };
1859
- var trackerInstance = null;
1860
- function initTurnStateTracker() {
1861
- if (!trackerInstance) {
1862
- try {
1863
- trackerInstance = new TurnStateTracker(true);
1864
- } catch {
1865
- trackerInstance = new TurnStateTracker(false);
1866
- }
1867
- }
1868
- return trackerInstance;
1869
- }
1870
- function getTurnStateTracker() {
1871
- return trackerInstance;
1872
- }
1873
-
1874
- // src/sdk/retry/quota.ts
1875
- var CLOUDCODE_DOMAINS = /* @__PURE__ */ new Set([
1876
- "cloudcode-pa.googleapis.com",
1877
- "staging-cloudcode-pa.googleapis.com",
1878
- "autopush-cloudcode-pa.googleapis.com",
1879
- "cloudaicompanion.googleapis.com",
1880
- "daily-cloudcode-pa.googleapis.com"
1881
- ]);
1882
- async function classifyQuotaResponse(response) {
1883
- const payload = await parseErrorBody(response);
1884
- if (!payload) {
1885
- return null;
1886
- }
1887
- const details = Array.isArray(payload.details) ? payload.details : [];
1888
- const retryInfo = details.find(
1889
- (detail) => isObject(detail) && detail["@type"] === "type.googleapis.com/google.rpc.RetryInfo"
1890
- );
1891
- const retryDelayMs = (retryInfo?.retryDelay ? parseRetryDelayValue(retryInfo.retryDelay) : null) ?? parseRetryDelayFromMessage(payload.message ?? "") ?? void 0;
1892
- const errorInfo = details.find(
1893
- (detail) => isObject(detail) && detail["@type"] === "type.googleapis.com/google.rpc.ErrorInfo"
1894
- );
1895
- if (errorInfo?.domain && !CLOUDCODE_DOMAINS.has(errorInfo.domain)) {
1896
- return null;
1897
- }
1898
- if (errorInfo?.reason === "QUOTA_EXHAUSTED") {
1899
- return { terminal: true, retryDelayMs, reason: errorInfo.reason };
1900
- }
1901
- if (errorInfo?.reason === "RATE_LIMIT_EXCEEDED") {
1902
- return { terminal: false, retryDelayMs: retryDelayMs ?? 1e4, reason: errorInfo.reason };
1903
- }
1904
- if (errorInfo?.reason === "MODEL_CAPACITY_EXHAUSTED") {
1905
- return {
1906
- terminal: retryDelayMs === void 0,
1907
- retryDelayMs,
1908
- reason: errorInfo.reason
1909
- };
1910
- }
1911
- const quotaFailure = details.find(
1912
- (detail) => isObject(detail) && detail["@type"] === "type.googleapis.com/google.rpc.QuotaFailure"
1913
- );
1914
- if (quotaFailure?.violations?.length) {
1915
- const allTexts = quotaFailure.violations.flatMap((violation) => [violation.quotaId ?? "", violation.description ?? ""]).join(" ").toLowerCase();
1916
- if (allTexts.includes("perday") || allTexts.includes("daily") || allTexts.includes("per day")) {
1917
- return { terminal: true, retryDelayMs, reason: errorInfo?.reason };
1918
- }
1919
- if (allTexts.includes("perminute") || allTexts.includes("per minute")) {
1920
- return { terminal: false, retryDelayMs: retryDelayMs ?? 6e4, reason: errorInfo?.reason };
1921
- }
1922
- return { terminal: false, retryDelayMs, reason: errorInfo?.reason };
1923
- }
1924
- const quotaLimit = errorInfo?.metadata?.quota_limit?.toLowerCase() ?? "";
1925
- if (quotaLimit.includes("perminute") || quotaLimit.includes("per minute")) {
1926
- return { terminal: false, retryDelayMs: retryDelayMs ?? 6e4, reason: errorInfo?.reason };
1927
- }
1928
- return { terminal: false, retryDelayMs, reason: errorInfo?.reason };
1929
- }
1930
- async function parseRetryDelayFromBody(response) {
1931
- const payload = await parseErrorBody(response);
1932
- if (!payload) {
1933
- return null;
1934
- }
1935
- const details = Array.isArray(payload.details) ? payload.details : [];
1936
- const retryInfo = details.find(
1937
- (detail) => isObject(detail) && detail["@type"] === "type.googleapis.com/google.rpc.RetryInfo"
1938
- );
1939
- if (retryInfo?.retryDelay) {
1940
- const delayMs = parseRetryDelayValue(retryInfo.retryDelay);
1941
- if (delayMs !== null) {
1942
- return delayMs;
1943
- }
1944
- }
1945
- if (typeof payload.message === "string") {
1946
- return parseRetryDelayFromMessage(payload.message);
1947
- }
1948
- return null;
1949
- }
1950
- function parseRetryDelayValue(value) {
1951
- if (typeof value === "string") {
1952
- const trimmed = value.trim();
1953
- if (!trimmed) {
1954
- return null;
1955
- }
1956
- if (trimmed.endsWith("ms")) {
1957
- const milliseconds = Number(trimmed.slice(0, -2));
1958
- return Number.isFinite(milliseconds) && milliseconds > 0 ? Math.round(milliseconds) : null;
1959
- }
1960
- const match = trimmed.match(/^([\d.]+)s$/);
1961
- if (!match?.[1]) {
1962
- return null;
1963
- }
1964
- const seconds2 = Number(match[1]);
1965
- return Number.isFinite(seconds2) && seconds2 > 0 ? Math.round(seconds2 * 1e3) : null;
1966
- }
1967
- const seconds = typeof value.seconds === "number" ? value.seconds : 0;
1968
- const nanos = typeof value.nanos === "number" ? value.nanos : 0;
1969
- if (!Number.isFinite(seconds) || !Number.isFinite(nanos)) {
1970
- return null;
1971
- }
1972
- const totalMs = Math.round(seconds * 1e3 + nanos / 1e6);
1973
- return totalMs > 0 ? totalMs : null;
1974
- }
1975
- function parseRetryDelayFromMessage(message) {
1976
- const retryMatch = message.match(/Please retry in ([0-9.]+(?:ms|s))/i);
1977
- if (retryMatch?.[1]) {
1978
- return parseRetryDelayValue(retryMatch[1]);
1979
- }
1980
- const afterMatch = message.match(/after\s+([0-9.]+(?:ms|s))/i);
1981
- if (afterMatch?.[1]) {
1982
- return parseRetryDelayValue(afterMatch[1]);
1983
- }
1984
- return null;
1985
- }
1986
- async function parseErrorBody(response) {
1987
- let text = "";
1988
- try {
1989
- text = await response.clone().text();
1990
- } catch {
1991
- return null;
1992
- }
1993
- if (!text) {
1994
- return null;
1995
- }
1996
- let parsed;
1997
- try {
1998
- parsed = JSON.parse(text);
1999
- } catch {
2000
- return null;
2001
- }
2002
- const normalized = normalizeErrorEnvelope(parsed);
2003
- if (!normalized || !isObject(normalized.error)) {
2004
- return null;
2005
- }
2006
- const error45 = normalized.error;
2007
- return {
2008
- message: typeof error45.message === "string" ? error45.message : void 0,
2009
- details: Array.isArray(error45.details) ? error45.details : void 0
2010
- };
2011
- }
2012
- function isObject(value) {
2013
- return !!value && typeof value === "object";
2014
- }
2015
- function normalizeErrorEnvelope(parsed) {
2016
- if (Array.isArray(parsed)) {
2017
- const first = parsed[0];
2018
- return isObject(first) ? first : null;
2019
- }
2020
- return isObject(parsed) ? parsed : null;
2021
- }
2022
-
2023
- // src/sdk/retry/helpers.ts
2024
- var DEFAULT_MAX_ATTEMPTS = 3;
2025
- var DEFAULT_INITIAL_DELAY_MS = 5e3;
2026
- var DEFAULT_MAX_DELAY_MS = 3e4;
2027
- var RETRYABLE_NETWORK_CODES = /* @__PURE__ */ new Set([
2028
- "ECONNRESET",
2029
- "ETIMEDOUT",
2030
- "EPIPE",
2031
- "ENOTFOUND",
2032
- "EAI_AGAIN",
2033
- "ECONNREFUSED",
2034
- "ERR_SSL_SSLV3_ALERT_BAD_RECORD_MAC",
2035
- "ERR_SSL_WRONG_VERSION_NUMBER",
2036
- "ERR_SSL_DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
2037
- "ERR_SSL_BAD_RECORD_MAC",
2038
- "EPROTO"
2039
- ]);
2040
- function canRetryRequest(init) {
2041
- if (!init?.body) {
2042
- return true;
2043
- }
2044
- const body = init.body;
2045
- if (typeof body === "string") {
2046
- return true;
2047
- }
2048
- if (typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams) {
2049
- return true;
2050
- }
2051
- if (typeof ArrayBuffer !== "undefined" && body instanceof ArrayBuffer) {
2052
- return true;
2053
- }
2054
- if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView(body)) {
2055
- return true;
2056
- }
2057
- if (typeof Blob !== "undefined" && body instanceof Blob) {
2058
- return true;
2059
- }
2060
- return false;
2061
- }
2062
- function isRetryableStatus(status) {
2063
- return status === 429 || status >= 500 && status < 600;
2064
- }
2065
- function isRetryableNetworkError(error45) {
2066
- const code = getNetworkErrorCode(error45);
2067
- if (code && RETRYABLE_NETWORK_CODES.has(code)) {
2068
- return true;
2069
- }
2070
- return error45 instanceof Error && error45.message.toLowerCase().includes("fetch failed");
2071
- }
2072
- async function resolveRetryDelayMs(response, attempt, quotaDelayMs) {
2073
- const retryAfterMsHeader = parseRetryAfterMs(response.headers.get("retry-after-ms"));
2074
- if (retryAfterMsHeader !== null) {
2075
- return clampDelay(retryAfterMsHeader);
2076
- }
2077
- const retryAfterHeader = parseRetryAfter(response.headers.get("retry-after"));
2078
- if (retryAfterHeader !== null) {
2079
- return clampDelay(retryAfterHeader);
2080
- }
2081
- if (quotaDelayMs !== void 0) {
2082
- return clampDelay(quotaDelayMs);
2083
- }
2084
- const bodyDelay = await parseRetryDelayFromBody(response);
2085
- if (bodyDelay !== null) {
2086
- return clampDelay(bodyDelay);
2087
- }
2088
- return getExponentialDelayWithJitter(attempt);
2089
- }
2090
- function getExponentialDelayWithJitter(attempt) {
2091
- const base = Math.min(DEFAULT_MAX_DELAY_MS, DEFAULT_INITIAL_DELAY_MS * Math.pow(2, attempt - 1));
2092
- const jitter = base * 0.3 * (Math.random() * 2 - 1);
2093
- return clampDelay(base + jitter);
2094
- }
2095
- function wait2(ms) {
2096
- return new Promise((resolve) => {
2097
- setTimeout(resolve, ms);
2098
- });
2099
- }
2100
- function getNetworkErrorCode(error45) {
2101
- const readCode = (value) => {
2102
- if (!value || typeof value !== "object") {
2103
- return void 0;
2104
- }
2105
- if ("code" in value && typeof value.code === "string") {
2106
- return value.code;
2107
- }
2108
- return void 0;
2109
- };
2110
- const direct = readCode(error45);
2111
- if (direct) {
2112
- return direct;
2113
- }
2114
- let cursor = error45;
2115
- for (let depth = 0; depth < 5; depth += 1) {
2116
- if (!cursor || typeof cursor !== "object" || !("cause" in cursor)) {
2117
- break;
2118
- }
2119
- cursor = cursor.cause;
2120
- const code = readCode(cursor);
2121
- if (code) {
2122
- return code;
2123
- }
2124
- }
2125
- return void 0;
2126
- }
2127
- function parseRetryAfterMs(value) {
2128
- if (!value) {
2129
- return null;
2130
- }
2131
- const parsed = Number(value.trim());
2132
- if (!Number.isFinite(parsed) || parsed <= 0) {
2133
- return null;
2134
- }
2135
- return Math.round(parsed);
2136
- }
2137
- function parseRetryAfter(value) {
2138
- if (!value) {
2139
- return null;
2140
- }
2141
- const trimmed = value.trim();
2142
- if (!trimmed) {
2143
- return null;
2144
- }
2145
- const seconds = Number(trimmed);
2146
- if (Number.isFinite(seconds)) {
2147
- return Math.max(0, Math.round(seconds * 1e3));
2148
- }
2149
- const parsedDate = Date.parse(trimmed);
2150
- if (!Number.isNaN(parsedDate)) {
2151
- return Math.max(0, parsedDate - Date.now());
2152
- }
2153
- return null;
2154
- }
2155
- function clampDelay(delayMs) {
2156
- if (!Number.isFinite(delayMs)) {
2157
- return DEFAULT_MAX_DELAY_MS;
2158
- }
2159
- return Math.min(Math.max(0, Math.round(delayMs)), DEFAULT_MAX_DELAY_MS);
2160
- }
2161
-
2162
- // src/sdk/retry/cooldown-store.ts
2163
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3, renameSync as renameSync3, unlinkSync as unlinkSync3 } from "fs";
2164
- import { join as join3, dirname as dirname3 } from "path";
2165
- import { homedir as homedir3, tmpdir as tmpdir3 } from "os";
2166
- var WRITE_THROTTLE_MS2 = 5e3;
2167
- function getConfigDir3() {
2168
- const platform2 = process.platform;
2169
- if (platform2 === "win32") {
2170
- return join3(process.env.APPDATA || join3(homedir3(), "AppData", "Roaming"), "opencode");
2171
- }
2172
- const xdgConfig = process.env.XDG_CONFIG_HOME || join3(homedir3(), ".config");
2173
- return join3(xdgConfig, "opencode");
2174
- }
2175
- function getCooldownFilePath() {
2176
- return join3(getConfigDir3(), "antigravity-retry-cooldowns.json");
2177
- }
2178
- function loadCooldowns() {
2179
- const result = /* @__PURE__ */ new Map();
2180
- try {
2181
- const filePath = getCooldownFilePath();
2182
- if (!existsSync3(filePath)) {
2183
- return result;
2184
- }
2185
- const content = readFileSync3(filePath, "utf-8");
2186
- const data = JSON.parse(content);
2187
- if (data.version !== "1.0") {
2188
- return result;
2189
- }
2190
- const now = Date.now();
2191
- for (const [key, expiresAt] of Object.entries(data.entries)) {
2192
- if (typeof expiresAt === "number" && expiresAt > now) {
2193
- result.set(key, expiresAt);
2194
- }
2195
- }
2196
- } catch {
2197
- }
2198
- return result;
2199
- }
2200
- function saveCooldowns(entries) {
2201
- try {
2202
- const filePath = getCooldownFilePath();
2203
- const dir = dirname3(filePath);
2204
- if (!existsSync3(dir)) {
2205
- mkdirSync3(dir, { recursive: true });
2206
- }
2207
- const now = Date.now();
2208
- const serializable = {};
2209
- for (const [key, expiresAt] of entries.entries()) {
2210
- if (expiresAt > now) {
2211
- serializable[key] = expiresAt;
2212
- }
2213
- }
2214
- const data = {
2215
- version: "1.0",
2216
- entries: serializable,
2217
- updatedAt: now
2218
- };
2219
- const tmpPath = join3(tmpdir3(), `antigravity-cooldowns-${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`);
2220
- writeFileSync3(tmpPath, JSON.stringify(data), "utf-8");
2221
- try {
2222
- renameSync3(tmpPath, filePath);
2223
- } catch {
2224
- writeFileSync3(filePath, readFileSync3(tmpPath));
2225
- try {
2226
- unlinkSync3(tmpPath);
2227
- } catch {
2228
- }
2229
- }
2230
- return true;
2231
- } catch {
2232
- return false;
2233
- }
2234
- }
2235
- var CooldownStore = class {
2236
- dirty = false;
2237
- lastWriteTime = 0;
2238
- writeTimer = null;
2239
- entries = /* @__PURE__ */ new Map();
2240
- bind(entries) {
2241
- this.entries = entries;
2242
- }
2243
- markDirty() {
2244
- this.dirty = true;
2245
- this.scheduleThrottledWrite();
2246
- }
2247
- flush() {
2248
- this.dirty = false;
2249
- this.clearWriteTimer();
2250
- this.lastWriteTime = Date.now();
2251
- return saveCooldowns(this.entries);
2252
- }
2253
- shutdown() {
2254
- this.clearWriteTimer();
2255
- if (this.dirty) {
2256
- saveCooldowns(this.entries);
2257
- this.dirty = false;
2258
- }
2259
- }
2260
- scheduleThrottledWrite() {
2261
- if (this.writeTimer) {
2262
- return;
2263
- }
2264
- const elapsed = Date.now() - this.lastWriteTime;
2265
- const remaining = Math.max(0, WRITE_THROTTLE_MS2 - elapsed);
2266
- this.writeTimer = setTimeout(() => {
2267
- this.writeTimer = null;
2268
- this.lastWriteTime = Date.now();
2269
- if (this.dirty) {
2270
- this.dirty = false;
2271
- saveCooldowns(this.entries);
2272
- }
2273
- }, remaining);
2274
- if (this.writeTimer && typeof this.writeTimer === "object" && "unref" in this.writeTimer) {
2275
- this.writeTimer.unref();
2276
- }
2277
- }
2278
- clearWriteTimer() {
2279
- if (this.writeTimer) {
2280
- clearTimeout(this.writeTimer);
2281
- this.writeTimer = null;
2282
- }
2283
- }
2284
- };
2285
-
2286
- // src/sdk/retry/index.ts
2287
- var retryCooldownByKey = /* @__PURE__ */ new Map();
2288
- var cooldownStore = new CooldownStore();
2289
- var cooldownPersistenceInitialized = false;
2290
- function initCooldownPersistence() {
2291
- if (cooldownPersistenceInitialized) return;
2292
- cooldownPersistenceInitialized = true;
2293
- try {
2294
- const persisted = loadCooldowns();
2295
- for (const [key, expiresAt] of persisted.entries()) {
2296
- retryCooldownByKey.set(key, expiresAt);
2297
- }
2298
- cooldownStore.bind(retryCooldownByKey);
2299
- } catch {
2300
- cooldownStore.bind(retryCooldownByKey);
2301
- }
2302
- }
2303
- var MODEL_CAPACITY_COOLDOWN_MS = 8e3;
2304
- async function fetchWithRetry(input, init) {
2305
- if (!cooldownPersistenceInitialized) initCooldownPersistence();
2306
- if (!canRetryRequest(init)) {
2307
- return agyFetch(input, init);
2308
- }
2309
- const retryInit = cloneRetryableInit(init);
2310
- const throttleKey = buildRetryThrottleKey(input, retryInit);
2311
- await waitForRetryCooldown(throttleKey, retryInit.signal);
2312
- let attempt = 1;
2313
- const url2 = readRequestUrl(input);
2314
- while (attempt <= DEFAULT_MAX_ATTEMPTS) {
2315
- let response;
2316
- try {
2317
- response = await agyFetch(input, retryInit);
2318
- } catch (error45) {
2319
- if (attempt >= DEFAULT_MAX_ATTEMPTS || !isRetryableNetworkError(error45)) {
2320
- throw error45;
2321
- }
2322
- if (retryInit.signal?.aborted) {
2323
- throw error45;
2324
- }
2325
- const delayMs2 = getExponentialDelayWithJitter(attempt);
2326
- await wait2(delayMs2);
2327
- attempt += 1;
2328
- continue;
2329
- }
2330
- if (!isRetryableStatus(response.status)) {
2331
- return response;
2332
- }
2333
- const quotaContext = response.status === 429 ? await classifyQuotaResponse(response) : null;
2334
- if (response.status === 429 && quotaContext?.terminal) {
2335
- if (quotaContext.reason === "MODEL_CAPACITY_EXHAUSTED") {
2336
- const cooldownMs = quotaContext.retryDelayMs ?? MODEL_CAPACITY_COOLDOWN_MS;
2337
- setRetryCooldown(throttleKey, cooldownMs);
2338
- }
2339
- return response;
2340
- }
2341
- if (attempt >= DEFAULT_MAX_ATTEMPTS || retryInit.signal?.aborted) {
2342
- return response;
2343
- }
2344
- const delayMs = await resolveRetryDelayMs(response, attempt, quotaContext?.retryDelayMs);
2345
- if (delayMs > 0 && response.status === 429) {
2346
- setRetryCooldown(throttleKey, delayMs);
2347
- }
2348
- if (delayMs > 0) {
2349
- await wait2(delayMs);
2350
- }
2351
- attempt += 1;
2352
- }
2353
- return agyFetch(input, retryInit);
2354
- }
2355
- function cloneRetryableInit(init) {
2356
- if (!init) {
2357
- return {};
2358
- }
2359
- return {
2360
- ...init,
2361
- headers: new Headers(init.headers ?? {})
2362
- };
2363
- }
2364
- function buildRetryThrottleKey(input, init) {
2365
- const url2 = readRequestUrl(input);
2366
- const body = typeof init.body === "string" ? safeParseBody(init.body) : null;
2367
- const project = readString(body?.project);
2368
- const model = readString(body?.model);
2369
- return `${url2}|${project ?? ""}|${model ?? ""}`;
2370
- }
2371
- async function waitForRetryCooldown(key, signal) {
2372
- const until = retryCooldownByKey.get(key);
2373
- if (!until) {
2374
- return;
2375
- }
2376
- const remaining = until - Date.now();
2377
- if (remaining <= 0) {
2378
- retryCooldownByKey.delete(key);
2379
- return;
2380
- }
2381
- if (signal?.aborted) {
2382
- return;
2383
- }
2384
- await wait2(remaining);
2385
- retryCooldownByKey.delete(key);
2386
- }
2387
- function setRetryCooldown(key, delayMs) {
2388
- if (!cooldownPersistenceInitialized) initCooldownPersistence();
2389
- const next = Date.now() + delayMs;
2390
- const current = retryCooldownByKey.get(key) ?? 0;
2391
- retryCooldownByKey.set(key, Math.max(current, next));
2392
- cooldownStore.markDirty();
2393
- }
2394
- function readRequestUrl(input) {
2395
- if (typeof input === "string") {
2396
- return input;
2397
- }
2398
- if (input instanceof URL) {
2399
- return input.toString();
2400
- }
2401
- const request = input;
2402
- if (request.url) {
2403
- return request.url;
2404
- }
2405
- return input.toString();
2406
- }
2407
- function safeParseBody(body) {
2408
- if (!body) {
2409
- return null;
2410
- }
2411
- try {
2412
- const parsed = JSON.parse(body);
2413
- if (parsed && typeof parsed === "object") {
2414
- return parsed;
2415
- }
2416
- } catch {
2417
- }
2418
- return null;
2419
- }
2420
- function readString(value) {
2421
- return typeof value === "string" && value.trim() ? value : void 0;
2422
- }
2423
-
2424
1288
  // node_modules/zod/v4/classic/external.js
2425
1289
  var external_exports = {};
2426
1290
  __export(external_exports, {
@@ -3016,7 +1880,7 @@ __export(util_exports, {
3016
1880
  getParsedType: () => getParsedType,
3017
1881
  getSizableOrigin: () => getSizableOrigin,
3018
1882
  hexToUint8Array: () => hexToUint8Array,
3019
- isObject: () => isObject2,
1883
+ isObject: () => isObject,
3020
1884
  isPlainObject: () => isPlainObject,
3021
1885
  issue: () => issue,
3022
1886
  joinValues: () => joinValues,
@@ -3181,7 +2045,7 @@ function esc(str) {
3181
2045
  }
3182
2046
  var captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => {
3183
2047
  };
3184
- function isObject2(data) {
2048
+ function isObject(data) {
3185
2049
  return typeof data === "object" && data !== null && !Array.isArray(data);
3186
2050
  }
3187
2051
  var allowsEval = cached(() => {
@@ -3197,13 +2061,13 @@ var allowsEval = cached(() => {
3197
2061
  }
3198
2062
  });
3199
2063
  function isPlainObject(o) {
3200
- if (isObject2(o) === false)
2064
+ if (isObject(o) === false)
3201
2065
  return false;
3202
2066
  const ctor = o.constructor;
3203
2067
  if (ctor === void 0)
3204
2068
  return true;
3205
2069
  const prot = ctor.prototype;
3206
- if (isObject2(prot) === false)
2070
+ if (isObject(prot) === false)
3207
2071
  return false;
3208
2072
  if (Object.prototype.hasOwnProperty.call(prot, "isPrototypeOf") === false) {
3209
2073
  return false;
@@ -5306,7 +4170,7 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
5306
4170
  }
5307
4171
  return propValues;
5308
4172
  });
5309
- const isObject3 = isObject2;
4173
+ const isObject3 = isObject;
5310
4174
  const catchall = def.catchall;
5311
4175
  let value;
5312
4176
  inst._zod.parse = (payload, ctx) => {
@@ -5386,7 +4250,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
5386
4250
  return (payload, ctx) => fn(shape, payload, ctx);
5387
4251
  };
5388
4252
  let fastpass;
5389
- const isObject3 = isObject2;
4253
+ const isObject3 = isObject;
5390
4254
  const jit = !globalConfig.jitless;
5391
4255
  const allowsEval2 = allowsEval;
5392
4256
  const fastEnabled = jit && allowsEval2.value;
@@ -5518,7 +4382,7 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
5518
4382
  });
5519
4383
  inst._zod.parse = (payload, ctx) => {
5520
4384
  const input = payload.value;
5521
- if (!isObject2(input)) {
4385
+ if (!isObject(input)) {
5522
4386
  payload.issues.push({
5523
4387
  code: "invalid_type",
5524
4388
  expected: "object",
@@ -14749,99 +13613,387 @@ function check(fn) {
14749
13613
  function custom(fn, _params) {
14750
13614
  return _custom(ZodCustom, fn ?? (() => true), _params);
14751
13615
  }
14752
- function refine(fn, _params = {}) {
14753
- return _refine(ZodCustom, fn, _params);
13616
+ function refine(fn, _params = {}) {
13617
+ return _refine(ZodCustom, fn, _params);
13618
+ }
13619
+ function superRefine(fn) {
13620
+ return _superRefine(fn);
13621
+ }
13622
+ function _instanceof(cls, params = {
13623
+ error: `Input not instance of ${cls.name}`
13624
+ }) {
13625
+ const inst = new ZodCustom({
13626
+ type: "custom",
13627
+ check: "custom",
13628
+ fn: (data) => data instanceof cls,
13629
+ abort: true,
13630
+ ...util_exports.normalizeParams(params)
13631
+ });
13632
+ inst._zod.bag.Class = cls;
13633
+ return inst;
13634
+ }
13635
+ var stringbool = (...args) => _stringbool({
13636
+ Codec: ZodCodec,
13637
+ Boolean: ZodBoolean,
13638
+ String: ZodString
13639
+ }, ...args);
13640
+ function json(params) {
13641
+ const jsonSchema = lazy(() => {
13642
+ return union([string2(params), number2(), boolean2(), _null3(), array(jsonSchema), record(string2(), jsonSchema)]);
13643
+ });
13644
+ return jsonSchema;
13645
+ }
13646
+ function preprocess(fn, schema) {
13647
+ return pipe(transform(fn), schema);
13648
+ }
13649
+
13650
+ // node_modules/zod/v4/classic/compat.js
13651
+ var ZodIssueCode = {
13652
+ invalid_type: "invalid_type",
13653
+ too_big: "too_big",
13654
+ too_small: "too_small",
13655
+ invalid_format: "invalid_format",
13656
+ not_multiple_of: "not_multiple_of",
13657
+ unrecognized_keys: "unrecognized_keys",
13658
+ invalid_union: "invalid_union",
13659
+ invalid_key: "invalid_key",
13660
+ invalid_element: "invalid_element",
13661
+ invalid_value: "invalid_value",
13662
+ custom: "custom"
13663
+ };
13664
+ function setErrorMap(map2) {
13665
+ config({
13666
+ customError: map2
13667
+ });
13668
+ }
13669
+ function getErrorMap() {
13670
+ return config().customError;
13671
+ }
13672
+ var ZodFirstPartyTypeKind;
13673
+ /* @__PURE__ */ (function(ZodFirstPartyTypeKind2) {
13674
+ })(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
13675
+
13676
+ // node_modules/zod/v4/classic/coerce.js
13677
+ var coerce_exports = {};
13678
+ __export(coerce_exports, {
13679
+ bigint: () => bigint3,
13680
+ boolean: () => boolean3,
13681
+ date: () => date4,
13682
+ number: () => number3,
13683
+ string: () => string3
13684
+ });
13685
+ function string3(params) {
13686
+ return _coercedString(ZodString, params);
13687
+ }
13688
+ function number3(params) {
13689
+ return _coercedNumber(ZodNumber, params);
13690
+ }
13691
+ function boolean3(params) {
13692
+ return _coercedBoolean(ZodBoolean, params);
13693
+ }
13694
+ function bigint3(params) {
13695
+ return _coercedBigint(ZodBigInt, params);
13696
+ }
13697
+ function date4(params) {
13698
+ return _coercedDate(ZodDate, params);
13699
+ }
13700
+
13701
+ // node_modules/zod/v4/classic/external.js
13702
+ config(en_default());
13703
+
13704
+ // node_modules/@opencode-ai/plugin/dist/tool.js
13705
+ function tool(input) {
13706
+ return input;
13707
+ }
13708
+ tool.schema = external_exports;
13709
+
13710
+ // src/sdk/retry/quota.ts
13711
+ var CLOUDCODE_DOMAINS = /* @__PURE__ */ new Set([
13712
+ "cloudcode-pa.googleapis.com",
13713
+ "staging-cloudcode-pa.googleapis.com",
13714
+ "autopush-cloudcode-pa.googleapis.com",
13715
+ "cloudaicompanion.googleapis.com",
13716
+ "daily-cloudcode-pa.googleapis.com"
13717
+ ]);
13718
+ async function classifyQuotaResponse(response) {
13719
+ const payload = await parseErrorBody(response);
13720
+ if (!payload) {
13721
+ return null;
13722
+ }
13723
+ const details = Array.isArray(payload.details) ? payload.details : [];
13724
+ const retryInfo = details.find(
13725
+ (detail) => isObject2(detail) && detail["@type"] === "type.googleapis.com/google.rpc.RetryInfo"
13726
+ );
13727
+ const retryDelayMs = (retryInfo?.retryDelay ? parseRetryDelayValue(retryInfo.retryDelay) : null) ?? parseRetryDelayFromMessage(payload.message ?? "") ?? void 0;
13728
+ const errorInfo = details.find(
13729
+ (detail) => isObject2(detail) && detail["@type"] === "type.googleapis.com/google.rpc.ErrorInfo"
13730
+ );
13731
+ if (errorInfo?.domain && !CLOUDCODE_DOMAINS.has(errorInfo.domain)) {
13732
+ return null;
13733
+ }
13734
+ if (errorInfo?.reason === "QUOTA_EXHAUSTED") {
13735
+ return { terminal: true, retryDelayMs, reason: errorInfo.reason };
13736
+ }
13737
+ if (errorInfo?.reason === "RATE_LIMIT_EXCEEDED") {
13738
+ return { terminal: false, retryDelayMs: retryDelayMs ?? 1e4, reason: errorInfo.reason };
13739
+ }
13740
+ if (errorInfo?.reason === "MODEL_CAPACITY_EXHAUSTED") {
13741
+ return {
13742
+ terminal: retryDelayMs === void 0,
13743
+ retryDelayMs,
13744
+ reason: errorInfo.reason
13745
+ };
13746
+ }
13747
+ const quotaFailure = details.find(
13748
+ (detail) => isObject2(detail) && detail["@type"] === "type.googleapis.com/google.rpc.QuotaFailure"
13749
+ );
13750
+ if (quotaFailure?.violations?.length) {
13751
+ const allTexts = quotaFailure.violations.flatMap((violation) => [violation.quotaId ?? "", violation.description ?? ""]).join(" ").toLowerCase();
13752
+ if (allTexts.includes("perday") || allTexts.includes("daily") || allTexts.includes("per day")) {
13753
+ return { terminal: true, retryDelayMs, reason: errorInfo?.reason };
13754
+ }
13755
+ if (allTexts.includes("perminute") || allTexts.includes("per minute")) {
13756
+ return { terminal: false, retryDelayMs: retryDelayMs ?? 6e4, reason: errorInfo?.reason };
13757
+ }
13758
+ return { terminal: false, retryDelayMs, reason: errorInfo?.reason };
13759
+ }
13760
+ const quotaLimit = errorInfo?.metadata?.quota_limit?.toLowerCase() ?? "";
13761
+ if (quotaLimit.includes("perminute") || quotaLimit.includes("per minute")) {
13762
+ return { terminal: false, retryDelayMs: retryDelayMs ?? 6e4, reason: errorInfo?.reason };
13763
+ }
13764
+ return { terminal: false, retryDelayMs, reason: errorInfo?.reason };
13765
+ }
13766
+ async function parseRetryDelayFromBody(response) {
13767
+ const payload = await parseErrorBody(response);
13768
+ if (!payload) {
13769
+ return null;
13770
+ }
13771
+ const details = Array.isArray(payload.details) ? payload.details : [];
13772
+ const retryInfo = details.find(
13773
+ (detail) => isObject2(detail) && detail["@type"] === "type.googleapis.com/google.rpc.RetryInfo"
13774
+ );
13775
+ if (retryInfo?.retryDelay) {
13776
+ const delayMs = parseRetryDelayValue(retryInfo.retryDelay);
13777
+ if (delayMs !== null) {
13778
+ return delayMs;
13779
+ }
13780
+ }
13781
+ if (typeof payload.message === "string") {
13782
+ return parseRetryDelayFromMessage(payload.message);
13783
+ }
13784
+ return null;
13785
+ }
13786
+ function parseRetryDelayValue(value) {
13787
+ if (typeof value === "string") {
13788
+ const trimmed = value.trim();
13789
+ if (!trimmed) {
13790
+ return null;
13791
+ }
13792
+ if (trimmed.endsWith("ms")) {
13793
+ const milliseconds = Number(trimmed.slice(0, -2));
13794
+ return Number.isFinite(milliseconds) && milliseconds > 0 ? Math.round(milliseconds) : null;
13795
+ }
13796
+ const match = trimmed.match(/^([\d.]+)s$/);
13797
+ if (!match?.[1]) {
13798
+ return null;
13799
+ }
13800
+ const seconds2 = Number(match[1]);
13801
+ return Number.isFinite(seconds2) && seconds2 > 0 ? Math.round(seconds2 * 1e3) : null;
13802
+ }
13803
+ const seconds = typeof value.seconds === "number" ? value.seconds : 0;
13804
+ const nanos = typeof value.nanos === "number" ? value.nanos : 0;
13805
+ if (!Number.isFinite(seconds) || !Number.isFinite(nanos)) {
13806
+ return null;
13807
+ }
13808
+ const totalMs = Math.round(seconds * 1e3 + nanos / 1e6);
13809
+ return totalMs > 0 ? totalMs : null;
14754
13810
  }
14755
- function superRefine(fn) {
14756
- return _superRefine(fn);
13811
+ function parseRetryDelayFromMessage(message) {
13812
+ const retryMatch = message.match(/Please retry in ([0-9.]+(?:ms|s))/i);
13813
+ if (retryMatch?.[1]) {
13814
+ return parseRetryDelayValue(retryMatch[1]);
13815
+ }
13816
+ const afterMatch = message.match(/after\s+([0-9.]+(?:ms|s))/i);
13817
+ if (afterMatch?.[1]) {
13818
+ return parseRetryDelayValue(afterMatch[1]);
13819
+ }
13820
+ return null;
14757
13821
  }
14758
- function _instanceof(cls, params = {
14759
- error: `Input not instance of ${cls.name}`
14760
- }) {
14761
- const inst = new ZodCustom({
14762
- type: "custom",
14763
- check: "custom",
14764
- fn: (data) => data instanceof cls,
14765
- abort: true,
14766
- ...util_exports.normalizeParams(params)
14767
- });
14768
- inst._zod.bag.Class = cls;
14769
- return inst;
13822
+ async function parseErrorBody(response) {
13823
+ let text = "";
13824
+ try {
13825
+ text = await response.clone().text();
13826
+ } catch {
13827
+ return null;
13828
+ }
13829
+ if (!text) {
13830
+ return null;
13831
+ }
13832
+ let parsed;
13833
+ try {
13834
+ parsed = JSON.parse(text);
13835
+ } catch {
13836
+ return null;
13837
+ }
13838
+ const normalized = normalizeErrorEnvelope(parsed);
13839
+ if (!normalized || !isObject2(normalized.error)) {
13840
+ return null;
13841
+ }
13842
+ const error45 = normalized.error;
13843
+ return {
13844
+ message: typeof error45.message === "string" ? error45.message : void 0,
13845
+ details: Array.isArray(error45.details) ? error45.details : void 0
13846
+ };
14770
13847
  }
14771
- var stringbool = (...args) => _stringbool({
14772
- Codec: ZodCodec,
14773
- Boolean: ZodBoolean,
14774
- String: ZodString
14775
- }, ...args);
14776
- function json(params) {
14777
- const jsonSchema = lazy(() => {
14778
- return union([string2(params), number2(), boolean2(), _null3(), array(jsonSchema), record(string2(), jsonSchema)]);
14779
- });
14780
- return jsonSchema;
13848
+ function isObject2(value) {
13849
+ return !!value && typeof value === "object";
14781
13850
  }
14782
- function preprocess(fn, schema) {
14783
- return pipe(transform(fn), schema);
13851
+ function normalizeErrorEnvelope(parsed) {
13852
+ if (Array.isArray(parsed)) {
13853
+ const first = parsed[0];
13854
+ return isObject2(first) ? first : null;
13855
+ }
13856
+ return isObject2(parsed) ? parsed : null;
14784
13857
  }
14785
13858
 
14786
- // node_modules/zod/v4/classic/compat.js
14787
- var ZodIssueCode = {
14788
- invalid_type: "invalid_type",
14789
- too_big: "too_big",
14790
- too_small: "too_small",
14791
- invalid_format: "invalid_format",
14792
- not_multiple_of: "not_multiple_of",
14793
- unrecognized_keys: "unrecognized_keys",
14794
- invalid_union: "invalid_union",
14795
- invalid_key: "invalid_key",
14796
- invalid_element: "invalid_element",
14797
- invalid_value: "invalid_value",
14798
- custom: "custom"
14799
- };
14800
- function setErrorMap(map2) {
14801
- config({
14802
- customError: map2
14803
- });
13859
+ // src/sdk/retry/helpers.ts
13860
+ var DEFAULT_MAX_ATTEMPTS = 3;
13861
+ var DEFAULT_INITIAL_DELAY_MS = 5e3;
13862
+ var DEFAULT_MAX_DELAY_MS = 3e4;
13863
+ var RETRYABLE_NETWORK_CODES = /* @__PURE__ */ new Set([
13864
+ "ECONNRESET",
13865
+ "ETIMEDOUT",
13866
+ "EPIPE",
13867
+ "ENOTFOUND",
13868
+ "EAI_AGAIN",
13869
+ "ECONNREFUSED",
13870
+ "ERR_SSL_SSLV3_ALERT_BAD_RECORD_MAC",
13871
+ "ERR_SSL_WRONG_VERSION_NUMBER",
13872
+ "ERR_SSL_DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
13873
+ "ERR_SSL_BAD_RECORD_MAC",
13874
+ "EPROTO"
13875
+ ]);
13876
+ function canRetryRequest(init) {
13877
+ if (!init?.body) {
13878
+ return true;
13879
+ }
13880
+ const body = init.body;
13881
+ if (typeof body === "string") {
13882
+ return true;
13883
+ }
13884
+ if (typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams) {
13885
+ return true;
13886
+ }
13887
+ if (typeof ArrayBuffer !== "undefined" && body instanceof ArrayBuffer) {
13888
+ return true;
13889
+ }
13890
+ if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView(body)) {
13891
+ return true;
13892
+ }
13893
+ if (typeof Blob !== "undefined" && body instanceof Blob) {
13894
+ return true;
13895
+ }
13896
+ return false;
14804
13897
  }
14805
- function getErrorMap() {
14806
- return config().customError;
13898
+ function isRetryableStatus(status) {
13899
+ return status === 429 || status >= 500 && status < 600;
14807
13900
  }
14808
- var ZodFirstPartyTypeKind;
14809
- /* @__PURE__ */ (function(ZodFirstPartyTypeKind2) {
14810
- })(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
14811
-
14812
- // node_modules/zod/v4/classic/coerce.js
14813
- var coerce_exports = {};
14814
- __export(coerce_exports, {
14815
- bigint: () => bigint3,
14816
- boolean: () => boolean3,
14817
- date: () => date4,
14818
- number: () => number3,
14819
- string: () => string3
14820
- });
14821
- function string3(params) {
14822
- return _coercedString(ZodString, params);
13901
+ function isRetryableNetworkError(error45) {
13902
+ const code = getNetworkErrorCode(error45);
13903
+ if (code && RETRYABLE_NETWORK_CODES.has(code)) {
13904
+ return true;
13905
+ }
13906
+ return error45 instanceof Error && error45.message.toLowerCase().includes("fetch failed");
14823
13907
  }
14824
- function number3(params) {
14825
- return _coercedNumber(ZodNumber, params);
13908
+ async function resolveRetryDelayMs(response, attempt, quotaDelayMs) {
13909
+ const retryAfterMsHeader = parseRetryAfterMs(response.headers.get("retry-after-ms"));
13910
+ if (retryAfterMsHeader !== null) {
13911
+ return clampDelay(retryAfterMsHeader);
13912
+ }
13913
+ const retryAfterHeader = parseRetryAfter(response.headers.get("retry-after"));
13914
+ if (retryAfterHeader !== null) {
13915
+ return clampDelay(retryAfterHeader);
13916
+ }
13917
+ if (quotaDelayMs !== void 0) {
13918
+ return clampDelay(quotaDelayMs);
13919
+ }
13920
+ const bodyDelay = await parseRetryDelayFromBody(response);
13921
+ if (bodyDelay !== null) {
13922
+ return clampDelay(bodyDelay);
13923
+ }
13924
+ return getExponentialDelayWithJitter(attempt);
14826
13925
  }
14827
- function boolean3(params) {
14828
- return _coercedBoolean(ZodBoolean, params);
13926
+ function getExponentialDelayWithJitter(attempt) {
13927
+ const base = Math.min(DEFAULT_MAX_DELAY_MS, DEFAULT_INITIAL_DELAY_MS * Math.pow(2, attempt - 1));
13928
+ const jitter = base * 0.3 * (Math.random() * 2 - 1);
13929
+ return clampDelay(base + jitter);
14829
13930
  }
14830
- function bigint3(params) {
14831
- return _coercedBigint(ZodBigInt, params);
13931
+ function wait2(ms) {
13932
+ return new Promise((resolve) => {
13933
+ setTimeout(resolve, ms);
13934
+ });
14832
13935
  }
14833
- function date4(params) {
14834
- return _coercedDate(ZodDate, params);
13936
+ function getNetworkErrorCode(error45) {
13937
+ const readCode = (value) => {
13938
+ if (!value || typeof value !== "object") {
13939
+ return void 0;
13940
+ }
13941
+ if ("code" in value && typeof value.code === "string") {
13942
+ return value.code;
13943
+ }
13944
+ return void 0;
13945
+ };
13946
+ const direct = readCode(error45);
13947
+ if (direct) {
13948
+ return direct;
13949
+ }
13950
+ let cursor = error45;
13951
+ for (let depth = 0; depth < 5; depth += 1) {
13952
+ if (!cursor || typeof cursor !== "object" || !("cause" in cursor)) {
13953
+ break;
13954
+ }
13955
+ cursor = cursor.cause;
13956
+ const code = readCode(cursor);
13957
+ if (code) {
13958
+ return code;
13959
+ }
13960
+ }
13961
+ return void 0;
13962
+ }
13963
+ function parseRetryAfterMs(value) {
13964
+ if (!value) {
13965
+ return null;
13966
+ }
13967
+ const parsed = Number(value.trim());
13968
+ if (!Number.isFinite(parsed) || parsed <= 0) {
13969
+ return null;
13970
+ }
13971
+ return Math.round(parsed);
13972
+ }
13973
+ function parseRetryAfter(value) {
13974
+ if (!value) {
13975
+ return null;
13976
+ }
13977
+ const trimmed = value.trim();
13978
+ if (!trimmed) {
13979
+ return null;
13980
+ }
13981
+ const seconds = Number(trimmed);
13982
+ if (Number.isFinite(seconds)) {
13983
+ return Math.max(0, Math.round(seconds * 1e3));
13984
+ }
13985
+ const parsedDate = Date.parse(trimmed);
13986
+ if (!Number.isNaN(parsedDate)) {
13987
+ return Math.max(0, parsedDate - Date.now());
13988
+ }
13989
+ return null;
14835
13990
  }
14836
-
14837
- // node_modules/zod/v4/classic/external.js
14838
- config(en_default());
14839
-
14840
- // node_modules/@opencode-ai/plugin/dist/tool.js
14841
- function tool(input) {
14842
- return input;
13991
+ function clampDelay(delayMs) {
13992
+ if (!Number.isFinite(delayMs)) {
13993
+ return DEFAULT_MAX_DELAY_MS;
13994
+ }
13995
+ return Math.min(Math.max(0, Math.round(delayMs)), DEFAULT_MAX_DELAY_MS);
14843
13996
  }
14844
- tool.schema = external_exports;
14845
13997
 
14846
13998
  // src/plugin/token.ts
14847
13999
  var refreshInFlight = /* @__PURE__ */ new Map();
@@ -16711,424 +15863,826 @@ function rewriteGeminiPreviewAccessError(body, status, requestedModel) {
16711
15863
  if (!needsPreviewAccessOverride(status, body, requestedModel)) {
16712
15864
  return null;
16713
15865
  }
16714
- const error45 = body.error ?? {};
16715
- const trimmedMessage = typeof error45.message === "string" ? error45.message.trim() : "";
16716
- const messagePrefix = trimmedMessage.length > 0 ? trimmedMessage : "Gemini 3 preview features are not enabled for this account.";
16717
- const enhancedMessage = `${messagePrefix} Request preview access at ${GEMINI_PREVIEW_LINK} before using Gemini 3 models.`;
15866
+ const error45 = body.error ?? {};
15867
+ const trimmedMessage = typeof error45.message === "string" ? error45.message.trim() : "";
15868
+ const messagePrefix = trimmedMessage.length > 0 ? trimmedMessage : "Gemini 3 preview features are not enabled for this account.";
15869
+ const enhancedMessage = `${messagePrefix} Request preview access at ${GEMINI_PREVIEW_LINK} before using Gemini 3 models.`;
15870
+ return {
15871
+ ...body,
15872
+ error: {
15873
+ ...error45,
15874
+ message: enhancedMessage
15875
+ }
15876
+ };
15877
+ }
15878
+ function enhanceGeminiErrorResponse(body, status) {
15879
+ const error45 = body.error;
15880
+ if (!error45) {
15881
+ return null;
15882
+ }
15883
+ const details = Array.isArray(error45.details) ? error45.details : [];
15884
+ const retryAfterMs = extractRetryDelay(details, error45.message) ?? void 0;
15885
+ if (status === 403) {
15886
+ const validationInfo = extractValidationInfo(details);
15887
+ if (validationInfo) {
15888
+ const message = [
15889
+ error45.message ?? "Account validation required for Gemini/Agy Code Assist.",
15890
+ validationInfo.link ? `Complete validation: ${validationInfo.link}` : void 0,
15891
+ validationInfo.learnMore ? `Learn more: ${validationInfo.learnMore}` : void 0
15892
+ ].filter(Boolean).join(" ");
15893
+ return {
15894
+ body: {
15895
+ ...body,
15896
+ error: {
15897
+ ...error45,
15898
+ message
15899
+ }
15900
+ },
15901
+ retryAfterMs
15902
+ };
15903
+ }
15904
+ }
15905
+ if (status === 429) {
15906
+ const quotaInfo = extractQuotaInfo(details);
15907
+ if (quotaInfo) {
15908
+ const message = quotaInfo.retryable ? `Rate limit exceeded. ${retryAfterMs ? "Please retry shortly." : "Please retry."}` : "Quota exhausted for this account. Please wait for your quota to reset or upgrade your plan.";
15909
+ return {
15910
+ body: {
15911
+ ...body,
15912
+ error: {
15913
+ ...error45,
15914
+ message
15915
+ }
15916
+ },
15917
+ retryAfterMs
15918
+ };
15919
+ }
15920
+ }
15921
+ return retryAfterMs !== void 0 ? { retryAfterMs } : null;
15922
+ }
15923
+ function needsPreviewAccessOverride(status, body, requestedModel) {
15924
+ if (status !== 404) {
15925
+ return false;
15926
+ }
15927
+ if (isGeminiThreeModel(requestedModel)) {
15928
+ return true;
15929
+ }
15930
+ return isGeminiThreeModel(typeof body.error?.message === "string" ? body.error.message : "");
15931
+ }
15932
+ function isGeminiThreeModel(target) {
15933
+ return !!target && /gemini[\s-]?3/i.test(target);
15934
+ }
15935
+ function extractValidationInfo(details) {
15936
+ const errorInfo = details.find(
15937
+ (detail) => typeof detail === "object" && detail !== null && detail["@type"] === "type.googleapis.com/google.rpc.ErrorInfo"
15938
+ );
15939
+ if (!errorInfo || errorInfo.reason !== "VALIDATION_REQUIRED" || !errorInfo.domain || !CLOUDCODE_DOMAINS2.includes(errorInfo.domain)) {
15940
+ return null;
15941
+ }
15942
+ const helpDetail = details.find(
15943
+ (detail) => typeof detail === "object" && detail !== null && detail["@type"] === "type.googleapis.com/google.rpc.Help"
15944
+ );
15945
+ let link;
15946
+ let learnMore;
15947
+ if (helpDetail?.links && helpDetail.links.length > 0) {
15948
+ link = helpDetail.links[0]?.url;
15949
+ const learnMoreLink = helpDetail.links.find((candidate) => {
15950
+ if (!candidate?.url) {
15951
+ return false;
15952
+ }
15953
+ if (candidate.description?.toLowerCase().trim() === "learn more") {
15954
+ return true;
15955
+ }
15956
+ try {
15957
+ return new URL(candidate.url).hostname === "support.google.com";
15958
+ } catch {
15959
+ return false;
15960
+ }
15961
+ });
15962
+ learnMore = learnMoreLink?.url;
15963
+ }
15964
+ if (!link && errorInfo.metadata?.validation_link) {
15965
+ link = errorInfo.metadata.validation_link;
15966
+ }
15967
+ return link || learnMore ? { link, learnMore } : null;
15968
+ }
15969
+ function extractQuotaInfo(details) {
15970
+ const errorInfo = details.find(
15971
+ (detail) => typeof detail === "object" && detail !== null && detail["@type"] === "type.googleapis.com/google.rpc.ErrorInfo"
15972
+ );
15973
+ if (errorInfo?.reason === "RATE_LIMIT_EXCEEDED") {
15974
+ return { retryable: true };
15975
+ }
15976
+ if (errorInfo?.reason === "QUOTA_EXHAUSTED") {
15977
+ return { retryable: false };
15978
+ }
15979
+ const quotaFailure = details.find(
15980
+ (detail) => typeof detail === "object" && detail !== null && detail["@type"] === "type.googleapis.com/google.rpc.QuotaFailure"
15981
+ );
15982
+ if (!quotaFailure?.violations?.length) {
15983
+ return null;
15984
+ }
15985
+ const description = quotaFailure.violations.map((violation) => violation.description?.toLowerCase() ?? "").join(" ");
15986
+ if (description.includes("daily") || description.includes("per day")) {
15987
+ return { retryable: false };
15988
+ }
15989
+ return { retryable: true };
15990
+ }
15991
+ function extractRetryDelay(details, errorMessage) {
15992
+ const retryInfo = details.find(
15993
+ (detail) => typeof detail === "object" && detail !== null && detail["@type"] === "type.googleapis.com/google.rpc.RetryInfo"
15994
+ );
15995
+ if (retryInfo?.retryDelay) {
15996
+ const delayMs = parseRetryDelayValue2(retryInfo.retryDelay);
15997
+ if (delayMs !== null) {
15998
+ return delayMs;
15999
+ }
16000
+ }
16001
+ if (!errorMessage) {
16002
+ return null;
16003
+ }
16004
+ const retryMatch = errorMessage.match(/Please retry in ([0-9.]+(?:ms|s))/);
16005
+ if (retryMatch?.[1]) {
16006
+ return parseRetryDelayValue2(retryMatch[1]);
16007
+ }
16008
+ const resetMatch = errorMessage.match(/after\s+([0-9.]+(?:ms|s))/i);
16009
+ if (resetMatch?.[1]) {
16010
+ return parseRetryDelayValue2(resetMatch[1]);
16011
+ }
16012
+ return null;
16013
+ }
16014
+ function parseRetryDelayValue2(value) {
16015
+ if (typeof value === "string") {
16016
+ const trimmed = value.trim();
16017
+ if (!trimmed) {
16018
+ return null;
16019
+ }
16020
+ if (trimmed.endsWith("ms")) {
16021
+ const ms = Number(trimmed.slice(0, -2));
16022
+ return Number.isFinite(ms) && ms > 0 ? Math.round(ms) : null;
16023
+ }
16024
+ const match = trimmed.match(/^([\d.]+)s$/);
16025
+ if (match?.[1]) {
16026
+ const seconds2 = Number(match[1]);
16027
+ return Number.isFinite(seconds2) && seconds2 > 0 ? Math.round(seconds2 * 1e3) : null;
16028
+ }
16029
+ return null;
16030
+ }
16031
+ const seconds = typeof value.seconds === "number" ? value.seconds : 0;
16032
+ const nanos = typeof value.nanos === "number" ? value.nanos : 0;
16033
+ if (!Number.isFinite(seconds) || !Number.isFinite(nanos)) {
16034
+ return null;
16035
+ }
16036
+ const totalMs = Math.round(seconds * 1e3 + nanos / 1e6);
16037
+ return totalMs > 0 ? totalMs : null;
16038
+ }
16039
+
16040
+ // src/sdk/request/identifiers.ts
16041
+ import { randomUUID as randomUUID2 } from "crypto";
16042
+
16043
+ // src/sdk/request/shared.ts
16044
+ var REQUEST_MODEL_FALLBACKS = {
16045
+ "gemini-2.5-flash-image": "gemini-2.5-flash",
16046
+ "gemini-3.1-pro-high": "gemini-pro-agent"
16047
+ };
16048
+ var GENERATIVE_LANGUAGE_HOST = new URL(AGY_GENERATIVE_LANGUAGE_ENDPOINT).host;
16049
+ var CODE_ASSIST_HOST_SUFFIX = "cloudcode-pa.googleapis.com";
16050
+ var MODEL_ACTION_PATTERN = /\/models\/[^:]+:\w+/;
16051
+ function toRequestUrlString(value) {
16052
+ if (typeof value === "string") {
16053
+ return value;
16054
+ }
16055
+ if (value instanceof URL) {
16056
+ return value.toString();
16057
+ }
16058
+ const candidate = value.url;
16059
+ if (candidate) {
16060
+ return candidate;
16061
+ }
16062
+ return value.toString();
16063
+ }
16064
+ function isGenerativeLanguageRequest(input) {
16065
+ const url2 = toRequestUrlString(input);
16066
+ return url2.includes(GENERATIVE_LANGUAGE_HOST) || url2.includes(CODE_ASSIST_HOST_SUFFIX) && MODEL_ACTION_PATTERN.test(url2);
16067
+ }
16068
+ function parseGenerativeLanguageRequest(input) {
16069
+ const match = toRequestUrlString(input).match(/\/models\/([^:]+):(\w+)/);
16070
+ if (!match) {
16071
+ return void 0;
16072
+ }
16073
+ const [, requestedModel = "", action = ""] = match;
16074
+ return {
16075
+ requestedModel,
16076
+ effectiveModel: REQUEST_MODEL_FALLBACKS[requestedModel] ?? requestedModel,
16077
+ action
16078
+ };
16079
+ }
16080
+ function isRecord(value) {
16081
+ return !!value && typeof value === "object";
16082
+ }
16083
+ function readString(value) {
16084
+ if (typeof value !== "string") {
16085
+ return void 0;
16086
+ }
16087
+ const trimmed = value.trim();
16088
+ return trimmed.length > 0 ? trimmed : void 0;
16089
+ }
16090
+ function pickString(...values) {
16091
+ for (const value of values) {
16092
+ const str = readString(value);
16093
+ if (str) {
16094
+ return str;
16095
+ }
16096
+ }
16097
+ return void 0;
16098
+ }
16099
+ function injectResponseIdFromTrace(body) {
16100
+ const traceId = readString(body.traceId);
16101
+ if (!traceId) {
16102
+ return body;
16103
+ }
16104
+ const response = body.response;
16105
+ if (!isRecord(response)) {
16106
+ return body;
16107
+ }
16108
+ if (readString(response.responseId)) {
16109
+ return body;
16110
+ }
16718
16111
  return {
16719
16112
  ...body,
16720
- error: {
16721
- ...error45,
16722
- message: enhancedMessage
16113
+ response: {
16114
+ ...response,
16115
+ responseId: traceId
16723
16116
  }
16724
16117
  };
16725
16118
  }
16726
- function enhanceGeminiErrorResponse(body, status) {
16727
- const error45 = body.error;
16728
- if (!error45) {
16729
- return null;
16730
- }
16731
- const details = Array.isArray(error45.details) ? error45.details : [];
16732
- const retryAfterMs = extractRetryDelay(details, error45.message) ?? void 0;
16733
- if (status === 403) {
16734
- const validationInfo = extractValidationInfo(details);
16735
- if (validationInfo) {
16736
- const message = [
16737
- error45.message ?? "Account validation required for Gemini/Agy Code Assist.",
16738
- validationInfo.link ? `Complete validation: ${validationInfo.link}` : void 0,
16739
- validationInfo.learnMore ? `Learn more: ${validationInfo.learnMore}` : void 0
16740
- ].filter(Boolean).join(" ");
16741
- return {
16742
- body: {
16743
- ...body,
16744
- error: {
16745
- ...error45,
16746
- message
16747
- }
16748
- },
16749
- retryAfterMs
16750
- };
16751
- }
16752
- }
16753
- if (status === 429) {
16754
- const quotaInfo = extractQuotaInfo(details);
16755
- if (quotaInfo) {
16756
- const message = quotaInfo.retryable ? `Rate limit exceeded. ${retryAfterMs ? "Please retry shortly." : "Please retry."}` : "Quota exhausted for this account. Please wait for your quota to reset or upgrade your plan.";
16757
- return {
16758
- body: {
16759
- ...body,
16760
- error: {
16761
- ...error45,
16762
- message
16763
- }
16764
- },
16765
- retryAfterMs
16766
- };
16767
- }
16119
+
16120
+ // src/sdk/request/identifiers.ts
16121
+ var PROCESS_SESSION_ID = randomUUID2();
16122
+ var PROCESS_REQUEST_INDEX = 0;
16123
+ function formatAgyRequestId(userPromptId, sessionId) {
16124
+ if (userPromptId.startsWith("agent/")) {
16125
+ return userPromptId;
16768
16126
  }
16769
- return retryAfterMs !== void 0 ? { retryAfterMs } : null;
16127
+ return `agent/${sessionId}/${Date.now()}/${userPromptId}/${PROCESS_REQUEST_INDEX++}`;
16770
16128
  }
16771
- function needsPreviewAccessOverride(status, body, requestedModel) {
16772
- if (status !== 404) {
16773
- return false;
16774
- }
16775
- if (isGeminiThreeModel(requestedModel)) {
16776
- return true;
16777
- }
16778
- return isGeminiThreeModel(typeof body.error?.message === "string" ? body.error.message : "");
16129
+ function resolveUserPromptId(payload, request) {
16130
+ const extra = isRecord(payload.extra_body) ? payload.extra_body : void 0;
16131
+ return pickString(
16132
+ payload.user_prompt_id,
16133
+ payload.userPromptId,
16134
+ payload.prompt_id,
16135
+ payload.promptId,
16136
+ payload.request_id,
16137
+ payload.requestId,
16138
+ request?.user_prompt_id,
16139
+ request?.userPromptId,
16140
+ request?.prompt_id,
16141
+ request?.promptId,
16142
+ request?.request_id,
16143
+ request?.requestId,
16144
+ extra?.user_prompt_id,
16145
+ extra?.userPromptId,
16146
+ extra?.prompt_id,
16147
+ extra?.promptId,
16148
+ extra?.request_id,
16149
+ extra?.requestId
16150
+ ) ?? randomUUID2();
16779
16151
  }
16780
- function isGeminiThreeModel(target) {
16781
- return !!target && /gemini[\s-]?3/i.test(target);
16152
+ function resolveSessionId(payload, request) {
16153
+ const extra = isRecord(payload.extra_body) ? payload.extra_body : void 0;
16154
+ return pickString(
16155
+ request?.session_id,
16156
+ request?.sessionId,
16157
+ payload.session_id,
16158
+ payload.sessionId,
16159
+ extra?.session_id,
16160
+ extra?.sessionId
16161
+ ) ?? PROCESS_SESSION_ID;
16782
16162
  }
16783
- function extractValidationInfo(details) {
16784
- const errorInfo = details.find(
16785
- (detail) => typeof detail === "object" && detail !== null && detail["@type"] === "type.googleapis.com/google.rpc.ErrorInfo"
16786
- );
16787
- if (!errorInfo || errorInfo.reason !== "VALIDATION_REQUIRED" || !errorInfo.domain || !CLOUDCODE_DOMAINS2.includes(errorInfo.domain)) {
16788
- return null;
16163
+ function stripPromptIdentifierAliases(payload) {
16164
+ delete payload.user_prompt_id;
16165
+ delete payload.userPromptId;
16166
+ delete payload.prompt_id;
16167
+ delete payload.promptId;
16168
+ delete payload.request_id;
16169
+ delete payload.requestId;
16170
+ }
16171
+ function stripSessionIdentifierAliases(payload) {
16172
+ delete payload.sessionId;
16173
+ }
16174
+ function normalizeWrappedIdentifiers(wrapped) {
16175
+ const request = isRecord(wrapped.request) ? { ...wrapped.request } : {};
16176
+ const userPromptId = resolveUserPromptId(wrapped, request);
16177
+ const sessionId = resolveSessionId(wrapped, request);
16178
+ const requestId = formatAgyRequestId(userPromptId, sessionId);
16179
+ request.session_id = sessionId;
16180
+ stripSessionIdentifierAliases(request);
16181
+ wrapped.request = request;
16182
+ stripPromptIdentifierAliases(wrapped);
16183
+ wrapped.requestId = requestId;
16184
+ return { userPromptId, sessionId, requestId };
16185
+ }
16186
+ function normalizeRequestPayloadIdentifiers(payload) {
16187
+ const userPromptId = resolveUserPromptId(payload);
16188
+ const sessionId = resolveSessionId(payload);
16189
+ const requestId = formatAgyRequestId(userPromptId, sessionId);
16190
+ payload.session_id = sessionId;
16191
+ stripSessionIdentifierAliases(payload);
16192
+ stripPromptIdentifierAliases(payload);
16193
+ return { userPromptId, sessionId, requestId };
16194
+ }
16195
+
16196
+ // src/sdk/request/openai.ts
16197
+ function transformOpenAIToolCalls(requestPayload) {
16198
+ const messages = requestPayload.messages;
16199
+ if (!messages || !Array.isArray(messages)) {
16200
+ return;
16789
16201
  }
16790
- const helpDetail = details.find(
16791
- (detail) => typeof detail === "object" && detail !== null && detail["@type"] === "type.googleapis.com/google.rpc.Help"
16792
- );
16793
- let link;
16794
- let learnMore;
16795
- if (helpDetail?.links && helpDetail.links.length > 0) {
16796
- link = helpDetail.links[0]?.url;
16797
- const learnMoreLink = helpDetail.links.find((candidate) => {
16798
- if (!candidate?.url) {
16799
- return false;
16202
+ for (const message of messages) {
16203
+ if (!message || typeof message !== "object") {
16204
+ continue;
16205
+ }
16206
+ const msgObj = message;
16207
+ const toolCalls = msgObj.tool_calls;
16208
+ if (!toolCalls || !Array.isArray(toolCalls) || toolCalls.length === 0) {
16209
+ continue;
16210
+ }
16211
+ const parts = [];
16212
+ if (typeof msgObj.content === "string" && msgObj.content.length > 0) {
16213
+ parts.push({ text: msgObj.content });
16214
+ }
16215
+ for (const toolCall of toolCalls) {
16216
+ if (!toolCall || typeof toolCall !== "object") {
16217
+ continue;
16800
16218
  }
16801
- if (candidate.description?.toLowerCase().trim() === "learn more") {
16802
- return true;
16219
+ const fn = toolCall.function;
16220
+ if (!fn || typeof fn !== "object") {
16221
+ continue;
16803
16222
  }
16804
- try {
16805
- return new URL(candidate.url).hostname === "support.google.com";
16806
- } catch {
16807
- return false;
16223
+ const name = fn.name;
16224
+ const args = parseJsonObject(fn.arguments);
16225
+ const functionCallPart = {
16226
+ name: name ?? "",
16227
+ args
16228
+ };
16229
+ if (typeof toolCall.id === "string" && toolCall.id.length > 0) {
16230
+ functionCallPart.id = toolCall.id;
16808
16231
  }
16809
- });
16810
- learnMore = learnMoreLink?.url;
16811
- }
16812
- if (!link && errorInfo.metadata?.validation_link) {
16813
- link = errorInfo.metadata.validation_link;
16232
+ parts.push({
16233
+ functionCall: functionCallPart,
16234
+ thoughtSignature: "skip_thought_signature_validator"
16235
+ });
16236
+ }
16237
+ msgObj.parts = parts;
16238
+ delete msgObj.tool_calls;
16239
+ delete msgObj.content;
16814
16240
  }
16815
- return link || learnMore ? { link, learnMore } : null;
16816
16241
  }
16817
- function extractQuotaInfo(details) {
16818
- const errorInfo = details.find(
16819
- (detail) => typeof detail === "object" && detail !== null && detail["@type"] === "type.googleapis.com/google.rpc.ErrorInfo"
16820
- );
16821
- if (errorInfo?.reason === "RATE_LIMIT_EXCEEDED") {
16822
- return { retryable: true };
16823
- }
16824
- if (errorInfo?.reason === "QUOTA_EXHAUSTED") {
16825
- return { retryable: false };
16826
- }
16827
- const quotaFailure = details.find(
16828
- (detail) => typeof detail === "object" && detail !== null && detail["@type"] === "type.googleapis.com/google.rpc.QuotaFailure"
16829
- );
16830
- if (!quotaFailure?.violations?.length) {
16831
- return null;
16832
- }
16833
- const description = quotaFailure.violations.map((violation) => violation.description?.toLowerCase() ?? "").join(" ");
16834
- if (description.includes("daily") || description.includes("per day")) {
16835
- return { retryable: false };
16242
+ function addThoughtSignaturesToFunctionCalls(requestPayload) {
16243
+ const processContents = (contents) => {
16244
+ if (!contents || !Array.isArray(contents)) {
16245
+ return;
16246
+ }
16247
+ for (const content of contents) {
16248
+ if (!content || typeof content !== "object") {
16249
+ continue;
16250
+ }
16251
+ const parts = content.parts;
16252
+ if (!parts || !Array.isArray(parts)) {
16253
+ continue;
16254
+ }
16255
+ for (const part of parts) {
16256
+ if (!part || typeof part !== "object") {
16257
+ continue;
16258
+ }
16259
+ const partObj = part;
16260
+ if (partObj.functionCall && !partObj.thoughtSignature) {
16261
+ partObj.thoughtSignature = "skip_thought_signature_validator";
16262
+ }
16263
+ }
16264
+ }
16265
+ };
16266
+ processContents(requestPayload.contents);
16267
+ if (requestPayload.request && typeof requestPayload.request === "object") {
16268
+ processContents(requestPayload.request.contents);
16836
16269
  }
16837
- return { retryable: true };
16838
16270
  }
16839
- function extractRetryDelay(details, errorMessage) {
16840
- const retryInfo = details.find(
16841
- (detail) => typeof detail === "object" && detail !== null && detail["@type"] === "type.googleapis.com/google.rpc.RetryInfo"
16842
- );
16843
- if (retryInfo?.retryDelay) {
16844
- const delayMs = parseRetryDelayValue2(retryInfo.retryDelay);
16845
- if (delayMs !== null) {
16846
- return delayMs;
16271
+ function parseJsonObject(value) {
16272
+ if (typeof value !== "string") {
16273
+ return {};
16274
+ }
16275
+ try {
16276
+ const parsed = JSON.parse(value);
16277
+ if (parsed && typeof parsed === "object") {
16278
+ return parsed;
16847
16279
  }
16280
+ return {};
16281
+ } catch {
16282
+ return {};
16848
16283
  }
16849
- if (!errorMessage) {
16850
- return null;
16284
+ }
16285
+
16286
+ // src/sdk/request/thinking.ts
16287
+ import "crypto";
16288
+ function createSignatureStore() {
16289
+ const store = /* @__PURE__ */ new Map();
16290
+ return {
16291
+ get: (key) => store.get(key),
16292
+ set: (key, value) => {
16293
+ store.set(key, value);
16294
+ },
16295
+ has: (key) => store.has(key),
16296
+ delete: (key) => {
16297
+ store.delete(key);
16298
+ }
16299
+ };
16300
+ }
16301
+ function createThoughtBuffer() {
16302
+ const buffer = /* @__PURE__ */ new Map();
16303
+ return {
16304
+ get: (index) => buffer.get(index),
16305
+ set: (index, text) => {
16306
+ buffer.set(index, text);
16307
+ },
16308
+ clear: () => buffer.clear()
16309
+ };
16310
+ }
16311
+ var defaultSignatureStore = createSignatureStore();
16312
+ function hashString(str) {
16313
+ let hash2 = 5381;
16314
+ for (let i = 0; i < str.length; i++) {
16315
+ hash2 = (hash2 << 5) + hash2 + str.charCodeAt(i);
16851
16316
  }
16852
- const retryMatch = errorMessage.match(/Please retry in ([0-9.]+(?:ms|s))/);
16853
- if (retryMatch?.[1]) {
16854
- return parseRetryDelayValue2(retryMatch[1]);
16317
+ return (hash2 >>> 0).toString(16);
16318
+ }
16319
+ function isThinkingPart(part) {
16320
+ if (!part || typeof part !== "object") return false;
16321
+ return part.thought === true || part.type === "thinking" || part.type === "redacted_thinking";
16322
+ }
16323
+ function isFunctionResponsePart(part) {
16324
+ return part && typeof part === "object" && "functionResponse" in part;
16325
+ }
16326
+ function isFunctionCallPart(part) {
16327
+ return part && typeof part === "object" && "functionCall" in part;
16328
+ }
16329
+ function isToolResultMessage(msg) {
16330
+ if (!msg || msg.role !== "user") return false;
16331
+ const parts = msg.parts || [];
16332
+ return parts.some(isFunctionResponsePart);
16333
+ }
16334
+ function messageHasThinking(msg) {
16335
+ if (!msg || typeof msg !== "object") return false;
16336
+ if (Array.isArray(msg.parts)) {
16337
+ return msg.parts.some(isThinkingPart);
16855
16338
  }
16856
- const resetMatch = errorMessage.match(/after\s+([0-9.]+(?:ms|s))/i);
16857
- if (resetMatch?.[1]) {
16858
- return parseRetryDelayValue2(resetMatch[1]);
16339
+ if (Array.isArray(msg.content)) {
16340
+ return msg.content.some(
16341
+ (block) => block?.type === "thinking" || block?.type === "redacted_thinking"
16342
+ );
16859
16343
  }
16860
- return null;
16344
+ return false;
16861
16345
  }
16862
- function parseRetryDelayValue2(value) {
16863
- if (typeof value === "string") {
16864
- const trimmed = value.trim();
16865
- if (!trimmed) {
16866
- return null;
16867
- }
16868
- if (trimmed.endsWith("ms")) {
16869
- const ms = Number(trimmed.slice(0, -2));
16870
- return Number.isFinite(ms) && ms > 0 ? Math.round(ms) : null;
16871
- }
16872
- const match = trimmed.match(/^([\d.]+)s$/);
16873
- if (match?.[1]) {
16874
- const seconds2 = Number(match[1]);
16875
- return Number.isFinite(seconds2) && seconds2 > 0 ? Math.round(seconds2 * 1e3) : null;
16876
- }
16877
- return null;
16346
+ function messageHasToolCalls(msg) {
16347
+ if (!msg || typeof msg !== "object") return false;
16348
+ if (Array.isArray(msg.parts)) {
16349
+ return msg.parts.some(isFunctionCallPart);
16878
16350
  }
16879
- const seconds = typeof value.seconds === "number" ? value.seconds : 0;
16880
- const nanos = typeof value.nanos === "number" ? value.nanos : 0;
16881
- if (!Number.isFinite(seconds) || !Number.isFinite(nanos)) {
16882
- return null;
16351
+ if (Array.isArray(msg.content)) {
16352
+ return msg.content.some((block) => block?.type === "tool_use");
16883
16353
  }
16884
- const totalMs = Math.round(seconds * 1e3 + nanos / 1e6);
16885
- return totalMs > 0 ? totalMs : null;
16354
+ return false;
16886
16355
  }
16887
-
16888
- // src/sdk/request/identifiers.ts
16889
- import { randomUUID as randomUUID2 } from "crypto";
16890
-
16891
- // src/sdk/request/shared.ts
16892
- var REQUEST_MODEL_FALLBACKS = {
16893
- "gemini-2.5-flash-image": "gemini-2.5-flash",
16894
- "gemini-3.1-pro-high": "gemini-pro-agent"
16895
- };
16896
- var GENERATIVE_LANGUAGE_HOST = new URL(AGY_GENERATIVE_LANGUAGE_ENDPOINT).host;
16897
- var CODE_ASSIST_HOST_SUFFIX = "cloudcode-pa.googleapis.com";
16898
- var MODEL_ACTION_PATTERN = /\/models\/[^:]+:\w+/;
16899
- function toRequestUrlString(value) {
16900
- if (typeof value === "string") {
16901
- return value;
16356
+ function analyzeConversationState(contents) {
16357
+ const state = {
16358
+ inToolLoop: false,
16359
+ turnStartIdx: -1,
16360
+ turnHasThinking: false,
16361
+ lastModelIdx: -1,
16362
+ lastModelHasThinking: false,
16363
+ lastModelHasToolCalls: false
16364
+ };
16365
+ if (!Array.isArray(contents) || contents.length === 0) {
16366
+ return state;
16902
16367
  }
16903
- if (value instanceof URL) {
16904
- return value.toString();
16368
+ let lastRealUserIdx = -1;
16369
+ for (let i = 0; i < contents.length; i++) {
16370
+ const msg = contents[i];
16371
+ if (msg?.role === "user" && !isToolResultMessage(msg)) {
16372
+ lastRealUserIdx = i;
16373
+ }
16905
16374
  }
16906
- const candidate = value.url;
16907
- if (candidate) {
16908
- return candidate;
16375
+ for (let i = 0; i < contents.length; i++) {
16376
+ const msg = contents[i];
16377
+ const role = msg?.role;
16378
+ if (role === "model" || role === "assistant") {
16379
+ const hasThinking = messageHasThinking(msg);
16380
+ const hasToolCalls = messageHasToolCalls(msg);
16381
+ if (i > lastRealUserIdx && state.turnStartIdx === -1) {
16382
+ state.turnStartIdx = i;
16383
+ state.turnHasThinking = hasThinking;
16384
+ }
16385
+ state.lastModelIdx = i;
16386
+ state.lastModelHasToolCalls = hasToolCalls;
16387
+ state.lastModelHasThinking = hasThinking;
16388
+ }
16909
16389
  }
16910
- return value.toString();
16390
+ if (contents.length > 0) {
16391
+ const lastMsg = contents[contents.length - 1];
16392
+ if (lastMsg?.role === "user" && isToolResultMessage(lastMsg)) {
16393
+ state.inToolLoop = true;
16394
+ }
16395
+ }
16396
+ return state;
16911
16397
  }
16912
- function isGenerativeLanguageRequest(input) {
16913
- const url2 = toRequestUrlString(input);
16914
- return url2.includes(GENERATIVE_LANGUAGE_HOST) || url2.includes(CODE_ASSIST_HOST_SUFFIX) && MODEL_ACTION_PATTERN.test(url2);
16398
+ function countTrailingToolResults(contents) {
16399
+ let count = 0;
16400
+ for (let i = contents.length - 1; i >= 0; i--) {
16401
+ const msg = contents[i];
16402
+ if (msg?.role === "user") {
16403
+ const parts = msg.parts || [];
16404
+ const functionResponses = parts.filter(isFunctionResponsePart);
16405
+ if (functionResponses.length > 0) {
16406
+ count += functionResponses.length;
16407
+ } else {
16408
+ break;
16409
+ }
16410
+ } else if (msg?.role === "model" || msg?.role === "assistant") {
16411
+ break;
16412
+ }
16413
+ }
16414
+ return count;
16915
16415
  }
16916
- function parseGenerativeLanguageRequest(input) {
16917
- const match = toRequestUrlString(input).match(/\/models\/([^:]+):(\w+)/);
16918
- if (!match) {
16919
- return void 0;
16416
+ function closeToolLoopForThinking(contents) {
16417
+ const strippedContents = contents;
16418
+ const toolResultCount = countTrailingToolResults(strippedContents);
16419
+ let syntheticModelContent;
16420
+ if (toolResultCount === 0) {
16421
+ syntheticModelContent = "[Processing prev ctx.]";
16422
+ } else if (toolResultCount === 1) {
16423
+ syntheticModelContent = "[Tool exec completed.]";
16424
+ } else {
16425
+ syntheticModelContent = `[${toolResultCount} tool executions completed.]`;
16920
16426
  }
16921
- const [, requestedModel = "", action = ""] = match;
16922
- return {
16923
- requestedModel,
16924
- effectiveModel: REQUEST_MODEL_FALLBACKS[requestedModel] ?? requestedModel,
16925
- action
16427
+ const syntheticModel = {
16428
+ role: "model",
16429
+ parts: [{ text: syntheticModelContent }]
16430
+ };
16431
+ const syntheticUser = {
16432
+ role: "user",
16433
+ parts: [{ text: "[Continue]" }]
16926
16434
  };
16435
+ return [...strippedContents, syntheticModel, syntheticUser];
16927
16436
  }
16928
- function isRecord(value) {
16929
- return !!value && typeof value === "object";
16437
+ function needsThinkingRecovery(state) {
16438
+ return state.inToolLoop && !state.turnHasThinking;
16930
16439
  }
16931
- function readString2(value) {
16932
- if (typeof value !== "string") {
16933
- return void 0;
16440
+ function deduplicateThinkingText(response, sentBuffer, displayedThinkingHashes) {
16441
+ if (!response || typeof response !== "object") return response;
16442
+ const resp = response;
16443
+ if (Array.isArray(resp.candidates)) {
16444
+ const newCandidates = resp.candidates.map((candidate, index) => {
16445
+ const cand = candidate;
16446
+ if (!cand?.content) return candidate;
16447
+ const content = cand.content;
16448
+ if (!Array.isArray(content.parts)) return candidate;
16449
+ const newParts = content.parts.map((part) => {
16450
+ const p = part;
16451
+ if (p.thought === true || p.type === "thinking") {
16452
+ const fullText = p.text || p.thinking || "";
16453
+ if (displayedThinkingHashes) {
16454
+ const hash2 = hashString(fullText);
16455
+ if (displayedThinkingHashes.has(hash2)) {
16456
+ sentBuffer.set(index, fullText);
16457
+ return null;
16458
+ }
16459
+ displayedThinkingHashes.add(hash2);
16460
+ }
16461
+ const sentText = sentBuffer.get(index) ?? "";
16462
+ if (fullText.startsWith(sentText)) {
16463
+ const delta = fullText.slice(sentText.length);
16464
+ sentBuffer.set(index, fullText);
16465
+ if (delta) {
16466
+ return { ...p, text: delta, thinking: delta };
16467
+ }
16468
+ return null;
16469
+ }
16470
+ sentBuffer.set(index, fullText);
16471
+ return part;
16472
+ }
16473
+ return part;
16474
+ });
16475
+ const filteredParts = newParts.filter((p) => p !== null);
16476
+ return {
16477
+ ...cand,
16478
+ content: { ...content, parts: filteredParts }
16479
+ };
16480
+ });
16481
+ return { ...resp, candidates: newCandidates };
16934
16482
  }
16935
- const trimmed = value.trim();
16936
- return trimmed.length > 0 ? trimmed : void 0;
16937
- }
16938
- function pickString(...values) {
16939
- for (const value of values) {
16940
- const str = readString2(value);
16941
- if (str) {
16942
- return str;
16483
+ if (Array.isArray(resp.content)) {
16484
+ let thinkingIndex = 0;
16485
+ const newContent = resp.content.map((block) => {
16486
+ const b = block;
16487
+ if (b?.type === "thinking") {
16488
+ const fullText = b.thinking || b.text || "";
16489
+ if (displayedThinkingHashes) {
16490
+ const hash2 = hashString(fullText);
16491
+ if (displayedThinkingHashes.has(hash2)) {
16492
+ sentBuffer.set(thinkingIndex, fullText);
16493
+ thinkingIndex++;
16494
+ return null;
16495
+ }
16496
+ displayedThinkingHashes.add(hash2);
16497
+ }
16498
+ const sentText = sentBuffer.get(thinkingIndex) ?? "";
16499
+ if (fullText.startsWith(sentText)) {
16500
+ const delta = fullText.slice(sentText.length);
16501
+ sentBuffer.set(thinkingIndex, fullText);
16502
+ thinkingIndex++;
16503
+ if (delta) {
16504
+ return { ...b, thinking: delta, text: delta };
16505
+ }
16506
+ return null;
16507
+ }
16508
+ sentBuffer.set(thinkingIndex, fullText);
16509
+ thinkingIndex++;
16510
+ return block;
16511
+ }
16512
+ return block;
16513
+ });
16514
+ const filteredContent = newContent.filter((b) => b !== null);
16515
+ if (filteredContent.length === 0) {
16516
+ return { ...resp, content: [] };
16943
16517
  }
16518
+ return { ...resp, content: filteredContent };
16944
16519
  }
16945
- return void 0;
16520
+ return response;
16946
16521
  }
16947
- function injectResponseIdFromTrace(body) {
16948
- const traceId = readString2(body.traceId);
16949
- if (!traceId) {
16950
- return body;
16951
- }
16952
- const response = body.response;
16953
- if (!isRecord(response)) {
16954
- return body;
16522
+ function cacheThinkingSignaturesFromResponse(response, signatureSessionKey, signatureStore, thoughtBuffer, onCacheSignature) {
16523
+ if (!response || typeof response !== "object") return;
16524
+ const resp = response;
16525
+ if (Array.isArray(resp.candidates)) {
16526
+ resp.candidates.forEach((candidate, index) => {
16527
+ const cand = candidate;
16528
+ if (!cand?.content) return;
16529
+ const content = cand.content;
16530
+ if (!Array.isArray(content.parts)) return;
16531
+ content.parts.forEach((part) => {
16532
+ const p = part;
16533
+ if (p.thought === true || p.type === "thinking") {
16534
+ const text = p.text || p.thinking || "";
16535
+ if (text) {
16536
+ const current = thoughtBuffer.get(index) ?? "";
16537
+ thoughtBuffer.set(index, current + text);
16538
+ }
16539
+ }
16540
+ if (p.thoughtSignature) {
16541
+ const fullText = thoughtBuffer.get(index) ?? "";
16542
+ if (fullText) {
16543
+ const signature = p.thoughtSignature;
16544
+ onCacheSignature?.(signatureSessionKey, fullText, signature);
16545
+ signatureStore.set(signatureSessionKey, { text: fullText, signature });
16546
+ }
16547
+ }
16548
+ });
16549
+ });
16955
16550
  }
16956
- if (readString2(response.responseId)) {
16957
- return body;
16551
+ if (Array.isArray(resp.content)) {
16552
+ const CLAUDE_BUFFER_KEY = 0;
16553
+ resp.content.forEach((block) => {
16554
+ const b = block;
16555
+ if (b?.type === "thinking") {
16556
+ const text = b.thinking || b.text || "";
16557
+ if (text) {
16558
+ const current = thoughtBuffer.get(CLAUDE_BUFFER_KEY) ?? "";
16559
+ thoughtBuffer.set(CLAUDE_BUFFER_KEY, current + text);
16560
+ }
16561
+ }
16562
+ if (b?.signature) {
16563
+ const fullText = thoughtBuffer.get(CLAUDE_BUFFER_KEY) ?? "";
16564
+ if (fullText) {
16565
+ const signature = b.signature;
16566
+ onCacheSignature?.(signatureSessionKey, fullText, signature);
16567
+ signatureStore.set(signatureSessionKey, { text: fullText, signature });
16568
+ }
16569
+ }
16570
+ });
16958
16571
  }
16959
- return {
16960
- ...body,
16961
- response: {
16962
- ...response,
16963
- responseId: traceId
16964
- }
16965
- };
16966
16572
  }
16967
-
16968
- // src/sdk/request/identifiers.ts
16969
- var PROCESS_SESSION_ID = randomUUID2();
16970
- var PROCESS_REQUEST_INDEX = 0;
16971
- function formatAgyRequestId(userPromptId, sessionId) {
16972
- if (userPromptId.startsWith("agent/")) {
16973
- return userPromptId;
16573
+ function transformSseEvent(eventText, signatureStore, thoughtBuffer, sentThinkingBuffer, callbacks, options, debugState) {
16574
+ const dataLines = [];
16575
+ const lines = eventText.split(/\r?\n/);
16576
+ let isDataEvent = false;
16577
+ for (const line of lines) {
16578
+ if (line.startsWith("data:")) {
16579
+ isDataEvent = true;
16580
+ dataLines.push(line.slice(5).trim());
16581
+ }
16974
16582
  }
16975
- return `agent/${sessionId}/${Date.now()}/${userPromptId}/${PROCESS_REQUEST_INDEX++}`;
16976
- }
16977
- function resolveUserPromptId(payload, request) {
16978
- const extra = isRecord(payload.extra_body) ? payload.extra_body : void 0;
16979
- return pickString(
16980
- payload.user_prompt_id,
16981
- payload.userPromptId,
16982
- payload.prompt_id,
16983
- payload.promptId,
16984
- payload.request_id,
16985
- payload.requestId,
16986
- request?.user_prompt_id,
16987
- request?.userPromptId,
16988
- request?.prompt_id,
16989
- request?.promptId,
16990
- request?.request_id,
16991
- request?.requestId,
16992
- extra?.user_prompt_id,
16993
- extra?.userPromptId,
16994
- extra?.prompt_id,
16995
- extra?.promptId,
16996
- extra?.request_id,
16997
- extra?.requestId
16998
- ) ?? randomUUID2();
16999
- }
17000
- function resolveSessionId(payload, request) {
17001
- const extra = isRecord(payload.extra_body) ? payload.extra_body : void 0;
17002
- return pickString(
17003
- request?.session_id,
17004
- request?.sessionId,
17005
- payload.session_id,
17006
- payload.sessionId,
17007
- extra?.session_id,
17008
- extra?.sessionId
17009
- ) ?? PROCESS_SESSION_ID;
17010
- }
17011
- function stripPromptIdentifierAliases(payload) {
17012
- delete payload.user_prompt_id;
17013
- delete payload.userPromptId;
17014
- delete payload.prompt_id;
17015
- delete payload.promptId;
17016
- delete payload.request_id;
17017
- delete payload.requestId;
17018
- }
17019
- function stripSessionIdentifierAliases(payload) {
17020
- delete payload.sessionId;
17021
- }
17022
- function normalizeWrappedIdentifiers(wrapped) {
17023
- const request = isRecord(wrapped.request) ? { ...wrapped.request } : {};
17024
- const userPromptId = resolveUserPromptId(wrapped, request);
17025
- const sessionId = resolveSessionId(wrapped, request);
17026
- const requestId = formatAgyRequestId(userPromptId, sessionId);
17027
- request.session_id = sessionId;
17028
- stripSessionIdentifierAliases(request);
17029
- wrapped.request = request;
17030
- stripPromptIdentifierAliases(wrapped);
17031
- wrapped.requestId = requestId;
17032
- return { userPromptId, sessionId, requestId };
17033
- }
17034
- function normalizeRequestPayloadIdentifiers(payload) {
17035
- const userPromptId = resolveUserPromptId(payload);
17036
- const sessionId = resolveSessionId(payload);
17037
- const requestId = formatAgyRequestId(userPromptId, sessionId);
17038
- payload.session_id = sessionId;
17039
- stripSessionIdentifierAliases(payload);
17040
- stripPromptIdentifierAliases(payload);
17041
- return { userPromptId, sessionId, requestId };
17042
- }
17043
-
17044
- // src/sdk/request/openai.ts
17045
- function transformOpenAIToolCalls(requestPayload) {
17046
- const messages = requestPayload.messages;
17047
- if (!messages || !Array.isArray(messages)) {
17048
- return;
16583
+ if (!isDataEvent) {
16584
+ return eventText;
17049
16585
  }
17050
- for (const message of messages) {
17051
- if (!message || typeof message !== "object") {
17052
- continue;
17053
- }
17054
- const msgObj = message;
17055
- const toolCalls = msgObj.tool_calls;
17056
- if (!toolCalls || !Array.isArray(toolCalls) || toolCalls.length === 0) {
17057
- continue;
17058
- }
17059
- const parts = [];
17060
- if (typeof msgObj.content === "string" && msgObj.content.length > 0) {
17061
- parts.push({ text: msgObj.content });
17062
- }
17063
- for (const toolCall of toolCalls) {
17064
- if (!toolCall || typeof toolCall !== "object") {
17065
- continue;
17066
- }
17067
- const fn = toolCall.function;
17068
- if (!fn || typeof fn !== "object") {
17069
- continue;
16586
+ const jsonString = dataLines.join("\n").trim();
16587
+ if (!jsonString) {
16588
+ return eventText;
16589
+ }
16590
+ try {
16591
+ const parsed = JSON.parse(jsonString);
16592
+ if (parsed && typeof parsed === "object" && parsed.response !== void 0) {
16593
+ if (options.cacheSignatures && options.signatureSessionKey) {
16594
+ cacheThinkingSignaturesFromResponse(
16595
+ parsed.response,
16596
+ options.signatureSessionKey,
16597
+ signatureStore,
16598
+ thoughtBuffer,
16599
+ callbacks.onCacheSignature
16600
+ );
17070
16601
  }
17071
- const name = fn.name;
17072
- const args = parseJsonObject(fn.arguments);
17073
- const functionCallPart = {
17074
- name: name ?? "",
17075
- args
17076
- };
17077
- if (typeof toolCall.id === "string" && toolCall.id.length > 0) {
17078
- functionCallPart.id = toolCall.id;
16602
+ let response = deduplicateThinkingText(
16603
+ parsed.response,
16604
+ sentThinkingBuffer,
16605
+ options.displayedThinkingHashes
16606
+ );
16607
+ if (options.debugText && callbacks.onInjectDebug && !debugState.injected) {
16608
+ response = callbacks.onInjectDebug(response, options.debugText);
16609
+ debugState.injected = true;
17079
16610
  }
17080
- parts.push({
17081
- functionCall: functionCallPart,
17082
- thoughtSignature: "skip_thought_signature_validator"
17083
- });
16611
+ const transformed = callbacks.transformThinkingParts ? callbacks.transformThinkingParts(response) : response;
16612
+ return `data: ${JSON.stringify(transformed)}`;
17084
16613
  }
17085
- msgObj.parts = parts;
17086
- delete msgObj.tool_calls;
17087
- delete msgObj.content;
16614
+ } catch (_) {
17088
16615
  }
16616
+ return eventText;
17089
16617
  }
17090
- function addThoughtSignaturesToFunctionCalls(requestPayload) {
17091
- const processContents = (contents) => {
17092
- if (!contents || !Array.isArray(contents)) {
17093
- return;
17094
- }
17095
- for (const content of contents) {
17096
- if (!content || typeof content !== "object") {
17097
- continue;
17098
- }
17099
- const parts = content.parts;
17100
- if (!parts || !Array.isArray(parts)) {
17101
- continue;
17102
- }
17103
- for (const part of parts) {
17104
- if (!part || typeof part !== "object") {
17105
- continue;
16618
+ function createStreamingTransformer(signatureStore, callbacks, options = {}) {
16619
+ const decoder2 = new TextDecoder();
16620
+ const encoder2 = new TextEncoder();
16621
+ let buffer = "";
16622
+ const thoughtBuffer = createThoughtBuffer();
16623
+ const sentThinkingBuffer = createThoughtBuffer();
16624
+ const debugState = { injected: false };
16625
+ let hasSeenUsageMetadata = false;
16626
+ const displayedThinkingHashes = options.displayedThinkingHashes ?? /* @__PURE__ */ new Set();
16627
+ const mergedOptions = { ...options, displayedThinkingHashes };
16628
+ return new TransformStream({
16629
+ transform(chunk, controller) {
16630
+ buffer += decoder2.decode(chunk, { stream: true });
16631
+ const events = buffer.split(/\r?\n\r?\n/);
16632
+ buffer = events.pop() || "";
16633
+ for (const event of events) {
16634
+ if (!event.trim()) continue;
16635
+ if (event.includes("usageMetadata")) {
16636
+ hasSeenUsageMetadata = true;
17106
16637
  }
17107
- const partObj = part;
17108
- if (partObj.functionCall && !partObj.thoughtSignature) {
17109
- partObj.thoughtSignature = "skip_thought_signature_validator";
16638
+ const transformedEvent = transformSseEvent(
16639
+ event,
16640
+ signatureStore,
16641
+ thoughtBuffer,
16642
+ sentThinkingBuffer,
16643
+ callbacks,
16644
+ mergedOptions,
16645
+ debugState
16646
+ );
16647
+ controller.enqueue(encoder2.encode(transformedEvent + "\n\n"));
16648
+ }
16649
+ },
16650
+ flush(controller) {
16651
+ buffer += decoder2.decode();
16652
+ if (buffer.trim()) {
16653
+ if (buffer.includes("usageMetadata")) {
16654
+ hasSeenUsageMetadata = true;
17110
16655
  }
16656
+ const transformedEvent = transformSseEvent(
16657
+ buffer,
16658
+ signatureStore,
16659
+ thoughtBuffer,
16660
+ sentThinkingBuffer,
16661
+ callbacks,
16662
+ mergedOptions,
16663
+ debugState
16664
+ );
16665
+ controller.enqueue(encoder2.encode(transformedEvent + "\n\n"));
16666
+ }
16667
+ if (!hasSeenUsageMetadata) {
16668
+ const syntheticUsage = {
16669
+ candidates: [
16670
+ {
16671
+ finishReason: "STOP"
16672
+ }
16673
+ ],
16674
+ usageMetadata: {
16675
+ promptTokenCount: 0,
16676
+ candidatesTokenCount: 0,
16677
+ totalTokenCount: 0
16678
+ }
16679
+ };
16680
+ controller.enqueue(encoder2.encode(`data: ${JSON.stringify(syntheticUsage)}
16681
+
16682
+ `));
17111
16683
  }
17112
16684
  }
17113
- };
17114
- processContents(requestPayload.contents);
17115
- if (requestPayload.request && typeof requestPayload.request === "object") {
17116
- processContents(requestPayload.request.contents);
17117
- }
17118
- }
17119
- function parseJsonObject(value) {
17120
- if (typeof value !== "string") {
17121
- return {};
17122
- }
17123
- try {
17124
- const parsed = JSON.parse(value);
17125
- if (parsed && typeof parsed === "object") {
17126
- return parsed;
17127
- }
17128
- return {};
17129
- } catch {
17130
- return {};
17131
- }
16685
+ });
17132
16686
  }
17133
16687
 
17134
16688
  // src/sdk/request/prepare.ts
@@ -17241,17 +16795,8 @@ function transformRequestBody(body, projectId, effectiveModel, requestedModel, t
17241
16795
  let contents2 = requestPayloadInside.contents;
17242
16796
  injectMissingToolCallIds(contents2);
17243
16797
  fixOrphanedFunctionResponses(contents2);
17244
- const tracker = getTurnStateTracker();
17245
- let needsRecovery = false;
17246
- if (sessionId2 && tracker) {
17247
- const existing = tracker.getState(sessionId2);
17248
- if (existing) {
17249
- needsRecovery = existing.inToolLoop && !existing.turnHasThinking;
17250
- } else {
17251
- needsRecovery = tracker.recoverFromContents(sessionId2, contents2).inToolLoop && !tracker.getState(sessionId2)?.turnHasThinking;
17252
- }
17253
- }
17254
- if (needsRecovery) {
16798
+ const state = analyzeConversationState(contents2);
16799
+ if (needsThinkingRecovery(state)) {
17255
16800
  contents2 = closeToolLoopForThinking(contents2);
17256
16801
  }
17257
16802
  contents2 = normalizeContentsSequence(contents2);
@@ -17279,17 +16824,8 @@ function transformRequestBody(body, projectId, effectiveModel, requestedModel, t
17279
16824
  if (Array.isArray(contents)) {
17280
16825
  injectMissingToolCallIds(contents);
17281
16826
  fixOrphanedFunctionResponses(contents);
17282
- const tracker = getTurnStateTracker();
17283
- let needsRecovery = false;
17284
- if (sessionId && tracker) {
17285
- const existing = tracker.getState(sessionId);
17286
- if (existing) {
17287
- needsRecovery = existing.inToolLoop && !existing.turnHasThinking;
17288
- } else {
17289
- needsRecovery = tracker.recoverFromContents(sessionId, contents).inToolLoop && !tracker.getState(sessionId)?.turnHasThinking;
17290
- }
17291
- }
17292
- if (needsRecovery) {
16827
+ const state = analyzeConversationState(contents);
16828
+ if (needsThinkingRecovery(state)) {
17293
16829
  contents = closeToolLoopForThinking(contents);
17294
16830
  }
17295
16831
  contents = normalizeContentsSequence(contents);
@@ -17674,17 +17210,6 @@ function transformStreamingPayloadStream(stream, sessionId, chatLogger) {
17674
17210
  onCacheSignature: (sessionKey, text, signature) => {
17675
17211
  cacheSignature(sessionKey, text, signature);
17676
17212
  },
17677
- onTurnStateUpdate: (sessionKey, state) => {
17678
- const tracker = getTurnStateTracker();
17679
- if (tracker) {
17680
- tracker.updateAfterResponse(sessionKey, {
17681
- inToolLoop: state.lastModelHasToolCalls,
17682
- turnHasThinking: state.turnHasThinking,
17683
- lastModelHasThinking: state.turnHasThinking,
17684
- lastModelHasToolCalls: state.lastModelHasToolCalls
17685
- });
17686
- }
17687
- },
17688
17213
  transformThinkingParts: (response) => {
17689
17214
  if (response && typeof response === "object") {
17690
17215
  return injectResponseIdFromTrace(response);
@@ -17707,20 +17232,20 @@ function transformStreamingPayloadStream(stream, sessionId, chatLogger) {
17707
17232
  }
17708
17233
 
17709
17234
  // src/sdk/chat-logger.ts
17710
- import { createWriteStream, existsSync as existsSync4, mkdirSync as mkdirSync4 } from "fs";
17711
- import { join as join4 } from "path";
17235
+ import { createWriteStream, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
17236
+ import { join as join2 } from "path";
17712
17237
  import { cwd } from "process";
17713
17238
  function createChatLogger() {
17714
17239
  if (process.env.AGY_LOG !== "1") {
17715
17240
  return null;
17716
17241
  }
17717
17242
  try {
17718
- const logDir = join4(cwd(), "agy_chat_log");
17719
- if (!existsSync4(logDir)) {
17720
- mkdirSync4(logDir, { recursive: true });
17243
+ const logDir = join2(cwd(), "agy_chat_log");
17244
+ if (!existsSync2(logDir)) {
17245
+ mkdirSync2(logDir, { recursive: true });
17721
17246
  }
17722
17247
  const timestamp = Date.now();
17723
- const logFile = join4(logDir, `${timestamp}.log`);
17248
+ const logFile = join2(logDir, `${timestamp}.log`);
17724
17249
  const stream = createWriteStream(logFile, { flags: "w", encoding: "utf8" });
17725
17250
  return new ChatLoggerImpl(stream);
17726
17251
  } catch (error45) {
@@ -17822,6 +17347,126 @@ var ChatLoggerImpl = class {
17822
17347
  }
17823
17348
  };
17824
17349
 
17350
+ // src/sdk/retry/index.ts
17351
+ var retryCooldownByKey = /* @__PURE__ */ new Map();
17352
+ var MODEL_CAPACITY_COOLDOWN_MS = 8e3;
17353
+ async function fetchWithRetry(input, init) {
17354
+ if (!canRetryRequest(init)) {
17355
+ return agyFetch(input, init);
17356
+ }
17357
+ const retryInit = cloneRetryableInit(init);
17358
+ const throttleKey = buildRetryThrottleKey(input, retryInit);
17359
+ await waitForRetryCooldown(throttleKey, retryInit.signal);
17360
+ let attempt = 1;
17361
+ const url2 = readRequestUrl(input);
17362
+ while (attempt <= DEFAULT_MAX_ATTEMPTS) {
17363
+ let response;
17364
+ try {
17365
+ response = await agyFetch(input, retryInit);
17366
+ } catch (error45) {
17367
+ if (attempt >= DEFAULT_MAX_ATTEMPTS || !isRetryableNetworkError(error45)) {
17368
+ throw error45;
17369
+ }
17370
+ if (retryInit.signal?.aborted) {
17371
+ throw error45;
17372
+ }
17373
+ const delayMs2 = getExponentialDelayWithJitter(attempt);
17374
+ await wait2(delayMs2);
17375
+ attempt += 1;
17376
+ continue;
17377
+ }
17378
+ if (!isRetryableStatus(response.status)) {
17379
+ return response;
17380
+ }
17381
+ const quotaContext = response.status === 429 ? await classifyQuotaResponse(response) : null;
17382
+ if (response.status === 429 && quotaContext?.terminal) {
17383
+ if (quotaContext.reason === "MODEL_CAPACITY_EXHAUSTED") {
17384
+ const cooldownMs = quotaContext.retryDelayMs ?? MODEL_CAPACITY_COOLDOWN_MS;
17385
+ setRetryCooldown(throttleKey, cooldownMs);
17386
+ }
17387
+ return response;
17388
+ }
17389
+ if (attempt >= DEFAULT_MAX_ATTEMPTS || retryInit.signal?.aborted) {
17390
+ return response;
17391
+ }
17392
+ const delayMs = await resolveRetryDelayMs(response, attempt, quotaContext?.retryDelayMs);
17393
+ if (delayMs > 0 && response.status === 429) {
17394
+ setRetryCooldown(throttleKey, delayMs);
17395
+ }
17396
+ if (delayMs > 0) {
17397
+ await wait2(delayMs);
17398
+ }
17399
+ attempt += 1;
17400
+ }
17401
+ return agyFetch(input, retryInit);
17402
+ }
17403
+ function cloneRetryableInit(init) {
17404
+ if (!init) {
17405
+ return {};
17406
+ }
17407
+ return {
17408
+ ...init,
17409
+ headers: new Headers(init.headers ?? {})
17410
+ };
17411
+ }
17412
+ function buildRetryThrottleKey(input, init) {
17413
+ const url2 = readRequestUrl(input);
17414
+ const body = typeof init.body === "string" ? safeParseBody(init.body) : null;
17415
+ const project = readString2(body?.project);
17416
+ const model = readString2(body?.model);
17417
+ return `${url2}|${project ?? ""}|${model ?? ""}`;
17418
+ }
17419
+ async function waitForRetryCooldown(key, signal) {
17420
+ const until = retryCooldownByKey.get(key);
17421
+ if (!until) {
17422
+ return;
17423
+ }
17424
+ const remaining = until - Date.now();
17425
+ if (remaining <= 0) {
17426
+ retryCooldownByKey.delete(key);
17427
+ return;
17428
+ }
17429
+ if (signal?.aborted) {
17430
+ return;
17431
+ }
17432
+ await wait2(remaining);
17433
+ retryCooldownByKey.delete(key);
17434
+ }
17435
+ function setRetryCooldown(key, delayMs) {
17436
+ const next = Date.now() + delayMs;
17437
+ const current = retryCooldownByKey.get(key) ?? 0;
17438
+ retryCooldownByKey.set(key, Math.max(current, next));
17439
+ }
17440
+ function readRequestUrl(input) {
17441
+ if (typeof input === "string") {
17442
+ return input;
17443
+ }
17444
+ if (input instanceof URL) {
17445
+ return input.toString();
17446
+ }
17447
+ const request = input;
17448
+ if (request.url) {
17449
+ return request.url;
17450
+ }
17451
+ return input.toString();
17452
+ }
17453
+ function safeParseBody(body) {
17454
+ if (!body) {
17455
+ return null;
17456
+ }
17457
+ try {
17458
+ const parsed = JSON.parse(body);
17459
+ if (parsed && typeof parsed === "object") {
17460
+ return parsed;
17461
+ }
17462
+ } catch {
17463
+ }
17464
+ return null;
17465
+ }
17466
+ function readString2(value) {
17467
+ return typeof value === "string" && value.trim() ? value : void 0;
17468
+ }
17469
+
17825
17470
  // src/plugin.ts
17826
17471
  var AGY_QUOTA_COMMAND = "agyquota";
17827
17472
  var AGY_QUOTA_COMMAND_TEMPLATE = `Retrieve Agy Code Assist quota usage for the current authenticated account.
@@ -18057,26 +17702,12 @@ var AgyCLIOAuthPlugin = async ({ client }) => {
18057
17702
  normalizeProviderModelCosts(provider);
18058
17703
  return STATIC_MODELS;
18059
17704
  };
18060
- try {
18061
- initDiskSignatureCache({
18062
- enabled: true,
18063
- memory_ttl_seconds: 3600,
18064
- disk_ttl_seconds: 86400,
18065
- write_interval_seconds: 30
18066
- });
18067
- } catch (e) {
18068
- console.warn(`[Agy Auth] initDiskSignatureCache failed, running without signature disk cache: ${e instanceof Error ? e.message : e}`);
18069
- }
18070
- try {
18071
- initTurnStateTracker();
18072
- } catch (e) {
18073
- console.warn(`[Agy Auth] initTurnStateTracker failed, running without turn-state tracking: ${e instanceof Error ? e.message : e}`);
18074
- }
18075
- try {
18076
- initCooldownPersistence();
18077
- } catch (e) {
18078
- console.warn(`[Agy Auth] initCooldownPersistence failed, running without cooldown disk persistence: ${e instanceof Error ? e.message : e}`);
18079
- }
17705
+ initDiskSignatureCache({
17706
+ enabled: true,
17707
+ memory_ttl_seconds: 3600,
17708
+ disk_ttl_seconds: 86400,
17709
+ write_interval_seconds: 30
17710
+ });
18080
17711
  const resolveLatestConfiguredProjectId = async (provider) => {
18081
17712
  const configProjectId = await resolveConfiguredProjectIdFromClient(client) ?? latestAgyConfiguredProjectId;
18082
17713
  const resolvedProjectId = resolveConfiguredProjectId({
@@ -18349,10 +17980,7 @@ function toUrlString(value) {
18349
17980
  }
18350
17981
 
18351
17982
  // index.ts
18352
- var index_default = {
18353
- id: "@anthonyhaussman/opencode-agy-auth",
18354
- server: AgyCLIOAuthPlugin
18355
- };
17983
+ var index_default = AgyCLIOAuthPlugin;
18356
17984
  export {
18357
17985
  AgyCLIOAuthPlugin,
18358
17986
  GoogleOAuthPlugin,