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

106 lines (105 loc) • 5.6 kB
/** * NeuroCoin ledger and per-window consumption tracking for borrowed traffic. * * Two jobs, deliberately in one module because they settle from the same event: * * 1. **Coins.** A grant with a coin entitlement spends against a balance. The * balance itself lives on the grant (one source of truth); this module holds * the entries and drives the deduction. * 2. **Window buckets.** How much of an account's 5h/7d window a grant has taken, * keyed by that window's reset timestamp so the counter starts fresh when the * window does. This is what makes a slice ceiling mean "a fifth of *this* * window" rather than "a fifth, once, forever". * * **Why hold-then-settle.** Real usage is only known when the response finishes * — for a stream, at `message_delta`. A balance checked at admission and * deducted at completion lets N concurrent streams each pass the same check and * overspend by N-1 requests. So admission opens a *hold* for an estimate, the * available balance is `balance - Σ open holds`, and settlement replaces the * hold with the real figure. A crash loses in-flight holds, which is the safe * direction: the balance is only ever reduced by traffic that actually happened. * * @module proxy/shareLedger */ import type { ProxyShareGrant, ProxyShareGrantUsageSummary, ProxyShareHold, ProxySharePoolUsage, ProxyShareSettlement, ProxyShareUsage, ProxyShareWindowObservation } from "../types/index.js"; /** Normalized tokens per coin. */ export declare const TOKENS_PER_COIN = 1000; export declare function initShareLedger(ledgerFilePath: string): void; export declare function modelCoinWeight(model: string | undefined): number; /** Convert real usage into coins. Pure — the pricing table is the whole story. */ export declare function usageToCoins(usage: ProxyShareUsage, model: string | undefined): number; /** * What to hold at admission, before anything is known about the response. * * Intentionally rough: the hold exists to stop concurrent streams from each * spending the last coin, not to predict the bill. Settlement replaces it with * the real figure moments later. */ export declare function estimateHoldCoins(model: string | undefined, maxTokens: number | undefined): number; /** Coins currently held against a grant by in-flight requests. */ export declare function heldCoins(grantId: string): number; /** * Balance a new request may draw on: the stored balance minus what in-flight * requests have already claimed. */ export declare function availableCoins(grant: ProxyShareGrant): number; export declare function openShareHold(grantId: string, coins: number, now?: number): ProxyShareHold; /** Drop a hold without spending it — the request never reached the upstream. */ export declare function releaseShareHold(holdId: string | undefined): void; /** * Record how much of an account's windows a borrowed request consumed. * * Never throws: a bookkeeping failure must not turn a response the borrower has * already received into an error. */ export declare function recordShareWindowDelta(observation: ProxyShareWindowObservation): Promise<void>; /** * Charge a finished borrowed request against its grant and close the hold. * * Never throws, for the same reason as above. */ export declare function settleShareUsage(settlement: ProxyShareSettlement): Promise<number>; /** * What a grant has taken from one account's current windows. * * Buckets whose reset timestamp no longer matches the account's are reported as * zero: they describe a window that has since rolled over. */ export declare function readShareWindowUsage(grantId: string, accountKey: string, currentSessionResetAt: number | null, currentWeeklyResetAt: number | null): Promise<{ sessionFraction: number; weeklyFraction: number; }>; /** * What a grant has taken from the pool as a whole, normalised to one window. * * Summing the per-account fractions and dividing by the account count is what * makes a ceiling mean the same thing on a one-account pool and a ten-account * one. Without the division, `--max-slice 20` would silently grant 20% of every * credential — 200% of a single window's worth across ten accounts. * * Buckets whose reset timestamp no longer matches contribute zero: they * describe a window that has since rolled over. */ export declare function readSharePoolWindowUsage(grantId: string, accounts: ReadonlyArray<{ accountKey: string; sessionResetAt: number | null; weeklyResetAt: number | null; }>): Promise<ProxySharePoolUsage>; /** Per-grant rollup across accounts, for `share status`. */ export declare function summarizeGrantUsage(grantId: string): Promise<ProxyShareGrantUsageSummary>; /** * Apply a standing allowance for every period that has elapsed. * * Called opportunistically at admission — there is no timer, so a node that is * off across one or more refill boundaries pays them on its next borrowed * request. Paying only the newest period would quietly turn "100 a week" into * "100 whenever you next happen to ask", which is not what the operator wrote. * * `lastAt` advances by whole periods rather than to `now`, so the schedule stays * anchored to when the grant was issued instead of drifting later with every * catch-up. It advances past the periods the cap refused to pay as well — see * {@link MAX_REFILL_CATCHUP_PERIODS}. */ export declare function applyRefillIfDue(grant: ProxyShareGrant, now?: number): Promise<ProxyShareGrant>; /** Drop all ledger state. Test isolation only. */ export declare function resetShareLedgerForTests(): void;