UNPKG

@juspay/neurolink

Version:

The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002

105 lines (104 loc) • 5.99 kB
/** * Codex (OpenAI ChatGPT) Proxy Routes * * Exposes `POST /backend-api/codex/responses` — the ChatGPT-backend Responses * API endpoint the Codex CLI talks to — and pools it across multiple ChatGPT * OAuth accounts, mirroring the Anthropic Claude pool engine. * * A Codex CLI configured with `model_providers.<name>.base_url` pointing at this * proxy sends its own OAuth token; the proxy strips it, selects a pooled * `codex:*` account, attaches that account's Bearer + matching chatgpt-account-id, * forwards to https://chatgpt.com/backend-api/codex, and relays the SSE stream. * On quota exhaustion (429 / usage limit) the account is cooled and the next * account is tried — so the user never has to switch accounts by hand. * * This engine is deliberately leaner than claudeProxyRoutes.ts: it reuses the * shared cooldown/quota persistence (keyed by the `codex:` account key so it * never collides with anthropic entries) and does pre-commit rotation only, not * the full transient-budget / admission machinery. */ import type { AccountQuota, CodexRefreshTokenStore, CodexResponseEnvelope, CodexResponseStream, CodexRuntimeAccount, CodexTokenRefresher, RateLimitCoolingReason, RouteGroup, ServerContext, ProxyRuntimeConfigProvider } from "../../types/index.js"; declare function refreshCodexTokenOnceWithDependencies(key: string, refreshToken: string, store: CodexRefreshTokenStore, refresh: CodexTokenRefresher): Promise<{ accessToken: string; refreshToken: string; expiresAt?: number; }>; /** Refresh an account's token at most once at a time. */ declare function refreshCodexTokenOnce(key: string, refreshToken: string): Promise<{ accessToken: string; refreshToken: string; expiresAt?: number; }>; /** * Load the Codex account pool from the token store, refreshing expired OAuth * tokens and hydrating cooldown + quota state from disk. */ declare function loadCodexProxyAccounts(): Promise<CodexRuntimeAccount[]>; /** * Order non-cooling accounts ahead of cooling ones, then defer rejected quota. * Within each group, probe unknown quota first and otherwise fill the least-used * session so fresh accounts get observed rather than starved. */ declare function orderCodexAccounts(accounts: CodexRuntimeAccount[], now: number): CodexRuntimeAccount[]; /** Build the upstream request headers, replacing client auth with the account's. */ declare function buildCodexUpstreamHeaders(clientHeaders: Record<string, string>, account: CodexRuntimeAccount): Record<string, string>; /** Honor known quota resets while bounding unscoped or transient account cooldowns. */ declare function planCodexCooldown(quota: AccountQuota | null, retryAfterMs: number, now: number, errorText?: string): { coolingUntil: number; reason: RateLimitCoolingReason; }; /** * Drive a `CodexResponseStream`'s `frames` generator into a `Response` body, * calling `onSettled` exactly once with the outcome: the terminal envelope on * a normal finish, the thrown error on the (never expected, still handled) * post-commit failure, or `cancelled` when the consumer cancels the * `ReadableStream` first (client disconnect, or an upstream timeout/abort). * * `createAnthropicFallbackStream`'s generator never throws once past its own * internal preflight (codexToAnthropicFallback.ts:220-517) — every * post-commit failure is instead serialized as a `response.failed` frame and * the generator completes normally — so the `catch` branch here is a * defensive backstop, not the documented failure path. */ declare function wrapCodexOutboundResponseStream(codecStream: CodexResponseStream, headers: Record<string, string>, onSettled: (result: { kind: "completed"; envelope: CodexResponseEnvelope; } | { kind: "error"; error: unknown; } | { kind: "cancelled"; }) => void): Response; /** Core pooled handler for POST /backend-api/codex/responses. */ export declare function handleCodexResponsesRequest(ctx: ServerContext, runtimeConfigProvider?: ProxyRuntimeConfigProvider, loopbackPort?: number, internalDispatch?: (request: Request) => Response | Promise<Response>): Promise<Response>; /** * Create Codex proxy routes. * * @param basePath - Base path prefix (default ""). * @param runtimeConfigProvider - Optional runtime config snapshot reader. * Gates the Codex-outbound fallback dispatcher at all four insertion * points in `dispatch()`: omitting it (or a snapshot with the feature * disabled / no targets configured) reproduces today's behavior exactly. * @param loopbackPort - The in-process HTTP port the outbound-fallback leg's * Anthropic-pool loopback request targets (mirrors `createOpenAIProxyRoutes`'s * bridge). Required only for an `anthropic` target; the `vertex` target * dispatches via `executeVertexAnthropicFallback` and never reads it. * @param internalDispatch - Optional in-process fetch (`(request) => * app.fetch(request)`), so the outbound-fallback loopback never re-enters * the public listener. Falls back to a real `fetch` against * `loopbackPort` when omitted. * @returns RouteGroup with the Codex backend Responses endpoint. */ export declare function createCodexProxyRoutes(basePath?: string, runtimeConfigProvider?: ProxyRuntimeConfigProvider, loopbackPort?: number, internalDispatch?: (request: Request) => Response | Promise<Response>): RouteGroup; export declare const __testHooks: { loadCodexProxyAccounts: typeof loadCodexProxyAccounts; orderCodexAccounts: typeof orderCodexAccounts; buildCodexUpstreamHeaders: typeof buildCodexUpstreamHeaders; planCodexCooldown: typeof planCodexCooldown; refreshCodexTokenOnce: typeof refreshCodexTokenOnce; refreshCodexTokenOnceWithDependencies: typeof refreshCodexTokenOnceWithDependencies; codexRefreshInFlightSize: () => number; setOutboundFallbackTimeoutMsForTests: (ms: number | null) => void; wrapCodexOutboundResponseStream: typeof wrapCodexOutboundResponseStream; }; export {};