@convex-dev/ai-budget 0.0.2-alpha.4 → 0.0.2-alpha.5

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.
@@ -39,14 +39,30 @@ function extractUsage(usage) {
39
39
  return {
40
40
  promptTokens: toTokenCount(usage?.inputTokens ?? usage?.promptTokens),
41
41
  completionTokens: toTokenCount(usage?.outputTokens ?? usage?.completionTokens),
42
- // cached prompt tokens: AI SDK v5 `cachedInputTokens`, OpenAI-compat
43
- // `prompt_tokens_details.cached_tokens` / `cached_tokens`.
44
- cachedTokens: toTokenCount(usage?.cachedInputTokens ??
42
+ // cached prompt tokens. The Convex gateway reports these at
43
+ // `usage.inputTokenDetails.cacheReadTokens`; the other paths cover AI SDK v5
44
+ // (`cachedInputTokens`) and raw OpenAI-compatible shapes.
45
+ cachedTokens: toTokenCount(usage?.inputTokenDetails?.cacheReadTokens ??
46
+ usage?.cachedInputTokens ??
45
47
  usage?.promptTokensDetails?.cachedTokens ??
46
48
  usage?.prompt_tokens_details?.cached_tokens ??
47
49
  usage?.cached_tokens),
48
50
  };
49
51
  }
52
+ // The gateway doesn't report a dollar cost today, but if a future response ever
53
+ // carries an unambiguous nanodollar cost we pass it straight through as
54
+ // authoritative (finishRequest prefers it over the token-based estimate). Only
55
+ // an explicitly nano-denominated field is trusted — a bare `cost` could be in
56
+ // dollars and silently mis-bill by 1e9×.
57
+ function extractGatewayCostNanos(result) {
58
+ const meta = result?.providerMetadata?.convexGateway;
59
+ const candidates = [meta?.costNanos, result?.usage?.costNanos];
60
+ for (const c of candidates) {
61
+ if (typeof c === "number" && Number.isFinite(c) && c >= 0)
62
+ return c;
63
+ }
64
+ return undefined;
65
+ }
50
66
  // Flatten an AI SDK prompt (roles + content parts) into simple storable messages.
51
67
  function simplifyPrompt(prompt) {
52
68
  if (!Array.isArray(prompt))
@@ -78,24 +94,46 @@ function extractText(result) {
78
94
  }
79
95
  return "";
80
96
  }
81
- // ---------- client ----------
82
97
  export class AIBudget {
83
98
  component;
84
99
  defaultModel;
85
100
  onSoftLimit;
101
+ onThreshold;
102
+ onLimitReached;
86
103
  constructor(component, options) {
87
104
  this.component = component;
88
105
  this.defaultModel = options?.defaultModel ?? "openai/gpt-4o-mini";
89
106
  this.onSoftLimit = options?.onSoftLimit;
107
+ this.onThreshold = options?.onThreshold;
108
+ this.onLimitReached = options?.onLimitReached;
90
109
  }
91
- async fireSoftLimit(info) {
92
- if (info.warnings.length === 0 || !this.onSoftLimit)
110
+ // Fire the soft-limit + threshold callbacks from a startRequest result.
111
+ async fireBudgetEvents(base, warnings, notices) {
112
+ if (warnings.length > 0 && this.onSoftLimit) {
113
+ try {
114
+ await this.onSoftLimit({ ...base, messages: warnings, warnings });
115
+ }
116
+ catch {
117
+ /* never let a callback error break a request */
118
+ }
119
+ }
120
+ if (notices.length > 0 && this.onThreshold) {
121
+ try {
122
+ await this.onThreshold({ ...base, messages: notices });
123
+ }
124
+ catch {
125
+ /* swallow */
126
+ }
127
+ }
128
+ }
129
+ async fireLimitReached(info) {
130
+ if (!this.onLimitReached)
93
131
  return;
94
132
  try {
95
- await this.onSoftLimit(info);
133
+ await this.onLimitReached(info);
96
134
  }
97
135
  catch {
98
- // never let a callback error break a request
136
+ /* swallow */
99
137
  }
100
138
  }
101
139
  /**
@@ -116,6 +154,14 @@ export class AIBudget {
116
154
  rerunOf: args.rerunOf,
117
155
  });
118
156
  if (!started.allowed) {
157
+ await this.fireLimitReached({
158
+ userId,
159
+ action: actionName,
160
+ tags: args.tags,
161
+ messages: [started.reason],
162
+ code: started.code,
163
+ reason: started.reason,
164
+ });
119
165
  throw new ConvexError({
120
166
  kind: "AIBudgetLimit",
121
167
  code: started.code,
@@ -124,13 +170,8 @@ export class AIBudget {
124
170
  }
125
171
  const requestId = started.requestId;
126
172
  const warnings = started.warnings;
127
- await this.fireSoftLimit({
128
- userId,
129
- action: actionName,
130
- tags: args.tags,
131
- requestId,
132
- warnings,
133
- });
173
+ const notices = started.notices;
174
+ await this.fireBudgetEvents({ userId, action: actionName, tags: args.tags, requestId }, warnings, notices);
134
175
  const start = Date.now();
135
176
  try {
136
177
  // The full chain (incl. system) is stored on the request for audit/replay,
@@ -150,9 +191,10 @@ export class AIBudget {
150
191
  requestId,
151
192
  responseText: result.text,
152
193
  ...usage,
194
+ costNanos: extractGatewayCostNanos(result),
153
195
  latencyMs: Date.now() - start,
154
196
  });
155
- return { text: result.text, requestId, costNanos, warnings, ...usage };
197
+ return { text: result.text, requestId, costNanos, warnings, notices, ...usage };
156
198
  }
157
199
  catch (e) {
158
200
  await ctx.runMutation(this.component.lib.finishRequest, {
@@ -172,10 +214,12 @@ export class AIBudget {
172
214
  languageModel(ctx, opts = {}) {
173
215
  const modelId = opts.model ?? this.defaultModel;
174
216
  const component = this.component;
175
- const fireSoftLimit = this.fireSoftLimit.bind(this);
217
+ const fireBudgetEvents = this.fireBudgetEvents.bind(this);
218
+ const fireLimitReached = this.fireLimitReached.bind(this);
176
219
  const begin = async (params) => {
177
220
  const userId = await resolveUserId(ctx, opts.userId);
178
221
  const actionName = await resolveActionName(ctx, opts.action);
222
+ const base = { userId, action: actionName, tags: opts.tags };
179
223
  const started = await ctx.runMutation(component.lib.startRequest, {
180
224
  userId,
181
225
  actionName,
@@ -184,19 +228,19 @@ export class AIBudget {
184
228
  messages: simplifyPrompt(params.prompt),
185
229
  });
186
230
  if (!started.allowed) {
231
+ await fireLimitReached({
232
+ ...base,
233
+ messages: [started.reason],
234
+ code: started.code,
235
+ reason: started.reason,
236
+ });
187
237
  throw new ConvexError({
188
238
  kind: "AIBudgetLimit",
189
239
  code: started.code,
190
240
  reason: started.reason,
191
241
  });
192
242
  }
193
- await fireSoftLimit({
194
- userId,
195
- action: actionName,
196
- tags: opts.tags,
197
- requestId: started.requestId,
198
- warnings: started.warnings,
199
- });
243
+ await fireBudgetEvents({ ...base, requestId: started.requestId }, started.warnings, started.notices);
200
244
  return started.requestId;
201
245
  };
202
246
  const finish = async (requestId, fields) => ctx.runMutation(component.lib.finishRequest, { requestId, ...fields });
@@ -211,6 +255,7 @@ export class AIBudget {
211
255
  await finish(requestId, {
212
256
  responseText: extractText(result),
213
257
  ...extractUsage(result.usage),
258
+ costNanos: extractGatewayCostNanos(result),
214
259
  latencyMs: Date.now() - start,
215
260
  });
216
261
  return result;
@@ -295,6 +340,7 @@ export class AIBudget {
295
340
  get requests() {
296
341
  const c = this.component;
297
342
  return {
343
+ /** Filter by userId, or by any {dimension, value} (incl. custom tags). */
298
344
  list: (ctx, args = {}) => ctx.runQuery(c.lib.listRequests, args),
299
345
  /** Ancestors up to the original, plus direct re-runs. */
300
346
  lineage: (ctx, args) => ctx.runQuery(c.lib.lineage, { requestId: args.requestId }),
@@ -307,74 +353,73 @@ export class AIBudget {
307
353
  * generalization of `users`/`actions`. Give it any dimension name (team,
308
354
  * project, tenant, customer, env, feature, …) and set caps per value:
309
355
  *
310
- * ai.tag("customer").setLimits(ctx, { value: "acme", dailySpendLimitNanos });
311
- * ai.tag("customer").list(ctx);
356
+ * ai.tag("customer").setLimits(ctx, { value: "acme", monthlySpendLimitNanos });
357
+ * ai.tag("customer").history(ctx, { value: "acme", period: "day" });
312
358
  *
313
359
  * Attribute a call to it by passing `tags` to `chat`/`languageModel`.
314
360
  */
315
361
  tag(dimension) {
362
+ return this.dimensionApi(dimension, (a) => a.value);
363
+ }
364
+ // Shared implementation behind tag()/users/actions. `key` maps the namespace's
365
+ // id field (value/userId/name) to the bucket value.
366
+ dimensionApi(dimension, key) {
316
367
  const c = this.component;
317
368
  return {
318
369
  /** All buckets in this dimension. */
319
370
  list: (ctx) => ctx.runQuery(c.lib.listBuckets, { dimension }),
320
371
  /** One bucket's limits + spend (null if it has none yet). */
321
- get: (ctx, args) => ctx.runQuery(c.lib.getBucket, { dimension, value: args.value }),
322
- setLimits: (ctx, args) => ctx.runMutation(c.lib.setBucketLimits, { dimension, ...args }),
323
- /** One-time "approve another $X" bump (daily is today-only). */
324
- bump: (ctx, args) => ctx.runMutation(c.lib.bumpBucket, { dimension, ...args }),
325
- /** Delete the bucket (for "user", also its request rows). */
326
- delete: (ctx, args) => ctx.runMutation(c.lib.deleteBucket, { dimension, value: args.value }),
327
- };
328
- }
329
- /** Per-user budgets and controls — sugar over the "user" dimension. */
330
- get users() {
331
- const c = this.component;
332
- return {
333
- list: (ctx) => ctx.runQuery(c.lib.listBuckets, { dimension: "user" }),
372
+ get: (ctx, args) => ctx.runQuery(c.lib.getBucket, { dimension, value: key(args) }),
334
373
  setLimits: (ctx, args) => {
335
- const { userId, ...limits } = args;
374
+ const { value, userId, name, ...limits } = args;
336
375
  return ctx.runMutation(c.lib.setBucketLimits, {
337
- dimension: "user",
338
- value: userId,
376
+ dimension,
377
+ value: key(args),
339
378
  ...limits,
340
379
  });
341
380
  },
342
- /** One-time "approve another $X" bump (daily is today-only). */
381
+ /** One-time "approve another $X" bump (daily/monthly reset with the window). */
343
382
  bump: (ctx, args) => ctx.runMutation(c.lib.bumpBucket, {
344
- dimension: "user",
345
- value: args.userId,
383
+ dimension,
384
+ value: key(args),
346
385
  dailyNanos: args.dailyNanos,
386
+ monthlyNanos: args.monthlyNanos,
347
387
  lifetimeNanos: args.lifetimeNanos,
348
388
  }),
349
- /** Delete a user and all their request rows. */
350
- delete: (ctx, args) => ctx.runMutation(c.lib.deleteBucket, {
351
- dimension: "user",
352
- value: args.userId,
389
+ /** Manually credit (negative) or debit (positive) this bucket. */
390
+ adjust: (ctx, args) => ctx.runMutation(c.lib.adjustBucket, {
391
+ dimension,
392
+ value: key(args),
393
+ deltaNanos: args.deltaNanos,
394
+ tokens: args.tokens,
395
+ reason: args.reason,
353
396
  }),
397
+ /** Durable spend history for this bucket (per day or per month). */
398
+ history: (ctx, args) => ctx.runQuery(c.lib.usageHistory, {
399
+ dimension,
400
+ value: key(args),
401
+ period: args.period ?? "day",
402
+ limit: args.limit,
403
+ }),
404
+ /** Manual-adjustment audit log for this bucket. */
405
+ adjustments: (ctx, args) => ctx.runQuery(c.lib.listAdjustments, {
406
+ dimension,
407
+ value: key(args),
408
+ limit: args.limit,
409
+ }),
410
+ /** Delete the bucket (for "user", also its request rows). */
411
+ delete: (ctx, args) => ctx.runMutation(c.lib.deleteBucket, { dimension, value: key(args) }),
354
412
  };
355
413
  }
414
+ /** Per-user budgets and controls — sugar over the "user" dimension. */
415
+ get users() {
416
+ return this.dimensionApi("user", (a) => a.userId);
417
+ }
356
418
  /** Per-action (per-feature) budgets — sugar over the "action" dimension. */
357
419
  get actions() {
358
- const c = this.component;
359
- return {
360
- list: (ctx) => ctx.runQuery(c.lib.listBuckets, { dimension: "action" }),
361
- setLimits: (ctx, args) => {
362
- const { name, ...limits } = args;
363
- return ctx.runMutation(c.lib.setBucketLimits, {
364
- dimension: "action",
365
- value: name,
366
- ...limits,
367
- });
368
- },
369
- bump: (ctx, args) => ctx.runMutation(c.lib.bumpBucket, {
370
- dimension: "action",
371
- value: args.name,
372
- dailyNanos: args.dailyNanos,
373
- lifetimeNanos: args.lifetimeNanos,
374
- }),
375
- };
420
+ return this.dimensionApi("action", (a) => a.name);
376
421
  }
377
- /** The deployment-wide budget and retention config. */
422
+ /** The deployment-wide budget, alerts, and retention config. */
378
423
  get global() {
379
424
  const c = this.component;
380
425
  return {
@@ -383,6 +428,8 @@ export class AIBudget {
383
428
  /** A killswitch spend cap across all users/actions (enforced approximately). */
384
429
  setLimits: (ctx, args) => ctx.runMutation(c.lib.setGlobalLimits, args),
385
430
  bump: (ctx, args) => ctx.runMutation(c.lib.bumpGlobal, args),
431
+ /** Default approaching-limit alert threshold (fraction of a cap, e.g. 0.8). */
432
+ setAlertDefaults: (ctx, args) => ctx.runMutation(c.lib.setAlertDefaults, args),
386
433
  /** Request-row retention window in ms (default 1h; 0 disables). */
387
434
  setRetention: (ctx, args) => ctx.runMutation(c.lib.setRetention, args),
388
435
  };
@@ -20,15 +20,24 @@ import type { FunctionReference } from "convex/server";
20
20
  */
21
21
  export type ComponentApi<Name extends string | undefined = string | undefined> = {
22
22
  lib: {
23
+ adjustBucket: FunctionReference<"mutation", "internal", {
24
+ deltaNanos: number;
25
+ dimension: string;
26
+ reason?: string;
27
+ tokens?: number;
28
+ value: string;
29
+ }, null, Name>;
23
30
  bumpBucket: FunctionReference<"mutation", "internal", {
24
31
  dailyNanos?: number;
25
32
  dimension: string;
26
33
  lifetimeNanos?: number;
34
+ monthlyNanos?: number;
27
35
  value: string;
28
36
  }, null, Name>;
29
37
  bumpGlobal: FunctionReference<"mutation", "internal", {
30
38
  dailyNanos?: number;
31
39
  lifetimeNanos?: number;
40
+ monthlyNanos?: number;
32
41
  }, null, Name>;
33
42
  deleteBucket: FunctionReference<"mutation", "internal", {
34
43
  dimension: string;
@@ -40,6 +49,7 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
40
49
  finishRequest: FunctionReference<"mutation", "internal", {
41
50
  cachedTokens?: number;
42
51
  completionTokens?: number;
52
+ costNanos?: number;
43
53
  error?: string;
44
54
  latencyMs?: number;
45
55
  promptTokens?: number;
@@ -69,14 +79,24 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
69
79
  lineage: FunctionReference<"query", "internal", {
70
80
  requestId: string;
71
81
  }, any, Name>;
82
+ listAdjustments: FunctionReference<"query", "internal", {
83
+ dimension: string;
84
+ limit?: number;
85
+ value: string;
86
+ }, any, Name>;
72
87
  listBuckets: FunctionReference<"query", "internal", {
73
88
  dimension?: string;
74
89
  }, any, Name>;
75
90
  listPrices: FunctionReference<"query", "internal", {}, any, Name>;
76
91
  listRequests: FunctionReference<"query", "internal", {
92
+ dimension?: string;
77
93
  limit?: number;
78
94
  userId?: string;
95
+ value?: string;
79
96
  }, any, Name>;
97
+ setAlertDefaults: FunctionReference<"mutation", "internal", {
98
+ warnAtPct?: number;
99
+ }, null, Name>;
80
100
  setBucketLimits: FunctionReference<"mutation", "internal", {
81
101
  blocked?: boolean;
82
102
  dailySpendLimitNanos?: number;
@@ -85,8 +105,12 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
85
105
  enforcement?: "hard" | "soft";
86
106
  lifetimeSpendLimitNanos?: number;
87
107
  lifetimeTokenLimit?: number;
108
+ maxConcurrent?: number;
109
+ monthlySpendLimitNanos?: number;
110
+ monthlyTokenLimit?: number;
88
111
  requestsPerMinute?: number;
89
112
  value: string;
113
+ warnAtPct?: number;
90
114
  }, null, Name>;
91
115
  setGlobalLimits: FunctionReference<"mutation", "internal", {
92
116
  dailySpendLimitNanos?: number;
@@ -98,6 +122,7 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
98
122
  models: Array<string>;
99
123
  }, null, Name>;
100
124
  setPrice: FunctionReference<"mutation", "internal", {
125
+ cachedNanosPerMTok?: number;
101
126
  inputNanosPerMTok: number;
102
127
  model: string;
103
128
  outputNanosPerMTok: number;
@@ -120,6 +145,7 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
120
145
  userId: string;
121
146
  }, {
122
147
  allowed: true;
148
+ notices: Array<string>;
123
149
  requestId: string;
124
150
  warnings: Array<string>;
125
151
  } | {
@@ -127,5 +153,11 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
127
153
  code: string;
128
154
  reason: string;
129
155
  }, Name>;
156
+ usageHistory: FunctionReference<"query", "internal", {
157
+ dimension: string;
158
+ limit?: number;
159
+ period: "day" | "month";
160
+ value: string;
161
+ }, any, Name>;
130
162
  };
131
163
  };
@@ -19,6 +19,7 @@ export declare const startRequest: import("convex/server").RegisteredMutation<"p
19
19
  allowed: true;
20
20
  requestId: import("convex/values").GenericId<"requests">;
21
21
  warnings: string[];
22
+ notices: string[];
22
23
  }>>;
23
24
  export declare const finishRequest: import("convex/server").RegisteredMutation<"public", {
24
25
  error?: string | undefined;
@@ -26,6 +27,7 @@ export declare const finishRequest: import("convex/server").RegisteredMutation<"
26
27
  promptTokens?: number | undefined;
27
28
  completionTokens?: number | undefined;
28
29
  cachedTokens?: number | undefined;
30
+ costNanos?: number | undefined;
29
31
  latencyMs?: number | undefined;
30
32
  requestId: import("convex/values").GenericId<"requests">;
31
33
  }, Promise<{
@@ -136,6 +138,8 @@ export declare const getRequest: import("convex/server").RegisteredQuery<"public
136
138
  status: "blocked" | "pending" | "success" | "error";
137
139
  } | null>>;
138
140
  export declare const listRequests: import("convex/server").RegisteredQuery<"public", {
141
+ dimension?: string | undefined;
142
+ value?: string | undefined;
139
143
  userId?: string | undefined;
140
144
  limit?: number | undefined;
141
145
  }, Promise<{
@@ -171,22 +175,33 @@ export declare const listBuckets: import("convex/server").RegisteredQuery<"publi
171
175
  dimension?: string | undefined;
172
176
  }, Promise<{
173
177
  spendTodayNanos: number;
178
+ spendThisMonthNanos: number;
174
179
  _id: import("convex/values").GenericId<"buckets">;
175
180
  _creationTime: number;
176
181
  requestsPerMinute?: number | undefined;
182
+ maxConcurrent?: number | undefined;
177
183
  dailySpendLimitNanos?: number | undefined;
184
+ monthlySpendLimitNanos?: number | undefined;
178
185
  lifetimeSpendLimitNanos?: number | undefined;
179
186
  dailyTokenLimit?: number | undefined;
187
+ monthlyTokenLimit?: number | undefined;
180
188
  lifetimeTokenLimit?: number | undefined;
181
189
  blocked?: boolean | undefined;
190
+ warnAtPct?: number | undefined;
182
191
  enforcement?: "hard" | "soft" | undefined;
183
192
  dailyBumpNanos?: number | undefined;
193
+ monthlyBumpNanos?: number | undefined;
184
194
  lifetimeBumpNanos?: number | undefined;
185
195
  bumpDayStamp?: string | undefined;
196
+ bumpMonthStamp?: string | undefined;
186
197
  tokensToday?: number | undefined;
198
+ monthStamp?: string | undefined;
199
+ tokensThisMonth?: number | undefined;
187
200
  reservedTodayNanos?: number | undefined;
201
+ reservedMonthNanos?: number | undefined;
188
202
  reservedTotalNanos?: number | undefined;
189
203
  reservedTodayTokens?: number | undefined;
204
+ reservedMonthTokens?: number | undefined;
190
205
  reservedTotalTokens?: number | undefined;
191
206
  pendingCount?: number | undefined;
192
207
  dimension: string;
@@ -201,22 +216,33 @@ export declare const getBucket: import("convex/server").RegisteredQuery<"public"
201
216
  value: string;
202
217
  }, Promise<{
203
218
  spendTodayNanos: number;
219
+ spendThisMonthNanos: number;
204
220
  _id: import("convex/values").GenericId<"buckets">;
205
221
  _creationTime: number;
206
222
  requestsPerMinute?: number | undefined;
223
+ maxConcurrent?: number | undefined;
207
224
  dailySpendLimitNanos?: number | undefined;
225
+ monthlySpendLimitNanos?: number | undefined;
208
226
  lifetimeSpendLimitNanos?: number | undefined;
209
227
  dailyTokenLimit?: number | undefined;
228
+ monthlyTokenLimit?: number | undefined;
210
229
  lifetimeTokenLimit?: number | undefined;
211
230
  blocked?: boolean | undefined;
231
+ warnAtPct?: number | undefined;
212
232
  enforcement?: "hard" | "soft" | undefined;
213
233
  dailyBumpNanos?: number | undefined;
234
+ monthlyBumpNanos?: number | undefined;
214
235
  lifetimeBumpNanos?: number | undefined;
215
236
  bumpDayStamp?: string | undefined;
237
+ bumpMonthStamp?: string | undefined;
216
238
  tokensToday?: number | undefined;
239
+ monthStamp?: string | undefined;
240
+ tokensThisMonth?: number | undefined;
217
241
  reservedTodayNanos?: number | undefined;
242
+ reservedMonthNanos?: number | undefined;
218
243
  reservedTotalNanos?: number | undefined;
219
244
  reservedTodayTokens?: number | undefined;
245
+ reservedMonthTokens?: number | undefined;
220
246
  reservedTotalTokens?: number | undefined;
221
247
  pendingCount?: number | undefined;
222
248
  dimension: string;
@@ -228,21 +254,65 @@ export declare const getBucket: import("convex/server").RegisteredQuery<"public"
228
254
  } | null>>;
229
255
  export declare const setBucketLimits: import("convex/server").RegisteredMutation<"public", {
230
256
  requestsPerMinute?: number | undefined;
257
+ maxConcurrent?: number | undefined;
231
258
  dailySpendLimitNanos?: number | undefined;
259
+ monthlySpendLimitNanos?: number | undefined;
232
260
  lifetimeSpendLimitNanos?: number | undefined;
233
261
  dailyTokenLimit?: number | undefined;
262
+ monthlyTokenLimit?: number | undefined;
234
263
  lifetimeTokenLimit?: number | undefined;
235
264
  blocked?: boolean | undefined;
265
+ warnAtPct?: number | undefined;
236
266
  enforcement?: "hard" | "soft" | undefined;
237
267
  dimension: string;
238
268
  value: string;
239
269
  }, Promise<null>>;
240
270
  export declare const bumpBucket: import("convex/server").RegisteredMutation<"public", {
241
271
  dailyNanos?: number | undefined;
272
+ monthlyNanos?: number | undefined;
242
273
  lifetimeNanos?: number | undefined;
243
274
  dimension: string;
244
275
  value: string;
245
276
  }, Promise<null>>;
277
+ export declare const adjustBucket: import("convex/server").RegisteredMutation<"public", {
278
+ tokens?: number | undefined;
279
+ reason?: string | undefined;
280
+ dimension: string;
281
+ value: string;
282
+ deltaNanos: number;
283
+ }, Promise<null>>;
284
+ export declare const listAdjustments: import("convex/server").RegisteredQuery<"public", {
285
+ limit?: number | undefined;
286
+ dimension: string;
287
+ value: string;
288
+ }, Promise<{
289
+ _id: import("convex/values").GenericId<"adjustments">;
290
+ _creationTime: number;
291
+ tokens?: number | undefined;
292
+ reason?: string | undefined;
293
+ dimension: string;
294
+ value: string;
295
+ deltaNanos: number;
296
+ }[]>>;
297
+ export declare const usageHistory: import("convex/server").RegisteredQuery<"public", {
298
+ limit?: number | undefined;
299
+ dimension: string;
300
+ value: string;
301
+ period: "day" | "month";
302
+ }, Promise<{
303
+ _id: import("convex/values").GenericId<"usage">;
304
+ _creationTime: number;
305
+ dimension: string;
306
+ value: string;
307
+ period: "day" | "month";
308
+ stamp: string;
309
+ spendNanos: number;
310
+ tokens: number;
311
+ requests: number;
312
+ }[]>>;
313
+ export declare const setAlertDefaults: import("convex/server").RegisteredMutation<"public", {
314
+ warnAtPct?: number | undefined;
315
+ }, Promise<null>>;
246
316
  export declare const deleteBucket: import("convex/server").RegisteredMutation<"public", {
247
317
  dimension: string;
248
318
  value: string;
@@ -268,6 +338,7 @@ export declare const setGlobalLimits: import("convex/server").RegisteredMutation
268
338
  }, Promise<null>>;
269
339
  export declare const bumpGlobal: import("convex/server").RegisteredMutation<"public", {
270
340
  dailyNanos?: number | undefined;
341
+ monthlyNanos?: number | undefined;
271
342
  lifetimeNanos?: number | undefined;
272
343
  }, Promise<null>>;
273
344
  export declare const setModelPolicy: import("convex/server").RegisteredMutation<"public", {
@@ -275,6 +346,7 @@ export declare const setModelPolicy: import("convex/server").RegisteredMutation<
275
346
  mode: "open" | "allowlist" | "denylist";
276
347
  }, Promise<null>>;
277
348
  export declare const setPrice: import("convex/server").RegisteredMutation<"public", {
349
+ cachedNanosPerMTok?: number | undefined;
278
350
  model: string;
279
351
  inputNanosPerMTok: number;
280
352
  outputNanosPerMTok: number;
@@ -282,5 +354,6 @@ export declare const setPrice: import("convex/server").RegisteredMutation<"publi
282
354
  export declare const listPrices: import("convex/server").RegisteredQuery<"public", {}, Promise<Record<string, {
283
355
  input: number;
284
356
  output: number;
357
+ cached?: number;
285
358
  overridden: boolean;
286
359
  }>>>;