@dudousxd/nestjs-agent 1.21.0 → 1.23.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
@@ -10,6 +10,13 @@ via signals).
10
10
  This is the NestJS module — it re-exports the entire `@dudousxd/nestjs-agent-core` surface, so you
11
11
  import tools, types, and the module from one place.
12
12
 
13
+ ## Component registries and server rendering
14
+
15
+ Tools support a `present` hook in both functional and decorated class forms. Register custom components per app, share React renderers between web screens and static exports, and generate paginated PNG/PDF tables and charts for your own delivery adapters.
16
+
17
+ See the [component rendering guide](../../docs/component-rendering.md) for complete examples, schemas, text fallbacks, and capture configuration.
18
+
19
+
13
20
  ## Install
14
21
 
15
22
  ```bash
@@ -1,7 +1,7 @@
1
- import { ResolveToolUiCatalog, ModelProvider, AgentStore, ToolRegistry, RolesPolicy, ApprovalPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, Persona, ToolTransientRetrySetting, Retriever, AgentPricingStore, HistoryPolicy, InputProcessor, OutputProcessor, AgentIntake, SkillsConfig, MemoryConfig, ToolSpec, ToolHandler, QuotaProvider, QuotaQuery, QuotaReport, ActionApprovalMode, BackgroundActorResolver, ModelCatalog, EmptyRoles, ActorResolver, AgentHistoryWindow, SkillProvider, ScopeResolver, MemoryProvider, AgentRegistry, PersonaCatalogEntry, ActionProposal, Actor, AttachmentStagingStore, ChatQueueStore, ChatQueueState, AgentRunner, AgentRunInput, AgentStreamEvent, QueuePauseReason } from '@dudousxd/nestjs-agent-core';
1
+ import { ResolveToolUiCatalog, ModelProvider, AgentStore, ToolRegistry, RolesPolicy, ApprovalPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, Persona, ToolTransientRetrySetting, Retriever, AgentPricingStore, HistoryPolicy, InputProcessor, OutputProcessor, AgentIntake, SkillsConfig, MemoryConfig, ToolSpec, ToolHandler, createFunctionalTool, QuotaProvider, QuotaQuery, QuotaReport, ActionApprovalMode, BackgroundActorResolver, TextActionProposalConfig, ModelCatalog, EmptyRoles, ActorResolver, AgentHistoryWindow, SkillProvider, ScopeResolver, MemoryProvider, AgentRegistry, PersonaCatalogEntry, ActionProposal, Actor, AttachmentStagingStore, ChatQueueStore, ChatQueueState, AgentRunner, AgentRunInput, AgentStreamEvent, QueuePauseReason } from '@dudousxd/nestjs-agent-core';
2
2
  import { Catalog } from '@dudousxd/nestjs-agent-core/genui';
3
3
  import { StandardSchemaV1 } from '@standard-schema/spec';
4
- import { Provider, FactoryProvider, Type, CanActivate, ModuleMetadata, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';
4
+ import { Provider, InjectionToken, Type, FactoryProvider, CanActivate, ModuleMetadata, OptionalFactoryDependency } from '@nestjs/common';
5
5
  import { GenuiCatalogResolver } from './genui/index.js';
6
6
 
7
7
  /** Everything `runAgentLoop` needs, minus the per-run `day` the runner stamps. */
@@ -72,6 +72,34 @@ interface AgentDeps {
72
72
  }
73
73
  declare function utcDay(date?: Date): string;
74
74
 
75
+ /**
76
+ * Something other than this library's loop that runs a turn — what `engine` on
77
+ * `AgentModule.forRoot` takes. An engine owns the turn end to end (the model calls, the tools, the
78
+ * context it keeps), and contributes the `AgentRunner` that `AGENT_RUNNER` binds to; everything
79
+ * around the turn stays the library's: the routes and the stream protocol, threads and the store,
80
+ * the sink, approvals and answers routed through `AgentService`, the queue and the quota.
81
+ *
82
+ * `openCode()` (`@dudousxd/nestjs-agent-opencode`) is the one that ships. An engine replaces the
83
+ * loop, so the options only the loop reads (`model`, processors, `outputSchema`, `maxSteps`,
84
+ * `history`, `retrieval`) do nothing under one; `model` becomes optional.
85
+ */
86
+ interface AgentEngine {
87
+ /** For logs and diagnostics. */
88
+ name: string;
89
+ /** The providers the engine needs, its runner among them. */
90
+ providers: Provider[];
91
+ /** The token of the engine's `AgentRunner`, which `AGENT_RUNNER` is bound to. */
92
+ runner: InjectionToken;
93
+ /** Providers the app may inject too (the module is global): e.g. what an MCP surface hooks into. */
94
+ exports?: InjectionToken[];
95
+ /**
96
+ * Controllers the engine mounts under the agent's path (e.g. the endpoint its own runtime calls
97
+ * back into). Not mounted on `surface: 'engine'`, and the module's `guards` are NOT applied: an
98
+ * engine's controller authenticates its own callers, which are not the app's users.
99
+ */
100
+ controllers?: Type<object>[];
101
+ }
102
+
75
103
  /**
76
104
  * Brand stamped onto a functional-tool provider instance so `AiToolDiscoveryService` picks it up
77
105
  * when it walks every provider at boot — the declarative alternative to a manual `registry.register`.
@@ -98,6 +126,8 @@ declare function provideAgentTool(factory: (...deps: never[]) => FunctionalTool,
98
126
  * factory's result is branded element by element; `AiToolDiscoveryService` registers each.
99
127
  */
100
128
  declare function provideAgentTools(factory: (...deps: never[]) => readonly FunctionalTool[] | Promise<readonly FunctionalTool[]>, inject?: FactoryProvider['inject']): Provider;
129
+ /** Author a functional tool with inferred Standard Schema input and domain output. */
130
+ declare const defineTool: typeof createFunctionalTool;
101
131
 
102
132
  /** Ceilings for a {@link LedgerQuotaProvider} window. Either, both, or neither. */
103
133
  interface QuotaWindowLimits {
@@ -244,18 +274,54 @@ interface AgentMemoryOptions {
244
274
  maxFactChars?: number;
245
275
  }
246
276
  interface AgentModuleOptions {
277
+ /**
278
+ * How an `action` tool waits for its approval. `'blocking'` (default): the turn parks on the
279
+ * decision and resumes when it lands. `'independent'`: the call is recorded as an action proposal
280
+ * and answered at once with a receipt (`{ proposalId, status: 'pending', executed: false }`), the
281
+ * turn finishes, and a background worker runs the action once it is approved — decided through
282
+ * `POST <base>/threads/:threadId/action-proposals/:proposalId/approve|reject`, the approval port or
283
+ * a text command. Needs `backgroundActorResolver` and a store with the proposal capabilities
284
+ * (both checked at boot). See `docs/independent-approvals.md`.
285
+ */
247
286
  actionApprovalMode?: ActionApprovalMode;
287
+ /**
288
+ * Resolves the CURRENT actor (id, tenant, roles) for a proposal's recorded `actorRef`/`tenantRef`
289
+ * when the worker runs it — there is no request to read an identity from. Return `null` for an
290
+ * actor that no longer exists or no longer belongs to the tenant; the action then fails rather
291
+ * than running. Required under `actionApprovalMode: 'independent'`.
292
+ */
248
293
  backgroundActorResolver?: BackgroundActorResolver;
294
+ /**
295
+ * Tuning for the worker that runs approved proposals under `actionApprovalMode: 'independent'`
296
+ * (started with the module unless `surface: 'http'`). `pollIntervalMs` — how often it looks for
297
+ * queued work, default 1000; `leaseMs` — how long a claim holds before another worker may recover
298
+ * it, default 30000; `maxConcurrency` — proposals claimed per poll, default 1. All positive
299
+ * integers, and `pollIntervalMs` must stay below a third of `leaseMs`.
300
+ */
249
301
  actionProposalWorker?: {
250
302
  pollIntervalMs?: number;
251
303
  leaseMs?: number;
252
304
  maxConcurrency?: number;
253
305
  };
306
+ /**
307
+ * The words a chat message must consist of to approve or reject a proposal by text, and what the
308
+ * agent answers. English by default (`yes`/`confirm`/`approve`, `no`/`cancel`/`reject`, …); pass
309
+ * `ptBrActionProposalText` from `@dudousxd/nestjs-agent-core` for Portuguese, or your own — either
310
+ * part replaces the default it names, field by field.
311
+ */
312
+ actionProposalText?: TextActionProposalConfig;
254
313
  /**
255
314
  * The LLM provider — `aiSdkModel(openai('gpt-5-mini'))`, or `aiSdkModels({ … })` for a model
256
- * picker (its catalog is used when `models` is omitted). The only required option.
315
+ * picker (its catalog is used when `models` is omitted). Required unless an `engine` runs the
316
+ * turns instead.
257
317
  */
258
- model: ModelProvider;
318
+ model?: ModelProvider;
319
+ /**
320
+ * Run turns on something other than this library's loop — e.g. `openCode({ host })`. The engine
321
+ * binds `AGENT_RUNNER`; the routes, store, sink, approvals and queue stay the library's. STATIC
322
+ * wiring, like `durable` (see {@link AgentEngine}). Omit → the loop, on `model`.
323
+ */
324
+ engine?: AgentEngine;
259
325
  /**
260
326
  * The base prompt of the default agent (and of any `@Agent` that declares none) — a string, or a
261
327
  * function of the turn's `{ actor, agentName, pageContext }`. Omit → `'You are a helpful
@@ -509,6 +575,11 @@ interface AgentModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
509
575
  surface?: AgentSurface;
510
576
  /** Wire protocols served alongside the native one — see `AgentModuleOptions.adapters`. STATIC. */
511
577
  adapters?: AgentProtocolAdapter[];
578
+ /**
579
+ * What runs the turns instead of the loop — see `AgentModuleOptions.engine`. STATIC, like
580
+ * `durable`: it decides which runner `AGENT_RUNNER` binds, before `useFactory` has resolved.
581
+ */
582
+ engine?: AgentEngine;
512
583
  }
513
584
 
514
585
  /**
@@ -729,4 +800,4 @@ declare class ChatQueueService {
729
800
  private freshAttachments;
730
801
  }
731
802
 
732
- export { AgentDepsFactory as A, ChatQueueService as C, type FunctionalTool as F, LedgerQuotaProvider as L, type QueuePlan as Q, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentProtocolAdapter as d, type AgentSkillsOptions as e, AGENT_TOOL_BRAND as f, type AgentAttachmentsOptions as g, type AgentDeps as h, type AgentMemoryOptions as i, type QueueSettleOutcome as j, type QueuedTurn as k, type QueuedTurnStarter as l, type QuotaLimits as m, type QuotaWindowLimits as n, delegateToolName as o, provideAgentTool as p, provideAgentTools as q, utcDay as u };
803
+ export { AgentDepsFactory as A, ChatQueueService as C, type FunctionalTool as F, LedgerQuotaProvider as L, type QueuePlan as Q, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentProtocolAdapter as d, type AgentSkillsOptions as e, AGENT_TOOL_BRAND as f, type AgentAttachmentsOptions as g, type AgentDeps as h, type AgentEngine as i, type AgentMemoryOptions as j, type QueueSettleOutcome as k, type QueuedTurn as l, type QueuedTurnStarter as m, type QuotaLimits as n, type QuotaWindowLimits as o, defineTool as p, delegateToolName as q, provideAgentTool as r, provideAgentTools as s, utcDay as u };
@@ -1,7 +1,7 @@
1
- import { ResolveToolUiCatalog, ModelProvider, AgentStore, ToolRegistry, RolesPolicy, ApprovalPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, Persona, ToolTransientRetrySetting, Retriever, AgentPricingStore, HistoryPolicy, InputProcessor, OutputProcessor, AgentIntake, SkillsConfig, MemoryConfig, ToolSpec, ToolHandler, QuotaProvider, QuotaQuery, QuotaReport, ActionApprovalMode, BackgroundActorResolver, ModelCatalog, EmptyRoles, ActorResolver, AgentHistoryWindow, SkillProvider, ScopeResolver, MemoryProvider, AgentRegistry, PersonaCatalogEntry, ActionProposal, Actor, AttachmentStagingStore, ChatQueueStore, ChatQueueState, AgentRunner, AgentRunInput, AgentStreamEvent, QueuePauseReason } from '@dudousxd/nestjs-agent-core';
1
+ import { ResolveToolUiCatalog, ModelProvider, AgentStore, ToolRegistry, RolesPolicy, ApprovalPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, Persona, ToolTransientRetrySetting, Retriever, AgentPricingStore, HistoryPolicy, InputProcessor, OutputProcessor, AgentIntake, SkillsConfig, MemoryConfig, ToolSpec, ToolHandler, createFunctionalTool, QuotaProvider, QuotaQuery, QuotaReport, ActionApprovalMode, BackgroundActorResolver, TextActionProposalConfig, ModelCatalog, EmptyRoles, ActorResolver, AgentHistoryWindow, SkillProvider, ScopeResolver, MemoryProvider, AgentRegistry, PersonaCatalogEntry, ActionProposal, Actor, AttachmentStagingStore, ChatQueueStore, ChatQueueState, AgentRunner, AgentRunInput, AgentStreamEvent, QueuePauseReason } from '@dudousxd/nestjs-agent-core';
2
2
  import { Catalog } from '@dudousxd/nestjs-agent-core/genui';
3
3
  import { StandardSchemaV1 } from '@standard-schema/spec';
4
- import { Provider, FactoryProvider, Type, CanActivate, ModuleMetadata, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';
4
+ import { Provider, InjectionToken, Type, FactoryProvider, CanActivate, ModuleMetadata, OptionalFactoryDependency } from '@nestjs/common';
5
5
  import { GenuiCatalogResolver } from './genui/index.cjs';
6
6
 
7
7
  /** Everything `runAgentLoop` needs, minus the per-run `day` the runner stamps. */
@@ -72,6 +72,34 @@ interface AgentDeps {
72
72
  }
73
73
  declare function utcDay(date?: Date): string;
74
74
 
75
+ /**
76
+ * Something other than this library's loop that runs a turn — what `engine` on
77
+ * `AgentModule.forRoot` takes. An engine owns the turn end to end (the model calls, the tools, the
78
+ * context it keeps), and contributes the `AgentRunner` that `AGENT_RUNNER` binds to; everything
79
+ * around the turn stays the library's: the routes and the stream protocol, threads and the store,
80
+ * the sink, approvals and answers routed through `AgentService`, the queue and the quota.
81
+ *
82
+ * `openCode()` (`@dudousxd/nestjs-agent-opencode`) is the one that ships. An engine replaces the
83
+ * loop, so the options only the loop reads (`model`, processors, `outputSchema`, `maxSteps`,
84
+ * `history`, `retrieval`) do nothing under one; `model` becomes optional.
85
+ */
86
+ interface AgentEngine {
87
+ /** For logs and diagnostics. */
88
+ name: string;
89
+ /** The providers the engine needs, its runner among them. */
90
+ providers: Provider[];
91
+ /** The token of the engine's `AgentRunner`, which `AGENT_RUNNER` is bound to. */
92
+ runner: InjectionToken;
93
+ /** Providers the app may inject too (the module is global): e.g. what an MCP surface hooks into. */
94
+ exports?: InjectionToken[];
95
+ /**
96
+ * Controllers the engine mounts under the agent's path (e.g. the endpoint its own runtime calls
97
+ * back into). Not mounted on `surface: 'engine'`, and the module's `guards` are NOT applied: an
98
+ * engine's controller authenticates its own callers, which are not the app's users.
99
+ */
100
+ controllers?: Type<object>[];
101
+ }
102
+
75
103
  /**
76
104
  * Brand stamped onto a functional-tool provider instance so `AiToolDiscoveryService` picks it up
77
105
  * when it walks every provider at boot — the declarative alternative to a manual `registry.register`.
@@ -98,6 +126,8 @@ declare function provideAgentTool(factory: (...deps: never[]) => FunctionalTool,
98
126
  * factory's result is branded element by element; `AiToolDiscoveryService` registers each.
99
127
  */
100
128
  declare function provideAgentTools(factory: (...deps: never[]) => readonly FunctionalTool[] | Promise<readonly FunctionalTool[]>, inject?: FactoryProvider['inject']): Provider;
129
+ /** Author a functional tool with inferred Standard Schema input and domain output. */
130
+ declare const defineTool: typeof createFunctionalTool;
101
131
 
102
132
  /** Ceilings for a {@link LedgerQuotaProvider} window. Either, both, or neither. */
103
133
  interface QuotaWindowLimits {
@@ -244,18 +274,54 @@ interface AgentMemoryOptions {
244
274
  maxFactChars?: number;
245
275
  }
246
276
  interface AgentModuleOptions {
277
+ /**
278
+ * How an `action` tool waits for its approval. `'blocking'` (default): the turn parks on the
279
+ * decision and resumes when it lands. `'independent'`: the call is recorded as an action proposal
280
+ * and answered at once with a receipt (`{ proposalId, status: 'pending', executed: false }`), the
281
+ * turn finishes, and a background worker runs the action once it is approved — decided through
282
+ * `POST <base>/threads/:threadId/action-proposals/:proposalId/approve|reject`, the approval port or
283
+ * a text command. Needs `backgroundActorResolver` and a store with the proposal capabilities
284
+ * (both checked at boot). See `docs/independent-approvals.md`.
285
+ */
247
286
  actionApprovalMode?: ActionApprovalMode;
287
+ /**
288
+ * Resolves the CURRENT actor (id, tenant, roles) for a proposal's recorded `actorRef`/`tenantRef`
289
+ * when the worker runs it — there is no request to read an identity from. Return `null` for an
290
+ * actor that no longer exists or no longer belongs to the tenant; the action then fails rather
291
+ * than running. Required under `actionApprovalMode: 'independent'`.
292
+ */
248
293
  backgroundActorResolver?: BackgroundActorResolver;
294
+ /**
295
+ * Tuning for the worker that runs approved proposals under `actionApprovalMode: 'independent'`
296
+ * (started with the module unless `surface: 'http'`). `pollIntervalMs` — how often it looks for
297
+ * queued work, default 1000; `leaseMs` — how long a claim holds before another worker may recover
298
+ * it, default 30000; `maxConcurrency` — proposals claimed per poll, default 1. All positive
299
+ * integers, and `pollIntervalMs` must stay below a third of `leaseMs`.
300
+ */
249
301
  actionProposalWorker?: {
250
302
  pollIntervalMs?: number;
251
303
  leaseMs?: number;
252
304
  maxConcurrency?: number;
253
305
  };
306
+ /**
307
+ * The words a chat message must consist of to approve or reject a proposal by text, and what the
308
+ * agent answers. English by default (`yes`/`confirm`/`approve`, `no`/`cancel`/`reject`, …); pass
309
+ * `ptBrActionProposalText` from `@dudousxd/nestjs-agent-core` for Portuguese, or your own — either
310
+ * part replaces the default it names, field by field.
311
+ */
312
+ actionProposalText?: TextActionProposalConfig;
254
313
  /**
255
314
  * The LLM provider — `aiSdkModel(openai('gpt-5-mini'))`, or `aiSdkModels({ … })` for a model
256
- * picker (its catalog is used when `models` is omitted). The only required option.
315
+ * picker (its catalog is used when `models` is omitted). Required unless an `engine` runs the
316
+ * turns instead.
257
317
  */
258
- model: ModelProvider;
318
+ model?: ModelProvider;
319
+ /**
320
+ * Run turns on something other than this library's loop — e.g. `openCode({ host })`. The engine
321
+ * binds `AGENT_RUNNER`; the routes, store, sink, approvals and queue stay the library's. STATIC
322
+ * wiring, like `durable` (see {@link AgentEngine}). Omit → the loop, on `model`.
323
+ */
324
+ engine?: AgentEngine;
259
325
  /**
260
326
  * The base prompt of the default agent (and of any `@Agent` that declares none) — a string, or a
261
327
  * function of the turn's `{ actor, agentName, pageContext }`. Omit → `'You are a helpful
@@ -509,6 +575,11 @@ interface AgentModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
509
575
  surface?: AgentSurface;
510
576
  /** Wire protocols served alongside the native one — see `AgentModuleOptions.adapters`. STATIC. */
511
577
  adapters?: AgentProtocolAdapter[];
578
+ /**
579
+ * What runs the turns instead of the loop — see `AgentModuleOptions.engine`. STATIC, like
580
+ * `durable`: it decides which runner `AGENT_RUNNER` binds, before `useFactory` has resolved.
581
+ */
582
+ engine?: AgentEngine;
512
583
  }
513
584
 
514
585
  /**
@@ -729,4 +800,4 @@ declare class ChatQueueService {
729
800
  private freshAttachments;
730
801
  }
731
802
 
732
- export { AgentDepsFactory as A, ChatQueueService as C, type FunctionalTool as F, LedgerQuotaProvider as L, type QueuePlan as Q, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentProtocolAdapter as d, type AgentSkillsOptions as e, AGENT_TOOL_BRAND as f, type AgentAttachmentsOptions as g, type AgentDeps as h, type AgentMemoryOptions as i, type QueueSettleOutcome as j, type QueuedTurn as k, type QueuedTurnStarter as l, type QuotaLimits as m, type QuotaWindowLimits as n, delegateToolName as o, provideAgentTool as p, provideAgentTools as q, utcDay as u };
803
+ export { AgentDepsFactory as A, ChatQueueService as C, type FunctionalTool as F, LedgerQuotaProvider as L, type QueuePlan as Q, type AgentSurface as a, type AgentModuleOptions as b, type AgentModuleAsyncOptions as c, type AgentProtocolAdapter as d, type AgentSkillsOptions as e, AGENT_TOOL_BRAND as f, type AgentAttachmentsOptions as g, type AgentDeps as h, type AgentEngine as i, type AgentMemoryOptions as j, type QueueSettleOutcome as k, type QueuedTurn as l, type QueuedTurnStarter as m, type QuotaLimits as n, type QuotaWindowLimits as o, defineTool as p, delegateToolName as q, provideAgentTool as r, provideAgentTools as s, utcDay as u };