@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
85 lines (84 loc) • 4.39 kB
TypeScript
/**
* Per-Account Quota Tracking
*
* Captures Anthropic rate-limit / utilisation headers from proxy responses
* and persists them to ~/.neurolink/account-quotas.json so the CLI can
* display remaining session & weekly capacity per account.
*
* Hot-path design: parseQuotaHeaders is pure CPU (no I/O). saveAccountQuota
* updates an in-memory cache and debounces disk writes so the request/response
* path is never blocked by file I/O.
*/
import type { AccountQuota, AccountQuotaWindow } from "../types/index.js";
/**
* Collapse a wire model id to its family by dropping the snapshot date, so
* `claude-fable-5-20260115` and `claude-fable-5-20260320` both tag the same
* scoped window. Without this a window would stop matching the day Anthropic
* ships a new snapshot.
*/
export declare function modelFamilyToken(model: string): string;
/** Read and normalize Anthropic's authoritative top-level unified status. */
export declare function getUnifiedRateLimitStatus(headers: Headers | Record<string, string>): string | undefined;
/**
* Whether Anthropic explicitly permits a request to use overage after a
* subscription window is exhausted. An active overage signal is authoritative;
* otherwise fresh responses require explicit fallback and upgrade-path signals.
* Older persisted snapshots predate those raw fields, but retain a positive
* fallback percentage together with an allowed overage status, which is the
* equivalent provider state.
*/
export declare function isQuotaOverageAvailable(quota: Pick<AccountQuota, "fallbackPercentage" | "fallbackStatus" | "overageStatus" | "overageInUse" | "overageEnabled" | "overageDisabledReason" | "upgradePaths"> | null | undefined): boolean;
/**
* Parse Anthropic rate-limit / quota headers into an `AccountQuota`.
* Returns `null` when key headers are absent.
* Pure computation — no I/O, no blocking.
*/
export declare function parseQuotaHeaders(headers: Headers | Record<string, string>, opts?: {
model?: string;
now?: number;
}): AccountQuota | null;
/**
* Merge dynamic limit windows across snapshots from different sources.
*
* The two sources see different things and neither is a superset: the usage API
* reports every plan bucket but only when explicitly refreshed, while response
* headers report only the window(s) touched by the request just served — but do
* so continuously. A plain overwrite in either direction loses real data, which
* is why a header capture used to erase the model-scoped windows a `/limits`
* refresh had just fetched.
*/
export declare function mergeQuotaWindows(existing: AccountQuotaWindow[] | undefined, incoming: AccountQuotaWindow[] | undefined): AccountQuotaWindow[] | undefined;
/**
* Fold a freshly observed snapshot onto the previous one for the same account,
* preserving dynamic windows the new snapshot does not carry.
*/
export declare function mergeQuotaSnapshot(previous: AccountQuota | undefined, incoming: AccountQuota): AccountQuota;
/**
* Initialise the quota module with a custom file path.
* When set, all reads/writes go to this path instead of the default
* ~/.neurolink/account-quotas.json. Call before the first load/save.
*/
export declare function initAccountQuota(quotaFilePath: string): void;
export declare function loadAccountQuotas(): Promise<Record<string, AccountQuota>>;
/**
* Load quota for a single account.
*/
export declare function loadAccountQuota(accountKey: string): Promise<AccountQuota | null>;
/**
* Update quota for a single account.
* Updates in-memory cache immediately (non-blocking),
* then debounces the disk write to every 5 seconds.
*
* Loads the persisted file into the cache before the first write so a save
* after a process restart merges with existing entries instead of rewriting
* the file with only the accounts used since boot (which silently erased
* other accounts' snapshots and blinded quota-aware routing to them).
*/
export declare function saveAccountQuota(accountKey: string, quota: AccountQuota): Promise<void>;
/**
* Cancel any pending debounced write and flush the cache to disk now.
* Short-lived processes (CLI refresh path) must call this before exit —
* the debounce timer is unref()'d and will not keep the process alive.
*/
export declare function flushAccountQuotas(): Promise<void>;
export declare function flushAccountQuotaStateForTests(): Promise<void>;