@dudousxd/nestjs-agent 1.8.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/README.md CHANGED
@@ -70,6 +70,39 @@ tools THIS actor can reach through that agent (the default agent when omitted; `
70
70
  one), built by `ToolRegistry.visibleSpecs`, the same gates the model is offered tools through. The
71
71
  React package's `useToolCatalog` reads it. The model never sees `presentation`.
72
72
 
73
+ ### Generative UI
74
+
75
+ A tool pushes a component into the answer with `ctx.emitUi(component, props)` — always present; a
76
+ no-op where there is no conversation (MCP). To let the MODEL compose UI from a catalog, import
77
+ `AgentGenuiModule` from `@dudousxd/nestjs-agent/genui` next to `AgentModule`:
78
+
79
+ ```ts
80
+ // catalog.ts — isomorphic: the React app imports this same file
81
+ import { defineCatalog, defineComponent } from '@dudousxd/nestjs-agent-core/genui';
82
+ import { BUILTIN_COMPONENTS } from '@dudousxd/nestjs-agent-core/genui/builtins';
83
+ export const catalog = defineCatalog([...BUILTIN_COMPONENTS, DealCard]);
84
+
85
+ // app.module.ts
86
+ AgentGenuiModule.forRoot({ catalog, mode: 'tree', terminal: true });
87
+ ```
88
+
89
+ It registers the tools (`ui__show_<component>` per component by default, one `ui__render` in `tree`
90
+ mode, plus a generic `ui__show` taking `{ component, props }` with `showTool: true`), validating
91
+ every call against the catalog. Options: `mode`, `terminal`, `treeToolName`, `treeInstructions`,
92
+ `treeLimits`, `namePrefix`, `showTool`, `showInstructions`, `roles`, `presentation`.
93
+ `forRootAsync({ imports, inject, useFactory })` builds them from config. The catalog is injectable
94
+ (`@InjectGenuiCatalog()`, token `GENUI_CATALOG`) and replaceable in a test with
95
+ `overrideProvider(GENUI_CATALOG)` — the tools are built from the injected one.
96
+
97
+ **Per-request catalogs.** Pass `resolver` (a class, resolved with DI, or an instance) extending
98
+ `GenuiCatalogResolver` — `resolve({ actor, threadId, tenant, agentName }) → Catalog | Promise<Catalog>`
99
+ (`tenant` is `actor.tenantRef`). It is consulted when a call is validated and when a turn's tool list
100
+ is described to the model (the core's `ToolHandler.describe`), so tenant-defined, versioned
101
+ components work without rebuilding tools at boot: the tree tool's and the show tool's descriptions
102
+ and schemas list the tenant's components for that turn, and a pushed component carries the resolved
103
+ definition's `version`. A tenant's own components are reached through the tree tool or
104
+ `showTool: true` — no boot-time tool can name them. Cache inside `resolve` if it costs a round trip.
105
+
73
106
  ### Message attachments
74
107
 
75
108
  A chat turn attaches a file by **`mediaId` only**:
@@ -86,6 +86,12 @@ interface FunctionalTool {
86
86
  */
87
87
  declare function provideAgentTool(tool: FunctionalTool): Provider;
88
88
  declare function provideAgentTool(factory: (...deps: never[]) => FunctionalTool, inject?: FactoryProvider['inject']): Provider;
89
+ /**
90
+ * Registers a LIST of functional tools from one factory — for a producer whose tool count is only
91
+ * known once its dependencies resolve (a catalog loaded from config, one tool per entry). The
92
+ * factory's result is branded element by element; `AiToolDiscoveryService` registers each.
93
+ */
94
+ declare function provideAgentTools(factory: (...deps: never[]) => readonly FunctionalTool[] | Promise<readonly FunctionalTool[]>, inject?: FactoryProvider['inject']): Provider;
89
95
 
90
96
  /** Ceilings for a {@link LedgerQuotaProvider} window. Either, both, or neither. */
91
97
  interface QuotaWindowLimits {
@@ -520,4 +526,4 @@ declare class AgentDepsFactory {
520
526
  private followUpsCount;
521
527
  }
522
528
 
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 };
529
+ 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, provideAgentTools as k, provideAgentTool as p, utcDay as u };
@@ -86,6 +86,12 @@ interface FunctionalTool {
86
86
  */
87
87
  declare function provideAgentTool(tool: FunctionalTool): Provider;
88
88
  declare function provideAgentTool(factory: (...deps: never[]) => FunctionalTool, inject?: FactoryProvider['inject']): Provider;
89
+ /**
90
+ * Registers a LIST of functional tools from one factory — for a producer whose tool count is only
91
+ * known once its dependencies resolve (a catalog loaded from config, one tool per entry). The
92
+ * factory's result is branded element by element; `AiToolDiscoveryService` registers each.
93
+ */
94
+ declare function provideAgentTools(factory: (...deps: never[]) => readonly FunctionalTool[] | Promise<readonly FunctionalTool[]>, inject?: FactoryProvider['inject']): Provider;
89
95
 
90
96
  /** Ceilings for a {@link LedgerQuotaProvider} window. Either, both, or neither. */
91
97
  interface QuotaWindowLimits {
@@ -520,4 +526,4 @@ declare class AgentDepsFactory {
520
526
  private followUpsCount;
521
527
  }
522
528
 
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 };
529
+ 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, provideAgentTools as k, provideAgentTool as p, utcDay as u };
@@ -100,7 +100,14 @@ var AgentRunSteps = class {
100
100
  const tools = (0, import_nestjs_agent_core.withMemoryTool)({
101
101
  tools: (0, import_nestjs_agent_core.withSkillTool)({
102
102
  tools: (0, import_nestjs_agent_core.withAskTool)({
103
- tools: await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList),
103
+ tools: await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList, {
104
+ ...input.threadId !== void 0 ? {
105
+ threadId: input.threadId
106
+ } : {},
107
+ ...input.agentName !== void 0 ? {
108
+ agentName: input.agentName
109
+ } : {}
110
+ }),
104
111
  ask: deps.ask
105
112
  }),
106
113
  enabled: deps.skills !== void 0
@@ -3497,6 +3504,14 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
3497
3504
  if (instance === null || instance === void 0 || typeof instance !== "object") {
3498
3505
  continue;
3499
3506
  }
3507
+ if (Array.isArray(instance) && instance.length > 0 && instance.every((each) => typeof each === "object" && each !== null && isBrandedFunctionalTool(each))) {
3508
+ for (const tool of instance) {
3509
+ if (this.registerFunctionalTool(tool)) {
3510
+ functional += 1;
3511
+ }
3512
+ }
3513
+ continue;
3514
+ }
3500
3515
  if (isBrandedFunctionalTool(instance)) {
3501
3516
  if (this.registerFunctionalTool(instance)) {
3502
3517
  functional += 1;
@@ -3544,6 +3559,9 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
3544
3559
  } : {},
3545
3560
  ...typeof handler.canUse === "function" ? {
3546
3561
  canUse: /* @__PURE__ */ __name((actor) => instance.canUse(actor), "canUse")
3562
+ } : {},
3563
+ ...typeof handler.describe === "function" ? {
3564
+ describe: /* @__PURE__ */ __name((scope) => instance.describe(scope), "describe")
3547
3565
  } : {}
3548
3566
  });
3549
3567
  count += 1;