@dudousxd/nestjs-agent 1.24.2 → 1.25.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 +13 -5
- package/dist/durable/index.cjs +93 -11
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.js +94 -12
- package/dist/durable/index.js.map +1 -1
- package/dist/genui/index.cjs.map +1 -1
- package/dist/genui/index.d.cts +16 -3
- package/dist/genui/index.d.ts +16 -3
- package/dist/genui/index.js.map +1 -1
- package/dist/index.cjs +79 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -13
- package/dist/index.d.ts +31 -13
- package/dist/index.js +78 -12
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/genui/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/genui/index.ts","../../src/genui/agent-genui.module.ts","../../src/functional-tool.ts"],"sourcesContent":["/**\n * `@dudousxd/nestjs-agent/genui` — generative UI for NestJS: {@link AgentGenuiModule} registers the\n * tools that push catalog components, `GENUI_CATALOG` / `@InjectGenuiCatalog()` expose the catalog,\n * and {@link GenuiCatalogResolver} serves per-request (per-tenant) catalogs. The catalog itself —\n * `defineComponent`, `defineCatalog`, validation, text fallbacks — is re-exported from\n * `@dudousxd/nestjs-agent-core/genui`, the isomorphic entry a browser imports too.\n */\nexport {\n AgentGenuiModule,\n type AgentGenuiModuleAsyncOptions,\n type AgentGenuiModuleOptions,\n type AgentGenuiOptions,\n GENUI_CATALOG,\n GENUI_OPTIONS,\n GenuiCatalogResolver,\n InjectGenuiCatalog,\n} from './agent-genui.module.js';\nexport * from '@dudousxd/nestjs-agent-core/genui';\n","import type { ToolPresentation } from '@dudousxd/nestjs-agent-core';\nimport type {\n Catalog,\n GenuiCatalogScope,\n GenuiToolsOptions,\n TreeLimits,\n} from '@dudousxd/nestjs-agent-core/genui';\nimport { defineCatalog, genuiTools } from '@dudousxd/nestjs-agent-core/genui';\nimport {\n type DynamicModule,\n type FactoryProvider,\n Inject,\n Module,\n type ModuleMetadata,\n type Provider,\n type Type,\n} from '@nestjs/common';\nimport { provideAgentTools } from '../functional-tool.js';\n\n/** The app's genui catalog — `@InjectGenuiCatalog()` it anywhere; `overrideProvider` it in tests. */\nexport const GENUI_CATALOG = Symbol.for('@dudousxd/nestjs-agent:genui-catalog');\n\n/** The resolved {@link AgentGenuiOptions} (without the resolver). */\nexport const GENUI_OPTIONS = Symbol.for('@dudousxd/nestjs-agent:genui-options');\n\n/** Inject the app's genui catalog ({@link GENUI_CATALOG}). */\nexport const InjectGenuiCatalog = (): ParameterDecorator & PropertyDecorator =>\n Inject(GENUI_CATALOG);\n\n/**\n * Picks the catalog for ONE request — a tenant's own, versioned components. Consulted when a genui\n * call is validated and when the turn's tool list is described to the model, so components can\n * change without rebuilding tools at boot. Cache in here if resolving costs a round trip: it runs\n * once per turn per genui tool, and once per call.\n *\n * Provide it through `AgentGenuiModule.forRoot({ resolver })` (a class, resolved with DI, or an\n * instance); it is then injectable, and replaceable in a test with\n * `overrideProvider(GenuiCatalogResolver)`.\n */\nexport abstract class GenuiCatalogResolver {\n abstract resolve(scope: GenuiCatalogScope): Catalog | Promise<Catalog>;\n}\n\n/** What {@link AgentGenuiModule} builds tools from. */\nexport interface AgentGenuiOptions {\n /**\n * The catalog. With a {@link GenuiCatalogResolver} it is the boot-time one — it names the\n * per-component tools — and may be empty. Default: an empty catalog.\n */\n catalog?: Catalog;\n /** `per-component` (default): one `ui__show_<snake>` tool per component. `tree`: one tool taking a composed tree. */\n mode?: 'per-component' | 'tree';\n /** End the model's turn once a genui call succeeds (no narrating follow-up call). */\n terminal?: boolean;\n /** Tool name in `tree` mode. Default `ui__render`. */\n treeToolName?: string;\n /** Text prepended to the tree tool's description. */\n treeInstructions?: string;\n treeLimits?: TreeLimits;\n /** Tool-name prefix in `per-component` mode. Default `ui__show_`. */\n namePrefix?: string;\n /**\n * Also register ONE generic tool taking `{ component, props }`, validated against the request's\n * catalog — how a model reaches a tenant's own components, which no boot-time tool names. `true`\n * names it `ui__show`.\n */\n showTool?: boolean | string;\n /** Text prepended to the show tool's description. */\n showInstructions?: string;\n /** Roles allowed to call the tools. Undefined → the roles policy default. */\n roles?: string[];\n /** Override the generated presentation per component (or per tree / show tool name). */\n presentation?: (component: string) => ToolPresentation | undefined;\n}\n\ntype ResolverOption = Type<GenuiCatalogResolver> | GenuiCatalogResolver;\n\nexport interface AgentGenuiModuleOptions extends AgentGenuiOptions {\n /** Per-request catalogs. A class is instantiated with DI (its dependencies must be global or exported to the root). */\n resolver?: ResolverOption;\n}\n\nexport interface AgentGenuiModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {\n inject?: FactoryProvider['inject'];\n useFactory: (...deps: any[]) => AgentGenuiOptions | Promise<AgentGenuiOptions>;\n /** Per-request catalogs. A class resolves its dependencies from `imports`. */\n resolver?: ResolverOption;\n}\n\nfunction resolverProviders(resolver: ResolverOption | undefined): Provider[] {\n if (resolver === undefined) return [];\n return [\n typeof resolver === 'function'\n ? { provide: GenuiCatalogResolver, useClass: resolver }\n : { provide: GenuiCatalogResolver, useValue: resolver },\n ];\n}\n\nfunction toolOptions(\n options: AgentGenuiOptions,\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions {\n const { catalog: _catalog, ...rest } = options;\n return {\n ...rest,\n ...(resolver !== undefined\n ? { resolveCatalog: (scope: GenuiCatalogScope) => resolver.resolve(scope) }\n : {}),\n };\n}\n\nfunction coreProviders(resolver: ResolverOption | undefined): Provider[] {\n return [\n {\n provide: GENUI_CATALOG,\n useFactory: (options: AgentGenuiOptions) => options.catalog ?? defineCatalog([]),\n inject: [GENUI_OPTIONS],\n },\n ...resolverProviders(resolver),\n // The generated tools, registered by the agent module's discovery like any `provideAgentTool`.\n // Built from the injected catalog, so `overrideProvider(GENUI_CATALOG)` changes them too.\n provideAgentTools(\n (options: AgentGenuiOptions, catalog: Catalog, perRequest?: GenuiCatalogResolver) =>\n genuiTools(catalog, toolOptions(options, perRequest)),\n [GENUI_OPTIONS, GENUI_CATALOG, { token: GenuiCatalogResolver, optional: true }],\n ),\n ];\n}\n\nconst EXPORTS = [GENUI_CATALOG, GENUI_OPTIONS];\n\n/**\n * Generative UI for the agent: registers the tools that let the model push catalog components\n * (`ui__show_<component>`, or one tree tool, or the generic `ui__show`), and makes the catalog\n * injectable. Global, like `AgentModule`; import it once, next to it.\n *\n * ```ts\n * AgentGenuiModule.forRoot({ catalog, mode: 'tree', terminal: true })\n * ```\n */\n@Module({})\nexport class AgentGenuiModule {\n static forRoot(options: AgentGenuiModuleOptions = {}): DynamicModule {\n const { resolver, ...rest } = options;\n return {\n module: AgentGenuiModule,\n global: true,\n providers: [{ provide: GENUI_OPTIONS, useValue: rest }, ...coreProviders(resolver)],\n exports: resolver === undefined ? EXPORTS : [...EXPORTS, GenuiCatalogResolver],\n };\n }\n\n static forRootAsync(options: AgentGenuiModuleAsyncOptions): DynamicModule {\n return {\n module: AgentGenuiModule,\n global: true,\n imports: options.imports ?? [],\n providers: [\n { provide: GENUI_OPTIONS, useFactory: options.useFactory, inject: options.inject ?? [] },\n ...coreProviders(options.resolver),\n ],\n exports: options.resolver === undefined ? EXPORTS : [...EXPORTS, GenuiCatalogResolver],\n };\n }\n}\n","import {\n type FunctionalToolDefinition,\n type ToolHandler,\n type ToolSpec,\n createFunctionalTool,\n} from '@dudousxd/nestjs-agent-core';\nimport type { FactoryProvider, Provider } from '@nestjs/common';\n\n/**\n * Brand stamped onto a functional-tool provider instance so `AiToolDiscoveryService` picks it up\n * when it walks every provider at boot — the declarative alternative to a manual `registry.register`.\n */\nexport const AGENT_TOOL_BRAND = Symbol.for('@dudousxd/nestjs-agent:functional-tool');\n\n/** A tool expressed as data + handler (e.g. from `createExecuteSqlTool`), not an `@AiTool` class. */\nexport interface FunctionalTool {\n spec: ToolSpec;\n handler: ToolHandler;\n}\n\n/** A {@link FunctionalTool} carrying {@link AGENT_TOOL_BRAND} — what a provider resolves to. */\nexport interface BrandedFunctionalTool extends FunctionalTool {\n readonly [AGENT_TOOL_BRAND]: true;\n}\n\nfunction brand(tool: FunctionalTool): BrandedFunctionalTool {\n return { [AGENT_TOOL_BRAND]: true, spec: tool.spec, handler: tool.handler };\n}\n\n/** Narrows a provider instance to a branded functional tool for boot-time registration. */\nexport function isBrandedFunctionalTool(value: object): value is BrandedFunctionalTool {\n return AGENT_TOOL_BRAND in value && 'spec' in value && 'handler' in value;\n}\n\n/**\n * Registers a functional tool declaratively — drop the returned provider in a module's `providers`\n * and `AiToolDiscoveryService` auto-registers it at boot. Each call uses a fresh, unique provide\n * token so the same tool can be provided many times without collisions.\n *\n * Two forms: a static tool (`useValue`) or a factory with `inject` for DI-resolved dependencies\n * (`useFactory`). Either way the resolved instance is branded with {@link AGENT_TOOL_BRAND}.\n */\nexport function provideAgentTool(tool: FunctionalTool): Provider;\nexport function provideAgentTool(\n factory: (...deps: never[]) => FunctionalTool,\n inject?: FactoryProvider['inject'],\n): Provider;\nexport function provideAgentTool(\n factoryOrTool: FunctionalTool | ((...deps: never[]) => FunctionalTool),\n inject?: FactoryProvider['inject'],\n): Provider {\n const provide = Symbol('nestjs-agent:functional-tool-instance');\n if (typeof factoryOrTool === 'function') {\n return {\n provide,\n useFactory: (...deps: never[]) => brand(factoryOrTool(...deps)),\n inject: inject ?? [],\n };\n }\n return { provide, useValue: brand(factoryOrTool) };\n}\n\n/**\n * Registers a LIST of functional tools from one factory — for a producer whose tool count is only\n * known once its dependencies resolve (a catalog loaded from config, one tool per entry). The\n * factory's result is branded element by element; `AiToolDiscoveryService` registers each.\n */\nexport function provideAgentTools(\n factory: (...deps: never[]) => readonly FunctionalTool[] | Promise<readonly FunctionalTool[]>,\n inject?: FactoryProvider['inject'],\n): Provider {\n return {\n provide: Symbol('nestjs-agent:functional-tool-list'),\n useFactory: async (...deps: never[]) => (await factory(...deps)).map(brand),\n inject: inject ?? [],\n };\n}\n\n/** Author a functional tool with inferred Standard Schema input and domain output. */\nexport const defineTool = createFunctionalTool;\nexport type { FunctionalToolDefinition };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;ACOA,mBAA0C;AAC1C,oBAQO;;;AChBP,+BAKO;AAOA,IAAMA,mBAAmBC,uBAAOC,IAAI,wCAAA;AAa3C,SAASC,MAAMC,MAAoB;AACjC,SAAO;IAAE,CAACJ,gBAAAA,GAAmB;IAAMK,MAAMD,KAAKC;IAAMC,SAASF,KAAKE;EAAQ;AAC5E;AAFSH;AA0CF,SAASI,kBACdC,SACAC,QAAkC;AAElC,SAAO;IACLC,SAASC,uBAAO,mCAAA;IAChBC,YAAY,iCAAUC,UAAmB,MAAML,QAAAA,GAAWK,IAAAA,GAAOC,IAAIC,KAAAA,GAAzD;IACZN,QAAQA,UAAU,CAAA;EACpB;AACF;AATgBF;;;;;;;;;;;;;;;;;AD/CT,IAAMS,gBAAgBC,uBAAOC,IAAI,sCAAA;AAGjC,IAAMC,gBAAgBF,uBAAOC,IAAI,sCAAA;AAGjC,IAAME,qBAAqB,iCAChCC,sBAAOL,aAAAA,GADyB;AAa3B,IAAeM,uBAAf,MAAeA;SAAAA;;;AAEtB;AAgDA,SAASC,kBAAkBC,UAAoC;AAC7D,MAAIA,aAAaC,OAAW,QAAO,CAAA;AACnC,SAAO;IACL,OAAOD,aAAa,aAChB;MAAEE,SAASJ;MAAsBK,UAAUH;IAAS,IACpD;MAAEE,SAASJ;MAAsBM,UAAUJ;IAAS;;AAE5D;AAPSD;AAST,SAASM,YACPC,SACAN,UAA0C;AAE1C,QAAM,EAAEO,SAASC,UAAU,GAAGC,KAAAA,IAASH;AACvC,SAAO;IACL,GAAGG;IACH,GAAIT,aAAaC,SACb;MAAES,gBAAgB,wBAACC,UAA6BX,SAASY,QAAQD,KAAAA,GAA/C;IAAsD,IACxE,CAAC;EACP;AACF;AAXSN;AAaT,SAASQ,cAAcb,UAAoC;AACzD,SAAO;IACL;MACEE,SAASV;MACTsB,YAAY,wBAACR,YAA+BA,QAAQC,eAAWQ,4BAAc,CAAA,CAAE,GAAnE;MACZC,QAAQ;QAACrB;;IACX;OACGI,kBAAkBC,QAAAA;;;IAGrBiB,kBACE,CAACX,SAA4BC,SAAkBW,mBAC7CC,yBAAWZ,SAASF,YAAYC,SAASY,UAAAA,CAAAA,GAC3C;MAACvB;MAAeH;MAAe;QAAE4B,OAAOtB;QAAsBuB,UAAU;MAAK;KAAE;;AAGrF;AAhBSR;AAkBT,IAAMS,UAAU;EAAC9B;EAAeG;;AAYzB,IAAM4B,mBAAN,MAAMA,kBAAAA;SAAAA;;;EACX,OAAOC,QAAQlB,UAAmC,CAAC,GAAkB;AACnE,UAAM,EAAEN,UAAU,GAAGS,KAAAA,IAASH;AAC9B,WAAO;MACLmB,QAAQF;MACRG,QAAQ;MACRC,WAAW;QAAC;UAAEzB,SAASP;UAAeS,UAAUK;QAAK;WAAMI,cAAcb,QAAAA;;MACzE4B,SAAS5B,aAAaC,SAAYqB,UAAU;WAAIA;QAASxB;;IAC3D;EACF;EAEA,OAAO+B,aAAavB,SAAsD;AACxE,WAAO;MACLmB,QAAQF;MACRG,QAAQ;MACRI,SAASxB,QAAQwB,WAAW,CAAA;MAC5BH,WAAW;QACT;UAAEzB,SAASP;UAAemB,YAAYR,QAAQQ;UAAYE,QAAQV,QAAQU,UAAU,CAAA;QAAG;WACpFH,cAAcP,QAAQN,QAAQ;;MAEnC4B,SAAStB,QAAQN,aAAaC,SAAYqB,UAAU;WAAIA;QAASxB;;IACnE;EACF;AACF;;;;;;ADnJA,0BAAc,8CAjBd;","names":["AGENT_TOOL_BRAND","Symbol","for","brand","tool","spec","handler","provideAgentTools","factory","inject","provide","Symbol","useFactory","deps","map","brand","GENUI_CATALOG","Symbol","for","GENUI_OPTIONS","InjectGenuiCatalog","Inject","GenuiCatalogResolver","resolverProviders","resolver","undefined","provide","useClass","useValue","toolOptions","options","catalog","_catalog","rest","resolveCatalog","scope","resolve","coreProviders","useFactory","defineCatalog","inject","provideAgentTools","perRequest","genuiTools","token","optional","EXPORTS","AgentGenuiModule","forRoot","module","global","providers","exports","forRootAsync","imports"]}
|
|
1
|
+
{"version":3,"sources":["../../src/genui/index.ts","../../src/genui/agent-genui.module.ts","../../src/functional-tool.ts"],"sourcesContent":["/**\n * `@dudousxd/nestjs-agent/genui` — generative UI for NestJS: {@link AgentGenuiModule} registers the\n * tools that push catalog components, `GENUI_CATALOG` / `@InjectGenuiCatalog()` expose the catalog,\n * and {@link GenuiCatalogResolver} serves per-request (per-tenant) catalogs. The catalog itself —\n * `defineComponent`, `defineCatalog`, validation, text fallbacks — is re-exported from\n * `@dudousxd/nestjs-agent-core/genui`, the isomorphic entry a browser imports too.\n */\nexport {\n AgentGenuiModule,\n type AgentGenuiModuleAsyncOptions,\n type AgentGenuiModuleOptions,\n type AgentGenuiOptions,\n GENUI_CATALOG,\n GENUI_OPTIONS,\n GenuiCatalogResolver,\n InjectGenuiCatalog,\n} from './agent-genui.module.js';\nexport * from '@dudousxd/nestjs-agent-core/genui';\n","import type { ToolPresentation } from '@dudousxd/nestjs-agent-core';\nimport type {\n Catalog,\n GenuiCatalogScope,\n GenuiStreaming,\n GenuiToolsOptions,\n TreeLimits,\n TreeSchemaMode,\n} from '@dudousxd/nestjs-agent-core/genui';\nimport { defineCatalog, genuiTools } from '@dudousxd/nestjs-agent-core/genui';\nimport {\n type DynamicModule,\n type FactoryProvider,\n Inject,\n Module,\n type ModuleMetadata,\n type Provider,\n type Type,\n} from '@nestjs/common';\nimport { provideAgentTools } from '../functional-tool.js';\n\n/** The app's genui catalog — `@InjectGenuiCatalog()` it anywhere; `overrideProvider` it in tests. */\nexport const GENUI_CATALOG = Symbol.for('@dudousxd/nestjs-agent:genui-catalog');\n\n/** The resolved {@link AgentGenuiOptions} (without the resolver). */\nexport const GENUI_OPTIONS = Symbol.for('@dudousxd/nestjs-agent:genui-options');\n\n/** Inject the app's genui catalog ({@link GENUI_CATALOG}). */\nexport const InjectGenuiCatalog = (): ParameterDecorator & PropertyDecorator =>\n Inject(GENUI_CATALOG);\n\n/**\n * Picks the catalog for ONE request — a tenant's own, versioned components. Consulted when a genui\n * call is validated and when the turn's tool list is described to the model, so components can\n * change without rebuilding tools at boot. Cache in here if resolving costs a round trip: it runs\n * once per turn per genui tool, and once per call.\n *\n * Provide it through `AgentGenuiModule.forRoot({ resolver })` (a class, resolved with DI, or an\n * instance); it is then injectable, and replaceable in a test with\n * `overrideProvider(GenuiCatalogResolver)`.\n */\nexport abstract class GenuiCatalogResolver {\n abstract resolve(scope: GenuiCatalogScope): Catalog | Promise<Catalog>;\n}\n\n/** What {@link AgentGenuiModule} builds tools from. */\nexport interface AgentGenuiOptions {\n /**\n * The catalog. With a {@link GenuiCatalogResolver} it is the boot-time one — it names the\n * per-component tools — and may be empty. Default: an empty catalog.\n */\n catalog?: Catalog;\n /**\n * `tree` (default): one `ui__render` tool taking a composed tree (a single node is pushed as that\n * component). `per-component`: one `ui__show_<snake>` tool per component.\n */\n mode?: 'per-component' | 'tree';\n /** `ui__render`'s input schema: `'strict'` (default, a `$defs` union per component) or `'loose'`. */\n treeSchema?: TreeSchemaMode;\n /**\n * Tree mode: `'complete'` (default) draws the tree once the call has run; `'partial'` streams it\n * as `partial` ui frames while the model writes it. A component's own `streaming` overrides it.\n */\n streaming?: GenuiStreaming;\n /** Least time between two partial tree frames of one call, in ms. Default 100. */\n streamingThrottleMs?: number;\n /** End the model's turn once a genui call succeeds (no narrating follow-up call). */\n terminal?: boolean;\n /** Tool name in `tree` mode. Default `ui__render`. */\n treeToolName?: string;\n /** Text prepended to the tree tool's description. */\n treeInstructions?: string;\n treeLimits?: TreeLimits;\n /** Tool-name prefix in `per-component` mode. Default `ui__show_`. */\n namePrefix?: string;\n /**\n * Also register ONE generic tool taking `{ component, props }`, validated against the request's\n * catalog — how a model reaches a tenant's own components, which no boot-time tool names. `true`\n * names it `ui__show`.\n */\n showTool?: boolean | string;\n /** Text prepended to the show tool's description. */\n showInstructions?: string;\n /** Roles allowed to call the tools. Undefined → the roles policy default. */\n roles?: string[];\n /** Override the generated presentation per component (or per tree / show tool name). */\n presentation?: (component: string) => ToolPresentation | undefined;\n}\n\ntype ResolverOption = Type<GenuiCatalogResolver> | GenuiCatalogResolver;\n\nexport interface AgentGenuiModuleOptions extends AgentGenuiOptions {\n /** Per-request catalogs. A class is instantiated with DI (its dependencies must be global or exported to the root). */\n resolver?: ResolverOption;\n}\n\nexport interface AgentGenuiModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {\n inject?: FactoryProvider['inject'];\n useFactory: (...deps: any[]) => AgentGenuiOptions | Promise<AgentGenuiOptions>;\n /** Per-request catalogs. A class resolves its dependencies from `imports`. */\n resolver?: ResolverOption;\n}\n\nfunction resolverProviders(resolver: ResolverOption | undefined): Provider[] {\n if (resolver === undefined) return [];\n return [\n typeof resolver === 'function'\n ? { provide: GenuiCatalogResolver, useClass: resolver }\n : { provide: GenuiCatalogResolver, useValue: resolver },\n ];\n}\n\nfunction toolOptions(\n options: AgentGenuiOptions,\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions {\n const { catalog: _catalog, ...rest } = options;\n return {\n ...rest,\n ...(resolver !== undefined\n ? { resolveCatalog: (scope: GenuiCatalogScope) => resolver.resolve(scope) }\n : {}),\n };\n}\n\nfunction coreProviders(resolver: ResolverOption | undefined): Provider[] {\n return [\n {\n provide: GENUI_CATALOG,\n useFactory: (options: AgentGenuiOptions) => options.catalog ?? defineCatalog([]),\n inject: [GENUI_OPTIONS],\n },\n ...resolverProviders(resolver),\n // The generated tools, registered by the agent module's discovery like any `provideAgentTool`.\n // Built from the injected catalog, so `overrideProvider(GENUI_CATALOG)` changes them too.\n provideAgentTools(\n (options: AgentGenuiOptions, catalog: Catalog, perRequest?: GenuiCatalogResolver) =>\n genuiTools(catalog, toolOptions(options, perRequest)),\n [GENUI_OPTIONS, GENUI_CATALOG, { token: GenuiCatalogResolver, optional: true }],\n ),\n ];\n}\n\nconst EXPORTS = [GENUI_CATALOG, GENUI_OPTIONS];\n\n/**\n * Generative UI for the agent: registers the tools that let the model push catalog components\n * (one `ui__render` tree tool, or `ui__show_<component>` per component, and/or the generic\n * `ui__show`), and makes the catalog\n * injectable. Global, like `AgentModule`; import it once, next to it.\n *\n * ```ts\n * AgentGenuiModule.forRoot({ catalog, mode: 'tree', terminal: true })\n * ```\n */\n@Module({})\nexport class AgentGenuiModule {\n static forRoot(options: AgentGenuiModuleOptions = {}): DynamicModule {\n const { resolver, ...rest } = options;\n return {\n module: AgentGenuiModule,\n global: true,\n providers: [{ provide: GENUI_OPTIONS, useValue: rest }, ...coreProviders(resolver)],\n exports: resolver === undefined ? EXPORTS : [...EXPORTS, GenuiCatalogResolver],\n };\n }\n\n static forRootAsync(options: AgentGenuiModuleAsyncOptions): DynamicModule {\n return {\n module: AgentGenuiModule,\n global: true,\n imports: options.imports ?? [],\n providers: [\n { provide: GENUI_OPTIONS, useFactory: options.useFactory, inject: options.inject ?? [] },\n ...coreProviders(options.resolver),\n ],\n exports: options.resolver === undefined ? EXPORTS : [...EXPORTS, GenuiCatalogResolver],\n };\n }\n}\n","import {\n type FunctionalToolDefinition,\n type ToolHandler,\n type ToolSpec,\n createFunctionalTool,\n} from '@dudousxd/nestjs-agent-core';\nimport type { FactoryProvider, Provider } from '@nestjs/common';\n\n/**\n * Brand stamped onto a functional-tool provider instance so `AiToolDiscoveryService` picks it up\n * when it walks every provider at boot — the declarative alternative to a manual `registry.register`.\n */\nexport const AGENT_TOOL_BRAND = Symbol.for('@dudousxd/nestjs-agent:functional-tool');\n\n/** A tool expressed as data + handler (e.g. from `createExecuteSqlTool`), not an `@AiTool` class. */\nexport interface FunctionalTool {\n spec: ToolSpec;\n handler: ToolHandler;\n}\n\n/** A {@link FunctionalTool} carrying {@link AGENT_TOOL_BRAND} — what a provider resolves to. */\nexport interface BrandedFunctionalTool extends FunctionalTool {\n readonly [AGENT_TOOL_BRAND]: true;\n}\n\nfunction brand(tool: FunctionalTool): BrandedFunctionalTool {\n return { [AGENT_TOOL_BRAND]: true, spec: tool.spec, handler: tool.handler };\n}\n\n/** Narrows a provider instance to a branded functional tool for boot-time registration. */\nexport function isBrandedFunctionalTool(value: object): value is BrandedFunctionalTool {\n return AGENT_TOOL_BRAND in value && 'spec' in value && 'handler' in value;\n}\n\n/**\n * Registers a functional tool declaratively — drop the returned provider in a module's `providers`\n * and `AiToolDiscoveryService` auto-registers it at boot. Each call uses a fresh, unique provide\n * token so the same tool can be provided many times without collisions.\n *\n * Two forms: a static tool (`useValue`) or a factory with `inject` for DI-resolved dependencies\n * (`useFactory`). Either way the resolved instance is branded with {@link AGENT_TOOL_BRAND}.\n */\nexport function provideAgentTool(tool: FunctionalTool): Provider;\nexport function provideAgentTool(\n factory: (...deps: never[]) => FunctionalTool,\n inject?: FactoryProvider['inject'],\n): Provider;\nexport function provideAgentTool(\n factoryOrTool: FunctionalTool | ((...deps: never[]) => FunctionalTool),\n inject?: FactoryProvider['inject'],\n): Provider {\n const provide = Symbol('nestjs-agent:functional-tool-instance');\n if (typeof factoryOrTool === 'function') {\n return {\n provide,\n useFactory: (...deps: never[]) => brand(factoryOrTool(...deps)),\n inject: inject ?? [],\n };\n }\n return { provide, useValue: brand(factoryOrTool) };\n}\n\n/**\n * Registers a LIST of functional tools from one factory — for a producer whose tool count is only\n * known once its dependencies resolve (a catalog loaded from config, one tool per entry). The\n * factory's result is branded element by element; `AiToolDiscoveryService` registers each.\n */\nexport function provideAgentTools(\n factory: (...deps: never[]) => readonly FunctionalTool[] | Promise<readonly FunctionalTool[]>,\n inject?: FactoryProvider['inject'],\n): Provider {\n return {\n provide: Symbol('nestjs-agent:functional-tool-list'),\n useFactory: async (...deps: never[]) => (await factory(...deps)).map(brand),\n inject: inject ?? [],\n };\n}\n\n/** Author a functional tool with inferred Standard Schema input and domain output. */\nexport const defineTool = createFunctionalTool;\nexport type { FunctionalToolDefinition };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;ACSA,mBAA0C;AAC1C,oBAQO;;;AClBP,+BAKO;AAOA,IAAMA,mBAAmBC,uBAAOC,IAAI,wCAAA;AAa3C,SAASC,MAAMC,MAAoB;AACjC,SAAO;IAAE,CAACJ,gBAAAA,GAAmB;IAAMK,MAAMD,KAAKC;IAAMC,SAASF,KAAKE;EAAQ;AAC5E;AAFSH;AA0CF,SAASI,kBACdC,SACAC,QAAkC;AAElC,SAAO;IACLC,SAASC,uBAAO,mCAAA;IAChBC,YAAY,iCAAUC,UAAmB,MAAML,QAAAA,GAAWK,IAAAA,GAAOC,IAAIC,KAAAA,GAAzD;IACZN,QAAQA,UAAU,CAAA;EACpB;AACF;AATgBF;;;;;;;;;;;;;;;;;AD7CT,IAAMS,gBAAgBC,uBAAOC,IAAI,sCAAA;AAGjC,IAAMC,gBAAgBF,uBAAOC,IAAI,sCAAA;AAGjC,IAAME,qBAAqB,iCAChCC,sBAAOL,aAAAA,GADyB;AAa3B,IAAeM,uBAAf,MAAeA;SAAAA;;;AAEtB;AA4DA,SAASC,kBAAkBC,UAAoC;AAC7D,MAAIA,aAAaC,OAAW,QAAO,CAAA;AACnC,SAAO;IACL,OAAOD,aAAa,aAChB;MAAEE,SAASJ;MAAsBK,UAAUH;IAAS,IACpD;MAAEE,SAASJ;MAAsBM,UAAUJ;IAAS;;AAE5D;AAPSD;AAST,SAASM,YACPC,SACAN,UAA0C;AAE1C,QAAM,EAAEO,SAASC,UAAU,GAAGC,KAAAA,IAASH;AACvC,SAAO;IACL,GAAGG;IACH,GAAIT,aAAaC,SACb;MAAES,gBAAgB,wBAACC,UAA6BX,SAASY,QAAQD,KAAAA,GAA/C;IAAsD,IACxE,CAAC;EACP;AACF;AAXSN;AAaT,SAASQ,cAAcb,UAAoC;AACzD,SAAO;IACL;MACEE,SAASV;MACTsB,YAAY,wBAACR,YAA+BA,QAAQC,eAAWQ,4BAAc,CAAA,CAAE,GAAnE;MACZC,QAAQ;QAACrB;;IACX;OACGI,kBAAkBC,QAAAA;;;IAGrBiB,kBACE,CAACX,SAA4BC,SAAkBW,mBAC7CC,yBAAWZ,SAASF,YAAYC,SAASY,UAAAA,CAAAA,GAC3C;MAACvB;MAAeH;MAAe;QAAE4B,OAAOtB;QAAsBuB,UAAU;MAAK;KAAE;;AAGrF;AAhBSR;AAkBT,IAAMS,UAAU;EAAC9B;EAAeG;;AAazB,IAAM4B,mBAAN,MAAMA,kBAAAA;SAAAA;;;EACX,OAAOC,QAAQlB,UAAmC,CAAC,GAAkB;AACnE,UAAM,EAAEN,UAAU,GAAGS,KAAAA,IAASH;AAC9B,WAAO;MACLmB,QAAQF;MACRG,QAAQ;MACRC,WAAW;QAAC;UAAEzB,SAASP;UAAeS,UAAUK;QAAK;WAAMI,cAAcb,QAAAA;;MACzE4B,SAAS5B,aAAaC,SAAYqB,UAAU;WAAIA;QAASxB;;IAC3D;EACF;EAEA,OAAO+B,aAAavB,SAAsD;AACxE,WAAO;MACLmB,QAAQF;MACRG,QAAQ;MACRI,SAASxB,QAAQwB,WAAW,CAAA;MAC5BH,WAAW;QACT;UAAEzB,SAASP;UAAemB,YAAYR,QAAQQ;UAAYE,QAAQV,QAAQU,UAAU,CAAA;QAAG;WACpFH,cAAcP,QAAQN,QAAQ;;MAEnC4B,SAAStB,QAAQN,aAAaC,SAAYqB,UAAU;WAAIA;QAASxB;;IACnE;EACF;AACF;;;;;;ADlKA,0BAAc,8CAjBd;","names":["AGENT_TOOL_BRAND","Symbol","for","brand","tool","spec","handler","provideAgentTools","factory","inject","provide","Symbol","useFactory","deps","map","brand","GENUI_CATALOG","Symbol","for","GENUI_OPTIONS","InjectGenuiCatalog","Inject","GenuiCatalogResolver","resolverProviders","resolver","undefined","provide","useClass","useValue","toolOptions","options","catalog","_catalog","rest","resolveCatalog","scope","resolve","coreProviders","useFactory","defineCatalog","inject","provideAgentTools","perRequest","genuiTools","token","optional","EXPORTS","AgentGenuiModule","forRoot","module","global","providers","exports","forRootAsync","imports"]}
|
package/dist/genui/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ToolPresentation } from '@dudousxd/nestjs-agent-core';
|
|
2
|
-
import { GenuiCatalogScope, Catalog, TreeLimits } from '@dudousxd/nestjs-agent-core/genui';
|
|
2
|
+
import { GenuiCatalogScope, Catalog, TreeSchemaMode, GenuiStreaming, TreeLimits } from '@dudousxd/nestjs-agent-core/genui';
|
|
3
3
|
export * from '@dudousxd/nestjs-agent-core/genui';
|
|
4
4
|
import { Type, DynamicModule, ModuleMetadata, FactoryProvider } from '@nestjs/common';
|
|
5
5
|
|
|
@@ -29,8 +29,20 @@ interface AgentGenuiOptions {
|
|
|
29
29
|
* per-component tools — and may be empty. Default: an empty catalog.
|
|
30
30
|
*/
|
|
31
31
|
catalog?: Catalog;
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* `tree` (default): one `ui__render` tool taking a composed tree (a single node is pushed as that
|
|
34
|
+
* component). `per-component`: one `ui__show_<snake>` tool per component.
|
|
35
|
+
*/
|
|
33
36
|
mode?: 'per-component' | 'tree';
|
|
37
|
+
/** `ui__render`'s input schema: `'strict'` (default, a `$defs` union per component) or `'loose'`. */
|
|
38
|
+
treeSchema?: TreeSchemaMode;
|
|
39
|
+
/**
|
|
40
|
+
* Tree mode: `'complete'` (default) draws the tree once the call has run; `'partial'` streams it
|
|
41
|
+
* as `partial` ui frames while the model writes it. A component's own `streaming` overrides it.
|
|
42
|
+
*/
|
|
43
|
+
streaming?: GenuiStreaming;
|
|
44
|
+
/** Least time between two partial tree frames of one call, in ms. Default 100. */
|
|
45
|
+
streamingThrottleMs?: number;
|
|
34
46
|
/** End the model's turn once a genui call succeeds (no narrating follow-up call). */
|
|
35
47
|
terminal?: boolean;
|
|
36
48
|
/** Tool name in `tree` mode. Default `ui__render`. */
|
|
@@ -66,7 +78,8 @@ interface AgentGenuiModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
|
|
|
66
78
|
}
|
|
67
79
|
/**
|
|
68
80
|
* Generative UI for the agent: registers the tools that let the model push catalog components
|
|
69
|
-
* (`
|
|
81
|
+
* (one `ui__render` tree tool, or `ui__show_<component>` per component, and/or the generic
|
|
82
|
+
* `ui__show`), and makes the catalog
|
|
70
83
|
* injectable. Global, like `AgentModule`; import it once, next to it.
|
|
71
84
|
*
|
|
72
85
|
* ```ts
|
package/dist/genui/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ToolPresentation } from '@dudousxd/nestjs-agent-core';
|
|
2
|
-
import { GenuiCatalogScope, Catalog, TreeLimits } from '@dudousxd/nestjs-agent-core/genui';
|
|
2
|
+
import { GenuiCatalogScope, Catalog, TreeSchemaMode, GenuiStreaming, TreeLimits } from '@dudousxd/nestjs-agent-core/genui';
|
|
3
3
|
export * from '@dudousxd/nestjs-agent-core/genui';
|
|
4
4
|
import { Type, DynamicModule, ModuleMetadata, FactoryProvider } from '@nestjs/common';
|
|
5
5
|
|
|
@@ -29,8 +29,20 @@ interface AgentGenuiOptions {
|
|
|
29
29
|
* per-component tools — and may be empty. Default: an empty catalog.
|
|
30
30
|
*/
|
|
31
31
|
catalog?: Catalog;
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* `tree` (default): one `ui__render` tool taking a composed tree (a single node is pushed as that
|
|
34
|
+
* component). `per-component`: one `ui__show_<snake>` tool per component.
|
|
35
|
+
*/
|
|
33
36
|
mode?: 'per-component' | 'tree';
|
|
37
|
+
/** `ui__render`'s input schema: `'strict'` (default, a `$defs` union per component) or `'loose'`. */
|
|
38
|
+
treeSchema?: TreeSchemaMode;
|
|
39
|
+
/**
|
|
40
|
+
* Tree mode: `'complete'` (default) draws the tree once the call has run; `'partial'` streams it
|
|
41
|
+
* as `partial` ui frames while the model writes it. A component's own `streaming` overrides it.
|
|
42
|
+
*/
|
|
43
|
+
streaming?: GenuiStreaming;
|
|
44
|
+
/** Least time between two partial tree frames of one call, in ms. Default 100. */
|
|
45
|
+
streamingThrottleMs?: number;
|
|
34
46
|
/** End the model's turn once a genui call succeeds (no narrating follow-up call). */
|
|
35
47
|
terminal?: boolean;
|
|
36
48
|
/** Tool name in `tree` mode. Default `ui__render`. */
|
|
@@ -66,7 +78,8 @@ interface AgentGenuiModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
|
|
|
66
78
|
}
|
|
67
79
|
/**
|
|
68
80
|
* Generative UI for the agent: registers the tools that let the model push catalog components
|
|
69
|
-
* (`
|
|
81
|
+
* (one `ui__render` tree tool, or `ui__show_<component>` per component, and/or the generic
|
|
82
|
+
* `ui__show`), and makes the catalog
|
|
70
83
|
* injectable. Global, like `AgentModule`; import it once, next to it.
|
|
71
84
|
*
|
|
72
85
|
* ```ts
|
package/dist/genui/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/genui/agent-genui.module.ts","../../src/functional-tool.ts","../../src/genui/index.ts"],"sourcesContent":["import type { ToolPresentation } from '@dudousxd/nestjs-agent-core';\nimport type {\n Catalog,\n GenuiCatalogScope,\n GenuiToolsOptions,\n TreeLimits,\n} from '@dudousxd/nestjs-agent-core/genui';\nimport { defineCatalog, genuiTools } from '@dudousxd/nestjs-agent-core/genui';\nimport {\n type DynamicModule,\n type FactoryProvider,\n Inject,\n Module,\n type ModuleMetadata,\n type Provider,\n type Type,\n} from '@nestjs/common';\nimport { provideAgentTools } from '../functional-tool.js';\n\n/** The app's genui catalog — `@InjectGenuiCatalog()` it anywhere; `overrideProvider` it in tests. */\nexport const GENUI_CATALOG = Symbol.for('@dudousxd/nestjs-agent:genui-catalog');\n\n/** The resolved {@link AgentGenuiOptions} (without the resolver). */\nexport const GENUI_OPTIONS = Symbol.for('@dudousxd/nestjs-agent:genui-options');\n\n/** Inject the app's genui catalog ({@link GENUI_CATALOG}). */\nexport const InjectGenuiCatalog = (): ParameterDecorator & PropertyDecorator =>\n Inject(GENUI_CATALOG);\n\n/**\n * Picks the catalog for ONE request — a tenant's own, versioned components. Consulted when a genui\n * call is validated and when the turn's tool list is described to the model, so components can\n * change without rebuilding tools at boot. Cache in here if resolving costs a round trip: it runs\n * once per turn per genui tool, and once per call.\n *\n * Provide it through `AgentGenuiModule.forRoot({ resolver })` (a class, resolved with DI, or an\n * instance); it is then injectable, and replaceable in a test with\n * `overrideProvider(GenuiCatalogResolver)`.\n */\nexport abstract class GenuiCatalogResolver {\n abstract resolve(scope: GenuiCatalogScope): Catalog | Promise<Catalog>;\n}\n\n/** What {@link AgentGenuiModule} builds tools from. */\nexport interface AgentGenuiOptions {\n /**\n * The catalog. With a {@link GenuiCatalogResolver} it is the boot-time one — it names the\n * per-component tools — and may be empty. Default: an empty catalog.\n */\n catalog?: Catalog;\n /** `per-component` (default): one `ui__show_<snake>` tool per component. `tree`: one tool taking a composed tree. */\n mode?: 'per-component' | 'tree';\n /** End the model's turn once a genui call succeeds (no narrating follow-up call). */\n terminal?: boolean;\n /** Tool name in `tree` mode. Default `ui__render`. */\n treeToolName?: string;\n /** Text prepended to the tree tool's description. */\n treeInstructions?: string;\n treeLimits?: TreeLimits;\n /** Tool-name prefix in `per-component` mode. Default `ui__show_`. */\n namePrefix?: string;\n /**\n * Also register ONE generic tool taking `{ component, props }`, validated against the request's\n * catalog — how a model reaches a tenant's own components, which no boot-time tool names. `true`\n * names it `ui__show`.\n */\n showTool?: boolean | string;\n /** Text prepended to the show tool's description. */\n showInstructions?: string;\n /** Roles allowed to call the tools. Undefined → the roles policy default. */\n roles?: string[];\n /** Override the generated presentation per component (or per tree / show tool name). */\n presentation?: (component: string) => ToolPresentation | undefined;\n}\n\ntype ResolverOption = Type<GenuiCatalogResolver> | GenuiCatalogResolver;\n\nexport interface AgentGenuiModuleOptions extends AgentGenuiOptions {\n /** Per-request catalogs. A class is instantiated with DI (its dependencies must be global or exported to the root). */\n resolver?: ResolverOption;\n}\n\nexport interface AgentGenuiModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {\n inject?: FactoryProvider['inject'];\n useFactory: (...deps: any[]) => AgentGenuiOptions | Promise<AgentGenuiOptions>;\n /** Per-request catalogs. A class resolves its dependencies from `imports`. */\n resolver?: ResolverOption;\n}\n\nfunction resolverProviders(resolver: ResolverOption | undefined): Provider[] {\n if (resolver === undefined) return [];\n return [\n typeof resolver === 'function'\n ? { provide: GenuiCatalogResolver, useClass: resolver }\n : { provide: GenuiCatalogResolver, useValue: resolver },\n ];\n}\n\nfunction toolOptions(\n options: AgentGenuiOptions,\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions {\n const { catalog: _catalog, ...rest } = options;\n return {\n ...rest,\n ...(resolver !== undefined\n ? { resolveCatalog: (scope: GenuiCatalogScope) => resolver.resolve(scope) }\n : {}),\n };\n}\n\nfunction coreProviders(resolver: ResolverOption | undefined): Provider[] {\n return [\n {\n provide: GENUI_CATALOG,\n useFactory: (options: AgentGenuiOptions) => options.catalog ?? defineCatalog([]),\n inject: [GENUI_OPTIONS],\n },\n ...resolverProviders(resolver),\n // The generated tools, registered by the agent module's discovery like any `provideAgentTool`.\n // Built from the injected catalog, so `overrideProvider(GENUI_CATALOG)` changes them too.\n provideAgentTools(\n (options: AgentGenuiOptions, catalog: Catalog, perRequest?: GenuiCatalogResolver) =>\n genuiTools(catalog, toolOptions(options, perRequest)),\n [GENUI_OPTIONS, GENUI_CATALOG, { token: GenuiCatalogResolver, optional: true }],\n ),\n ];\n}\n\nconst EXPORTS = [GENUI_CATALOG, GENUI_OPTIONS];\n\n/**\n * Generative UI for the agent: registers the tools that let the model push catalog components\n * (`ui__show_<component>`, or one tree tool, or the generic `ui__show`), and makes the catalog\n * injectable. Global, like `AgentModule`; import it once, next to it.\n *\n * ```ts\n * AgentGenuiModule.forRoot({ catalog, mode: 'tree', terminal: true })\n * ```\n */\n@Module({})\nexport class AgentGenuiModule {\n static forRoot(options: AgentGenuiModuleOptions = {}): DynamicModule {\n const { resolver, ...rest } = options;\n return {\n module: AgentGenuiModule,\n global: true,\n providers: [{ provide: GENUI_OPTIONS, useValue: rest }, ...coreProviders(resolver)],\n exports: resolver === undefined ? EXPORTS : [...EXPORTS, GenuiCatalogResolver],\n };\n }\n\n static forRootAsync(options: AgentGenuiModuleAsyncOptions): DynamicModule {\n return {\n module: AgentGenuiModule,\n global: true,\n imports: options.imports ?? [],\n providers: [\n { provide: GENUI_OPTIONS, useFactory: options.useFactory, inject: options.inject ?? [] },\n ...coreProviders(options.resolver),\n ],\n exports: options.resolver === undefined ? EXPORTS : [...EXPORTS, GenuiCatalogResolver],\n };\n }\n}\n","import {\n type FunctionalToolDefinition,\n type ToolHandler,\n type ToolSpec,\n createFunctionalTool,\n} from '@dudousxd/nestjs-agent-core';\nimport type { FactoryProvider, Provider } from '@nestjs/common';\n\n/**\n * Brand stamped onto a functional-tool provider instance so `AiToolDiscoveryService` picks it up\n * when it walks every provider at boot — the declarative alternative to a manual `registry.register`.\n */\nexport const AGENT_TOOL_BRAND = Symbol.for('@dudousxd/nestjs-agent:functional-tool');\n\n/** A tool expressed as data + handler (e.g. from `createExecuteSqlTool`), not an `@AiTool` class. */\nexport interface FunctionalTool {\n spec: ToolSpec;\n handler: ToolHandler;\n}\n\n/** A {@link FunctionalTool} carrying {@link AGENT_TOOL_BRAND} — what a provider resolves to. */\nexport interface BrandedFunctionalTool extends FunctionalTool {\n readonly [AGENT_TOOL_BRAND]: true;\n}\n\nfunction brand(tool: FunctionalTool): BrandedFunctionalTool {\n return { [AGENT_TOOL_BRAND]: true, spec: tool.spec, handler: tool.handler };\n}\n\n/** Narrows a provider instance to a branded functional tool for boot-time registration. */\nexport function isBrandedFunctionalTool(value: object): value is BrandedFunctionalTool {\n return AGENT_TOOL_BRAND in value && 'spec' in value && 'handler' in value;\n}\n\n/**\n * Registers a functional tool declaratively — drop the returned provider in a module's `providers`\n * and `AiToolDiscoveryService` auto-registers it at boot. Each call uses a fresh, unique provide\n * token so the same tool can be provided many times without collisions.\n *\n * Two forms: a static tool (`useValue`) or a factory with `inject` for DI-resolved dependencies\n * (`useFactory`). Either way the resolved instance is branded with {@link AGENT_TOOL_BRAND}.\n */\nexport function provideAgentTool(tool: FunctionalTool): Provider;\nexport function provideAgentTool(\n factory: (...deps: never[]) => FunctionalTool,\n inject?: FactoryProvider['inject'],\n): Provider;\nexport function provideAgentTool(\n factoryOrTool: FunctionalTool | ((...deps: never[]) => FunctionalTool),\n inject?: FactoryProvider['inject'],\n): Provider {\n const provide = Symbol('nestjs-agent:functional-tool-instance');\n if (typeof factoryOrTool === 'function') {\n return {\n provide,\n useFactory: (...deps: never[]) => brand(factoryOrTool(...deps)),\n inject: inject ?? [],\n };\n }\n return { provide, useValue: brand(factoryOrTool) };\n}\n\n/**\n * Registers a LIST of functional tools from one factory — for a producer whose tool count is only\n * known once its dependencies resolve (a catalog loaded from config, one tool per entry). The\n * factory's result is branded element by element; `AiToolDiscoveryService` registers each.\n */\nexport function provideAgentTools(\n factory: (...deps: never[]) => readonly FunctionalTool[] | Promise<readonly FunctionalTool[]>,\n inject?: FactoryProvider['inject'],\n): Provider {\n return {\n provide: Symbol('nestjs-agent:functional-tool-list'),\n useFactory: async (...deps: never[]) => (await factory(...deps)).map(brand),\n inject: inject ?? [],\n };\n}\n\n/** Author a functional tool with inferred Standard Schema input and domain output. */\nexport const defineTool = createFunctionalTool;\nexport type { FunctionalToolDefinition };\n","/**\n * `@dudousxd/nestjs-agent/genui` — generative UI for NestJS: {@link AgentGenuiModule} registers the\n * tools that push catalog components, `GENUI_CATALOG` / `@InjectGenuiCatalog()` expose the catalog,\n * and {@link GenuiCatalogResolver} serves per-request (per-tenant) catalogs. The catalog itself —\n * `defineComponent`, `defineCatalog`, validation, text fallbacks — is re-exported from\n * `@dudousxd/nestjs-agent-core/genui`, the isomorphic entry a browser imports too.\n */\nexport {\n AgentGenuiModule,\n type AgentGenuiModuleAsyncOptions,\n type AgentGenuiModuleOptions,\n type AgentGenuiOptions,\n GENUI_CATALOG,\n GENUI_OPTIONS,\n GenuiCatalogResolver,\n InjectGenuiCatalog,\n} from './agent-genui.module.js';\nexport * from '@dudousxd/nestjs-agent-core/genui';\n"],"mappings":";;;;AAOA,SAASA,eAAeC,kBAAkB;AAC1C,SAGEC,QACAC,cAIK;;;AChBP,SAIEC,4BACK;AAOA,IAAMC,mBAAmBC,uBAAOC,IAAI,wCAAA;AAa3C,SAASC,MAAMC,MAAoB;AACjC,SAAO;IAAE,CAACJ,gBAAAA,GAAmB;IAAMK,MAAMD,KAAKC;IAAMC,SAASF,KAAKE;EAAQ;AAC5E;AAFSH;AA0CF,SAASI,kBACdC,SACAC,QAAkC;AAElC,SAAO;IACLC,SAASC,uBAAO,mCAAA;IAChBC,YAAY,iCAAUC,UAAmB,MAAML,QAAAA,GAAWK,IAAAA,GAAOC,IAAIC,KAAAA,GAAzD;IACZN,QAAQA,UAAU,CAAA;EACpB;AACF;AATgBF;;;;;;;;;;;;;;;;;AD/CT,IAAMS,gBAAgBC,uBAAOC,IAAI,sCAAA;AAGjC,IAAMC,gBAAgBF,uBAAOC,IAAI,sCAAA;AAGjC,IAAME,qBAAqB,6BAChCC,OAAOL,aAAAA,GADyB;AAa3B,IAAeM,uBAAf,MAAeA;SAAAA;;;AAEtB;AAgDA,SAASC,kBAAkBC,UAAoC;AAC7D,MAAIA,aAAaC,OAAW,QAAO,CAAA;AACnC,SAAO;IACL,OAAOD,aAAa,aAChB;MAAEE,SAASJ;MAAsBK,UAAUH;IAAS,IACpD;MAAEE,SAASJ;MAAsBM,UAAUJ;IAAS;;AAE5D;AAPSD;AAST,SAASM,YACPC,SACAN,UAA0C;AAE1C,QAAM,EAAEO,SAASC,UAAU,GAAGC,KAAAA,IAASH;AACvC,SAAO;IACL,GAAGG;IACH,GAAIT,aAAaC,SACb;MAAES,gBAAgB,wBAACC,UAA6BX,SAASY,QAAQD,KAAAA,GAA/C;IAAsD,IACxE,CAAC;EACP;AACF;AAXSN;AAaT,SAASQ,cAAcb,UAAoC;AACzD,SAAO;IACL;MACEE,SAASV;MACTsB,YAAY,wBAACR,YAA+BA,QAAQC,WAAWQ,cAAc,CAAA,CAAE,GAAnE;MACZC,QAAQ;QAACrB;;IACX;OACGI,kBAAkBC,QAAAA;;;IAGrBiB,kBACE,CAACX,SAA4BC,SAAkBW,eAC7CC,WAAWZ,SAASF,YAAYC,SAASY,UAAAA,CAAAA,GAC3C;MAACvB;MAAeH;MAAe;QAAE4B,OAAOtB;QAAsBuB,UAAU;MAAK;KAAE;;AAGrF;AAhBSR;AAkBT,IAAMS,UAAU;EAAC9B;EAAeG;;AAYzB,IAAM4B,mBAAN,MAAMA,kBAAAA;SAAAA;;;EACX,OAAOC,QAAQlB,UAAmC,CAAC,GAAkB;AACnE,UAAM,EAAEN,UAAU,GAAGS,KAAAA,IAASH;AAC9B,WAAO;MACLmB,QAAQF;MACRG,QAAQ;MACRC,WAAW;QAAC;UAAEzB,SAASP;UAAeS,UAAUK;QAAK;WAAMI,cAAcb,QAAAA;;MACzE4B,SAAS5B,aAAaC,SAAYqB,UAAU;WAAIA;QAASxB;;IAC3D;EACF;EAEA,OAAO+B,aAAavB,SAAsD;AACxE,WAAO;MACLmB,QAAQF;MACRG,QAAQ;MACRI,SAASxB,QAAQwB,WAAW,CAAA;MAC5BH,WAAW;QACT;UAAEzB,SAASP;UAAemB,YAAYR,QAAQQ;UAAYE,QAAQV,QAAQU,UAAU,CAAA;QAAG;WACpFH,cAAcP,QAAQN,QAAQ;;MAEnC4B,SAAStB,QAAQN,aAAaC,SAAYqB,UAAU;WAAIA;QAASxB;;IACnE;EACF;AACF;;;;;;AEnJA,cAAc;","names":["defineCatalog","genuiTools","Inject","Module","createFunctionalTool","AGENT_TOOL_BRAND","Symbol","for","brand","tool","spec","handler","provideAgentTools","factory","inject","provide","Symbol","useFactory","deps","map","brand","GENUI_CATALOG","Symbol","for","GENUI_OPTIONS","InjectGenuiCatalog","Inject","GenuiCatalogResolver","resolverProviders","resolver","undefined","provide","useClass","useValue","toolOptions","options","catalog","_catalog","rest","resolveCatalog","scope","resolve","coreProviders","useFactory","defineCatalog","inject","provideAgentTools","perRequest","genuiTools","token","optional","EXPORTS","AgentGenuiModule","forRoot","module","global","providers","exports","forRootAsync","imports"]}
|
|
1
|
+
{"version":3,"sources":["../../src/genui/agent-genui.module.ts","../../src/functional-tool.ts","../../src/genui/index.ts"],"sourcesContent":["import type { ToolPresentation } from '@dudousxd/nestjs-agent-core';\nimport type {\n Catalog,\n GenuiCatalogScope,\n GenuiStreaming,\n GenuiToolsOptions,\n TreeLimits,\n TreeSchemaMode,\n} from '@dudousxd/nestjs-agent-core/genui';\nimport { defineCatalog, genuiTools } from '@dudousxd/nestjs-agent-core/genui';\nimport {\n type DynamicModule,\n type FactoryProvider,\n Inject,\n Module,\n type ModuleMetadata,\n type Provider,\n type Type,\n} from '@nestjs/common';\nimport { provideAgentTools } from '../functional-tool.js';\n\n/** The app's genui catalog — `@InjectGenuiCatalog()` it anywhere; `overrideProvider` it in tests. */\nexport const GENUI_CATALOG = Symbol.for('@dudousxd/nestjs-agent:genui-catalog');\n\n/** The resolved {@link AgentGenuiOptions} (without the resolver). */\nexport const GENUI_OPTIONS = Symbol.for('@dudousxd/nestjs-agent:genui-options');\n\n/** Inject the app's genui catalog ({@link GENUI_CATALOG}). */\nexport const InjectGenuiCatalog = (): ParameterDecorator & PropertyDecorator =>\n Inject(GENUI_CATALOG);\n\n/**\n * Picks the catalog for ONE request — a tenant's own, versioned components. Consulted when a genui\n * call is validated and when the turn's tool list is described to the model, so components can\n * change without rebuilding tools at boot. Cache in here if resolving costs a round trip: it runs\n * once per turn per genui tool, and once per call.\n *\n * Provide it through `AgentGenuiModule.forRoot({ resolver })` (a class, resolved with DI, or an\n * instance); it is then injectable, and replaceable in a test with\n * `overrideProvider(GenuiCatalogResolver)`.\n */\nexport abstract class GenuiCatalogResolver {\n abstract resolve(scope: GenuiCatalogScope): Catalog | Promise<Catalog>;\n}\n\n/** What {@link AgentGenuiModule} builds tools from. */\nexport interface AgentGenuiOptions {\n /**\n * The catalog. With a {@link GenuiCatalogResolver} it is the boot-time one — it names the\n * per-component tools — and may be empty. Default: an empty catalog.\n */\n catalog?: Catalog;\n /**\n * `tree` (default): one `ui__render` tool taking a composed tree (a single node is pushed as that\n * component). `per-component`: one `ui__show_<snake>` tool per component.\n */\n mode?: 'per-component' | 'tree';\n /** `ui__render`'s input schema: `'strict'` (default, a `$defs` union per component) or `'loose'`. */\n treeSchema?: TreeSchemaMode;\n /**\n * Tree mode: `'complete'` (default) draws the tree once the call has run; `'partial'` streams it\n * as `partial` ui frames while the model writes it. A component's own `streaming` overrides it.\n */\n streaming?: GenuiStreaming;\n /** Least time between two partial tree frames of one call, in ms. Default 100. */\n streamingThrottleMs?: number;\n /** End the model's turn once a genui call succeeds (no narrating follow-up call). */\n terminal?: boolean;\n /** Tool name in `tree` mode. Default `ui__render`. */\n treeToolName?: string;\n /** Text prepended to the tree tool's description. */\n treeInstructions?: string;\n treeLimits?: TreeLimits;\n /** Tool-name prefix in `per-component` mode. Default `ui__show_`. */\n namePrefix?: string;\n /**\n * Also register ONE generic tool taking `{ component, props }`, validated against the request's\n * catalog — how a model reaches a tenant's own components, which no boot-time tool names. `true`\n * names it `ui__show`.\n */\n showTool?: boolean | string;\n /** Text prepended to the show tool's description. */\n showInstructions?: string;\n /** Roles allowed to call the tools. Undefined → the roles policy default. */\n roles?: string[];\n /** Override the generated presentation per component (or per tree / show tool name). */\n presentation?: (component: string) => ToolPresentation | undefined;\n}\n\ntype ResolverOption = Type<GenuiCatalogResolver> | GenuiCatalogResolver;\n\nexport interface AgentGenuiModuleOptions extends AgentGenuiOptions {\n /** Per-request catalogs. A class is instantiated with DI (its dependencies must be global or exported to the root). */\n resolver?: ResolverOption;\n}\n\nexport interface AgentGenuiModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {\n inject?: FactoryProvider['inject'];\n useFactory: (...deps: any[]) => AgentGenuiOptions | Promise<AgentGenuiOptions>;\n /** Per-request catalogs. A class resolves its dependencies from `imports`. */\n resolver?: ResolverOption;\n}\n\nfunction resolverProviders(resolver: ResolverOption | undefined): Provider[] {\n if (resolver === undefined) return [];\n return [\n typeof resolver === 'function'\n ? { provide: GenuiCatalogResolver, useClass: resolver }\n : { provide: GenuiCatalogResolver, useValue: resolver },\n ];\n}\n\nfunction toolOptions(\n options: AgentGenuiOptions,\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions {\n const { catalog: _catalog, ...rest } = options;\n return {\n ...rest,\n ...(resolver !== undefined\n ? { resolveCatalog: (scope: GenuiCatalogScope) => resolver.resolve(scope) }\n : {}),\n };\n}\n\nfunction coreProviders(resolver: ResolverOption | undefined): Provider[] {\n return [\n {\n provide: GENUI_CATALOG,\n useFactory: (options: AgentGenuiOptions) => options.catalog ?? defineCatalog([]),\n inject: [GENUI_OPTIONS],\n },\n ...resolverProviders(resolver),\n // The generated tools, registered by the agent module's discovery like any `provideAgentTool`.\n // Built from the injected catalog, so `overrideProvider(GENUI_CATALOG)` changes them too.\n provideAgentTools(\n (options: AgentGenuiOptions, catalog: Catalog, perRequest?: GenuiCatalogResolver) =>\n genuiTools(catalog, toolOptions(options, perRequest)),\n [GENUI_OPTIONS, GENUI_CATALOG, { token: GenuiCatalogResolver, optional: true }],\n ),\n ];\n}\n\nconst EXPORTS = [GENUI_CATALOG, GENUI_OPTIONS];\n\n/**\n * Generative UI for the agent: registers the tools that let the model push catalog components\n * (one `ui__render` tree tool, or `ui__show_<component>` per component, and/or the generic\n * `ui__show`), and makes the catalog\n * injectable. Global, like `AgentModule`; import it once, next to it.\n *\n * ```ts\n * AgentGenuiModule.forRoot({ catalog, mode: 'tree', terminal: true })\n * ```\n */\n@Module({})\nexport class AgentGenuiModule {\n static forRoot(options: AgentGenuiModuleOptions = {}): DynamicModule {\n const { resolver, ...rest } = options;\n return {\n module: AgentGenuiModule,\n global: true,\n providers: [{ provide: GENUI_OPTIONS, useValue: rest }, ...coreProviders(resolver)],\n exports: resolver === undefined ? EXPORTS : [...EXPORTS, GenuiCatalogResolver],\n };\n }\n\n static forRootAsync(options: AgentGenuiModuleAsyncOptions): DynamicModule {\n return {\n module: AgentGenuiModule,\n global: true,\n imports: options.imports ?? [],\n providers: [\n { provide: GENUI_OPTIONS, useFactory: options.useFactory, inject: options.inject ?? [] },\n ...coreProviders(options.resolver),\n ],\n exports: options.resolver === undefined ? EXPORTS : [...EXPORTS, GenuiCatalogResolver],\n };\n }\n}\n","import {\n type FunctionalToolDefinition,\n type ToolHandler,\n type ToolSpec,\n createFunctionalTool,\n} from '@dudousxd/nestjs-agent-core';\nimport type { FactoryProvider, Provider } from '@nestjs/common';\n\n/**\n * Brand stamped onto a functional-tool provider instance so `AiToolDiscoveryService` picks it up\n * when it walks every provider at boot — the declarative alternative to a manual `registry.register`.\n */\nexport const AGENT_TOOL_BRAND = Symbol.for('@dudousxd/nestjs-agent:functional-tool');\n\n/** A tool expressed as data + handler (e.g. from `createExecuteSqlTool`), not an `@AiTool` class. */\nexport interface FunctionalTool {\n spec: ToolSpec;\n handler: ToolHandler;\n}\n\n/** A {@link FunctionalTool} carrying {@link AGENT_TOOL_BRAND} — what a provider resolves to. */\nexport interface BrandedFunctionalTool extends FunctionalTool {\n readonly [AGENT_TOOL_BRAND]: true;\n}\n\nfunction brand(tool: FunctionalTool): BrandedFunctionalTool {\n return { [AGENT_TOOL_BRAND]: true, spec: tool.spec, handler: tool.handler };\n}\n\n/** Narrows a provider instance to a branded functional tool for boot-time registration. */\nexport function isBrandedFunctionalTool(value: object): value is BrandedFunctionalTool {\n return AGENT_TOOL_BRAND in value && 'spec' in value && 'handler' in value;\n}\n\n/**\n * Registers a functional tool declaratively — drop the returned provider in a module's `providers`\n * and `AiToolDiscoveryService` auto-registers it at boot. Each call uses a fresh, unique provide\n * token so the same tool can be provided many times without collisions.\n *\n * Two forms: a static tool (`useValue`) or a factory with `inject` for DI-resolved dependencies\n * (`useFactory`). Either way the resolved instance is branded with {@link AGENT_TOOL_BRAND}.\n */\nexport function provideAgentTool(tool: FunctionalTool): Provider;\nexport function provideAgentTool(\n factory: (...deps: never[]) => FunctionalTool,\n inject?: FactoryProvider['inject'],\n): Provider;\nexport function provideAgentTool(\n factoryOrTool: FunctionalTool | ((...deps: never[]) => FunctionalTool),\n inject?: FactoryProvider['inject'],\n): Provider {\n const provide = Symbol('nestjs-agent:functional-tool-instance');\n if (typeof factoryOrTool === 'function') {\n return {\n provide,\n useFactory: (...deps: never[]) => brand(factoryOrTool(...deps)),\n inject: inject ?? [],\n };\n }\n return { provide, useValue: brand(factoryOrTool) };\n}\n\n/**\n * Registers a LIST of functional tools from one factory — for a producer whose tool count is only\n * known once its dependencies resolve (a catalog loaded from config, one tool per entry). The\n * factory's result is branded element by element; `AiToolDiscoveryService` registers each.\n */\nexport function provideAgentTools(\n factory: (...deps: never[]) => readonly FunctionalTool[] | Promise<readonly FunctionalTool[]>,\n inject?: FactoryProvider['inject'],\n): Provider {\n return {\n provide: Symbol('nestjs-agent:functional-tool-list'),\n useFactory: async (...deps: never[]) => (await factory(...deps)).map(brand),\n inject: inject ?? [],\n };\n}\n\n/** Author a functional tool with inferred Standard Schema input and domain output. */\nexport const defineTool = createFunctionalTool;\nexport type { FunctionalToolDefinition };\n","/**\n * `@dudousxd/nestjs-agent/genui` — generative UI for NestJS: {@link AgentGenuiModule} registers the\n * tools that push catalog components, `GENUI_CATALOG` / `@InjectGenuiCatalog()` expose the catalog,\n * and {@link GenuiCatalogResolver} serves per-request (per-tenant) catalogs. The catalog itself —\n * `defineComponent`, `defineCatalog`, validation, text fallbacks — is re-exported from\n * `@dudousxd/nestjs-agent-core/genui`, the isomorphic entry a browser imports too.\n */\nexport {\n AgentGenuiModule,\n type AgentGenuiModuleAsyncOptions,\n type AgentGenuiModuleOptions,\n type AgentGenuiOptions,\n GENUI_CATALOG,\n GENUI_OPTIONS,\n GenuiCatalogResolver,\n InjectGenuiCatalog,\n} from './agent-genui.module.js';\nexport * from '@dudousxd/nestjs-agent-core/genui';\n"],"mappings":";;;;AASA,SAASA,eAAeC,kBAAkB;AAC1C,SAGEC,QACAC,cAIK;;;AClBP,SAIEC,4BACK;AAOA,IAAMC,mBAAmBC,uBAAOC,IAAI,wCAAA;AAa3C,SAASC,MAAMC,MAAoB;AACjC,SAAO;IAAE,CAACJ,gBAAAA,GAAmB;IAAMK,MAAMD,KAAKC;IAAMC,SAASF,KAAKE;EAAQ;AAC5E;AAFSH;AA0CF,SAASI,kBACdC,SACAC,QAAkC;AAElC,SAAO;IACLC,SAASC,uBAAO,mCAAA;IAChBC,YAAY,iCAAUC,UAAmB,MAAML,QAAAA,GAAWK,IAAAA,GAAOC,IAAIC,KAAAA,GAAzD;IACZN,QAAQA,UAAU,CAAA;EACpB;AACF;AATgBF;;;;;;;;;;;;;;;;;AD7CT,IAAMS,gBAAgBC,uBAAOC,IAAI,sCAAA;AAGjC,IAAMC,gBAAgBF,uBAAOC,IAAI,sCAAA;AAGjC,IAAME,qBAAqB,6BAChCC,OAAOL,aAAAA,GADyB;AAa3B,IAAeM,uBAAf,MAAeA;SAAAA;;;AAEtB;AA4DA,SAASC,kBAAkBC,UAAoC;AAC7D,MAAIA,aAAaC,OAAW,QAAO,CAAA;AACnC,SAAO;IACL,OAAOD,aAAa,aAChB;MAAEE,SAASJ;MAAsBK,UAAUH;IAAS,IACpD;MAAEE,SAASJ;MAAsBM,UAAUJ;IAAS;;AAE5D;AAPSD;AAST,SAASM,YACPC,SACAN,UAA0C;AAE1C,QAAM,EAAEO,SAASC,UAAU,GAAGC,KAAAA,IAASH;AACvC,SAAO;IACL,GAAGG;IACH,GAAIT,aAAaC,SACb;MAAES,gBAAgB,wBAACC,UAA6BX,SAASY,QAAQD,KAAAA,GAA/C;IAAsD,IACxE,CAAC;EACP;AACF;AAXSN;AAaT,SAASQ,cAAcb,UAAoC;AACzD,SAAO;IACL;MACEE,SAASV;MACTsB,YAAY,wBAACR,YAA+BA,QAAQC,WAAWQ,cAAc,CAAA,CAAE,GAAnE;MACZC,QAAQ;QAACrB;;IACX;OACGI,kBAAkBC,QAAAA;;;IAGrBiB,kBACE,CAACX,SAA4BC,SAAkBW,eAC7CC,WAAWZ,SAASF,YAAYC,SAASY,UAAAA,CAAAA,GAC3C;MAACvB;MAAeH;MAAe;QAAE4B,OAAOtB;QAAsBuB,UAAU;MAAK;KAAE;;AAGrF;AAhBSR;AAkBT,IAAMS,UAAU;EAAC9B;EAAeG;;AAazB,IAAM4B,mBAAN,MAAMA,kBAAAA;SAAAA;;;EACX,OAAOC,QAAQlB,UAAmC,CAAC,GAAkB;AACnE,UAAM,EAAEN,UAAU,GAAGS,KAAAA,IAASH;AAC9B,WAAO;MACLmB,QAAQF;MACRG,QAAQ;MACRC,WAAW;QAAC;UAAEzB,SAASP;UAAeS,UAAUK;QAAK;WAAMI,cAAcb,QAAAA;;MACzE4B,SAAS5B,aAAaC,SAAYqB,UAAU;WAAIA;QAASxB;;IAC3D;EACF;EAEA,OAAO+B,aAAavB,SAAsD;AACxE,WAAO;MACLmB,QAAQF;MACRG,QAAQ;MACRI,SAASxB,QAAQwB,WAAW,CAAA;MAC5BH,WAAW;QACT;UAAEzB,SAASP;UAAemB,YAAYR,QAAQQ;UAAYE,QAAQV,QAAQU,UAAU,CAAA;QAAG;WACpFH,cAAcP,QAAQN,QAAQ;;MAEnC4B,SAAStB,QAAQN,aAAaC,SAAYqB,UAAU;WAAIA;QAASxB;;IACnE;EACF;AACF;;;;;;AElKA,cAAc;","names":["defineCatalog","genuiTools","Inject","Module","createFunctionalTool","AGENT_TOOL_BRAND","Symbol","for","brand","tool","spec","handler","provideAgentTools","factory","inject","provide","Symbol","useFactory","deps","map","brand","GENUI_CATALOG","Symbol","for","GENUI_OPTIONS","InjectGenuiCatalog","Inject","GenuiCatalogResolver","resolverProviders","resolver","undefined","provide","useClass","useValue","toolOptions","options","catalog","_catalog","rest","resolveCatalog","scope","resolve","coreProviders","useFactory","defineCatalog","inject","provideAgentTools","perRequest","genuiTools","token","optional","EXPORTS","AgentGenuiModule","forRoot","module","global","providers","exports","forRootAsync","imports"]}
|
package/dist/index.cjs
CHANGED
|
@@ -53,6 +53,7 @@ __export(index_exports, {
|
|
|
53
53
|
MemoriesController: () => MemoriesController,
|
|
54
54
|
MessagesController: () => MessagesController,
|
|
55
55
|
ModelsController: () => ModelsController,
|
|
56
|
+
NO_USER_MESSAGE_CODE: () => NO_USER_MESSAGE_CODE,
|
|
56
57
|
QueueController: () => QueueController,
|
|
57
58
|
RunNotActiveException: () => RunNotActiveException,
|
|
58
59
|
SKILL_METADATA: () => SKILL_METADATA,
|
|
@@ -749,9 +750,13 @@ var ActionProposalService = class {
|
|
|
749
750
|
/** The words a text decision is made of, and what the agent answers — English unless configured. */
|
|
750
751
|
vocabulary;
|
|
751
752
|
replies;
|
|
753
|
+
hasCapability() {
|
|
754
|
+
const store = this.store;
|
|
755
|
+
return typeof store.getThreadActionProposalScope === "function" && typeof store.listActionProposals === "function";
|
|
756
|
+
}
|
|
752
757
|
capability() {
|
|
753
758
|
const store = this.store;
|
|
754
|
-
if (
|
|
759
|
+
if (!this.hasCapability()) throw new import_common3.NotImplementedException("Action proposals are unavailable");
|
|
755
760
|
return store;
|
|
756
761
|
}
|
|
757
762
|
async scope(threadId, actor) {
|
|
@@ -767,7 +772,16 @@ var ActionProposalService = class {
|
|
|
767
772
|
requesterRef: proposal.actorRef
|
|
768
773
|
});
|
|
769
774
|
}
|
|
775
|
+
/**
|
|
776
|
+
* One page of a thread's proposals this actor may see. A store without the proposal capability
|
|
777
|
+
* can only run blocking approvals, so a thread there has no proposals: an empty, final page rather
|
|
778
|
+
* than `501` — a client that lists by default (React's `useAgentChat`) needs no flag. Deciding one
|
|
779
|
+
* still answers `501`.
|
|
780
|
+
*/
|
|
770
781
|
async listPage(threadId, actor, query = {}) {
|
|
782
|
+
if (!this.hasCapability()) return {
|
|
783
|
+
items: []
|
|
784
|
+
};
|
|
771
785
|
const scope = await this.scope(threadId, actor);
|
|
772
786
|
const rows = await this.capability().listActionProposals(scope, {
|
|
773
787
|
limit: 1e3,
|
|
@@ -1439,6 +1453,30 @@ function _ts_param4(paramIndex, decorator) {
|
|
|
1439
1453
|
};
|
|
1440
1454
|
}
|
|
1441
1455
|
__name(_ts_param4, "_ts_param");
|
|
1456
|
+
var NO_USER_MESSAGE_CODE = "no_user_message";
|
|
1457
|
+
function sendableParams(params) {
|
|
1458
|
+
const message = params.message;
|
|
1459
|
+
if (message !== void 0 && message !== null && typeof message !== "string") {
|
|
1460
|
+
throw new import_common6.BadRequestException({
|
|
1461
|
+
statusCode: 400,
|
|
1462
|
+
code: "invalid_message",
|
|
1463
|
+
message: "message must be a string"
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
const text = typeof message === "string" ? message : "";
|
|
1467
|
+
if (text.trim().length === 0 && (params.attachments?.length ?? 0) === 0 && params.regenerate !== true) {
|
|
1468
|
+
throw new import_common6.BadRequestException({
|
|
1469
|
+
statusCode: 400,
|
|
1470
|
+
code: NO_USER_MESSAGE_CODE,
|
|
1471
|
+
message: "nothing to answer: send a non-empty message, an attachment, or regenerate"
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
return text === message ? params : {
|
|
1475
|
+
...params,
|
|
1476
|
+
message: text
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
__name(sendableParams, "sendableParams");
|
|
1442
1480
|
var AgentService = class {
|
|
1443
1481
|
static {
|
|
1444
1482
|
__name(this, "AgentService");
|
|
@@ -1501,12 +1539,13 @@ var AgentService = class {
|
|
|
1501
1539
|
}
|
|
1502
1540
|
/**
|
|
1503
1541
|
* The proposals of a thread this actor may see — the thread's own actor, or one the policy lets
|
|
1504
|
-
* decide them; what `GET <base>/threads/:threadId/action-proposals` serves (its first page).
|
|
1505
|
-
*
|
|
1542
|
+
* decide them; what `GET <base>/threads/:threadId/action-proposals` serves (its first page).
|
|
1543
|
+
* Without independent approvals (the default blocking mode) there are none, so the read answers an
|
|
1544
|
+
* empty list rather than refusing; deciding one still refuses.
|
|
1506
1545
|
*/
|
|
1507
1546
|
async listActionProposals(actor, threadId) {
|
|
1508
1547
|
if (this.options?.actionApprovalMode !== "independent" || !this.proposals) {
|
|
1509
|
-
|
|
1548
|
+
return [];
|
|
1510
1549
|
}
|
|
1511
1550
|
return this.proposals.list(threadId, actor);
|
|
1512
1551
|
}
|
|
@@ -1706,7 +1745,8 @@ var AgentService = class {
|
|
|
1706
1745
|
* Send a message: start a turn, or — when its thread already has one running — queue the message
|
|
1707
1746
|
* to run after it (see {@link ChatSendMode}). What `POST <base>/chat` calls.
|
|
1708
1747
|
*/
|
|
1709
|
-
async send(
|
|
1748
|
+
async send(claimed, sendOptions = {}) {
|
|
1749
|
+
const params = sendableParams(claimed);
|
|
1710
1750
|
if (sendOptions.textDecisions !== false && this.options?.actionApprovalMode === "independent" && params.threadId !== void 0 && params.regenerate !== true && this.proposals) {
|
|
1711
1751
|
const decision = await this.proposals.handleTextDecision(params.threadId, params.actor, params.message);
|
|
1712
1752
|
if ("proposalDecision" in decision) return decision;
|
|
@@ -5500,6 +5540,11 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
5500
5540
|
* running it. A cancelled id is dropped once the run settles, so the set tracks live runs only.
|
|
5501
5541
|
*/
|
|
5502
5542
|
cancelled = /* @__PURE__ */ new Set();
|
|
5543
|
+
/**
|
|
5544
|
+
* Aborted by {@link cancel}: what cuts short the model call or tool a stopped run is in (the
|
|
5545
|
+
* loop's `abortSignal` hook). Keyed like {@link cancelled}, and dropped with it.
|
|
5546
|
+
*/
|
|
5547
|
+
aborts = /* @__PURE__ */ new Map();
|
|
5503
5548
|
/** Top-level runs this process is running now — what {@link isRunActive} answers from. */
|
|
5504
5549
|
live = /* @__PURE__ */ new Set();
|
|
5505
5550
|
constructor(factory, store, queue) {
|
|
@@ -5569,7 +5614,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
5569
5614
|
await (0, import_nestjs_agent_core31.releaseThreadRun)(this.store, input.threadId, runId);
|
|
5570
5615
|
await writer.fail((0, import_nestjs_agent_core31.streamFailure)(error));
|
|
5571
5616
|
}).finally(() => {
|
|
5572
|
-
this.
|
|
5617
|
+
this.forgetCancel(runId);
|
|
5573
5618
|
this.live.delete(runId);
|
|
5574
5619
|
});
|
|
5575
5620
|
return {
|
|
@@ -5588,8 +5633,10 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
5588
5633
|
* Ask a run to stop, and settle whatever it was parked on.
|
|
5589
5634
|
*
|
|
5590
5635
|
* The loop observes the request at its next safe point (between steps, before the turn's tools) and
|
|
5591
|
-
* unwinds from there
|
|
5592
|
-
*
|
|
5636
|
+
* unwinds from there. What the run is in right now is aborted (its `abortSignal`): the model call
|
|
5637
|
+
* streaming the answer ends at once and the step it was writing is not persisted, and a tool that
|
|
5638
|
+
* passes `ctx.abortSignal` on is cut short and recorded failed; a tool that ignores the signal is
|
|
5639
|
+
* left to finish, and its result is recorded exactly as it would have been. What this cannot wait for is a turn parked on a human: that wait
|
|
5593
5640
|
* is a promise nobody is going to resolve, so it is REJECTED here with the same
|
|
5594
5641
|
* {@link RunCancelledError} the loop would have thrown, and the run unwinds through the identical
|
|
5595
5642
|
* path.
|
|
@@ -5600,6 +5647,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
5600
5647
|
*/
|
|
5601
5648
|
async cancel(runId) {
|
|
5602
5649
|
this.cancelled.add(runId);
|
|
5650
|
+
this.aborts.get(runId)?.abort(new import_nestjs_agent_core31.RunCancelledError());
|
|
5603
5651
|
for (const [key, waiter] of this.pending) {
|
|
5604
5652
|
if (key.startsWith(`${runId}:`)) {
|
|
5605
5653
|
this.pending.delete(key);
|
|
@@ -5608,6 +5656,20 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
5608
5656
|
}
|
|
5609
5657
|
await Promise.resolve();
|
|
5610
5658
|
}
|
|
5659
|
+
/** The signal {@link cancel} aborts for `runId` — one per run, shared by its awaited delegates. */
|
|
5660
|
+
abortSignalFor(runId) {
|
|
5661
|
+
let controller = this.aborts.get(runId);
|
|
5662
|
+
if (controller === void 0) {
|
|
5663
|
+
controller = new AbortController();
|
|
5664
|
+
this.aborts.set(runId, controller);
|
|
5665
|
+
}
|
|
5666
|
+
return controller.signal;
|
|
5667
|
+
}
|
|
5668
|
+
/** Drop a settled run's Stop: its flag and its abort controller. */
|
|
5669
|
+
forgetCancel(runId) {
|
|
5670
|
+
this.cancelled.delete(runId);
|
|
5671
|
+
this.aborts.delete(runId);
|
|
5672
|
+
}
|
|
5611
5673
|
/**
|
|
5612
5674
|
* The single place a cancelled run's state is settled: recorded as its own terminal (never
|
|
5613
5675
|
* `failed` — a user pressing Stop must not land in someone's error rate), the thread released, and
|
|
@@ -5727,6 +5789,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
5727
5789
|
step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
|
|
5728
5790
|
parallel: import_nestjs_agent_core31.settleAll,
|
|
5729
5791
|
cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId), "cancelled"),
|
|
5792
|
+
abortSignal: this.abortSignalFor(runId),
|
|
5730
5793
|
runAgent: /* @__PURE__ */ __name((agentName, task) => this.runNested({
|
|
5731
5794
|
agentName,
|
|
5732
5795
|
task,
|
|
@@ -5778,6 +5841,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
5778
5841
|
step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
|
|
5779
5842
|
parallel: import_nestjs_agent_core31.settleAll,
|
|
5780
5843
|
cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId), "cancelled"),
|
|
5844
|
+
abortSignal: this.abortSignalFor(runId),
|
|
5781
5845
|
runAgent: /* @__PURE__ */ __name((childName, childTask) => this.runNested({
|
|
5782
5846
|
agentName: childName,
|
|
5783
5847
|
task: childTask,
|
|
@@ -5853,7 +5917,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
5853
5917
|
}
|
|
5854
5918
|
});
|
|
5855
5919
|
}).finally(async () => {
|
|
5856
|
-
this.
|
|
5920
|
+
this.forgetCancel(runId);
|
|
5857
5921
|
await this.store.setActiveStream(subThread.id, null);
|
|
5858
5922
|
});
|
|
5859
5923
|
return {
|
|
@@ -5885,6 +5949,8 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
5885
5949
|
// A child stops when it is cancelled OR when the run a human is actually watching is: the
|
|
5886
5950
|
// canceller names the top-level run, which is the only id that ever left the server.
|
|
5887
5951
|
cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId) || this.cancelled.has(sinkRunId), "cancelled"),
|
|
5952
|
+
// Aborted by a Stop on the run the human is watching, which is the id a canceller names.
|
|
5953
|
+
abortSignal: this.abortSignalFor(sinkRunId),
|
|
5888
5954
|
runAgent: /* @__PURE__ */ __name((childName, childTask) => this.runNested({
|
|
5889
5955
|
agentName: childName,
|
|
5890
5956
|
task: childTask,
|
|
@@ -6535,7 +6601,7 @@ var AgUiRunHandler = class {
|
|
|
6535
6601
|
}
|
|
6536
6602
|
const turn = (0, import_ag_ui.readUserTurn)(input.messages);
|
|
6537
6603
|
if (turn === null) {
|
|
6538
|
-
throw invalid(
|
|
6604
|
+
throw invalid(NO_USER_MESSAGE_CODE, "messages carries no user message to answer");
|
|
6539
6605
|
}
|
|
6540
6606
|
warnings.push(...turn.dropped);
|
|
6541
6607
|
const owner = await this.agent.threadOwner(input.threadId);
|
|
@@ -6561,8 +6627,8 @@ var AgUiRunHandler = class {
|
|
|
6561
6627
|
}
|
|
6562
6628
|
}
|
|
6563
6629
|
const refs = await this.stage(actor, turn.media, warnings, turn.staged);
|
|
6564
|
-
if (turn.text.trim().length === 0 && refs.length === 0) {
|
|
6565
|
-
throw invalid(
|
|
6630
|
+
if (turn.text.trim().length === 0 && refs.length === 0 && forwarded.regenerate !== true) {
|
|
6631
|
+
throw invalid(NO_USER_MESSAGE_CODE, "the user message to answer is empty");
|
|
6566
6632
|
}
|
|
6567
6633
|
const context = (0, import_ag_ui.readContext)(input.context);
|
|
6568
6634
|
const pageContext = forwarded.pageContext !== void 0 || context !== void 0 ? {
|
|
@@ -6952,6 +7018,7 @@ __reExport(index_exports, require("@dudousxd/nestjs-agent-core"), module.exports
|
|
|
6952
7018
|
MemoriesController,
|
|
6953
7019
|
MessagesController,
|
|
6954
7020
|
ModelsController,
|
|
7021
|
+
NO_USER_MESSAGE_CODE,
|
|
6955
7022
|
QueueController,
|
|
6956
7023
|
RunNotActiveException,
|
|
6957
7024
|
SKILL_METADATA,
|