@dudousxd/nestjs-agent 1.11.0 → 1.12.1

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
@@ -142,9 +142,13 @@ With nothing bound to `AGENT_ATTACHMENT_STAGING` there is no way to tell whose m
142
142
  turn carrying attachments is refused with `501`. Text-only turns are unaffected. At most 10
143
143
  attachments per turn.
144
144
 
145
- The optional `POST /agent/attachments` upload route (`attachments: { upload: true }`) aborts a body
146
- larger than `HARD_MAX_ATTACHMENT_BYTES` (32 MiB) while it streams; `attachments.maxBytes` narrows
147
- that ceiling at request time and cannot raise it.
145
+ `POST /agent/attachments` (multipart, live whenever a staging store is bound — `501` otherwise)
146
+ aborts a body larger than `HARD_MAX_ATTACHMENT_BYTES` (32 MiB) while it streams; the configured
147
+ `maxBytes` narrows that ceiling at request time and cannot raise it. The limits come from ONE place:
148
+ the staging store's own `describe()` when it declares them (`AgentMediaAttachmentsModule` does),
149
+ else `AgentModule`'s `attachments: { maxBytes, allowedContentTypes }`, else 20 MiB and the default
150
+ types. `GET /agent/config` serves them — with the upload mode (`multipart` or `resumable`) and the
151
+ per-message cap — so a client never repeats them.
148
152
 
149
153
  ### Sweeping attachments nobody sent
150
154
 
@@ -170,8 +174,7 @@ regenerating a turn does — deletes messages and frees their media again. If ei
170
174
  missing the call raises `501` rather than reporting everything as collectable.
171
175
 
172
176
  `GET /agent/attachments` returns the caller's own staged files as metadata (no urls — those are
173
- minted per turn by `resolve`), bounded to `ATTACHMENT_PAGE_SIZE`, and rides the same
174
- `attachments: { upload: true }` flag. It takes no `threadId` filter: a thread's attachments already
177
+ minted per turn by `resolve`), bounded to `ATTACHMENT_PAGE_SIZE`. It takes no `threadId` filter: a thread's attachments already
175
178
  ride on its messages in `GET /agent/threads/:id`.
176
179
 
177
180
  ### Attachments on nestjs-media (`@dudousxd/nestjs-agent/media`)
@@ -218,10 +221,14 @@ Each attachment is a media record (`ownerType: 'agent-actor'`, `ownerId: actor.i
218
221
  | 3. complete | `POST /agent/attachments/uploads/:mediaId/complete` → `MessageAttachment` | agent — checks the bytes landed at the declared size |
219
222
  | drop | `DELETE /agent/attachments/uploads/:mediaId` | agent — aborts the session, deletes bytes + record |
220
223
 
221
- `@dudousxd/nestjs-agent-react/media` drives all three for `useAttachments`. `POST /agent/attachments`
222
- (the buffered multipart route, `attachments: { upload: true }`) keeps working on the same store — its
223
- `stage()` writes a media record too — but it is not needed with this module; `GET
224
- /agent/attachments` lists either kind.
224
+ `@dudousxd/nestjs-agent-react/media` drives all three for `useAttachments`; this is THE upload route
225
+ with this module (`GET /agent/config` answers `upload: 'resumable'`). The buffered multipart `POST
226
+ /agent/attachments` still stages into the same store, but is not the documented path here; `GET
227
+ /agent/attachments` lists either kind. The module's `maxBytes` / `allowedContentTypes` are the only
228
+ limits in force — `AgentModule`'s `attachments` option is ignored while it is imported.
229
+
230
+ A replayed thread (`GET /agent/threads/:id`) re-mints each attachment's url from the store by
231
+ `mediaId` on every read, so an old turn never shows an expired presigned link.
225
232
 
226
233
  `resolve` hands the model provider a presigned url when the disk can mint one (`urlExpiresInSeconds`,
227
234
  default 7 days), the disk's public `url()` with `visibility: 'public'`, or — on a disk that can do
@@ -273,8 +280,8 @@ export class S3Staging implements AttachmentStagingStore {
273
280
  { provide: AGENT_ATTACHMENT_STAGING, useClass: S3Staging }
274
281
  ```
275
282
 
276
- Then either set `attachments: { upload: true }` for the built-in `POST /agent/attachments` (which
277
- calls your `stage`), or upload through your own route and give the React side your own `upload`
283
+ Then the built-in `POST /agent/attachments` calls your `stage` (no flag — binding the store is what
284
+ turns it on), or upload through your own route and give the React side your own `upload`
278
285
  (`useAttachments({ upload })` / a backend's `uploadAttachment`) that resolves to a `{ mediaId, … }`
279
286
  your `resolve` recognises. `list` is optional and only needed for `GET /agent/attachments` and
280
287
  sweeping.
@@ -348,13 +355,13 @@ and only reports. Configure it and it also gates sends — a `blocked` report re
348
355
  ```ts
349
356
  AgentModule.forRoot({
350
357
  // ceilings on the default ledger provider
351
- quotaLimits: { day: { tokens: 200_000 }, month: { usd: 20 } },
358
+ quota: { limits: { day: { tokens: 200_000 }, month: { usd: 20 } } },
352
359
  // …or your own budget, e.g. an AI-gateway spend cap:
353
- // quotaProvider: { report: async ({ actor }) => myGatewayBudget(actor.id) },
360
+ // quota: { report: async ({ actor }) => myGatewayBudget(actor.id) },
354
361
  });
355
362
  ```
356
363
 
357
- `GET /agent/quota/today` stays as it was.
364
+ In anonymous mode the limits apply per browser (each is its own actor).
358
365
 
359
366
  ### Who approves an action, and for how long
360
367
 
@@ -98,7 +98,7 @@ interface QuotaWindowLimits {
98
98
  tokens?: number;
99
99
  usd?: number;
100
100
  }
101
- /** Per-window ceilings: `AgentModule.forRoot({ quotaLimits })`. */
101
+ /** Per-window ceilings: `AgentModule.forRoot({ quota: { limits } })`. */
102
102
  interface QuotaLimits {
103
103
  day?: QuotaWindowLimits;
104
104
  month?: QuotaWindowLimits;
@@ -106,8 +106,7 @@ interface QuotaLimits {
106
106
  /**
107
107
  * The default {@link QuotaProvider}: windows read off the usage ledger the loop already writes.
108
108
  *
109
- * - `day` — always; `usedTokens`/limit come from the bound {@link QuotaStore} when there is one (so
110
- * the report matches what the loop enforces), spend from the ledger.
109
+ * - `day` — always.
111
110
  * - `month` — when the store implements `usageBetween`.
112
111
  *
113
112
  * `limits` add ceilings per window (tokens and/or USD). A window that reaches one makes the report
@@ -115,9 +114,8 @@ interface QuotaLimits {
115
114
  */
116
115
  declare class LedgerQuotaProvider implements QuotaProvider {
117
116
  private readonly store;
118
- private readonly quota?;
119
117
  private readonly limits;
120
- constructor(store: AgentStore, quota?: QuotaStore | undefined, limits?: QuotaLimits);
118
+ constructor(store: AgentStore, limits?: QuotaLimits);
121
119
  report(query: QuotaQuery): Promise<QuotaReport>;
122
120
  private dayWindow;
123
121
  private window;
@@ -144,8 +142,9 @@ declare class LedgerQuotaProvider implements QuotaProvider {
144
142
  */
145
143
  type AgentSurface = 'http' | 'engine' | 'both';
146
144
  /**
147
- * `AgentModuleOptions.attachments` — bounds and content-type allowlist for the optional
148
- * `POST /agent/attachments` upload controller (see `attachments.upload`).
145
+ * `AgentModuleOptions.attachments` — limits for `POST <base>/attachments`, when the bound
146
+ * `AGENT_ATTACHMENT_STAGING` store does not declare its own (`AgentMediaAttachmentsModule` does, and
147
+ * then it is the only source). Served to clients by `GET <base>/config`.
149
148
  */
150
149
  interface AgentAttachmentsOptions {
151
150
  /** Per-file size cap. Defaults to 20 MiB. */
@@ -155,13 +154,6 @@ interface AgentAttachmentsOptions {
155
154
  * `image/png`, `image/jpeg`, `image/gif`, `image/webp`, `application/pdf`, `text/plain`, `text/csv`.
156
155
  */
157
156
  allowedContentTypes?: string[];
158
- /**
159
- * Mount `POST /agent/attachments`. Defaults to `false` — the controller is build-time (static)
160
- * wiring, so this can't be inferred from whether `AGENT_ATTACHMENT_STAGING` ends up bound (that's
161
- * a DI-time fact); set it explicitly. `true` with no `AGENT_ATTACHMENT_STAGING` provider bound
162
- * fails boot loudly instead of silently mounting a controller that 501s on every request.
163
- */
164
- upload?: boolean;
165
157
  }
166
158
  /**
167
159
  * `AgentModuleOptions.skills` — where a turn's skills come from, and which scopes an actor draws
@@ -240,34 +232,22 @@ interface AgentModuleOptions {
240
232
  /** Live token transport. Defaults to a single-process in-memory sink. */
241
233
  sink?: TokenStreamSink;
242
234
  /**
243
- * A {@link QuotaStore} for the daily token budget. Optional — omit (and omit `quotaLimitTokens`)
244
- * to disable quotas. Provide this to plug a custom budget; for the common case use the simpler
245
- * `quotaLimitTokens` instead, which binds the built-in ledger-backed store.
235
+ * The caller's budget. `{ limits: { day?: { tokens?, usd? }, month?: { tokens?, usd? } } }` puts
236
+ * ceilings on the built-in ledger provider; a {@link QuotaProvider} of your own replaces it. Either
237
+ * way `GET <base>/quota` reports it and a send whose report comes back `blocked` is refused with
238
+ * `429` before the turn starts. Omit → reported (usage off the ledger), never enforced — for a
239
+ * public (anonymous) deployment that means unbounded model spend, so set limits there; they apply
240
+ * per actor, which is per browser in anonymous mode.
246
241
  */
247
- quota?: QuotaStore;
242
+ quota?: {
243
+ limits: QuotaLimits;
244
+ } | QuotaProvider;
248
245
  /**
249
246
  * Which models a caller may pick — `GET <base>/models`, a send's `model`, a thread's pinned model
250
- * (`PATCH <base>/threads/:id { model }`). The picked id reaches the {@link ModelProvider} as
251
- * `ModelTurnArgs.model`. Omit → an empty catalog, and a request naming a model is refused.
247
+ * (`PATCH <base>/threads/:id { model }`). Omit → the catalog the model provider carries
248
+ * (`aiSdkModels`), else none, and a request naming a model is refused.
252
249
  */
253
250
  models?: ModelCatalog;
254
- /**
255
- * The actor's budget across windows, for `GET <base>/quota` — and, once set, a gate: a send whose
256
- * report comes back `blocked` is refused with `429` before the turn starts. Default: a
257
- * {@link LedgerQuotaProvider} over the usage ledger (reporting only, unless `quotaLimits` is set).
258
- */
259
- quotaProvider?: QuotaProvider;
260
- /**
261
- * Ceilings for the default ledger provider's windows — `{ day?: { tokens?, usd? }, month?: {
262
- * tokens?, usd? } }`. Setting it turns the send gate on. Ignored when `quotaProvider` is given.
263
- */
264
- quotaLimits?: QuotaLimits;
265
- /**
266
- * Daily per-actor token budget, enforced against the persisted usage ledger by the built-in
267
- * `LedgerQuotaStore`. A convenience over wiring a {@link QuotaStore} by hand — set this and quotas
268
- * turn on with no extra store. Ignored when an explicit `quota` is provided. Omit to disable.
269
- */
270
- quotaLimitTokens?: number;
271
251
  /** Tool authorization gate. Defaults to role-in-`defaultRoles`. */
272
252
  rolesPolicy?: RolesPolicy;
273
253
  /**
@@ -361,7 +341,7 @@ interface AgentModuleOptions {
361
341
  /**
362
342
  * A {@link HistoryPolicy} of your own — for a window the built-in can't express (pinning the
363
343
  * thread's opening brief, keeping every message that carries a tool result, a budget that varies
364
- * by actor). A convenience-vs-custom pair like `quotaLimitTokens`/`quota`: this outranks a
344
+ * by actor). A convenience-vs-custom pair: this outranks a
365
345
  * module-wide `history`, and `@Agent({ history })` outranks both for the agent that declares it.
366
346
  * `select` MUST be pure — see the SPI's determinism contract.
367
347
  */
@@ -426,14 +406,14 @@ interface AgentModuleOptions {
426
406
  defaultAgent?: string;
427
407
  /**
428
408
  * Guard(s) applied uniformly to EVERY controller this module mounts (chat, threads, tool-call,
429
- * quota, agents, and — when `attachments.upload` is set — attachments). Third-party controller
409
+ * quota, agents, attachments, config, …). Third-party controller
430
410
  * classes can't be annotated with `@UseGuards` by consumers, so without this option every route is
431
411
  * open beyond whatever `actorResolver` itself enforces. Guard classes are added to this module's
432
412
  * `providers` so Nest can DI-instantiate them; if a guard has its own dependencies, make sure they
433
413
  * resolve from this module's imports or a global module.
434
414
  */
435
415
  guards?: Type<CanActivate>[];
436
- /** Bounds/allowlist for the optional attachment-upload controller. Omit → 20 MiB, the documented default types, not mounted. */
416
+ /** Upload limits when the staging store declares none. Omit → 20 MiB and the default types. */
437
417
  attachments?: AgentAttachmentsOptions;
438
418
  /**
439
419
  * Which half of the module this process mounts (see {@link AgentSurface}). Omit → `'both'`,
@@ -465,16 +445,9 @@ interface AgentModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
465
445
  * `useFactory`. Same default-open caveat as `AgentModuleOptions.guards`.
466
446
  */
467
447
  guards?: Type<CanActivate>[];
468
- /**
469
- * Mount `POST /agent/attachments`. Static, build-time control (same reasoning as `durable`/`path`
470
- * above) — `useFactory` resolves too late to decide which controllers exist. The resolved
471
- * `AgentModuleOptions.attachments` (maxBytes/allowedContentTypes) still applies at request time;
472
- * only the yes/no mount decision has to live here.
473
- */
474
- attachmentsUpload?: boolean;
475
448
  /**
476
449
  * Which half of the module this process mounts (see {@link AgentSurface}). Same static-wiring
477
- * reasoning as `attachmentsUpload`/`durable` above — `useFactory` resolves too late to decide
450
+ * reasoning as `durable` above — `useFactory` resolves too late to decide
478
451
  * which controllers exist. Omit → `'both'`, today's behavior with zero change.
479
452
  */
480
453
  surface?: AgentSurface;
@@ -502,11 +475,10 @@ declare class AgentDepsFactory {
502
475
  private readonly registry;
503
476
  private readonly agents;
504
477
  private readonly promptContributors;
505
- private readonly quota;
506
478
  private readonly pricingStore;
507
479
  private readonly skills;
508
480
  private readonly memory;
509
- constructor(options: AgentModuleOptions, model: ModelProvider, store: AgentStore, sink: TokenStreamSink, rolesPolicy: RolesPolicy, registry: ToolRegistry, agents: AgentRegistry, promptContributors: PromptContributor[], quota: QuotaStore | undefined, pricingStore: AgentPricingStore | undefined, skills: SkillsConfig | undefined, memory: MemoryConfig | undefined);
481
+ constructor(options: AgentModuleOptions, model: ModelProvider, store: AgentStore, sink: TokenStreamSink, rolesPolicy: RolesPolicy, registry: ToolRegistry, agents: AgentRegistry, promptContributors: PromptContributor[], pricingStore: AgentPricingStore | undefined, skills: SkillsConfig | undefined, memory: MemoryConfig | undefined);
510
482
  /** The turn's memory seam, shared with the read-back endpoint. Undefined → memory is not configured. */
511
483
  memoryConfig(): MemoryConfig | undefined;
512
484
  /** The turn's skills seam, shared with the listing endpoint. Undefined → skills are not configured. */
@@ -98,7 +98,7 @@ interface QuotaWindowLimits {
98
98
  tokens?: number;
99
99
  usd?: number;
100
100
  }
101
- /** Per-window ceilings: `AgentModule.forRoot({ quotaLimits })`. */
101
+ /** Per-window ceilings: `AgentModule.forRoot({ quota: { limits } })`. */
102
102
  interface QuotaLimits {
103
103
  day?: QuotaWindowLimits;
104
104
  month?: QuotaWindowLimits;
@@ -106,8 +106,7 @@ interface QuotaLimits {
106
106
  /**
107
107
  * The default {@link QuotaProvider}: windows read off the usage ledger the loop already writes.
108
108
  *
109
- * - `day` — always; `usedTokens`/limit come from the bound {@link QuotaStore} when there is one (so
110
- * the report matches what the loop enforces), spend from the ledger.
109
+ * - `day` — always.
111
110
  * - `month` — when the store implements `usageBetween`.
112
111
  *
113
112
  * `limits` add ceilings per window (tokens and/or USD). A window that reaches one makes the report
@@ -115,9 +114,8 @@ interface QuotaLimits {
115
114
  */
116
115
  declare class LedgerQuotaProvider implements QuotaProvider {
117
116
  private readonly store;
118
- private readonly quota?;
119
117
  private readonly limits;
120
- constructor(store: AgentStore, quota?: QuotaStore | undefined, limits?: QuotaLimits);
118
+ constructor(store: AgentStore, limits?: QuotaLimits);
121
119
  report(query: QuotaQuery): Promise<QuotaReport>;
122
120
  private dayWindow;
123
121
  private window;
@@ -144,8 +142,9 @@ declare class LedgerQuotaProvider implements QuotaProvider {
144
142
  */
145
143
  type AgentSurface = 'http' | 'engine' | 'both';
146
144
  /**
147
- * `AgentModuleOptions.attachments` — bounds and content-type allowlist for the optional
148
- * `POST /agent/attachments` upload controller (see `attachments.upload`).
145
+ * `AgentModuleOptions.attachments` — limits for `POST <base>/attachments`, when the bound
146
+ * `AGENT_ATTACHMENT_STAGING` store does not declare its own (`AgentMediaAttachmentsModule` does, and
147
+ * then it is the only source). Served to clients by `GET <base>/config`.
149
148
  */
150
149
  interface AgentAttachmentsOptions {
151
150
  /** Per-file size cap. Defaults to 20 MiB. */
@@ -155,13 +154,6 @@ interface AgentAttachmentsOptions {
155
154
  * `image/png`, `image/jpeg`, `image/gif`, `image/webp`, `application/pdf`, `text/plain`, `text/csv`.
156
155
  */
157
156
  allowedContentTypes?: string[];
158
- /**
159
- * Mount `POST /agent/attachments`. Defaults to `false` — the controller is build-time (static)
160
- * wiring, so this can't be inferred from whether `AGENT_ATTACHMENT_STAGING` ends up bound (that's
161
- * a DI-time fact); set it explicitly. `true` with no `AGENT_ATTACHMENT_STAGING` provider bound
162
- * fails boot loudly instead of silently mounting a controller that 501s on every request.
163
- */
164
- upload?: boolean;
165
157
  }
166
158
  /**
167
159
  * `AgentModuleOptions.skills` — where a turn's skills come from, and which scopes an actor draws
@@ -240,34 +232,22 @@ interface AgentModuleOptions {
240
232
  /** Live token transport. Defaults to a single-process in-memory sink. */
241
233
  sink?: TokenStreamSink;
242
234
  /**
243
- * A {@link QuotaStore} for the daily token budget. Optional — omit (and omit `quotaLimitTokens`)
244
- * to disable quotas. Provide this to plug a custom budget; for the common case use the simpler
245
- * `quotaLimitTokens` instead, which binds the built-in ledger-backed store.
235
+ * The caller's budget. `{ limits: { day?: { tokens?, usd? }, month?: { tokens?, usd? } } }` puts
236
+ * ceilings on the built-in ledger provider; a {@link QuotaProvider} of your own replaces it. Either
237
+ * way `GET <base>/quota` reports it and a send whose report comes back `blocked` is refused with
238
+ * `429` before the turn starts. Omit → reported (usage off the ledger), never enforced — for a
239
+ * public (anonymous) deployment that means unbounded model spend, so set limits there; they apply
240
+ * per actor, which is per browser in anonymous mode.
246
241
  */
247
- quota?: QuotaStore;
242
+ quota?: {
243
+ limits: QuotaLimits;
244
+ } | QuotaProvider;
248
245
  /**
249
246
  * Which models a caller may pick — `GET <base>/models`, a send's `model`, a thread's pinned model
250
- * (`PATCH <base>/threads/:id { model }`). The picked id reaches the {@link ModelProvider} as
251
- * `ModelTurnArgs.model`. Omit → an empty catalog, and a request naming a model is refused.
247
+ * (`PATCH <base>/threads/:id { model }`). Omit → the catalog the model provider carries
248
+ * (`aiSdkModels`), else none, and a request naming a model is refused.
252
249
  */
253
250
  models?: ModelCatalog;
254
- /**
255
- * The actor's budget across windows, for `GET <base>/quota` — and, once set, a gate: a send whose
256
- * report comes back `blocked` is refused with `429` before the turn starts. Default: a
257
- * {@link LedgerQuotaProvider} over the usage ledger (reporting only, unless `quotaLimits` is set).
258
- */
259
- quotaProvider?: QuotaProvider;
260
- /**
261
- * Ceilings for the default ledger provider's windows — `{ day?: { tokens?, usd? }, month?: {
262
- * tokens?, usd? } }`. Setting it turns the send gate on. Ignored when `quotaProvider` is given.
263
- */
264
- quotaLimits?: QuotaLimits;
265
- /**
266
- * Daily per-actor token budget, enforced against the persisted usage ledger by the built-in
267
- * `LedgerQuotaStore`. A convenience over wiring a {@link QuotaStore} by hand — set this and quotas
268
- * turn on with no extra store. Ignored when an explicit `quota` is provided. Omit to disable.
269
- */
270
- quotaLimitTokens?: number;
271
251
  /** Tool authorization gate. Defaults to role-in-`defaultRoles`. */
272
252
  rolesPolicy?: RolesPolicy;
273
253
  /**
@@ -361,7 +341,7 @@ interface AgentModuleOptions {
361
341
  /**
362
342
  * A {@link HistoryPolicy} of your own — for a window the built-in can't express (pinning the
363
343
  * thread's opening brief, keeping every message that carries a tool result, a budget that varies
364
- * by actor). A convenience-vs-custom pair like `quotaLimitTokens`/`quota`: this outranks a
344
+ * by actor). A convenience-vs-custom pair: this outranks a
365
345
  * module-wide `history`, and `@Agent({ history })` outranks both for the agent that declares it.
366
346
  * `select` MUST be pure — see the SPI's determinism contract.
367
347
  */
@@ -426,14 +406,14 @@ interface AgentModuleOptions {
426
406
  defaultAgent?: string;
427
407
  /**
428
408
  * Guard(s) applied uniformly to EVERY controller this module mounts (chat, threads, tool-call,
429
- * quota, agents, and — when `attachments.upload` is set — attachments). Third-party controller
409
+ * quota, agents, attachments, config, …). Third-party controller
430
410
  * classes can't be annotated with `@UseGuards` by consumers, so without this option every route is
431
411
  * open beyond whatever `actorResolver` itself enforces. Guard classes are added to this module's
432
412
  * `providers` so Nest can DI-instantiate them; if a guard has its own dependencies, make sure they
433
413
  * resolve from this module's imports or a global module.
434
414
  */
435
415
  guards?: Type<CanActivate>[];
436
- /** Bounds/allowlist for the optional attachment-upload controller. Omit → 20 MiB, the documented default types, not mounted. */
416
+ /** Upload limits when the staging store declares none. Omit → 20 MiB and the default types. */
437
417
  attachments?: AgentAttachmentsOptions;
438
418
  /**
439
419
  * Which half of the module this process mounts (see {@link AgentSurface}). Omit → `'both'`,
@@ -465,16 +445,9 @@ interface AgentModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
465
445
  * `useFactory`. Same default-open caveat as `AgentModuleOptions.guards`.
466
446
  */
467
447
  guards?: Type<CanActivate>[];
468
- /**
469
- * Mount `POST /agent/attachments`. Static, build-time control (same reasoning as `durable`/`path`
470
- * above) — `useFactory` resolves too late to decide which controllers exist. The resolved
471
- * `AgentModuleOptions.attachments` (maxBytes/allowedContentTypes) still applies at request time;
472
- * only the yes/no mount decision has to live here.
473
- */
474
- attachmentsUpload?: boolean;
475
448
  /**
476
449
  * Which half of the module this process mounts (see {@link AgentSurface}). Same static-wiring
477
- * reasoning as `attachmentsUpload`/`durable` above — `useFactory` resolves too late to decide
450
+ * reasoning as `durable` above — `useFactory` resolves too late to decide
478
451
  * which controllers exist. Omit → `'both'`, today's behavior with zero change.
479
452
  */
480
453
  surface?: AgentSurface;
@@ -502,11 +475,10 @@ declare class AgentDepsFactory {
502
475
  private readonly registry;
503
476
  private readonly agents;
504
477
  private readonly promptContributors;
505
- private readonly quota;
506
478
  private readonly pricingStore;
507
479
  private readonly skills;
508
480
  private readonly memory;
509
- constructor(options: AgentModuleOptions, model: ModelProvider, store: AgentStore, sink: TokenStreamSink, rolesPolicy: RolesPolicy, registry: ToolRegistry, agents: AgentRegistry, promptContributors: PromptContributor[], quota: QuotaStore | undefined, pricingStore: AgentPricingStore | undefined, skills: SkillsConfig | undefined, memory: MemoryConfig | undefined);
481
+ constructor(options: AgentModuleOptions, model: ModelProvider, store: AgentStore, sink: TokenStreamSink, rolesPolicy: RolesPolicy, registry: ToolRegistry, agents: AgentRegistry, promptContributors: PromptContributor[], pricingStore: AgentPricingStore | undefined, skills: SkillsConfig | undefined, memory: MemoryConfig | undefined);
510
482
  /** The turn's memory seam, shared with the read-back endpoint. Undefined → memory is not configured. */
511
483
  memoryConfig(): MemoryConfig | undefined;
512
484
  /** The turn's skills seam, shared with the listing endpoint. Undefined → skills are not configured. */