@earendil-works/pi-ai 0.80.2 → 0.80.5

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 (176) hide show
  1. package/README.md +1 -1
  2. package/dist/api/anthropic-messages.d.ts.map +1 -1
  3. package/dist/api/anthropic-messages.js +13 -4
  4. package/dist/api/anthropic-messages.js.map +1 -1
  5. package/dist/api/azure-openai-responses.d.ts.map +1 -1
  6. package/dist/api/azure-openai-responses.js +14 -18
  7. package/dist/api/azure-openai-responses.js.map +1 -1
  8. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  9. package/dist/api/bedrock-converse-stream.js +21 -9
  10. package/dist/api/bedrock-converse-stream.js.map +1 -1
  11. package/dist/api/google-generative-ai.d.ts.map +1 -1
  12. package/dist/api/google-generative-ai.js +4 -2
  13. package/dist/api/google-generative-ai.js.map +1 -1
  14. package/dist/api/google-vertex.d.ts.map +1 -1
  15. package/dist/api/google-vertex.js +4 -2
  16. package/dist/api/google-vertex.js.map +1 -1
  17. package/dist/api/mistral-conversations.d.ts.map +1 -1
  18. package/dist/api/mistral-conversations.js +1 -1
  19. package/dist/api/mistral-conversations.js.map +1 -1
  20. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  21. package/dist/api/openai-codex-responses.js +62 -42
  22. package/dist/api/openai-codex-responses.js.map +1 -1
  23. package/dist/api/openai-completions.d.ts.map +1 -1
  24. package/dist/api/openai-completions.js +12 -5
  25. package/dist/api/openai-completions.js.map +1 -1
  26. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  27. package/dist/api/openai-responses-shared.js +153 -176
  28. package/dist/api/openai-responses-shared.js.map +1 -1
  29. package/dist/api/openai-responses.d.ts.map +1 -1
  30. package/dist/api/openai-responses.js +6 -16
  31. package/dist/api/openai-responses.js.map +1 -1
  32. package/dist/api/openrouter-images.d.ts.map +1 -1
  33. package/dist/api/openrouter-images.js +2 -1
  34. package/dist/api/openrouter-images.js.map +1 -1
  35. package/dist/api/simple-options.d.ts +3 -2
  36. package/dist/api/simple-options.d.ts.map +1 -1
  37. package/dist/api/simple-options.js +11 -2
  38. package/dist/api/simple-options.js.map +1 -1
  39. package/dist/api/transform-messages.d.ts.map +1 -1
  40. package/dist/api/transform-messages.js +4 -1
  41. package/dist/api/transform-messages.js.map +1 -1
  42. package/dist/image-models.generated.d.ts +34 -19
  43. package/dist/image-models.generated.d.ts.map +1 -1
  44. package/dist/image-models.generated.js +60 -45
  45. package/dist/image-models.generated.js.map +1 -1
  46. package/dist/index.d.ts +1 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +1 -0
  49. package/dist/index.js.map +1 -1
  50. package/dist/models.generated.d.ts +1754 -498
  51. package/dist/models.generated.d.ts.map +1 -1
  52. package/dist/providers/amazon-bedrock.models.d.ts +157 -0
  53. package/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
  54. package/dist/providers/amazon-bedrock.models.js +166 -12
  55. package/dist/providers/amazon-bedrock.models.js.map +1 -1
  56. package/dist/providers/anthropic.models.d.ts +6 -190
  57. package/dist/providers/anthropic.models.d.ts.map +1 -1
  58. package/dist/providers/anthropic.models.js +21 -207
  59. package/dist/providers/anthropic.models.js.map +1 -1
  60. package/dist/providers/azure-openai-responses.models.d.ts +84 -0
  61. package/dist/providers/azure-openai-responses.models.d.ts.map +1 -1
  62. package/dist/providers/azure-openai-responses.models.js +72 -0
  63. package/dist/providers/azure-openai-responses.models.js.map +1 -1
  64. package/dist/providers/cerebras.models.d.ts +21 -0
  65. package/dist/providers/cerebras.models.d.ts.map +1 -1
  66. package/dist/providers/cerebras.models.js +18 -0
  67. package/dist/providers/cerebras.models.js.map +1 -1
  68. package/dist/providers/cloudflare-ai-gateway.models.d.ts +21 -0
  69. package/dist/providers/cloudflare-ai-gateway.models.d.ts.map +1 -1
  70. package/dist/providers/cloudflare-ai-gateway.models.js +18 -0
  71. package/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
  72. package/dist/providers/fireworks.models.d.ts +28 -0
  73. package/dist/providers/fireworks.models.d.ts.map +1 -1
  74. package/dist/providers/fireworks.models.js +21 -2
  75. package/dist/providers/fireworks.models.js.map +1 -1
  76. package/dist/providers/github-copilot.models.d.ts +82 -0
  77. package/dist/providers/github-copilot.models.d.ts.map +1 -1
  78. package/dist/providers/github-copilot.models.js +62 -5
  79. package/dist/providers/github-copilot.models.js.map +1 -1
  80. package/dist/providers/groq.models.d.ts.map +1 -1
  81. package/dist/providers/groq.models.js +1 -1
  82. package/dist/providers/groq.models.js.map +1 -1
  83. package/dist/providers/huggingface.models.d.ts +100 -0
  84. package/dist/providers/huggingface.models.d.ts.map +1 -1
  85. package/dist/providers/huggingface.models.js +90 -0
  86. package/dist/providers/huggingface.models.js.map +1 -1
  87. package/dist/providers/minimax-cn.models.d.ts.map +1 -1
  88. package/dist/providers/minimax-cn.models.js +4 -4
  89. package/dist/providers/minimax-cn.models.js.map +1 -1
  90. package/dist/providers/minimax.models.d.ts.map +1 -1
  91. package/dist/providers/minimax.models.js +4 -4
  92. package/dist/providers/minimax.models.js.map +1 -1
  93. package/dist/providers/mistral.models.d.ts +1 -1
  94. package/dist/providers/mistral.models.d.ts.map +1 -1
  95. package/dist/providers/mistral.models.js +4 -4
  96. package/dist/providers/mistral.models.js.map +1 -1
  97. package/dist/providers/nvidia.models.d.ts +29 -1
  98. package/dist/providers/nvidia.models.d.ts.map +1 -1
  99. package/dist/providers/nvidia.models.js +23 -4
  100. package/dist/providers/nvidia.models.js.map +1 -1
  101. package/dist/providers/openai-codex.models.d.ts +63 -0
  102. package/dist/providers/openai-codex.models.d.ts.map +1 -1
  103. package/dist/providers/openai-codex.models.js +54 -0
  104. package/dist/providers/openai-codex.models.js.map +1 -1
  105. package/dist/providers/openai.models.d.ts +84 -0
  106. package/dist/providers/openai.models.d.ts.map +1 -1
  107. package/dist/providers/openai.models.js +72 -0
  108. package/dist/providers/openai.models.js.map +1 -1
  109. package/dist/providers/opencode-go.models.d.ts.map +1 -1
  110. package/dist/providers/opencode-go.models.js +6 -6
  111. package/dist/providers/opencode-go.models.js.map +1 -1
  112. package/dist/providers/opencode.models.d.ts +132 -0
  113. package/dist/providers/opencode.models.d.ts.map +1 -1
  114. package/dist/providers/opencode.models.js +111 -2
  115. package/dist/providers/opencode.models.js.map +1 -1
  116. package/dist/providers/openrouter.models.d.ts +358 -55
  117. package/dist/providers/openrouter.models.d.ts.map +1 -1
  118. package/dist/providers/openrouter.models.js +395 -138
  119. package/dist/providers/openrouter.models.js.map +1 -1
  120. package/dist/providers/together.models.d.ts +31 -0
  121. package/dist/providers/together.models.d.ts.map +1 -1
  122. package/dist/providers/together.models.js +21 -2
  123. package/dist/providers/together.models.js.map +1 -1
  124. package/dist/providers/vercel-ai-gateway.models.d.ts +446 -36
  125. package/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
  126. package/dist/providers/vercel-ai-gateway.models.js +477 -80
  127. package/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  128. package/dist/providers/xai.models.d.ts +22 -0
  129. package/dist/providers/xai.models.d.ts.map +1 -1
  130. package/dist/providers/xai.models.js +18 -0
  131. package/dist/providers/xai.models.js.map +1 -1
  132. package/dist/providers/xiaomi-token-plan-ams.models.d.ts +0 -42
  133. package/dist/providers/xiaomi-token-plan-ams.models.d.ts.map +1 -1
  134. package/dist/providers/xiaomi-token-plan-ams.models.js +9 -45
  135. package/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
  136. package/dist/providers/xiaomi-token-plan-cn.models.d.ts +0 -42
  137. package/dist/providers/xiaomi-token-plan-cn.models.d.ts.map +1 -1
  138. package/dist/providers/xiaomi-token-plan-cn.models.js +9 -45
  139. package/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
  140. package/dist/providers/xiaomi-token-plan-sgp.models.d.ts +0 -42
  141. package/dist/providers/xiaomi-token-plan-sgp.models.d.ts.map +1 -1
  142. package/dist/providers/xiaomi-token-plan-sgp.models.js +9 -45
  143. package/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
  144. package/dist/providers/xiaomi.models.d.ts.map +1 -1
  145. package/dist/providers/xiaomi.models.js +15 -15
  146. package/dist/providers/xiaomi.models.js.map +1 -1
  147. package/dist/types.d.ts +6 -0
  148. package/dist/types.d.ts.map +1 -1
  149. package/dist/types.js.map +1 -1
  150. package/dist/utils/error-body.d.ts +25 -0
  151. package/dist/utils/error-body.d.ts.map +1 -0
  152. package/dist/utils/error-body.js +109 -0
  153. package/dist/utils/error-body.js.map +1 -0
  154. package/dist/utils/estimate.d.ts +17 -0
  155. package/dist/utils/estimate.d.ts.map +1 -0
  156. package/dist/utils/estimate.js +95 -0
  157. package/dist/utils/estimate.js.map +1 -0
  158. package/dist/utils/oauth/device-code.d.ts +2 -0
  159. package/dist/utils/oauth/device-code.d.ts.map +1 -1
  160. package/dist/utils/oauth/device-code.js +15 -2
  161. package/dist/utils/oauth/device-code.js.map +1 -1
  162. package/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  163. package/dist/utils/oauth/github-copilot.js +3 -2
  164. package/dist/utils/oauth/github-copilot.js.map +1 -1
  165. package/dist/utils/overflow.d.ts +1 -0
  166. package/dist/utils/overflow.d.ts.map +1 -1
  167. package/dist/utils/overflow.js +3 -0
  168. package/dist/utils/overflow.js.map +1 -1
  169. package/dist/utils/retry.d.ts +12 -0
  170. package/dist/utils/retry.d.ts.map +1 -0
  171. package/dist/utils/retry.js +90 -0
  172. package/dist/utils/retry.js.map +1 -0
  173. package/dist/utils/validation.d.ts.map +1 -1
  174. package/dist/utils/validation.js +9 -21
  175. package/dist/utils/validation.js.map +1 -1
  176. package/package.json +1 -1
@@ -1,24 +1,16 @@
1
- var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
- if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
- return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
- return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
- });
1
+ function loadNodeOs() {
2
+ if (typeof process === "undefined" || !(process.versions?.node || process.versions?.bun)) {
3
+ return null;
6
4
  }
7
- return path;
8
- };
9
- // NEVER convert to top-level runtime imports - breaks browser/Vite builds
10
- let _os = null;
11
- const dynamicImport = (specifier) => import(__rewriteRelativeImportExtension(specifier));
12
- const NODE_OS_SPECIFIER = "node:" + "os";
13
- if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
14
- dynamicImport(NODE_OS_SPECIFIER).then((m) => {
15
- _os = m;
16
- });
5
+ return process.getBuiltinModule?.("node:os") ?? null;
17
6
  }
7
+ // NEVER convert to top-level runtime imports - breaks browser/Vite builds
8
+ const _os = loadNodeOs();
18
9
  import { clampThinkingLevel } from "../models.js";
19
10
  import { registerSessionResourceCleanup } from "../session-resources.js";
20
11
  import { combineAbortSignals } from "../utils/abort-signals.js";
21
12
  import { appendAssistantMessageDiagnostic, createAssistantMessageDiagnostic, formatThrownValue, } from "../utils/diagnostics.js";
13
+ import { formatProviderError, normalizeProviderError } from "../utils/error-body.js";
22
14
  import { AssistantMessageEventStream } from "../utils/event-stream.js";
23
15
  import { headersToRecord } from "../utils/headers.js";
24
16
  import { resolveHttpProxyUrlForTarget } from "../utils/node-http-proxy.js";
@@ -33,10 +25,10 @@ const JWT_CLAIM_PATH = "https://api.openai.com/auth";
33
25
  const DEFAULT_MAX_RETRIES = 0;
34
26
  const BASE_DELAY_MS = 1000;
35
27
  const DEFAULT_MAX_RETRY_DELAY_MS = 60_000;
36
- // Keep a bounded pre-header timeout so zero-event Codex SSE stalls fail instead of
37
- // leaving callers stuck on "Working..." indefinitely. See #4945.
38
- const DEFAULT_SSE_HEADER_TIMEOUT_MS = 20_000;
39
28
  const DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS = 15_000;
29
+ // The Codex backend accepts zstd-compressed request bodies on the SSE responses
30
+ // endpoint (the same endpoint the official Codex client compresses against).
31
+ const REQUEST_COMPRESSION_ZSTD_LEVEL = 3;
40
32
  const CODEX_TOOL_CALL_PROVIDERS = new Set(["openai", "openai-codex", "opencode"]);
41
33
  const WEBSOCKET_MESSAGE_TOO_BIG_CLOSE_CODE = 1009;
42
34
  const WEBSOCKET_CONNECTION_LIMIT_REACHED_CODE = "websocket_connection_limit_reached";
@@ -110,18 +102,29 @@ function normalizeTimeoutMs(value) {
110
102
  }
111
103
  return Math.floor(value);
112
104
  }
113
- function createSSEHeaderTimeout() {
114
- const controller = new AbortController();
115
- let error;
116
- const timeout = setTimeout(() => {
117
- error = new Error(`Codex SSE response headers timed out after ${DEFAULT_SSE_HEADER_TIMEOUT_MS}ms`);
118
- controller.abort(error);
119
- }, DEFAULT_SSE_HEADER_TIMEOUT_MS);
120
- return {
121
- signal: controller.signal,
122
- clear: () => clearTimeout(timeout),
123
- error: () => error,
124
- };
105
+ function loadNodeZlib() {
106
+ if (typeof process === "undefined" || !(process.versions?.node || process.versions?.bun)) {
107
+ return null;
108
+ }
109
+ return process.getBuiltinModule?.("node:zlib") ?? null;
110
+ }
111
+ // Returns the zstd-compressed body bytes, or null when compression is
112
+ // unavailable (browser/Vite builds). Callers fall back to sending the
113
+ // uncompressed JSON when this returns null.
114
+ function compressRequestBodyZstd(bodyJson) {
115
+ const zlib = loadNodeZlib();
116
+ if (!zlib || typeof zlib.zstdCompressSync !== "function") {
117
+ return null;
118
+ }
119
+ try {
120
+ const compressed = zlib.zstdCompressSync(bodyJson, {
121
+ params: { [zlib.constants.ZSTD_c_compressionLevel]: REQUEST_COMPRESSION_ZSTD_LEVEL },
122
+ });
123
+ return new Uint8Array(compressed.buffer, compressed.byteOffset, compressed.byteLength);
124
+ }
125
+ catch {
126
+ return null;
127
+ }
125
128
  }
126
129
  // ============================================================================
127
130
  // Main Stream Function
@@ -161,7 +164,7 @@ export const stream = (model, context, options) => {
161
164
  const sseHeaders = buildSSEHeaders(model.headers, options?.headers, accountId, apiKey, options?.sessionId);
162
165
  const websocketHeaders = buildWebSocketHeaders(model.headers, options?.headers, accountId, apiKey, websocketRequestId);
163
166
  const bodyJson = JSON.stringify(body);
164
- const idleTimeoutMs = normalizeTimeoutMs(options?.timeoutMs);
167
+ const httpTimeoutMs = normalizeTimeoutMs(options?.timeoutMs);
165
168
  const websocketConnectTimeoutMs = normalizeTimeoutMs(options?.websocketConnectTimeoutMs);
166
169
  const transport = options?.transport || "auto";
167
170
  const websocketDisabledForSession = transport !== "sse" && isWebSocketSseFallbackActive(options?.sessionId);
@@ -176,7 +179,7 @@ export const stream = (model, context, options) => {
176
179
  try {
177
180
  await processWebSocketStream(resolveCodexWebSocketUrl(model.baseUrl), body, websocketHeaders, output, stream, model, () => {
178
181
  websocketStarted = true;
179
- }, idleTimeoutMs, websocketConnectTimeoutMs, options);
182
+ }, httpTimeoutMs, websocketConnectTimeoutMs, options);
180
183
  if (options?.signal?.aborted) {
181
184
  throw new Error("Request was aborted");
182
185
  }
@@ -214,6 +217,14 @@ export const stream = (model, context, options) => {
214
217
  }
215
218
  }
216
219
  }
220
+ // Compress the request body once for the SSE path. The Codex backend
221
+ // decodes Content-Encoding: zstd; the WebSocket transport above sends the
222
+ // uncompressed JSON frame, matching the official Codex client.
223
+ const compressedBody = compressRequestBodyZstd(bodyJson);
224
+ if (compressedBody) {
225
+ sseHeaders.set("content-encoding", "zstd");
226
+ }
227
+ const sseBody = compressedBody ?? bodyJson;
217
228
  // Fetch with retry logic for rate limits and transient errors
218
229
  let response;
219
230
  let lastError;
@@ -223,23 +234,24 @@ export const stream = (model, context, options) => {
223
234
  throw new Error("Request was aborted");
224
235
  }
225
236
  try {
226
- const headerTimeout = createSSEHeaderTimeout();
227
- const combinedSignal = combineAbortSignals([options?.signal, headerTimeout.signal]);
237
+ const headerTimeoutSignal = httpTimeoutMs !== undefined && httpTimeoutMs > 0 ? AbortSignal.timeout(httpTimeoutMs) : undefined;
238
+ const combinedSignal = combineAbortSignals([options?.signal, headerTimeoutSignal]);
228
239
  try {
229
240
  response = await fetch(resolveCodexUrl(model.baseUrl), {
230
241
  method: "POST",
231
242
  headers: sseHeaders,
232
- body: bodyJson,
243
+ body: sseBody,
233
244
  signal: combinedSignal.signal,
234
245
  });
235
246
  }
236
247
  catch (error) {
237
- const timeoutError = headerTimeout.error();
238
- throw timeoutError && !options?.signal?.aborted ? timeoutError : error;
248
+ if (headerTimeoutSignal?.aborted && !options?.signal?.aborted) {
249
+ throw new Error(`Codex SSE response headers timed out after ${httpTimeoutMs}ms`);
250
+ }
251
+ throw error;
239
252
  }
240
253
  finally {
241
254
  combinedSignal.cleanup();
242
- headerTimeout.clear();
243
255
  }
244
256
  await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);
245
257
  if (response.ok) {
@@ -300,7 +312,7 @@ export const stream = (model, context, options) => {
300
312
  delete block.partialJson;
301
313
  }
302
314
  output.stopReason = options?.signal?.aborted ? "aborted" : "error";
303
- output.errorMessage = error instanceof Error ? error.message : String(error);
315
+ output.errorMessage = formatProviderError(normalizeProviderError(error));
304
316
  stream.push({ type: "error", reason: output.stopReason, error: output });
305
317
  stream.end();
306
318
  }
@@ -312,7 +324,7 @@ export const streamSimple = (model, context, options) => {
312
324
  if (!apiKey) {
313
325
  throw new Error(`No API key for provider: ${model.provider}`);
314
326
  }
315
- const base = buildBaseOptions(model, options, apiKey);
327
+ const base = buildBaseOptions(model, context, options, apiKey);
316
328
  const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
317
329
  const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
318
330
  return stream(model, context, {
@@ -553,6 +565,7 @@ async function* parseSSE(response, signal) {
553
565
  // ============================================================================
554
566
  const OPENAI_BETA_RESPONSES_WEBSOCKETS = "responses_websockets=2026-02-06";
555
567
  const SESSION_WEBSOCKET_CACHE_TTL_MS = 5 * 60 * 1000;
568
+ const SESSION_WEBSOCKET_MAX_AGE_MS = 55 * 60 * 1000;
556
569
  const websocketSessionCache = new Map();
557
570
  const websocketDebugStats = new Map();
558
571
  const websocketSseFallbackSessions = new Set();
@@ -677,6 +690,9 @@ function isWebSocketReusable(socket) {
677
690
  // If readyState is unavailable, assume the runtime keeps it open/reusable.
678
691
  return readyState === undefined || readyState === 1;
679
692
  }
693
+ function isWebSocketSessionExpired(entry) {
694
+ return Date.now() - entry.createdAt >= SESSION_WEBSOCKET_MAX_AGE_MS;
695
+ }
680
696
  function closeWebSocketSilently(socket, code = 1000, reason = "done") {
681
697
  try {
682
698
  socket.close(code, reason);
@@ -777,7 +793,11 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
777
793
  clearTimeout(cached.idleTimer);
778
794
  cached.idleTimer = undefined;
779
795
  }
780
- if (!cached.busy && isWebSocketReusable(cached.socket)) {
796
+ if (!cached.busy && isWebSocketSessionExpired(cached)) {
797
+ closeWebSocketSilently(cached.socket, 1000, "connection_age_limit");
798
+ websocketSessionCache.delete(sessionId);
799
+ }
800
+ else if (!cached.busy && isWebSocketReusable(cached.socket)) {
781
801
  cached.busy = true;
782
802
  return {
783
803
  socket: cached.socket,
@@ -810,7 +830,7 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
810
830
  }
811
831
  }
812
832
  const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs, env);
813
- const entry = { socket, busy: true };
833
+ const entry = { socket, busy: true, createdAt: Date.now() };
814
834
  websocketSessionCache.set(sessionId, entry);
815
835
  return {
816
836
  socket,