@juspay/neurolink 12.7.2 → 12.7.4

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.
@@ -24,7 +24,8 @@ import { formatUptime, isProcessRunning, StateFileManager, } from "../utils/serv
24
24
  import { configureProxyKeepAliveDispatcher } from "../../proxy/proxyDispatcher.js";
25
25
  import { ProxyRuntimeConfigStore } from "../../proxy/runtimeConfig.js";
26
26
  import { startProxyLogCleanupScheduler } from "../../proxy/logCleanupScheduler.js";
27
- import { anthropicAccountKeysEqual, createAccountAllowlist, ENV_ANTHROPIC_ACCOUNT_KEY, isAccountAllowed, LEGACY_ANTHROPIC_ACCOUNT_KEY, normalizeAnthropicAccountKey, shouldLoadFallbackCredential, } from "../../proxy/accountSelection.js";
27
+ import { anthropicAccountKeysEqual, createAccountAllowlist, isAccountAllowed, LEGACY_ANTHROPIC_ACCOUNT_KEY, normalizeAnthropicAccountKey, shouldLoadFallbackCredential, } from "../../proxy/accountSelection.js";
28
+ import { resolveProxyStatusAccountIdentity } from "../../proxy/codexAccountUsage.js";
28
29
  import { beginProxyRequest, getProxyActivitySnapshot, trackProxyResponse, } from "../../proxy/proxyActivity.js";
29
30
  import { flushProxyLifecycleEvents, getProxyLifecycleLoggerSnapshot, hashProxyLifecycleSessionId, logProxyLifecycleEvent, } from "../../proxy/proxyLifecycle.js";
30
31
  import { describeInstallFailure, getGlobalInstallArgs, isTransientInstallFailure, resolveGlobalInstaller, validateInstalledVersion, } from "../../proxy/globalInstaller.js";
@@ -65,11 +66,9 @@ const gatedShareRequests = new WeakSet();
65
66
  const PROXY_LIFECYCLE_SHUTDOWN_TIMEOUT_MS = 5_000;
66
67
  /** How long shutdown waits on the share listener before moving on. */
67
68
  const SHARE_LISTENER_CLOSE_TIMEOUT_MS = 10_000;
68
- const LEGACY_STATUS_ACCOUNT_CACHE_TTL_MS = 5_000;
69
69
  const PROXY_STATUS_TOKEN_READ_TIMEOUT_MS = 2_000;
70
70
  const PROXY_STATUS_RECONCILE_TIMEOUT_MS = 750;
71
71
  const PROXY_STATUS_ACCOUNT_INVENTORY_TIMEOUT_MS = 750;
72
- let legacyStatusAccountCache;
73
72
  // Allowed drift between a pid's OS-reported start time and the persisted
74
73
  // ProxySupervisorState.startTime before processLooksLikeProxySupervisor
75
74
  // treats it as a confident mismatch (recycled pid). Generous on purpose:
@@ -385,34 +384,6 @@ async function resolveStatusPrimaryAccount(proxyConfig) {
385
384
  source: "fallback",
386
385
  };
387
386
  }
388
- async function resolveLegacyStatusAccountLabel(storedAnthropicAccountCount) {
389
- if (storedAnthropicAccountCount !== 0) {
390
- return null;
391
- }
392
- const credentialsPath = join(homedir(), ".neurolink", "anthropic-credentials.json");
393
- const now = Date.now();
394
- if (legacyStatusAccountCache?.credentialsPath === credentialsPath &&
395
- legacyStatusAccountCache.expiresAt > now) {
396
- return legacyStatusAccountCache.label;
397
- }
398
- let label = null;
399
- try {
400
- const { readFile } = await import("node:fs/promises");
401
- const parsed = JSON.parse(await readFile(credentialsPath, "utf8"));
402
- if (parsed.oauth?.accessToken) {
403
- label = parsed.email?.trim() || "legacy-default";
404
- }
405
- }
406
- catch {
407
- label = null;
408
- }
409
- legacyStatusAccountCache = {
410
- credentialsPath,
411
- expiresAt: now + LEGACY_STATUS_ACCOUNT_CACHE_TTL_MS,
412
- label,
413
- };
414
- return label;
415
- }
416
387
  function deriveAccountAllowance(accountKey, now, allowlist, expirations, cooldowns) {
417
388
  const allowed = isAccountAllowed(accountKey, allowlist);
418
389
  const expiresAt = expirations.get(accountKey);
@@ -1066,6 +1037,7 @@ function redactStatusAccounts(rows, allowed) {
1066
1037
  return rows.map((row, index) => ({
1067
1038
  ...row,
1068
1039
  label: `account-${index + 1}`,
1040
+ ...(row.key !== undefined ? { key: null } : {}),
1069
1041
  ...(row.email !== undefined ? { email: null } : {}),
1070
1042
  }));
1071
1043
  }
@@ -1685,20 +1657,28 @@ export async function createProxyStartApp(params) {
1685
1657
  logger.debug(`[proxy] /status using empty cooldown snapshot: ${error instanceof Error ? error.message : String(error)}`);
1686
1658
  return {};
1687
1659
  });
1688
- const storedAccountKeys = new Set();
1660
+ const storedAnthropicAccountKeys = new Set();
1661
+ const storedCodexAccountKeys = new Set();
1689
1662
  const storedAccountExpirations = new Map();
1690
- const disabledAccountKeys = new Set();
1663
+ const disabledProviderAccountKeys = new Set();
1691
1664
  let accountInventoryLoaded = false;
1692
1665
  try {
1693
1666
  const { tokenStore } = await import("../../auth/tokenStore.js");
1694
- const storedKeys = await withTimeout(tokenStore.listByPrefix("anthropic:"), PROXY_STATUS_ACCOUNT_INVENTORY_TIMEOUT_MS, "[proxy] /status account enumeration timed out");
1695
- for (const key of storedKeys) {
1696
- storedAccountKeys.add(normalizeAnthropicAccountKey(key));
1667
+ const [anthropicKeys, codexKeys] = await withTimeout(Promise.all([
1668
+ tokenStore.listByPrefix("anthropic:"),
1669
+ tokenStore.listByPrefix("codex:"),
1670
+ ]), PROXY_STATUS_ACCOUNT_INVENTORY_TIMEOUT_MS, "[proxy] /status account enumeration timed out");
1671
+ for (const key of anthropicKeys) {
1672
+ storedAnthropicAccountKeys.add(normalizeAnthropicAccountKey(key));
1673
+ }
1674
+ for (const key of codexKeys) {
1675
+ storedCodexAccountKeys.add(key);
1697
1676
  }
1698
1677
  // Once account names are known, preserve them even when optional token
1699
1678
  // metadata is slow. That keeps the status table useful and avoids
1700
1679
  // incorrectly presenting known accounts as removed.
1701
1680
  accountInventoryLoaded = true;
1681
+ const storedKeys = [...anthropicKeys, ...codexKeys];
1702
1682
  const inventory = await withTimeout((async () => {
1703
1683
  const tokenExpirations = await Promise.all(storedKeys.map(async (key) => {
1704
1684
  try {
@@ -1715,19 +1695,21 @@ export async function createProxyStartApp(params) {
1715
1695
  })(), PROXY_STATUS_ACCOUNT_INVENTORY_TIMEOUT_MS, "[proxy] /status account metadata timed out");
1716
1696
  for (const expiration of inventory.tokenExpirations) {
1717
1697
  if (expiration) {
1718
- storedAccountExpirations.set(normalizeAnthropicAccountKey(expiration[0]), expiration[1]);
1698
+ const key = expiration[0].startsWith("anthropic:")
1699
+ ? normalizeAnthropicAccountKey(expiration[0])
1700
+ : expiration[0];
1701
+ storedAccountExpirations.set(key, expiration[1]);
1719
1702
  }
1720
1703
  }
1721
1704
  for (const key of inventory.disabledKeys) {
1722
- disabledAccountKeys.add(normalizeAnthropicAccountKey(key));
1705
+ disabledProviderAccountKeys.add(key.startsWith("anthropic:")
1706
+ ? normalizeAnthropicAccountKey(key)
1707
+ : key);
1723
1708
  }
1724
1709
  }
1725
1710
  catch (err) {
1726
1711
  logger.debug(`[proxy] /status: failed to resolve account cooldown labels: ${err instanceof Error ? err.message : String(err)}`);
1727
1712
  }
1728
- const legacyAccountLabel = accountInventoryLoaded
1729
- ? await withTimeout(resolveLegacyStatusAccountLabel(storedAccountKeys.size), PROXY_STATUS_ACCOUNT_INVENTORY_TIMEOUT_MS, "[proxy] /status legacy account inspection timed out").catch(() => null)
1730
- : null;
1731
1713
  const now = Date.now();
1732
1714
  const health = buildProxyHealthResponse(readiness, {
1733
1715
  strategy: activeStrategy,
@@ -1741,34 +1723,54 @@ export async function createProxyStartApp(params) {
1741
1723
  source: "fallback",
1742
1724
  }));
1743
1725
  const activeUpdaterPid = supervisorState?.updaterPid ?? runtimeState?.updaterPid;
1744
- const accountRows = Object.values(stats.accounts).map((account) => {
1745
- const normalizedKey = normalizeAnthropicAccountKey(account.label);
1746
- const isLegacyAccount = account.type === "oauth" && account.label === legacyAccountLabel;
1747
- const accountKey = storedAccountKeys.has(normalizedKey)
1748
- ? normalizedKey
1749
- : isLegacyAccount
1750
- ? LEGACY_ANTHROPIC_ACCOUNT_KEY
1751
- : account.label === "env"
1752
- ? ENV_ANTHROPIC_ACCOUNT_KEY
1753
- : normalizedKey;
1754
- const isStored = storedAccountKeys.has(accountKey) || isLegacyAccount;
1755
- const { allowed, expired, cooling } = deriveAccountAllowance(accountKey, now, activeAccountAllowlist, storedAccountExpirations, cooldowns);
1726
+ const accountRows = Object.entries(stats.accounts).map(([persistedMapKey, account]) => {
1727
+ // Legacy snapshots used their bare map key as an inferred identity. Do
1728
+ // not map those old rows to a provider based on an email: the same email
1729
+ // can be present in both pools. New records carry account.key.
1730
+ const persistedKey = account.key ?? null;
1731
+ const identity = persistedKey
1732
+ ? resolveProxyStatusAccountIdentity(account.label, account.type, persistedKey)
1733
+ : { provider: "other", key: null };
1734
+ const isLegacyUnattributed = persistedKey === null &&
1735
+ (account.type === "oauth" ||
1736
+ account.type === "api_key" ||
1737
+ account.type === "codex-oauth");
1738
+ const isAnthropicAccount = identity.provider === "anthropic";
1739
+ const isCodexAccount = identity.provider === "codex";
1740
+ const accountKey = identity.key ?? (persistedKey || persistedMapKey);
1741
+ const isStored = (isAnthropicAccount && storedAnthropicAccountKeys.has(accountKey)) ||
1742
+ (isCodexAccount && storedCodexAccountKeys.has(accountKey));
1743
+ const providerState = isAnthropicAccount
1744
+ ? deriveAccountAllowance(accountKey, now, activeAccountAllowlist, storedAccountExpirations, cooldowns)
1745
+ : isCodexAccount
1746
+ ? {
1747
+ allowed: true,
1748
+ expired: (storedAccountExpirations.get(accountKey) ?? 0) > 0 &&
1749
+ (storedAccountExpirations.get(accountKey) ?? 0) <= now,
1750
+ cooling: (cooldowns[accountKey]?.coolingUntil ?? 0) > now,
1751
+ }
1752
+ : { allowed: true, expired: false, cooling: false };
1753
+ const isDisabled = !isLegacyUnattributed && disabledProviderAccountKeys.has(accountKey);
1756
1754
  const accountStatus = account.type === "internal"
1757
1755
  ? "internal"
1758
- : disabledAccountKeys.has(accountKey)
1759
- ? "disabled"
1760
- : expired
1761
- ? "expired"
1762
- : !allowed
1763
- ? "excluded"
1764
- : accountInventoryLoaded &&
1765
- account.type === "oauth" &&
1766
- !isStored
1767
- ? "removed"
1768
- : cooling
1769
- ? "cooling"
1770
- : "active";
1756
+ : isLegacyUnattributed
1757
+ ? "unattributed"
1758
+ : isDisabled
1759
+ ? "disabled"
1760
+ : providerState.expired
1761
+ ? "expired"
1762
+ : isAnthropicAccount && !providerState.allowed
1763
+ ? "excluded"
1764
+ : accountInventoryLoaded &&
1765
+ (isAnthropicAccount || isCodexAccount) &&
1766
+ !isStored
1767
+ ? "removed"
1768
+ : providerState.cooling
1769
+ ? "cooling"
1770
+ : "active";
1771
1771
  return {
1772
+ key: isLegacyUnattributed ? null : accountKey,
1773
+ provider: isLegacyUnattributed ? "unknown" : identity.provider,
1772
1774
  label: account.label,
1773
1775
  type: account.type,
1774
1776
  attempts: account.attemptCount,
@@ -1779,21 +1781,26 @@ export async function createProxyStartApp(params) {
1779
1781
  rateLimits: account.rateLimitCount,
1780
1782
  transientRateLimits: account.transientRateLimitCount,
1781
1783
  quotaRateLimits: account.quotaRateLimitCount,
1782
- cooling,
1784
+ cooling: providerState.cooling,
1783
1785
  status: accountStatus,
1784
- allowed: account.type === "internal" ? undefined : allowed,
1785
- expired: account.type === "oauth" ? expired : undefined,
1786
+ allowed: account.type === "internal" ? undefined : providerState.allowed,
1787
+ expired: isAnthropicAccount || isCodexAccount
1788
+ ? providerState.expired
1789
+ : undefined,
1786
1790
  };
1787
1791
  });
1788
- const representedAccountKeys = new Set(accountRows
1789
- .filter((account) => account.type === "oauth")
1790
- .map((account) => normalizeAnthropicAccountKey(account.label)));
1791
- for (const accountKey of storedAccountKeys) {
1792
+ const representedAccountKeys = new Set(accountRows.flatMap((account) => account.key &&
1793
+ (account.provider === "anthropic" || account.provider === "codex")
1794
+ ? [account.key]
1795
+ : []));
1796
+ for (const accountKey of storedAnthropicAccountKeys) {
1792
1797
  if (representedAccountKeys.has(accountKey)) {
1793
1798
  continue;
1794
1799
  }
1795
1800
  const { allowed, expired, cooling } = deriveAccountAllowance(accountKey, now, activeAccountAllowlist, storedAccountExpirations, cooldowns);
1796
1801
  accountRows.push({
1802
+ key: accountKey,
1803
+ provider: "anthropic",
1797
1804
  label: accountKey.slice("anthropic:".length),
1798
1805
  type: "oauth",
1799
1806
  attempts: 0,
@@ -1805,7 +1812,7 @@ export async function createProxyStartApp(params) {
1805
1812
  transientRateLimits: 0,
1806
1813
  quotaRateLimits: 0,
1807
1814
  cooling,
1808
- status: disabledAccountKeys.has(accountKey)
1815
+ status: disabledProviderAccountKeys.has(accountKey)
1809
1816
  ? "disabled"
1810
1817
  : expired
1811
1818
  ? "expired"
@@ -1818,6 +1825,38 @@ export async function createProxyStartApp(params) {
1818
1825
  expired,
1819
1826
  });
1820
1827
  }
1828
+ for (const accountKey of storedCodexAccountKeys) {
1829
+ if (representedAccountKeys.has(accountKey)) {
1830
+ continue;
1831
+ }
1832
+ const expiresAt = storedAccountExpirations.get(accountKey);
1833
+ const expired = expiresAt !== undefined && expiresAt > 0 && expiresAt <= now;
1834
+ const cooling = (cooldowns[accountKey]?.coolingUntil ?? 0) > now;
1835
+ accountRows.push({
1836
+ key: accountKey,
1837
+ provider: "codex",
1838
+ label: accountKey.slice("codex:".length),
1839
+ type: "codex-oauth",
1840
+ attempts: 0,
1841
+ requests: 0,
1842
+ success: 0,
1843
+ errors: 0,
1844
+ attemptErrors: 0,
1845
+ rateLimits: 0,
1846
+ transientRateLimits: 0,
1847
+ quotaRateLimits: 0,
1848
+ cooling,
1849
+ status: disabledProviderAccountKeys.has(accountKey)
1850
+ ? "disabled"
1851
+ : expired
1852
+ ? "expired"
1853
+ : cooling
1854
+ ? "cooling"
1855
+ : "active",
1856
+ allowed: true,
1857
+ expired,
1858
+ });
1859
+ }
1821
1860
  const attributed = accountRows.reduce((total, account) => ({
1822
1861
  attempts: total.attempts + (account.attempts ?? 0),
1823
1862
  requests: total.requests + (account.requests ?? 0),
@@ -3010,7 +3049,8 @@ function printStatusStats(stats) {
3010
3049
  if (lastError) {
3011
3050
  const cause = lastError.errorType ?? lastError.category;
3012
3051
  const code = lastError.errorCode ? `/${lastError.errorCode}` : "";
3013
- const account = lastError.account ? ` account=${lastError.account}` : "";
3052
+ const accountIdentity = lastError.accountKey ?? lastError.account;
3053
+ const account = accountIdentity ? ` account=${accountIdentity}` : "";
3014
3054
  console.info(` Last error: ${new Date(lastError.at).toISOString()} ${cause}${code} status=${lastError.status}${account}`);
3015
3055
  if (lastError.message) {
3016
3056
  console.info(` Last cause: ${sanitizeProxyStatusTerminalErrorMessage(lastError.message)}`);
@@ -6,10 +6,8 @@
6
6
  * - login, logout, status, refresh: Anthropic OAuth (API key + OAuth)
7
7
  * - providers, validate, health: Multi-provider auth management
8
8
  */
9
- /**
10
- * Supported providers for authentication
11
- */
12
- const SUPPORTED_PROVIDERS = ["anthropic", "codex"];
9
+ /** Providers with first-class credential flows in `neurolink auth`. */
10
+ const AUTH_LOGIN_PROVIDERS = ["anthropic", "codex"];
13
11
  /**
14
12
  * Auth Command Factory
15
13
  *
@@ -167,7 +165,7 @@ export class AuthCommandFactory {
167
165
  .positional("provider", {
168
166
  type: "string",
169
167
  description: "AI provider to authenticate with",
170
- choices: SUPPORTED_PROVIDERS,
168
+ choices: AUTH_LOGIN_PROVIDERS,
171
169
  demandOption: true,
172
170
  })
173
171
  .option("method", {
@@ -204,7 +202,7 @@ export class AuthCommandFactory {
204
202
  .positional("provider", {
205
203
  type: "string",
206
204
  description: "AI provider to log out from",
207
- choices: SUPPORTED_PROVIDERS,
205
+ choices: AUTH_LOGIN_PROVIDERS,
208
206
  demandOption: true,
209
207
  })
210
208
  .example("$0 auth logout anthropic", "Clear all Anthropic credentials");
@@ -217,7 +215,7 @@ export class AuthCommandFactory {
217
215
  .positional("provider", {
218
216
  type: "string",
219
217
  description: "AI provider to check (optional, shows all if not specified)",
220
- choices: SUPPORTED_PROVIDERS,
218
+ choices: AUTH_LOGIN_PROVIDERS,
221
219
  })
222
220
  .example("$0 auth status", "Show status for all configured providers")
223
221
  .example("$0 auth status anthropic", "Show Anthropic authentication status")
@@ -231,7 +229,7 @@ export class AuthCommandFactory {
231
229
  .positional("provider", {
232
230
  type: "string",
233
231
  description: "AI provider to refresh tokens for",
234
- choices: SUPPORTED_PROVIDERS,
232
+ choices: AUTH_LOGIN_PROVIDERS,
235
233
  demandOption: true,
236
234
  })
237
235
  .example("$0 auth refresh anthropic", "Refresh Anthropic OAuth tokens");
@@ -244,7 +242,7 @@ export class AuthCommandFactory {
244
242
  .option("refresh", {
245
243
  type: "boolean",
246
244
  default: false,
247
- description: "Fetch fresh limits from Anthropic for all OAuth accounts before listing (via the running proxy when available)",
245
+ description: "Refresh available provider limits for authenticated accounts; show unsupported providers explicitly",
248
246
  })
249
247
  .example("$0 auth list", "List all authenticated accounts")
250
248
  .example("$0 auth list --format json", "List accounts in JSON format")
@@ -257,8 +255,7 @@ export class AuthCommandFactory {
257
255
  return yargs
258
256
  .positional("provider", {
259
257
  type: "string",
260
- description: "AI provider to remove account from",
261
- choices: SUPPORTED_PROVIDERS,
258
+ description: "Provider namespace to remove an account from",
262
259
  demandOption: true,
263
260
  })
264
261
  .option("label", {
@@ -6,8 +6,13 @@
6
6
  * map onto the shared AccountQuota session/weekly fields so the same routing,
7
7
  * cooldown, and display code works for both providers.
8
8
  */
9
+ import type { CodexProxyStatusAccountIdentity } from "../types/index.js";
9
10
  import type { AccountQuota, CodexRateLimits, CodexUsageFetchResult, ProxyPassthroughAccount } from "../types/index.js";
10
11
  export declare const CODEX_ACCOUNT_PREFIX = "codex:";
12
+ /** Keep an account label in the Codex namespace used by its token store. */
13
+ export declare function normalizeCodexAccountKey(value: string): string;
14
+ /** Resolve the provider-qualified key used to render a proxy status row. */
15
+ export declare function resolveProxyStatusAccountIdentity(label: string, type: string, persistedKey?: string): CodexProxyStatusAccountIdentity;
11
16
  /** Enumerate Codex OAuth accounts from the token store for usage refresh. */
12
17
  export declare function listCodexAccountsForUsage(): Promise<ProxyPassthroughAccount[]>;
13
18
  /** Normalise a Codex rate-limit block into the shared AccountQuota shape. */
@@ -7,9 +7,39 @@
7
7
  * cooldown, and display code works for both providers.
8
8
  */
9
9
  import { tokenStore } from "../auth/tokenStore.js";
10
+ import { normalizeAnthropicAccountKey } from "./accountSelection.js";
10
11
  import { CODEX_ORIGINATOR, CODEX_USAGE_URL, CODEX_USER_AGENT, decodeCodexAccessToken, resolveCodexAccountId, } from "../auth/codexOAuth.js";
11
12
  import { logger } from "../utils/logger.js";
12
13
  export const CODEX_ACCOUNT_PREFIX = "codex:";
14
+ /** Keep an account label in the Codex namespace used by its token store. */
15
+ export function normalizeCodexAccountKey(value) {
16
+ const trimmed = value.trim();
17
+ return trimmed.startsWith(CODEX_ACCOUNT_PREFIX)
18
+ ? trimmed
19
+ : `${CODEX_ACCOUNT_PREFIX}${trimmed}`;
20
+ }
21
+ /** Resolve the provider-qualified key used to render a proxy status row. */
22
+ export function resolveProxyStatusAccountIdentity(label, type, persistedKey) {
23
+ // Current counter snapshots persist the provider-qualified key. Prefer it
24
+ // over the display type so a future type rename cannot move an account into
25
+ // the wrong cooldown/disabled namespace.
26
+ if (persistedKey?.toLowerCase().startsWith("anthropic:")) {
27
+ return {
28
+ provider: "anthropic",
29
+ key: normalizeAnthropicAccountKey(persistedKey),
30
+ };
31
+ }
32
+ if (persistedKey?.startsWith(CODEX_ACCOUNT_PREFIX)) {
33
+ return { provider: "codex", key: persistedKey };
34
+ }
35
+ if (type === "oauth" || type === "api_key") {
36
+ return { provider: "anthropic", key: normalizeAnthropicAccountKey(label) };
37
+ }
38
+ if (type === "codex-oauth") {
39
+ return { provider: "codex", key: normalizeCodexAccountKey(label) };
40
+ }
41
+ return { provider: "other", key: null };
42
+ }
13
43
  /** Enumerate Codex OAuth accounts from the token store for usage refresh. */
14
44
  export async function listCodexAccountsForUsage() {
15
45
  const keys = await tokenStore.listByPrefix(CODEX_ACCOUNT_PREFIX);
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Anthropic Messages API fallback over the pooled Codex Responses transport.
3
+ *
4
+ * This module deliberately contains only wire-format conversion and buffered
5
+ * SSE parsing. Account selection, OAuth, cooldowns, and quota persistence stay
6
+ * in the native Codex proxy handler so fallback traffic follows the same pool
7
+ * rules as a native Codex request.
8
+ */
9
+ import type { ClaudeRequest, CodexFallbackResult, CodexResponsesRequest } from "../types/index.js";
10
+ export declare class CodexFallbackResponseError extends Error {
11
+ readonly status: number;
12
+ readonly responseBody: string;
13
+ constructor(status: number, responseBody: string);
14
+ }
15
+ /** Convert a Claude Messages request into the ChatGPT Codex Responses shape. */
16
+ export declare function convertClaudeRequestToCodex(body: ClaudeRequest, model: string): CodexResponsesRequest;
17
+ /**
18
+ * Parse a complete Codex Responses SSE stream before emitting Claude output.
19
+ *
20
+ * A missing terminal event, malformed JSON, terminal error, or empty response
21
+ * is rejected. That makes it safe for the caller to try the next configured
22
+ * fallback without ever replaying output already sent to a client.
23
+ */
24
+ export declare function parseCodexFallbackSSE(sse: string): CodexFallbackResult;
25
+ /** Consume and validate a native Codex response before producing Claude output. */
26
+ export declare function consumeCodexFallbackResponse(response: Response): Promise<CodexFallbackResult>;