@agentproto/model-intel 0.0.0 → 0.2.0
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.
- package/dist/index.d.ts +42 -1
- package/dist/index.mjs +114 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -118,6 +118,47 @@ interface AnthropicHeadersInput {
|
|
|
118
118
|
*/
|
|
119
119
|
declare function quotaFromAnthropicHeaders(input: AnthropicHeadersInput): QuotaStatus | undefined;
|
|
120
120
|
|
|
121
|
+
/** One side of a Codex `rate_limits` payload. */
|
|
122
|
+
interface CodexRateLimitWindow {
|
|
123
|
+
used_percent: number;
|
|
124
|
+
window_minutes?: number;
|
|
125
|
+
/** Epoch seconds. */
|
|
126
|
+
reset_at?: number;
|
|
127
|
+
}
|
|
128
|
+
interface CodexRateLimits {
|
|
129
|
+
primary?: CodexRateLimitWindow;
|
|
130
|
+
secondary?: CodexRateLimitWindow;
|
|
131
|
+
}
|
|
132
|
+
interface CodexCredits {
|
|
133
|
+
has_credits?: boolean;
|
|
134
|
+
unlimited?: boolean;
|
|
135
|
+
balance?: number;
|
|
136
|
+
}
|
|
137
|
+
interface CodexRateLimitsInput {
|
|
138
|
+
profileRef: string;
|
|
139
|
+
rateLimits: CodexRateLimits;
|
|
140
|
+
credits?: CodexCredits;
|
|
141
|
+
now?: () => Date;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Pure parser for a Codex `rate_limits` payload: each present side becomes one
|
|
145
|
+
* window and optional credits become a credits block. Never throws; a missing
|
|
146
|
+
* or non-numeric field is dropped, a valid value (0 included) is kept.
|
|
147
|
+
*/
|
|
148
|
+
declare function quotaFromCodexRateLimits(input: CodexRateLimitsInput): QuotaStatus | undefined;
|
|
149
|
+
|
|
150
|
+
interface MoonshotQuotaReaderOptions {
|
|
151
|
+
baseUrl?: string;
|
|
152
|
+
timeoutMs?: number;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Moonshot balance reader: `GET /v1/users/me/balance` exposes the account's
|
|
156
|
+
* available USD balance, but no cap, so it is reported as credits-only (no
|
|
157
|
+
* window). The whole read never throws; a balance of 0 or below is real data
|
|
158
|
+
* and is kept as is.
|
|
159
|
+
*/
|
|
160
|
+
declare function createMoonshotQuotaReader(opts?: MoonshotQuotaReaderOptions): QuotaReader;
|
|
161
|
+
|
|
121
162
|
interface OpenRouterQuotaReaderOptions {
|
|
122
163
|
baseUrl?: string;
|
|
123
164
|
timeoutMs?: number;
|
|
@@ -141,4 +182,4 @@ declare function createOpenRouterQuotaReader(opts?: OpenRouterQuotaReaderOptions
|
|
|
141
182
|
declare const SPEC_NAME: "quota/v1";
|
|
142
183
|
declare const SPEC_VERSION: "1.0.0-alpha";
|
|
143
184
|
|
|
144
|
-
export { type BuildQuotaStatusInput, QUOTA_BASES, type QuotaBasis, type QuotaCredits, type QuotaProfile, type QuotaReadContext, type QuotaReader, QuotaReaderRegistry, type QuotaStatus, type QuotaWindow, SPEC_NAME, SPEC_VERSION, buildQuotaStatus, createOpenRouterQuotaReader, defineQuotaReader, quotaCreditsSchema, quotaFromAnthropicHeaders, quotaStatusSchema, quotaWindowSchema, remainingPctFromCounts, remainingPctFromUsed };
|
|
185
|
+
export { type BuildQuotaStatusInput, type CodexCredits, type CodexRateLimitWindow, type CodexRateLimits, type CodexRateLimitsInput, QUOTA_BASES, type QuotaBasis, type QuotaCredits, type QuotaProfile, type QuotaReadContext, type QuotaReader, QuotaReaderRegistry, type QuotaStatus, type QuotaWindow, SPEC_NAME, SPEC_VERSION, buildQuotaStatus, createMoonshotQuotaReader, createOpenRouterQuotaReader, defineQuotaReader, quotaCreditsSchema, quotaFromAnthropicHeaders, quotaFromCodexRateLimits, quotaStatusSchema, quotaWindowSchema, remainingPctFromCounts, remainingPctFromUsed };
|
package/dist/index.mjs
CHANGED
|
@@ -145,12 +145,12 @@ function quotaFromAnthropicHeaders(input) {
|
|
|
145
145
|
const limit = parseCount(headerGet(input.headers, `${prefix}-limit`));
|
|
146
146
|
const remaining = parseCount(headerGet(input.headers, `${prefix}-remaining`));
|
|
147
147
|
if (limit === void 0 || remaining === void 0) continue;
|
|
148
|
-
const
|
|
149
|
-
if (
|
|
148
|
+
const remainingPct2 = remainingPctFromCounts(remaining, limit);
|
|
149
|
+
if (remainingPct2 === void 0) continue;
|
|
150
150
|
const resetsAt = parseReset(headerGet(input.headers, `${prefix}-reset`));
|
|
151
151
|
windows.push({
|
|
152
152
|
id: dimension.id,
|
|
153
|
-
remainingPct,
|
|
153
|
+
remainingPct: remainingPct2,
|
|
154
154
|
limit,
|
|
155
155
|
remaining,
|
|
156
156
|
unit: dimension.unit,
|
|
@@ -165,8 +165,112 @@ function quotaFromAnthropicHeaders(input) {
|
|
|
165
165
|
windows
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
|
-
|
|
168
|
+
|
|
169
|
+
// src/readers/codex.ts
|
|
170
|
+
function remainingPct(used) {
|
|
171
|
+
return Math.max(0, Math.min(100, 100 - used));
|
|
172
|
+
}
|
|
173
|
+
function windowFromSide(id, side) {
|
|
174
|
+
if (!side || typeof side.used_percent !== "number" || !Number.isFinite(side.used_percent)) {
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
const window = { id, remainingPct: remainingPct(side.used_percent) };
|
|
178
|
+
if (typeof side.reset_at === "number" && Number.isFinite(side.reset_at)) {
|
|
179
|
+
const date = new Date(side.reset_at * 1e3);
|
|
180
|
+
if (!Number.isNaN(date.getTime())) window.resetsAt = date.toISOString();
|
|
181
|
+
}
|
|
182
|
+
return window;
|
|
183
|
+
}
|
|
184
|
+
function quotaFromCodexRateLimits(input) {
|
|
185
|
+
try {
|
|
186
|
+
const windows = [];
|
|
187
|
+
const primary = windowFromSide("primary", input.rateLimits?.primary);
|
|
188
|
+
if (primary) windows.push(primary);
|
|
189
|
+
const secondary = windowFromSide("secondary", input.rateLimits?.secondary);
|
|
190
|
+
if (secondary) windows.push(secondary);
|
|
191
|
+
let credits;
|
|
192
|
+
const raw = input.credits;
|
|
193
|
+
if (raw) {
|
|
194
|
+
const hasBalance = typeof raw.balance === "number" && Number.isFinite(raw.balance);
|
|
195
|
+
if (raw.unlimited === true || hasBalance) {
|
|
196
|
+
credits = { currency: "USD" };
|
|
197
|
+
if (raw.unlimited === true) credits.unlimited = true;
|
|
198
|
+
if (hasBalance) credits.balanceUsd = raw.balance;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return buildQuotaStatus({
|
|
202
|
+
profileRef: input.profileRef,
|
|
203
|
+
basis: "provider",
|
|
204
|
+
source: "codex:rate_limits",
|
|
205
|
+
now: input.now,
|
|
206
|
+
windows,
|
|
207
|
+
...credits !== void 0 ? { credits } : {}
|
|
208
|
+
});
|
|
209
|
+
} catch {
|
|
210
|
+
return void 0;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
var DEFAULT_BASE_URL = "https://api.moonshot.ai";
|
|
169
214
|
var DEFAULT_TIMEOUT_MS = 4e3;
|
|
215
|
+
var MOONSHOT_BALANCE_SCHEMA = z.object({
|
|
216
|
+
data: z.object({
|
|
217
|
+
available_balance: z.number()
|
|
218
|
+
}).passthrough()
|
|
219
|
+
}).passthrough();
|
|
220
|
+
async function getBalanceJson(baseUrl, secret, ctx, timeoutMs) {
|
|
221
|
+
const controller = new AbortController();
|
|
222
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
223
|
+
const onAbort = () => controller.abort();
|
|
224
|
+
ctx.signal?.addEventListener("abort", onAbort);
|
|
225
|
+
try {
|
|
226
|
+
const res = await (ctx.fetchImpl ?? fetch)(`${baseUrl}/v1/users/me/balance`, {
|
|
227
|
+
method: "GET",
|
|
228
|
+
headers: { authorization: `Bearer ${secret}` },
|
|
229
|
+
signal: controller.signal
|
|
230
|
+
});
|
|
231
|
+
if (!res.ok) return void 0;
|
|
232
|
+
return await res.json();
|
|
233
|
+
} catch {
|
|
234
|
+
return void 0;
|
|
235
|
+
} finally {
|
|
236
|
+
clearTimeout(timer);
|
|
237
|
+
ctx.signal?.removeEventListener("abort", onAbort);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function createMoonshotQuotaReader(opts) {
|
|
241
|
+
const baseUrl = opts?.baseUrl ?? DEFAULT_BASE_URL;
|
|
242
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
243
|
+
return defineQuotaReader({
|
|
244
|
+
id: "moonshot-balance",
|
|
245
|
+
supports: (profile) => profile.endpoint === "moonshot" && profile.method === "api-key",
|
|
246
|
+
read: async (profile, ctx) => {
|
|
247
|
+
try {
|
|
248
|
+
if (!profile.credentialRef) return void 0;
|
|
249
|
+
if (!ctx.resolveCredential) return void 0;
|
|
250
|
+
const secret = await ctx.resolveCredential(profile.credentialRef).catch(() => void 0);
|
|
251
|
+
if (!secret) return void 0;
|
|
252
|
+
const body = await getBalanceJson(baseUrl, secret, ctx, timeoutMs);
|
|
253
|
+
if (body === void 0) return void 0;
|
|
254
|
+
const parsed = MOONSHOT_BALANCE_SCHEMA.safeParse(body);
|
|
255
|
+
if (!parsed.success) return void 0;
|
|
256
|
+
const balance = parsed.data.data.available_balance;
|
|
257
|
+
if (!Number.isFinite(balance)) return void 0;
|
|
258
|
+
return buildQuotaStatus({
|
|
259
|
+
profileRef: profile.profileRef,
|
|
260
|
+
basis: "provider",
|
|
261
|
+
source: "moonshot:/users/me/balance",
|
|
262
|
+
now: ctx.now,
|
|
263
|
+
windows: [],
|
|
264
|
+
credits: { balanceUsd: balance, currency: "USD" }
|
|
265
|
+
});
|
|
266
|
+
} catch {
|
|
267
|
+
return void 0;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
var DEFAULT_BASE_URL2 = "https://openrouter.ai/api/v1";
|
|
273
|
+
var DEFAULT_TIMEOUT_MS2 = 4e3;
|
|
170
274
|
var OPENROUTER_KEY_SCHEMA = z.object({
|
|
171
275
|
data: z.object({
|
|
172
276
|
limit: z.number().nullable().optional(),
|
|
@@ -194,8 +298,8 @@ async function getKeyJson(baseUrl, secret, ctx, timeoutMs) {
|
|
|
194
298
|
}
|
|
195
299
|
}
|
|
196
300
|
function createOpenRouterQuotaReader(opts) {
|
|
197
|
-
const baseUrl = opts?.baseUrl ??
|
|
198
|
-
const timeoutMs = opts?.timeoutMs ??
|
|
301
|
+
const baseUrl = opts?.baseUrl ?? DEFAULT_BASE_URL2;
|
|
302
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
199
303
|
return defineQuotaReader({
|
|
200
304
|
id: "openrouter-key",
|
|
201
305
|
supports: (profile) => profile.endpoint === "openrouter" && profile.method === "api-key",
|
|
@@ -212,11 +316,11 @@ function createOpenRouterQuotaReader(opts) {
|
|
|
212
316
|
const { limit, limit_remaining } = parsed.data.data;
|
|
213
317
|
const windows = [];
|
|
214
318
|
if (typeof limit === "number" && Number.isFinite(limit) && typeof limit_remaining === "number" && Number.isFinite(limit_remaining)) {
|
|
215
|
-
const
|
|
216
|
-
if (
|
|
319
|
+
const remainingPct2 = remainingPctFromCounts(limit_remaining, limit);
|
|
320
|
+
if (remainingPct2 !== void 0) {
|
|
217
321
|
windows.push({
|
|
218
322
|
id: "key_limit",
|
|
219
|
-
remainingPct,
|
|
323
|
+
remainingPct: remainingPct2,
|
|
220
324
|
remaining: limit_remaining,
|
|
221
325
|
limit,
|
|
222
326
|
unit: "USD"
|
|
@@ -246,6 +350,6 @@ function createOpenRouterQuotaReader(opts) {
|
|
|
246
350
|
var SPEC_NAME = "quota/v1";
|
|
247
351
|
var SPEC_VERSION = "1.0.0-alpha";
|
|
248
352
|
|
|
249
|
-
export { QUOTA_BASES, QuotaReaderRegistry, SPEC_NAME, SPEC_VERSION, buildQuotaStatus, createOpenRouterQuotaReader, defineQuotaReader, quotaCreditsSchema, quotaFromAnthropicHeaders, quotaStatusSchema, quotaWindowSchema, remainingPctFromCounts, remainingPctFromUsed };
|
|
353
|
+
export { QUOTA_BASES, QuotaReaderRegistry, SPEC_NAME, SPEC_VERSION, buildQuotaStatus, createMoonshotQuotaReader, createOpenRouterQuotaReader, defineQuotaReader, quotaCreditsSchema, quotaFromAnthropicHeaders, quotaFromCodexRateLimits, quotaStatusSchema, quotaWindowSchema, remainingPctFromCounts, remainingPctFromUsed };
|
|
250
354
|
//# sourceMappingURL=index.mjs.map
|
|
251
355
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/build.ts","../src/registry.ts","../src/readers/anthropic.ts","../src/readers/openrouter.ts","../src/index.ts"],"names":["z"],"mappings":"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","file":"index.mjs","sourcesContent":["import { z } from \"zod\"\n\n/**\n * Where a quota figure came from. `provider` is a documented provider\n * surface; `observed` is derived from this host's own traffic; `estimated`\n * is a local computation; `probe` is an undocumented surface reached through\n * a connector and MUST NOT be emitted by core readers.\n */\nexport const QUOTA_BASES = [\"provider\", \"probe\", \"observed\", \"estimated\"] as const\nexport type QuotaBasis = (typeof QUOTA_BASES)[number]\n\nconst isoTimestamp = z.string().refine((s) => !Number.isNaN(Date.parse(s)), {\n message: \"expected an ISO-8601 timestamp\",\n})\n\nexport const quotaWindowSchema = z.object({\n /** Open string: \"5h\", \"7d\", \"month\", \"minute\", \"day\", \"primary\", \"key_limit\", ... */\n id: z.string().min(1),\n /** 0-100. Required: a window that cannot state it is not emitted. */\n remainingPct: z.number().min(0).max(100),\n used: z.number().optional(),\n limit: z.number().optional(),\n remaining: z.number().optional(),\n unit: z.string().optional(),\n resetsAt: isoTimestamp.optional(),\n})\nexport type QuotaWindow = z.infer<typeof quotaWindowSchema>\n\nexport const quotaCreditsSchema = z.object({\n balanceUsd: z.number().optional(),\n unlimited: z.boolean().optional(),\n currency: z.string().min(1),\n})\nexport type QuotaCredits = z.infer<typeof quotaCreditsSchema>\n\nexport const quotaStatusSchema = z.object({\n profileRef: z.string().min(1),\n asOf: isoTimestamp,\n basis: z.enum(QUOTA_BASES),\n source: z.string().optional(),\n windows: z.array(quotaWindowSchema),\n credits: quotaCreditsSchema.optional(),\n})\nexport type QuotaStatus = z.infer<typeof quotaStatusSchema>\n\n/** The minimal auth-profile projection a reader needs. */\nexport interface QuotaProfile {\n profileRef: string\n endpoint: string\n method: \"oauth-bearer\" | \"api-key\"\n credentialRef?: string\n}\n\nexport interface QuotaReadContext {\n signal?: AbortSignal\n /** Resolve a profile's opaque credentialRef to a bearer secret. */\n resolveCredential?(ref: string): Promise<string | undefined>\n fetchImpl?: typeof fetch\n now?: () => Date\n}\n\n/**\n * Reads quota for a profile. MUST NOT throw: any failure or unknown value\n * resolves to `undefined`. Never fabricates a figure.\n */\nexport interface QuotaReader {\n readonly id: string\n supports(profile: QuotaProfile): boolean\n read(profile: QuotaProfile, ctx: QuotaReadContext): Promise<QuotaStatus | undefined>\n}\n","import type { QuotaBasis, QuotaCredits, QuotaStatus, QuotaWindow } from \"./types.js\"\nimport { quotaWindowSchema } from \"./types.js\"\n\n/** remainingPct from a used percentage, or undefined when it is not a finite 0-100 number. */\nexport function remainingPctFromUsed(usedPct: number | null | undefined): number | undefined {\n if (usedPct === null || usedPct === undefined || !Number.isFinite(usedPct)) return undefined\n if (usedPct < 0 || usedPct > 100) return undefined\n return 100 - usedPct\n}\n\n/** remainingPct from remaining/limit counts, or undefined when limit is not a positive finite number. */\nexport function remainingPctFromCounts(\n remaining: number | null | undefined,\n limit: number | null | undefined,\n): number | undefined {\n if (remaining === null || remaining === undefined || limit === null || limit === undefined) {\n return undefined\n }\n if (!Number.isFinite(remaining) || !Number.isFinite(limit) || limit <= 0) return undefined\n if (remaining < 0 || remaining > limit) return undefined\n return (remaining / limit) * 100\n}\n\nexport interface BuildQuotaStatusInput {\n profileRef: string\n basis: QuotaBasis\n source?: string\n now?: () => Date\n /** Candidate windows; any that fail validation are dropped, never repaired. */\n windows?: readonly unknown[]\n credits?: QuotaCredits\n}\n\n/**\n * Assemble a QuotaStatus. Invalid windows are omitted. Returns `undefined`\n * when there is nothing to report (no valid window and no credits).\n */\nexport function buildQuotaStatus(input: BuildQuotaStatusInput): QuotaStatus | undefined {\n const windows: QuotaWindow[] = []\n for (const candidate of input.windows ?? []) {\n const parsed = quotaWindowSchema.safeParse(candidate)\n if (parsed.success) windows.push(parsed.data)\n }\n if (windows.length === 0 && input.credits === undefined) return undefined\n return {\n profileRef: input.profileRef,\n asOf: (input.now ?? (() => new Date()))().toISOString(),\n basis: input.basis,\n ...(input.source !== undefined ? { source: input.source } : {}),\n windows,\n ...(input.credits !== undefined ? { credits: input.credits } : {}),\n }\n}\n","import type { QuotaProfile, QuotaReadContext, QuotaReader, QuotaStatus } from \"./types.js\"\n\n/** Identity helper that fixes the QuotaReader contract at definition time (AIP-43 handle). */\nexport function defineQuotaReader(reader: QuotaReader): QuotaReader {\n return reader\n}\n\nexport class QuotaReaderRegistry {\n private readonly readers = new Map<string, QuotaReader>()\n\n register(reader: QuotaReader): this {\n if (this.readers.has(reader.id)) {\n throw new Error(`quota reader already registered: ${reader.id}`)\n }\n this.readers.set(reader.id, reader)\n return this\n }\n\n list(): QuotaReader[] {\n return [...this.readers.values()]\n }\n\n /** First registered reader that supports the profile, in registration order. */\n find(profile: QuotaProfile): QuotaReader | undefined {\n for (const reader of this.readers.values()) {\n if (safeSupports(reader, profile)) return reader\n }\n return undefined\n }\n\n /** Read through the first supporting reader. Never throws; unknown -> undefined. */\n async read(profile: QuotaProfile, ctx: QuotaReadContext = {}): Promise<QuotaStatus | undefined> {\n const reader = this.find(profile)\n if (!reader) return undefined\n try {\n return await reader.read(profile, ctx)\n } catch {\n return undefined\n }\n }\n}\n\nfunction safeSupports(reader: QuotaReader, profile: QuotaProfile): boolean {\n try {\n return reader.supports(profile)\n } catch {\n return false\n }\n}\n","import { buildQuotaStatus, remainingPctFromCounts } from \"../build.js\"\nimport type { QuotaStatus } from \"../types.js\"\n\nexport interface AnthropicHeadersInput {\n profileRef: string\n headers: Headers | Record<string, string | undefined>\n now?: () => Date\n}\n\ninterface Dimension {\n id: string\n header: string\n unit: string\n}\n\nconst DIMENSIONS: readonly Dimension[] = [\n { id: \"requests-1m\", header: \"requests\", unit: \"requests\" },\n { id: \"tokens-1m\", header: \"tokens\", unit: \"tokens\" },\n { id: \"input-tokens-1m\", header: \"input-tokens\", unit: \"tokens\" },\n { id: \"output-tokens-1m\", header: \"output-tokens\", unit: \"tokens\" },\n]\n\n/** Read a header case-insensitively from a `Headers` or a plain record. */\nfunction headerGet(\n headers: Headers | Record<string, string | undefined>,\n name: string,\n): string | undefined {\n if (headers instanceof Headers) {\n return headers.get(name) ?? undefined\n }\n const lower = name.toLowerCase()\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lower) return value\n }\n return undefined\n}\n\n/** Parse a numeric rate-limit header; empty/garbage → undefined. */\nfunction parseCount(raw: string | undefined): number | undefined {\n if (raw === undefined) return undefined\n const trimmed = raw.trim()\n if (!trimmed) return undefined\n const n = Number(trimmed)\n return Number.isFinite(n) ? n : undefined\n}\n\n/** Normalize an RFC 3339 reset header to an ISO string; unparseable → undefined. */\nfunction parseReset(raw: string | undefined): string | undefined {\n if (raw === undefined) return undefined\n const trimmed = raw.trim()\n if (!trimmed) return undefined\n const date = new Date(trimmed)\n return Number.isNaN(date.getTime()) ? undefined : date.toISOString()\n}\n\n/**\n * PURE: build a QuotaStatus from Anthropic's DOCUMENTED rate-limit headers\n * `anthropic-ratelimit-{requests,tokens,input-tokens,output-tokens}-{limit,remaining,reset}`.\n * The undocumented `anthropic-ratelimit-unified-*` family is never read.\n * A dimension with a missing/non-numeric limit or remaining is skipped.\n */\nexport function quotaFromAnthropicHeaders(input: AnthropicHeadersInput): QuotaStatus | undefined {\n const windows: Record<string, unknown>[] = []\n for (const dimension of DIMENSIONS) {\n const prefix = `anthropic-ratelimit-${dimension.header}`\n const limit = parseCount(headerGet(input.headers, `${prefix}-limit`))\n const remaining = parseCount(headerGet(input.headers, `${prefix}-remaining`))\n if (limit === undefined || remaining === undefined) continue\n const remainingPct = remainingPctFromCounts(remaining, limit)\n if (remainingPct === undefined) continue\n const resetsAt = parseReset(headerGet(input.headers, `${prefix}-reset`))\n windows.push({\n id: dimension.id,\n remainingPct,\n limit,\n remaining,\n unit: dimension.unit,\n ...(resetsAt !== undefined ? { resetsAt } : {}),\n })\n }\n return buildQuotaStatus({\n profileRef: input.profileRef,\n basis: \"provider\",\n source: \"anthropic:ratelimit-headers\",\n now: input.now,\n windows,\n })\n}\n","import { z } from \"zod\"\nimport { buildQuotaStatus, remainingPctFromCounts } from \"../build.js\"\nimport { defineQuotaReader } from \"../registry.js\"\nimport type { QuotaCredits, QuotaProfile, QuotaReadContext, QuotaReader, QuotaStatus, QuotaWindow } from \"../types.js\"\n\nconst DEFAULT_BASE_URL = \"https://openrouter.ai/api/v1\"\nconst DEFAULT_TIMEOUT_MS = 4000\n\nconst OPENROUTER_KEY_SCHEMA = z\n .object({\n data: z\n .object({\n limit: z.number().nullable().optional(),\n limit_remaining: z.number().nullable().optional(),\n })\n .passthrough(),\n })\n .passthrough()\n\nexport interface OpenRouterQuotaReaderOptions {\n baseUrl?: string\n timeoutMs?: number\n}\n\n/** GET `${baseUrl}/key` and parse the body, never throwing. */\nasync function getKeyJson(\n baseUrl: string,\n secret: string,\n ctx: QuotaReadContext,\n timeoutMs: number,\n): Promise<unknown | undefined> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n const onAbort = () => controller.abort()\n ctx.signal?.addEventListener(\"abort\", onAbort)\n try {\n const res = await (ctx.fetchImpl ?? fetch)(`${baseUrl}/key`, {\n method: \"GET\",\n headers: { authorization: `Bearer ${secret}` },\n signal: controller.signal,\n })\n if (!res.ok) return undefined\n return await res.json()\n } catch {\n return undefined\n } finally {\n clearTimeout(timer)\n ctx.signal?.removeEventListener(\"abort\", onAbort)\n }\n}\n\n/**\n * OpenRouter quota reader: `GET /key` exposes the key's USD cap and remaining\n * headroom. The whole read is wrapped so it never throws; an uncapped key\n * (`limit_remaining` null/absent) yields no window and no credits.\n */\nexport function createOpenRouterQuotaReader(opts?: OpenRouterQuotaReaderOptions): QuotaReader {\n const baseUrl = opts?.baseUrl ?? DEFAULT_BASE_URL\n const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS\n\n return defineQuotaReader({\n id: \"openrouter-key\",\n supports: (profile: QuotaProfile): boolean =>\n profile.endpoint === \"openrouter\" && profile.method === \"api-key\",\n read: async (\n profile: QuotaProfile,\n ctx: QuotaReadContext,\n ): Promise<QuotaStatus | undefined> => {\n try {\n if (!profile.credentialRef) return undefined\n if (!ctx.resolveCredential) return undefined\n const secret = await ctx.resolveCredential(profile.credentialRef).catch(() => undefined)\n if (!secret) return undefined\n\n const body = await getKeyJson(baseUrl, secret, ctx, timeoutMs)\n if (body === undefined) return undefined\n const parsed = OPENROUTER_KEY_SCHEMA.safeParse(body)\n if (!parsed.success) return undefined\n\n const { limit, limit_remaining } = parsed.data.data\n const windows: QuotaWindow[] = []\n if (\n typeof limit === \"number\" &&\n Number.isFinite(limit) &&\n typeof limit_remaining === \"number\" &&\n Number.isFinite(limit_remaining)\n ) {\n const remainingPct = remainingPctFromCounts(limit_remaining, limit)\n if (remainingPct !== undefined) {\n windows.push({\n id: \"key_limit\",\n remainingPct,\n remaining: limit_remaining,\n limit,\n unit: \"USD\",\n })\n }\n }\n let credits: QuotaCredits | undefined\n if (typeof limit_remaining === \"number\" && Number.isFinite(limit_remaining)) {\n credits = { balanceUsd: limit_remaining, currency: \"USD\" }\n }\n\n return buildQuotaStatus({\n profileRef: profile.profileRef,\n basis: \"provider\",\n source: \"openrouter:/key\",\n now: ctx.now,\n windows,\n ...(credits !== undefined ? { credits } : {}),\n })\n } catch {\n return undefined\n }\n },\n })\n}\n","/**\n * @agentproto/model-intel — model intelligence primitives.\n *\n * Unified, provider-neutral quota status (AIP-67): one QuotaStatus shape with a\n * mandatory `basis`, a never-throw QuotaReader contract, and a reader registry.\n * Unknown is omitted, never fabricated.\n *\n * @see https://agentproto.sh/docs/aip-67\n */\n\nexport const SPEC_NAME = \"quota/v1\" as const\nexport const SPEC_VERSION = \"1.0.0-alpha\" as const\n\nexport {\n QUOTA_BASES,\n quotaCreditsSchema,\n quotaStatusSchema,\n quotaWindowSchema,\n} from \"./types.js\"\nexport type {\n QuotaBasis,\n QuotaCredits,\n QuotaProfile,\n QuotaReadContext,\n QuotaReader,\n QuotaStatus,\n QuotaWindow,\n} from \"./types.js\"\nexport {\n buildQuotaStatus,\n remainingPctFromCounts,\n remainingPctFromUsed,\n} from \"./build.js\"\nexport type { BuildQuotaStatusInput } from \"./build.js\"\nexport { QuotaReaderRegistry, defineQuotaReader } from \"./registry.js\"\nexport { quotaFromAnthropicHeaders } from \"./readers/anthropic.js\"\nexport { createOpenRouterQuotaReader } from \"./readers/openrouter.js\"\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/build.ts","../src/registry.ts","../src/readers/anthropic.ts","../src/readers/codex.ts","../src/readers/moonshot.ts","../src/readers/openrouter.ts","../src/index.ts"],"names":["remainingPct","z","DEFAULT_BASE_URL","DEFAULT_TIMEOUT_MS"],"mappings":"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","file":"index.mjs","sourcesContent":["import { z } from \"zod\"\n\n/**\n * Where a quota figure came from. `provider` is a documented provider\n * surface; `observed` is derived from this host's own traffic; `estimated`\n * is a local computation; `probe` is an undocumented surface reached through\n * a connector and MUST NOT be emitted by core readers.\n */\nexport const QUOTA_BASES = [\"provider\", \"probe\", \"observed\", \"estimated\"] as const\nexport type QuotaBasis = (typeof QUOTA_BASES)[number]\n\nconst isoTimestamp = z.string().refine((s) => !Number.isNaN(Date.parse(s)), {\n message: \"expected an ISO-8601 timestamp\",\n})\n\nexport const quotaWindowSchema = z.object({\n /** Open string: \"5h\", \"7d\", \"month\", \"minute\", \"day\", \"primary\", \"key_limit\", ... */\n id: z.string().min(1),\n /** 0-100. Required: a window that cannot state it is not emitted. */\n remainingPct: z.number().min(0).max(100),\n used: z.number().optional(),\n limit: z.number().optional(),\n remaining: z.number().optional(),\n unit: z.string().optional(),\n resetsAt: isoTimestamp.optional(),\n})\nexport type QuotaWindow = z.infer<typeof quotaWindowSchema>\n\nexport const quotaCreditsSchema = z.object({\n balanceUsd: z.number().optional(),\n unlimited: z.boolean().optional(),\n currency: z.string().min(1),\n})\nexport type QuotaCredits = z.infer<typeof quotaCreditsSchema>\n\nexport const quotaStatusSchema = z.object({\n profileRef: z.string().min(1),\n asOf: isoTimestamp,\n basis: z.enum(QUOTA_BASES),\n source: z.string().optional(),\n windows: z.array(quotaWindowSchema),\n credits: quotaCreditsSchema.optional(),\n})\nexport type QuotaStatus = z.infer<typeof quotaStatusSchema>\n\n/** The minimal auth-profile projection a reader needs. */\nexport interface QuotaProfile {\n profileRef: string\n endpoint: string\n method: \"oauth-bearer\" | \"api-key\"\n credentialRef?: string\n}\n\nexport interface QuotaReadContext {\n signal?: AbortSignal\n /** Resolve a profile's opaque credentialRef to a bearer secret. */\n resolveCredential?(ref: string): Promise<string | undefined>\n fetchImpl?: typeof fetch\n now?: () => Date\n}\n\n/**\n * Reads quota for a profile. MUST NOT throw: any failure or unknown value\n * resolves to `undefined`. Never fabricates a figure.\n */\nexport interface QuotaReader {\n readonly id: string\n supports(profile: QuotaProfile): boolean\n read(profile: QuotaProfile, ctx: QuotaReadContext): Promise<QuotaStatus | undefined>\n}\n","import type { QuotaBasis, QuotaCredits, QuotaStatus, QuotaWindow } from \"./types.js\"\nimport { quotaWindowSchema } from \"./types.js\"\n\n/** remainingPct from a used percentage, or undefined when it is not a finite 0-100 number. */\nexport function remainingPctFromUsed(usedPct: number | null | undefined): number | undefined {\n if (usedPct === null || usedPct === undefined || !Number.isFinite(usedPct)) return undefined\n if (usedPct < 0 || usedPct > 100) return undefined\n return 100 - usedPct\n}\n\n/** remainingPct from remaining/limit counts, or undefined when limit is not a positive finite number. */\nexport function remainingPctFromCounts(\n remaining: number | null | undefined,\n limit: number | null | undefined,\n): number | undefined {\n if (remaining === null || remaining === undefined || limit === null || limit === undefined) {\n return undefined\n }\n if (!Number.isFinite(remaining) || !Number.isFinite(limit) || limit <= 0) return undefined\n if (remaining < 0 || remaining > limit) return undefined\n return (remaining / limit) * 100\n}\n\nexport interface BuildQuotaStatusInput {\n profileRef: string\n basis: QuotaBasis\n source?: string\n now?: () => Date\n /** Candidate windows; any that fail validation are dropped, never repaired. */\n windows?: readonly unknown[]\n credits?: QuotaCredits\n}\n\n/**\n * Assemble a QuotaStatus. Invalid windows are omitted. Returns `undefined`\n * when there is nothing to report (no valid window and no credits).\n */\nexport function buildQuotaStatus(input: BuildQuotaStatusInput): QuotaStatus | undefined {\n const windows: QuotaWindow[] = []\n for (const candidate of input.windows ?? []) {\n const parsed = quotaWindowSchema.safeParse(candidate)\n if (parsed.success) windows.push(parsed.data)\n }\n if (windows.length === 0 && input.credits === undefined) return undefined\n return {\n profileRef: input.profileRef,\n asOf: (input.now ?? (() => new Date()))().toISOString(),\n basis: input.basis,\n ...(input.source !== undefined ? { source: input.source } : {}),\n windows,\n ...(input.credits !== undefined ? { credits: input.credits } : {}),\n }\n}\n","import type { QuotaProfile, QuotaReadContext, QuotaReader, QuotaStatus } from \"./types.js\"\n\n/** Identity helper that fixes the QuotaReader contract at definition time (AIP-43 handle). */\nexport function defineQuotaReader(reader: QuotaReader): QuotaReader {\n return reader\n}\n\nexport class QuotaReaderRegistry {\n private readonly readers = new Map<string, QuotaReader>()\n\n register(reader: QuotaReader): this {\n if (this.readers.has(reader.id)) {\n throw new Error(`quota reader already registered: ${reader.id}`)\n }\n this.readers.set(reader.id, reader)\n return this\n }\n\n list(): QuotaReader[] {\n return [...this.readers.values()]\n }\n\n /** First registered reader that supports the profile, in registration order. */\n find(profile: QuotaProfile): QuotaReader | undefined {\n for (const reader of this.readers.values()) {\n if (safeSupports(reader, profile)) return reader\n }\n return undefined\n }\n\n /** Read through the first supporting reader. Never throws; unknown -> undefined. */\n async read(profile: QuotaProfile, ctx: QuotaReadContext = {}): Promise<QuotaStatus | undefined> {\n const reader = this.find(profile)\n if (!reader) return undefined\n try {\n return await reader.read(profile, ctx)\n } catch {\n return undefined\n }\n }\n}\n\nfunction safeSupports(reader: QuotaReader, profile: QuotaProfile): boolean {\n try {\n return reader.supports(profile)\n } catch {\n return false\n }\n}\n","import { buildQuotaStatus, remainingPctFromCounts } from \"../build.js\"\nimport type { QuotaStatus } from \"../types.js\"\n\nexport interface AnthropicHeadersInput {\n profileRef: string\n headers: Headers | Record<string, string | undefined>\n now?: () => Date\n}\n\ninterface Dimension {\n id: string\n header: string\n unit: string\n}\n\nconst DIMENSIONS: readonly Dimension[] = [\n { id: \"requests-1m\", header: \"requests\", unit: \"requests\" },\n { id: \"tokens-1m\", header: \"tokens\", unit: \"tokens\" },\n { id: \"input-tokens-1m\", header: \"input-tokens\", unit: \"tokens\" },\n { id: \"output-tokens-1m\", header: \"output-tokens\", unit: \"tokens\" },\n]\n\n/** Read a header case-insensitively from a `Headers` or a plain record. */\nfunction headerGet(\n headers: Headers | Record<string, string | undefined>,\n name: string,\n): string | undefined {\n if (headers instanceof Headers) {\n return headers.get(name) ?? undefined\n }\n const lower = name.toLowerCase()\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lower) return value\n }\n return undefined\n}\n\n/** Parse a numeric rate-limit header; empty/garbage → undefined. */\nfunction parseCount(raw: string | undefined): number | undefined {\n if (raw === undefined) return undefined\n const trimmed = raw.trim()\n if (!trimmed) return undefined\n const n = Number(trimmed)\n return Number.isFinite(n) ? n : undefined\n}\n\n/** Normalize an RFC 3339 reset header to an ISO string; unparseable → undefined. */\nfunction parseReset(raw: string | undefined): string | undefined {\n if (raw === undefined) return undefined\n const trimmed = raw.trim()\n if (!trimmed) return undefined\n const date = new Date(trimmed)\n return Number.isNaN(date.getTime()) ? undefined : date.toISOString()\n}\n\n/**\n * PURE: build a QuotaStatus from Anthropic's DOCUMENTED rate-limit headers\n * `anthropic-ratelimit-{requests,tokens,input-tokens,output-tokens}-{limit,remaining,reset}`.\n * The undocumented `anthropic-ratelimit-unified-*` family is never read.\n * A dimension with a missing/non-numeric limit or remaining is skipped.\n */\nexport function quotaFromAnthropicHeaders(input: AnthropicHeadersInput): QuotaStatus | undefined {\n const windows: Record<string, unknown>[] = []\n for (const dimension of DIMENSIONS) {\n const prefix = `anthropic-ratelimit-${dimension.header}`\n const limit = parseCount(headerGet(input.headers, `${prefix}-limit`))\n const remaining = parseCount(headerGet(input.headers, `${prefix}-remaining`))\n if (limit === undefined || remaining === undefined) continue\n const remainingPct = remainingPctFromCounts(remaining, limit)\n if (remainingPct === undefined) continue\n const resetsAt = parseReset(headerGet(input.headers, `${prefix}-reset`))\n windows.push({\n id: dimension.id,\n remainingPct,\n limit,\n remaining,\n unit: dimension.unit,\n ...(resetsAt !== undefined ? { resetsAt } : {}),\n })\n }\n return buildQuotaStatus({\n profileRef: input.profileRef,\n basis: \"provider\",\n source: \"anthropic:ratelimit-headers\",\n now: input.now,\n windows,\n })\n}\n","import { buildQuotaStatus } from \"../build.js\"\nimport type { QuotaCredits, QuotaStatus, QuotaWindow } from \"../types.js\"\n\n/** One side of a Codex `rate_limits` payload. */\nexport interface CodexRateLimitWindow {\n used_percent: number\n window_minutes?: number\n /** Epoch seconds. */\n reset_at?: number\n}\n\nexport interface CodexRateLimits {\n primary?: CodexRateLimitWindow\n secondary?: CodexRateLimitWindow\n}\n\nexport interface CodexCredits {\n has_credits?: boolean\n unlimited?: boolean\n balance?: number\n}\n\nexport interface CodexRateLimitsInput {\n profileRef: string\n rateLimits: CodexRateLimits\n credits?: CodexCredits\n now?: () => Date\n}\n\n/** remainingPct clamped to 0..100; a used percentage >100 maps to 0, kept. */\nfunction remainingPct(used: number): number {\n return Math.max(0, Math.min(100, 100 - used))\n}\n\nfunction windowFromSide(id: string, side: CodexRateLimitWindow | undefined): QuotaWindow | undefined {\n if (!side || typeof side.used_percent !== \"number\" || !Number.isFinite(side.used_percent)) {\n return undefined\n }\n const window: QuotaWindow = { id, remainingPct: remainingPct(side.used_percent) }\n if (typeof side.reset_at === \"number\" && Number.isFinite(side.reset_at)) {\n const date = new Date(side.reset_at * 1000)\n if (!Number.isNaN(date.getTime())) window.resetsAt = date.toISOString()\n }\n return window\n}\n\n/**\n * Pure parser for a Codex `rate_limits` payload: each present side becomes one\n * window and optional credits become a credits block. Never throws; a missing\n * or non-numeric field is dropped, a valid value (0 included) is kept.\n */\nexport function quotaFromCodexRateLimits(\n input: CodexRateLimitsInput,\n): QuotaStatus | undefined {\n try {\n const windows: QuotaWindow[] = []\n const primary = windowFromSide(\"primary\", input.rateLimits?.primary)\n if (primary) windows.push(primary)\n const secondary = windowFromSide(\"secondary\", input.rateLimits?.secondary)\n if (secondary) windows.push(secondary)\n\n let credits: QuotaCredits | undefined\n const raw = input.credits\n if (raw) {\n const hasBalance = typeof raw.balance === \"number\" && Number.isFinite(raw.balance)\n if (raw.unlimited === true || hasBalance) {\n credits = { currency: \"USD\" }\n if (raw.unlimited === true) credits.unlimited = true\n if (hasBalance) credits.balanceUsd = raw.balance\n }\n }\n\n return buildQuotaStatus({\n profileRef: input.profileRef,\n basis: \"provider\",\n source: \"codex:rate_limits\",\n now: input.now,\n windows,\n ...(credits !== undefined ? { credits } : {}),\n })\n } catch {\n return undefined\n }\n}\n","import { z } from \"zod\"\nimport { buildQuotaStatus } from \"../build.js\"\nimport { defineQuotaReader } from \"../registry.js\"\nimport type { QuotaProfile, QuotaReadContext, QuotaReader, QuotaStatus } from \"../types.js\"\n\nconst DEFAULT_BASE_URL = \"https://api.moonshot.ai\"\nconst DEFAULT_TIMEOUT_MS = 4000\n\nconst MOONSHOT_BALANCE_SCHEMA = z\n .object({\n data: z\n .object({\n available_balance: z.number(),\n })\n .passthrough(),\n })\n .passthrough()\n\nexport interface MoonshotQuotaReaderOptions {\n baseUrl?: string\n timeoutMs?: number\n}\n\n/** GET `${baseUrl}/v1/users/me/balance` and parse the body, never throwing. */\nasync function getBalanceJson(\n baseUrl: string,\n secret: string,\n ctx: QuotaReadContext,\n timeoutMs: number,\n): Promise<unknown | undefined> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n const onAbort = () => controller.abort()\n ctx.signal?.addEventListener(\"abort\", onAbort)\n try {\n const res = await (ctx.fetchImpl ?? fetch)(`${baseUrl}/v1/users/me/balance`, {\n method: \"GET\",\n headers: { authorization: `Bearer ${secret}` },\n signal: controller.signal,\n })\n if (!res.ok) return undefined\n return await res.json()\n } catch {\n return undefined\n } finally {\n clearTimeout(timer)\n ctx.signal?.removeEventListener(\"abort\", onAbort)\n }\n}\n\n/**\n * Moonshot balance reader: `GET /v1/users/me/balance` exposes the account's\n * available USD balance, but no cap, so it is reported as credits-only (no\n * window). The whole read never throws; a balance of 0 or below is real data\n * and is kept as is.\n */\nexport function createMoonshotQuotaReader(opts?: MoonshotQuotaReaderOptions): QuotaReader {\n const baseUrl = opts?.baseUrl ?? DEFAULT_BASE_URL\n const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS\n\n return defineQuotaReader({\n id: \"moonshot-balance\",\n supports: (profile: QuotaProfile): boolean =>\n profile.endpoint === \"moonshot\" && profile.method === \"api-key\",\n read: async (\n profile: QuotaProfile,\n ctx: QuotaReadContext,\n ): Promise<QuotaStatus | undefined> => {\n try {\n if (!profile.credentialRef) return undefined\n if (!ctx.resolveCredential) return undefined\n const secret = await ctx.resolveCredential(profile.credentialRef).catch(() => undefined)\n if (!secret) return undefined\n\n const body = await getBalanceJson(baseUrl, secret, ctx, timeoutMs)\n if (body === undefined) return undefined\n const parsed = MOONSHOT_BALANCE_SCHEMA.safeParse(body)\n if (!parsed.success) return undefined\n\n const balance = parsed.data.data.available_balance\n if (!Number.isFinite(balance)) return undefined\n\n return buildQuotaStatus({\n profileRef: profile.profileRef,\n basis: \"provider\",\n source: \"moonshot:/users/me/balance\",\n now: ctx.now,\n windows: [],\n credits: { balanceUsd: balance, currency: \"USD\" },\n })\n } catch {\n return undefined\n }\n },\n })\n}\n","import { z } from \"zod\"\nimport { buildQuotaStatus, remainingPctFromCounts } from \"../build.js\"\nimport { defineQuotaReader } from \"../registry.js\"\nimport type { QuotaCredits, QuotaProfile, QuotaReadContext, QuotaReader, QuotaStatus, QuotaWindow } from \"../types.js\"\n\nconst DEFAULT_BASE_URL = \"https://openrouter.ai/api/v1\"\nconst DEFAULT_TIMEOUT_MS = 4000\n\nconst OPENROUTER_KEY_SCHEMA = z\n .object({\n data: z\n .object({\n limit: z.number().nullable().optional(),\n limit_remaining: z.number().nullable().optional(),\n })\n .passthrough(),\n })\n .passthrough()\n\nexport interface OpenRouterQuotaReaderOptions {\n baseUrl?: string\n timeoutMs?: number\n}\n\n/** GET `${baseUrl}/key` and parse the body, never throwing. */\nasync function getKeyJson(\n baseUrl: string,\n secret: string,\n ctx: QuotaReadContext,\n timeoutMs: number,\n): Promise<unknown | undefined> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n const onAbort = () => controller.abort()\n ctx.signal?.addEventListener(\"abort\", onAbort)\n try {\n const res = await (ctx.fetchImpl ?? fetch)(`${baseUrl}/key`, {\n method: \"GET\",\n headers: { authorization: `Bearer ${secret}` },\n signal: controller.signal,\n })\n if (!res.ok) return undefined\n return await res.json()\n } catch {\n return undefined\n } finally {\n clearTimeout(timer)\n ctx.signal?.removeEventListener(\"abort\", onAbort)\n }\n}\n\n/**\n * OpenRouter quota reader: `GET /key` exposes the key's USD cap and remaining\n * headroom. The whole read is wrapped so it never throws; an uncapped key\n * (`limit_remaining` null/absent) yields no window and no credits.\n */\nexport function createOpenRouterQuotaReader(opts?: OpenRouterQuotaReaderOptions): QuotaReader {\n const baseUrl = opts?.baseUrl ?? DEFAULT_BASE_URL\n const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS\n\n return defineQuotaReader({\n id: \"openrouter-key\",\n supports: (profile: QuotaProfile): boolean =>\n profile.endpoint === \"openrouter\" && profile.method === \"api-key\",\n read: async (\n profile: QuotaProfile,\n ctx: QuotaReadContext,\n ): Promise<QuotaStatus | undefined> => {\n try {\n if (!profile.credentialRef) return undefined\n if (!ctx.resolveCredential) return undefined\n const secret = await ctx.resolveCredential(profile.credentialRef).catch(() => undefined)\n if (!secret) return undefined\n\n const body = await getKeyJson(baseUrl, secret, ctx, timeoutMs)\n if (body === undefined) return undefined\n const parsed = OPENROUTER_KEY_SCHEMA.safeParse(body)\n if (!parsed.success) return undefined\n\n const { limit, limit_remaining } = parsed.data.data\n const windows: QuotaWindow[] = []\n if (\n typeof limit === \"number\" &&\n Number.isFinite(limit) &&\n typeof limit_remaining === \"number\" &&\n Number.isFinite(limit_remaining)\n ) {\n const remainingPct = remainingPctFromCounts(limit_remaining, limit)\n if (remainingPct !== undefined) {\n windows.push({\n id: \"key_limit\",\n remainingPct,\n remaining: limit_remaining,\n limit,\n unit: \"USD\",\n })\n }\n }\n let credits: QuotaCredits | undefined\n if (typeof limit_remaining === \"number\" && Number.isFinite(limit_remaining)) {\n credits = { balanceUsd: limit_remaining, currency: \"USD\" }\n }\n\n return buildQuotaStatus({\n profileRef: profile.profileRef,\n basis: \"provider\",\n source: \"openrouter:/key\",\n now: ctx.now,\n windows,\n ...(credits !== undefined ? { credits } : {}),\n })\n } catch {\n return undefined\n }\n },\n })\n}\n","/**\n * @agentproto/model-intel — model intelligence primitives.\n *\n * Unified, provider-neutral quota status (AIP-67): one QuotaStatus shape with a\n * mandatory `basis`, a never-throw QuotaReader contract, and a reader registry.\n * Unknown is omitted, never fabricated.\n *\n * @see https://agentproto.sh/docs/aip-67\n */\n\nexport const SPEC_NAME = \"quota/v1\" as const\nexport const SPEC_VERSION = \"1.0.0-alpha\" as const\n\nexport {\n QUOTA_BASES,\n quotaCreditsSchema,\n quotaStatusSchema,\n quotaWindowSchema,\n} from \"./types.js\"\nexport type {\n QuotaBasis,\n QuotaCredits,\n QuotaProfile,\n QuotaReadContext,\n QuotaReader,\n QuotaStatus,\n QuotaWindow,\n} from \"./types.js\"\nexport {\n buildQuotaStatus,\n remainingPctFromCounts,\n remainingPctFromUsed,\n} from \"./build.js\"\nexport type { BuildQuotaStatusInput } from \"./build.js\"\nexport { QuotaReaderRegistry, defineQuotaReader } from \"./registry.js\"\nexport { quotaFromAnthropicHeaders } from \"./readers/anthropic.js\"\nexport { quotaFromCodexRateLimits } from \"./readers/codex.js\"\nexport type {\n CodexCredits,\n CodexRateLimits,\n CodexRateLimitsInput,\n CodexRateLimitWindow,\n} from \"./readers/codex.js\"\nexport { createMoonshotQuotaReader } from \"./readers/moonshot.js\"\nexport { createOpenRouterQuotaReader } from \"./readers/openrouter.js\"\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentproto/model-intel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "@agentproto/model-intel — model intelligence primitives. Unified, provider-neutral quota status (AIP-67): a QuotaStatus shape with a mandatory basis, a never-throw QuotaReader contract, and a reader registry. Unknown is omitted, never fabricated.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agentproto",
|