@dudousxd/nestjs-agent 1.7.0 → 1.8.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.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { DynamicModule, OnModuleInit, Type, OnApplicationBootstrap } from '@nestjs/common';
2
- import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, d as AgentSkillsOptions } from './agent-deps.factory-CiC5Va9J.cjs';
3
- export { e as AGENT_TOOL_BRAND, f as AgentAttachmentsOptions, g as AgentDeps, h as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, i as delegateToolName, p as provideAgentTool, u as utcDay } from './agent-deps.factory-CiC5Va9J.cjs';
4
- import { AgentRunner, AgentStore, QuotaStore, AttachmentStagingStore, ModelCatalog, Actor, ModelCatalogView, AttachmentRef, PageContext, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, QuotaView, AgentApprovalPort, ActorResolver, MessageAttachment, ToolPresentation, AgentHistoryWindow, AgentIntake, SkillContext, ToolRegistry, AgentRegistry, PromptContributor, SkillsConfig, SkillCatalogEntry, ToolCatalogEntry, MemoryConfig, MemoryDigestEntry, SkillProvider, AgentRunInput, TokenStreamSink, SinkWriter, QuotaState } from '@dudousxd/nestjs-agent-core';
2
+ import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, d as AgentSkillsOptions } from './agent-deps.factory-Cus_RqwJ.cjs';
3
+ export { e as AGENT_TOOL_BRAND, f as AgentAttachmentsOptions, g as AgentDeps, h as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, L as LedgerQuotaProvider, Q as QuotaLimits, i as QuotaWindowLimits, j as delegateToolName, p as provideAgentTool, u as utcDay } from './agent-deps.factory-Cus_RqwJ.cjs';
4
+ import { AgentRunner, AgentStore, QuotaStore, AttachmentStagingStore, ModelCatalog, QuotaProvider, Actor, QuotaReport, ModelCatalogView, AttachmentRef, PageContext, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, QuotaView, AgentApprovalPort, ActorResolver, MessageAttachment, ToolPresentation, AgentHistoryWindow, AgentIntake, SkillContext, ToolRegistry, AgentRegistry, PromptContributor, SkillsConfig, SkillCatalogEntry, ToolCatalogEntry, MemoryConfig, MemoryDigestEntry, SkillProvider, AgentRunInput, TokenStreamSink, SinkWriter, QuotaState } from '@dudousxd/nestjs-agent-core';
5
5
  export * from '@dudousxd/nestjs-agent-core';
6
6
  import { Request } from 'express';
7
7
  import { StandardSchemaV1 } from '@standard-schema/spec';
@@ -59,7 +59,20 @@ declare class AgentService {
59
59
  private readonly quota;
60
60
  private readonly staging?;
61
61
  private readonly models?;
62
- constructor(runner: AgentRunner, store: AgentStore, deps: AgentDepsFactory, quota: QuotaStore | undefined, staging?: AttachmentStagingStore | undefined, models?: ModelCatalog | undefined);
62
+ private readonly quotaProvider?;
63
+ private readonly options?;
64
+ constructor(runner: AgentRunner, store: AgentStore, deps: AgentDepsFactory, quota: QuotaStore | undefined, staging?: AttachmentStagingStore | undefined, models?: ModelCatalog | undefined, quotaProvider?: QuotaProvider | undefined, options?: Pick<AgentModuleOptions, "quotaProvider" | "quotaLimits"> | undefined);
65
+ /**
66
+ * The actor's budget across windows (`GET <base>/quota`) — the bound {@link QuotaProvider}'s
67
+ * report. Without one (a service built outside the module), a day window from the ledger.
68
+ */
69
+ quotaReport(actor: Actor): Promise<QuotaReport>;
70
+ /**
71
+ * Refuse a turn the actor's budget no longer covers — only when the host configured one
72
+ * (`quotaProvider` or `quotaLimits`): the default report is informational, and the daily token
73
+ * quota the loop enforces keeps working as it always has.
74
+ */
75
+ private assertWithinQuota;
63
76
  /**
64
77
  * The models `actor` may pick for `agent` (`GET <base>/models`). An empty catalog when none is
65
78
  * bound, so a picker simply has nothing to offer.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { DynamicModule, OnModuleInit, Type, OnApplicationBootstrap } from '@nestjs/common';
2
- import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, d as AgentSkillsOptions } from './agent-deps.factory-CiC5Va9J.js';
3
- export { e as AGENT_TOOL_BRAND, f as AgentAttachmentsOptions, g as AgentDeps, h as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, i as delegateToolName, p as provideAgentTool, u as utcDay } from './agent-deps.factory-CiC5Va9J.js';
4
- import { AgentRunner, AgentStore, QuotaStore, AttachmentStagingStore, ModelCatalog, Actor, ModelCatalogView, AttachmentRef, PageContext, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, QuotaView, AgentApprovalPort, ActorResolver, MessageAttachment, ToolPresentation, AgentHistoryWindow, AgentIntake, SkillContext, ToolRegistry, AgentRegistry, PromptContributor, SkillsConfig, SkillCatalogEntry, ToolCatalogEntry, MemoryConfig, MemoryDigestEntry, SkillProvider, AgentRunInput, TokenStreamSink, SinkWriter, QuotaState } from '@dudousxd/nestjs-agent-core';
2
+ import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, d as AgentSkillsOptions } from './agent-deps.factory-Cus_RqwJ.js';
3
+ export { e as AGENT_TOOL_BRAND, f as AgentAttachmentsOptions, g as AgentDeps, h as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, L as LedgerQuotaProvider, Q as QuotaLimits, i as QuotaWindowLimits, j as delegateToolName, p as provideAgentTool, u as utcDay } from './agent-deps.factory-Cus_RqwJ.js';
4
+ import { AgentRunner, AgentStore, QuotaStore, AttachmentStagingStore, ModelCatalog, QuotaProvider, Actor, QuotaReport, ModelCatalogView, AttachmentRef, PageContext, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, QuotaView, AgentApprovalPort, ActorResolver, MessageAttachment, ToolPresentation, AgentHistoryWindow, AgentIntake, SkillContext, ToolRegistry, AgentRegistry, PromptContributor, SkillsConfig, SkillCatalogEntry, ToolCatalogEntry, MemoryConfig, MemoryDigestEntry, SkillProvider, AgentRunInput, TokenStreamSink, SinkWriter, QuotaState } from '@dudousxd/nestjs-agent-core';
5
5
  export * from '@dudousxd/nestjs-agent-core';
6
6
  import { Request } from 'express';
7
7
  import { StandardSchemaV1 } from '@standard-schema/spec';
@@ -59,7 +59,20 @@ declare class AgentService {
59
59
  private readonly quota;
60
60
  private readonly staging?;
61
61
  private readonly models?;
62
- constructor(runner: AgentRunner, store: AgentStore, deps: AgentDepsFactory, quota: QuotaStore | undefined, staging?: AttachmentStagingStore | undefined, models?: ModelCatalog | undefined);
62
+ private readonly quotaProvider?;
63
+ private readonly options?;
64
+ constructor(runner: AgentRunner, store: AgentStore, deps: AgentDepsFactory, quota: QuotaStore | undefined, staging?: AttachmentStagingStore | undefined, models?: ModelCatalog | undefined, quotaProvider?: QuotaProvider | undefined, options?: Pick<AgentModuleOptions, "quotaProvider" | "quotaLimits"> | undefined);
65
+ /**
66
+ * The actor's budget across windows (`GET <base>/quota`) — the bound {@link QuotaProvider}'s
67
+ * report. Without one (a service built outside the module), a day window from the ledger.
68
+ */
69
+ quotaReport(actor: Actor): Promise<QuotaReport>;
70
+ /**
71
+ * Refuse a turn the actor's budget no longer covers — only when the host configured one
72
+ * (`quotaProvider` or `quotaLimits`): the default report is informational, and the daily token
73
+ * quota the loop enforces keeps working as it always has.
74
+ */
75
+ private assertWithinQuota;
63
76
  /**
64
77
  * The models `actor` may pick for `agent` (`GET <base>/models`). An empty catalog when none is
65
78
  * bound, so a picker simply has nothing to offer.
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
4
  // src/agent.module.ts
5
- import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER11, AGENT_APPROVAL_PORT, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY5, AGENT_DURABLE_RUNNER, AGENT_MEMORY as AGENT_MEMORY3, AGENT_MODEL as AGENT_MODEL2, AGENT_MODEL_CATALOG as AGENT_MODEL_CATALOG2, AGENT_OPTIONS as AGENT_OPTIONS4, AGENT_PROMPT_CONTRIBUTORS as AGENT_PROMPT_CONTRIBUTORS3, AGENT_QUOTA_STORE as AGENT_QUOTA_STORE3, AGENT_REGISTRY as AGENT_REGISTRY6, AGENT_ROLES_POLICY as AGENT_ROLES_POLICY2, AGENT_RUNNER as AGENT_RUNNER2, AGENT_SINK as AGENT_SINK2, AGENT_SKILLS as AGENT_SKILLS3, AGENT_SKILL_SOURCES as AGENT_SKILL_SOURCES2, AGENT_STORE as AGENT_STORE4, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY3, AgentRegistry as AgentRegistry6, DefaultRolesPolicy, ToolRegistry as ToolRegistry3 } from "@dudousxd/nestjs-agent-core";
5
+ import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER11, AGENT_APPROVAL_PORT, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY5, AGENT_DURABLE_RUNNER, AGENT_MEMORY as AGENT_MEMORY3, AGENT_MODEL as AGENT_MODEL2, AGENT_MODEL_CATALOG as AGENT_MODEL_CATALOG2, AGENT_OPTIONS as AGENT_OPTIONS5, AGENT_PROMPT_CONTRIBUTORS as AGENT_PROMPT_CONTRIBUTORS3, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER2, AGENT_QUOTA_STORE as AGENT_QUOTA_STORE3, AGENT_REGISTRY as AGENT_REGISTRY6, AGENT_ROLES_POLICY as AGENT_ROLES_POLICY2, AGENT_RUNNER as AGENT_RUNNER2, AGENT_SINK as AGENT_SINK2, AGENT_SKILLS as AGENT_SKILLS3, AGENT_SKILL_SOURCES as AGENT_SKILL_SOURCES2, AGENT_STORE as AGENT_STORE4, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY3, AgentRegistry as AgentRegistry6, DefaultRolesPolicy, ToolRegistry as ToolRegistry3 } from "@dudousxd/nestjs-agent-core";
6
6
  import { Global, Module } from "@nestjs/common";
7
7
  import { DiscoveryModule, RouterModule } from "@nestjs/core";
8
8
 
@@ -272,8 +272,8 @@ AgentDepsFactory2 = _ts_decorate([
272
272
  ], AgentDepsFactory2);
273
273
 
274
274
  // src/agent.service.ts
275
- import { AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_MODEL_CATALOG, AGENT_QUOTA_STORE as AGENT_QUOTA_STORE2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE2, REQUESTER_APPROVER, findCatalogModel, mayDecideApproval, readElicitationQuestions, validateElicitationAnswer } from "@dudousxd/nestjs-agent-core";
276
- import { BadRequestException, ForbiddenException, GoneException, Inject as Inject2, Injectable as Injectable2, NotFoundException, NotImplementedException, Optional as Optional2 } from "@nestjs/common";
275
+ import { AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_MODEL_CATALOG, AGENT_OPTIONS as AGENT_OPTIONS2, AGENT_QUOTA_PROVIDER, AGENT_QUOTA_STORE as AGENT_QUOTA_STORE2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE2, REQUESTER_APPROVER, findCatalogModel, mayDecideApproval, readElicitationQuestions, validateElicitationAnswer } from "@dudousxd/nestjs-agent-core";
276
+ import { BadRequestException, ForbiddenException, GoneException, HttpException, HttpStatus, Inject as Inject2, Injectable as Injectable2, NotFoundException, NotImplementedException, Optional as Optional2 } from "@nestjs/common";
277
277
 
278
278
  // src/agent-deps.ts
279
279
  function utcDay(date = /* @__PURE__ */ new Date()) {
@@ -328,13 +328,68 @@ var AgentService = class {
328
328
  quota;
329
329
  staging;
330
330
  models;
331
- constructor(runner, store, deps, quota, staging, models) {
331
+ quotaProvider;
332
+ options;
333
+ constructor(runner, store, deps, quota, staging, models, quotaProvider, options) {
332
334
  this.runner = runner;
333
335
  this.store = store;
334
336
  this.deps = deps;
335
337
  this.quota = quota;
336
338
  this.staging = staging;
337
339
  this.models = models;
340
+ this.quotaProvider = quotaProvider;
341
+ this.options = options;
342
+ }
343
+ /**
344
+ * The actor's budget across windows (`GET <base>/quota`) — the bound {@link QuotaProvider}'s
345
+ * report. Without one (a service built outside the module), a day window from the ledger.
346
+ */
347
+ async quotaReport(actor) {
348
+ if (this.quotaProvider !== void 0) {
349
+ return this.quotaProvider.report({
350
+ actor
351
+ });
352
+ }
353
+ const today = await this.quotaToday(actor.id);
354
+ return {
355
+ windows: [
356
+ {
357
+ period: "day",
358
+ usedTokens: today.usedTokens,
359
+ ...today.limitTokens !== null ? {
360
+ limitTokens: today.limitTokens
361
+ } : {},
362
+ usedUsd: today.costUsd
363
+ }
364
+ ],
365
+ ...today.withinLimit ? {} : {
366
+ blocked: {
367
+ period: "day"
368
+ }
369
+ }
370
+ };
371
+ }
372
+ /**
373
+ * Refuse a turn the actor's budget no longer covers — only when the host configured one
374
+ * (`quotaProvider` or `quotaLimits`): the default report is informational, and the daily token
375
+ * quota the loop enforces keeps working as it always has.
376
+ */
377
+ async assertWithinQuota(actor) {
378
+ const gated = this.options?.quotaProvider !== void 0 || this.options?.quotaLimits !== void 0;
379
+ if (!gated || this.quotaProvider === void 0) {
380
+ return;
381
+ }
382
+ const { blocked } = await this.quotaProvider.report({
383
+ actor
384
+ });
385
+ if (blocked !== void 0) {
386
+ throw new HttpException({
387
+ statusCode: HttpStatus.TOO_MANY_REQUESTS,
388
+ code: "quota_exceeded",
389
+ period: blocked.period,
390
+ message: blocked.reason ?? `The ${blocked.period === "day" ? "daily" : "monthly"} quota is used up`
391
+ }, HttpStatus.TOO_MANY_REQUESTS);
392
+ }
338
393
  }
339
394
  /**
340
395
  * The models `actor` may pick for `agent` (`GET <base>/models`). An empty catalog when none is
@@ -391,6 +446,7 @@ var AgentService = class {
391
446
  return (await this.store.getThread(threadId))?.model ?? null;
392
447
  }
393
448
  async chat(params) {
449
+ await this.assertWithinQuota(params.actor);
394
450
  const agentName = await this.resolveAgentName(params.agentName, params.threadId);
395
451
  const model = await this.resolveModel(params.actor, agentName, params.model, params.threadId);
396
452
  const attachments = await this.resolveAttachments(params.actor, params.attachments ?? []);
@@ -932,6 +988,10 @@ AgentService = _ts_decorate2([
932
988
  _ts_param2(4, Inject2(AGENT_ATTACHMENT_STAGING)),
933
989
  _ts_param2(5, Optional2()),
934
990
  _ts_param2(5, Inject2(AGENT_MODEL_CATALOG)),
991
+ _ts_param2(6, Optional2()),
992
+ _ts_param2(6, Inject2(AGENT_QUOTA_PROVIDER)),
993
+ _ts_param2(7, Optional2()),
994
+ _ts_param2(7, Inject2(AGENT_OPTIONS2)),
935
995
  _ts_metadata2("design:type", Function),
936
996
  _ts_metadata2("design:paramtypes", [
937
997
  typeof AgentRunner === "undefined" ? Object : AgentRunner,
@@ -939,7 +999,9 @@ AgentService = _ts_decorate2([
939
999
  typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
940
1000
  Object,
941
1001
  typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore,
942
- typeof ModelCatalog === "undefined" ? Object : ModelCatalog
1002
+ typeof ModelCatalog === "undefined" ? Object : ModelCatalog,
1003
+ typeof QuotaProvider === "undefined" ? Object : QuotaProvider,
1004
+ typeof Pick === "undefined" ? Object : Pick
943
1005
  ])
944
1006
  ], AgentService);
945
1007
 
@@ -1078,7 +1140,7 @@ AgentsController = _ts_decorate4([
1078
1140
  ], AgentsController);
1079
1141
 
1080
1142
  // src/controller/attachments.controller.ts
1081
- import { AGENT_ACTOR_RESOLVER, AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING2, AGENT_OPTIONS as AGENT_OPTIONS2 } from "@dudousxd/nestjs-agent-core";
1143
+ import { AGENT_ACTOR_RESOLVER, AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING2, AGENT_OPTIONS as AGENT_OPTIONS3 } from "@dudousxd/nestjs-agent-core";
1082
1144
  import { BadRequestException as BadRequestException2, Controller as Controller2, Get as Get2, Inject as Inject4, NotImplementedException as NotImplementedException2, Optional as Optional3, PayloadTooLargeException, Post, Req, UnsupportedMediaTypeException, UploadedFile, UseInterceptors } from "@nestjs/common";
1083
1145
  import { FileInterceptor } from "@nestjs/platform-express";
1084
1146
  function _ts_decorate5(decorators, target, key, desc) {
@@ -1211,7 +1273,7 @@ _ts_decorate5([
1211
1273
  ], AttachmentsController.prototype, "upload", null);
1212
1274
  AttachmentsController = _ts_decorate5([
1213
1275
  Controller2("attachments"),
1214
- _ts_param4(0, Inject4(AGENT_OPTIONS2)),
1276
+ _ts_param4(0, Inject4(AGENT_OPTIONS3)),
1215
1277
  _ts_param4(1, Inject4(AGENT_ACTOR_RESOLVER)),
1216
1278
  _ts_param4(3, Optional3()),
1217
1279
  _ts_param4(3, Inject4(AGENT_ATTACHMENT_STAGING2)),
@@ -1786,11 +1848,28 @@ var QuotaController = class {
1786
1848
  this.agent = agent;
1787
1849
  this.actorResolver = actorResolver;
1788
1850
  }
1851
+ /**
1852
+ * The caller's budget across windows — `{ windows: [{ period, usedTokens, limitTokens?, usedUsd,
1853
+ * limitUsd?, resetsAt? }], blocked?: { period, reason? } }` — from the bound `QuotaProvider`.
1854
+ */
1855
+ async report(req) {
1856
+ const actor = await this.actorResolver.resolve(req);
1857
+ return this.agent.quotaReport(actor);
1858
+ }
1789
1859
  async today(req) {
1790
1860
  const actor = await this.actorResolver.resolve(req);
1791
1861
  return this.agent.quotaToday(actor.id);
1792
1862
  }
1793
1863
  };
1864
+ _ts_decorate10([
1865
+ Get6(),
1866
+ _ts_param9(0, Req6()),
1867
+ _ts_metadata10("design:type", Function),
1868
+ _ts_metadata10("design:paramtypes", [
1869
+ typeof Request === "undefined" ? Object : Request
1870
+ ]),
1871
+ _ts_metadata10("design:returntype", Promise)
1872
+ ], QuotaController.prototype, "report", null);
1794
1873
  _ts_decorate10([
1795
1874
  Get6("today"),
1796
1875
  _ts_param9(0, Req6()),
@@ -2565,7 +2644,7 @@ AgentDiscoveryService = _ts_decorate15([
2565
2644
  ], AgentDiscoveryService);
2566
2645
 
2567
2646
  // src/discovery/ai-tool-discovery.service.ts
2568
- import { AGENT_OPTIONS as AGENT_OPTIONS3, AGENT_REGISTRY as AGENT_REGISTRY5, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY2, normalizeDelegation as normalizeDelegation2 } from "@dudousxd/nestjs-agent-core";
2647
+ import { AGENT_OPTIONS as AGENT_OPTIONS4, AGENT_REGISTRY as AGENT_REGISTRY5, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY2, normalizeDelegation as normalizeDelegation2 } from "@dudousxd/nestjs-agent-core";
2569
2648
  import { Inject as Inject15, Injectable as Injectable5, Logger as Logger2 } from "@nestjs/common";
2570
2649
  import { DiscoveryService as DiscoveryService2 } from "@nestjs/core";
2571
2650
  import { z } from "zod";
@@ -2777,7 +2856,7 @@ AiToolDiscoveryService = _ts_decorate16([
2777
2856
  Injectable5(),
2778
2857
  _ts_param15(1, Inject15(AGENT_TOOL_REGISTRY2)),
2779
2858
  _ts_param15(2, Inject15(AGENT_REGISTRY5)),
2780
- _ts_param15(3, Inject15(AGENT_OPTIONS3)),
2859
+ _ts_param15(3, Inject15(AGENT_OPTIONS4)),
2781
2860
  _ts_metadata16("design:type", Function),
2782
2861
  _ts_metadata16("design:paramtypes", [
2783
2862
  typeof DiscoveryService2 === "undefined" ? Object : DiscoveryService2,
@@ -2959,6 +3038,69 @@ var InProcessTokenStreamSink = class {
2959
3038
  }
2960
3039
  };
2961
3040
 
3041
+ // src/ledger-quota-provider.ts
3042
+ import { exhaustedWindow, quotaPeriodRange } from "@dudousxd/nestjs-agent-core";
3043
+ var LedgerQuotaProvider = class {
3044
+ static {
3045
+ __name(this, "LedgerQuotaProvider");
3046
+ }
3047
+ store;
3048
+ quota;
3049
+ limits;
3050
+ constructor(store, quota, limits = {}) {
3051
+ this.store = store;
3052
+ this.quota = quota;
3053
+ this.limits = limits;
3054
+ }
3055
+ async report(query) {
3056
+ const now = query.now ?? /* @__PURE__ */ new Date();
3057
+ const actorRef = query.actor.id;
3058
+ const windows = [
3059
+ await this.dayWindow(actorRef, now)
3060
+ ];
3061
+ if (this.store.usageBetween !== void 0) {
3062
+ const range = quotaPeriodRange("month", now);
3063
+ const used = await this.store.usageBetween(actorRef, range.fromDay, range.toDay);
3064
+ windows.push(this.window("month", used.usedTokens, used.costUsd, range.resetsAt));
3065
+ }
3066
+ const blocked = exhaustedWindow(windows);
3067
+ return {
3068
+ windows,
3069
+ ...blocked !== void 0 ? {
3070
+ blocked
3071
+ } : {}
3072
+ };
3073
+ }
3074
+ async dayWindow(actorRef, now) {
3075
+ const range = quotaPeriodRange("day", now);
3076
+ const { usedTokens, costUsd } = await this.store.quotaToday(actorRef, range.fromDay);
3077
+ if (this.quota === void 0) {
3078
+ return this.window("day", usedTokens, costUsd, range.resetsAt);
3079
+ }
3080
+ const state = await this.quota.check(actorRef, range.fromDay);
3081
+ const window = this.window("day", state.usedTokens, costUsd, range.resetsAt);
3082
+ if (window.limitTokens === void 0) {
3083
+ window.limitTokens = state.limitTokens;
3084
+ }
3085
+ return window;
3086
+ }
3087
+ window(period, usedTokens, usedUsd, resetsAt) {
3088
+ const limits = this.limits[period] ?? {};
3089
+ return {
3090
+ period,
3091
+ usedTokens,
3092
+ ...limits.tokens !== void 0 ? {
3093
+ limitTokens: limits.tokens
3094
+ } : {},
3095
+ usedUsd,
3096
+ ...limits.usd !== void 0 ? {
3097
+ limitUsd: limits.usd
3098
+ } : {},
3099
+ resetsAt
3100
+ };
3101
+ }
3102
+ };
3103
+
2962
3104
  // src/ledger-quota-store.ts
2963
3105
  var LedgerQuotaStore = class {
2964
3106
  static {
@@ -3485,7 +3627,7 @@ function sharedProviders(durable, includeStore) {
3485
3627
  provide: AGENT_SKILLS3,
3486
3628
  useFactory: /* @__PURE__ */ __name((options, declared) => resolveSkillsConfig(options.skills, declared), "useFactory"),
3487
3629
  inject: [
3488
- AGENT_OPTIONS4,
3630
+ AGENT_OPTIONS5,
3489
3631
  AGENT_SKILL_SOURCES2
3490
3632
  ]
3491
3633
  },
@@ -3495,35 +3637,35 @@ function sharedProviders(durable, includeStore) {
3495
3637
  provide: AGENT_MEMORY3,
3496
3638
  useFactory: /* @__PURE__ */ __name((options) => options.memory, "useFactory"),
3497
3639
  inject: [
3498
- AGENT_OPTIONS4
3640
+ AGENT_OPTIONS5
3499
3641
  ]
3500
3642
  },
3501
3643
  {
3502
3644
  provide: AGENT_SINK2,
3503
3645
  useFactory: /* @__PURE__ */ __name((options) => options.sink ?? new InProcessTokenStreamSink(), "useFactory"),
3504
3646
  inject: [
3505
- AGENT_OPTIONS4
3647
+ AGENT_OPTIONS5
3506
3648
  ]
3507
3649
  },
3508
3650
  {
3509
3651
  provide: AGENT_ROLES_POLICY2,
3510
3652
  useFactory: /* @__PURE__ */ __name((options) => options.rolesPolicy ?? new DefaultRolesPolicy(options.defaultRoles), "useFactory"),
3511
3653
  inject: [
3512
- AGENT_OPTIONS4
3654
+ AGENT_OPTIONS5
3513
3655
  ]
3514
3656
  },
3515
3657
  {
3516
3658
  provide: AGENT_ACTOR_RESOLVER11,
3517
3659
  useFactory: /* @__PURE__ */ __name((options) => options.actorResolver, "useFactory"),
3518
3660
  inject: [
3519
- AGENT_OPTIONS4
3661
+ AGENT_OPTIONS5
3520
3662
  ]
3521
3663
  },
3522
3664
  {
3523
3665
  provide: AGENT_MODEL2,
3524
3666
  useFactory: /* @__PURE__ */ __name((o) => o.model, "useFactory"),
3525
3667
  inject: [
3526
- AGENT_OPTIONS4
3668
+ AGENT_OPTIONS5
3527
3669
  ]
3528
3670
  },
3529
3671
  {
@@ -3533,15 +3675,24 @@ function sharedProviders(durable, includeStore) {
3533
3675
  provide: AGENT_QUOTA_STORE3,
3534
3676
  useFactory: /* @__PURE__ */ __name((o, store) => o.quota ?? (o.quotaLimitTokens !== void 0 ? new LedgerQuotaStore(store, o.quotaLimitTokens) : void 0), "useFactory"),
3535
3677
  inject: [
3536
- AGENT_OPTIONS4,
3678
+ AGENT_OPTIONS5,
3537
3679
  AGENT_STORE4
3538
3680
  ]
3539
3681
  },
3682
+ {
3683
+ provide: AGENT_QUOTA_PROVIDER2,
3684
+ useFactory: /* @__PURE__ */ __name((o, store, quota) => o.quotaProvider ?? new LedgerQuotaProvider(store, quota, o.quotaLimits), "useFactory"),
3685
+ inject: [
3686
+ AGENT_OPTIONS5,
3687
+ AGENT_STORE4,
3688
+ AGENT_QUOTA_STORE3
3689
+ ]
3690
+ },
3540
3691
  {
3541
3692
  provide: AGENT_MODEL_CATALOG2,
3542
3693
  useFactory: /* @__PURE__ */ __name((o) => o.models, "useFactory"),
3543
3694
  inject: [
3544
- AGENT_OPTIONS4
3695
+ AGENT_OPTIONS5
3545
3696
  ]
3546
3697
  },
3547
3698
  AgentDepsFactory2,
@@ -3569,7 +3720,7 @@ function sharedProviders(durable, includeStore) {
3569
3720
  provide: AGENT_STORE4,
3570
3721
  useFactory: /* @__PURE__ */ __name((o) => o.store, "useFactory"),
3571
3722
  inject: [
3572
- AGENT_OPTIONS4
3723
+ AGENT_OPTIONS5
3573
3724
  ]
3574
3725
  });
3575
3726
  }
@@ -3600,7 +3751,7 @@ function sharedProviders(durable, includeStore) {
3600
3751
  __name(sharedProviders, "sharedProviders");
3601
3752
  function exportsFor(includeStore) {
3602
3753
  return [
3603
- AGENT_OPTIONS4,
3754
+ AGENT_OPTIONS5,
3604
3755
  AGENT_TOOL_REGISTRY3,
3605
3756
  AGENT_REGISTRY6,
3606
3757
  AGENT_SINK2,
@@ -3612,6 +3763,7 @@ function exportsFor(includeStore) {
3612
3763
  ] : [],
3613
3764
  AGENT_QUOTA_STORE3,
3614
3765
  AGENT_MODEL_CATALOG2,
3766
+ AGENT_QUOTA_PROVIDER2,
3615
3767
  AGENT_PROMPT_CONTRIBUTORS3,
3616
3768
  AGENT_SKILLS3,
3617
3769
  AGENT_MEMORY3,
@@ -3691,7 +3843,7 @@ var AgentModule = class _AgentModule {
3691
3843
  controllers: controllersForSurface(options.surface, options.attachments?.upload === true),
3692
3844
  providers: [
3693
3845
  {
3694
- provide: AGENT_OPTIONS4,
3846
+ provide: AGENT_OPTIONS5,
3695
3847
  useValue: options
3696
3848
  },
3697
3849
  ...sharedProviders(options.durable ?? false, includeStore),
@@ -3715,7 +3867,7 @@ var AgentModule = class _AgentModule {
3715
3867
  controllers: controllersForSurface(options.surface, options.attachmentsUpload === true),
3716
3868
  providers: [
3717
3869
  {
3718
- provide: AGENT_OPTIONS4,
3870
+ provide: AGENT_OPTIONS5,
3719
3871
  // Stamp the STATIC wiring flags onto the factory result: `durable`/`surface` are
3720
3872
  // authoritative on the async config object (they decided the actual wiring above), and
3721
3873
  // the durable module reads `durable` back off AGENT_OPTIONS. `surface` isn't read back by
@@ -3793,6 +3945,7 @@ export {
3793
3945
  HeaderActorResolver,
3794
3946
  InProcessTokenStreamSink,
3795
3947
  InlineAgentRunner,
3948
+ LedgerQuotaProvider,
3796
3949
  LedgerQuotaStore,
3797
3950
  MemoriesController,
3798
3951
  MessagesController,