@convex-dev/ai-budget 0.0.2-alpha.3 → 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.
@@ -11,21 +11,44 @@ type UseApi<API> = Expand<{
11
11
  export type AIBudgetApi = UseApi<typeof api>;
12
12
  /** @deprecated use AIBudgetApi */
13
13
  export type AIGatewayApi = AIBudgetApi;
14
- /** Fired when a request is admitted over a *soft* limit. */
15
- export type SoftLimitInfo = {
14
+ /**
15
+ * One attribution tag: a (dimension, value) pair, e.g. {dimension:"customer",
16
+ * value:"acme"}. `user` and `action` are built-in dimensions (set via
17
+ * userId/action); use tags for anything else — team, project, tenant, env, ….
18
+ * Any tagged bucket can carry its own budget (see `ai.tag(dimension)`).
19
+ */
20
+ export type Tag = {
21
+ dimension: string;
22
+ value: string;
23
+ };
24
+ /** Common shape for budget-event callbacks. */
25
+ export type BudgetEventInfo = {
16
26
  userId: string;
17
27
  action?: string;
18
- requestId: string;
28
+ tags?: Tag[];
29
+ requestId?: string;
30
+ /** soft-cap warnings (onSoftLimit) or approaching-cap notices (onThreshold). */
31
+ messages: string[];
32
+ /** rejection code/reason (onLimitReached only). */
33
+ code?: string;
34
+ reason?: string;
35
+ };
36
+ /** @deprecated use BudgetEventInfo */
37
+ export type SoftLimitInfo = BudgetEventInfo & {
19
38
  warnings: string[];
20
39
  };
21
40
  export type AIBudgetOptions = {
22
41
  defaultModel?: string;
23
42
  /**
24
- * Called when a soft limit is exceeded (the request is still allowed). Lets
25
- * you surface budget warnings even on the languageModel/Agent path, where
26
- * they can't be returned. Errors thrown here are swallowed.
43
+ * A *soft* limit was exceeded (request still allowed). Lets you surface budget
44
+ * warnings even on the languageModel/Agent path where they can't be returned.
45
+ * Errors thrown in any of these callbacks are swallowed.
27
46
  */
28
47
  onSoftLimit?: (info: SoftLimitInfo) => void | Promise<void>;
48
+ /** Usage crossed a bucket's warnAtPct threshold (approaching a cap). */
49
+ onThreshold?: (info: BudgetEventInfo) => void | Promise<void>;
50
+ /** A *hard* limit blocked the request (fires just before chat/model throws). */
51
+ onLimitReached?: (info: BudgetEventInfo) => void | Promise<void>;
29
52
  };
30
53
  type RunQueryCtx = {
31
54
  runQuery: <Query extends FunctionReference<"query", "internal">>(query: Query, args: Query["_args"]) => Promise<Query["_returnType"]>;
@@ -56,13 +79,39 @@ export type ChatResult = {
56
79
  cachedTokens: number;
57
80
  /** Soft-limit warnings raised at admission (empty unless a soft cap was hit). */
58
81
  warnings: string[];
82
+ /** Approaching-cap notices (empty unless a warnAtPct threshold was crossed). */
83
+ notices: string[];
84
+ };
85
+ /** Limits/controls settable on any budget bucket (user, action, or tag). */
86
+ export type BucketLimits = {
87
+ requestsPerMinute?: number;
88
+ maxConcurrent?: number;
89
+ dailySpendLimitNanos?: number;
90
+ monthlySpendLimitNanos?: number;
91
+ lifetimeSpendLimitNanos?: number;
92
+ dailyTokenLimit?: number;
93
+ monthlyTokenLimit?: number;
94
+ lifetimeTokenLimit?: number;
95
+ /** Fire an approaching-limit alert at this fraction of a cap (e.g. 0.8). */
96
+ warnAtPct?: number;
97
+ enforcement?: "hard" | "soft";
98
+ blocked?: boolean;
99
+ };
100
+ /** One-time bump amounts, added on top of a standing cap. */
101
+ export type BumpArgs = {
102
+ dailyNanos?: number;
103
+ monthlyNanos?: number;
104
+ lifetimeNanos?: number;
59
105
  };
60
106
  export declare class AIBudget {
61
107
  component: AIBudgetApi;
62
108
  defaultModel: string;
63
109
  private onSoftLimit?;
110
+ private onThreshold?;
111
+ private onLimitReached?;
64
112
  constructor(component: AIBudgetApi, options?: AIBudgetOptions);
65
- private fireSoftLimit;
113
+ private fireBudgetEvents;
114
+ private fireLimitReached;
66
115
  /**
67
116
  * One-shot chat through the AI Gateway with tracking + limits.
68
117
  * Call from an action. `userId` defaults to the authenticated caller.
@@ -76,6 +125,8 @@ export declare class AIBudget {
76
125
  rerunOf?: string;
77
126
  /** Attribute spend to this action name. Defaults to the calling Convex action. */
78
127
  action?: string;
128
+ /** Extra attribution dimensions to bill/limit (team, customer, env, …). */
129
+ tags?: Tag[];
79
130
  }): Promise<ChatResult>;
80
131
  /**
81
132
  * An AI SDK LanguageModel that enforces limits and records usage/cost for
@@ -87,17 +138,26 @@ export declare class AIBudget {
87
138
  userId?: string;
88
139
  model?: string;
89
140
  action?: string;
141
+ /** Extra attribution dimensions to bill/limit (team, customer, env, …). */
142
+ tags?: Tag[];
90
143
  }): LanguageModel;
91
144
  private rerunImpl;
92
145
  /** The request audit log, replay, and re-run lineage. */
93
146
  get requests(): {
147
+ /** Filter by userId, or by any {dimension, value} (incl. custom tags). */
94
148
  list: (ctx: RunQueryCtx, args?: {
95
149
  userId?: string;
150
+ dimension?: string;
151
+ value?: string;
96
152
  limit?: number;
97
153
  }) => Promise<{
98
154
  _id: string;
99
155
  _creationTime: number;
100
156
  actionName?: string | undefined;
157
+ tags?: {
158
+ dimension: string;
159
+ value: string;
160
+ }[] | undefined;
101
161
  estimatedNanos?: number | undefined;
102
162
  estimatedTokens?: number | undefined;
103
163
  unpricedModel?: boolean | undefined;
@@ -127,6 +187,10 @@ export declare class AIBudget {
127
187
  _id: string;
128
188
  _creationTime: number;
129
189
  actionName?: string | undefined;
190
+ tags?: {
191
+ dimension: string;
192
+ value: string;
193
+ }[] | undefined;
130
194
  estimatedNanos?: number | undefined;
131
195
  estimatedTokens?: number | undefined;
132
196
  unpricedModel?: boolean | undefined;
@@ -152,6 +216,10 @@ export declare class AIBudget {
152
216
  _id: string;
153
217
  _creationTime: number;
154
218
  actionName?: string | undefined;
219
+ tags?: {
220
+ dimension: string;
221
+ value: string;
222
+ }[] | undefined;
155
223
  estimatedNanos?: number | undefined;
156
224
  estimatedTokens?: number | undefined;
157
225
  unpricedModel?: boolean | undefined;
@@ -181,51 +249,281 @@ export declare class AIBudget {
181
249
  model?: string;
182
250
  }) => Promise<ChatResult>;
183
251
  };
184
- /** Per-user budgets and controls. */
252
+ /**
253
+ * Budgets and controls for an arbitrary attribution dimension — the
254
+ * generalization of `users`/`actions`. Give it any dimension name (team,
255
+ * project, tenant, customer, env, feature, …) and set caps per value:
256
+ *
257
+ * ai.tag("customer").setLimits(ctx, { value: "acme", monthlySpendLimitNanos });
258
+ * ai.tag("customer").history(ctx, { value: "acme", period: "day" });
259
+ *
260
+ * Attribute a call to it by passing `tags` to `chat`/`languageModel`.
261
+ */
262
+ tag(dimension: string): {
263
+ /** All buckets in this dimension. */
264
+ list: (ctx: RunQueryCtx) => Promise<{
265
+ spendTodayNanos: number;
266
+ spendThisMonthNanos: number;
267
+ _id: string;
268
+ _creationTime: number;
269
+ requestsPerMinute?: number | undefined;
270
+ maxConcurrent?: number | undefined;
271
+ dailySpendLimitNanos?: number | undefined;
272
+ monthlySpendLimitNanos?: number | undefined;
273
+ lifetimeSpendLimitNanos?: number | undefined;
274
+ dailyTokenLimit?: number | undefined;
275
+ monthlyTokenLimit?: number | undefined;
276
+ lifetimeTokenLimit?: number | undefined;
277
+ blocked?: boolean | undefined;
278
+ warnAtPct?: number | undefined;
279
+ enforcement?: "hard" | "soft" | undefined;
280
+ dailyBumpNanos?: number | undefined;
281
+ monthlyBumpNanos?: number | undefined;
282
+ lifetimeBumpNanos?: number | undefined;
283
+ bumpDayStamp?: string | undefined;
284
+ bumpMonthStamp?: string | undefined;
285
+ tokensToday?: number | undefined;
286
+ monthStamp?: string | undefined;
287
+ tokensThisMonth?: number | undefined;
288
+ reservedTodayNanos?: number | undefined;
289
+ reservedMonthNanos?: number | undefined;
290
+ reservedTotalNanos?: number | undefined;
291
+ reservedTodayTokens?: number | undefined;
292
+ reservedMonthTokens?: number | undefined;
293
+ reservedTotalTokens?: number | undefined;
294
+ pendingCount?: number | undefined;
295
+ dimension: string;
296
+ value: string;
297
+ totalSpendNanos: number;
298
+ totalRequests: number;
299
+ totalTokens: number;
300
+ dayStamp: string;
301
+ }[]>;
302
+ /** One bucket's limits + spend (null if it has none yet). */
303
+ get: (ctx: RunQueryCtx, args: {
304
+ value: string;
305
+ }) => Promise<{
306
+ spendTodayNanos: number;
307
+ spendThisMonthNanos: number;
308
+ _id: string;
309
+ _creationTime: number;
310
+ requestsPerMinute?: number | undefined;
311
+ maxConcurrent?: number | undefined;
312
+ dailySpendLimitNanos?: number | undefined;
313
+ monthlySpendLimitNanos?: number | undefined;
314
+ lifetimeSpendLimitNanos?: number | undefined;
315
+ dailyTokenLimit?: number | undefined;
316
+ monthlyTokenLimit?: number | undefined;
317
+ lifetimeTokenLimit?: number | undefined;
318
+ blocked?: boolean | undefined;
319
+ warnAtPct?: number | undefined;
320
+ enforcement?: "hard" | "soft" | undefined;
321
+ dailyBumpNanos?: number | undefined;
322
+ monthlyBumpNanos?: number | undefined;
323
+ lifetimeBumpNanos?: number | undefined;
324
+ bumpDayStamp?: string | undefined;
325
+ bumpMonthStamp?: string | undefined;
326
+ tokensToday?: number | undefined;
327
+ monthStamp?: string | undefined;
328
+ tokensThisMonth?: number | undefined;
329
+ reservedTodayNanos?: number | undefined;
330
+ reservedMonthNanos?: number | undefined;
331
+ reservedTotalNanos?: number | undefined;
332
+ reservedTodayTokens?: number | undefined;
333
+ reservedMonthTokens?: number | undefined;
334
+ reservedTotalTokens?: number | undefined;
335
+ pendingCount?: number | undefined;
336
+ dimension: string;
337
+ value: string;
338
+ totalSpendNanos: number;
339
+ totalRequests: number;
340
+ totalTokens: number;
341
+ dayStamp: string;
342
+ } | null>;
343
+ setLimits: (ctx: RunMutationCtx, args: {
344
+ value: string;
345
+ } & BucketLimits) => Promise<null>;
346
+ /** One-time "approve another $X" bump (daily/monthly reset with the window). */
347
+ bump: (ctx: RunMutationCtx, args: {
348
+ value: string;
349
+ } & BumpArgs) => Promise<null>;
350
+ /** Manually credit (negative) or debit (positive) this bucket. */
351
+ adjust: (ctx: RunMutationCtx, args: {
352
+ value: string;
353
+ } & {
354
+ deltaNanos: number;
355
+ tokens?: number;
356
+ reason?: string;
357
+ }) => Promise<null>;
358
+ /** Durable spend history for this bucket (per day or per month). */
359
+ history: (ctx: RunQueryCtx, args: {
360
+ value: string;
361
+ } & {
362
+ period?: "day" | "month";
363
+ limit?: number;
364
+ }) => Promise<{
365
+ _id: string;
366
+ _creationTime: number;
367
+ dimension: string;
368
+ value: string;
369
+ period: "day" | "month";
370
+ stamp: string;
371
+ spendNanos: number;
372
+ tokens: number;
373
+ requests: number;
374
+ }[]>;
375
+ /** Manual-adjustment audit log for this bucket. */
376
+ adjustments: (ctx: RunQueryCtx, args: {
377
+ value: string;
378
+ } & {
379
+ limit?: number;
380
+ }) => Promise<{
381
+ _id: string;
382
+ _creationTime: number;
383
+ tokens?: number | undefined;
384
+ reason?: string | undefined;
385
+ dimension: string;
386
+ value: string;
387
+ deltaNanos: number;
388
+ }[]>;
389
+ /** Delete the bucket (for "user", also its request rows). */
390
+ delete: (ctx: RunMutationCtx, args: {
391
+ value: string;
392
+ }) => Promise<{
393
+ deletedThisBatch: number;
394
+ done: boolean;
395
+ }>;
396
+ };
397
+ private dimensionApi;
398
+ /** Per-user budgets and controls — sugar over the "user" dimension. */
185
399
  get users(): {
400
+ /** All buckets in this dimension. */
186
401
  list: (ctx: RunQueryCtx) => Promise<{
187
402
  spendTodayNanos: number;
403
+ spendThisMonthNanos: number;
188
404
  _id: string;
189
405
  _creationTime: number;
190
406
  requestsPerMinute?: number | undefined;
407
+ maxConcurrent?: number | undefined;
191
408
  dailySpendLimitNanos?: number | undefined;
409
+ monthlySpendLimitNanos?: number | undefined;
192
410
  lifetimeSpendLimitNanos?: number | undefined;
193
411
  dailyTokenLimit?: number | undefined;
412
+ monthlyTokenLimit?: number | undefined;
194
413
  lifetimeTokenLimit?: number | undefined;
195
414
  blocked?: boolean | undefined;
415
+ warnAtPct?: number | undefined;
196
416
  enforcement?: "hard" | "soft" | undefined;
197
417
  dailyBumpNanos?: number | undefined;
418
+ monthlyBumpNanos?: number | undefined;
198
419
  lifetimeBumpNanos?: number | undefined;
199
420
  bumpDayStamp?: string | undefined;
421
+ bumpMonthStamp?: string | undefined;
200
422
  tokensToday?: number | undefined;
423
+ monthStamp?: string | undefined;
424
+ tokensThisMonth?: number | undefined;
201
425
  reservedTodayNanos?: number | undefined;
426
+ reservedMonthNanos?: number | undefined;
202
427
  reservedTotalNanos?: number | undefined;
203
428
  reservedTodayTokens?: number | undefined;
429
+ reservedMonthTokens?: number | undefined;
204
430
  reservedTotalTokens?: number | undefined;
205
431
  pendingCount?: number | undefined;
206
- userId: string;
432
+ dimension: string;
433
+ value: string;
207
434
  totalSpendNanos: number;
208
435
  totalRequests: number;
209
436
  totalTokens: number;
210
437
  dayStamp: string;
211
438
  }[]>;
439
+ /** One bucket's limits + spend (null if it has none yet). */
440
+ get: (ctx: RunQueryCtx, args: {
441
+ userId: string;
442
+ }) => Promise<{
443
+ spendTodayNanos: number;
444
+ spendThisMonthNanos: number;
445
+ _id: string;
446
+ _creationTime: number;
447
+ requestsPerMinute?: number | undefined;
448
+ maxConcurrent?: number | undefined;
449
+ dailySpendLimitNanos?: number | undefined;
450
+ monthlySpendLimitNanos?: number | undefined;
451
+ lifetimeSpendLimitNanos?: number | undefined;
452
+ dailyTokenLimit?: number | undefined;
453
+ monthlyTokenLimit?: number | undefined;
454
+ lifetimeTokenLimit?: number | undefined;
455
+ blocked?: boolean | undefined;
456
+ warnAtPct?: number | undefined;
457
+ enforcement?: "hard" | "soft" | undefined;
458
+ dailyBumpNanos?: number | undefined;
459
+ monthlyBumpNanos?: number | undefined;
460
+ lifetimeBumpNanos?: number | undefined;
461
+ bumpDayStamp?: string | undefined;
462
+ bumpMonthStamp?: string | undefined;
463
+ tokensToday?: number | undefined;
464
+ monthStamp?: string | undefined;
465
+ tokensThisMonth?: number | undefined;
466
+ reservedTodayNanos?: number | undefined;
467
+ reservedMonthNanos?: number | undefined;
468
+ reservedTotalNanos?: number | undefined;
469
+ reservedTodayTokens?: number | undefined;
470
+ reservedMonthTokens?: number | undefined;
471
+ reservedTotalTokens?: number | undefined;
472
+ pendingCount?: number | undefined;
473
+ dimension: string;
474
+ value: string;
475
+ totalSpendNanos: number;
476
+ totalRequests: number;
477
+ totalTokens: number;
478
+ dayStamp: string;
479
+ } | null>;
212
480
  setLimits: (ctx: RunMutationCtx, args: {
213
481
  userId: string;
214
- requestsPerMinute?: number;
215
- dailySpendLimitNanos?: number;
216
- lifetimeSpendLimitNanos?: number;
217
- dailyTokenLimit?: number;
218
- lifetimeTokenLimit?: number;
219
- enforcement?: "hard" | "soft";
220
- blocked?: boolean;
221
- }) => Promise<null>;
222
- /** One-time "approve another $X" bump (daily is today-only). */
482
+ } & BucketLimits) => Promise<null>;
483
+ /** One-time "approve another $X" bump (daily/monthly reset with the window). */
223
484
  bump: (ctx: RunMutationCtx, args: {
224
485
  userId: string;
225
- dailyNanos?: number;
226
- lifetimeNanos?: number;
486
+ } & BumpArgs) => Promise<null>;
487
+ /** Manually credit (negative) or debit (positive) this bucket. */
488
+ adjust: (ctx: RunMutationCtx, args: {
489
+ userId: string;
490
+ } & {
491
+ deltaNanos: number;
492
+ tokens?: number;
493
+ reason?: string;
227
494
  }) => Promise<null>;
228
- /** Delete a user and all their request rows. */
495
+ /** Durable spend history for this bucket (per day or per month). */
496
+ history: (ctx: RunQueryCtx, args: {
497
+ userId: string;
498
+ } & {
499
+ period?: "day" | "month";
500
+ limit?: number;
501
+ }) => Promise<{
502
+ _id: string;
503
+ _creationTime: number;
504
+ dimension: string;
505
+ value: string;
506
+ period: "day" | "month";
507
+ stamp: string;
508
+ spendNanos: number;
509
+ tokens: number;
510
+ requests: number;
511
+ }[]>;
512
+ /** Manual-adjustment audit log for this bucket. */
513
+ adjustments: (ctx: RunQueryCtx, args: {
514
+ userId: string;
515
+ } & {
516
+ limit?: number;
517
+ }) => Promise<{
518
+ _id: string;
519
+ _creationTime: number;
520
+ tokens?: number | undefined;
521
+ reason?: string | undefined;
522
+ dimension: string;
523
+ value: string;
524
+ deltaNanos: number;
525
+ }[]>;
526
+ /** Delete the bucket (for "user", also its request rows). */
229
527
  delete: (ctx: RunMutationCtx, args: {
230
528
  userId: string;
231
529
  }) => Promise<{
@@ -233,49 +531,143 @@ export declare class AIBudget {
233
531
  done: boolean;
234
532
  }>;
235
533
  };
236
- /** Per-action (per-feature) budgets. */
534
+ /** Per-action (per-feature) budgets — sugar over the "action" dimension. */
237
535
  get actions(): {
536
+ /** All buckets in this dimension. */
238
537
  list: (ctx: RunQueryCtx) => Promise<{
239
538
  spendTodayNanos: number;
539
+ spendThisMonthNanos: number;
240
540
  _id: string;
241
541
  _creationTime: number;
542
+ requestsPerMinute?: number | undefined;
543
+ maxConcurrent?: number | undefined;
242
544
  dailySpendLimitNanos?: number | undefined;
545
+ monthlySpendLimitNanos?: number | undefined;
243
546
  lifetimeSpendLimitNanos?: number | undefined;
244
547
  dailyTokenLimit?: number | undefined;
548
+ monthlyTokenLimit?: number | undefined;
245
549
  lifetimeTokenLimit?: number | undefined;
550
+ blocked?: boolean | undefined;
551
+ warnAtPct?: number | undefined;
246
552
  enforcement?: "hard" | "soft" | undefined;
247
553
  dailyBumpNanos?: number | undefined;
554
+ monthlyBumpNanos?: number | undefined;
248
555
  lifetimeBumpNanos?: number | undefined;
249
556
  bumpDayStamp?: string | undefined;
557
+ bumpMonthStamp?: string | undefined;
250
558
  tokensToday?: number | undefined;
559
+ monthStamp?: string | undefined;
560
+ tokensThisMonth?: number | undefined;
251
561
  reservedTodayNanos?: number | undefined;
562
+ reservedMonthNanos?: number | undefined;
252
563
  reservedTotalNanos?: number | undefined;
253
564
  reservedTodayTokens?: number | undefined;
565
+ reservedMonthTokens?: number | undefined;
254
566
  reservedTotalTokens?: number | undefined;
255
567
  pendingCount?: number | undefined;
256
- disabled?: boolean | undefined;
568
+ dimension: string;
569
+ value: string;
257
570
  totalSpendNanos: number;
258
571
  totalRequests: number;
259
572
  totalTokens: number;
260
573
  dayStamp: string;
261
- name: string;
262
574
  }[]>;
575
+ /** One bucket's limits + spend (null if it has none yet). */
576
+ get: (ctx: RunQueryCtx, args: {
577
+ name: string;
578
+ }) => Promise<{
579
+ spendTodayNanos: number;
580
+ spendThisMonthNanos: number;
581
+ _id: string;
582
+ _creationTime: number;
583
+ requestsPerMinute?: number | undefined;
584
+ maxConcurrent?: number | undefined;
585
+ dailySpendLimitNanos?: number | undefined;
586
+ monthlySpendLimitNanos?: number | undefined;
587
+ lifetimeSpendLimitNanos?: number | undefined;
588
+ dailyTokenLimit?: number | undefined;
589
+ monthlyTokenLimit?: number | undefined;
590
+ lifetimeTokenLimit?: number | undefined;
591
+ blocked?: boolean | undefined;
592
+ warnAtPct?: number | undefined;
593
+ enforcement?: "hard" | "soft" | undefined;
594
+ dailyBumpNanos?: number | undefined;
595
+ monthlyBumpNanos?: number | undefined;
596
+ lifetimeBumpNanos?: number | undefined;
597
+ bumpDayStamp?: string | undefined;
598
+ bumpMonthStamp?: string | undefined;
599
+ tokensToday?: number | undefined;
600
+ monthStamp?: string | undefined;
601
+ tokensThisMonth?: number | undefined;
602
+ reservedTodayNanos?: number | undefined;
603
+ reservedMonthNanos?: number | undefined;
604
+ reservedTotalNanos?: number | undefined;
605
+ reservedTodayTokens?: number | undefined;
606
+ reservedMonthTokens?: number | undefined;
607
+ reservedTotalTokens?: number | undefined;
608
+ pendingCount?: number | undefined;
609
+ dimension: string;
610
+ value: string;
611
+ totalSpendNanos: number;
612
+ totalRequests: number;
613
+ totalTokens: number;
614
+ dayStamp: string;
615
+ } | null>;
263
616
  setLimits: (ctx: RunMutationCtx, args: {
264
617
  name: string;
265
- dailySpendLimitNanos?: number;
266
- lifetimeSpendLimitNanos?: number;
267
- dailyTokenLimit?: number;
268
- lifetimeTokenLimit?: number;
269
- enforcement?: "hard" | "soft";
270
- disabled?: boolean;
271
- }) => Promise<null>;
618
+ } & BucketLimits) => Promise<null>;
619
+ /** One-time "approve another $X" bump (daily/monthly reset with the window). */
272
620
  bump: (ctx: RunMutationCtx, args: {
273
621
  name: string;
274
- dailyNanos?: number;
275
- lifetimeNanos?: number;
622
+ } & BumpArgs) => Promise<null>;
623
+ /** Manually credit (negative) or debit (positive) this bucket. */
624
+ adjust: (ctx: RunMutationCtx, args: {
625
+ name: string;
626
+ } & {
627
+ deltaNanos: number;
628
+ tokens?: number;
629
+ reason?: string;
276
630
  }) => Promise<null>;
631
+ /** Durable spend history for this bucket (per day or per month). */
632
+ history: (ctx: RunQueryCtx, args: {
633
+ name: string;
634
+ } & {
635
+ period?: "day" | "month";
636
+ limit?: number;
637
+ }) => Promise<{
638
+ _id: string;
639
+ _creationTime: number;
640
+ dimension: string;
641
+ value: string;
642
+ period: "day" | "month";
643
+ stamp: string;
644
+ spendNanos: number;
645
+ tokens: number;
646
+ requests: number;
647
+ }[]>;
648
+ /** Manual-adjustment audit log for this bucket. */
649
+ adjustments: (ctx: RunQueryCtx, args: {
650
+ name: string;
651
+ } & {
652
+ limit?: number;
653
+ }) => Promise<{
654
+ _id: string;
655
+ _creationTime: number;
656
+ tokens?: number | undefined;
657
+ reason?: string | undefined;
658
+ dimension: string;
659
+ value: string;
660
+ deltaNanos: number;
661
+ }[]>;
662
+ /** Delete the bucket (for "user", also its request rows). */
663
+ delete: (ctx: RunMutationCtx, args: {
664
+ name: string;
665
+ }) => Promise<{
666
+ deletedThisBatch: number;
667
+ done: boolean;
668
+ }>;
277
669
  };
278
- /** The deployment-wide budget and retention config. */
670
+ /** The deployment-wide budget, alerts, and retention config. */
279
671
  get global(): {
280
672
  /** Limits + spend today/total. */
281
673
  status: (ctx: RunQueryCtx) => Promise<{
@@ -295,6 +687,10 @@ export declare class AIBudget {
295
687
  dailyNanos?: number;
296
688
  lifetimeNanos?: number;
297
689
  }) => Promise<null>;
690
+ /** Default approaching-limit alert threshold (fraction of a cap, e.g. 0.8). */
691
+ setAlertDefaults: (ctx: RunMutationCtx, args: {
692
+ warnAtPct?: number;
693
+ }) => Promise<null>;
298
694
  /** Request-row retention window in ms (default 1h; 0 disables). */
299
695
  setRetention: (ctx: RunMutationCtx, args: {
300
696
  retentionMs: number;
@@ -318,6 +714,7 @@ export declare class AIBudget {
318
714
  [x: string]: {
319
715
  input: number;
320
716
  output: number;
717
+ cached?: number | undefined;
321
718
  overridden: boolean;
322
719
  };
323
720
  }>;
@@ -325,6 +722,8 @@ export declare class AIBudget {
325
722
  model: string;
326
723
  inputNanosPerMTok: number;
327
724
  outputNanosPerMTok: number;
725
+ /** Cache-read rate; defaults to a discount off input if omitted. */
726
+ cachedNanosPerMTok?: number;
328
727
  }) => Promise<null>;
329
728
  };
330
729
  }