@dudousxd/nestjs-agent 1.10.0 → 1.12.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 +75 -48
- package/dist/{agent-deps.factory-DuTy1UyU.d.cts → agent-deps.factory-pqv_qTmJ.d.cts} +47 -71
- package/dist/{agent-deps.factory-DuTy1UyU.d.ts → agent-deps.factory-pqv_qTmJ.d.ts} +47 -71
- package/dist/durable/index.cjs +729 -584
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +1 -1
- package/dist/durable/index.d.ts +1 -1
- package/dist/durable/index.js +634 -489
- package/dist/durable/index.js.map +1 -1
- package/dist/index.cjs +805 -591
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +137 -55
- package/dist/index.d.ts +137 -55
- package/dist/index.js +699 -491
- package/dist/index.js.map +1 -1
- package/dist/media/index.cjs +11 -2
- package/dist/media/index.cjs.map +1 -1
- package/dist/media/index.d.cts +5 -1
- package/dist/media/index.d.ts +5 -1
- package/dist/media/index.js +11 -2
- package/dist/media/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -18,28 +18,47 @@ pnpm add @dudousxd/nestjs-agent @dudousxd/nestjs-agent-core
|
|
|
18
18
|
|
|
19
19
|
## Use
|
|
20
20
|
|
|
21
|
+
The whole server — a public chat with one tool:
|
|
22
|
+
|
|
21
23
|
```ts
|
|
22
|
-
import { AgentModule, AiTool
|
|
24
|
+
import { AgentModule, AiTool } from '@dudousxd/nestjs-agent';
|
|
25
|
+
import { aiSdkModel } from '@dudousxd/nestjs-agent-ai-sdk';
|
|
26
|
+
import { openai } from '@ai-sdk/openai';
|
|
23
27
|
import { z } from 'zod';
|
|
24
28
|
|
|
25
|
-
@AiTool({
|
|
26
|
-
export class GetWeatherTool
|
|
27
|
-
async execute(
|
|
29
|
+
@AiTool({ description: 'Current weather for a city', input: z.object({ city: z.string() }) })
|
|
30
|
+
export class GetWeatherTool { // name: getWeather, kind: read
|
|
31
|
+
async execute({ city }: { city: string }) { return { city, tempC: 21 }; }
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
@Module({
|
|
31
|
-
imports: [AgentModule.forRoot({
|
|
32
|
-
model, store, actorResolver: new HeaderActorResolver(),
|
|
33
|
-
defaultAgent: { systemPrompt: '…', modelId: 'claude-sonnet-4-6' },
|
|
34
|
-
})],
|
|
35
|
+
imports: [AgentModule.forRoot({ model: aiSdkModel(openai('gpt-5-mini')) })],
|
|
35
36
|
providers: [GetWeatherTool],
|
|
36
37
|
})
|
|
37
38
|
export class AppModule {}
|
|
38
39
|
```
|
|
39
40
|
|
|
40
|
-
The module mounts SSE + REST endpoints under `/agent` (`POST /agent/chat`, tool-call
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
The module mounts SSE + REST endpoints under `/agent` (`POST /agent/chat`, threads, tool-call
|
|
42
|
+
approve/reject, quota, models, tools). Everything but `model` defaults, and each default is one
|
|
43
|
+
option away:
|
|
44
|
+
|
|
45
|
+
| Default | Change it with |
|
|
46
|
+
|---|---|
|
|
47
|
+
| In-memory store (boot warning: not for production) | `store`, or import a store module (`MikroOrmAgentStoreModule.forFeature()`) — found automatically |
|
|
48
|
+
| Public endpoints; each browser its own anonymous actor (HttpOnly cookie) | `actorResolver: requestUserActorResolver()` (reads `req.user`), or your own |
|
|
49
|
+
| Every tool callable by any resolved actor | `@AiTool({ roles })`, `defaultRoles`, or a `rolesPolicy` |
|
|
50
|
+
| `'You are a helpful assistant.'` | `systemPrompt: 'You are …'` or `({ actor }) => …`; `@Agent` classes for personas |
|
|
51
|
+
| `@AiTool` name = class name minus `Tool`, camelCased; kind `read` | `@AiTool({ name, kind: 'action' })` |
|
|
52
|
+
|
|
53
|
+
**Anonymous mode, and what it means.** With no `actorResolver`, anyone who can reach the API can
|
|
54
|
+
chat, and each browser gets its own identity: a random token in an `HttpOnly`, `SameSite=Lax`
|
|
55
|
+
cookie (`Secure` over HTTPS), the actor id a SHA-256 digest of it. Threads, quota and attachments
|
|
56
|
+
are scoped by that id, so visitors never see each other's conversations; clearing cookies starts
|
|
57
|
+
over. `action` tools still park on approval — but the approver is the requester, so for an anonymous
|
|
58
|
+
visitor approval is a confirmation step, not an authorization: gate a consequential tool with
|
|
59
|
+
`roles` (which anonymous actors do not hold). Without a quota, a public deployment's model spend is
|
|
60
|
+
unbounded — set `quota` limits (they apply per anonymous id) before going public. Requiring login
|
|
61
|
+
is one line: `actorResolver: requestUserActorResolver()`.
|
|
43
62
|
|
|
44
63
|
### How a chat talks about a tool
|
|
45
64
|
|
|
@@ -123,9 +142,13 @@ With nothing bound to `AGENT_ATTACHMENT_STAGING` there is no way to tell whose m
|
|
|
123
142
|
turn carrying attachments is refused with `501`. Text-only turns are unaffected. At most 10
|
|
124
143
|
attachments per turn.
|
|
125
144
|
|
|
126
|
-
|
|
127
|
-
larger than `HARD_MAX_ATTACHMENT_BYTES` (32 MiB) while it streams;
|
|
128
|
-
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.
|
|
129
152
|
|
|
130
153
|
### Sweeping attachments nobody sent
|
|
131
154
|
|
|
@@ -151,8 +174,7 @@ regenerating a turn does — deletes messages and frees their media again. If ei
|
|
|
151
174
|
missing the call raises `501` rather than reporting everything as collectable.
|
|
152
175
|
|
|
153
176
|
`GET /agent/attachments` returns the caller's own staged files as metadata (no urls — those are
|
|
154
|
-
minted per turn by `resolve`), bounded to `ATTACHMENT_PAGE_SIZE
|
|
155
|
-
`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
|
|
156
178
|
ride on its messages in `GET /agent/threads/:id`.
|
|
157
179
|
|
|
158
180
|
### Attachments on nestjs-media (`@dudousxd/nestjs-agent/media`)
|
|
@@ -199,10 +221,14 @@ Each attachment is a media record (`ownerType: 'agent-actor'`, `ownerId: actor.i
|
|
|
199
221
|
| 3. complete | `POST /agent/attachments/uploads/:mediaId/complete` → `MessageAttachment` | agent — checks the bytes landed at the declared size |
|
|
200
222
|
| drop | `DELETE /agent/attachments/uploads/:mediaId` | agent — aborts the session, deletes bytes + record |
|
|
201
223
|
|
|
202
|
-
`@dudousxd/nestjs-agent-react/media` drives all three for `useAttachments
|
|
203
|
-
|
|
204
|
-
`
|
|
205
|
-
/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.
|
|
206
232
|
|
|
207
233
|
`resolve` hands the model provider a presigned url when the disk can mint one (`urlExpiresInSeconds`,
|
|
208
234
|
default 7 days), the disk's public `url()` with `visibility: 'public'`, or — on a disk that can do
|
|
@@ -254,8 +280,8 @@ export class S3Staging implements AttachmentStagingStore {
|
|
|
254
280
|
{ provide: AGENT_ATTACHMENT_STAGING, useClass: S3Staging }
|
|
255
281
|
```
|
|
256
282
|
|
|
257
|
-
Then
|
|
258
|
-
|
|
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`
|
|
259
285
|
(`useAttachments({ upload })` / a backend's `uploadAttachment`) that resolves to a `{ mediaId, … }`
|
|
260
286
|
your `resolve` recognises. `list` is optional and only needed for `GET /agent/attachments` and
|
|
261
287
|
sweeping.
|
|
@@ -286,36 +312,37 @@ bundled stores and `InMemoryAgentStore` have them) — `501` otherwise.
|
|
|
286
312
|
|
|
287
313
|
```ts
|
|
288
314
|
AgentModule.forRoot({
|
|
289
|
-
model:
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
label: 'OpenAI',
|
|
297
|
-
models: [
|
|
298
|
-
{ id: 'openai/gpt-4o-mini', label: 'GPT-4o mini', badges: ['fast'], available: true },
|
|
299
|
-
{
|
|
300
|
-
id: 'openai/o3',
|
|
301
|
-
label: 'o3',
|
|
302
|
-
badges: ['reasoning'],
|
|
303
|
-
available: actor.roles?.includes('PRO') === true,
|
|
304
|
-
unavailableReason: 'Pro plan',
|
|
305
|
-
},
|
|
306
|
-
],
|
|
307
|
-
},
|
|
308
|
-
],
|
|
309
|
-
}),
|
|
310
|
-
},
|
|
315
|
+
model: aiSdkModels(
|
|
316
|
+
{
|
|
317
|
+
'openai/gpt-4o-mini': { model: 'openai/gpt-4o-mini', label: 'GPT-4o mini', badges: ['fast'] },
|
|
318
|
+
'openai/o3': { model: 'openai/o3', label: 'o3', badges: ['reasoning'] },
|
|
319
|
+
},
|
|
320
|
+
{ default: 'openai/gpt-4o-mini' },
|
|
321
|
+
),
|
|
311
322
|
});
|
|
312
323
|
```
|
|
313
324
|
|
|
325
|
+
`aiSdkModels` (from `@dudousxd/nestjs-agent-ai-sdk`) carries its own catalog, used when `models` is
|
|
326
|
+
omitted. For availability that depends on the caller, pass a `models` catalog of your own next to it:
|
|
327
|
+
|
|
328
|
+
```ts
|
|
329
|
+
models: {
|
|
330
|
+
list: ({ actor }) => ({
|
|
331
|
+
default: 'openai/gpt-4o-mini',
|
|
332
|
+
providers: [{ id: 'openai', label: 'OpenAI', models: [
|
|
333
|
+
{ id: 'openai/gpt-4o-mini', label: 'GPT-4o mini', available: true },
|
|
334
|
+
{ id: 'openai/o3', label: 'o3', available: actor.roles?.includes('PRO') === true, unavailableReason: 'Pro plan' },
|
|
335
|
+
] }],
|
|
336
|
+
}),
|
|
337
|
+
},
|
|
338
|
+
```
|
|
339
|
+
|
|
314
340
|
`GET /agent/models?agent=` answers the catalog for the caller (empty without one). A turn runs on
|
|
315
341
|
the send's `model`, else the thread's pinned one (`PATCH /agent/threads/:id { model }`), else the
|
|
316
342
|
provider's default; the id reaches the provider as `ModelTurnArgs.model` for every call of the turn.
|
|
317
343
|
A model the catalog does not list as available for that actor and agent is refused with `400` —
|
|
318
|
-
when pinned and again on each turn
|
|
344
|
+
when pinned and again on each turn — and a provider asked for a model it does not serve fails the
|
|
345
|
+
turn rather than answering on another. `staticModelCatalog(view)` wraps a fixed list.
|
|
319
346
|
|
|
320
347
|
### Budgets: `GET /agent/quota`
|
|
321
348
|
|
|
@@ -328,13 +355,13 @@ and only reports. Configure it and it also gates sends — a `blocked` report re
|
|
|
328
355
|
```ts
|
|
329
356
|
AgentModule.forRoot({
|
|
330
357
|
// ceilings on the default ledger provider
|
|
331
|
-
|
|
358
|
+
quota: { limits: { day: { tokens: 200_000 }, month: { usd: 20 } } },
|
|
332
359
|
// …or your own budget, e.g. an AI-gateway spend cap:
|
|
333
|
-
//
|
|
360
|
+
// quota: { report: async ({ actor }) => myGatewayBudget(actor.id) },
|
|
334
361
|
});
|
|
335
362
|
```
|
|
336
363
|
|
|
337
|
-
|
|
364
|
+
In anonymous mode the limits apply per browser (each is its own actor).
|
|
338
365
|
|
|
339
366
|
### Who approves an action, and for how long
|
|
340
367
|
|
|
@@ -98,7 +98,7 @@ interface QuotaWindowLimits {
|
|
|
98
98
|
tokens?: number;
|
|
99
99
|
usd?: number;
|
|
100
100
|
}
|
|
101
|
-
/** Per-window ceilings: `AgentModule.forRoot({
|
|
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
|
|
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,
|
|
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` —
|
|
148
|
-
* `
|
|
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
|
|
@@ -219,45 +211,43 @@ interface AgentMemoryOptions {
|
|
|
219
211
|
maxFactChars?: number;
|
|
220
212
|
}
|
|
221
213
|
interface AgentModuleOptions {
|
|
222
|
-
/**
|
|
214
|
+
/**
|
|
215
|
+
* The LLM provider — `aiSdkModel(openai('gpt-5-mini'))`, or `aiSdkModels({ … })` for a model
|
|
216
|
+
* picker (its catalog is used when `models` is omitted). The only required option.
|
|
217
|
+
*/
|
|
223
218
|
model: ModelProvider;
|
|
224
219
|
/**
|
|
225
|
-
*
|
|
226
|
-
* `
|
|
227
|
-
*
|
|
220
|
+
* The base prompt of the default agent (and of any `@Agent` that declares none) — a string, or a
|
|
221
|
+
* function of the turn's `{ actor, agentName, pageContext }`. Omit → `'You are a helpful
|
|
222
|
+
* assistant.'`.
|
|
223
|
+
*/
|
|
224
|
+
systemPrompt?: string | PromptBuilder;
|
|
225
|
+
/**
|
|
226
|
+
* Persistence adapter. Omit it and either import a store module (e.g.
|
|
227
|
+
* `MikroOrmAgentStoreModule.forFeature()`, which binds `AGENT_STORE` globally — it is found and
|
|
228
|
+
* used), or run on the built-in in-memory store — fine for a demo, logged at boot as not for
|
|
229
|
+
* production: threads vanish on restart and are not shared between processes.
|
|
228
230
|
*/
|
|
229
231
|
store?: AgentStore;
|
|
230
232
|
/** Live token transport. Defaults to a single-process in-memory sink. */
|
|
231
233
|
sink?: TokenStreamSink;
|
|
232
234
|
/**
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
* `
|
|
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.
|
|
236
241
|
*/
|
|
237
|
-
quota?:
|
|
242
|
+
quota?: {
|
|
243
|
+
limits: QuotaLimits;
|
|
244
|
+
} | QuotaProvider;
|
|
238
245
|
/**
|
|
239
246
|
* Which models a caller may pick — `GET <base>/models`, a send's `model`, a thread's pinned model
|
|
240
|
-
* (`PATCH <base>/threads/:id { model }`).
|
|
241
|
-
* `
|
|
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.
|
|
242
249
|
*/
|
|
243
250
|
models?: ModelCatalog;
|
|
244
|
-
/**
|
|
245
|
-
* The actor's budget across windows, for `GET <base>/quota` — and, once set, a gate: a send whose
|
|
246
|
-
* report comes back `blocked` is refused with `429` before the turn starts. Default: a
|
|
247
|
-
* {@link LedgerQuotaProvider} over the usage ledger (reporting only, unless `quotaLimits` is set).
|
|
248
|
-
*/
|
|
249
|
-
quotaProvider?: QuotaProvider;
|
|
250
|
-
/**
|
|
251
|
-
* Ceilings for the default ledger provider's windows — `{ day?: { tokens?, usd? }, month?: {
|
|
252
|
-
* tokens?, usd? } }`. Setting it turns the send gate on. Ignored when `quotaProvider` is given.
|
|
253
|
-
*/
|
|
254
|
-
quotaLimits?: QuotaLimits;
|
|
255
|
-
/**
|
|
256
|
-
* Daily per-actor token budget, enforced against the persisted usage ledger by the built-in
|
|
257
|
-
* `LedgerQuotaStore`. A convenience over wiring a {@link QuotaStore} by hand — set this and quotas
|
|
258
|
-
* turn on with no extra store. Ignored when an explicit `quota` is provided. Omit to disable.
|
|
259
|
-
*/
|
|
260
|
-
quotaLimitTokens?: number;
|
|
261
251
|
/** Tool authorization gate. Defaults to role-in-`defaultRoles`. */
|
|
262
252
|
rolesPolicy?: RolesPolicy;
|
|
263
253
|
/**
|
|
@@ -267,15 +257,20 @@ interface AgentModuleOptions {
|
|
|
267
257
|
* deciding actor must hold that role. See `ApprovalPolicy`.
|
|
268
258
|
*/
|
|
269
259
|
approvalPolicy?: ApprovalPolicy;
|
|
270
|
-
/**
|
|
260
|
+
/**
|
|
261
|
+
* Roles a tool requires when its own `roles` is omitted. Default `[]` — no restriction: every
|
|
262
|
+
* tool is callable by whoever `actorResolver` resolved (an anonymous visitor included, when none is
|
|
263
|
+
* configured). `action` tools still park on approval regardless.
|
|
264
|
+
*/
|
|
271
265
|
defaultRoles?: string[];
|
|
272
266
|
/**
|
|
273
|
-
* Resolves the acting actor for each request (the identity seam).
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
267
|
+
* Resolves the acting actor for each request (the identity seam). Omit → the endpoints are public
|
|
268
|
+
* and every browser is its own anonymous actor (`AnonymousActorResolver`: an `HttpOnly` cookie,
|
|
269
|
+
* the actor id a digest of it), so visitors never see each other's threads, quota or attachments.
|
|
270
|
+
* A boot notice says so. Require login with `requestUserActorResolver()` (reads `req.user`), or a
|
|
271
|
+
* resolver of your own over your session / JWT / `nestjs-context`.
|
|
277
272
|
*/
|
|
278
|
-
actorResolver
|
|
273
|
+
actorResolver?: ActorResolver;
|
|
279
274
|
/** Route prefix the controllers mount under. Defaults to `'agent'` (→ `/agent/chat`, …). */
|
|
280
275
|
path?: string;
|
|
281
276
|
/**
|
|
@@ -346,7 +341,7 @@ interface AgentModuleOptions {
|
|
|
346
341
|
/**
|
|
347
342
|
* A {@link HistoryPolicy} of your own — for a window the built-in can't express (pinning the
|
|
348
343
|
* thread's opening brief, keeping every message that carries a tool result, a budget that varies
|
|
349
|
-
* by actor). A convenience-vs-custom pair
|
|
344
|
+
* by actor). A convenience-vs-custom pair: this outranks a
|
|
350
345
|
* module-wide `history`, and `@Agent({ history })` outranks both for the agent that declares it.
|
|
351
346
|
* `select` MUST be pure — see the SPI's determinism contract.
|
|
352
347
|
*/
|
|
@@ -411,14 +406,14 @@ interface AgentModuleOptions {
|
|
|
411
406
|
defaultAgent?: string;
|
|
412
407
|
/**
|
|
413
408
|
* Guard(s) applied uniformly to EVERY controller this module mounts (chat, threads, tool-call,
|
|
414
|
-
* quota, agents,
|
|
409
|
+
* quota, agents, attachments, config, …). Third-party controller
|
|
415
410
|
* classes can't be annotated with `@UseGuards` by consumers, so without this option every route is
|
|
416
411
|
* open beyond whatever `actorResolver` itself enforces. Guard classes are added to this module's
|
|
417
412
|
* `providers` so Nest can DI-instantiate them; if a guard has its own dependencies, make sure they
|
|
418
413
|
* resolve from this module's imports or a global module.
|
|
419
414
|
*/
|
|
420
415
|
guards?: Type<CanActivate>[];
|
|
421
|
-
/**
|
|
416
|
+
/** Upload limits when the staging store declares none. Omit → 20 MiB and the default types. */
|
|
422
417
|
attachments?: AgentAttachmentsOptions;
|
|
423
418
|
/**
|
|
424
419
|
* Which half of the module this process mounts (see {@link AgentSurface}). Omit → `'both'`,
|
|
@@ -441,17 +436,6 @@ interface AgentModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
|
|
|
441
436
|
* the runner. Requires importing `AgentDurableModule` and a configured `DurableModule`.
|
|
442
437
|
*/
|
|
443
438
|
durable?: boolean;
|
|
444
|
-
/**
|
|
445
|
-
* Set when `AGENT_STORE` is bound by a globally-imported store module (e.g.
|
|
446
|
-
* `MikroOrmAgentStoreModule.forFeature()`) instead of returned as `store` from `useFactory`.
|
|
447
|
-
*
|
|
448
|
-
* `forRoot` decides this synchronously (`store` present or not), but the async factory resolves
|
|
449
|
-
* too late to inspect — so by default `forRootAsync` binds `AGENT_STORE` from the factory result,
|
|
450
|
-
* which would shadow a global store binding with `undefined` when the factory omits `store`. Set
|
|
451
|
-
* this to `true` to skip the local binding and defer to the global one. Leave it unset (and return
|
|
452
|
-
* `store` from the factory) when the store is constructed inside the factory.
|
|
453
|
-
*/
|
|
454
|
-
externalStore?: boolean;
|
|
455
439
|
/**
|
|
456
440
|
* Guard(s) applied uniformly to every controller this module mounts. A STATIC field on the async
|
|
457
441
|
* config object itself — NOT part of what `useFactory` resolves — because controllers (and the
|
|
@@ -461,16 +445,9 @@ interface AgentModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
|
|
|
461
445
|
* `useFactory`. Same default-open caveat as `AgentModuleOptions.guards`.
|
|
462
446
|
*/
|
|
463
447
|
guards?: Type<CanActivate>[];
|
|
464
|
-
/**
|
|
465
|
-
* Mount `POST /agent/attachments`. Static, build-time control (same reasoning as `durable`/`path`
|
|
466
|
-
* above) — `useFactory` resolves too late to decide which controllers exist. The resolved
|
|
467
|
-
* `AgentModuleOptions.attachments` (maxBytes/allowedContentTypes) still applies at request time;
|
|
468
|
-
* only the yes/no mount decision has to live here.
|
|
469
|
-
*/
|
|
470
|
-
attachmentsUpload?: boolean;
|
|
471
448
|
/**
|
|
472
449
|
* Which half of the module this process mounts (see {@link AgentSurface}). Same static-wiring
|
|
473
|
-
* reasoning as `
|
|
450
|
+
* reasoning as `durable` above — `useFactory` resolves too late to decide
|
|
474
451
|
* which controllers exist. Omit → `'both'`, today's behavior with zero change.
|
|
475
452
|
*/
|
|
476
453
|
surface?: AgentSurface;
|
|
@@ -498,11 +475,10 @@ declare class AgentDepsFactory {
|
|
|
498
475
|
private readonly registry;
|
|
499
476
|
private readonly agents;
|
|
500
477
|
private readonly promptContributors;
|
|
501
|
-
private readonly quota;
|
|
502
478
|
private readonly pricingStore;
|
|
503
479
|
private readonly skills;
|
|
504
480
|
private readonly memory;
|
|
505
|
-
constructor(options: AgentModuleOptions, model: ModelProvider, store: AgentStore, sink: TokenStreamSink, rolesPolicy: RolesPolicy, registry: ToolRegistry, agents: AgentRegistry, promptContributors: PromptContributor[],
|
|
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);
|
|
506
482
|
/** The turn's memory seam, shared with the read-back endpoint. Undefined → memory is not configured. */
|
|
507
483
|
memoryConfig(): MemoryConfig | undefined;
|
|
508
484
|
/** The turn's skills seam, shared with the listing endpoint. Undefined → skills are not configured. */
|