@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.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-DuTy1UyU.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, k as provideAgentTools, u as utcDay } from './agent-deps.factory-DuTy1UyU.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-DuTy1UyU.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, k as provideAgentTools, u as utcDay } from './agent-deps.factory-DuTy1UyU.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";
@@ -2613,6 +2692,14 @@ function provideAgentTool(factoryOrTool, inject) {
2613
2692
  };
2614
2693
  }
2615
2694
  __name(provideAgentTool, "provideAgentTool");
2695
+ function provideAgentTools(factory, inject) {
2696
+ return {
2697
+ provide: /* @__PURE__ */ Symbol("nestjs-agent:functional-tool-list"),
2698
+ useFactory: /* @__PURE__ */ __name(async (...deps) => (await factory(...deps)).map(brand), "useFactory"),
2699
+ inject: inject ?? []
2700
+ };
2701
+ }
2702
+ __name(provideAgentTools, "provideAgentTools");
2616
2703
 
2617
2704
  // src/discovery/ai-tool-discovery.service.ts
2618
2705
  function _ts_decorate16(decorators, target, key, desc) {
@@ -2664,6 +2751,14 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
2664
2751
  if (instance === null || instance === void 0 || typeof instance !== "object") {
2665
2752
  continue;
2666
2753
  }
2754
+ if (Array.isArray(instance) && instance.length > 0 && instance.every((each) => typeof each === "object" && each !== null && isBrandedFunctionalTool(each))) {
2755
+ for (const tool of instance) {
2756
+ if (this.registerFunctionalTool(tool)) {
2757
+ functional += 1;
2758
+ }
2759
+ }
2760
+ continue;
2761
+ }
2667
2762
  if (isBrandedFunctionalTool(instance)) {
2668
2763
  if (this.registerFunctionalTool(instance)) {
2669
2764
  functional += 1;
@@ -2711,6 +2806,9 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
2711
2806
  } : {},
2712
2807
  ...typeof handler.canUse === "function" ? {
2713
2808
  canUse: /* @__PURE__ */ __name((actor) => instance.canUse(actor), "canUse")
2809
+ } : {},
2810
+ ...typeof handler.describe === "function" ? {
2811
+ describe: /* @__PURE__ */ __name((scope) => instance.describe(scope), "describe")
2714
2812
  } : {}
2715
2813
  });
2716
2814
  count += 1;
@@ -2777,7 +2875,7 @@ AiToolDiscoveryService = _ts_decorate16([
2777
2875
  Injectable5(),
2778
2876
  _ts_param15(1, Inject15(AGENT_TOOL_REGISTRY2)),
2779
2877
  _ts_param15(2, Inject15(AGENT_REGISTRY5)),
2780
- _ts_param15(3, Inject15(AGENT_OPTIONS3)),
2878
+ _ts_param15(3, Inject15(AGENT_OPTIONS4)),
2781
2879
  _ts_metadata16("design:type", Function),
2782
2880
  _ts_metadata16("design:paramtypes", [
2783
2881
  typeof DiscoveryService2 === "undefined" ? Object : DiscoveryService2,
@@ -2959,6 +3057,69 @@ var InProcessTokenStreamSink = class {
2959
3057
  }
2960
3058
  };
2961
3059
 
3060
+ // src/ledger-quota-provider.ts
3061
+ import { exhaustedWindow, quotaPeriodRange } from "@dudousxd/nestjs-agent-core";
3062
+ var LedgerQuotaProvider = class {
3063
+ static {
3064
+ __name(this, "LedgerQuotaProvider");
3065
+ }
3066
+ store;
3067
+ quota;
3068
+ limits;
3069
+ constructor(store, quota, limits = {}) {
3070
+ this.store = store;
3071
+ this.quota = quota;
3072
+ this.limits = limits;
3073
+ }
3074
+ async report(query) {
3075
+ const now = query.now ?? /* @__PURE__ */ new Date();
3076
+ const actorRef = query.actor.id;
3077
+ const windows = [
3078
+ await this.dayWindow(actorRef, now)
3079
+ ];
3080
+ if (this.store.usageBetween !== void 0) {
3081
+ const range = quotaPeriodRange("month", now);
3082
+ const used = await this.store.usageBetween(actorRef, range.fromDay, range.toDay);
3083
+ windows.push(this.window("month", used.usedTokens, used.costUsd, range.resetsAt));
3084
+ }
3085
+ const blocked = exhaustedWindow(windows);
3086
+ return {
3087
+ windows,
3088
+ ...blocked !== void 0 ? {
3089
+ blocked
3090
+ } : {}
3091
+ };
3092
+ }
3093
+ async dayWindow(actorRef, now) {
3094
+ const range = quotaPeriodRange("day", now);
3095
+ const { usedTokens, costUsd } = await this.store.quotaToday(actorRef, range.fromDay);
3096
+ if (this.quota === void 0) {
3097
+ return this.window("day", usedTokens, costUsd, range.resetsAt);
3098
+ }
3099
+ const state = await this.quota.check(actorRef, range.fromDay);
3100
+ const window = this.window("day", state.usedTokens, costUsd, range.resetsAt);
3101
+ if (window.limitTokens === void 0) {
3102
+ window.limitTokens = state.limitTokens;
3103
+ }
3104
+ return window;
3105
+ }
3106
+ window(period, usedTokens, usedUsd, resetsAt) {
3107
+ const limits = this.limits[period] ?? {};
3108
+ return {
3109
+ period,
3110
+ usedTokens,
3111
+ ...limits.tokens !== void 0 ? {
3112
+ limitTokens: limits.tokens
3113
+ } : {},
3114
+ usedUsd,
3115
+ ...limits.usd !== void 0 ? {
3116
+ limitUsd: limits.usd
3117
+ } : {},
3118
+ resetsAt
3119
+ };
3120
+ }
3121
+ };
3122
+
2962
3123
  // src/ledger-quota-store.ts
2963
3124
  var LedgerQuotaStore = class {
2964
3125
  static {
@@ -3485,7 +3646,7 @@ function sharedProviders(durable, includeStore) {
3485
3646
  provide: AGENT_SKILLS3,
3486
3647
  useFactory: /* @__PURE__ */ __name((options, declared) => resolveSkillsConfig(options.skills, declared), "useFactory"),
3487
3648
  inject: [
3488
- AGENT_OPTIONS4,
3649
+ AGENT_OPTIONS5,
3489
3650
  AGENT_SKILL_SOURCES2
3490
3651
  ]
3491
3652
  },
@@ -3495,35 +3656,35 @@ function sharedProviders(durable, includeStore) {
3495
3656
  provide: AGENT_MEMORY3,
3496
3657
  useFactory: /* @__PURE__ */ __name((options) => options.memory, "useFactory"),
3497
3658
  inject: [
3498
- AGENT_OPTIONS4
3659
+ AGENT_OPTIONS5
3499
3660
  ]
3500
3661
  },
3501
3662
  {
3502
3663
  provide: AGENT_SINK2,
3503
3664
  useFactory: /* @__PURE__ */ __name((options) => options.sink ?? new InProcessTokenStreamSink(), "useFactory"),
3504
3665
  inject: [
3505
- AGENT_OPTIONS4
3666
+ AGENT_OPTIONS5
3506
3667
  ]
3507
3668
  },
3508
3669
  {
3509
3670
  provide: AGENT_ROLES_POLICY2,
3510
3671
  useFactory: /* @__PURE__ */ __name((options) => options.rolesPolicy ?? new DefaultRolesPolicy(options.defaultRoles), "useFactory"),
3511
3672
  inject: [
3512
- AGENT_OPTIONS4
3673
+ AGENT_OPTIONS5
3513
3674
  ]
3514
3675
  },
3515
3676
  {
3516
3677
  provide: AGENT_ACTOR_RESOLVER11,
3517
3678
  useFactory: /* @__PURE__ */ __name((options) => options.actorResolver, "useFactory"),
3518
3679
  inject: [
3519
- AGENT_OPTIONS4
3680
+ AGENT_OPTIONS5
3520
3681
  ]
3521
3682
  },
3522
3683
  {
3523
3684
  provide: AGENT_MODEL2,
3524
3685
  useFactory: /* @__PURE__ */ __name((o) => o.model, "useFactory"),
3525
3686
  inject: [
3526
- AGENT_OPTIONS4
3687
+ AGENT_OPTIONS5
3527
3688
  ]
3528
3689
  },
3529
3690
  {
@@ -3533,15 +3694,24 @@ function sharedProviders(durable, includeStore) {
3533
3694
  provide: AGENT_QUOTA_STORE3,
3534
3695
  useFactory: /* @__PURE__ */ __name((o, store) => o.quota ?? (o.quotaLimitTokens !== void 0 ? new LedgerQuotaStore(store, o.quotaLimitTokens) : void 0), "useFactory"),
3535
3696
  inject: [
3536
- AGENT_OPTIONS4,
3697
+ AGENT_OPTIONS5,
3537
3698
  AGENT_STORE4
3538
3699
  ]
3539
3700
  },
3701
+ {
3702
+ provide: AGENT_QUOTA_PROVIDER2,
3703
+ useFactory: /* @__PURE__ */ __name((o, store, quota) => o.quotaProvider ?? new LedgerQuotaProvider(store, quota, o.quotaLimits), "useFactory"),
3704
+ inject: [
3705
+ AGENT_OPTIONS5,
3706
+ AGENT_STORE4,
3707
+ AGENT_QUOTA_STORE3
3708
+ ]
3709
+ },
3540
3710
  {
3541
3711
  provide: AGENT_MODEL_CATALOG2,
3542
3712
  useFactory: /* @__PURE__ */ __name((o) => o.models, "useFactory"),
3543
3713
  inject: [
3544
- AGENT_OPTIONS4
3714
+ AGENT_OPTIONS5
3545
3715
  ]
3546
3716
  },
3547
3717
  AgentDepsFactory2,
@@ -3569,7 +3739,7 @@ function sharedProviders(durable, includeStore) {
3569
3739
  provide: AGENT_STORE4,
3570
3740
  useFactory: /* @__PURE__ */ __name((o) => o.store, "useFactory"),
3571
3741
  inject: [
3572
- AGENT_OPTIONS4
3742
+ AGENT_OPTIONS5
3573
3743
  ]
3574
3744
  });
3575
3745
  }
@@ -3600,7 +3770,7 @@ function sharedProviders(durable, includeStore) {
3600
3770
  __name(sharedProviders, "sharedProviders");
3601
3771
  function exportsFor(includeStore) {
3602
3772
  return [
3603
- AGENT_OPTIONS4,
3773
+ AGENT_OPTIONS5,
3604
3774
  AGENT_TOOL_REGISTRY3,
3605
3775
  AGENT_REGISTRY6,
3606
3776
  AGENT_SINK2,
@@ -3612,6 +3782,7 @@ function exportsFor(includeStore) {
3612
3782
  ] : [],
3613
3783
  AGENT_QUOTA_STORE3,
3614
3784
  AGENT_MODEL_CATALOG2,
3785
+ AGENT_QUOTA_PROVIDER2,
3615
3786
  AGENT_PROMPT_CONTRIBUTORS3,
3616
3787
  AGENT_SKILLS3,
3617
3788
  AGENT_MEMORY3,
@@ -3691,7 +3862,7 @@ var AgentModule = class _AgentModule {
3691
3862
  controllers: controllersForSurface(options.surface, options.attachments?.upload === true),
3692
3863
  providers: [
3693
3864
  {
3694
- provide: AGENT_OPTIONS4,
3865
+ provide: AGENT_OPTIONS5,
3695
3866
  useValue: options
3696
3867
  },
3697
3868
  ...sharedProviders(options.durable ?? false, includeStore),
@@ -3715,7 +3886,7 @@ var AgentModule = class _AgentModule {
3715
3886
  controllers: controllersForSurface(options.surface, options.attachmentsUpload === true),
3716
3887
  providers: [
3717
3888
  {
3718
- provide: AGENT_OPTIONS4,
3889
+ provide: AGENT_OPTIONS5,
3719
3890
  // Stamp the STATIC wiring flags onto the factory result: `durable`/`surface` are
3720
3891
  // authoritative on the async config object (they decided the actual wiring above), and
3721
3892
  // the durable module reads `durable` back off AGENT_OPTIONS. `surface` isn't read back by
@@ -3793,6 +3964,7 @@ export {
3793
3964
  HeaderActorResolver,
3794
3965
  InProcessTokenStreamSink,
3795
3966
  InlineAgentRunner,
3967
+ LedgerQuotaProvider,
3796
3968
  LedgerQuotaStore,
3797
3969
  MemoriesController,
3798
3970
  MessagesController,
@@ -3809,6 +3981,7 @@ export {
3809
3981
  declaredSkillProvider,
3810
3982
  delegateToolName,
3811
3983
  provideAgentTool,
3984
+ provideAgentTools,
3812
3985
  readAgentMetadata,
3813
3986
  readAiToolMetadata,
3814
3987
  readSkillMetadata,