@letrquan/book 0.2.0 → 0.3.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.
Files changed (157) hide show
  1. package/CHANGELOG.md +2747 -40
  2. package/README.md +132 -1311
  3. package/dist/additional-roots-H7UNAEHS.js +31 -0
  4. package/dist/{app-MOXXWEOY.js → app-GE4OHJOC.js} +5740 -4045
  5. package/dist/app-GE4OHJOC.js.map +1 -0
  6. package/dist/{chunk-5GDZ22YP.js → chunk-224FJZLH.js} +99 -108
  7. package/dist/chunk-224FJZLH.js.map +1 -0
  8. package/dist/chunk-2AAOF5B5.js +28 -0
  9. package/dist/chunk-2AAOF5B5.js.map +1 -0
  10. package/dist/{chunk-CAGOB2N4.js → chunk-4AS7LKKQ.js} +6 -4
  11. package/dist/chunk-4AS7LKKQ.js.map +1 -0
  12. package/dist/chunk-525CAZPY.js +120 -0
  13. package/dist/chunk-525CAZPY.js.map +1 -0
  14. package/dist/{chunk-URLQAXTR.js → chunk-56SIEMDX.js} +2 -2
  15. package/dist/chunk-56SIEMDX.js.map +1 -0
  16. package/dist/{chunk-XIFFTATU.js → chunk-5YHTKWJN.js} +5420 -4031
  17. package/dist/chunk-5YHTKWJN.js.map +1 -0
  18. package/dist/chunk-62QL5QUP.js +283 -0
  19. package/dist/chunk-62QL5QUP.js.map +1 -0
  20. package/dist/{chunk-KWHQ2XXL.js → chunk-67UZEWWF.js} +3 -3
  21. package/dist/chunk-67UZEWWF.js.map +1 -0
  22. package/dist/chunk-6OQQOMZR.js +785 -0
  23. package/dist/chunk-6OQQOMZR.js.map +1 -0
  24. package/dist/{chunk-GTVB4HEM.js → chunk-AQEQX4FF.js} +344 -315
  25. package/dist/chunk-AQEQX4FF.js.map +1 -0
  26. package/dist/chunk-C7ADUNPR.js +273 -0
  27. package/dist/chunk-C7ADUNPR.js.map +1 -0
  28. package/dist/{chunk-E75IPST5.js → chunk-EFJ2NH6E.js} +12 -58
  29. package/dist/chunk-EFJ2NH6E.js.map +1 -0
  30. package/dist/{chunk-5KLVH3PY.js → chunk-HQI7NYGX.js} +5 -3
  31. package/dist/chunk-HQI7NYGX.js.map +1 -0
  32. package/dist/chunk-IME7R2UI.js +6541 -0
  33. package/dist/chunk-IME7R2UI.js.map +1 -0
  34. package/dist/chunk-J4F2QLM2.js +273 -0
  35. package/dist/chunk-J4F2QLM2.js.map +1 -0
  36. package/dist/{chunk-MAQXCUR4.js → chunk-J62VZYOB.js} +444 -112
  37. package/dist/chunk-J62VZYOB.js.map +1 -0
  38. package/dist/chunk-JTPOI3KU.js +826 -0
  39. package/dist/chunk-JTPOI3KU.js.map +1 -0
  40. package/dist/{chunk-WKBO5R4O.js → chunk-KBQS35OV.js} +2 -2
  41. package/dist/chunk-KBQS35OV.js.map +1 -0
  42. package/dist/chunk-KXAYUIKP.js +90 -0
  43. package/dist/chunk-KXAYUIKP.js.map +1 -0
  44. package/dist/{chunk-VZQXX3WW.js → chunk-QYBD22H5.js} +1 -1
  45. package/dist/chunk-QYBD22H5.js.map +1 -0
  46. package/dist/{chunk-V4BOYR52.js → chunk-RFJ6Q6LE.js} +763 -198
  47. package/dist/chunk-RFJ6Q6LE.js.map +1 -0
  48. package/dist/{chunk-7N4J557C.js → chunk-RT5SATF7.js} +1 -1
  49. package/dist/chunk-RT5SATF7.js.map +1 -0
  50. package/dist/{chunk-C7D4NJ2D.js → chunk-S4JMID4G.js} +68 -26
  51. package/dist/chunk-S4JMID4G.js.map +1 -0
  52. package/dist/{chunk-ANSJPYGI.js → chunk-SOW4WRQP.js} +3 -3
  53. package/dist/chunk-SOW4WRQP.js.map +1 -0
  54. package/dist/{chunk-J7MIZ5CA.js → chunk-TLX3H2CL.js} +518 -79
  55. package/dist/chunk-TLX3H2CL.js.map +1 -0
  56. package/dist/{chunk-DGMQEI6Y.js → chunk-VPNLCMVR.js} +22 -9
  57. package/dist/chunk-VPNLCMVR.js.map +1 -0
  58. package/dist/{chunk-BTZZUCLI.js → chunk-W3XFHEF4.js} +173 -29
  59. package/dist/chunk-W3XFHEF4.js.map +1 -0
  60. package/dist/{chunk-574C6MQR.js → chunk-X4NJT436.js} +130 -60
  61. package/dist/chunk-X4NJT436.js.map +1 -0
  62. package/dist/chunk-X66I2NQO.js +137 -0
  63. package/dist/chunk-X66I2NQO.js.map +1 -0
  64. package/dist/chunk-XHAO3K7I.js +18 -0
  65. package/dist/chunk-XHAO3K7I.js.map +1 -0
  66. package/dist/{chunk-3U5IBM24.js → chunk-Y2VHN7TC.js} +2 -2
  67. package/dist/chunk-Y2VHN7TC.js.map +1 -0
  68. package/dist/chunk-YC6W4EJH.js +947 -0
  69. package/dist/chunk-YC6W4EJH.js.map +1 -0
  70. package/dist/{chunk-24AXE6SP.js → chunk-ZPSZZUWF.js} +1 -1
  71. package/dist/chunk-ZPSZZUWF.js.map +1 -0
  72. package/dist/{command-approvals-6Y57VCWZ.js → command-approvals-VBIU6BLM.js} +6 -5
  73. package/dist/context-CBOBDY5Q.js +38 -0
  74. package/dist/{hook-approvals-CTUFKEJT.js → hook-approvals-ZVT4V7IM.js} +5 -5
  75. package/dist/index.js +996 -155
  76. package/dist/index.js.map +1 -1
  77. package/dist/{interactive-assets-CCAAWVKH.js → interactive-assets-T4I4SEHU.js} +13 -9
  78. package/dist/interactive-assets-T4I4SEHU.js.map +1 -0
  79. package/dist/job-runner.js +159 -111
  80. package/dist/job-runner.js.map +1 -1
  81. package/dist/job-supervisor.d.ts +2 -0
  82. package/dist/job-supervisor.js +112 -0
  83. package/dist/job-supervisor.js.map +1 -0
  84. package/dist/loader-S77OVTHH.js +18 -0
  85. package/dist/{mcp-approvals-WNPH65BK.js → mcp-approvals-HJ2VDYMC.js} +5 -5
  86. package/dist/{mcp-config-YIJIES2C.js → mcp-config-RNB5LEVE.js} +3 -3
  87. package/dist/memory-store-DZUT5HUH.js +75 -0
  88. package/dist/{model-window-store-YFVNXCIP.js → model-window-store-MTSQ5JDJ.js} +8 -4
  89. package/dist/openai-compatible-2OB54YST.js +14 -0
  90. package/dist/{permission-approvals-76PVREFD.js → permission-approvals-YLV6UC5W.js} +5 -5
  91. package/dist/permissions-DHOKF3W2.js +45 -0
  92. package/dist/sandbox-WRYTZH3D.js +41 -0
  93. package/dist/{scrollback-LUKLIBVI.js → scrollback-35ME2GFX.js} +32 -22
  94. package/dist/scrollback-35ME2GFX.js.map +1 -0
  95. package/dist/sdk.d.ts +2219 -2361
  96. package/dist/sdk.js +53 -38
  97. package/dist/sdk.js.map +1 -1
  98. package/dist/settings-loader-JUNPGAAM.js +35 -0
  99. package/dist/settings-loader-JUNPGAAM.js.map +1 -0
  100. package/dist/{shell-selection-V6QAYXPX.js → shell-selection-CDHGJ4GC.js} +2 -2
  101. package/dist/shell-selection-CDHGJ4GC.js.map +1 -0
  102. package/package.json +23 -22
  103. package/dist/app-MOXXWEOY.js.map +0 -1
  104. package/dist/chunk-24AXE6SP.js.map +0 -1
  105. package/dist/chunk-3U5IBM24.js.map +0 -1
  106. package/dist/chunk-574C6MQR.js.map +0 -1
  107. package/dist/chunk-5GDZ22YP.js.map +0 -1
  108. package/dist/chunk-5KLVH3PY.js.map +0 -1
  109. package/dist/chunk-7N4J557C.js.map +0 -1
  110. package/dist/chunk-A7JLBK2Y.js +0 -3506
  111. package/dist/chunk-A7JLBK2Y.js.map +0 -1
  112. package/dist/chunk-ANSJPYGI.js.map +0 -1
  113. package/dist/chunk-BTZZUCLI.js.map +0 -1
  114. package/dist/chunk-C7D4NJ2D.js.map +0 -1
  115. package/dist/chunk-CAGOB2N4.js.map +0 -1
  116. package/dist/chunk-DGMQEI6Y.js.map +0 -1
  117. package/dist/chunk-E75IPST5.js.map +0 -1
  118. package/dist/chunk-EYGD6X2T.js +0 -180
  119. package/dist/chunk-EYGD6X2T.js.map +0 -1
  120. package/dist/chunk-GTVB4HEM.js.map +0 -1
  121. package/dist/chunk-J7MIZ5CA.js.map +0 -1
  122. package/dist/chunk-KWHQ2XXL.js.map +0 -1
  123. package/dist/chunk-L6LK2QIQ.js +0 -657
  124. package/dist/chunk-L6LK2QIQ.js.map +0 -1
  125. package/dist/chunk-MAQXCUR4.js.map +0 -1
  126. package/dist/chunk-S4XL7HOM.js +0 -402
  127. package/dist/chunk-S4XL7HOM.js.map +0 -1
  128. package/dist/chunk-URLQAXTR.js.map +0 -1
  129. package/dist/chunk-V4BOYR52.js.map +0 -1
  130. package/dist/chunk-VZQXX3WW.js.map +0 -1
  131. package/dist/chunk-WKBO5R4O.js.map +0 -1
  132. package/dist/chunk-XIFFTATU.js.map +0 -1
  133. package/dist/context-ZC5IFEAX.js +0 -25
  134. package/dist/interactive-assets-CCAAWVKH.js.map +0 -1
  135. package/dist/loader-4IDS2RIE.js +0 -15
  136. package/dist/openai-compatible-RHZUBHV6.js +0 -10
  137. package/dist/permissions-CHCKTFQQ.js +0 -28
  138. package/dist/sandbox-CNVAQDA7.js +0 -23
  139. package/dist/scrollback-LUKLIBVI.js.map +0 -1
  140. package/dist/settings-loader-M2QP5TX2.js +0 -21
  141. package/patches/ink+6.8.0.patch +0 -13
  142. package/scripts/apply-ink-patch.mjs +0 -29
  143. package/scripts/ink-patch.mjs +0 -59
  144. package/scripts/verify-ink-patch.mjs +0 -11
  145. /package/dist/{command-approvals-6Y57VCWZ.js.map → additional-roots-H7UNAEHS.js.map} +0 -0
  146. /package/dist/{context-ZC5IFEAX.js.map → command-approvals-VBIU6BLM.js.map} +0 -0
  147. /package/dist/{hook-approvals-CTUFKEJT.js.map → context-CBOBDY5Q.js.map} +0 -0
  148. /package/dist/{loader-4IDS2RIE.js.map → hook-approvals-ZVT4V7IM.js.map} +0 -0
  149. /package/dist/{mcp-approvals-WNPH65BK.js.map → loader-S77OVTHH.js.map} +0 -0
  150. /package/dist/{mcp-config-YIJIES2C.js.map → mcp-approvals-HJ2VDYMC.js.map} +0 -0
  151. /package/dist/{model-window-store-YFVNXCIP.js.map → mcp-config-RNB5LEVE.js.map} +0 -0
  152. /package/dist/{openai-compatible-RHZUBHV6.js.map → memory-store-DZUT5HUH.js.map} +0 -0
  153. /package/dist/{permission-approvals-76PVREFD.js.map → model-window-store-MTSQ5JDJ.js.map} +0 -0
  154. /package/dist/{permissions-CHCKTFQQ.js.map → openai-compatible-2OB54YST.js.map} +0 -0
  155. /package/dist/{sandbox-CNVAQDA7.js.map → permission-approvals-YLV6UC5W.js.map} +0 -0
  156. /package/dist/{settings-loader-M2QP5TX2.js.map → permissions-DHOKF3W2.js.map} +0 -0
  157. /package/dist/{shell-selection-V6QAYXPX.js.map → sandbox-WRYTZH3D.js.map} +0 -0
@@ -1,289 +1,101 @@
1
+ import {
2
+ escapeInvisibleCharacters
3
+ } from "./chunk-2AAOF5B5.js";
1
4
  import {
2
5
  systemClock
3
- } from "./chunk-7N4J557C.js";
4
-
5
- // src/debug-log.ts
6
+ } from "./chunk-RT5SATF7.js";
6
7
  import {
7
- appendFileSync,
8
- existsSync,
9
- mkdirSync,
10
- readdirSync,
11
- renameSync,
12
- statSync,
13
- unlinkSync
14
- } from "fs";
15
- import { dirname, join } from "path";
16
- var DEBUG_ENABLED = process.env.BOOK_DEBUG === "1";
17
- var UI_DEBUG_ENABLED = process.env.BOOK_DEBUG_UI === "1" || DEBUG_ENABLED;
18
- var RENDER_DEBUG_ENABLED = process.env.BOOK_DEBUG_RENDER === "1";
19
- var FLOW_DEBUG_ENABLED = process.env.BOOK_DEBUG_FLOW === "1";
20
- var debugLogPath;
21
- var debugLogSizes = /* @__PURE__ */ new Map();
22
- var DEFAULT_DEBUG_LOG_MAX_BYTES = 5 * 1024 * 1024;
23
- var MIN_DEBUG_LOG_MAX_BYTES = 4;
24
- var DEFAULT_DEBUG_LOG_BACKUPS = 3;
25
- var DEFAULT_LOCAL_DATA_RETENTION_DAYS = 30;
26
- function positiveInteger(value, fallback) {
27
- const parsed = Number(value);
28
- return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;
29
- }
30
- function debugLogMaxBytes() {
31
- return Math.max(
32
- MIN_DEBUG_LOG_MAX_BYTES,
33
- positiveInteger(process.env.BOOK_DEBUG_MAX_BYTES, DEFAULT_DEBUG_LOG_MAX_BYTES)
34
- );
8
+ createDebugLogger,
9
+ isDebugEnabled
10
+ } from "./chunk-62QL5QUP.js";
11
+
12
+ // src/provider/reliability.ts
13
+ function classifyHttpStatus(status) {
14
+ if (status === 413) return { code: "context_overflow", retryable: false };
15
+ if (status === 429) return { code: "rate_limited", retryable: true };
16
+ if (status === 529) return { code: "overloaded", retryable: true };
17
+ if (status >= 500 && status < 600) return { code: "server_error", retryable: true };
18
+ if (status === 408) return { code: "timeout", retryable: true };
19
+ if (status === 401 || status === 403) return { code: "auth", retryable: false };
20
+ if (status === 402) return { code: "quota", retryable: false };
21
+ if (status === 400) return { code: "bad_request", retryable: false };
22
+ if (status === 404) return { code: "not_found", retryable: false };
23
+ if (status === 422) return { code: "unprocessable", retryable: false };
24
+ return { code: "unknown", retryable: false };
35
25
  }
36
- function rotateDebugLog(target, incomingBytes) {
37
- if (!existsSync(target)) {
38
- debugLogSizes.set(target, 0);
39
- return;
26
+ var CAPACITY_OUTAGE_404 = /no\s+(?:endpoints|accounts)\s+found/i;
27
+ var RESET_AFTER = /\(reset after\s*[^)]+\)/i;
28
+ function quotedUpstreamStatus(body) {
29
+ if (!body) return void 0;
30
+ const text = body.length > 65536 ? body.slice(0, 65536) : body;
31
+ const patterns = [
32
+ /\[[^\]\s]+\]\s*\[(4\d\d)\]:/,
33
+ /"error"\s*:\s*\{[^{}]*?"code"\s*:\s*"?(4\d\d)(?![\d.])/
34
+ ];
35
+ const capacityOutage = CAPACITY_OUTAGE_404.test(text) && RESET_AFTER.test(text);
36
+ if (capacityOutage) return void 0;
37
+ for (const pattern of patterns) {
38
+ const match = text.match(pattern);
39
+ if (match) return Number(match[1]);
40
40
  }
41
- const maxBytes = debugLogMaxBytes();
42
- const currentBytes = debugLogSizes.get(target) ?? statSync(target).size;
43
- debugLogSizes.set(target, currentBytes);
44
- if (currentBytes + incomingBytes <= maxBytes) return;
45
- const backups = positiveInteger(process.env.BOOK_DEBUG_BACKUPS, DEFAULT_DEBUG_LOG_BACKUPS);
46
- const oldest = `${target}.${backups}`;
47
- if (existsSync(oldest)) unlinkSync(oldest);
48
- for (let index = backups - 1; index >= 1; index--) {
49
- const source = `${target}.${index}`;
50
- if (existsSync(source)) renameSync(source, `${target}.${index + 1}`);
51
- }
52
- renameSync(target, `${target}.1`);
53
- debugLogSizes.set(target, 0);
54
- }
55
- function defaultDebugLogPath() {
56
- return join(process.env.BOOK_WORKSPACE || process.cwd(), ".book", "debug.log");
57
- }
58
- function getDebugLogPath() {
59
- if (process.env.BOOK_DEBUG_STDERR === "1") return void 0;
60
- if (process.env.BOOK_DEBUG_FILE) return process.env.BOOK_DEBUG_FILE;
61
- if (process.stderr.isTTY) return defaultDebugLogPath();
62
41
  return void 0;
63
42
  }
64
- function cleanupDebugLogs(days = DEFAULT_LOCAL_DATA_RETENTION_DAYS, target = getDebugLogPath(), now = Date.now()) {
65
- if (!target) return 0;
66
- const cutoff = now - Math.max(1, days) * 864e5;
67
- const directory = dirname(target);
68
- const prefix = `${target.split(/[\\/]/).pop()}.`;
69
- let removed = 0;
43
+ function wrappedUpstreamStatus(status, body) {
44
+ return classifyHttpStatus(status).retryable ? quotedUpstreamStatus(body) : void 0;
45
+ }
46
+ var CONTEXT_OVERFLOW_ERROR_NAMES = /* @__PURE__ */ new Set([
47
+ "context_length_exceeded",
48
+ "request_too_large",
49
+ // llama.cpp's server.
50
+ "exceed_context_size_error"
51
+ ]);
52
+ function errorBodyParts(body) {
53
+ let parsedJson;
70
54
  try {
71
- for (const entry of readdirSync(directory, { withFileTypes: true })) {
72
- if (!entry.isFile() || !entry.name.startsWith(prefix)) continue;
73
- const path = join(directory, entry.name);
74
- if (statSync(path).mtimeMs >= cutoff) continue;
75
- unlinkSync(path);
76
- debugLogSizes.delete(path);
77
- removed++;
78
- }
55
+ parsedJson = JSON.parse(body);
79
56
  } catch {
80
- }
81
- return removed;
82
- }
83
- function writeDebugLine(line) {
84
- const target = debugLogPath ?? (debugLogPath = getDebugLogPath());
85
- if (!target) {
86
- process.stderr.write(line);
87
- return;
88
- }
89
- try {
90
- mkdirSync(dirname(target), { recursive: true });
91
- const lineBytes = Buffer.byteLength(line);
92
- rotateDebugLog(target, lineBytes);
93
- appendFileSync(target, line, "utf8");
94
- debugLogSizes.set(target, (debugLogSizes.get(target) ?? 0) + lineBytes);
95
- } catch {
96
- process.stderr.write(line);
97
- }
98
- }
99
- function writeSizeBoundedDebugLine(line, maxBytes) {
100
- if (Buffer.byteLength(line) <= maxBytes) {
101
- writeDebugLine(line);
102
- return;
103
- }
104
- let chunk = "";
105
- let chunkBytes = 0;
106
- for (const character of line) {
107
- const characterBytes = Buffer.byteLength(character);
108
- if (chunk && chunkBytes + characterBytes > maxBytes) {
109
- writeDebugLine(chunk);
110
- chunk = "";
111
- chunkBytes = 0;
112
- }
113
- chunk += character;
114
- chunkBytes += characterBytes;
115
- }
116
- if (chunk) writeDebugLine(chunk);
117
- }
118
- var pendingRenderDebug = [];
119
- var renderDebugFlush = null;
120
- function writeRenderDebugLine(line) {
121
- pendingRenderDebug.push(line);
122
- if (renderDebugFlush !== null) return;
123
- renderDebugFlush = setImmediate(() => {
124
- renderDebugFlush = null;
125
- const batch = pendingRenderDebug;
126
- pendingRenderDebug = [];
127
- const maxBytes = debugLogMaxBytes();
128
- let chunk = "";
129
- let chunkBytes = 0;
130
- for (const pendingLine of batch) {
131
- const lineBytes = Buffer.byteLength(pendingLine);
132
- if (chunk && chunkBytes + lineBytes > maxBytes) {
133
- writeDebugLine(chunk);
134
- chunk = "";
135
- chunkBytes = 0;
136
- }
137
- if (lineBytes > maxBytes) {
138
- writeSizeBoundedDebugLine(pendingLine, maxBytes);
139
- continue;
140
- }
141
- chunk += pendingLine;
142
- chunkBytes += lineBytes;
57
+ const reachedCap = new TextEncoder().encode(body).byteLength >= ERROR_BODY_MAX_BYTES - 3;
58
+ if (!reachedCap || !/^\s*(?:\{|\[\s*\{)/.test(body)) {
59
+ return { message: body, names: [], parsed: false };
143
60
  }
144
- if (chunk) writeDebugLine(chunk);
145
- });
146
- }
147
- var namespaceCounters = /* @__PURE__ */ new Map();
148
- function nextEventId(namespace) {
149
- const n = (namespaceCounters.get(namespace) ?? 0) + 1;
150
- namespaceCounters.set(namespace, n);
151
- return n;
152
- }
153
- function isUiDebugEnabled() {
154
- return UI_DEBUG_ENABLED;
155
- }
156
- function isRenderDebugEnabled() {
157
- return RENDER_DEBUG_ENABLED;
158
- }
159
- function timestamp() {
160
- const now = /* @__PURE__ */ new Date();
161
- const h = String(now.getHours()).padStart(2, "0");
162
- const m = String(now.getMinutes()).padStart(2, "0");
163
- const s = String(now.getSeconds()).padStart(2, "0");
164
- const ms = String(now.getMilliseconds()).padStart(3, "0");
165
- return `${h}:${m}:${s}.${ms}`;
166
- }
167
- function truncate(value, max = 80) {
168
- const single = value.replace(/\s+/g, " ").trim();
169
- if (single.length <= max) return single;
170
- return `${single.slice(0, max)}\u2026`;
171
- }
172
- function formatValue(a) {
173
- if (typeof a === "string") return a;
174
- if (a instanceof Error) return a.message;
175
- try {
176
- return JSON.stringify(a);
177
- } catch {
178
- return String(a);
179
- }
180
- }
181
- function formatMessage(...args) {
182
- return args.map(formatValue).join(" ");
183
- }
184
- function formatMeta(meta) {
185
- const parts = [];
186
- for (const [key, value] of Object.entries(meta)) {
187
- let repr;
188
- if (typeof value === "string") {
189
- repr = truncate(value, 120);
190
- } else if (value === null) {
191
- repr = "null";
192
- } else if (value === void 0) {
193
- repr = "undefined";
194
- } else {
61
+ const readString = (key) => {
62
+ const match = body.match(new RegExp(`"${key}"\\s*:\\s*"((?:[^"\\\\]|\\\\.)*)"`));
63
+ if (!match) return "";
195
64
  try {
196
- repr = JSON.stringify(value);
65
+ return JSON.parse(`"${match[1]}"`);
197
66
  } catch {
198
- repr = String(value);
67
+ return "";
199
68
  }
200
- }
201
- parts.push(`${key}=${repr}`);
69
+ };
70
+ const message2 = readString("message") || readString("error") || readString("detail");
71
+ const names = [body.match(/"code"\s*:\s*"([^"]*)"/), body.match(/"type"\s*:\s*"([^"]*)"/)].filter((name) => name !== null).map((name) => name[1]);
72
+ return { message: message2, names, parsed: true };
202
73
  }
203
- return parts.join(" ");
204
- }
205
- function noop() {
206
- }
207
- var NOOP_LOGGER = {
208
- debug: noop,
209
- info: noop,
210
- warn: noop,
211
- event: noop
212
- };
213
- function makePrefix(namespace, level) {
214
- return `[${timestamp()}] [${namespace}] [${level}]`;
215
- }
216
- function buildLogger(namespace, write = writeDebugLine) {
74
+ const root = Array.isArray(parsedJson) ? parsedJson[0] : parsedJson;
75
+ if (typeof root !== "object" || root === null) {
76
+ return { message: body, names: [], parsed: false };
77
+ }
78
+ const error = root.error;
79
+ if (typeof error === "string") return { message: error, names: [], parsed: true };
80
+ const source = typeof error === "object" && error !== null ? error : root;
81
+ const fallback = root.detail;
82
+ const message = typeof source.message === "string" ? source.message : typeof fallback === "string" ? fallback : "";
83
+ const metadata = source.metadata;
84
+ const raw = metadata?.raw;
217
85
  return {
218
- debug: (...args) => {
219
- write(`${makePrefix(namespace, "DEBUG")} ${formatMessage(...args)}
220
- `);
221
- },
222
- info: (...args) => {
223
- write(`${makePrefix(namespace, "INFO")} ${formatMessage(...args)}
224
- `);
225
- },
226
- warn: (...args) => {
227
- write(`${makePrefix(namespace, "WARN")} ${formatMessage(...args)}
228
- `);
229
- },
230
- event: (event, meta) => {
231
- const suffix = meta && Object.keys(meta).length > 0 ? ` ${formatMeta(meta)}` : "";
232
- write(`${makePrefix(namespace, "DEBUG")} ${event}${suffix}
233
- `);
234
- }
86
+ message,
87
+ names: [source.code, source.type].filter((name) => typeof name === "string"),
88
+ raw: typeof raw === "string" ? raw : typeof raw === "object" && raw !== null ? JSON.stringify(raw) : void 0,
89
+ parsed: true
235
90
  };
236
91
  }
237
- function createDebugLogger(namespace) {
238
- if (!DEBUG_ENABLED) return NOOP_LOGGER;
239
- return buildLogger(namespace);
240
- }
241
- function createDebugLoggerWithCounter(namespace) {
242
- if (!DEBUG_ENABLED) return NOOP_LOGGER;
243
- const wrap = (level) => (...args) => {
244
- const id = nextEventId(namespace);
245
- writeDebugLine(
246
- `[${timestamp()}] [${namespace}] [${level.toUpperCase()}#${id}] ${formatMessage(...args)}
247
- `
248
- );
249
- };
250
- return {
251
- debug: wrap("debug"),
252
- info: wrap("info"),
253
- warn: wrap("warn"),
254
- event: (event, meta) => {
255
- const id = nextEventId(namespace);
256
- const suffix = meta && Object.keys(meta).length > 0 ? ` ${formatMeta(meta)}` : "";
257
- writeDebugLine(`[${timestamp()}] [${namespace}] [DEBUG#${id}] ${event}${suffix}
258
- `);
259
- }
260
- };
261
- }
262
- function createUiDebugLogger(namespace) {
263
- if (!UI_DEBUG_ENABLED) return NOOP_LOGGER;
264
- return buildLogger(namespace);
265
- }
266
- function createRenderDebugLogger(namespace) {
267
- if (!RENDER_DEBUG_ENABLED) return NOOP_LOGGER;
268
- return buildLogger(namespace, writeRenderDebugLine);
269
- }
270
-
271
- // src/provider/reliability.ts
272
- function classifyHttpStatus(status) {
273
- if (status === 413) return { code: "context_overflow", retryable: false };
274
- if (status === 429) return { code: "rate_limited", retryable: true };
275
- if (status === 529) return { code: "overloaded", retryable: true };
276
- if (status >= 500 && status < 600) return { code: "server_error", retryable: true };
277
- if (status === 408) return { code: "timeout", retryable: true };
278
- if (status === 401 || status === 403) return { code: "auth", retryable: false };
279
- if (status === 402) return { code: "quota", retryable: false };
280
- if (status === 400) return { code: "bad_request", retryable: false };
281
- if (status === 404) return { code: "not_found", retryable: false };
282
- return { code: "unknown", retryable: false };
92
+ function statesContextOverflow(body) {
93
+ const { message, names, raw } = errorBodyParts(body);
94
+ return names.some((name) => CONTEXT_OVERFLOW_ERROR_NAMES.has(name.toLowerCase())) || isContextOverflowError(message) || raw !== void 0 && statesContextOverflow(raw);
283
95
  }
284
96
  function classifyApiError(status, body) {
285
- const code = classifyHttpStatus(status).code;
286
- return code === "bad_request" && isContextOverflowError(body) ? "context_overflow" : code;
97
+ const code = classifyHttpStatus(wrappedUpstreamStatus(status, body) ?? status).code;
98
+ return code === "bad_request" && statesContextOverflow(body) ? "context_overflow" : code;
287
99
  }
288
100
  function classifyProviderError(error) {
289
101
  if (error instanceof DOMException && error.name === "TimeoutError") return "timeout";
@@ -300,7 +112,7 @@ function formatApiError(status, body) {
300
112
  case "context_overflow":
301
113
  return `${base} ${detail || "Input exceeds the model context window."} Reduce the conversation or tool output and try again.`;
302
114
  case "rate_limited":
303
- return `${base} ${detail}. This may be a temporary capacity issue. Try again in a moment.`;
115
+ return isOversizedForRateLimit(detail) ? `${base} ${detail}. The request is larger than the rate limit allows at once, so it has to shrink; waiting will not help.` : `${base} ${detail}. This may be a temporary capacity issue. Try again in a moment.`;
304
116
  case "overloaded":
305
117
  return `${base} Repeated 529 Overloaded errors. The API is at capacity \u2014 this is usually temporary. Try again in a moment.`;
306
118
  case "server_error":
@@ -317,10 +129,80 @@ function formatApiError(status, body) {
317
129
  }
318
130
  function isContextOverflowError(error) {
319
131
  const normalized = (error instanceof Error ? error.message : String(error)).toLowerCase();
320
- return /\b(?:api error:\s*)?413\b/.test(normalized) || normalized.includes("request entity too large") || normalized.includes("payload too large") || normalized.includes("request too large") || normalized.includes("context_length_exceeded") || normalized.includes("maximum context length") || normalized.includes("context window") || normalized.includes("prompt too long") || /prompt\s+is\s+too\s+long/.test(normalized) || /input\s+(?:is\s+)?too\s+long/.test(normalized) || normalized.includes("too many tokens") || /input\s+(?:token\s+count\s+)?exceeds?.*(?:context|limit|maximum)/.test(normalized) || /input\s+exceeds?.*(?:context\s+window|context\s+length|token\s+limit)/.test(normalized) || /maximum\s+context|context\s+(?:length|window|size).*(?:exceed|overflow|too\s+(?:long|large)|maximum)/.test(
132
+ return /\b(?:api\s+error|http|(?:error|status)(?:\s+code)?)\s*:?\s*413\b/.test(normalized) || normalized.includes("request entity too large") || normalized.includes("payload too large") || normalized.includes("request too large") || normalized.includes("context_length_exceeded") || normalized.includes("maximum context length") || normalized.includes("context window") || normalized.includes("prompt too long") || /prompt\s+is\s+too\s+long/.test(normalized) || /input\s+(?:is\s+)?too\s+long/.test(normalized) || normalized.includes("too many tokens") || // Gemini names the count: `The input token count (1196266) exceeds the maximum …`.
133
+ /input\s+(?:token\s+count\s+)?(?:\(\d+\)\s+)?exceeds?.*(?:context|limit|maximum)/.test(
134
+ normalized
135
+ ) || /input\s+exceeds?.*(?:context\s+window|context\s+length|token\s+limit)/.test(normalized) || /maximum\s+context|context\s+(?:length|window|size).*(?:exceed|overflow|too\s+(?:long|large)|maximum)/.test(
321
136
  normalized
322
137
  ) || /too\s+many\s+(?:input\s+)?tokens|request\s+too\s+large.*token/.test(normalized);
323
138
  }
139
+ function isOversizedForRateLimit(text) {
140
+ if (!/\brequest too large\b/i.test(text)) return false;
141
+ const limit = text.match(/\blimit:?\s*(\d+)/i);
142
+ const requested = text.match(/\brequested:?\s*(\d+)/i);
143
+ return !limit || !requested || Number(requested[1]) > Number(limit[1]);
144
+ }
145
+ function statedRateLimit(text) {
146
+ if (!isOversizedForRateLimit(text)) return void 0;
147
+ const limit = text.match(/\blimit:?\s*(\d+)/i);
148
+ return limit ? Number(limit[1]) : void 0;
149
+ }
150
+ var ERROR_ENVELOPE_MAX_CHARS = 2e3;
151
+ function isZeroUsage(usage) {
152
+ return usage != null && usage.promptTokens === 0 && usage.completionTokens === 0 && (usage.cacheReadInputTokens ?? 0) === 0 && (usage.cacheCreationInputTokens ?? 0) === 0;
153
+ }
154
+ function isErrorEnvelopeShape(text, usage) {
155
+ if (isZeroUsage(usage)) return /^\s*\[Error\]/i.test(text);
156
+ const trimmed = text.trim();
157
+ return trimmed.length <= ERROR_ENVELOPE_MAX_CHARS && /^\[Error\]/i.test(trimmed) && !/[\r\n]/.test(trimmed);
158
+ }
159
+ function isUpstreamErrorEnvelope(text, usage) {
160
+ if (!isErrorEnvelopeShape(text, usage)) return false;
161
+ return isZeroUsage(usage) || /\brequest id\b/i.test(text) || /help\.openai\.com/i.test(text) || /error occurred while processing/i.test(text);
162
+ }
163
+ var ERROR_BODY_READ_TIMEOUT_MS = 5e3;
164
+ var ERROR_BODY_MAX_BYTES = 65536;
165
+ async function readErrorBody(response, signal) {
166
+ if (signal?.aborted || !response.body) return "";
167
+ let reader;
168
+ try {
169
+ reader = response.body.getReader();
170
+ } catch {
171
+ return "";
172
+ }
173
+ const decoder = new TextDecoder();
174
+ let text = "";
175
+ let received = 0;
176
+ let finished = false;
177
+ const stop = () => {
178
+ reader.cancel().catch(() => {
179
+ });
180
+ };
181
+ const timer = setTimeout(stop, ERROR_BODY_READ_TIMEOUT_MS);
182
+ signal?.addEventListener("abort", stop, { once: true });
183
+ try {
184
+ while (received < ERROR_BODY_MAX_BYTES) {
185
+ const chunk = await reader.read();
186
+ if (chunk.done) {
187
+ finished = true;
188
+ break;
189
+ }
190
+ const bytes = chunk.value.subarray(0, ERROR_BODY_MAX_BYTES - received);
191
+ received += bytes.byteLength;
192
+ text += decoder.decode(bytes, { stream: true });
193
+ }
194
+ } catch {
195
+ } finally {
196
+ clearTimeout(timer);
197
+ signal?.removeEventListener("abort", stop);
198
+ if (!finished) stop();
199
+ try {
200
+ reader.releaseLock();
201
+ } catch {
202
+ }
203
+ }
204
+ return text + decoder.decode();
205
+ }
324
206
  async function fetchWithRetry(url, init, retry, signal, onRetry, logger, clock = systemClock) {
325
207
  const startMs = clock.monotonicNowMs();
326
208
  const maxAttempts = retry.watchdog ? Number.MAX_SAFE_INTEGER : retry.maxAttempts;
@@ -341,20 +223,48 @@ async function fetchWithRetry(url, init, retry, signal, onRetry, logger, clock =
341
223
  delayMs: delay2,
342
224
  error: lastError
343
225
  });
344
- onRetry?.(attempt + 1, maxAttempts > 100 ? -1 : maxAttempts, delay2);
226
+ onRetry?.(attempt + 1, maxAttempts === Number.MAX_SAFE_INTEGER ? -1 : maxAttempts, delay2);
345
227
  await sleep(delay2, signal);
346
228
  continue;
347
229
  }
348
230
  const classification = classifyHttpStatus(response.status);
349
231
  if (!classification.retryable) return response;
350
232
  lastError = `API error ${response.status}`;
233
+ const bodyText = await readErrorBody(response, signal);
234
+ const quoted = quotedUpstreamStatus(bodyText);
235
+ if (quoted !== void 0 && !classifyHttpStatus(quoted).retryable) {
236
+ logger?.warn("upstream error quoted in retryable status; not retrying", {
237
+ status: response.status,
238
+ upstreamStatus: quoted
239
+ });
240
+ return new Response(bodyText, {
241
+ status: response.status,
242
+ statusText: response.statusText,
243
+ headers: response.headers
244
+ });
245
+ }
246
+ if ((quoted ?? response.status) === 429 && isOversizedForRateLimit(formatApiError(response.status, bodyText))) {
247
+ logger?.warn("rate limit on a request too large to ever fit; not retrying", {
248
+ status: response.status
249
+ });
250
+ return new Response(bodyText, {
251
+ status: response.status,
252
+ statusText: response.statusText,
253
+ headers: response.headers
254
+ });
255
+ }
351
256
  const watchdogRetry = retry.watchdog && (response.status === 429 || response.status === 529);
352
257
  const effectiveMax = watchdogRetry ? Number.MAX_SAFE_INTEGER : maxAttempts;
353
- if (attempt >= effectiveMax || budgetExhausted(clock, startMs, retry.totalBudgetMs))
354
- return response;
258
+ if (attempt >= effectiveMax || budgetExhausted(clock, startMs, retry.totalBudgetMs)) {
259
+ return new Response(bodyText, {
260
+ status: response.status,
261
+ statusText: response.statusText,
262
+ headers: response.headers
263
+ });
264
+ }
355
265
  const delay = boundedDelay(
356
266
  clock,
357
- backoffMs(attempt, retry, response.headers.get("retry-after")),
267
+ backoffMs(attempt, retry, response.headers.get("retry-after"), bodyText),
358
268
  startMs,
359
269
  retry.totalBudgetMs
360
270
  );
@@ -363,11 +273,15 @@ async function fetchWithRetry(url, init, retry, signal, onRetry, logger, clock =
363
273
  status: response.status,
364
274
  delayMs: delay
365
275
  });
366
- onRetry?.(attempt + 1, watchdogRetry ? -1 : maxAttempts, delay);
276
+ onRetry?.(attempt + 1, effectiveMax === Number.MAX_SAFE_INTEGER ? -1 : effectiveMax, delay);
367
277
  try {
368
278
  await sleep(delay, signal);
369
279
  } catch {
370
- return response;
280
+ return new Response(bodyText, {
281
+ status: response.status,
282
+ statusText: response.statusText,
283
+ headers: response.headers
284
+ });
371
285
  }
372
286
  try {
373
287
  await response.body?.cancel();
@@ -413,11 +327,8 @@ function abortError(signal) {
413
327
  return signal.reason instanceof Error ? signal.reason : new Error("Aborted");
414
328
  }
415
329
  function safeErrorDetail(body) {
416
- try {
417
- const parsed = JSON.parse(body);
418
- if (typeof parsed.error?.message === "string") return parsed.error.message.slice(0, 2e3);
419
- } catch {
420
- }
330
+ const { message, parsed } = errorBodyParts(body);
331
+ if (parsed && message) return message.slice(0, 2e3);
421
332
  return body.slice(0, 200);
422
333
  }
423
334
  function sleep(ms, signal) {
@@ -437,8 +348,8 @@ function sleep(ms, signal) {
437
348
  signal?.addEventListener("abort", onAbort, { once: true });
438
349
  });
439
350
  }
440
- function backoffMs(attempt, retry, retryAfter) {
441
- const retryAfterMs = parseRetryAfter(retryAfter);
351
+ function backoffMs(attempt, retry, retryAfter, body) {
352
+ const retryAfterMs = parseRetryAfter(retryAfter) ?? parseCooldownReset(body);
442
353
  if (retryAfterMs !== void 0) return Math.min(retryAfterMs, retry.maxDelayMs);
443
354
  const exponential = Math.min(retry.baseDelayMs * 2 ** attempt, retry.maxDelayMs);
444
355
  return Math.round(exponential * (0.5 + Math.random()));
@@ -447,9 +358,40 @@ function parseRetryAfter(value) {
447
358
  if (!value) return void 0;
448
359
  const seconds = Number(value);
449
360
  if (Number.isFinite(seconds) && seconds > 0) return seconds * 1e3;
450
- const timestamp2 = Date.parse(value);
451
- if (!Number.isFinite(timestamp2)) return void 0;
452
- return Math.max(0, timestamp2 - Date.now());
361
+ const timestamp = Date.parse(value);
362
+ if (!Number.isFinite(timestamp)) return void 0;
363
+ return Math.max(0, timestamp - Date.now());
364
+ }
365
+ var COOLDOWN_UNIT_MS = {
366
+ ms: 1,
367
+ s: 1e3,
368
+ sec: 1e3,
369
+ secs: 1e3,
370
+ second: 1e3,
371
+ seconds: 1e3,
372
+ m: 6e4,
373
+ min: 6e4,
374
+ mins: 6e4,
375
+ minute: 6e4,
376
+ minutes: 6e4,
377
+ h: 36e5,
378
+ hr: 36e5,
379
+ hrs: 36e5,
380
+ hour: 36e5,
381
+ hours: 36e5
382
+ };
383
+ var COOLDOWN_UNIT = /(\d+)\s*(ms|sec(?:ond)?s?|min(?:ute)?s?|h(?:ours?|rs?)?|s|m)(?![a-z])/gi;
384
+ function parseCooldownReset(body) {
385
+ if (!body) return void 0;
386
+ const stated = body.match(/\(reset after\s*([^)]+)\)/i);
387
+ if (!stated) return void 0;
388
+ let totalMs = 0;
389
+ let statedUnits = 0;
390
+ for (const unit of stated[1].matchAll(COOLDOWN_UNIT)) {
391
+ totalMs += Number(unit[1]) * COOLDOWN_UNIT_MS[unit[2].toLowerCase()];
392
+ statedUnits++;
393
+ }
394
+ return statedUnits > 0 && totalMs > 0 ? totalMs : void 0;
453
395
  }
454
396
  function budgetExhausted(clock, startMs, budgetMs) {
455
397
  return budgetMs > 0 && clock.monotonicNowMs() - startMs >= budgetMs;
@@ -462,12 +404,17 @@ function boundedDelay(clock, delayMs, startMs, budgetMs) {
462
404
  // src/provider/openai-compatible.ts
463
405
  var log = createDebugLogger("provider");
464
406
  function parseToolArguments(raw) {
465
- if (!raw.trim()) return {};
407
+ if (!raw.trim()) return { arguments: {} };
466
408
  try {
467
409
  const parsed = JSON.parse(raw);
468
- return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
469
- } catch {
470
- return { __raw: raw };
410
+ return {
411
+ arguments: parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {}
412
+ };
413
+ } catch (error) {
414
+ return {
415
+ arguments: {},
416
+ unparsedArguments: { raw, error: error instanceof Error ? error.message : String(error) }
417
+ };
471
418
  }
472
419
  }
473
420
  function parseReasoningDelta(delta) {
@@ -502,6 +449,64 @@ function flattenMessages(messages) {
502
449
  ) : reasoningContent ? ["<reasoning_context>", reasoningContent, "</reasoning_context>", msg.content ?? ""].filter(Boolean).join("\n") : msg.content
503
450
  }));
504
451
  }
452
+ function parseCompatibleUsage(raw) {
453
+ if (!raw || typeof raw !== "object") return null;
454
+ const usage = raw;
455
+ const details = usage.prompt_tokens_details && typeof usage.prompt_tokens_details === "object" ? usage.prompt_tokens_details : {};
456
+ const tokens = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
457
+ const firstCount = (...values) => {
458
+ for (const value of values) {
459
+ const count = tokens(value);
460
+ if (count > 0) return count;
461
+ }
462
+ return 0;
463
+ };
464
+ const prompt = tokens(usage.prompt_tokens);
465
+ const base = {
466
+ promptTokens: prompt,
467
+ completionTokens: tokens(usage.completion_tokens),
468
+ // A provider that omits `total_tokens` would otherwise read as zero context pressure.
469
+ totalTokens: tokens(usage.total_tokens) || prompt + tokens(usage.completion_tokens)
470
+ };
471
+ const topRead = tokens(usage.cache_read_input_tokens);
472
+ const topWrite = tokens(usage.cache_creation_input_tokens);
473
+ const normalisedRead = firstCount(
474
+ details.cached_tokens,
475
+ usage.prompt_cache_hit_tokens,
476
+ usage.cached_tokens
477
+ );
478
+ const normalisedWrite = firstCount(
479
+ details.cache_creation_tokens,
480
+ details.cache_write_tokens,
481
+ details.cache_creation_input_tokens
482
+ );
483
+ const read = normalisedRead || topRead;
484
+ const write = normalisedWrite || topWrite;
485
+ if (read === 0 && write === 0) return base;
486
+ const reportsOpenAiCacheField = [
487
+ details.cached_tokens,
488
+ details.cache_creation_tokens,
489
+ details.cache_write_tokens,
490
+ details.cache_creation_input_tokens,
491
+ usage.prompt_cache_hit_tokens,
492
+ usage.cached_tokens
493
+ ].some((value) => typeof value === "number");
494
+ const anthropicPassThrough = !reportsOpenAiCacheField && topRead + topWrite > 0;
495
+ if (!anthropicPassThrough && read + write <= prompt) {
496
+ return {
497
+ ...base,
498
+ promptTokens: prompt - read - write,
499
+ cacheReadInputTokens: read,
500
+ cacheCreationInputTokens: write
501
+ };
502
+ }
503
+ return {
504
+ ...base,
505
+ cacheReadInputTokens: read,
506
+ cacheCreationInputTokens: write,
507
+ contextTokens: prompt + read + write
508
+ };
509
+ }
505
510
  function convertTools(tools) {
506
511
  return tools.map((tool) => ({
507
512
  type: "function",
@@ -570,11 +575,12 @@ async function* chatCompletionStream(config, messages, tools, options) {
570
575
  }
571
576
  log.debug("response received", { status: response.status, ok: response.ok });
572
577
  if (!response.ok) {
573
- const errorText = await response.text();
578
+ const errorText = await readErrorBody(response, signal);
574
579
  yield {
575
580
  type: "error",
576
581
  error: formatApiError(response.status, errorText),
577
- errorCode: classifyApiError(response.status, errorText)
582
+ errorCode: classifyApiError(response.status, errorText),
583
+ upstreamStatus: wrappedUpstreamStatus(response.status, errorText)
578
584
  };
579
585
  return;
580
586
  }
@@ -593,12 +599,24 @@ async function* chatCompletionStream(config, messages, tools, options) {
593
599
  const emitToolCalls = function* () {
594
600
  for (const part of [...toolCallParts].sort((a, b) => a.index - b.index)) {
595
601
  if (!part.id && !part.name) continue;
602
+ const { arguments: arguments_, unparsedArguments } = parseToolArguments(part.arguments);
603
+ if (unparsedArguments) {
604
+ log.warn("tool call arguments are not valid JSON", {
605
+ index: part.index,
606
+ id: part.id,
607
+ name: escapeInvisibleCharacters(part.name),
608
+ fragments: part.fragments,
609
+ length: part.arguments.length,
610
+ head: escapeInvisibleCharacters(part.arguments.slice(0, 120))
611
+ });
612
+ }
596
613
  yield {
597
614
  type: "tool_call",
598
615
  toolCall: {
599
616
  id: part.id || `tool-${part.index}`,
600
617
  name: part.name,
601
- arguments: parseToolArguments(part.arguments)
618
+ arguments: arguments_,
619
+ ...unparsedArguments ? { unparsedArguments } : {}
602
620
  }
603
621
  };
604
622
  }
@@ -609,7 +627,9 @@ async function* chatCompletionStream(config, messages, tools, options) {
609
627
  terminal,
610
628
  promptTokens: currentUsage?.promptTokens ?? 0,
611
629
  completionTokens: currentUsage?.completionTokens ?? 0,
612
- totalTokens: currentUsage?.totalTokens ?? 0
630
+ totalTokens: currentUsage?.totalTokens ?? 0,
631
+ cacheReadInputTokens: currentUsage?.cacheReadInputTokens ?? 0,
632
+ cacheCreationInputTokens: currentUsage?.cacheCreationInputTokens ?? 0
613
633
  });
614
634
  yield {
615
635
  type: "done",
@@ -631,13 +651,8 @@ async function* chatCompletionStream(config, messages, tools, options) {
631
651
  const parsed = JSON.parse(data);
632
652
  if (typeof parsed.model === "string") responseModel = parsed.model;
633
653
  if (typeof parsed.id === "string") responseId = parsed.id;
634
- if (parsed.usage) {
635
- currentUsage = {
636
- promptTokens: parsed.usage.prompt_tokens ?? 0,
637
- completionTokens: parsed.usage.completion_tokens ?? 0,
638
- totalTokens: parsed.usage.total_tokens ?? 0
639
- };
640
- }
654
+ const usage = parseCompatibleUsage(parsed.usage);
655
+ if (usage) currentUsage = usage;
641
656
  const choice = parsed.choices?.[0];
642
657
  if (!choice) return false;
643
658
  const finishReason = choice.finish_reason;
@@ -646,15 +661,19 @@ async function* chatCompletionStream(config, messages, tools, options) {
646
661
  if (!delta) return false;
647
662
  const reasoning = parseReasoningDelta(delta);
648
663
  if (reasoning) {
664
+ if (retry.thinkingStallTimeoutMs) {
665
+ stallTimeoutMs = Math.max(stallTimeoutMs, retry.thinkingStallTimeoutMs);
666
+ }
649
667
  log.debug("stream reasoning", { len: reasoning.length });
650
668
  yield { type: "reasoning", reasoning };
651
669
  }
652
670
  if (delta.content) {
671
+ stallTimeoutMs = startingStallTimeoutMs;
653
672
  log.debug("stream text", { len: delta.content.length });
654
673
  yield { type: "text", content: delta.content };
655
674
  }
656
675
  if (delta.tool_calls) {
657
- log.debug("stream tool_call delta", { count: delta.tool_calls.length });
676
+ stallTimeoutMs = startingStallTimeoutMs;
658
677
  for (const tc of delta.tool_calls) {
659
678
  const explicitIndex = Number.isInteger(tc.index) ? tc.index : void 0;
660
679
  let index = explicitIndex;
@@ -666,19 +685,32 @@ async function* chatCompletionStream(config, messages, tools, options) {
666
685
  }
667
686
  let part = toolCallParts.find((p) => p.index === index);
668
687
  if (!part) {
669
- part = { index, id: "", name: "", arguments: "" };
688
+ part = { index, id: "", name: "", arguments: "", fragments: 0 };
670
689
  toolCallParts.push(part);
671
690
  }
672
691
  if (tc.id) part.id = tc.id;
673
692
  if (tc.function?.name) part.name = tc.function.name;
674
- if (tc.function?.arguments) part.arguments += tc.function.arguments;
693
+ if (tc.function?.arguments) {
694
+ if (part.fragments === 0 && isDebugEnabled()) {
695
+ log.debug("stream tool_call delta", {
696
+ index,
697
+ id: tc.id,
698
+ name: escapeInvisibleCharacters(tc.function.name ?? ""),
699
+ argumentsLength: tc.function.arguments.length,
700
+ argumentsHead: escapeInvisibleCharacters(tc.function.arguments.slice(0, 120))
701
+ });
702
+ }
703
+ part.arguments += tc.function.arguments;
704
+ part.fragments++;
705
+ }
675
706
  }
676
707
  }
677
708
  } catch {
678
709
  }
679
710
  return false;
680
711
  };
681
- const stallTimeoutMs = reasoningEnabled && retry.thinkingStallTimeoutMs ? Math.max(retry.streamStallTimeoutMs, retry.thinkingStallTimeoutMs) : retry.streamStallTimeoutMs;
712
+ const startingStallTimeoutMs = reasoningEnabled && retry.thinkingStallTimeoutMs ? Math.max(retry.streamStallTimeoutMs, retry.thinkingStallTimeoutMs) : retry.streamStallTimeoutMs;
713
+ let stallTimeoutMs = startingStallTimeoutMs;
682
714
  try {
683
715
  while (true) {
684
716
  const result = await readStreamChunk(reader, signal, stallTimeoutMs);
@@ -743,23 +775,20 @@ async function* chatCompletionStream(config, messages, tools, options) {
743
775
  }
744
776
 
745
777
  export {
746
- DEFAULT_LOCAL_DATA_RETENTION_DAYS,
747
- positiveInteger,
748
- getDebugLogPath,
749
- cleanupDebugLogs,
750
- isUiDebugEnabled,
751
- isRenderDebugEnabled,
752
- createDebugLogger,
753
- createDebugLoggerWithCounter,
754
- createUiDebugLogger,
755
- createRenderDebugLogger,
778
+ wrappedUpstreamStatus,
756
779
  classifyApiError,
757
780
  classifyProviderError,
758
781
  formatApiError,
759
782
  isContextOverflowError,
783
+ isOversizedForRateLimit,
784
+ statedRateLimit,
785
+ isErrorEnvelopeShape,
786
+ isUpstreamErrorEnvelope,
787
+ readErrorBody,
760
788
  fetchWithRetry,
761
789
  readStreamChunk,
790
+ parseCompatibleUsage,
762
791
  convertTools,
763
792
  chatCompletionStream
764
793
  };
765
- //# sourceMappingURL=chunk-GTVB4HEM.js.map
794
+ //# sourceMappingURL=chunk-AQEQX4FF.js.map