@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/README.md CHANGED
@@ -179,6 +179,25 @@ provider's default; the id reaches the provider as `ModelTurnArgs.model` for eve
179
179
  A model the catalog does not list as available for that actor and agent is refused with `400` —
180
180
  when pinned and again on each turn. `staticModelCatalog(view)` wraps a fixed list.
181
181
 
182
+ ### Budgets: `GET /agent/quota`
183
+
184
+ `GET /agent/quota` reports `{ windows: [{ period: 'day' | 'month', usedTokens, limitTokens?,
185
+ usedUsd, limitUsd?, resetsAt? }], blocked? }` from a `QuotaProvider`. The default,
186
+ `LedgerQuotaProvider`, reads the usage ledger (day, plus month when the store has `usageBetween`)
187
+ and only reports. Configure it and it also gates sends — a `blocked` report refuses `POST
188
+ /agent/chat` with `429 { code: 'quota_exceeded', period }` before the turn starts:
189
+
190
+ ```ts
191
+ AgentModule.forRoot({
192
+ // ceilings on the default ledger provider
193
+ quotaLimits: { day: { tokens: 200_000 }, month: { usd: 20 } },
194
+ // …or your own budget, e.g. an AI-gateway spend cap:
195
+ // quotaProvider: { report: async ({ actor }) => myGatewayBudget(actor.id) },
196
+ });
197
+ ```
198
+
199
+ `GET /agent/quota/today` stays as it was.
200
+
182
201
  ### Who approves an action, and for how long
183
202
 
184
203
  Every `action` tool call waits on the person chatting by default. `approvalPolicy` changes that per
@@ -1,4 +1,4 @@
1
- import { ModelProvider, AgentStore, ToolRegistry, RolesPolicy, ApprovalPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, ToolTransientRetrySetting, Retriever, AgentPricingStore, HistoryPolicy, InputProcessor, OutputProcessor, AgentIntake, SkillsConfig, MemoryConfig, ToolSpec, ToolHandler, ModelCatalog, ActorResolver, AgentHistoryWindow, SkillProvider, ScopeResolver, MemoryProvider, AgentRegistry } from '@dudousxd/nestjs-agent-core';
1
+ import { ModelProvider, AgentStore, ToolRegistry, RolesPolicy, ApprovalPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, ToolTransientRetrySetting, Retriever, AgentPricingStore, HistoryPolicy, InputProcessor, OutputProcessor, AgentIntake, SkillsConfig, MemoryConfig, ToolSpec, ToolHandler, QuotaProvider, QuotaQuery, QuotaReport, ModelCatalog, ActorResolver, AgentHistoryWindow, SkillProvider, ScopeResolver, MemoryProvider, AgentRegistry } from '@dudousxd/nestjs-agent-core';
2
2
  import { StandardSchemaV1 } from '@standard-schema/spec';
3
3
  import { Provider, FactoryProvider, Type, CanActivate, ModuleMetadata, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';
4
4
 
@@ -87,6 +87,36 @@ interface FunctionalTool {
87
87
  declare function provideAgentTool(tool: FunctionalTool): Provider;
88
88
  declare function provideAgentTool(factory: (...deps: never[]) => FunctionalTool, inject?: FactoryProvider['inject']): Provider;
89
89
 
90
+ /** Ceilings for a {@link LedgerQuotaProvider} window. Either, both, or neither. */
91
+ interface QuotaWindowLimits {
92
+ tokens?: number;
93
+ usd?: number;
94
+ }
95
+ /** Per-window ceilings: `AgentModule.forRoot({ quotaLimits })`. */
96
+ interface QuotaLimits {
97
+ day?: QuotaWindowLimits;
98
+ month?: QuotaWindowLimits;
99
+ }
100
+ /**
101
+ * The default {@link QuotaProvider}: windows read off the usage ledger the loop already writes.
102
+ *
103
+ * - `day` — always; `usedTokens`/limit come from the bound {@link QuotaStore} when there is one (so
104
+ * the report matches what the loop enforces), spend from the ledger.
105
+ * - `month` — when the store implements `usageBetween`.
106
+ *
107
+ * `limits` add ceilings per window (tokens and/or USD). A window that reaches one makes the report
108
+ * `blocked`.
109
+ */
110
+ declare class LedgerQuotaProvider implements QuotaProvider {
111
+ private readonly store;
112
+ private readonly quota?;
113
+ private readonly limits;
114
+ constructor(store: AgentStore, quota?: QuotaStore | undefined, limits?: QuotaLimits);
115
+ report(query: QuotaQuery): Promise<QuotaReport>;
116
+ private dayWindow;
117
+ private window;
118
+ }
119
+
90
120
  /**
91
121
  * Which half of the module this process mounts — the split that lets an API pod and a WORKER pod
92
122
  * each load `AgentModule` without either one doing the other's job:
@@ -205,6 +235,17 @@ interface AgentModuleOptions {
205
235
  * `ModelTurnArgs.model`. Omit → an empty catalog, and a request naming a model is refused.
206
236
  */
207
237
  models?: ModelCatalog;
238
+ /**
239
+ * The actor's budget across windows, for `GET <base>/quota` — and, once set, a gate: a send whose
240
+ * report comes back `blocked` is refused with `429` before the turn starts. Default: a
241
+ * {@link LedgerQuotaProvider} over the usage ledger (reporting only, unless `quotaLimits` is set).
242
+ */
243
+ quotaProvider?: QuotaProvider;
244
+ /**
245
+ * Ceilings for the default ledger provider's windows — `{ day?: { tokens?, usd? }, month?: {
246
+ * tokens?, usd? } }`. Setting it turns the send gate on. Ignored when `quotaProvider` is given.
247
+ */
248
+ quotaLimits?: QuotaLimits;
208
249
  /**
209
250
  * Daily per-actor token budget, enforced against the persisted usage ledger by the built-in
210
251
  * `LedgerQuotaStore`. A convenience over wiring a {@link QuotaStore} by hand — set this and quotas
@@ -479,4 +520,4 @@ declare class AgentDepsFactory {
479
520
  private followUpsCount;
480
521
  }
481
522
 
482
- export { AgentDepsFactory as A, type FunctionalTool as F, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentSkillsOptions as d, AGENT_TOOL_BRAND as e, type AgentAttachmentsOptions as f, type AgentDeps as g, type AgentMemoryOptions as h, delegateToolName as i, provideAgentTool as p, utcDay as u };
523
+ export { AgentDepsFactory as A, type FunctionalTool as F, LedgerQuotaProvider as L, type QuotaLimits as Q, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentSkillsOptions as d, AGENT_TOOL_BRAND as e, type AgentAttachmentsOptions as f, type AgentDeps as g, type AgentMemoryOptions as h, type QuotaWindowLimits as i, delegateToolName as j, provideAgentTool as p, utcDay as u };
@@ -1,4 +1,4 @@
1
- import { ModelProvider, AgentStore, ToolRegistry, RolesPolicy, ApprovalPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, ToolTransientRetrySetting, Retriever, AgentPricingStore, HistoryPolicy, InputProcessor, OutputProcessor, AgentIntake, SkillsConfig, MemoryConfig, ToolSpec, ToolHandler, ModelCatalog, ActorResolver, AgentHistoryWindow, SkillProvider, ScopeResolver, MemoryProvider, AgentRegistry } from '@dudousxd/nestjs-agent-core';
1
+ import { ModelProvider, AgentStore, ToolRegistry, RolesPolicy, ApprovalPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, ToolTransientRetrySetting, Retriever, AgentPricingStore, HistoryPolicy, InputProcessor, OutputProcessor, AgentIntake, SkillsConfig, MemoryConfig, ToolSpec, ToolHandler, QuotaProvider, QuotaQuery, QuotaReport, ModelCatalog, ActorResolver, AgentHistoryWindow, SkillProvider, ScopeResolver, MemoryProvider, AgentRegistry } from '@dudousxd/nestjs-agent-core';
2
2
  import { StandardSchemaV1 } from '@standard-schema/spec';
3
3
  import { Provider, FactoryProvider, Type, CanActivate, ModuleMetadata, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';
4
4
 
@@ -87,6 +87,36 @@ interface FunctionalTool {
87
87
  declare function provideAgentTool(tool: FunctionalTool): Provider;
88
88
  declare function provideAgentTool(factory: (...deps: never[]) => FunctionalTool, inject?: FactoryProvider['inject']): Provider;
89
89
 
90
+ /** Ceilings for a {@link LedgerQuotaProvider} window. Either, both, or neither. */
91
+ interface QuotaWindowLimits {
92
+ tokens?: number;
93
+ usd?: number;
94
+ }
95
+ /** Per-window ceilings: `AgentModule.forRoot({ quotaLimits })`. */
96
+ interface QuotaLimits {
97
+ day?: QuotaWindowLimits;
98
+ month?: QuotaWindowLimits;
99
+ }
100
+ /**
101
+ * The default {@link QuotaProvider}: windows read off the usage ledger the loop already writes.
102
+ *
103
+ * - `day` — always; `usedTokens`/limit come from the bound {@link QuotaStore} when there is one (so
104
+ * the report matches what the loop enforces), spend from the ledger.
105
+ * - `month` — when the store implements `usageBetween`.
106
+ *
107
+ * `limits` add ceilings per window (tokens and/or USD). A window that reaches one makes the report
108
+ * `blocked`.
109
+ */
110
+ declare class LedgerQuotaProvider implements QuotaProvider {
111
+ private readonly store;
112
+ private readonly quota?;
113
+ private readonly limits;
114
+ constructor(store: AgentStore, quota?: QuotaStore | undefined, limits?: QuotaLimits);
115
+ report(query: QuotaQuery): Promise<QuotaReport>;
116
+ private dayWindow;
117
+ private window;
118
+ }
119
+
90
120
  /**
91
121
  * Which half of the module this process mounts — the split that lets an API pod and a WORKER pod
92
122
  * each load `AgentModule` without either one doing the other's job:
@@ -205,6 +235,17 @@ interface AgentModuleOptions {
205
235
  * `ModelTurnArgs.model`. Omit → an empty catalog, and a request naming a model is refused.
206
236
  */
207
237
  models?: ModelCatalog;
238
+ /**
239
+ * The actor's budget across windows, for `GET <base>/quota` — and, once set, a gate: a send whose
240
+ * report comes back `blocked` is refused with `429` before the turn starts. Default: a
241
+ * {@link LedgerQuotaProvider} over the usage ledger (reporting only, unless `quotaLimits` is set).
242
+ */
243
+ quotaProvider?: QuotaProvider;
244
+ /**
245
+ * Ceilings for the default ledger provider's windows — `{ day?: { tokens?, usd? }, month?: {
246
+ * tokens?, usd? } }`. Setting it turns the send gate on. Ignored when `quotaProvider` is given.
247
+ */
248
+ quotaLimits?: QuotaLimits;
208
249
  /**
209
250
  * Daily per-actor token budget, enforced against the persisted usage ledger by the built-in
210
251
  * `LedgerQuotaStore`. A convenience over wiring a {@link QuotaStore} by hand — set this and quotas
@@ -479,4 +520,4 @@ declare class AgentDepsFactory {
479
520
  private followUpsCount;
480
521
  }
481
522
 
482
- export { AgentDepsFactory as A, type FunctionalTool as F, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentSkillsOptions as d, AGENT_TOOL_BRAND as e, type AgentAttachmentsOptions as f, type AgentDeps as g, type AgentMemoryOptions as h, delegateToolName as i, provideAgentTool as p, utcDay as u };
523
+ export { AgentDepsFactory as A, type FunctionalTool as F, LedgerQuotaProvider as L, type QuotaLimits as Q, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentSkillsOptions as d, AGENT_TOOL_BRAND as e, type AgentAttachmentsOptions as f, type AgentDeps as g, type AgentMemoryOptions as h, type QuotaWindowLimits as i, delegateToolName as j, provideAgentTool as p, utcDay as u };