@dudousxd/nestjs-agent 1.33.0 → 1.35.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/vite/index.ts","../../src/genui/kit.ts","../../src/genui/index.ts","../../src/genui/agent-genui.module.ts","../../src/functional-tool.ts","../../src/genui/agent-genui.token.ts"],"sourcesContent":["/**\n * `@dudousxd/nestjs-agent/vite` — `genuiSandboxKit()`, the Vite plugin that puts the app's design\n * system (its styles, its components, its providers) inside the sandbox, whatever the stack:\n *\n * ```ts\n * // vite.config.ts (the SPA that talks to the agent)\n * import { genuiSandboxKit } from '@dudousxd/nestjs-agent/vite'\n * export default defineConfig({\n * plugins: [react(), genuiSandboxKit({ styles: 'src/index.css', components: 'src/components/ui' })],\n * })\n * ```\n *\n * Then `AgentGenuiModule.forRoot({ sandbox: { kit: true } })` finds what it built: the descriptor\n * the dev server writes (`.genui/sandbox-kit.json`) in dev, the Vite manifest in production (see\n * `AgentGenuiOptions.sandboxKit`).\n */\nimport {\n type GenuiSandboxKitApi,\n type GenuiSandboxKitOptions,\n type GenuiSandboxKitPlugin,\n SANDBOX_KIT_DEV_PREFIX,\n SANDBOX_KIT_MANIFEST_KEYS,\n SANDBOX_KIT_UPDATE_EVENT,\n createGenuiSandboxKitPlugin,\n} from '@dudousxd/nestjs-agent-core/genui/kit';\n\n/**\n * Where the dev descriptor is written, relative to the Vite root — and where the server reads it,\n * relative to its working directory (run both from the project root, or point\n * `sandboxKit.descriptor` at it). Add `.genui/` to `.gitignore`.\n */\nexport const NEST_SANDBOX_KIT_DESCRIPTOR = '.genui/sandbox-kit.json';\n\n/**\n * The sandbox kit plugin: `styles` (the app's style entries — default, the stylesheets among its\n * Vite entrypoints or `index.html`), `components` (modules or globs exporting React components —\n * default, the first `components/ui` folder), `wrapper` (a module whose default export wraps the\n * model's App). See {@link GenuiSandboxKitOptions}.\n */\nexport function genuiSandboxKit(options: GenuiSandboxKitOptions = {}): GenuiSandboxKitPlugin {\n return createGenuiSandboxKitPlugin(options, {\n descriptor: NEST_SANDBOX_KIT_DESCRIPTOR,\n rendererImport: /@dudousxd\\/nestjs-agent-react/,\n });\n}\n\nexport {\n type GenuiSandboxKitApi,\n type GenuiSandboxKitOptions,\n type GenuiSandboxKitPlugin,\n SANDBOX_KIT_DEV_PREFIX,\n SANDBOX_KIT_MANIFEST_KEYS,\n SANDBOX_KIT_UPDATE_EVENT,\n};\n","/**\n * The sandbox kit in a Nest app. No Vite runs in the Nest process, so the kit is found in files:\n * the descriptor `genuiSandboxKit()` (`@dudousxd/nestjs-agent/vite`) writes while the dev server\n * runs, and in production the Vite manifest the build wrote (`genui-sandbox-kit.json` and the assets\n * it names). Node-only: loaded by {@link AgentGenuiModule} only when a sandbox is configured.\n */\nimport { resolve } from 'node:path';\nimport {\n type SandboxKitDiscovery,\n sandboxKitDescriptorPath,\n sandboxKitDiscovery,\n} from '@dudousxd/nestjs-agent-core/genui/kit';\nimport { NEST_SANDBOX_KIT_DESCRIPTOR } from '../vite/index.js';\nimport type { AgentGenuiSandboxKitOptions } from './agent-genui.module.js';\n\n/** Where the production Vite manifest is looked for by default, and the directory it is relative to. */\nexport const NEST_SANDBOX_KIT_MANIFEST = Object.freeze({\n file: 'public/.vite/manifest.json',\n outDir: 'public',\n});\n\n/**\n * Find the kit for `AgentGenuiModule.forRoot({ sandbox: { kit: true } })` — a named kit's\n * (`genuiSandboxKit({ name })`, `sandbox: { kit: true, kitName }`) with `name`.\n */\nexport function nestSandboxKitDiscovery(\n options: AgentGenuiSandboxKitOptions = {},\n name?: string,\n): SandboxKitDiscovery {\n const manifest = options.manifest ?? NEST_SANDBOX_KIT_MANIFEST;\n return sandboxKitDiscovery({\n root: resolve(options.root ?? process.cwd()),\n ...(name !== undefined ? { name } : {}),\n descriptor: sandboxKitDescriptorPath(options.descriptor ?? NEST_SANDBOX_KIT_DESCRIPTOR, name),\n ...(manifest !== false ? { manifest: { file: manifest.file, outDir: manifest.outDir } } : {}),\n ...(options.kitUrl !== undefined ? { kitUrl: options.kitUrl } : {}),\n ...(options.cssUrl !== undefined ? { cssUrl: options.cssUrl } : {}),\n ...(options.tailwindUrl !== undefined ? { tailwindUrl: options.tailwindUrl } : {}),\n ...(options.production !== undefined ? { production: options.production } : {}),\n });\n}\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 AGENT_GENUI,\n AgentGenui,\n AgentGenuiModule,\n type AgentGenuiModuleAsyncOptions,\n type AgentGenuiModuleOptions,\n type AgentGenuiOptions,\n type AgentGenuiSandboxKitOptions,\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 GenuiAbility,\n GenuiCatalogScope,\n GenuiChannels,\n GenuiStreaming,\n GenuiToolsOptions,\n SandboxClientConfig,\n TreeLimits,\n TreeSchemaMode,\n} from '@dudousxd/nestjs-agent-core/genui';\nimport {\n type DefineSandboxOptions,\n type SandboxDefinition,\n assertGenuiChannels,\n defineCatalog,\n defineSandbox,\n genuiTools,\n sandboxPolicyOf,\n} 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';\nimport { AGENT_GENUI, AgentGenui } from './agent-genui.token.js';\n\nexport { AGENT_GENUI, AgentGenui } from './agent-genui.token.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/** The sandbox and channels as boot resolved them (kit, Tailwind and theme found). Internal. */\nconst GENUI_RESOLVED = Symbol.for('@dudousxd/nestjs-agent:genui-resolved');\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 /**\n * Tree mode: components that ALSO get a flat tool whose input IS their props —\n * `componentTools: ['Sandbox']` adds `ui__sandbox`, so a model writing a big component on its own\n * has no `{ type, props }` envelope to leave out.\n */\n componentTools?: readonly string[];\n /** Tool-name prefix for `componentTools`. Default `ui__` (`Sandbox` → `ui__sandbox`). */\n componentToolPrefix?: string;\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 /**\n * The authorization ability the UI tools declare (`ToolSpec.ability`), for an ability-aware\n * authorizer such as `authzToolAuthorizer`, which denies a tool with none. A string for every\n * tool; a map by tool name (`{ ui__render: 'genui.render', ui__sandbox: 'genui.sandbox' }`, a tool\n * left out declares none); or a function of `{ name, component }`. The authorizer decides.\n */\n ability?: GenuiAbility;\n /** Override the generated presentation per component (or per tree / show tool name). */\n presentation?: (component: string) => ToolPresentation | undefined;\n /**\n * Add the sandbox component (`Sandbox`): the model may write HTML, CSS and JS for a one-off\n * interactive answer when no catalog component fits. `true` for the defaults (no network), or\n * the {@link DefineSandboxOptions} (a policy listing origins, extra instructions). Off by default.\n * The browser's catalog should carry the same definition (`defineSandbox(...)` in the shared\n * catalog file) so the renderer enforces the same policy.\n *\n * `theme` (default on) and `kit` put the app's design system in the frame: `kit: true` turns on\n * whatever `genuiSandboxKit()` built (styles, Tailwind, components, wrapper, docs), found through\n * `sandboxKit`: the descriptor\n * `genuiSandboxKit()` (`@dudousxd/nestjs-agent/vite`) writes in dev, the Vite manifest in\n * production — and `GET <base>/config` tells the renderer where the assets are.\n */\n sandbox?: boolean | DefineSandboxOptions;\n /**\n * Per-channel generative UI: each entry sets the mode, streaming, sandbox and rendering of one\n * channel (`web`, `mobile`, `whatsapp`, `telegram`, `email`, or `default` for the rest), over the\n * top-level options. A text channel (`@dudousxd/nestjs-agent-channels`) configured here draws the\n * components natively (reply buttons, lists, images). Omitted → every channel is served by the\n * top-level options, as before.\n */\n channels?: GenuiChannels;\n /**\n * Where the sandbox kit is found (with `sandbox: { kit: true }` or the theme's names). No Vite\n * runs in the Nest process, so: the descriptor the dev plugin writes, or the production Vite\n * manifest — in production the manifest first, otherwise whichever was written last.\n */\n sandboxKit?: AgentGenuiSandboxKitOptions;\n}\n\n/** {@link AgentGenuiOptions.sandboxKit}. Relative paths resolve against `root`. */\nexport interface AgentGenuiSandboxKitOptions {\n /** Default `process.cwd()`. */\n root?: string;\n /**\n * The dev descriptor `genuiSandboxKit()` writes. Default `.genui/sandbox-kit.json` — for a named\n * kit (`genuiSandboxKit({ name })`, picked with `kitName`), `.genui/sandbox-kit.<name>.json`.\n */\n descriptor?: string;\n /**\n * The production Vite manifest, and the directory its `file`s are relative to. Default\n * `{ file: 'public/.vite/manifest.json', outDir: 'public' }`; `false` → none.\n */\n manifest?: { file: string; outDir: string } | false;\n /** An explicit kit url (an SPA served from elsewhere), over what is found. */\n kitUrl?: string;\n /** An explicit url of the compiled styles, over what is found (the same SPA case). */\n cssUrl?: string;\n /** An explicit url of the Tailwind browser runtime, over what is found (the same SPA case). */\n tailwindUrl?: string;\n /** Read the manifest first (else the freshest of the two). Default: `NODE_ENV === 'production'`. */\n production?: boolean;\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\n/** The sandbox and channels with the kit and theme names found ({@link GENUI_RESOLVED}). */\ninterface ResolvedGenui {\n sandbox?: boolean | DefineSandboxOptions;\n /** A kit sandbox the catalog itself defines, resolved (under its own name). */\n catalogSandbox?: DefineSandboxOptions;\n channels?: GenuiChannels;\n sandboxClient?: () => SandboxClientConfig;\n}\n\n/** What every configured sandbox (top level and channels) needs from the browser, together. */\nfunction mergeSandboxClients(clients: Array<() => SandboxClientConfig>): SandboxClientConfig {\n const merged: SandboxClientConfig = { theme: false };\n for (const client of clients) {\n const one = client();\n merged.theme ||= one.theme;\n if (one.name !== undefined && merged.kit === undefined && one.kit !== undefined)\n merged.name = one.name;\n if (one.kit !== undefined) merged.kit ??= one.kit;\n if (one.css !== undefined) merged.css ??= one.css;\n if (one.tailwind !== undefined) merged.tailwind ??= one.tailwind;\n }\n return merged;\n}\n\n/** Resolve the sandbox (top level and per channel) against the kit discovery. */\nasync function resolveGenui(options: AgentGenuiOptions): Promise<ResolvedGenui> {\n const { sandbox: asked, channels: askedChannels } = options;\n assertGenuiChannels(askedChannels);\n // A sandbox's kit (styles, components, wrapper) and theme names are found through the app's Vite output.\n const clients: Array<() => SandboxClientConfig> = [];\n const discoveries = new Map<\n string,\n import('@dudousxd/nestjs-agent-core/genui/kit').SandboxKitDiscovery\n >();\n const resolveSandbox = async (\n value: boolean | DefineSandboxOptions | undefined,\n ): Promise<boolean | DefineSandboxOptions | undefined> => {\n if (value === undefined || value === false) return value;\n // Node-only, and only with a sandbox: loaded when one is configured.\n const [{ nestSandboxKitDiscovery }, { resolveSandboxServer }] = await Promise.all([\n import('./kit.js'),\n import('@dudousxd/nestjs-agent-core/genui/kit'),\n ]);\n const kitName = value === true ? undefined : value.kitName;\n let discovery = discoveries.get(kitName ?? '');\n if (discovery === undefined) {\n discovery = nestSandboxKitDiscovery(options.sandboxKit, kitName);\n discoveries.set(kitName ?? '', discovery);\n }\n const resolved = resolveSandboxServer(value, discovery);\n clients.push(resolved.client);\n return resolved.define;\n };\n const sandbox = await resolveSandbox(asked);\n // A kit sandbox defined in the (shared) catalog itself: found the same way, and put\n // back under its own name, so the browser's copy of the catalog validates what the model writes.\n const own = options.catalog?.components.find((each) => sandboxPolicyOf(each) !== undefined) as\n | SandboxDefinition\n | undefined;\n const ownOptions =\n asked === undefined && own?.sandboxOptions !== undefined && own.sandboxView?.kit === true\n ? await resolveSandbox({ ...own.sandboxOptions, name: own.name })\n : undefined;\n let channels: GenuiChannels | undefined;\n if (askedChannels !== undefined) {\n channels = {};\n for (const [name, entry] of Object.entries(askedChannels)) {\n if (entry === undefined) continue;\n const own = await resolveSandbox(entry.sandbox);\n channels[name] = { ...entry, ...(own !== undefined ? { sandbox: own } : {}) };\n }\n }\n return {\n ...(sandbox !== undefined ? { sandbox } : {}),\n ...(typeof ownOptions === 'object' ? { catalogSandbox: ownOptions } : {}),\n ...(channels !== undefined ? { channels } : {}),\n ...(clients.length > 0 ? { sandboxClient: () => mergeSandboxClients(clients) } : {}),\n };\n}\n\nfunction perRequest(\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions['resolveCatalog'] | undefined {\n return resolver === undefined ? undefined : (scope: GenuiCatalogScope) => resolver.resolve(scope);\n}\n\nfunction toolOptions(\n options: AgentGenuiOptions,\n resolved: ResolvedGenui,\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions {\n const {\n catalog: _catalog,\n sandbox: _sandbox,\n channels: _channels,\n sandboxKit: _sandboxKit,\n ...rest\n } = options;\n const resolveCatalog = perRequest(resolver);\n return {\n ...rest,\n ...(resolved.channels !== undefined ? { channels: resolved.channels } : {}),\n ...(resolved.sandbox !== undefined ? { sandbox: resolved.sandbox } : {}),\n ...(resolveCatalog !== undefined ? { resolveCatalog } : {}),\n };\n}\n\n/** The configured catalog, with the sandbox component added when `sandbox` asks for it. */\nfunction withSandbox(options: AgentGenuiOptions, resolved: ResolvedGenui): Catalog {\n const base = options.catalog ?? defineCatalog([]);\n const { sandbox, catalogSandbox } = resolved;\n if (sandbox === undefined || sandbox === false)\n return catalogSandbox !== undefined ? base.extend([defineSandbox(catalogSandbox)]) : base;\n return base.extend([defineSandbox(sandbox === true ? {} : sandbox)]);\n}\n\nfunction coreProviders(resolver: ResolverOption | undefined): Provider[] {\n return [\n {\n provide: GENUI_RESOLVED,\n useFactory: (options: AgentGenuiOptions) => resolveGenui(options),\n inject: [GENUI_OPTIONS],\n },\n {\n provide: GENUI_CATALOG,\n useFactory: (options: AgentGenuiOptions, resolved: ResolvedGenui) =>\n withSandbox(options, resolved),\n inject: [GENUI_OPTIONS, GENUI_RESOLVED],\n },\n {\n provide: AGENT_GENUI,\n useFactory: (\n options: AgentGenuiOptions,\n catalog: Catalog,\n resolved: ResolvedGenui,\n resolverInstance?: GenuiCatalogResolver,\n ) =>\n new AgentGenui(\n catalog,\n perRequest(resolverInstance),\n resolved.channels,\n {\n ...(options.mode !== undefined ? { mode: options.mode } : {}),\n ...(options.streaming !== undefined ? { streaming: options.streaming } : {}),\n ...(resolved.sandbox !== undefined ? { sandbox: resolved.sandbox } : {}),\n },\n resolved.sandboxClient,\n ),\n inject: [\n GENUI_OPTIONS,\n GENUI_CATALOG,\n GENUI_RESOLVED,\n { token: GenuiCatalogResolver, optional: true },\n ],\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 (\n options: AgentGenuiOptions,\n catalog: Catalog,\n resolved: ResolvedGenui,\n perRequestResolver?: GenuiCatalogResolver,\n ) => genuiTools(catalog, toolOptions(options, resolved, perRequestResolver)),\n [\n GENUI_OPTIONS,\n GENUI_CATALOG,\n GENUI_RESOLVED,\n { token: GenuiCatalogResolver, optional: true },\n ],\n ),\n ];\n}\n\nconst EXPORTS = [GENUI_CATALOG, GENUI_OPTIONS, AGENT_GENUI];\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","import type {\n Catalog,\n GenuiCatalogScope,\n GenuiChannelBase,\n GenuiChannels,\n SandboxClientConfig,\n} from '@dudousxd/nestjs-agent-core/genui';\n\n/**\n * The app's genui setup ({@link AgentGenui}): the catalog, the per-channel options and what the\n * sandbox renderer is told — what the text channels (`@dudousxd/nestjs-agent-channels`) and\n * `GET <base>/config` read.\n */\nexport const AGENT_GENUI = Symbol.for('@dudousxd/nestjs-agent:genui');\n\n/**\n * The app's genui setup, bound to {@link AGENT_GENUI}: what a text channel draws with\n * (`catalog`, `channels`, `base`) and what the sandbox renderer is told (`sandboxClient`).\n */\nexport class AgentGenui {\n constructor(\n readonly catalog: Catalog,\n readonly resolveCatalog?: (scope: GenuiCatalogScope) => Catalog | Promise<Catalog>,\n /** `AgentGenuiModule.forRoot({ channels })`, when configured. */\n readonly channels?: GenuiChannels,\n /** The top-level options a channel falls back to. */\n readonly base: GenuiChannelBase = {},\n /** What the sandbox renderer is told, when a sandbox is configured. */\n readonly sandboxClient?: () => SandboxClientConfig,\n ) {}\n}\n"],"mappings":"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","names":["NEST_SANDBOX_KIT_DESCRIPTOR","nestSandboxKitDiscovery","options","name","manifest","NEST_SANDBOX_KIT_MANIFEST","sandboxKitDiscovery","root","resolve","process","cwd","undefined","descriptor","sandboxKitDescriptorPath","NEST_SANDBOX_KIT_DESCRIPTOR","file","outDir","kitUrl","cssUrl","tailwindUrl","production","import_kit","Object","freeze","AGENT_TOOL_BRAND","Symbol","for","brand","tool","spec","handler","provideAgentTools","factory","inject","provide","Symbol","useFactory","deps","map","brand","AGENT_GENUI","Symbol","for","AgentGenui","catalog","resolveCatalog","channels","base","sandboxClient","GENUI_CATALOG","Symbol","for","GENUI_OPTIONS","GENUI_RESOLVED","InjectGenuiCatalog","Inject","GenuiCatalogResolver","resolverProviders","resolver","undefined","provide","useClass","useValue","mergeSandboxClients","clients","merged","theme","client","one","name","kit","css","tailwind","resolveGenui","options","sandbox","asked","channels","askedChannels","assertGenuiChannels","discoveries","Map","resolveSandbox","value","nestSandboxKitDiscovery","resolveSandboxServer","Promise","all","kitName","discovery","get","sandboxKit","set","resolved","push","define","own","catalog","components","find","each","sandboxPolicyOf","ownOptions","sandboxOptions","sandboxView","entry","Object","entries","catalogSandbox","length","sandboxClient","perRequest","scope","resolve","toolOptions","_catalog","_sandbox","_channels","_sandboxKit","rest","resolveCatalog","withSandbox","base","defineCatalog","extend","defineSandbox","coreProviders","useFactory","inject","AGENT_GENUI","resolverInstance","AgentGenui","mode","streaming","token","optional","provideAgentTools","perRequestResolver","genuiTools","EXPORTS","AgentGenuiModule","forRoot","module","global","providers","exports","forRootAsync","imports"]}
1
+ {"version":3,"sources":["../../src/vite/index.ts","../../src/genui/kit.ts","../../src/genui/index.ts","../../src/genui/agent-genui.module.ts","../../src/functional-tool.ts","../../src/genui/agent-genui.token.ts"],"sourcesContent":["/**\n * `@dudousxd/nestjs-agent/vite` — `genuiSandboxKit()`, the Vite plugin that puts the app's design\n * system (its styles, its components, its providers) inside the sandbox, whatever the stack:\n *\n * ```ts\n * // vite.config.ts (the SPA that talks to the agent)\n * import { genuiSandboxKit } from '@dudousxd/nestjs-agent/vite'\n * export default defineConfig({\n * plugins: [react(), genuiSandboxKit({ styles: 'src/index.css', components: 'src/components/ui' })],\n * })\n * ```\n *\n * Then `AgentGenuiModule.forRoot({ sandbox: { kit: true } })` finds what it built: the descriptor\n * the dev server writes (`.genui/sandbox-kit.json`) in dev, the Vite manifest in production (see\n * `AgentGenuiOptions.sandboxKit`).\n */\nimport {\n type GenuiSandboxKitApi,\n type GenuiSandboxKitOptions,\n type GenuiSandboxKitPlugin,\n SANDBOX_KIT_DEV_PREFIX,\n SANDBOX_KIT_MANIFEST_KEYS,\n SANDBOX_KIT_UPDATE_EVENT,\n createGenuiSandboxKitPlugin,\n} from '@dudousxd/nestjs-agent-core/genui/kit';\n\n/**\n * Where the dev descriptor is written, relative to the Vite root — and where the server reads it,\n * relative to its working directory (run both from the project root, or point\n * `sandboxKit.descriptor` at it). Add `.genui/` to `.gitignore`.\n */\nexport const NEST_SANDBOX_KIT_DESCRIPTOR = '.genui/sandbox-kit.json';\n\n/**\n * The sandbox kit plugin: `styles` (the app's style entries — default, the stylesheets among its\n * Vite entrypoints or `index.html`), `components` (modules or globs exporting React components —\n * default, the first `components/ui` folder), `wrapper` (a module whose default export wraps the\n * model's App). See {@link GenuiSandboxKitOptions}.\n */\nexport function genuiSandboxKit(options: GenuiSandboxKitOptions = {}): GenuiSandboxKitPlugin {\n return createGenuiSandboxKitPlugin(options, {\n descriptor: NEST_SANDBOX_KIT_DESCRIPTOR,\n rendererImport: /@dudousxd\\/nestjs-agent-react/,\n });\n}\n\nexport {\n type GenuiSandboxKitApi,\n type GenuiSandboxKitOptions,\n type GenuiSandboxKitPlugin,\n SANDBOX_KIT_DEV_PREFIX,\n SANDBOX_KIT_MANIFEST_KEYS,\n SANDBOX_KIT_UPDATE_EVENT,\n};\n","/**\n * The sandbox kit in a Nest app. No Vite runs in the Nest process, so the kit is found in files:\n * the descriptor `genuiSandboxKit()` (`@dudousxd/nestjs-agent/vite`) writes while the dev server\n * runs, and in production the Vite manifest the build wrote (`genui-sandbox-kit.json` and the assets\n * it names). Node-only: loaded by {@link AgentGenuiModule} only when a sandbox is configured.\n */\nimport { resolve } from 'node:path';\nimport {\n type SandboxKitDiscovery,\n sandboxKitDescriptorPath,\n sandboxKitDiscovery,\n} from '@dudousxd/nestjs-agent-core/genui/kit';\nimport { NEST_SANDBOX_KIT_DESCRIPTOR } from '../vite/index.js';\nimport type { AgentGenuiSandboxKitOptions } from './agent-genui.module.js';\n\n/** Where the production Vite manifest is looked for by default, and the directory it is relative to. */\nexport const NEST_SANDBOX_KIT_MANIFEST = Object.freeze({\n file: 'public/.vite/manifest.json',\n outDir: 'public',\n});\n\n/**\n * Find the kit for `AgentGenuiModule.forRoot({ sandbox: { kit: true } })` — a named kit's\n * (`genuiSandboxKit({ name })`, `sandbox: { kit: true, kitName }`) with `name`.\n */\nexport function nestSandboxKitDiscovery(\n options: AgentGenuiSandboxKitOptions = {},\n name?: string,\n): SandboxKitDiscovery {\n const manifest = options.manifest ?? NEST_SANDBOX_KIT_MANIFEST;\n return sandboxKitDiscovery({\n root: resolve(options.root ?? process.cwd()),\n ...(name !== undefined ? { name } : {}),\n descriptor: sandboxKitDescriptorPath(options.descriptor ?? NEST_SANDBOX_KIT_DESCRIPTOR, name),\n ...(manifest !== false ? { manifest: { file: manifest.file, outDir: manifest.outDir } } : {}),\n ...(options.kitUrl !== undefined ? { kitUrl: options.kitUrl } : {}),\n ...(options.cssUrl !== undefined ? { cssUrl: options.cssUrl } : {}),\n ...(options.tailwindUrl !== undefined ? { tailwindUrl: options.tailwindUrl } : {}),\n ...(options.production !== undefined ? { production: options.production } : {}),\n });\n}\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 AGENT_GENUI,\n AgentGenui,\n AgentGenuiModule,\n type AgentGenuiModuleAsyncOptions,\n type AgentGenuiModuleOptions,\n type AgentGenuiOptions,\n type AgentGenuiSandboxKitOptions,\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 GenuiAbility,\n GenuiCatalogScope,\n GenuiChannels,\n GenuiStreaming,\n GenuiTelemetryOptions,\n GenuiToolsOptions,\n SandboxClientConfig,\n TreeLimits,\n TreeSchemaMode,\n} from '@dudousxd/nestjs-agent-core/genui';\nimport {\n type DefineSandboxOptions,\n type SandboxDefinition,\n assertGenuiChannels,\n defineCatalog,\n defineSandbox,\n genuiTools,\n sandboxPolicyOf,\n} 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';\nimport { AGENT_GENUI, AgentGenui } from './agent-genui.token.js';\n\nexport { AGENT_GENUI, AgentGenui } from './agent-genui.token.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/** The sandbox and channels as boot resolved them (kit, Tailwind and theme found). Internal. */\nconst GENUI_RESOLVED = Symbol.for('@dudousxd/nestjs-agent:genui-resolved');\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 /**\n * Tree mode: components that ALSO get a flat tool whose input IS their props —\n * `componentTools: ['Sandbox']` adds `ui__sandbox`, so a model writing a big component on its own\n * has no `{ type, props }` envelope to leave out.\n */\n componentTools?: readonly string[];\n /** Tool-name prefix for `componentTools`. Default `ui__` (`Sandbox` → `ui__sandbox`). */\n componentToolPrefix?: string;\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 /**\n * The authorization ability the UI tools declare (`ToolSpec.ability`), for an ability-aware\n * authorizer such as `authzToolAuthorizer`, which denies a tool with none. A string for every\n * tool; a map by tool name (`{ ui__render: 'genui.render', ui__sandbox: 'genui.sandbox' }`, a tool\n * left out declares none); or a function of `{ name, component }`. The authorizer decides.\n */\n ability?: GenuiAbility;\n /** Override the generated presentation per component (or per tree / show tool name). */\n presentation?: (component: string) => ToolPresentation | undefined;\n /**\n * Add the sandbox component (`Sandbox`): the model may write HTML, CSS and JS for a one-off\n * interactive answer when no catalog component fits. `true` for the defaults (no network), or\n * the {@link DefineSandboxOptions} (a policy listing origins, extra instructions). Off by default.\n * The browser's catalog should carry the same definition (`defineSandbox(...)` in the shared\n * catalog file) so the renderer enforces the same policy.\n *\n * `theme` (default on) and `kit` put the app's design system in the frame: `kit: true` turns on\n * whatever `genuiSandboxKit()` built (styles, Tailwind, components, wrapper, docs), found through\n * `sandboxKit`: the descriptor\n * `genuiSandboxKit()` (`@dudousxd/nestjs-agent/vite`) writes in dev, the Vite manifest in\n * production — and `GET <base>/config` tells the renderer where the assets are.\n */\n sandbox?: boolean | DefineSandboxOptions;\n /**\n * Per-channel generative UI: each entry sets the mode, streaming, sandbox and rendering of one\n * channel (`web`, `mobile`, `whatsapp`, `telegram`, `email`, or `default` for the rest), over the\n * top-level options. A text channel (`@dudousxd/nestjs-agent-channels`) configured here draws the\n * components natively (reply buttons, lists, images). Omitted → every channel is served by the\n * top-level options, as before.\n */\n channels?: GenuiChannels;\n /**\n * Where the sandbox kit is found (with `sandbox: { kit: true }` or the theme's names). No Vite\n * runs in the Nest process, so: the descriptor the dev plugin writes, or the production Vite\n * manifest — in production the manifest first, otherwise whichever was written last.\n */\n sandboxKit?: AgentGenuiSandboxKitOptions;\n /**\n * Generative-UI telemetry, recorded by the loop for every UI call (the dashboard's \"Generative UI\"\n * page): tool, channel, mode, attempt, validity, error category, tokens and cost, time to first and\n * complete frame. Metadata only by default — the generated HTML/JSX and props are NEVER stored\n * unless `samplePayloads: true` (debugging; keep it off where a view may show personal data).\n * `false` records nothing. Needs a store that records it (`recordGenuiCalls`).\n */\n telemetry?: GenuiTelemetryOptions | false;\n}\n\n/** {@link AgentGenuiOptions.sandboxKit}. Relative paths resolve against `root`. */\nexport interface AgentGenuiSandboxKitOptions {\n /** Default `process.cwd()`. */\n root?: string;\n /**\n * The dev descriptor `genuiSandboxKit()` writes. Default `.genui/sandbox-kit.json` — for a named\n * kit (`genuiSandboxKit({ name })`, picked with `kitName`), `.genui/sandbox-kit.<name>.json`.\n */\n descriptor?: string;\n /**\n * The production Vite manifest, and the directory its `file`s are relative to. Default\n * `{ file: 'public/.vite/manifest.json', outDir: 'public' }`; `false` → none.\n */\n manifest?: { file: string; outDir: string } | false;\n /** An explicit kit url (an SPA served from elsewhere), over what is found. */\n kitUrl?: string;\n /** An explicit url of the compiled styles, over what is found (the same SPA case). */\n cssUrl?: string;\n /** An explicit url of the Tailwind browser runtime, over what is found (the same SPA case). */\n tailwindUrl?: string;\n /** Read the manifest first (else the freshest of the two). Default: `NODE_ENV === 'production'`. */\n production?: boolean;\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\n/** The sandbox and channels with the kit and theme names found ({@link GENUI_RESOLVED}). */\ninterface ResolvedGenui {\n sandbox?: boolean | DefineSandboxOptions;\n /** A kit sandbox the catalog itself defines, resolved (under its own name). */\n catalogSandbox?: DefineSandboxOptions;\n channels?: GenuiChannels;\n sandboxClient?: () => SandboxClientConfig;\n}\n\n/** What every configured sandbox (top level and channels) needs from the browser, together. */\nfunction mergeSandboxClients(clients: Array<() => SandboxClientConfig>): SandboxClientConfig {\n const merged: SandboxClientConfig = { theme: false };\n for (const client of clients) {\n const one = client();\n merged.theme ||= one.theme;\n if (one.name !== undefined && merged.kit === undefined && one.kit !== undefined)\n merged.name = one.name;\n if (one.kit !== undefined) merged.kit ??= one.kit;\n if (one.css !== undefined) merged.css ??= one.css;\n if (one.tailwind !== undefined) merged.tailwind ??= one.tailwind;\n }\n return merged;\n}\n\n/** Resolve the sandbox (top level and per channel) against the kit discovery. */\nasync function resolveGenui(options: AgentGenuiOptions): Promise<ResolvedGenui> {\n const { sandbox: asked, channels: askedChannels } = options;\n assertGenuiChannels(askedChannels);\n // A sandbox's kit (styles, components, wrapper) and theme names are found through the app's Vite output.\n const clients: Array<() => SandboxClientConfig> = [];\n const discoveries = new Map<\n string,\n import('@dudousxd/nestjs-agent-core/genui/kit').SandboxKitDiscovery\n >();\n const resolveSandbox = async (\n value: boolean | DefineSandboxOptions | undefined,\n ): Promise<boolean | DefineSandboxOptions | undefined> => {\n if (value === undefined || value === false) return value;\n // Node-only, and only with a sandbox: loaded when one is configured.\n const [{ nestSandboxKitDiscovery }, { resolveSandboxServer }] = await Promise.all([\n import('./kit.js'),\n import('@dudousxd/nestjs-agent-core/genui/kit'),\n ]);\n const kitName = value === true ? undefined : value.kitName;\n let discovery = discoveries.get(kitName ?? '');\n if (discovery === undefined) {\n discovery = nestSandboxKitDiscovery(options.sandboxKit, kitName);\n discoveries.set(kitName ?? '', discovery);\n }\n const resolved = resolveSandboxServer(value, discovery);\n clients.push(resolved.client);\n return resolved.define;\n };\n const sandbox = await resolveSandbox(asked);\n // A kit sandbox defined in the (shared) catalog itself: found the same way, and put\n // back under its own name, so the browser's copy of the catalog validates what the model writes.\n const own = options.catalog?.components.find((each) => sandboxPolicyOf(each) !== undefined) as\n | SandboxDefinition\n | undefined;\n const ownOptions =\n asked === undefined && own?.sandboxOptions !== undefined && own.sandboxView?.kit === true\n ? await resolveSandbox({ ...own.sandboxOptions, name: own.name })\n : undefined;\n let channels: GenuiChannels | undefined;\n if (askedChannels !== undefined) {\n channels = {};\n for (const [name, entry] of Object.entries(askedChannels)) {\n if (entry === undefined) continue;\n const own = await resolveSandbox(entry.sandbox);\n channels[name] = { ...entry, ...(own !== undefined ? { sandbox: own } : {}) };\n }\n }\n return {\n ...(sandbox !== undefined ? { sandbox } : {}),\n ...(typeof ownOptions === 'object' ? { catalogSandbox: ownOptions } : {}),\n ...(channels !== undefined ? { channels } : {}),\n ...(clients.length > 0 ? { sandboxClient: () => mergeSandboxClients(clients) } : {}),\n };\n}\n\nfunction perRequest(\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions['resolveCatalog'] | undefined {\n return resolver === undefined ? undefined : (scope: GenuiCatalogScope) => resolver.resolve(scope);\n}\n\nfunction toolOptions(\n options: AgentGenuiOptions,\n resolved: ResolvedGenui,\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions {\n const {\n catalog: _catalog,\n sandbox: _sandbox,\n channels: _channels,\n sandboxKit: _sandboxKit,\n ...rest\n } = options;\n const resolveCatalog = perRequest(resolver);\n return {\n ...rest,\n ...(resolved.channels !== undefined ? { channels: resolved.channels } : {}),\n ...(resolved.sandbox !== undefined ? { sandbox: resolved.sandbox } : {}),\n ...(resolveCatalog !== undefined ? { resolveCatalog } : {}),\n };\n}\n\n/** The configured catalog, with the sandbox component added when `sandbox` asks for it. */\nfunction withSandbox(options: AgentGenuiOptions, resolved: ResolvedGenui): Catalog {\n const base = options.catalog ?? defineCatalog([]);\n const { sandbox, catalogSandbox } = resolved;\n if (sandbox === undefined || sandbox === false)\n return catalogSandbox !== undefined ? base.extend([defineSandbox(catalogSandbox)]) : base;\n return base.extend([defineSandbox(sandbox === true ? {} : sandbox)]);\n}\n\nfunction coreProviders(resolver: ResolverOption | undefined): Provider[] {\n return [\n {\n provide: GENUI_RESOLVED,\n useFactory: (options: AgentGenuiOptions) => resolveGenui(options),\n inject: [GENUI_OPTIONS],\n },\n {\n provide: GENUI_CATALOG,\n useFactory: (options: AgentGenuiOptions, resolved: ResolvedGenui) =>\n withSandbox(options, resolved),\n inject: [GENUI_OPTIONS, GENUI_RESOLVED],\n },\n {\n provide: AGENT_GENUI,\n useFactory: (\n options: AgentGenuiOptions,\n catalog: Catalog,\n resolved: ResolvedGenui,\n resolverInstance?: GenuiCatalogResolver,\n ) =>\n new AgentGenui(\n catalog,\n perRequest(resolverInstance),\n resolved.channels,\n {\n ...(options.mode !== undefined ? { mode: options.mode } : {}),\n ...(options.streaming !== undefined ? { streaming: options.streaming } : {}),\n ...(resolved.sandbox !== undefined ? { sandbox: resolved.sandbox } : {}),\n },\n resolved.sandboxClient,\n ),\n inject: [\n GENUI_OPTIONS,\n GENUI_CATALOG,\n GENUI_RESOLVED,\n { token: GenuiCatalogResolver, optional: true },\n ],\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 (\n options: AgentGenuiOptions,\n catalog: Catalog,\n resolved: ResolvedGenui,\n perRequestResolver?: GenuiCatalogResolver,\n ) => genuiTools(catalog, toolOptions(options, resolved, perRequestResolver)),\n [\n GENUI_OPTIONS,\n GENUI_CATALOG,\n GENUI_RESOLVED,\n { token: GenuiCatalogResolver, optional: true },\n ],\n ),\n ];\n}\n\nconst EXPORTS = [GENUI_CATALOG, GENUI_OPTIONS, AGENT_GENUI];\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","import type {\n Catalog,\n GenuiCatalogScope,\n GenuiChannelBase,\n GenuiChannels,\n SandboxClientConfig,\n} from '@dudousxd/nestjs-agent-core/genui';\n\n/**\n * The app's genui setup ({@link AgentGenui}): the catalog, the per-channel options and what the\n * sandbox renderer is told — what the text channels (`@dudousxd/nestjs-agent-channels`) and\n * `GET <base>/config` read.\n */\nexport const AGENT_GENUI = Symbol.for('@dudousxd/nestjs-agent:genui');\n\n/**\n * The app's genui setup, bound to {@link AGENT_GENUI}: what a text channel draws with\n * (`catalog`, `channels`, `base`) and what the sandbox renderer is told (`sandboxClient`).\n */\nexport class AgentGenui {\n constructor(\n readonly catalog: Catalog,\n readonly resolveCatalog?: (scope: GenuiCatalogScope) => Catalog | Promise<Catalog>,\n /** `AgentGenuiModule.forRoot({ channels })`, when configured. */\n readonly channels?: GenuiChannels,\n /** The top-level options a channel falls back to. */\n readonly base: GenuiChannelBase = {},\n /** What the sandbox renderer is told, when a sandbox is configured. */\n readonly sandboxClient?: () => SandboxClientConfig,\n ) {}\n}\n"],"mappings":"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","names":["NEST_SANDBOX_KIT_DESCRIPTOR","nestSandboxKitDiscovery","options","name","manifest","NEST_SANDBOX_KIT_MANIFEST","sandboxKitDiscovery","root","resolve","process","cwd","undefined","descriptor","sandboxKitDescriptorPath","NEST_SANDBOX_KIT_DESCRIPTOR","file","outDir","kitUrl","cssUrl","tailwindUrl","production","import_kit","Object","freeze","AGENT_TOOL_BRAND","Symbol","for","brand","tool","spec","handler","provideAgentTools","factory","inject","provide","Symbol","useFactory","deps","map","brand","AGENT_GENUI","Symbol","for","AgentGenui","catalog","resolveCatalog","channels","base","sandboxClient","GENUI_CATALOG","Symbol","for","GENUI_OPTIONS","GENUI_RESOLVED","InjectGenuiCatalog","Inject","GenuiCatalogResolver","resolverProviders","resolver","undefined","provide","useClass","useValue","mergeSandboxClients","clients","merged","theme","client","one","name","kit","css","tailwind","resolveGenui","options","sandbox","asked","channels","askedChannels","assertGenuiChannels","discoveries","Map","resolveSandbox","value","nestSandboxKitDiscovery","resolveSandboxServer","Promise","all","kitName","discovery","get","sandboxKit","set","resolved","push","define","own","catalog","components","find","each","sandboxPolicyOf","ownOptions","sandboxOptions","sandboxView","entry","Object","entries","catalogSandbox","length","sandboxClient","perRequest","scope","resolve","toolOptions","_catalog","_sandbox","_channels","_sandboxKit","rest","resolveCatalog","withSandbox","base","defineCatalog","extend","defineSandbox","coreProviders","useFactory","inject","AGENT_GENUI","resolverInstance","AgentGenui","mode","streaming","token","optional","provideAgentTools","perRequestResolver","genuiTools","EXPORTS","AgentGenuiModule","forRoot","module","global","providers","exports","forRootAsync","imports"]}
@@ -1,5 +1,5 @@
1
1
  import { ToolPresentation } from '@dudousxd/nestjs-agent-core';
2
- import { Catalog, GenuiCatalogScope, GenuiChannels, GenuiChannelBase, SandboxClientConfig, TreeSchemaMode, GenuiStreaming, TreeLimits, GenuiAbility, DefineSandboxOptions } from '@dudousxd/nestjs-agent-core/genui';
2
+ import { Catalog, GenuiCatalogScope, GenuiChannels, GenuiChannelBase, SandboxClientConfig, TreeSchemaMode, GenuiStreaming, TreeLimits, GenuiAbility, DefineSandboxOptions, GenuiTelemetryOptions } 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
 
@@ -135,6 +135,14 @@ interface AgentGenuiOptions {
135
135
  * manifest — in production the manifest first, otherwise whichever was written last.
136
136
  */
137
137
  sandboxKit?: AgentGenuiSandboxKitOptions;
138
+ /**
139
+ * Generative-UI telemetry, recorded by the loop for every UI call (the dashboard's "Generative UI"
140
+ * page): tool, channel, mode, attempt, validity, error category, tokens and cost, time to first and
141
+ * complete frame. Metadata only by default — the generated HTML/JSX and props are NEVER stored
142
+ * unless `samplePayloads: true` (debugging; keep it off where a view may show personal data).
143
+ * `false` records nothing. Needs a store that records it (`recordGenuiCalls`).
144
+ */
145
+ telemetry?: GenuiTelemetryOptions | false;
138
146
  }
139
147
  /** {@link AgentGenuiOptions.sandboxKit}. Relative paths resolve against `root`. */
140
148
  interface AgentGenuiSandboxKitOptions {
@@ -1,5 +1,5 @@
1
1
  import { ToolPresentation } from '@dudousxd/nestjs-agent-core';
2
- import { Catalog, GenuiCatalogScope, GenuiChannels, GenuiChannelBase, SandboxClientConfig, TreeSchemaMode, GenuiStreaming, TreeLimits, GenuiAbility, DefineSandboxOptions } from '@dudousxd/nestjs-agent-core/genui';
2
+ import { Catalog, GenuiCatalogScope, GenuiChannels, GenuiChannelBase, SandboxClientConfig, TreeSchemaMode, GenuiStreaming, TreeLimits, GenuiAbility, DefineSandboxOptions, GenuiTelemetryOptions } 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
 
@@ -135,6 +135,14 @@ interface AgentGenuiOptions {
135
135
  * manifest — in production the manifest first, otherwise whichever was written last.
136
136
  */
137
137
  sandboxKit?: AgentGenuiSandboxKitOptions;
138
+ /**
139
+ * Generative-UI telemetry, recorded by the loop for every UI call (the dashboard's "Generative UI"
140
+ * page): tool, channel, mode, attempt, validity, error category, tokens and cost, time to first and
141
+ * complete frame. Metadata only by default — the generated HTML/JSX and props are NEVER stored
142
+ * unless `samplePayloads: true` (debugging; keep it off where a view may show personal data).
143
+ * `false` records nothing. Needs a store that records it (`recordGenuiCalls`).
144
+ */
145
+ telemetry?: GenuiTelemetryOptions | false;
138
146
  }
139
147
  /** {@link AgentGenuiOptions.sandboxKit}. Relative paths resolve against `root`. */
140
148
  interface AgentGenuiSandboxKitOptions {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/vite/index.ts","../../src/genui/kit.ts","../../src/genui/agent-genui.module.ts","../../src/functional-tool.ts","../../src/genui/agent-genui.token.ts","../../src/genui/index.ts"],"sourcesContent":["/**\n * `@dudousxd/nestjs-agent/vite` — `genuiSandboxKit()`, the Vite plugin that puts the app's design\n * system (its styles, its components, its providers) inside the sandbox, whatever the stack:\n *\n * ```ts\n * // vite.config.ts (the SPA that talks to the agent)\n * import { genuiSandboxKit } from '@dudousxd/nestjs-agent/vite'\n * export default defineConfig({\n * plugins: [react(), genuiSandboxKit({ styles: 'src/index.css', components: 'src/components/ui' })],\n * })\n * ```\n *\n * Then `AgentGenuiModule.forRoot({ sandbox: { kit: true } })` finds what it built: the descriptor\n * the dev server writes (`.genui/sandbox-kit.json`) in dev, the Vite manifest in production (see\n * `AgentGenuiOptions.sandboxKit`).\n */\nimport {\n type GenuiSandboxKitApi,\n type GenuiSandboxKitOptions,\n type GenuiSandboxKitPlugin,\n SANDBOX_KIT_DEV_PREFIX,\n SANDBOX_KIT_MANIFEST_KEYS,\n SANDBOX_KIT_UPDATE_EVENT,\n createGenuiSandboxKitPlugin,\n} from '@dudousxd/nestjs-agent-core/genui/kit';\n\n/**\n * Where the dev descriptor is written, relative to the Vite root — and where the server reads it,\n * relative to its working directory (run both from the project root, or point\n * `sandboxKit.descriptor` at it). Add `.genui/` to `.gitignore`.\n */\nexport const NEST_SANDBOX_KIT_DESCRIPTOR = '.genui/sandbox-kit.json';\n\n/**\n * The sandbox kit plugin: `styles` (the app's style entries — default, the stylesheets among its\n * Vite entrypoints or `index.html`), `components` (modules or globs exporting React components —\n * default, the first `components/ui` folder), `wrapper` (a module whose default export wraps the\n * model's App). See {@link GenuiSandboxKitOptions}.\n */\nexport function genuiSandboxKit(options: GenuiSandboxKitOptions = {}): GenuiSandboxKitPlugin {\n return createGenuiSandboxKitPlugin(options, {\n descriptor: NEST_SANDBOX_KIT_DESCRIPTOR,\n rendererImport: /@dudousxd\\/nestjs-agent-react/,\n });\n}\n\nexport {\n type GenuiSandboxKitApi,\n type GenuiSandboxKitOptions,\n type GenuiSandboxKitPlugin,\n SANDBOX_KIT_DEV_PREFIX,\n SANDBOX_KIT_MANIFEST_KEYS,\n SANDBOX_KIT_UPDATE_EVENT,\n};\n","/**\n * The sandbox kit in a Nest app. No Vite runs in the Nest process, so the kit is found in files:\n * the descriptor `genuiSandboxKit()` (`@dudousxd/nestjs-agent/vite`) writes while the dev server\n * runs, and in production the Vite manifest the build wrote (`genui-sandbox-kit.json` and the assets\n * it names). Node-only: loaded by {@link AgentGenuiModule} only when a sandbox is configured.\n */\nimport { resolve } from 'node:path';\nimport {\n type SandboxKitDiscovery,\n sandboxKitDescriptorPath,\n sandboxKitDiscovery,\n} from '@dudousxd/nestjs-agent-core/genui/kit';\nimport { NEST_SANDBOX_KIT_DESCRIPTOR } from '../vite/index.js';\nimport type { AgentGenuiSandboxKitOptions } from './agent-genui.module.js';\n\n/** Where the production Vite manifest is looked for by default, and the directory it is relative to. */\nexport const NEST_SANDBOX_KIT_MANIFEST = Object.freeze({\n file: 'public/.vite/manifest.json',\n outDir: 'public',\n});\n\n/**\n * Find the kit for `AgentGenuiModule.forRoot({ sandbox: { kit: true } })` — a named kit's\n * (`genuiSandboxKit({ name })`, `sandbox: { kit: true, kitName }`) with `name`.\n */\nexport function nestSandboxKitDiscovery(\n options: AgentGenuiSandboxKitOptions = {},\n name?: string,\n): SandboxKitDiscovery {\n const manifest = options.manifest ?? NEST_SANDBOX_KIT_MANIFEST;\n return sandboxKitDiscovery({\n root: resolve(options.root ?? process.cwd()),\n ...(name !== undefined ? { name } : {}),\n descriptor: sandboxKitDescriptorPath(options.descriptor ?? NEST_SANDBOX_KIT_DESCRIPTOR, name),\n ...(manifest !== false ? { manifest: { file: manifest.file, outDir: manifest.outDir } } : {}),\n ...(options.kitUrl !== undefined ? { kitUrl: options.kitUrl } : {}),\n ...(options.cssUrl !== undefined ? { cssUrl: options.cssUrl } : {}),\n ...(options.tailwindUrl !== undefined ? { tailwindUrl: options.tailwindUrl } : {}),\n ...(options.production !== undefined ? { production: options.production } : {}),\n });\n}\n","import type { ToolPresentation } from '@dudousxd/nestjs-agent-core';\nimport type {\n Catalog,\n GenuiAbility,\n GenuiCatalogScope,\n GenuiChannels,\n GenuiStreaming,\n GenuiToolsOptions,\n SandboxClientConfig,\n TreeLimits,\n TreeSchemaMode,\n} from '@dudousxd/nestjs-agent-core/genui';\nimport {\n type DefineSandboxOptions,\n type SandboxDefinition,\n assertGenuiChannels,\n defineCatalog,\n defineSandbox,\n genuiTools,\n sandboxPolicyOf,\n} 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';\nimport { AGENT_GENUI, AgentGenui } from './agent-genui.token.js';\n\nexport { AGENT_GENUI, AgentGenui } from './agent-genui.token.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/** The sandbox and channels as boot resolved them (kit, Tailwind and theme found). Internal. */\nconst GENUI_RESOLVED = Symbol.for('@dudousxd/nestjs-agent:genui-resolved');\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 /**\n * Tree mode: components that ALSO get a flat tool whose input IS their props —\n * `componentTools: ['Sandbox']` adds `ui__sandbox`, so a model writing a big component on its own\n * has no `{ type, props }` envelope to leave out.\n */\n componentTools?: readonly string[];\n /** Tool-name prefix for `componentTools`. Default `ui__` (`Sandbox` → `ui__sandbox`). */\n componentToolPrefix?: string;\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 /**\n * The authorization ability the UI tools declare (`ToolSpec.ability`), for an ability-aware\n * authorizer such as `authzToolAuthorizer`, which denies a tool with none. A string for every\n * tool; a map by tool name (`{ ui__render: 'genui.render', ui__sandbox: 'genui.sandbox' }`, a tool\n * left out declares none); or a function of `{ name, component }`. The authorizer decides.\n */\n ability?: GenuiAbility;\n /** Override the generated presentation per component (or per tree / show tool name). */\n presentation?: (component: string) => ToolPresentation | undefined;\n /**\n * Add the sandbox component (`Sandbox`): the model may write HTML, CSS and JS for a one-off\n * interactive answer when no catalog component fits. `true` for the defaults (no network), or\n * the {@link DefineSandboxOptions} (a policy listing origins, extra instructions). Off by default.\n * The browser's catalog should carry the same definition (`defineSandbox(...)` in the shared\n * catalog file) so the renderer enforces the same policy.\n *\n * `theme` (default on) and `kit` put the app's design system in the frame: `kit: true` turns on\n * whatever `genuiSandboxKit()` built (styles, Tailwind, components, wrapper, docs), found through\n * `sandboxKit`: the descriptor\n * `genuiSandboxKit()` (`@dudousxd/nestjs-agent/vite`) writes in dev, the Vite manifest in\n * production — and `GET <base>/config` tells the renderer where the assets are.\n */\n sandbox?: boolean | DefineSandboxOptions;\n /**\n * Per-channel generative UI: each entry sets the mode, streaming, sandbox and rendering of one\n * channel (`web`, `mobile`, `whatsapp`, `telegram`, `email`, or `default` for the rest), over the\n * top-level options. A text channel (`@dudousxd/nestjs-agent-channels`) configured here draws the\n * components natively (reply buttons, lists, images). Omitted → every channel is served by the\n * top-level options, as before.\n */\n channels?: GenuiChannels;\n /**\n * Where the sandbox kit is found (with `sandbox: { kit: true }` or the theme's names). No Vite\n * runs in the Nest process, so: the descriptor the dev plugin writes, or the production Vite\n * manifest — in production the manifest first, otherwise whichever was written last.\n */\n sandboxKit?: AgentGenuiSandboxKitOptions;\n}\n\n/** {@link AgentGenuiOptions.sandboxKit}. Relative paths resolve against `root`. */\nexport interface AgentGenuiSandboxKitOptions {\n /** Default `process.cwd()`. */\n root?: string;\n /**\n * The dev descriptor `genuiSandboxKit()` writes. Default `.genui/sandbox-kit.json` — for a named\n * kit (`genuiSandboxKit({ name })`, picked with `kitName`), `.genui/sandbox-kit.<name>.json`.\n */\n descriptor?: string;\n /**\n * The production Vite manifest, and the directory its `file`s are relative to. Default\n * `{ file: 'public/.vite/manifest.json', outDir: 'public' }`; `false` → none.\n */\n manifest?: { file: string; outDir: string } | false;\n /** An explicit kit url (an SPA served from elsewhere), over what is found. */\n kitUrl?: string;\n /** An explicit url of the compiled styles, over what is found (the same SPA case). */\n cssUrl?: string;\n /** An explicit url of the Tailwind browser runtime, over what is found (the same SPA case). */\n tailwindUrl?: string;\n /** Read the manifest first (else the freshest of the two). Default: `NODE_ENV === 'production'`. */\n production?: boolean;\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\n/** The sandbox and channels with the kit and theme names found ({@link GENUI_RESOLVED}). */\ninterface ResolvedGenui {\n sandbox?: boolean | DefineSandboxOptions;\n /** A kit sandbox the catalog itself defines, resolved (under its own name). */\n catalogSandbox?: DefineSandboxOptions;\n channels?: GenuiChannels;\n sandboxClient?: () => SandboxClientConfig;\n}\n\n/** What every configured sandbox (top level and channels) needs from the browser, together. */\nfunction mergeSandboxClients(clients: Array<() => SandboxClientConfig>): SandboxClientConfig {\n const merged: SandboxClientConfig = { theme: false };\n for (const client of clients) {\n const one = client();\n merged.theme ||= one.theme;\n if (one.name !== undefined && merged.kit === undefined && one.kit !== undefined)\n merged.name = one.name;\n if (one.kit !== undefined) merged.kit ??= one.kit;\n if (one.css !== undefined) merged.css ??= one.css;\n if (one.tailwind !== undefined) merged.tailwind ??= one.tailwind;\n }\n return merged;\n}\n\n/** Resolve the sandbox (top level and per channel) against the kit discovery. */\nasync function resolveGenui(options: AgentGenuiOptions): Promise<ResolvedGenui> {\n const { sandbox: asked, channels: askedChannels } = options;\n assertGenuiChannels(askedChannels);\n // A sandbox's kit (styles, components, wrapper) and theme names are found through the app's Vite output.\n const clients: Array<() => SandboxClientConfig> = [];\n const discoveries = new Map<\n string,\n import('@dudousxd/nestjs-agent-core/genui/kit').SandboxKitDiscovery\n >();\n const resolveSandbox = async (\n value: boolean | DefineSandboxOptions | undefined,\n ): Promise<boolean | DefineSandboxOptions | undefined> => {\n if (value === undefined || value === false) return value;\n // Node-only, and only with a sandbox: loaded when one is configured.\n const [{ nestSandboxKitDiscovery }, { resolveSandboxServer }] = await Promise.all([\n import('./kit.js'),\n import('@dudousxd/nestjs-agent-core/genui/kit'),\n ]);\n const kitName = value === true ? undefined : value.kitName;\n let discovery = discoveries.get(kitName ?? '');\n if (discovery === undefined) {\n discovery = nestSandboxKitDiscovery(options.sandboxKit, kitName);\n discoveries.set(kitName ?? '', discovery);\n }\n const resolved = resolveSandboxServer(value, discovery);\n clients.push(resolved.client);\n return resolved.define;\n };\n const sandbox = await resolveSandbox(asked);\n // A kit sandbox defined in the (shared) catalog itself: found the same way, and put\n // back under its own name, so the browser's copy of the catalog validates what the model writes.\n const own = options.catalog?.components.find((each) => sandboxPolicyOf(each) !== undefined) as\n | SandboxDefinition\n | undefined;\n const ownOptions =\n asked === undefined && own?.sandboxOptions !== undefined && own.sandboxView?.kit === true\n ? await resolveSandbox({ ...own.sandboxOptions, name: own.name })\n : undefined;\n let channels: GenuiChannels | undefined;\n if (askedChannels !== undefined) {\n channels = {};\n for (const [name, entry] of Object.entries(askedChannels)) {\n if (entry === undefined) continue;\n const own = await resolveSandbox(entry.sandbox);\n channels[name] = { ...entry, ...(own !== undefined ? { sandbox: own } : {}) };\n }\n }\n return {\n ...(sandbox !== undefined ? { sandbox } : {}),\n ...(typeof ownOptions === 'object' ? { catalogSandbox: ownOptions } : {}),\n ...(channels !== undefined ? { channels } : {}),\n ...(clients.length > 0 ? { sandboxClient: () => mergeSandboxClients(clients) } : {}),\n };\n}\n\nfunction perRequest(\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions['resolveCatalog'] | undefined {\n return resolver === undefined ? undefined : (scope: GenuiCatalogScope) => resolver.resolve(scope);\n}\n\nfunction toolOptions(\n options: AgentGenuiOptions,\n resolved: ResolvedGenui,\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions {\n const {\n catalog: _catalog,\n sandbox: _sandbox,\n channels: _channels,\n sandboxKit: _sandboxKit,\n ...rest\n } = options;\n const resolveCatalog = perRequest(resolver);\n return {\n ...rest,\n ...(resolved.channels !== undefined ? { channels: resolved.channels } : {}),\n ...(resolved.sandbox !== undefined ? { sandbox: resolved.sandbox } : {}),\n ...(resolveCatalog !== undefined ? { resolveCatalog } : {}),\n };\n}\n\n/** The configured catalog, with the sandbox component added when `sandbox` asks for it. */\nfunction withSandbox(options: AgentGenuiOptions, resolved: ResolvedGenui): Catalog {\n const base = options.catalog ?? defineCatalog([]);\n const { sandbox, catalogSandbox } = resolved;\n if (sandbox === undefined || sandbox === false)\n return catalogSandbox !== undefined ? base.extend([defineSandbox(catalogSandbox)]) : base;\n return base.extend([defineSandbox(sandbox === true ? {} : sandbox)]);\n}\n\nfunction coreProviders(resolver: ResolverOption | undefined): Provider[] {\n return [\n {\n provide: GENUI_RESOLVED,\n useFactory: (options: AgentGenuiOptions) => resolveGenui(options),\n inject: [GENUI_OPTIONS],\n },\n {\n provide: GENUI_CATALOG,\n useFactory: (options: AgentGenuiOptions, resolved: ResolvedGenui) =>\n withSandbox(options, resolved),\n inject: [GENUI_OPTIONS, GENUI_RESOLVED],\n },\n {\n provide: AGENT_GENUI,\n useFactory: (\n options: AgentGenuiOptions,\n catalog: Catalog,\n resolved: ResolvedGenui,\n resolverInstance?: GenuiCatalogResolver,\n ) =>\n new AgentGenui(\n catalog,\n perRequest(resolverInstance),\n resolved.channels,\n {\n ...(options.mode !== undefined ? { mode: options.mode } : {}),\n ...(options.streaming !== undefined ? { streaming: options.streaming } : {}),\n ...(resolved.sandbox !== undefined ? { sandbox: resolved.sandbox } : {}),\n },\n resolved.sandboxClient,\n ),\n inject: [\n GENUI_OPTIONS,\n GENUI_CATALOG,\n GENUI_RESOLVED,\n { token: GenuiCatalogResolver, optional: true },\n ],\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 (\n options: AgentGenuiOptions,\n catalog: Catalog,\n resolved: ResolvedGenui,\n perRequestResolver?: GenuiCatalogResolver,\n ) => genuiTools(catalog, toolOptions(options, resolved, perRequestResolver)),\n [\n GENUI_OPTIONS,\n GENUI_CATALOG,\n GENUI_RESOLVED,\n { token: GenuiCatalogResolver, optional: true },\n ],\n ),\n ];\n}\n\nconst EXPORTS = [GENUI_CATALOG, GENUI_OPTIONS, AGENT_GENUI];\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","import type {\n Catalog,\n GenuiCatalogScope,\n GenuiChannelBase,\n GenuiChannels,\n SandboxClientConfig,\n} from '@dudousxd/nestjs-agent-core/genui';\n\n/**\n * The app's genui setup ({@link AgentGenui}): the catalog, the per-channel options and what the\n * sandbox renderer is told — what the text channels (`@dudousxd/nestjs-agent-channels`) and\n * `GET <base>/config` read.\n */\nexport const AGENT_GENUI = Symbol.for('@dudousxd/nestjs-agent:genui');\n\n/**\n * The app's genui setup, bound to {@link AGENT_GENUI}: what a text channel draws with\n * (`catalog`, `channels`, `base`) and what the sandbox renderer is told (`sandboxClient`).\n */\nexport class AgentGenui {\n constructor(\n readonly catalog: Catalog,\n readonly resolveCatalog?: (scope: GenuiCatalogScope) => Catalog | Promise<Catalog>,\n /** `AgentGenuiModule.forRoot({ channels })`, when configured. */\n readonly channels?: GenuiChannels,\n /** The top-level options a channel falls back to. */\n readonly base: GenuiChannelBase = {},\n /** What the sandbox renderer is told, when a sandbox is configured. */\n readonly sandboxClient?: () => SandboxClientConfig,\n ) {}\n}\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 AGENT_GENUI,\n AgentGenui,\n AgentGenuiModule,\n type AgentGenuiModuleAsyncOptions,\n type AgentGenuiModuleOptions,\n type AgentGenuiOptions,\n type AgentGenuiSandboxKitOptions,\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":"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","names":["SANDBOX_KIT_DEV_PREFIX","SANDBOX_KIT_MANIFEST_KEYS","SANDBOX_KIT_UPDATE_EVENT","createGenuiSandboxKitPlugin","NEST_SANDBOX_KIT_DESCRIPTOR","resolve","sandboxKitDescriptorPath","sandboxKitDiscovery","nestSandboxKitDiscovery","options","name","manifest","NEST_SANDBOX_KIT_MANIFEST","root","process","cwd","undefined","descriptor","NEST_SANDBOX_KIT_DESCRIPTOR","file","outDir","kitUrl","cssUrl","tailwindUrl","production","Object","freeze","assertGenuiChannels","defineCatalog","defineSandbox","genuiTools","sandboxPolicyOf","Inject","Module","createFunctionalTool","AGENT_TOOL_BRAND","Symbol","for","brand","tool","spec","handler","provideAgentTools","factory","inject","provide","Symbol","useFactory","deps","map","brand","AGENT_GENUI","Symbol","for","AgentGenui","catalog","resolveCatalog","channels","base","sandboxClient","GENUI_CATALOG","Symbol","for","GENUI_OPTIONS","GENUI_RESOLVED","InjectGenuiCatalog","Inject","GenuiCatalogResolver","resolverProviders","resolver","undefined","provide","useClass","useValue","mergeSandboxClients","clients","merged","theme","client","one","name","kit","css","tailwind","resolveGenui","options","sandbox","asked","channels","askedChannels","assertGenuiChannels","discoveries","Map","resolveSandbox","value","nestSandboxKitDiscovery","resolveSandboxServer","Promise","all","kitName","discovery","get","sandboxKit","set","resolved","push","define","own","catalog","components","find","each","sandboxPolicyOf","ownOptions","sandboxOptions","sandboxView","entry","Object","entries","catalogSandbox","length","sandboxClient","perRequest","scope","resolve","toolOptions","_catalog","_sandbox","_channels","_sandboxKit","rest","resolveCatalog","withSandbox","base","defineCatalog","extend","defineSandbox","coreProviders","useFactory","inject","AGENT_GENUI","resolverInstance","AgentGenui","mode","streaming","token","optional","provideAgentTools","perRequestResolver","genuiTools","EXPORTS","AgentGenuiModule","forRoot","module","global","providers","exports","forRootAsync","imports"]}
1
+ {"version":3,"sources":["../../src/vite/index.ts","../../src/genui/kit.ts","../../src/genui/agent-genui.module.ts","../../src/functional-tool.ts","../../src/genui/agent-genui.token.ts","../../src/genui/index.ts"],"sourcesContent":["/**\n * `@dudousxd/nestjs-agent/vite` — `genuiSandboxKit()`, the Vite plugin that puts the app's design\n * system (its styles, its components, its providers) inside the sandbox, whatever the stack:\n *\n * ```ts\n * // vite.config.ts (the SPA that talks to the agent)\n * import { genuiSandboxKit } from '@dudousxd/nestjs-agent/vite'\n * export default defineConfig({\n * plugins: [react(), genuiSandboxKit({ styles: 'src/index.css', components: 'src/components/ui' })],\n * })\n * ```\n *\n * Then `AgentGenuiModule.forRoot({ sandbox: { kit: true } })` finds what it built: the descriptor\n * the dev server writes (`.genui/sandbox-kit.json`) in dev, the Vite manifest in production (see\n * `AgentGenuiOptions.sandboxKit`).\n */\nimport {\n type GenuiSandboxKitApi,\n type GenuiSandboxKitOptions,\n type GenuiSandboxKitPlugin,\n SANDBOX_KIT_DEV_PREFIX,\n SANDBOX_KIT_MANIFEST_KEYS,\n SANDBOX_KIT_UPDATE_EVENT,\n createGenuiSandboxKitPlugin,\n} from '@dudousxd/nestjs-agent-core/genui/kit';\n\n/**\n * Where the dev descriptor is written, relative to the Vite root — and where the server reads it,\n * relative to its working directory (run both from the project root, or point\n * `sandboxKit.descriptor` at it). Add `.genui/` to `.gitignore`.\n */\nexport const NEST_SANDBOX_KIT_DESCRIPTOR = '.genui/sandbox-kit.json';\n\n/**\n * The sandbox kit plugin: `styles` (the app's style entries — default, the stylesheets among its\n * Vite entrypoints or `index.html`), `components` (modules or globs exporting React components —\n * default, the first `components/ui` folder), `wrapper` (a module whose default export wraps the\n * model's App). See {@link GenuiSandboxKitOptions}.\n */\nexport function genuiSandboxKit(options: GenuiSandboxKitOptions = {}): GenuiSandboxKitPlugin {\n return createGenuiSandboxKitPlugin(options, {\n descriptor: NEST_SANDBOX_KIT_DESCRIPTOR,\n rendererImport: /@dudousxd\\/nestjs-agent-react/,\n });\n}\n\nexport {\n type GenuiSandboxKitApi,\n type GenuiSandboxKitOptions,\n type GenuiSandboxKitPlugin,\n SANDBOX_KIT_DEV_PREFIX,\n SANDBOX_KIT_MANIFEST_KEYS,\n SANDBOX_KIT_UPDATE_EVENT,\n};\n","/**\n * The sandbox kit in a Nest app. No Vite runs in the Nest process, so the kit is found in files:\n * the descriptor `genuiSandboxKit()` (`@dudousxd/nestjs-agent/vite`) writes while the dev server\n * runs, and in production the Vite manifest the build wrote (`genui-sandbox-kit.json` and the assets\n * it names). Node-only: loaded by {@link AgentGenuiModule} only when a sandbox is configured.\n */\nimport { resolve } from 'node:path';\nimport {\n type SandboxKitDiscovery,\n sandboxKitDescriptorPath,\n sandboxKitDiscovery,\n} from '@dudousxd/nestjs-agent-core/genui/kit';\nimport { NEST_SANDBOX_KIT_DESCRIPTOR } from '../vite/index.js';\nimport type { AgentGenuiSandboxKitOptions } from './agent-genui.module.js';\n\n/** Where the production Vite manifest is looked for by default, and the directory it is relative to. */\nexport const NEST_SANDBOX_KIT_MANIFEST = Object.freeze({\n file: 'public/.vite/manifest.json',\n outDir: 'public',\n});\n\n/**\n * Find the kit for `AgentGenuiModule.forRoot({ sandbox: { kit: true } })` — a named kit's\n * (`genuiSandboxKit({ name })`, `sandbox: { kit: true, kitName }`) with `name`.\n */\nexport function nestSandboxKitDiscovery(\n options: AgentGenuiSandboxKitOptions = {},\n name?: string,\n): SandboxKitDiscovery {\n const manifest = options.manifest ?? NEST_SANDBOX_KIT_MANIFEST;\n return sandboxKitDiscovery({\n root: resolve(options.root ?? process.cwd()),\n ...(name !== undefined ? { name } : {}),\n descriptor: sandboxKitDescriptorPath(options.descriptor ?? NEST_SANDBOX_KIT_DESCRIPTOR, name),\n ...(manifest !== false ? { manifest: { file: manifest.file, outDir: manifest.outDir } } : {}),\n ...(options.kitUrl !== undefined ? { kitUrl: options.kitUrl } : {}),\n ...(options.cssUrl !== undefined ? { cssUrl: options.cssUrl } : {}),\n ...(options.tailwindUrl !== undefined ? { tailwindUrl: options.tailwindUrl } : {}),\n ...(options.production !== undefined ? { production: options.production } : {}),\n });\n}\n","import type { ToolPresentation } from '@dudousxd/nestjs-agent-core';\nimport type {\n Catalog,\n GenuiAbility,\n GenuiCatalogScope,\n GenuiChannels,\n GenuiStreaming,\n GenuiTelemetryOptions,\n GenuiToolsOptions,\n SandboxClientConfig,\n TreeLimits,\n TreeSchemaMode,\n} from '@dudousxd/nestjs-agent-core/genui';\nimport {\n type DefineSandboxOptions,\n type SandboxDefinition,\n assertGenuiChannels,\n defineCatalog,\n defineSandbox,\n genuiTools,\n sandboxPolicyOf,\n} 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';\nimport { AGENT_GENUI, AgentGenui } from './agent-genui.token.js';\n\nexport { AGENT_GENUI, AgentGenui } from './agent-genui.token.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/** The sandbox and channels as boot resolved them (kit, Tailwind and theme found). Internal. */\nconst GENUI_RESOLVED = Symbol.for('@dudousxd/nestjs-agent:genui-resolved');\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 /**\n * Tree mode: components that ALSO get a flat tool whose input IS their props —\n * `componentTools: ['Sandbox']` adds `ui__sandbox`, so a model writing a big component on its own\n * has no `{ type, props }` envelope to leave out.\n */\n componentTools?: readonly string[];\n /** Tool-name prefix for `componentTools`. Default `ui__` (`Sandbox` → `ui__sandbox`). */\n componentToolPrefix?: string;\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 /**\n * The authorization ability the UI tools declare (`ToolSpec.ability`), for an ability-aware\n * authorizer such as `authzToolAuthorizer`, which denies a tool with none. A string for every\n * tool; a map by tool name (`{ ui__render: 'genui.render', ui__sandbox: 'genui.sandbox' }`, a tool\n * left out declares none); or a function of `{ name, component }`. The authorizer decides.\n */\n ability?: GenuiAbility;\n /** Override the generated presentation per component (or per tree / show tool name). */\n presentation?: (component: string) => ToolPresentation | undefined;\n /**\n * Add the sandbox component (`Sandbox`): the model may write HTML, CSS and JS for a one-off\n * interactive answer when no catalog component fits. `true` for the defaults (no network), or\n * the {@link DefineSandboxOptions} (a policy listing origins, extra instructions). Off by default.\n * The browser's catalog should carry the same definition (`defineSandbox(...)` in the shared\n * catalog file) so the renderer enforces the same policy.\n *\n * `theme` (default on) and `kit` put the app's design system in the frame: `kit: true` turns on\n * whatever `genuiSandboxKit()` built (styles, Tailwind, components, wrapper, docs), found through\n * `sandboxKit`: the descriptor\n * `genuiSandboxKit()` (`@dudousxd/nestjs-agent/vite`) writes in dev, the Vite manifest in\n * production — and `GET <base>/config` tells the renderer where the assets are.\n */\n sandbox?: boolean | DefineSandboxOptions;\n /**\n * Per-channel generative UI: each entry sets the mode, streaming, sandbox and rendering of one\n * channel (`web`, `mobile`, `whatsapp`, `telegram`, `email`, or `default` for the rest), over the\n * top-level options. A text channel (`@dudousxd/nestjs-agent-channels`) configured here draws the\n * components natively (reply buttons, lists, images). Omitted → every channel is served by the\n * top-level options, as before.\n */\n channels?: GenuiChannels;\n /**\n * Where the sandbox kit is found (with `sandbox: { kit: true }` or the theme's names). No Vite\n * runs in the Nest process, so: the descriptor the dev plugin writes, or the production Vite\n * manifest — in production the manifest first, otherwise whichever was written last.\n */\n sandboxKit?: AgentGenuiSandboxKitOptions;\n /**\n * Generative-UI telemetry, recorded by the loop for every UI call (the dashboard's \"Generative UI\"\n * page): tool, channel, mode, attempt, validity, error category, tokens and cost, time to first and\n * complete frame. Metadata only by default — the generated HTML/JSX and props are NEVER stored\n * unless `samplePayloads: true` (debugging; keep it off where a view may show personal data).\n * `false` records nothing. Needs a store that records it (`recordGenuiCalls`).\n */\n telemetry?: GenuiTelemetryOptions | false;\n}\n\n/** {@link AgentGenuiOptions.sandboxKit}. Relative paths resolve against `root`. */\nexport interface AgentGenuiSandboxKitOptions {\n /** Default `process.cwd()`. */\n root?: string;\n /**\n * The dev descriptor `genuiSandboxKit()` writes. Default `.genui/sandbox-kit.json` — for a named\n * kit (`genuiSandboxKit({ name })`, picked with `kitName`), `.genui/sandbox-kit.<name>.json`.\n */\n descriptor?: string;\n /**\n * The production Vite manifest, and the directory its `file`s are relative to. Default\n * `{ file: 'public/.vite/manifest.json', outDir: 'public' }`; `false` → none.\n */\n manifest?: { file: string; outDir: string } | false;\n /** An explicit kit url (an SPA served from elsewhere), over what is found. */\n kitUrl?: string;\n /** An explicit url of the compiled styles, over what is found (the same SPA case). */\n cssUrl?: string;\n /** An explicit url of the Tailwind browser runtime, over what is found (the same SPA case). */\n tailwindUrl?: string;\n /** Read the manifest first (else the freshest of the two). Default: `NODE_ENV === 'production'`. */\n production?: boolean;\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\n/** The sandbox and channels with the kit and theme names found ({@link GENUI_RESOLVED}). */\ninterface ResolvedGenui {\n sandbox?: boolean | DefineSandboxOptions;\n /** A kit sandbox the catalog itself defines, resolved (under its own name). */\n catalogSandbox?: DefineSandboxOptions;\n channels?: GenuiChannels;\n sandboxClient?: () => SandboxClientConfig;\n}\n\n/** What every configured sandbox (top level and channels) needs from the browser, together. */\nfunction mergeSandboxClients(clients: Array<() => SandboxClientConfig>): SandboxClientConfig {\n const merged: SandboxClientConfig = { theme: false };\n for (const client of clients) {\n const one = client();\n merged.theme ||= one.theme;\n if (one.name !== undefined && merged.kit === undefined && one.kit !== undefined)\n merged.name = one.name;\n if (one.kit !== undefined) merged.kit ??= one.kit;\n if (one.css !== undefined) merged.css ??= one.css;\n if (one.tailwind !== undefined) merged.tailwind ??= one.tailwind;\n }\n return merged;\n}\n\n/** Resolve the sandbox (top level and per channel) against the kit discovery. */\nasync function resolveGenui(options: AgentGenuiOptions): Promise<ResolvedGenui> {\n const { sandbox: asked, channels: askedChannels } = options;\n assertGenuiChannels(askedChannels);\n // A sandbox's kit (styles, components, wrapper) and theme names are found through the app's Vite output.\n const clients: Array<() => SandboxClientConfig> = [];\n const discoveries = new Map<\n string,\n import('@dudousxd/nestjs-agent-core/genui/kit').SandboxKitDiscovery\n >();\n const resolveSandbox = async (\n value: boolean | DefineSandboxOptions | undefined,\n ): Promise<boolean | DefineSandboxOptions | undefined> => {\n if (value === undefined || value === false) return value;\n // Node-only, and only with a sandbox: loaded when one is configured.\n const [{ nestSandboxKitDiscovery }, { resolveSandboxServer }] = await Promise.all([\n import('./kit.js'),\n import('@dudousxd/nestjs-agent-core/genui/kit'),\n ]);\n const kitName = value === true ? undefined : value.kitName;\n let discovery = discoveries.get(kitName ?? '');\n if (discovery === undefined) {\n discovery = nestSandboxKitDiscovery(options.sandboxKit, kitName);\n discoveries.set(kitName ?? '', discovery);\n }\n const resolved = resolveSandboxServer(value, discovery);\n clients.push(resolved.client);\n return resolved.define;\n };\n const sandbox = await resolveSandbox(asked);\n // A kit sandbox defined in the (shared) catalog itself: found the same way, and put\n // back under its own name, so the browser's copy of the catalog validates what the model writes.\n const own = options.catalog?.components.find((each) => sandboxPolicyOf(each) !== undefined) as\n | SandboxDefinition\n | undefined;\n const ownOptions =\n asked === undefined && own?.sandboxOptions !== undefined && own.sandboxView?.kit === true\n ? await resolveSandbox({ ...own.sandboxOptions, name: own.name })\n : undefined;\n let channels: GenuiChannels | undefined;\n if (askedChannels !== undefined) {\n channels = {};\n for (const [name, entry] of Object.entries(askedChannels)) {\n if (entry === undefined) continue;\n const own = await resolveSandbox(entry.sandbox);\n channels[name] = { ...entry, ...(own !== undefined ? { sandbox: own } : {}) };\n }\n }\n return {\n ...(sandbox !== undefined ? { sandbox } : {}),\n ...(typeof ownOptions === 'object' ? { catalogSandbox: ownOptions } : {}),\n ...(channels !== undefined ? { channels } : {}),\n ...(clients.length > 0 ? { sandboxClient: () => mergeSandboxClients(clients) } : {}),\n };\n}\n\nfunction perRequest(\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions['resolveCatalog'] | undefined {\n return resolver === undefined ? undefined : (scope: GenuiCatalogScope) => resolver.resolve(scope);\n}\n\nfunction toolOptions(\n options: AgentGenuiOptions,\n resolved: ResolvedGenui,\n resolver: GenuiCatalogResolver | undefined,\n): GenuiToolsOptions {\n const {\n catalog: _catalog,\n sandbox: _sandbox,\n channels: _channels,\n sandboxKit: _sandboxKit,\n ...rest\n } = options;\n const resolveCatalog = perRequest(resolver);\n return {\n ...rest,\n ...(resolved.channels !== undefined ? { channels: resolved.channels } : {}),\n ...(resolved.sandbox !== undefined ? { sandbox: resolved.sandbox } : {}),\n ...(resolveCatalog !== undefined ? { resolveCatalog } : {}),\n };\n}\n\n/** The configured catalog, with the sandbox component added when `sandbox` asks for it. */\nfunction withSandbox(options: AgentGenuiOptions, resolved: ResolvedGenui): Catalog {\n const base = options.catalog ?? defineCatalog([]);\n const { sandbox, catalogSandbox } = resolved;\n if (sandbox === undefined || sandbox === false)\n return catalogSandbox !== undefined ? base.extend([defineSandbox(catalogSandbox)]) : base;\n return base.extend([defineSandbox(sandbox === true ? {} : sandbox)]);\n}\n\nfunction coreProviders(resolver: ResolverOption | undefined): Provider[] {\n return [\n {\n provide: GENUI_RESOLVED,\n useFactory: (options: AgentGenuiOptions) => resolveGenui(options),\n inject: [GENUI_OPTIONS],\n },\n {\n provide: GENUI_CATALOG,\n useFactory: (options: AgentGenuiOptions, resolved: ResolvedGenui) =>\n withSandbox(options, resolved),\n inject: [GENUI_OPTIONS, GENUI_RESOLVED],\n },\n {\n provide: AGENT_GENUI,\n useFactory: (\n options: AgentGenuiOptions,\n catalog: Catalog,\n resolved: ResolvedGenui,\n resolverInstance?: GenuiCatalogResolver,\n ) =>\n new AgentGenui(\n catalog,\n perRequest(resolverInstance),\n resolved.channels,\n {\n ...(options.mode !== undefined ? { mode: options.mode } : {}),\n ...(options.streaming !== undefined ? { streaming: options.streaming } : {}),\n ...(resolved.sandbox !== undefined ? { sandbox: resolved.sandbox } : {}),\n },\n resolved.sandboxClient,\n ),\n inject: [\n GENUI_OPTIONS,\n GENUI_CATALOG,\n GENUI_RESOLVED,\n { token: GenuiCatalogResolver, optional: true },\n ],\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 (\n options: AgentGenuiOptions,\n catalog: Catalog,\n resolved: ResolvedGenui,\n perRequestResolver?: GenuiCatalogResolver,\n ) => genuiTools(catalog, toolOptions(options, resolved, perRequestResolver)),\n [\n GENUI_OPTIONS,\n GENUI_CATALOG,\n GENUI_RESOLVED,\n { token: GenuiCatalogResolver, optional: true },\n ],\n ),\n ];\n}\n\nconst EXPORTS = [GENUI_CATALOG, GENUI_OPTIONS, AGENT_GENUI];\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","import type {\n Catalog,\n GenuiCatalogScope,\n GenuiChannelBase,\n GenuiChannels,\n SandboxClientConfig,\n} from '@dudousxd/nestjs-agent-core/genui';\n\n/**\n * The app's genui setup ({@link AgentGenui}): the catalog, the per-channel options and what the\n * sandbox renderer is told — what the text channels (`@dudousxd/nestjs-agent-channels`) and\n * `GET <base>/config` read.\n */\nexport const AGENT_GENUI = Symbol.for('@dudousxd/nestjs-agent:genui');\n\n/**\n * The app's genui setup, bound to {@link AGENT_GENUI}: what a text channel draws with\n * (`catalog`, `channels`, `base`) and what the sandbox renderer is told (`sandboxClient`).\n */\nexport class AgentGenui {\n constructor(\n readonly catalog: Catalog,\n readonly resolveCatalog?: (scope: GenuiCatalogScope) => Catalog | Promise<Catalog>,\n /** `AgentGenuiModule.forRoot({ channels })`, when configured. */\n readonly channels?: GenuiChannels,\n /** The top-level options a channel falls back to. */\n readonly base: GenuiChannelBase = {},\n /** What the sandbox renderer is told, when a sandbox is configured. */\n readonly sandboxClient?: () => SandboxClientConfig,\n ) {}\n}\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 AGENT_GENUI,\n AgentGenui,\n AgentGenuiModule,\n type AgentGenuiModuleAsyncOptions,\n type AgentGenuiModuleOptions,\n type AgentGenuiOptions,\n type AgentGenuiSandboxKitOptions,\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":"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","names":["SANDBOX_KIT_DEV_PREFIX","SANDBOX_KIT_MANIFEST_KEYS","SANDBOX_KIT_UPDATE_EVENT","createGenuiSandboxKitPlugin","NEST_SANDBOX_KIT_DESCRIPTOR","resolve","sandboxKitDescriptorPath","sandboxKitDiscovery","nestSandboxKitDiscovery","options","name","manifest","NEST_SANDBOX_KIT_MANIFEST","root","process","cwd","undefined","descriptor","NEST_SANDBOX_KIT_DESCRIPTOR","file","outDir","kitUrl","cssUrl","tailwindUrl","production","Object","freeze","assertGenuiChannels","defineCatalog","defineSandbox","genuiTools","sandboxPolicyOf","Inject","Module","createFunctionalTool","AGENT_TOOL_BRAND","Symbol","for","brand","tool","spec","handler","provideAgentTools","factory","inject","provide","Symbol","useFactory","deps","map","brand","AGENT_GENUI","Symbol","for","AgentGenui","catalog","resolveCatalog","channels","base","sandboxClient","GENUI_CATALOG","Symbol","for","GENUI_OPTIONS","GENUI_RESOLVED","InjectGenuiCatalog","Inject","GenuiCatalogResolver","resolverProviders","resolver","undefined","provide","useClass","useValue","mergeSandboxClients","clients","merged","theme","client","one","name","kit","css","tailwind","resolveGenui","options","sandbox","asked","channels","askedChannels","assertGenuiChannels","discoveries","Map","resolveSandbox","value","nestSandboxKitDiscovery","resolveSandboxServer","Promise","all","kitName","discovery","get","sandboxKit","set","resolved","push","define","own","catalog","components","find","each","sandboxPolicyOf","ownOptions","sandboxOptions","sandboxView","entry","Object","entries","catalogSandbox","length","sandboxClient","perRequest","scope","resolve","toolOptions","_catalog","_sandbox","_channels","_sandboxKit","rest","resolveCatalog","withSandbox","base","defineCatalog","extend","defineSandbox","coreProviders","useFactory","inject","AGENT_GENUI","resolverInstance","AgentGenui","mode","streaming","token","optional","provideAgentTools","perRequestResolver","genuiTools","EXPORTS","AgentGenuiModule","forRoot","module","global","providers","exports","forRootAsync","imports"]}
@@ -2,7 +2,7 @@ import { A2uiStreamOptions, a2uiThreadReplay } from '@dudousxd/nestjs-agent-core
2
2
  import { AgentAttachmentConfig, AttachmentStagingStore, AgentStore, Actor, ListActionProposals, ActionProposalView, ActionProposalMutationView, TextActionProposalVocabulary, AgentRunner, ModelCatalog, QuotaProvider, ActionApprovalMode, MessageAttachment, QuotaReport, ModelCatalogView, AgentHostContext, AttachmentRef, PageContext, ChatQueueState, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, ActorResolver } from '@dudousxd/nestjs-agent-core';
3
3
  import { Request, Response } from 'express';
4
4
  import { UiCapabilities } from '@dudousxd/nestjs-agent-core/genui';
5
- import { b as AgentModuleOptions, A as AgentDepsFactory, C as ChatQueueService, d as AgentProtocolAdapter } from './chat-queue.service-wNWaoUN8.js';
5
+ import { b as AgentModuleOptions, A as AgentDepsFactory, C as ChatQueueService, d as AgentProtocolAdapter } from './chat-queue.service-CzXsKVb1.js';
6
6
 
7
7
  /** Default per-file size cap (20 MiB). */
8
8
  declare const DEFAULT_MAX_ATTACHMENT_BYTES: number;
@@ -2,7 +2,7 @@ import { A2uiStreamOptions, a2uiThreadReplay } from '@dudousxd/nestjs-agent-core
2
2
  import { AgentAttachmentConfig, AttachmentStagingStore, AgentStore, Actor, ListActionProposals, ActionProposalView, ActionProposalMutationView, TextActionProposalVocabulary, AgentRunner, ModelCatalog, QuotaProvider, ActionApprovalMode, MessageAttachment, QuotaReport, ModelCatalogView, AgentHostContext, AttachmentRef, PageContext, ChatQueueState, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, ActorResolver } from '@dudousxd/nestjs-agent-core';
3
3
  import { Request, Response } from 'express';
4
4
  import { UiCapabilities } from '@dudousxd/nestjs-agent-core/genui';
5
- import { b as AgentModuleOptions, A as AgentDepsFactory, C as ChatQueueService, d as AgentProtocolAdapter } from './chat-queue.service-QIuTS-5c.cjs';
5
+ import { b as AgentModuleOptions, A as AgentDepsFactory, C as ChatQueueService, d as AgentProtocolAdapter } from './chat-queue.service-CF2fcJDx.cjs';
6
6
 
7
7
  /** Default per-file size cap (20 MiB). */
8
8
  declare const DEFAULT_MAX_ATTACHMENT_BYTES: number;
package/dist/index.cjs CHANGED
@@ -4985,9 +4985,19 @@ var AgentDiscoveryService = class _AgentDiscoveryService {
4985
4985
  this.logger.warn(`Agent "${meta.name}" hands off to ${target.name}, which is not an @Agent \u2014 skipped.`);
4986
4986
  continue;
4987
4987
  }
4988
- edges.push(detached ? {
4988
+ const roles = typeof entry === "function" ? void 0 : entry.roles;
4989
+ const ability = typeof entry === "function" ? void 0 : entry.ability;
4990
+ edges.push(detached || roles !== void 0 || ability !== void 0 ? {
4989
4991
  agent: targetMeta.name,
4990
- detached: true
4992
+ ...detached ? {
4993
+ detached: true
4994
+ } : {},
4995
+ ...roles !== void 0 ? {
4996
+ roles
4997
+ } : {},
4998
+ ...ability !== void 0 ? {
4999
+ ability
5000
+ } : {}
4991
5001
  } : targetMeta.name);
4992
5002
  }
4993
5003
  return edges;
@@ -5199,7 +5209,7 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
5199
5209
  let delegates = 0;
5200
5210
  for (const definition of this.agents.list()) {
5201
5211
  for (const edge of definition.delegatesTo ?? []) {
5202
- const { agent: target, detached } = (0, import_nestjs_agent_core24.normalizeDelegation)(edge);
5212
+ const { agent: target, detached, roles, ability } = (0, import_nestjs_agent_core24.normalizeDelegation)(edge);
5203
5213
  const targetDefinition = this.agents.get(target);
5204
5214
  if (targetDefinition === void 0) {
5205
5215
  throw new Error(`Agent "${definition.name}" hands off to "${target}", which is not a registered @Agent. Declare it as an @Agent provider or fix the reference.`);
@@ -5221,6 +5231,12 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
5221
5231
  ...detached ? {
5222
5232
  detached: true
5223
5233
  } : {},
5234
+ ...roles !== void 0 ? {
5235
+ roles
5236
+ } : {},
5237
+ ...ability !== void 0 ? {
5238
+ ability
5239
+ } : {},
5224
5240
  description,
5225
5241
  inputSchema: import_zod.z.object({
5226
5242
  task: import_zod.z.string()
@@ -5633,6 +5649,35 @@ var ActionProposalWorkerService = class _ActionProposalWorkerService {
5633
5649
  worker;
5634
5650
  logger = new import_common25.Logger(_ActionProposalWorkerService.name);
5635
5651
  settledListeners = /* @__PURE__ */ new Set();
5652
+ admittedListeners = /* @__PURE__ */ new Set();
5653
+ /**
5654
+ * Run `listener` once a settled proposal's outcome is written to its thread by this process's
5655
+ * worker (the thread was free) — what a module uses to CONTINUE a conversation once an action it
5656
+ * proposed ran (a Poppy connect: the next turn goes on with what was asked). Next to
5657
+ * `actionProposalWorker.onAdmitted`; a listener that throws is logged and does not stop the
5658
+ * others. Returns the unsubscribe.
5659
+ */
5660
+ onAdmitted(listener) {
5661
+ this.admittedListeners.add(listener);
5662
+ return () => {
5663
+ this.admittedListeners.delete(listener);
5664
+ };
5665
+ }
5666
+ async admitted(outcome) {
5667
+ const configured = this.options.actionProposalWorker?.onAdmitted;
5668
+ for (const listener of [
5669
+ ...configured ? [
5670
+ configured
5671
+ ] : [],
5672
+ ...this.admittedListeners
5673
+ ]) {
5674
+ try {
5675
+ await listener(outcome);
5676
+ } catch (error) {
5677
+ this.logger.error(error);
5678
+ }
5679
+ }
5680
+ }
5636
5681
  /**
5637
5682
  * Run `listener` after every proposal this process's worker settles — how a module relays an
5638
5683
  * outcome somewhere the turn's stream no longer reaches (a text channel's conversation). Next to
@@ -5676,6 +5721,7 @@ var ActionProposalWorkerService = class _ActionProposalWorkerService {
5676
5721
  workerId: (0, import_node_crypto2.randomUUID)(),
5677
5722
  ...this.options.actionProposalWorker,
5678
5723
  onSettled: /* @__PURE__ */ __name((proposal) => this.settled(proposal), "onSettled"),
5724
+ onAdmitted: /* @__PURE__ */ __name((outcome) => this.admitted(outcome), "onAdmitted"),
5679
5725
  executor: new import_nestjs_agent_core30.ActionProposalExecutor({
5680
5726
  resolver,
5681
5727
  resolveExecution: /* @__PURE__ */ __name(async (proposal, actor) => {
@@ -6494,6 +6540,13 @@ function forwardingPolicy(wrapper) {
6494
6540
  throw new Error("AgentModule: the AGENT_ROLES_POLICY bound by another module is not ready yet");
6495
6541
  }
6496
6542
  return policy.can(actor, tool);
6543
+ },
6544
+ canOffer(actor, tool) {
6545
+ const policy = wrapper.instance;
6546
+ if (policy === void 0 || policy === null) {
6547
+ throw new Error("AgentModule: the AGENT_ROLES_POLICY bound by another module is not ready yet");
6548
+ }
6549
+ return policy.canOffer ? policy.canOffer(actor, tool) : policy.can(actor, tool);
6497
6550
  }
6498
6551
  };
6499
6552
  }
@@ -6535,7 +6588,14 @@ function sharedProviders(durable, engine) {
6535
6588
  // drift, and a user would be offered a skill the agent cannot reach. `undefined` when the
6536
6589
  // host configured none — which is what keeps the turn's checkpoint sequence unchanged.
6537
6590
  provide: import_nestjs_agent_core34.AGENT_SKILLS,
6538
- useFactory: /* @__PURE__ */ __name((options, declared) => resolveSkillsConfig(options.skills, declared), "useFactory"),
6591
+ // Personal agents resolve no skill scope (`personalAgentScopes`): nothing of the app's to load.
6592
+ useFactory: /* @__PURE__ */ __name((options, declared) => {
6593
+ const skills = resolveSkillsConfig(options.skills, declared);
6594
+ return skills === void 0 ? void 0 : {
6595
+ ...skills,
6596
+ scopes: (0, import_nestjs_agent_core34.personalAgentScopes)(skills.scopes)
6597
+ };
6598
+ }, "useFactory"),
6539
6599
  inject: [
6540
6600
  import_nestjs_agent_core34.AGENT_OPTIONS,
6541
6601
  import_nestjs_agent_core34.AGENT_SKILL_SOURCES
@@ -6545,7 +6605,12 @@ function sharedProviders(durable, engine) {
6545
6605
  // One resolution, shared by the loop's deps and the read-back endpoint: a person has to be
6546
6606
  // shown what the model was shown, and two resolutions would eventually disagree about that.
6547
6607
  provide: import_nestjs_agent_core34.AGENT_MEMORY,
6548
- useFactory: /* @__PURE__ */ __name((options) => options.memory, "useFactory"),
6608
+ // Personal agents resolve no memory scope (`personalAgentScopes`): under a signed-in Poppy
6609
+ // conversation the actor is the account, and it must neither read nor write its memories.
6610
+ useFactory: /* @__PURE__ */ __name((options) => options.memory === void 0 ? void 0 : {
6611
+ ...options.memory,
6612
+ scopes: (0, import_nestjs_agent_core34.personalAgentScopes)(options.memory.scopes)
6613
+ }, "useFactory"),
6549
6614
  inject: [
6550
6615
  import_nestjs_agent_core34.AGENT_OPTIONS
6551
6616
  ]
@@ -6559,7 +6624,10 @@ function sharedProviders(durable, engine) {
6559
6624
  },
6560
6625
  {
6561
6626
  provide: import_nestjs_agent_core34.AGENT_ROLES_POLICY,
6562
- useFactory: /* @__PURE__ */ __name((options, modules) => resolveRolesPolicy(options, modules), "useFactory"),
6627
+ // Personal agents (a Poppy conversation, a Poppy session's MCP token) reach only the tools
6628
+ // written for them, and run only those of the scopes their user granted. A no-op for every
6629
+ // other actor.
6630
+ useFactory: /* @__PURE__ */ __name((options, modules) => (0, import_nestjs_agent_core34.personalAgentGate)(resolveRolesPolicy(options, modules)), "useFactory"),
6563
6631
  inject: [
6564
6632
  import_nestjs_agent_core34.AGENT_OPTIONS,
6565
6633
  import_core4.ModulesContainer