@dudousxd/nestjs-agent 1.7.0 → 1.9.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.cjs CHANGED
@@ -40,6 +40,7 @@ __export(index_exports, {
40
40
  HeaderActorResolver: () => HeaderActorResolver,
41
41
  InProcessTokenStreamSink: () => InProcessTokenStreamSink,
42
42
  InlineAgentRunner: () => InlineAgentRunner,
43
+ LedgerQuotaProvider: () => LedgerQuotaProvider,
43
44
  LedgerQuotaStore: () => LedgerQuotaStore,
44
45
  MemoriesController: () => MemoriesController,
45
46
  MessagesController: () => MessagesController,
@@ -56,6 +57,7 @@ __export(index_exports, {
56
57
  declaredSkillProvider: () => declaredSkillProvider,
57
58
  delegateToolName: () => delegateToolName,
58
59
  provideAgentTool: () => provideAgentTool,
60
+ provideAgentTools: () => provideAgentTools,
59
61
  readAgentMetadata: () => readAgentMetadata,
60
62
  readAiToolMetadata: () => readAiToolMetadata,
61
63
  readSkillMetadata: () => readSkillMetadata,
@@ -66,7 +68,7 @@ __export(index_exports, {
66
68
  module.exports = __toCommonJS(index_exports);
67
69
 
68
70
  // src/agent.module.ts
69
- var import_nestjs_agent_core22 = require("@dudousxd/nestjs-agent-core");
71
+ var import_nestjs_agent_core23 = require("@dudousxd/nestjs-agent-core");
70
72
  var import_common19 = require("@nestjs/common");
71
73
  var import_core4 = require("@nestjs/core");
72
74
 
@@ -392,13 +394,68 @@ var AgentService = class {
392
394
  quota;
393
395
  staging;
394
396
  models;
395
- constructor(runner, store, deps, quota, staging, models) {
397
+ quotaProvider;
398
+ options;
399
+ constructor(runner, store, deps, quota, staging, models, quotaProvider, options) {
396
400
  this.runner = runner;
397
401
  this.store = store;
398
402
  this.deps = deps;
399
403
  this.quota = quota;
400
404
  this.staging = staging;
401
405
  this.models = models;
406
+ this.quotaProvider = quotaProvider;
407
+ this.options = options;
408
+ }
409
+ /**
410
+ * The actor's budget across windows (`GET <base>/quota`) — the bound {@link QuotaProvider}'s
411
+ * report. Without one (a service built outside the module), a day window from the ledger.
412
+ */
413
+ async quotaReport(actor) {
414
+ if (this.quotaProvider !== void 0) {
415
+ return this.quotaProvider.report({
416
+ actor
417
+ });
418
+ }
419
+ const today = await this.quotaToday(actor.id);
420
+ return {
421
+ windows: [
422
+ {
423
+ period: "day",
424
+ usedTokens: today.usedTokens,
425
+ ...today.limitTokens !== null ? {
426
+ limitTokens: today.limitTokens
427
+ } : {},
428
+ usedUsd: today.costUsd
429
+ }
430
+ ],
431
+ ...today.withinLimit ? {} : {
432
+ blocked: {
433
+ period: "day"
434
+ }
435
+ }
436
+ };
437
+ }
438
+ /**
439
+ * Refuse a turn the actor's budget no longer covers — only when the host configured one
440
+ * (`quotaProvider` or `quotaLimits`): the default report is informational, and the daily token
441
+ * quota the loop enforces keeps working as it always has.
442
+ */
443
+ async assertWithinQuota(actor) {
444
+ const gated = this.options?.quotaProvider !== void 0 || this.options?.quotaLimits !== void 0;
445
+ if (!gated || this.quotaProvider === void 0) {
446
+ return;
447
+ }
448
+ const { blocked } = await this.quotaProvider.report({
449
+ actor
450
+ });
451
+ if (blocked !== void 0) {
452
+ throw new import_common2.HttpException({
453
+ statusCode: import_common2.HttpStatus.TOO_MANY_REQUESTS,
454
+ code: "quota_exceeded",
455
+ period: blocked.period,
456
+ message: blocked.reason ?? `The ${blocked.period === "day" ? "daily" : "monthly"} quota is used up`
457
+ }, import_common2.HttpStatus.TOO_MANY_REQUESTS);
458
+ }
402
459
  }
403
460
  /**
404
461
  * The models `actor` may pick for `agent` (`GET <base>/models`). An empty catalog when none is
@@ -455,6 +512,7 @@ var AgentService = class {
455
512
  return (await this.store.getThread(threadId))?.model ?? null;
456
513
  }
457
514
  async chat(params) {
515
+ await this.assertWithinQuota(params.actor);
458
516
  const agentName = await this.resolveAgentName(params.agentName, params.threadId);
459
517
  const model = await this.resolveModel(params.actor, agentName, params.model, params.threadId);
460
518
  const attachments = await this.resolveAttachments(params.actor, params.attachments ?? []);
@@ -996,6 +1054,10 @@ AgentService = _ts_decorate2([
996
1054
  _ts_param2(4, (0, import_common2.Inject)(import_nestjs_agent_core3.AGENT_ATTACHMENT_STAGING)),
997
1055
  _ts_param2(5, (0, import_common2.Optional)()),
998
1056
  _ts_param2(5, (0, import_common2.Inject)(import_nestjs_agent_core3.AGENT_MODEL_CATALOG)),
1057
+ _ts_param2(6, (0, import_common2.Optional)()),
1058
+ _ts_param2(6, (0, import_common2.Inject)(import_nestjs_agent_core3.AGENT_QUOTA_PROVIDER)),
1059
+ _ts_param2(7, (0, import_common2.Optional)()),
1060
+ _ts_param2(7, (0, import_common2.Inject)(import_nestjs_agent_core3.AGENT_OPTIONS)),
999
1061
  _ts_metadata2("design:type", Function),
1000
1062
  _ts_metadata2("design:paramtypes", [
1001
1063
  typeof AgentRunner === "undefined" ? Object : AgentRunner,
@@ -1003,7 +1065,9 @@ AgentService = _ts_decorate2([
1003
1065
  typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
1004
1066
  Object,
1005
1067
  typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore,
1006
- typeof ModelCatalog === "undefined" ? Object : ModelCatalog
1068
+ typeof ModelCatalog === "undefined" ? Object : ModelCatalog,
1069
+ typeof QuotaProvider === "undefined" ? Object : QuotaProvider,
1070
+ typeof Pick === "undefined" ? Object : Pick
1007
1071
  ])
1008
1072
  ], AgentService);
1009
1073
 
@@ -1850,11 +1914,28 @@ var QuotaController = class {
1850
1914
  this.agent = agent;
1851
1915
  this.actorResolver = actorResolver;
1852
1916
  }
1917
+ /**
1918
+ * The caller's budget across windows — `{ windows: [{ period, usedTokens, limitTokens?, usedUsd,
1919
+ * limitUsd?, resetsAt? }], blocked?: { period, reason? } }` — from the bound `QuotaProvider`.
1920
+ */
1921
+ async report(req) {
1922
+ const actor = await this.actorResolver.resolve(req);
1923
+ return this.agent.quotaReport(actor);
1924
+ }
1853
1925
  async today(req) {
1854
1926
  const actor = await this.actorResolver.resolve(req);
1855
1927
  return this.agent.quotaToday(actor.id);
1856
1928
  }
1857
1929
  };
1930
+ _ts_decorate10([
1931
+ (0, import_common10.Get)(),
1932
+ _ts_param9(0, (0, import_common10.Req)()),
1933
+ _ts_metadata10("design:type", Function),
1934
+ _ts_metadata10("design:paramtypes", [
1935
+ typeof Request === "undefined" ? Object : Request
1936
+ ]),
1937
+ _ts_metadata10("design:returntype", Promise)
1938
+ ], QuotaController.prototype, "report", null);
1858
1939
  _ts_decorate10([
1859
1940
  (0, import_common10.Get)("today"),
1860
1941
  _ts_param9(0, (0, import_common10.Req)()),
@@ -2677,6 +2758,14 @@ function provideAgentTool(factoryOrTool, inject) {
2677
2758
  };
2678
2759
  }
2679
2760
  __name(provideAgentTool, "provideAgentTool");
2761
+ function provideAgentTools(factory, inject) {
2762
+ return {
2763
+ provide: /* @__PURE__ */ Symbol("nestjs-agent:functional-tool-list"),
2764
+ useFactory: /* @__PURE__ */ __name(async (...deps) => (await factory(...deps)).map(brand), "useFactory"),
2765
+ inject: inject ?? []
2766
+ };
2767
+ }
2768
+ __name(provideAgentTools, "provideAgentTools");
2680
2769
 
2681
2770
  // src/discovery/ai-tool-discovery.service.ts
2682
2771
  function _ts_decorate16(decorators, target, key, desc) {
@@ -2728,6 +2817,14 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
2728
2817
  if (instance === null || instance === void 0 || typeof instance !== "object") {
2729
2818
  continue;
2730
2819
  }
2820
+ if (Array.isArray(instance) && instance.length > 0 && instance.every((each) => typeof each === "object" && each !== null && isBrandedFunctionalTool(each))) {
2821
+ for (const tool of instance) {
2822
+ if (this.registerFunctionalTool(tool)) {
2823
+ functional += 1;
2824
+ }
2825
+ }
2826
+ continue;
2827
+ }
2731
2828
  if (isBrandedFunctionalTool(instance)) {
2732
2829
  if (this.registerFunctionalTool(instance)) {
2733
2830
  functional += 1;
@@ -2775,6 +2872,9 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
2775
2872
  } : {},
2776
2873
  ...typeof handler.canUse === "function" ? {
2777
2874
  canUse: /* @__PURE__ */ __name((actor) => instance.canUse(actor), "canUse")
2875
+ } : {},
2876
+ ...typeof handler.describe === "function" ? {
2877
+ describe: /* @__PURE__ */ __name((scope) => instance.describe(scope), "describe")
2778
2878
  } : {}
2779
2879
  });
2780
2880
  count += 1;
@@ -3023,6 +3123,69 @@ var InProcessTokenStreamSink = class {
3023
3123
  }
3024
3124
  };
3025
3125
 
3126
+ // src/ledger-quota-provider.ts
3127
+ var import_nestjs_agent_core20 = require("@dudousxd/nestjs-agent-core");
3128
+ var LedgerQuotaProvider = class {
3129
+ static {
3130
+ __name(this, "LedgerQuotaProvider");
3131
+ }
3132
+ store;
3133
+ quota;
3134
+ limits;
3135
+ constructor(store, quota, limits = {}) {
3136
+ this.store = store;
3137
+ this.quota = quota;
3138
+ this.limits = limits;
3139
+ }
3140
+ async report(query) {
3141
+ const now = query.now ?? /* @__PURE__ */ new Date();
3142
+ const actorRef = query.actor.id;
3143
+ const windows = [
3144
+ await this.dayWindow(actorRef, now)
3145
+ ];
3146
+ if (this.store.usageBetween !== void 0) {
3147
+ const range = (0, import_nestjs_agent_core20.quotaPeriodRange)("month", now);
3148
+ const used = await this.store.usageBetween(actorRef, range.fromDay, range.toDay);
3149
+ windows.push(this.window("month", used.usedTokens, used.costUsd, range.resetsAt));
3150
+ }
3151
+ const blocked = (0, import_nestjs_agent_core20.exhaustedWindow)(windows);
3152
+ return {
3153
+ windows,
3154
+ ...blocked !== void 0 ? {
3155
+ blocked
3156
+ } : {}
3157
+ };
3158
+ }
3159
+ async dayWindow(actorRef, now) {
3160
+ const range = (0, import_nestjs_agent_core20.quotaPeriodRange)("day", now);
3161
+ const { usedTokens, costUsd } = await this.store.quotaToday(actorRef, range.fromDay);
3162
+ if (this.quota === void 0) {
3163
+ return this.window("day", usedTokens, costUsd, range.resetsAt);
3164
+ }
3165
+ const state = await this.quota.check(actorRef, range.fromDay);
3166
+ const window = this.window("day", state.usedTokens, costUsd, range.resetsAt);
3167
+ if (window.limitTokens === void 0) {
3168
+ window.limitTokens = state.limitTokens;
3169
+ }
3170
+ return window;
3171
+ }
3172
+ window(period, usedTokens, usedUsd, resetsAt) {
3173
+ const limits = this.limits[period] ?? {};
3174
+ return {
3175
+ period,
3176
+ usedTokens,
3177
+ ...limits.tokens !== void 0 ? {
3178
+ limitTokens: limits.tokens
3179
+ } : {},
3180
+ usedUsd,
3181
+ ...limits.usd !== void 0 ? {
3182
+ limitUsd: limits.usd
3183
+ } : {},
3184
+ resetsAt
3185
+ };
3186
+ }
3187
+ };
3188
+
3026
3189
  // src/ledger-quota-store.ts
3027
3190
  var LedgerQuotaStore = class {
3028
3191
  static {
@@ -3047,7 +3210,7 @@ var LedgerQuotaStore = class {
3047
3210
  };
3048
3211
 
3049
3212
  // src/runner/inline-agent-runner.ts
3050
- var import_nestjs_agent_core20 = require("@dudousxd/nestjs-agent-core");
3213
+ var import_nestjs_agent_core21 = require("@dudousxd/nestjs-agent-core");
3051
3214
  var import_common18 = require("@nestjs/common");
3052
3215
  function _ts_decorate18(decorators, target, key, desc) {
3053
3216
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -3110,18 +3273,18 @@ var InlineAgentRunner = class _InlineAgentRunner {
3110
3273
  ] : []
3111
3274
  ]
3112
3275
  });
3113
- void (0, import_nestjs_agent_core20.runAgentLoop)({
3276
+ void (0, import_nestjs_agent_core21.runAgentLoop)({
3114
3277
  ...deps,
3115
3278
  day
3116
3279
  }, input, hooks).then(() => this.store.setActiveStream(input.threadId, null)).catch(async (error) => {
3117
- if (error instanceof import_nestjs_agent_core20.RunCancelledError) {
3280
+ if (error instanceof import_nestjs_agent_core21.RunCancelledError) {
3118
3281
  await this.settleCancelled(runId, input.threadId, deps);
3119
3282
  return;
3120
3283
  }
3121
3284
  const message = error instanceof Error ? error.message : String(error);
3122
- const code = (0, import_nestjs_agent_core20.agentFailureCode)(error);
3285
+ const code = (0, import_nestjs_agent_core21.agentFailureCode)(error);
3123
3286
  this.logger.error(`agent run ${runId} failed (${code}): ${message}`);
3124
- (0, import_nestjs_agent_core20.publishAgentRunFailed)({
3287
+ (0, import_nestjs_agent_core21.publishAgentRunFailed)({
3125
3288
  runId,
3126
3289
  code,
3127
3290
  message
@@ -3170,7 +3333,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
3170
3333
  for (const [key, waiter] of this.pending) {
3171
3334
  if (key.startsWith(`${runId}:`)) {
3172
3335
  this.pending.delete(key);
3173
- waiter.reject(new import_nestjs_agent_core20.RunCancelledError());
3336
+ waiter.reject(new import_nestjs_agent_core21.RunCancelledError());
3174
3337
  }
3175
3338
  }
3176
3339
  await Promise.resolve();
@@ -3185,7 +3348,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
3185
3348
  this.logger.log(`agent run ${runId} cancelled`);
3186
3349
  await this.store.setActiveStream(threadId, null);
3187
3350
  const writer = await deps.sink.open(runId);
3188
- await writer.write((0, import_nestjs_agent_core20.encodeStreamEvent)({
3351
+ await writer.write((0, import_nestjs_agent_core21.encodeStreamEvent)({
3189
3352
  kind: "cancelled"
3190
3353
  }));
3191
3354
  await writer.end();
@@ -3246,7 +3409,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
3246
3409
  awaitApproval: /* @__PURE__ */ __name((call, _ctx, opts) => this.parkApproval(runId, call.id, opts?.timeoutMs), "awaitApproval"),
3247
3410
  awaitAnswers: /* @__PURE__ */ __name((request) => this.park(runId, request.id), "awaitAnswers"),
3248
3411
  step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
3249
- parallel: import_nestjs_agent_core20.settleAll,
3412
+ parallel: import_nestjs_agent_core21.settleAll,
3250
3413
  cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId), "cancelled"),
3251
3414
  runAgent: /* @__PURE__ */ __name((agentName, task) => this.runNested({
3252
3415
  agentName,
@@ -3297,7 +3460,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
3297
3460
  awaitApproval: /* @__PURE__ */ __name((call, _ctx, opts) => this.parkApproval(runId, call.id, opts?.timeoutMs), "awaitApproval"),
3298
3461
  awaitAnswers: /* @__PURE__ */ __name((request) => this.park(runId, request.id), "awaitAnswers"),
3299
3462
  step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
3300
- parallel: import_nestjs_agent_core20.settleAll,
3463
+ parallel: import_nestjs_agent_core21.settleAll,
3301
3464
  cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId), "cancelled"),
3302
3465
  runAgent: /* @__PURE__ */ __name((childName, childTask) => this.runNested({
3303
3466
  agentName: childName,
@@ -3330,7 +3493,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
3330
3493
  }
3331
3494
  }), "startAgent")
3332
3495
  };
3333
- void (0, import_nestjs_agent_core20.runAgentLoop)({
3496
+ void (0, import_nestjs_agent_core21.runAgentLoop)({
3334
3497
  ...deps,
3335
3498
  day
3336
3499
  }, {
@@ -3344,13 +3507,13 @@ var InlineAgentRunner = class _InlineAgentRunner {
3344
3507
  parentRunId,
3345
3508
  deliverTo
3346
3509
  }, hooks).catch(async (error) => {
3347
- const cancelled = error instanceof import_nestjs_agent_core20.RunCancelledError;
3510
+ const cancelled = error instanceof import_nestjs_agent_core21.RunCancelledError;
3348
3511
  const message = error instanceof Error ? error.message : String(error);
3349
3512
  if (!cancelled) {
3350
3513
  this.logger.error(`detached agent run ${runId} failed: ${message}`);
3351
- (0, import_nestjs_agent_core20.publishAgentRunFailed)({
3514
+ (0, import_nestjs_agent_core21.publishAgentRunFailed)({
3352
3515
  runId,
3353
- code: (0, import_nestjs_agent_core20.agentFailureCode)(error),
3516
+ code: (0, import_nestjs_agent_core21.agentFailureCode)(error),
3354
3517
  message
3355
3518
  });
3356
3519
  }
@@ -3358,11 +3521,11 @@ var InlineAgentRunner = class _InlineAgentRunner {
3358
3521
  runId,
3359
3522
  status: cancelled ? "cancelled" : "failed",
3360
3523
  ...cancelled ? {} : {
3361
- errorCode: (0, import_nestjs_agent_core20.agentFailureCode)(error),
3524
+ errorCode: (0, import_nestjs_agent_core21.agentFailureCode)(error),
3362
3525
  errorMessage: message
3363
3526
  }
3364
3527
  });
3365
- await (0, import_nestjs_agent_core20.settleUnsettledDelegation)({
3528
+ await (0, import_nestjs_agent_core21.settleUnsettledDelegation)({
3366
3529
  store: this.store,
3367
3530
  delivery: deliverTo,
3368
3531
  agent: agentName,
@@ -3401,7 +3564,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
3401
3564
  awaitApproval: /* @__PURE__ */ __name((call, _ctx, opts) => this.parkApproval(runId, call.id, opts?.timeoutMs), "awaitApproval"),
3402
3565
  awaitAnswers: /* @__PURE__ */ __name((request) => this.park(runId, request.id), "awaitAnswers"),
3403
3566
  step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
3404
- parallel: import_nestjs_agent_core20.settleAll,
3567
+ parallel: import_nestjs_agent_core21.settleAll,
3405
3568
  // A child stops when it is cancelled OR when the run a human is actually watching is: the
3406
3569
  // canceller names the top-level run, which is the only id that ever left the server.
3407
3570
  cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId) || this.cancelled.has(sinkRunId), "cancelled"),
@@ -3436,7 +3599,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
3436
3599
  }), "startAgent")
3437
3600
  };
3438
3601
  try {
3439
- return await (0, import_nestjs_agent_core20.runAgentLoop)({
3602
+ return await (0, import_nestjs_agent_core21.runAgentLoop)({
3440
3603
  ...deps,
3441
3604
  day
3442
3605
  }, {
@@ -3457,8 +3620,8 @@ var InlineAgentRunner = class _InlineAgentRunner {
3457
3620
  };
3458
3621
  InlineAgentRunner = _ts_decorate18([
3459
3622
  (0, import_common18.Injectable)(),
3460
- _ts_param17(0, (0, import_common18.Inject)(import_nestjs_agent_core20.AGENT_DEPS_FACTORY)),
3461
- _ts_param17(1, (0, import_common18.Inject)(import_nestjs_agent_core20.AGENT_STORE)),
3623
+ _ts_param17(0, (0, import_common18.Inject)(import_nestjs_agent_core21.AGENT_DEPS_FACTORY)),
3624
+ _ts_param17(1, (0, import_common18.Inject)(import_nestjs_agent_core21.AGENT_STORE)),
3462
3625
  _ts_metadata18("design:type", Function),
3463
3626
  _ts_metadata18("design:paramtypes", [
3464
3627
  typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
@@ -3467,7 +3630,7 @@ InlineAgentRunner = _ts_decorate18([
3467
3630
  ], InlineAgentRunner);
3468
3631
 
3469
3632
  // src/skills-config.ts
3470
- var import_nestjs_agent_core21 = require("@dudousxd/nestjs-agent-core");
3633
+ var import_nestjs_agent_core22 = require("@dudousxd/nestjs-agent-core");
3471
3634
  function declaredSkillProvider(declared) {
3472
3635
  return {
3473
3636
  list: /* @__PURE__ */ __name(({ scopes }) => declared.filter((skill) => scopes.includes(skill.scope)).map(({ name, description, scope }) => ({
@@ -3493,7 +3656,7 @@ function resolveSkillsConfig(options, declared) {
3493
3656
  declaredSkillProvider(declared)
3494
3657
  ];
3495
3658
  return {
3496
- provider: providers.length === 1 ? providers[0] : (0, import_nestjs_agent_core21.compositeSkillProvider)(providers),
3659
+ provider: providers.length === 1 ? providers[0] : (0, import_nestjs_agent_core22.compositeSkillProvider)(providers),
3497
3660
  ...options.scopes !== void 0 ? {
3498
3661
  scopes: options.scopes
3499
3662
  } : {},
@@ -3523,94 +3686,103 @@ var DEFAULT_PATH = "agent";
3523
3686
  function sharedProviders(durable, includeStore) {
3524
3687
  const providers = [
3525
3688
  {
3526
- provide: import_nestjs_agent_core22.AGENT_TOOL_REGISTRY,
3527
- useFactory: /* @__PURE__ */ __name(() => new import_nestjs_agent_core22.ToolRegistry(), "useFactory")
3689
+ provide: import_nestjs_agent_core23.AGENT_TOOL_REGISTRY,
3690
+ useFactory: /* @__PURE__ */ __name(() => new import_nestjs_agent_core23.ToolRegistry(), "useFactory")
3528
3691
  },
3529
3692
  // Starts empty; AgentDiscoveryService populates it from `@Agent`-decorated providers at boot.
3530
3693
  {
3531
- provide: import_nestjs_agent_core22.AGENT_REGISTRY,
3532
- useFactory: /* @__PURE__ */ __name(() => new import_nestjs_agent_core22.AgentRegistry(), "useFactory")
3694
+ provide: import_nestjs_agent_core23.AGENT_REGISTRY,
3695
+ useFactory: /* @__PURE__ */ __name(() => new import_nestjs_agent_core23.AgentRegistry(), "useFactory")
3533
3696
  },
3534
3697
  // A shared, mutable list AgentDiscoveryService fills with `@SystemPromptContributor()` methods.
3535
3698
  {
3536
- provide: import_nestjs_agent_core22.AGENT_PROMPT_CONTRIBUTORS,
3699
+ provide: import_nestjs_agent_core23.AGENT_PROMPT_CONTRIBUTORS,
3537
3700
  useFactory: /* @__PURE__ */ __name(() => [], "useFactory")
3538
3701
  },
3539
3702
  // Likewise for `@Skill`-decorated providers — filled by SkillDiscoveryService at onModuleInit,
3540
3703
  // read lazily by the AGENT_SKILLS provider below (which DI builds before discovery has run).
3541
3704
  {
3542
- provide: import_nestjs_agent_core22.AGENT_SKILL_SOURCES,
3705
+ provide: import_nestjs_agent_core23.AGENT_SKILL_SOURCES,
3543
3706
  useFactory: /* @__PURE__ */ __name(() => [], "useFactory")
3544
3707
  },
3545
3708
  {
3546
3709
  // One resolution, shared by the loop's deps and the listing endpoint: a second one would
3547
3710
  // drift, and a user would be offered a skill the agent cannot reach. `undefined` when the
3548
3711
  // host configured none — which is what keeps the turn's checkpoint sequence unchanged.
3549
- provide: import_nestjs_agent_core22.AGENT_SKILLS,
3712
+ provide: import_nestjs_agent_core23.AGENT_SKILLS,
3550
3713
  useFactory: /* @__PURE__ */ __name((options, declared) => resolveSkillsConfig(options.skills, declared), "useFactory"),
3551
3714
  inject: [
3552
- import_nestjs_agent_core22.AGENT_OPTIONS,
3553
- import_nestjs_agent_core22.AGENT_SKILL_SOURCES
3715
+ import_nestjs_agent_core23.AGENT_OPTIONS,
3716
+ import_nestjs_agent_core23.AGENT_SKILL_SOURCES
3554
3717
  ]
3555
3718
  },
3556
3719
  {
3557
3720
  // One resolution, shared by the loop's deps and the read-back endpoint: a person has to be
3558
3721
  // shown what the model was shown, and two resolutions would eventually disagree about that.
3559
- provide: import_nestjs_agent_core22.AGENT_MEMORY,
3722
+ provide: import_nestjs_agent_core23.AGENT_MEMORY,
3560
3723
  useFactory: /* @__PURE__ */ __name((options) => options.memory, "useFactory"),
3561
3724
  inject: [
3562
- import_nestjs_agent_core22.AGENT_OPTIONS
3725
+ import_nestjs_agent_core23.AGENT_OPTIONS
3563
3726
  ]
3564
3727
  },
3565
3728
  {
3566
- provide: import_nestjs_agent_core22.AGENT_SINK,
3729
+ provide: import_nestjs_agent_core23.AGENT_SINK,
3567
3730
  useFactory: /* @__PURE__ */ __name((options) => options.sink ?? new InProcessTokenStreamSink(), "useFactory"),
3568
3731
  inject: [
3569
- import_nestjs_agent_core22.AGENT_OPTIONS
3732
+ import_nestjs_agent_core23.AGENT_OPTIONS
3570
3733
  ]
3571
3734
  },
3572
3735
  {
3573
- provide: import_nestjs_agent_core22.AGENT_ROLES_POLICY,
3574
- useFactory: /* @__PURE__ */ __name((options) => options.rolesPolicy ?? new import_nestjs_agent_core22.DefaultRolesPolicy(options.defaultRoles), "useFactory"),
3736
+ provide: import_nestjs_agent_core23.AGENT_ROLES_POLICY,
3737
+ useFactory: /* @__PURE__ */ __name((options) => options.rolesPolicy ?? new import_nestjs_agent_core23.DefaultRolesPolicy(options.defaultRoles), "useFactory"),
3575
3738
  inject: [
3576
- import_nestjs_agent_core22.AGENT_OPTIONS
3739
+ import_nestjs_agent_core23.AGENT_OPTIONS
3577
3740
  ]
3578
3741
  },
3579
3742
  {
3580
- provide: import_nestjs_agent_core22.AGENT_ACTOR_RESOLVER,
3743
+ provide: import_nestjs_agent_core23.AGENT_ACTOR_RESOLVER,
3581
3744
  useFactory: /* @__PURE__ */ __name((options) => options.actorResolver, "useFactory"),
3582
3745
  inject: [
3583
- import_nestjs_agent_core22.AGENT_OPTIONS
3746
+ import_nestjs_agent_core23.AGENT_OPTIONS
3584
3747
  ]
3585
3748
  },
3586
3749
  {
3587
- provide: import_nestjs_agent_core22.AGENT_MODEL,
3750
+ provide: import_nestjs_agent_core23.AGENT_MODEL,
3588
3751
  useFactory: /* @__PURE__ */ __name((o) => o.model, "useFactory"),
3589
3752
  inject: [
3590
- import_nestjs_agent_core22.AGENT_OPTIONS
3753
+ import_nestjs_agent_core23.AGENT_OPTIONS
3591
3754
  ]
3592
3755
  },
3593
3756
  {
3594
3757
  // An explicit `quota` wins; otherwise `quotaLimitTokens` binds the built-in ledger-backed
3595
3758
  // store; otherwise quotas are off (undefined). The ledger store reads the same usage rows
3596
3759
  // the loop already writes, so enforcement needs no extra shared state across replicas.
3597
- provide: import_nestjs_agent_core22.AGENT_QUOTA_STORE,
3760
+ provide: import_nestjs_agent_core23.AGENT_QUOTA_STORE,
3598
3761
  useFactory: /* @__PURE__ */ __name((o, store) => o.quota ?? (o.quotaLimitTokens !== void 0 ? new LedgerQuotaStore(store, o.quotaLimitTokens) : void 0), "useFactory"),
3599
3762
  inject: [
3600
- import_nestjs_agent_core22.AGENT_OPTIONS,
3601
- import_nestjs_agent_core22.AGENT_STORE
3763
+ import_nestjs_agent_core23.AGENT_OPTIONS,
3764
+ import_nestjs_agent_core23.AGENT_STORE
3765
+ ]
3766
+ },
3767
+ {
3768
+ provide: import_nestjs_agent_core23.AGENT_QUOTA_PROVIDER,
3769
+ useFactory: /* @__PURE__ */ __name((o, store, quota) => o.quotaProvider ?? new LedgerQuotaProvider(store, quota, o.quotaLimits), "useFactory"),
3770
+ inject: [
3771
+ import_nestjs_agent_core23.AGENT_OPTIONS,
3772
+ import_nestjs_agent_core23.AGENT_STORE,
3773
+ import_nestjs_agent_core23.AGENT_QUOTA_STORE
3602
3774
  ]
3603
3775
  },
3604
3776
  {
3605
- provide: import_nestjs_agent_core22.AGENT_MODEL_CATALOG,
3777
+ provide: import_nestjs_agent_core23.AGENT_MODEL_CATALOG,
3606
3778
  useFactory: /* @__PURE__ */ __name((o) => o.models, "useFactory"),
3607
3779
  inject: [
3608
- import_nestjs_agent_core22.AGENT_OPTIONS
3780
+ import_nestjs_agent_core23.AGENT_OPTIONS
3609
3781
  ]
3610
3782
  },
3611
3783
  AgentDepsFactory2,
3612
3784
  {
3613
- provide: import_nestjs_agent_core22.AGENT_DEPS_FACTORY,
3785
+ provide: import_nestjs_agent_core23.AGENT_DEPS_FACTORY,
3614
3786
  useExisting: AgentDepsFactory2
3615
3787
  },
3616
3788
  // Populates the registry + contributors (onModuleInit) BEFORE AiToolDiscoveryService synthesizes
@@ -3624,22 +3796,22 @@ function sharedProviders(durable, includeStore) {
3624
3796
  // through AgentService.signalToolCall, which reaches whichever AGENT_RUNNER is bound above.
3625
3797
  AgentApprovalPortAdapter,
3626
3798
  {
3627
- provide: import_nestjs_agent_core22.AGENT_APPROVAL_PORT,
3799
+ provide: import_nestjs_agent_core23.AGENT_APPROVAL_PORT,
3628
3800
  useExisting: AgentApprovalPortAdapter
3629
3801
  }
3630
3802
  ];
3631
3803
  if (includeStore) {
3632
3804
  providers.push({
3633
- provide: import_nestjs_agent_core22.AGENT_STORE,
3805
+ provide: import_nestjs_agent_core23.AGENT_STORE,
3634
3806
  useFactory: /* @__PURE__ */ __name((o) => o.store, "useFactory"),
3635
3807
  inject: [
3636
- import_nestjs_agent_core22.AGENT_OPTIONS
3808
+ import_nestjs_agent_core23.AGENT_OPTIONS
3637
3809
  ]
3638
3810
  });
3639
3811
  }
3640
3812
  if (durable) {
3641
3813
  providers.push({
3642
- provide: import_nestjs_agent_core22.AGENT_RUNNER,
3814
+ provide: import_nestjs_agent_core23.AGENT_RUNNER,
3643
3815
  useFactory: /* @__PURE__ */ __name((durableRunner) => {
3644
3816
  if (durableRunner === void 0) {
3645
3817
  throw new Error("AgentModule.forRoot({ durable: true }) requires importing AgentDurableModule from '@dudousxd/nestjs-agent/durable' (alongside a configured DurableModule). It was not found.");
@@ -3648,14 +3820,14 @@ function sharedProviders(durable, includeStore) {
3648
3820
  }, "useFactory"),
3649
3821
  inject: [
3650
3822
  {
3651
- token: import_nestjs_agent_core22.AGENT_DURABLE_RUNNER,
3823
+ token: import_nestjs_agent_core23.AGENT_DURABLE_RUNNER,
3652
3824
  optional: true
3653
3825
  }
3654
3826
  ]
3655
3827
  });
3656
3828
  } else {
3657
3829
  providers.push({
3658
- provide: import_nestjs_agent_core22.AGENT_RUNNER,
3830
+ provide: import_nestjs_agent_core23.AGENT_RUNNER,
3659
3831
  useExisting: InlineAgentRunner
3660
3832
  });
3661
3833
  }
@@ -3664,26 +3836,27 @@ function sharedProviders(durable, includeStore) {
3664
3836
  __name(sharedProviders, "sharedProviders");
3665
3837
  function exportsFor(includeStore) {
3666
3838
  return [
3667
- import_nestjs_agent_core22.AGENT_OPTIONS,
3668
- import_nestjs_agent_core22.AGENT_TOOL_REGISTRY,
3669
- import_nestjs_agent_core22.AGENT_REGISTRY,
3670
- import_nestjs_agent_core22.AGENT_SINK,
3671
- import_nestjs_agent_core22.AGENT_ROLES_POLICY,
3672
- import_nestjs_agent_core22.AGENT_ACTOR_RESOLVER,
3673
- import_nestjs_agent_core22.AGENT_MODEL,
3839
+ import_nestjs_agent_core23.AGENT_OPTIONS,
3840
+ import_nestjs_agent_core23.AGENT_TOOL_REGISTRY,
3841
+ import_nestjs_agent_core23.AGENT_REGISTRY,
3842
+ import_nestjs_agent_core23.AGENT_SINK,
3843
+ import_nestjs_agent_core23.AGENT_ROLES_POLICY,
3844
+ import_nestjs_agent_core23.AGENT_ACTOR_RESOLVER,
3845
+ import_nestjs_agent_core23.AGENT_MODEL,
3674
3846
  ...includeStore ? [
3675
- import_nestjs_agent_core22.AGENT_STORE
3847
+ import_nestjs_agent_core23.AGENT_STORE
3676
3848
  ] : [],
3677
- import_nestjs_agent_core22.AGENT_QUOTA_STORE,
3678
- import_nestjs_agent_core22.AGENT_MODEL_CATALOG,
3679
- import_nestjs_agent_core22.AGENT_PROMPT_CONTRIBUTORS,
3680
- import_nestjs_agent_core22.AGENT_SKILLS,
3681
- import_nestjs_agent_core22.AGENT_MEMORY,
3682
- import_nestjs_agent_core22.AGENT_DEPS_FACTORY,
3849
+ import_nestjs_agent_core23.AGENT_QUOTA_STORE,
3850
+ import_nestjs_agent_core23.AGENT_MODEL_CATALOG,
3851
+ import_nestjs_agent_core23.AGENT_QUOTA_PROVIDER,
3852
+ import_nestjs_agent_core23.AGENT_PROMPT_CONTRIBUTORS,
3853
+ import_nestjs_agent_core23.AGENT_SKILLS,
3854
+ import_nestjs_agent_core23.AGENT_MEMORY,
3855
+ import_nestjs_agent_core23.AGENT_DEPS_FACTORY,
3683
3856
  AgentDepsFactory2,
3684
3857
  AgentService,
3685
3858
  InlineAgentRunner,
3686
- import_nestjs_agent_core22.AGENT_APPROVAL_PORT
3859
+ import_nestjs_agent_core23.AGENT_APPROVAL_PORT
3687
3860
  ];
3688
3861
  }
3689
3862
  __name(exportsFor, "exportsFor");
@@ -3755,7 +3928,7 @@ var AgentModule = class _AgentModule {
3755
3928
  controllers: controllersForSurface(options.surface, options.attachments?.upload === true),
3756
3929
  providers: [
3757
3930
  {
3758
- provide: import_nestjs_agent_core22.AGENT_OPTIONS,
3931
+ provide: import_nestjs_agent_core23.AGENT_OPTIONS,
3759
3932
  useValue: options
3760
3933
  },
3761
3934
  ...sharedProviders(options.durable ?? false, includeStore),
@@ -3779,7 +3952,7 @@ var AgentModule = class _AgentModule {
3779
3952
  controllers: controllersForSurface(options.surface, options.attachmentsUpload === true),
3780
3953
  providers: [
3781
3954
  {
3782
- provide: import_nestjs_agent_core22.AGENT_OPTIONS,
3955
+ provide: import_nestjs_agent_core23.AGENT_OPTIONS,
3783
3956
  // Stamp the STATIC wiring flags onto the factory result: `durable`/`surface` are
3784
3957
  // authoritative on the async config object (they decided the actual wiring above), and
3785
3958
  // the durable module reads `durable` back off AGENT_OPTIONS. `surface` isn't read back by
@@ -3858,6 +4031,7 @@ __reExport(index_exports, require("@dudousxd/nestjs-agent-core"), module.exports
3858
4031
  HeaderActorResolver,
3859
4032
  InProcessTokenStreamSink,
3860
4033
  InlineAgentRunner,
4034
+ LedgerQuotaProvider,
3861
4035
  LedgerQuotaStore,
3862
4036
  MemoriesController,
3863
4037
  MessagesController,
@@ -3874,6 +4048,7 @@ __reExport(index_exports, require("@dudousxd/nestjs-agent-core"), module.exports
3874
4048
  declaredSkillProvider,
3875
4049
  delegateToolName,
3876
4050
  provideAgentTool,
4051
+ provideAgentTools,
3877
4052
  readAgentMetadata,
3878
4053
  readAiToolMetadata,
3879
4054
  readSkillMetadata,