@north-light/api 0.3.505 → 0.3.506

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.
@@ -3,6 +3,8 @@ export declare const ANTHROPIC_PROVIDER_ID = "anthropic";
3
3
  export declare const OPENAI_CODEX_PROVIDER_ID = "openai-codex";
4
4
  /** pi's built-in `openai` provider signed in with a ChatGPT account (dynamic OAuth client). Distinct from Codex: its own pool, credential file and sign-in. */
5
5
  export declare const OPENAI_CHATGPT_PROVIDER_ID = "openai";
6
+ /** Longest a recorded 429 keeps an account or model family cooling, whatever the provider's Retry-After or window reset says: after this the next real call probes the provider, and a success clears the row. */
7
+ export declare const MAX_RATE_LIMIT_COOLDOWN_MS: number;
6
8
  export declare const INVALID_REFRESH_TOKEN_BACKOFF_MS: number;
7
9
  export type ManagedProviderId = typeof ANTHROPIC_PROVIDER_ID | typeof OPENAI_CODEX_PROVIDER_ID | typeof OPENAI_CHATGPT_PROVIDER_ID;
8
10
  export declare const MANAGED_PROVIDER_IDS: readonly ManagedProviderId[];
@@ -13,6 +13,8 @@ export const ANTHROPIC_PROVIDER_ID = 'anthropic';
13
13
  export const OPENAI_CODEX_PROVIDER_ID = 'openai-codex';
14
14
  /** pi's built-in `openai` provider signed in with a ChatGPT account (dynamic OAuth client). Distinct from Codex: its own pool, credential file and sign-in. */
15
15
  export const OPENAI_CHATGPT_PROVIDER_ID = 'openai';
16
+ /** Longest a recorded 429 keeps an account or model family cooling, whatever the provider's Retry-After or window reset says: after this the next real call probes the provider, and a success clears the row. */
17
+ export const MAX_RATE_LIMIT_COOLDOWN_MS = 10 * 60 * 1000;
16
18
  export const INVALID_REFRESH_TOKEN_BACKOFF_MS = 30 * 24 * 60 * 60 * 1000;
17
19
  export const MANAGED_PROVIDER_IDS = [ANTHROPIC_PROVIDER_ID, OPENAI_CODEX_PROVIDER_ID, OPENAI_CHATGPT_PROVIDER_ID];
18
20
  const DEFAULT_FALLBACK_STRENGTH = 'strong';
@@ -158,8 +160,9 @@ export async function markSubscriptionAuthenticationFailed(provider, ref, attemp
158
160
  return publicPool(provider, file); providerWrite(agentDir(), (db) => update(db, { ...current.row, authFailure: 'invalid_grant', lastAttemptAt: Math.max(current.row.lastAttemptAt, attemptAt), rateLimitedUntil: Math.max(current.row.rateLimitedUntil, attemptAt + Math.max(0, retryAfterMs)) })); return publicPool(provider, file); }); }
159
161
  /** Record a 429 on an account. `scope` defaults to the whole account; a model scope cools only that family on this account, and a 429 older than the newest one already recorded for the same scope is ignored. */
160
162
  export async function markSubscriptionRateLimited(provider, ref, retryAfterMs, attemptAt = Date.now(), rateLimitedAt = Date.now(), scope = { kind: 'account' }) {
163
+ retryAfterMs = Math.min(Math.max(0, retryAfterMs), MAX_RATE_LIMIT_COOLDOWN_MS);
161
164
  if (scope.kind === 'account')
162
- return mutateHealth(provider, ref, (row) => rateLimitedAt < row.lastRateLimitedAt ? null : { ...row, lastAttemptAt: Math.max(row.lastAttemptAt, attemptAt), lastRateLimitedAt: rateLimitedAt, rateLimitedUntil: rateLimitedAt + Math.max(0, retryAfterMs) });
165
+ return mutateHealth(provider, ref, (row) => rateLimitedAt < row.lastRateLimitedAt ? null : { ...row, lastAttemptAt: Math.max(row.lastAttemptAt, attemptAt), lastRateLimitedAt: rateLimitedAt, rateLimitedUntil: rateLimitedAt + retryAfterMs });
163
166
  providerWrite(agentDir(), (db) => {
164
167
  const row = providerRowByReference(db, provider, ref);
165
168
  if (!row)
@@ -168,7 +171,7 @@ export async function markSubscriptionRateLimited(provider, ref, retryAfterMs, a
168
171
  const current = providerModelCooldowns(db, provider).get(row.id)?.find((cooldown) => cooldown.family === scope.family);
169
172
  if (current && rateLimitedAt < current.lastRateLimitedAt)
170
173
  return;
171
- upsertModelCooldown(db, provider, row.id, scope.family, rateLimitedAt + Math.max(0, retryAfterMs), rateLimitedAt);
174
+ upsertModelCooldown(db, provider, row.id, scope.family, rateLimitedAt + retryAfterMs, rateLimitedAt);
172
175
  });
173
176
  return readSubscriptionPool(provider);
174
177
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/api",
3
- "version": "0.3.505",
3
+ "version": "0.3.506",
4
4
  "description": "Typed crtrd /v1 API contract — DTOs, route builders, the error contract, the CrtrClient, and the command-plugin manifest format. Zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "main": "./dist/api/index.js",