@nestjs/ai 0.0.0-stage → 0.0.2

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.
Files changed (101) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +108 -2
  3. package/dist/ai.constants.d.ts +30 -0
  4. package/dist/ai.constants.js +34 -0
  5. package/dist/ai.module-definition.d.ts +23 -0
  6. package/dist/ai.module-definition.js +39 -0
  7. package/dist/ai.module.d.ts +11 -0
  8. package/dist/ai.module.js +45 -0
  9. package/dist/context/ai-execution-context.d.ts +32 -0
  10. package/dist/context/ai-execution-context.js +41 -0
  11. package/dist/context/ai-params.d.ts +20 -0
  12. package/dist/context/ai-params.js +44 -0
  13. package/dist/decorators/agent-function.decorator.d.ts +22 -0
  14. package/dist/decorators/agent-function.decorator.js +36 -0
  15. package/dist/decorators/index.d.ts +3 -0
  16. package/dist/decorators/index.js +3 -0
  17. package/dist/decorators/inject-embedding-model.decorator.d.ts +10 -0
  18. package/dist/decorators/inject-embedding-model.decorator.js +16 -0
  19. package/dist/decorators/inject-model.decorator.d.ts +10 -0
  20. package/dist/decorators/inject-model.decorator.js +16 -0
  21. package/dist/errors/ai.errors.d.ts +54 -0
  22. package/dist/errors/ai.errors.js +62 -0
  23. package/dist/errors/index.d.ts +1 -0
  24. package/dist/errors/index.js +1 -0
  25. package/dist/http/keep-alive.util.d.ts +6 -0
  26. package/dist/http/keep-alive.util.js +38 -0
  27. package/dist/http/node-response.util.d.ts +14 -0
  28. package/dist/http/node-response.util.js +104 -0
  29. package/dist/index.d.ts +14 -0
  30. package/dist/index.js +16 -0
  31. package/dist/interfaces/agent-function.interface.d.ts +53 -0
  32. package/dist/interfaces/agent-function.interface.js +1 -0
  33. package/dist/interfaces/ai-call-options.interface.d.ts +65 -0
  34. package/dist/interfaces/ai-call-options.interface.js +1 -0
  35. package/dist/interfaces/ai-embedding.interface.d.ts +79 -0
  36. package/dist/interfaces/ai-embedding.interface.js +1 -0
  37. package/dist/interfaces/ai-module-options.interface.d.ts +110 -0
  38. package/dist/interfaces/ai-module-options.interface.js +1 -0
  39. package/dist/interfaces/ai-result.interface.d.ts +57 -0
  40. package/dist/interfaces/ai-result.interface.js +1 -0
  41. package/dist/interfaces/ai-schema.interface.d.ts +44 -0
  42. package/dist/interfaces/ai-schema.interface.js +1 -0
  43. package/dist/interfaces/ai-tool.interface.d.ts +22 -0
  44. package/dist/interfaces/ai-tool.interface.js +1 -0
  45. package/dist/interfaces/ai-usage.interface.d.ts +30 -0
  46. package/dist/interfaces/ai-usage.interface.js +1 -0
  47. package/dist/interfaces/index.d.ts +8 -0
  48. package/dist/interfaces/index.js +8 -0
  49. package/dist/models/ai-embedding-models.service.d.ts +31 -0
  50. package/dist/models/ai-embedding-models.service.js +138 -0
  51. package/dist/models/ai-models.service.d.ts +29 -0
  52. package/dist/models/ai-models.service.js +112 -0
  53. package/dist/models/model-registry.util.d.ts +6 -0
  54. package/dist/models/model-registry.util.js +21 -0
  55. package/dist/models/model-requests.d.ts +5 -0
  56. package/dist/models/model-requests.js +20 -0
  57. package/dist/runtime/agent-loop.d.ts +30 -0
  58. package/dist/runtime/agent-loop.js +81 -0
  59. package/dist/runtime/call-plan.d.ts +54 -0
  60. package/dist/runtime/call-plan.js +105 -0
  61. package/dist/runtime/embedding-call.d.ts +38 -0
  62. package/dist/runtime/embedding-call.js +120 -0
  63. package/dist/runtime/model-policy.d.ts +53 -0
  64. package/dist/runtime/model-policy.js +202 -0
  65. package/dist/runtime/steps.d.ts +32 -0
  66. package/dist/runtime/steps.js +190 -0
  67. package/dist/runtime/text-stream.d.ts +64 -0
  68. package/dist/runtime/text-stream.js +211 -0
  69. package/dist/services/ai.service.d.ts +70 -0
  70. package/dist/services/ai.service.js +183 -0
  71. package/dist/testing/fake-embedding-model.d.ts +57 -0
  72. package/dist/testing/fake-embedding-model.js +82 -0
  73. package/dist/testing/fake-model.d.ts +96 -0
  74. package/dist/testing/fake-model.js +201 -0
  75. package/dist/testing/index.d.ts +32 -0
  76. package/dist/testing/index.js +27 -0
  77. package/dist/tools/ai-tools.service.d.ts +77 -0
  78. package/dist/tools/ai-tools.service.js +234 -0
  79. package/dist/tools/tool-output.util.d.ts +6 -0
  80. package/dist/tools/tool-output.util.js +38 -0
  81. package/dist/utils/duration.util.d.ts +3 -0
  82. package/dist/utils/duration.util.js +17 -0
  83. package/dist/utils/errors.util.d.ts +16 -0
  84. package/dist/utils/errors.util.js +35 -0
  85. package/dist/utils/names.util.d.ts +2 -0
  86. package/dist/utils/names.util.js +10 -0
  87. package/dist/utils/schema.util.d.ts +16 -0
  88. package/dist/utils/schema.util.js +70 -0
  89. package/dist/utils/usage.util.d.ts +10 -0
  90. package/dist/utils/usage.util.js +42 -0
  91. package/dist/workflows/ai-agent.interfaces.d.ts +70 -0
  92. package/dist/workflows/ai-agent.interfaces.js +1 -0
  93. package/dist/workflows/ai-agent.workflow.d.ts +15 -0
  94. package/dist/workflows/ai-agent.workflow.js +25 -0
  95. package/dist/workflows/ai-agents.service.d.ts +83 -0
  96. package/dist/workflows/ai-agents.service.js +277 -0
  97. package/dist/workflows/ai-workflows.module.d.ts +6 -0
  98. package/dist/workflows/ai-workflows.module.js +22 -0
  99. package/dist/workflows/index.d.ts +6 -0
  100. package/dist/workflows/index.js +5 -0
  101. package/package.json +115 -4
package/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2026 Kamil Mysliwiec
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
package/README.md CHANGED
@@ -1,3 +1,109 @@
1
- # Temporary Holding Version
1
+ <p align="center">
2
+ <a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
3
+ </p>
2
4
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
5
+ [travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master
6
+ [travis-url]: https://travis-ci.org/nestjs/nest
7
+ [linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux
8
+ [linux-url]: https://travis-ci.org/nestjs/nest
9
+
10
+ <p align="center">A progressive <a href="http://nodejs.org" target="blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
13
+ <a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
14
+ <a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/dm/@nestjs/core.svg" alt="NPM Downloads" /></a>
15
+ <a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
16
+ <a href="https://opencollective.com/nest#backer"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
17
+ <a href="https://opencollective.com/nest#sponsor"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
18
+ <a href="https://paypal.me/kamilmysliwiec"><img src="https://img.shields.io/badge/Donate-PayPal-dc3d53.svg"/></a>
19
+ <a href="https://twitter.com/nestframework"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
20
+ </p>
21
+ <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
22
+ [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
23
+
24
+ ## Description
25
+
26
+ Language models for [Nest](https://github.com/nestjs/nest): named models through dependency injection, model calls with timeouts, retries and fallback models (run on [`@nestjs/resilience`](https://github.com/nestjs/resilience) policies, or your own), budgets and usage events, structured output validated by a schema, the application's own provider methods as agent functions its agents call (through Nest's guards, interceptors, pipes and exception filters, as the user the agent acts for), answers streamed to the browser on Express, Fastify and the Node adapter, and durable agent runs on [`@nestjs/workflows`](https://github.com/nestjs/workflows) (`@nestjs/ai/workflows`) that survive restarts and wait for a person's approval. You write an agent function with `@AgentFunction()`, and the model is offered it as a tool; a method can be an MCP tool too, served by [`@nestjs/mcp`](https://github.com/nestjs/mcp), with its `@Tool()` stacked on it. Embedding models have their own named registry, dependency injection, resilient single and batch calls, and usage events. Comes with fake language and embedding models for tests. Built on the [AI SDK](https://ai-sdk.dev) (`ai`) and its provider packages.
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ $ npm i --save @nestjs/ai @nestjs/resilience ai @ai-sdk/anthropic zod
32
+ ```
33
+
34
+ Any `@ai-sdk/*` provider package works (`@ai-sdk/openai`, `@ai-sdk/google`, ...). Zod 4.2 or later for the schemas; any other [Standard Schema](https://standardschema.dev) library that produces JSON Schema works too. Node.js 22 or later.
35
+
36
+ Each major version of `@nestjs/ai` supports one major version of the AI SDK: this one, `ai` 7.
37
+
38
+ ## Quick Start
39
+
40
+ Register the models, and call them:
41
+
42
+ ```ts
43
+ import { anthropic } from '@ai-sdk/anthropic';
44
+ import { Injectable, Module } from '@nestjs/common';
45
+ import { AgentFunction, AiModule, AiService, type AgentFunctionContext } from '@nestjs/ai';
46
+ import * as z from 'zod';
47
+
48
+ @Injectable()
49
+ export class OrdersTools {
50
+ constructor(private readonly orders: OrdersService) {}
51
+
52
+ @AgentFunction({
53
+ name: 'find-order',
54
+ description: 'Find an order by its id',
55
+ inputSchema: z.object({ orderId: z.string() }),
56
+ })
57
+ find({ orderId }: { orderId: string }, ctx: AgentFunctionContext) {
58
+ return this.orders.findFor(ctx.request?.user, orderId);
59
+ }
60
+ }
61
+
62
+ @Injectable()
63
+ export class SupportService {
64
+ constructor(private readonly ai: AiService) {}
65
+
66
+ async answer(question: string, request: unknown) {
67
+ const { text } = await this.ai.generateText({
68
+ prompt: question,
69
+ tools: ['find-order'],
70
+ caller: { request },
71
+ });
72
+ return text;
73
+ }
74
+ }
75
+
76
+ @Module({
77
+ imports: [
78
+ AiModule.forRoot({
79
+ models: {
80
+ default: anthropic('claude-opus-5-5'),
81
+ fast: anthropic('claude-haiku-5-5'),
82
+ },
83
+ defaults: { timeout: '30s', retry: { attempts: 3 } },
84
+ }),
85
+ ],
86
+ providers: [OrdersService, OrdersTools, SupportService],
87
+ })
88
+ export class AppModule {}
89
+ ```
90
+
91
+ A method that MCP clients call too also carries `@nestjs/mcp`'s `@Tool()`, with options of its own: the two decorators don't read each other's, and one schema constant serves both. `generateObject({ schema })` answers a typed object, and `streamText()` an answer a controller sends to the browser with `pipeUIMessageStreamToResponse(res)`, as the AI SDK's `useChat()` reads it. Agent function calls run through the guards, interceptors, pipes and filters of the class and the method, with the context type `'ai'`, so `AiExecutionContext` reads them in enhancers (on a method with both decorators, they see `'mcp'` for MCP clients' calls), and `@nestjs/authentication` (0.1.4 or later) and `@nestjs/authorization` (0.1.2 or later) authenticate and authorize them. `@nestjs/ai/testing` has `FakeModel`, which answers with text, tool calls, objects or errors, without a network.
92
+
93
+ The [sample](sample) is a cat store: it triages support emails, and runs a chat assistant that calls the same `find-order` method its MCP server serves. `npm run build && npx tsc -p sample/tsconfig.json`, then `node sample/dist/main.js` (with `ANTHROPIC_API_KEY` set, Claude answers; without it, fake models do).
94
+
95
+ Read [Overview](https://docs.nestjs.com/ai/overview) to get started and for the module's options, [Models](https://docs.nestjs.com/ai/models) for retries, timeouts, fallback models and budgets, [Tools](https://docs.nestjs.com/ai/tools) for agent functions, the call context, guards and authorization, [Agents](https://docs.nestjs.com/ai/agents) for the agent loop, streaming to the browser and durable runs, and [Testing](https://docs.nestjs.com/ai/testing) for the fake model.
96
+
97
+ ## Support
98
+
99
+ Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
100
+
101
+ ## Stay in touch
102
+
103
+ - Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
104
+ - Website - [https://nestjs.com](https://nestjs.com/)
105
+ - Twitter - [@nestframework](https://twitter.com/nestframework)
106
+
107
+ ## License
108
+
109
+ Nest is [MIT licensed](LICENSE).
@@ -0,0 +1,30 @@
1
+ /** The module options (`forRoot()`'s, or what the `forRootAsync()` factory returns). */
2
+ export declare const AI_MODULE_OPTIONS = "AI_MODULE_OPTIONS";
3
+ /** Where `@AgentFunction()` records its options, on the method. */
4
+ export declare const AGENT_FUNCTION_METADATA = "nestjs:ai:agent-function";
5
+ /**
6
+ * The `ExecutionContext` type of agent function calls: `context.getType() === 'ai'` in a guard, an interceptor or an
7
+ * exception filter, which reads the call with `AiExecutionContext`.
8
+ */
9
+ export declare const AI_CONTEXT_TYPE = "ai";
10
+ /**
11
+ * The parameter metadata of agent functions, read by `ExternalContextCreator` (so that pipes run on the input): Nest's
12
+ * own route-arguments key, where `createParamDecorator()` decorators record themselves. `@nestjs/mcp` records the two
13
+ * parameters of its methods under the same key, with the same numbers (`AiParamtype`), so a method that is both an
14
+ * agent function and an MCP tool is recorded once, and both read it.
15
+ */
16
+ export declare const AI_PARAMS_METADATA = "__routeArguments__";
17
+ /** The name of the model calls use when they name none. */
18
+ export declare const DEFAULT_MODEL_NAME = "default";
19
+ /** Models that replace configured ones by name, from `@nestjs/ai/testing`'s `overrideModels()`. Internal. */
20
+ export declare const AI_MODEL_OVERRIDES: unique symbol;
21
+ /**
22
+ * Embedding-model replacements from `@nestjs/ai/testing`'s `overrideEmbeddingModels()`. Internal.
23
+ */
24
+ export declare const AI_EMBEDDING_MODEL_OVERRIDES: unique symbol;
25
+ /** The injection token of the model called `name`, which `@InjectModel(name)` injects. */
26
+ export declare function getModelToken(name?: string): string;
27
+ /**
28
+ * The injection token of the embedding model called `name`, independent of language-model names.
29
+ */
30
+ export declare function getEmbeddingModelToken(name?: string): string;
@@ -0,0 +1,34 @@
1
+ /** The module options (`forRoot()`'s, or what the `forRootAsync()` factory returns). */
2
+ export const AI_MODULE_OPTIONS = 'AI_MODULE_OPTIONS';
3
+ /** Where `@AgentFunction()` records its options, on the method. */
4
+ export const AGENT_FUNCTION_METADATA = 'nestjs:ai:agent-function';
5
+ /**
6
+ * The `ExecutionContext` type of agent function calls: `context.getType() === 'ai'` in a guard, an interceptor or an
7
+ * exception filter, which reads the call with `AiExecutionContext`.
8
+ */
9
+ export const AI_CONTEXT_TYPE = 'ai';
10
+ /**
11
+ * The parameter metadata of agent functions, read by `ExternalContextCreator` (so that pipes run on the input): Nest's
12
+ * own route-arguments key, where `createParamDecorator()` decorators record themselves. `@nestjs/mcp` records the two
13
+ * parameters of its methods under the same key, with the same numbers (`AiParamtype`), so a method that is both an
14
+ * agent function and an MCP tool is recorded once, and both read it.
15
+ */
16
+ export const AI_PARAMS_METADATA = '__routeArguments__';
17
+ /** The name of the model calls use when they name none. */
18
+ export const DEFAULT_MODEL_NAME = 'default';
19
+ /** Models that replace configured ones by name, from `@nestjs/ai/testing`'s `overrideModels()`. Internal. */
20
+ export const AI_MODEL_OVERRIDES = Symbol('AI_MODEL_OVERRIDES');
21
+ /**
22
+ * Embedding-model replacements from `@nestjs/ai/testing`'s `overrideEmbeddingModels()`. Internal.
23
+ */
24
+ export const AI_EMBEDDING_MODEL_OVERRIDES = Symbol('AI_EMBEDDING_MODEL_OVERRIDES');
25
+ /** The injection token of the model called `name`, which `@InjectModel(name)` injects. */
26
+ export function getModelToken(name = DEFAULT_MODEL_NAME) {
27
+ return `nestjs:ai:model:${name}`;
28
+ }
29
+ /**
30
+ * The injection token of the embedding model called `name`, independent of language-model names.
31
+ */
32
+ export function getEmbeddingModelToken(name = DEFAULT_MODEL_NAME) {
33
+ return `nestjs:ai:embedding-model:${name}`;
34
+ }
@@ -0,0 +1,23 @@
1
+ import { type ConfigurableModuleAsyncOptions } from '@nestjs/common';
2
+ import type { AiModuleOptions, AiModuleStructure, AiOptionsFactory } from './interfaces/ai-module-options.interface.js';
3
+ import { AI_MODULE_OPTIONS } from './ai.constants.js';
4
+ /** `forRoot()`'s options: the module options, and `isGlobal` (default false). */
5
+ export type AiModuleRootOptions = AiModuleOptions & {
6
+ isGlobal?: boolean;
7
+ };
8
+ /**
9
+ * What `forRootAsync()` takes: `modelNames`, `embeddingModelNames` and `isGlobal` at the top level, and one of
10
+ * `useFactory`, `useClass` or `useExisting` for the options.
11
+ */
12
+ export type AiModuleAsyncOptions = ConfigurableModuleAsyncOptions<AiModuleOptions, 'createAiOptions'> & AiModuleStructure & {
13
+ isGlobal?: boolean;
14
+ };
15
+ export type { AiOptionsFactory };
16
+ export { AI_MODULE_OPTIONS };
17
+ export declare const ConfigurableModuleClass: import("@nestjs/common").ConfigurableModuleCls<AiModuleOptions, "forRoot", "createAiOptions", AiModuleStructure & {
18
+ isGlobal?: boolean;
19
+ }>, OPTIONS_TYPE: AiModuleOptions & Partial<AiModuleStructure & {
20
+ isGlobal?: boolean;
21
+ }>, ASYNC_OPTIONS_TYPE: ConfigurableModuleAsyncOptions<AiModuleOptions, "createAiOptions"> & Partial<AiModuleStructure & {
22
+ isGlobal?: boolean;
23
+ }>;
@@ -0,0 +1,39 @@
1
+ import { ConfigurableModuleBuilder, Scope } from '@nestjs/common';
2
+ import { INQUIRER } from '@nestjs/core';
3
+ import { AI_MODULE_OPTIONS, getEmbeddingModelToken, getModelToken } from './ai.constants.js';
4
+ import { AiModels } from './models/ai-models.service.js';
5
+ import { AiEmbeddingModels } from './models/ai-embedding-models.service.js';
6
+ import { requestedEmbeddingModelNames, requestedModelNames } from './models/model-requests.js';
7
+ export { AI_MODULE_OPTIONS };
8
+ export const { ConfigurableModuleClass, OPTIONS_TYPE, ASYNC_OPTIONS_TYPE } = new ConfigurableModuleBuilder({
9
+ moduleName: 'Ai',
10
+ optionsInjectionToken: AI_MODULE_OPTIONS,
11
+ })
12
+ .setClassMethodName('forRoot')
13
+ .setFactoryMethodName('createAiOptions')
14
+ .setExtras({ isGlobal: false, modelNames: undefined, embeddingModelNames: undefined }, (definition, { isGlobal, modelNames, embeddingModelNames }) => {
15
+ const names = new Set([...(modelNames ?? []), ...requestedModelNames()]);
16
+ // Transient, so that each class that injects a model is known (INQUIRER), and one that asks for a model the
17
+ // module does not configure is named in the error.
18
+ const tokens = [...names].map((name) => ({
19
+ provide: getModelToken(name),
20
+ scope: Scope.TRANSIENT,
21
+ inject: [AiModels, INQUIRER],
22
+ useFactory: (models, inquirer) => models.injected(name, inquirer),
23
+ }));
24
+ const embeddingNames = new Set([...(embeddingModelNames ?? []), ...requestedEmbeddingModelNames()]);
25
+ const embeddingTokens = [...embeddingNames].map((name) => ({
26
+ provide: getEmbeddingModelToken(name),
27
+ scope: Scope.TRANSIENT,
28
+ inject: [AiEmbeddingModels, INQUIRER],
29
+ useFactory: (models, inquirer) => models.injected(name, inquirer),
30
+ }));
31
+ const allTokens = [...tokens, ...embeddingTokens];
32
+ return {
33
+ ...definition,
34
+ global: isGlobal,
35
+ providers: [...(definition.providers ?? []), ...allTokens],
36
+ exports: [...(definition.exports ?? []), ...allTokens.map((provider) => provider.provide)],
37
+ };
38
+ })
39
+ .build();
@@ -0,0 +1,11 @@
1
+ import { type DynamicModule } from '@nestjs/common';
2
+ import { ConfigurableModuleClass, type AiModuleAsyncOptions, type AiModuleRootOptions } from './ai.module-definition.js';
3
+ /**
4
+ * `AiModule.forRoot({ models: { default: ... } })`, or `forRootAsync({ imports, inject, useFactory })`: the
5
+ * application's models by name, `AiService` for model calls, and the `@AgentFunction()` methods of its providers,
6
+ * which its agents call as tools. Global with `isGlobal: true`.
7
+ */
8
+ export declare class AiModule extends ConfigurableModuleClass {
9
+ static forRoot(options: AiModuleRootOptions): DynamicModule;
10
+ static forRootAsync(options: AiModuleAsyncOptions): DynamicModule;
11
+ }
@@ -0,0 +1,45 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Module } from '@nestjs/common';
8
+ import { DiscoveryModule } from '@nestjs/core';
9
+ import { AI_EMBEDDING_MODEL_OVERRIDES, AI_MODEL_OVERRIDES } from './ai.constants.js';
10
+ import { ConfigurableModuleClass, } from './ai.module-definition.js';
11
+ import { AiModels } from './models/ai-models.service.js';
12
+ import { AiEmbeddingModels } from './models/ai-embedding-models.service.js';
13
+ import { AiService } from './services/ai.service.js';
14
+ import { AiTools } from './tools/ai-tools.service.js';
15
+ /**
16
+ * `AiModule.forRoot({ models: { default: ... } })`, or `forRootAsync({ imports, inject, useFactory })`: the
17
+ * application's models by name, `AiService` for model calls, and the `@AgentFunction()` methods of its providers,
18
+ * which its agents call as tools. Global with `isGlobal: true`.
19
+ */
20
+ let AiModule = class AiModule extends ConfigurableModuleClass {
21
+ static forRoot(options) {
22
+ // `@InjectModel()` may ask for every model `forRoot()` names.
23
+ const modelNames = Object.keys(options?.models ?? {});
24
+ const embeddingModelNames = Object.keys(options?.embeddingModels ?? {});
25
+ return super.forRoot({ ...options, modelNames, embeddingModelNames });
26
+ }
27
+ static forRootAsync(options) {
28
+ return super.forRootAsync(options);
29
+ }
30
+ };
31
+ AiModule = __decorate([
32
+ Module({
33
+ imports: [DiscoveryModule],
34
+ providers: [
35
+ AiModels,
36
+ AiEmbeddingModels,
37
+ AiTools,
38
+ AiService,
39
+ { provide: AI_MODEL_OVERRIDES, useValue: null },
40
+ { provide: AI_EMBEDDING_MODEL_OVERRIDES, useValue: null },
41
+ ],
42
+ exports: [AiModels, AiEmbeddingModels, AiTools, AiService],
43
+ })
44
+ ], AiModule);
45
+ export { AiModule };
@@ -0,0 +1,32 @@
1
+ import type { ArgumentsHost, ExecutionContext } from '@nestjs/common';
2
+ import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host.js';
3
+ import type { AgentFunctionContext } from '../interfaces/agent-function.interface.js';
4
+ /** `context.getType<AiContextType>() === 'ai'` in an enhancer tells an agent function call from an HTTP request. */
5
+ export type AiContextType = 'ai';
6
+ /**
7
+ * The execution context of an agent function call, for guards, interceptors and exception filters, as
8
+ * `McpExecutionContext` is for MCP calls:
9
+ *
10
+ * ```ts
11
+ * canActivate(context: ExecutionContext) {
12
+ * if (context.getType<AiContextType>() !== 'ai') {
13
+ * return true;
14
+ * }
15
+ * const call = AiExecutionContext.create(context);
16
+ * return call.getRequest()?.user?.role === 'support';
17
+ * }
18
+ * ```
19
+ *
20
+ * The arguments of an agent function call are `[input, context]`: `getInput()` (also `switchToRpc().getData()`) and
21
+ * `getContext()`.
22
+ */
23
+ export declare class AiExecutionContext extends ExecutionContextHost {
24
+ static create(context: ExecutionContext | ArgumentsHost): AiExecutionContext;
25
+ /** The arguments, validated against the function's `inputSchema`. */
26
+ getInput<T = any>(): T;
27
+ getContext<TRequest = any, TUser = any>(): AgentFunctionContext<TRequest, TUser>;
28
+ /** The agent function's name. */
29
+ getName(): string | undefined;
30
+ /** The HTTP platform's request the agent runs in (`caller.request`); `undefined` where there is none, as in a job. */
31
+ getRequest<TRequest = any>(): TRequest | undefined;
32
+ }
@@ -0,0 +1,41 @@
1
+ import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host.js';
2
+ /**
3
+ * The execution context of an agent function call, for guards, interceptors and exception filters, as
4
+ * `McpExecutionContext` is for MCP calls:
5
+ *
6
+ * ```ts
7
+ * canActivate(context: ExecutionContext) {
8
+ * if (context.getType<AiContextType>() !== 'ai') {
9
+ * return true;
10
+ * }
11
+ * const call = AiExecutionContext.create(context);
12
+ * return call.getRequest()?.user?.role === 'support';
13
+ * }
14
+ * ```
15
+ *
16
+ * The arguments of an agent function call are `[input, context]`: `getInput()` (also `switchToRpc().getData()`) and
17
+ * `getContext()`.
18
+ */
19
+ export class AiExecutionContext extends ExecutionContextHost {
20
+ static create(context) {
21
+ const host = context;
22
+ const ai = new AiExecutionContext(context.getArgs(), host.getClass?.(), host.getHandler?.());
23
+ ai.setType(context.getType());
24
+ return ai;
25
+ }
26
+ /** The arguments, validated against the function's `inputSchema`. */
27
+ getInput() {
28
+ return this.getArgByIndex(0);
29
+ }
30
+ getContext() {
31
+ return this.getArgByIndex(1);
32
+ }
33
+ /** The agent function's name. */
34
+ getName() {
35
+ return this.getContext()?.name;
36
+ }
37
+ /** The HTTP platform's request the agent runs in (`caller.request`); `undefined` where there is none, as in a job. */
38
+ getRequest() {
39
+ return this.getContext()?.request;
40
+ }
41
+ }
@@ -0,0 +1,20 @@
1
+ import type { ParamsFactory } from '@nestjs/core';
2
+ /**
3
+ * The parameters of an agent function. Pipes see the input as a `body` parameter (so `ValidationPipe` validates a DTO
4
+ * class) and the context as a `custom` one (which it skips). The numbers are `@nestjs/mcp`'s, and must stay so: a
5
+ * method that is an MCP tool too has its parameters recorded once, under the key both packages read, and either
6
+ * package's factory reads them.
7
+ */
8
+ export declare enum AiParamtype {
9
+ INPUT = 3,
10
+ CONTEXT = 1001
11
+ }
12
+ export declare class AiParamsFactory implements ParamsFactory {
13
+ exchangeKeyForValue(type: number, data: unknown, args: unknown[]): unknown;
14
+ }
15
+ /**
16
+ * Records the two parameters of an agent function, `(input, context)`, as parameter metadata, where no parameter
17
+ * decorator took their place. `ExternalContextCreator` runs pipes only on parameters it has metadata for, and calls
18
+ * the method with those alone: custom decorators (`createParamDecorator()`) on other parameters keep theirs.
19
+ */
20
+ export declare function recordHandlerParams(target: Function, methodName: string): void;
@@ -0,0 +1,44 @@
1
+ import { RouteParamtypes } from '@nestjs/common/enums/route-paramtypes.enum.js';
2
+ import { AI_PARAMS_METADATA } from '../ai.constants.js';
3
+ /**
4
+ * The parameters of an agent function. Pipes see the input as a `body` parameter (so `ValidationPipe` validates a DTO
5
+ * class) and the context as a `custom` one (which it skips). The numbers are `@nestjs/mcp`'s, and must stay so: a
6
+ * method that is an MCP tool too has its parameters recorded once, under the key both packages read, and either
7
+ * package's factory reads them.
8
+ */
9
+ export var AiParamtype;
10
+ (function (AiParamtype) {
11
+ AiParamtype[AiParamtype["INPUT"] = 3] = "INPUT";
12
+ AiParamtype[AiParamtype["CONTEXT"] = 1001] = "CONTEXT";
13
+ })(AiParamtype || (AiParamtype = {}));
14
+ export class AiParamsFactory {
15
+ exchangeKeyForValue(type, data, args) {
16
+ switch (type) {
17
+ case AiParamtype.INPUT: {
18
+ const input = args[0];
19
+ return typeof data === 'string' && input ? input[data] : input;
20
+ }
21
+ case AiParamtype.CONTEXT:
22
+ return args[1];
23
+ default:
24
+ return null;
25
+ }
26
+ }
27
+ }
28
+ /**
29
+ * Records the two parameters of an agent function, `(input, context)`, as parameter metadata, where no parameter
30
+ * decorator took their place. `ExternalContextCreator` runs pipes only on parameters it has metadata for, and calls
31
+ * the method with those alone: custom decorators (`createParamDecorator()`) on other parameters keep theirs.
32
+ */
33
+ export function recordHandlerParams(target, methodName) {
34
+ const existing = Reflect.getMetadata(AI_PARAMS_METADATA, target, methodName) ?? {};
35
+ const taken = new Set(Object.values(existing).map((param) => param.index));
36
+ if (taken.has(0) && taken.has(1)) {
37
+ return;
38
+ }
39
+ Reflect.defineMetadata(AI_PARAMS_METADATA, {
40
+ ...existing,
41
+ ...(!taken.has(0) && { [`${AiParamtype.INPUT}:0`]: { index: 0, data: undefined, pipes: [] } }),
42
+ ...(!taken.has(1) && { [`${AiParamtype.CONTEXT}:1`]: { index: 1, data: undefined, pipes: [] } }),
43
+ }, target, methodName);
44
+ }
@@ -0,0 +1,22 @@
1
+ import type { AgentFunctionOptions } from '../interfaces/agent-function.interface.js';
2
+ /**
3
+ * Makes the method an agent function: one the application's agents may call, which a call lists in `tools`, and the
4
+ * model is offered as a tool. It is called as `(input, context)`: `input` is the arguments, validated against
5
+ * `inputSchema`, and `context` the `AgentFunctionContext`. Guards, interceptors, pipes and exception filters run
6
+ * around it, with the context type `'ai'` (`AiExecutionContext` reads the call).
7
+ *
8
+ * ```ts
9
+ * @AgentFunction({
10
+ * name: 'find-order',
11
+ * description: 'Find an order by its id',
12
+ * inputSchema: z.object({ orderId: z.string() }),
13
+ * })
14
+ * find({ orderId }: { orderId: string }, ctx: AgentFunctionContext) {
15
+ * return this.orders.find(orderId);
16
+ * }
17
+ * ```
18
+ *
19
+ * A method that MCP clients call too also carries `@nestjs/mcp`'s `@Tool()`, with options of its own: neither
20
+ * decorator reads the other's.
21
+ */
22
+ export declare function AgentFunction(options?: AgentFunctionOptions): MethodDecorator;
@@ -0,0 +1,36 @@
1
+ import { AGENT_FUNCTION_METADATA } from '../ai.constants.js';
2
+ /**
3
+ * Makes the method an agent function: one the application's agents may call, which a call lists in `tools`, and the
4
+ * model is offered as a tool. It is called as `(input, context)`: `input` is the arguments, validated against
5
+ * `inputSchema`, and `context` the `AgentFunctionContext`. Guards, interceptors, pipes and exception filters run
6
+ * around it, with the context type `'ai'` (`AiExecutionContext` reads the call).
7
+ *
8
+ * ```ts
9
+ * @AgentFunction({
10
+ * name: 'find-order',
11
+ * description: 'Find an order by its id',
12
+ * inputSchema: z.object({ orderId: z.string() }),
13
+ * })
14
+ * find({ orderId }: { orderId: string }, ctx: AgentFunctionContext) {
15
+ * return this.orders.find(orderId);
16
+ * }
17
+ * ```
18
+ *
19
+ * A method that MCP clients call too also carries `@nestjs/mcp`'s `@Tool()`, with options of its own: neither
20
+ * decorator reads the other's.
21
+ */
22
+ export function AgentFunction(options = {}) {
23
+ const metadata = { ...options };
24
+ return (target, key, descriptor) => {
25
+ const method = descriptor.value;
26
+ const where = `${typeof target === 'function' ? target.name : target.constructor.name}.${String(key)}`;
27
+ if (typeof method !== 'function') {
28
+ throw new TypeError(`@AgentFunction() goes on a method, and ${where} is not one.`);
29
+ }
30
+ if (Reflect.hasOwnMetadata(AGENT_FUNCTION_METADATA, method)) {
31
+ throw new TypeError(`${where} has @AgentFunction() twice: give it one, with all its options.`);
32
+ }
33
+ Reflect.defineMetadata(AGENT_FUNCTION_METADATA, metadata, method);
34
+ return descriptor;
35
+ };
36
+ }
@@ -0,0 +1,3 @@
1
+ export * from './agent-function.decorator.js';
2
+ export * from './inject-model.decorator.js';
3
+ export * from './inject-embedding-model.decorator.js';
@@ -0,0 +1,3 @@
1
+ export * from './agent-function.decorator.js';
2
+ export * from './inject-model.decorator.js';
3
+ export * from './inject-embedding-model.decorator.js';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Injects the configured `EmbeddingModel` called `name` (default `'default'`), for code that calls
3
+ * `ai` directly. Direct SDK calls do not get `AiService`'s resilience or usage events. An unknown
4
+ * name fails at startup.
5
+ *
6
+ * ```ts
7
+ * constructor(@InjectEmbeddingModel('documents') private readonly model: EmbeddingModel) {}
8
+ * ```
9
+ */
10
+ export declare function InjectEmbeddingModel(name?: string): PropertyDecorator & ParameterDecorator;
@@ -0,0 +1,16 @@
1
+ import { Inject } from '@nestjs/common';
2
+ import { DEFAULT_MODEL_NAME, getEmbeddingModelToken } from '../ai.constants.js';
3
+ import { recordEmbeddingModelRequest } from '../models/model-requests.js';
4
+ /**
5
+ * Injects the configured `EmbeddingModel` called `name` (default `'default'`), for code that calls
6
+ * `ai` directly. Direct SDK calls do not get `AiService`'s resilience or usage events. An unknown
7
+ * name fails at startup.
8
+ *
9
+ * ```ts
10
+ * constructor(@InjectEmbeddingModel('documents') private readonly model: EmbeddingModel) {}
11
+ * ```
12
+ */
13
+ export function InjectEmbeddingModel(name = DEFAULT_MODEL_NAME) {
14
+ recordEmbeddingModelRequest(name);
15
+ return Inject(getEmbeddingModelToken(name));
16
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Injects the configured `LanguageModel` called `name` (default `'default'`), for code that calls `ai` itself.
3
+ * `AiService` calls get retries, timeouts, fallback and usage events; a direct `ai` call gets none of them. A name
4
+ * the module does not configure fails at startup.
5
+ *
6
+ * ```ts
7
+ * constructor(@InjectModel('fast') private readonly model: LanguageModel) {}
8
+ * ```
9
+ */
10
+ export declare function InjectModel(name?: string): PropertyDecorator & ParameterDecorator;
@@ -0,0 +1,16 @@
1
+ import { Inject } from '@nestjs/common';
2
+ import { DEFAULT_MODEL_NAME, getModelToken } from '../ai.constants.js';
3
+ import { recordModelRequest } from '../models/model-requests.js';
4
+ /**
5
+ * Injects the configured `LanguageModel` called `name` (default `'default'`), for code that calls `ai` itself.
6
+ * `AiService` calls get retries, timeouts, fallback and usage events; a direct `ai` call gets none of them. A name
7
+ * the module does not configure fails at startup.
8
+ *
9
+ * ```ts
10
+ * constructor(@InjectModel('fast') private readonly model: LanguageModel) {}
11
+ * ```
12
+ */
13
+ export function InjectModel(name = DEFAULT_MODEL_NAME) {
14
+ recordModelRequest(name);
15
+ return Inject(getModelToken(name));
16
+ }