@demicodes/provider-codex 0.6.1 → 0.7.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.d.mts CHANGED
@@ -95,8 +95,6 @@ interface CodexProviderConfig {
95
95
  transport?: CodexTransportMode;
96
96
  headers?: Record<string, string>;
97
97
  userAgent?: string;
98
- maxRetries?: number;
99
- retryBaseDelayMs?: number;
100
98
  headerTimeoutMs?: number;
101
99
  websocketConnectTimeoutMs?: number;
102
100
  streamIdleTimeoutMs?: number;
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { Buffer } from "node:buffer";
3
3
  import { chmod, mkdir, open, readFile, rename, rm, writeFile } from "node:fs/promises";
4
4
  import { homedir } from "node:os";
5
5
  import { dirname, join } from "node:path";
6
- import { applyModelPolicy, clampPromptCacheKey, clampUsedPercent, createProviderQuota, defineProvider, httpErrorCode, normalizeErrorCode, numberHeader, redactCredentialText, severityFromUsedPercent, unixSecondsToIso } from "@demicodes/provider";
6
+ import { applyModelPolicy, clampPromptCacheKey, clampUsedPercent, createProviderQuota, defineProvider, httpErrorCode, normalizeErrorCode, numberHeader, redactCredentialText, retryAfterMsFromHeader, severityFromUsedPercent, unixSecondsToIso } from "@demicodes/provider";
7
7
  import { FileCredentialPool, credentialIdFromIdentity } from "@demicodes/provider/credentials-pool";
8
8
  import { randomUUID } from "node:crypto";
9
9
  //#region src/auth.ts
@@ -1037,10 +1037,18 @@ function* mapCodexResponseEvent(event, state = newStreamState()) {
1037
1037
  return;
1038
1038
  case "error": {
1039
1039
  const nested = isRecord(event.error) ? event.error : null;
1040
+ const message = event.message ?? stringOrNull(nested?.message) ?? "Codex stream error";
1041
+ const rawCode = event.code ?? stringOrNull(nested?.code) ?? stringOrNull(nested?.type);
1042
+ const providerRequestId = providerRequestIdFrom(nested, message);
1040
1043
  yield {
1041
1044
  type: "error",
1042
- message: event.message ?? stringOrNull(nested?.message) ?? "Codex stream error",
1043
- code: event.code ?? stringOrNull(nested?.code) ?? stringOrNull(nested?.type) ?? null
1045
+ message,
1046
+ code: normalizeErrorCode(rawCode, message),
1047
+ diagnostics: {
1048
+ source: "stream",
1049
+ ...rawCode ? { providerCode: rawCode } : {},
1050
+ ...providerRequestId ? { providerRequestId } : {}
1051
+ }
1044
1052
  };
1045
1053
  return;
1046
1054
  }
@@ -1194,12 +1202,26 @@ function reasoningText(item) {
1194
1202
  function errorEventFromFailedResponse(response) {
1195
1203
  const error = isRecord(response) && isRecord(response.error) ? response.error : null;
1196
1204
  const message = stringOrNull(error?.message) ?? "Codex response failed";
1205
+ const rawCode = stringOrNull(error?.code) ?? stringOrNull(error?.type);
1206
+ const providerRequestId = providerRequestIdFrom(error, message);
1207
+ const providerResponseId = isRecord(response) ? stringOrNull(response.id) : null;
1197
1208
  return {
1198
1209
  type: "error",
1199
1210
  message,
1200
- code: normalizeErrorCode(stringOrNull(error?.code) ?? stringOrNull(error?.type), message)
1211
+ code: normalizeErrorCode(rawCode, message),
1212
+ diagnostics: {
1213
+ source: "stream",
1214
+ ...rawCode ? { providerCode: rawCode } : {},
1215
+ ...providerRequestId ? { providerRequestId } : {},
1216
+ ...providerResponseId ? { providerResponseId } : {}
1217
+ }
1201
1218
  };
1202
1219
  }
1220
+ function providerRequestIdFrom(value, message) {
1221
+ const explicit = stringOrNull(value?.request_id) ?? stringOrNull(value?.requestId);
1222
+ if (explicit) return explicit;
1223
+ return message.match(/request ID ([A-Za-z0-9-]+)/i)?.[1] ?? null;
1224
+ }
1203
1225
  function incompleteReason(response) {
1204
1226
  if (isRecord(response) && isRecord(response.incomplete_details) && typeof response.incomplete_details.reason === "string") return response.incomplete_details.reason;
1205
1227
  return "unknown";
@@ -1530,8 +1552,6 @@ function defaultWebSocketConstructor() {
1530
1552
  //#region src/provider.ts
1531
1553
  const DEFAULT_CHATGPT_CODEX_BASE_URL = "https://chatgpt.com/backend-api";
1532
1554
  const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
1533
- const DEFAULT_MAX_RETRIES = 2;
1534
- const DEFAULT_RETRY_BASE_DELAY_MS = 250;
1535
1555
  const DEFAULT_SSE_HEADER_TIMEOUT_MS = 2e4;
1536
1556
  const DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS = 1e4;
1537
1557
  var CodexProvider = class {
@@ -1546,8 +1566,6 @@ var CodexProvider = class {
1546
1566
  transport: options.transport ?? "auto",
1547
1567
  headers: options.headers,
1548
1568
  userAgent: options.userAgent ?? defaultUserAgent(),
1549
- maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,
1550
- retryBaseDelayMs: options.retryBaseDelayMs ?? DEFAULT_RETRY_BASE_DELAY_MS,
1551
1569
  headerTimeoutMs: options.headerTimeoutMs ?? DEFAULT_SSE_HEADER_TIMEOUT_MS,
1552
1570
  websocketConnectTimeoutMs: options.websocketConnectTimeoutMs ?? DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS,
1553
1571
  streamIdleTimeoutMs: options.streamIdleTimeoutMs ?? 0,
@@ -1560,8 +1578,7 @@ var CodexProvider = class {
1560
1578
  async *run(request) {
1561
1579
  const body = buildCodexResponsesRequestBody(request);
1562
1580
  let forceRefresh = false;
1563
- let retryAttempt = 0;
1564
- while (retryAttempt <= this.config.maxRetries) try {
1581
+ while (true) try {
1565
1582
  const auth = await this.authStore.resolveAuth({ forceRefresh });
1566
1583
  const url = responsesUrlForAuth(auth, this.config.baseUrl);
1567
1584
  const headers = buildCodexHeaders(auth, request, this.config);
@@ -1595,11 +1612,6 @@ var CodexProvider = class {
1595
1612
  forceRefresh = true;
1596
1613
  continue;
1597
1614
  }
1598
- if (error instanceof CodexHttpError && isRetryableHttpStatus(error.status) && retryAttempt < this.config.maxRetries) {
1599
- await sleep(this.config.retryBaseDelayMs * 2 ** retryAttempt, request.cancel);
1600
- retryAttempt += 1;
1601
- continue;
1602
- }
1603
1615
  yield providerErrorFromUnknown(error);
1604
1616
  return;
1605
1617
  }
@@ -1623,8 +1635,6 @@ function createCodexProvider(options = {}) {
1623
1635
  transport: options.transport,
1624
1636
  headers: options.headers,
1625
1637
  userAgent: options.userAgent,
1626
- maxRetries: options.maxRetries,
1627
- retryBaseDelayMs: options.retryBaseDelayMs,
1628
1638
  headerTimeoutMs: options.headerTimeoutMs,
1629
1639
  websocketConnectTimeoutMs: options.websocketConnectTimeoutMs,
1630
1640
  streamIdleTimeoutMs: options.streamIdleTimeoutMs,
@@ -1688,33 +1698,35 @@ function providerErrorFromUnknown(error) {
1688
1698
  message: redactCodexSecretText(error.message),
1689
1699
  code: error.code
1690
1700
  };
1691
- if (error instanceof CodexHttpError) return {
1692
- type: "error",
1693
- message: redactCodexSecretText(error.message),
1694
- code: httpErrorCode(error.status, error.message)
1695
- };
1701
+ if (error instanceof CodexHttpError) {
1702
+ const body = parseJsonObject(error.responseText);
1703
+ const bodyError = isRecord(body?.error) ? body.error : null;
1704
+ const providerCode = stringOrNull(bodyError?.code) ?? stringOrNull(bodyError?.type);
1705
+ const providerRequestId = error.headers.get("x-request-id") ?? stringOrNull(body?.request_id);
1706
+ const retryAfterMs = retryAfterMsFromHeader(error.headers.get("retry-after"));
1707
+ return {
1708
+ type: "error",
1709
+ message: redactCodexSecretText(error.message),
1710
+ code: httpErrorCode(error.status, error.message),
1711
+ ...retryAfterMs !== void 0 ? { retryAfterMs } : {},
1712
+ diagnostics: {
1713
+ source: "http",
1714
+ httpStatus: error.status,
1715
+ ...providerCode ? { providerCode } : {},
1716
+ ...providerRequestId ? { providerRequestId } : {}
1717
+ }
1718
+ };
1719
+ }
1696
1720
  const message = error instanceof Error ? error.message : String(error);
1697
1721
  return {
1698
1722
  type: "error",
1699
1723
  message: redactCodexSecretText(message),
1700
- code: normalizeErrorCode(null, message)
1724
+ code: normalizeErrorCode(null, message),
1725
+ diagnostics: { source: "transport" }
1701
1726
  };
1702
1727
  }
1703
- function isRetryableHttpStatus(status) {
1704
- return status === 408 || status === 409 || status === 425 || status === 429 || status === 500 || status === 502 || status === 503 || status === 504;
1705
- }
1706
1728
  function defaultUserAgent() {
1707
1729
  return `demi-codex-provider/0.0.0 (${process.platform}; ${process.arch})`;
1708
1730
  }
1709
- function sleep(ms, signal) {
1710
- if (signal.aborted) return Promise.reject(new DOMException("Aborted", "AbortError"));
1711
- return new Promise((resolve, reject) => {
1712
- const timeout = setTimeout(resolve, ms);
1713
- signal.addEventListener("abort", () => {
1714
- clearTimeout(timeout);
1715
- reject(new DOMException("Aborted", "AbortError"));
1716
- }, { once: true });
1717
- });
1718
- }
1719
1731
  //#endregion
1720
1732
  export { PoolAwareCodexAuthStore, codexAuthStatus, createCodexCredentials, createCodexProvider, createCodexQuota, listCodexModels, mapCodexRateLimitHeaders, openCodexCredentialPool, runCodexDeviceLogin };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@demicodes/provider-codex",
3
3
  "description": "Codex provider adapter for Demi.",
4
- "version": "0.6.1",
4
+ "version": "0.7.0",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "exports": {
@@ -11,13 +11,13 @@
11
11
  }
12
12
  },
13
13
  "dependencies": {
14
- "@demicodes/core": "^0.6.1",
15
- "@demicodes/provider": "^0.6.1",
16
- "@demicodes/utils": "^0.6.1"
14
+ "@demicodes/core": "^0.7.0",
15
+ "@demicodes/provider": "^0.7.0",
16
+ "@demicodes/utils": "^0.7.0"
17
17
  },
18
18
  "devDependencies": {
19
- "@demicodes/agent": "^0.6.1",
20
- "@demicodes/shell": "^0.6.1"
19
+ "@demicodes/agent": "^0.7.0",
20
+ "@demicodes/shell": "^0.7.0"
21
21
  },
22
22
  "license": "Apache-2.0",
23
23
  "main": "./dist/index.mjs",