@nestjs/ai 0.0.0-stage → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +108 -2
  3. package/dist/ai.constants.d.ts +22 -0
  4. package/dist/ai.constants.js +24 -0
  5. package/dist/ai.module-definition.d.ts +23 -0
  6. package/dist/ai.module-definition.js +30 -0
  7. package/dist/ai.module.d.ts +11 -0
  8. package/dist/ai.module.js +36 -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 +2 -0
  16. package/dist/decorators/index.js +2 -0
  17. package/dist/decorators/inject-model.decorator.d.ts +10 -0
  18. package/dist/decorators/inject-model.decorator.js +16 -0
  19. package/dist/errors/ai.errors.d.ts +54 -0
  20. package/dist/errors/ai.errors.js +62 -0
  21. package/dist/errors/index.d.ts +1 -0
  22. package/dist/errors/index.js +1 -0
  23. package/dist/http/keep-alive.util.d.ts +6 -0
  24. package/dist/http/keep-alive.util.js +38 -0
  25. package/dist/http/node-response.util.d.ts +14 -0
  26. package/dist/http/node-response.util.js +104 -0
  27. package/dist/index.d.ts +13 -0
  28. package/dist/index.js +15 -0
  29. package/dist/interfaces/agent-function.interface.d.ts +53 -0
  30. package/dist/interfaces/agent-function.interface.js +1 -0
  31. package/dist/interfaces/ai-call-options.interface.d.ts +65 -0
  32. package/dist/interfaces/ai-call-options.interface.js +1 -0
  33. package/dist/interfaces/ai-module-options.interface.d.ts +88 -0
  34. package/dist/interfaces/ai-module-options.interface.js +1 -0
  35. package/dist/interfaces/ai-result.interface.d.ts +54 -0
  36. package/dist/interfaces/ai-result.interface.js +1 -0
  37. package/dist/interfaces/ai-schema.interface.d.ts +44 -0
  38. package/dist/interfaces/ai-schema.interface.js +1 -0
  39. package/dist/interfaces/ai-tool.interface.d.ts +22 -0
  40. package/dist/interfaces/ai-tool.interface.js +1 -0
  41. package/dist/interfaces/ai-usage.interface.d.ts +30 -0
  42. package/dist/interfaces/ai-usage.interface.js +1 -0
  43. package/dist/interfaces/index.d.ts +7 -0
  44. package/dist/interfaces/index.js +7 -0
  45. package/dist/models/ai-models.service.d.ts +29 -0
  46. package/dist/models/ai-models.service.js +113 -0
  47. package/dist/models/model-requests.d.ts +2 -0
  48. package/dist/models/model-requests.js +12 -0
  49. package/dist/runtime/agent-loop.d.ts +30 -0
  50. package/dist/runtime/agent-loop.js +81 -0
  51. package/dist/runtime/call-plan.d.ts +54 -0
  52. package/dist/runtime/call-plan.js +105 -0
  53. package/dist/runtime/model-policy.d.ts +48 -0
  54. package/dist/runtime/model-policy.js +202 -0
  55. package/dist/runtime/steps.d.ts +32 -0
  56. package/dist/runtime/steps.js +190 -0
  57. package/dist/runtime/text-stream.d.ts +64 -0
  58. package/dist/runtime/text-stream.js +211 -0
  59. package/dist/services/ai.service.d.ts +57 -0
  60. package/dist/services/ai.service.js +139 -0
  61. package/dist/testing/fake-model.d.ts +96 -0
  62. package/dist/testing/fake-model.js +201 -0
  63. package/dist/testing/index.d.ts +26 -0
  64. package/dist/testing/index.js +19 -0
  65. package/dist/tools/ai-tools.service.d.ts +77 -0
  66. package/dist/tools/ai-tools.service.js +234 -0
  67. package/dist/tools/tool-output.util.d.ts +6 -0
  68. package/dist/tools/tool-output.util.js +38 -0
  69. package/dist/utils/duration.util.d.ts +3 -0
  70. package/dist/utils/duration.util.js +17 -0
  71. package/dist/utils/errors.util.d.ts +16 -0
  72. package/dist/utils/errors.util.js +35 -0
  73. package/dist/utils/names.util.d.ts +2 -0
  74. package/dist/utils/names.util.js +10 -0
  75. package/dist/utils/schema.util.d.ts +16 -0
  76. package/dist/utils/schema.util.js +70 -0
  77. package/dist/utils/usage.util.d.ts +10 -0
  78. package/dist/utils/usage.util.js +42 -0
  79. package/dist/workflows/ai-agent.interfaces.d.ts +70 -0
  80. package/dist/workflows/ai-agent.interfaces.js +1 -0
  81. package/dist/workflows/ai-agent.workflow.d.ts +15 -0
  82. package/dist/workflows/ai-agent.workflow.js +25 -0
  83. package/dist/workflows/ai-agents.service.d.ts +83 -0
  84. package/dist/workflows/ai-agents.service.js +277 -0
  85. package/dist/workflows/ai-workflows.module.d.ts +6 -0
  86. package/dist/workflows/ai-workflows.module.js +22 -0
  87. package/dist/workflows/index.d.ts +6 -0
  88. package/dist/workflows/index.js +5 -0
  89. package/package.json +100 -4
@@ -0,0 +1 @@
1
+ export * from './ai.errors.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * `body` with a keep-alive comment written whenever it has been quiet for `intervalMs`: while a tool runs, or the
3
+ * model thinks, so that proxies and load balancers do not close the connection as idle. Comments go between the
4
+ * body's chunks, each a whole server-sent event.
5
+ */
6
+ export declare function withKeepAlive(body: ReadableStream<Uint8Array>, intervalMs: number): ReadableStream<Uint8Array>;
@@ -0,0 +1,38 @@
1
+ /** An SSE comment line: clients skip it, and proxies see the connection is alive. */
2
+ const KEEP_ALIVE = new TextEncoder().encode(': keep-alive\n\n');
3
+ /**
4
+ * `body` with a keep-alive comment written whenever it has been quiet for `intervalMs`: while a tool runs, or the
5
+ * model thinks, so that proxies and load balancers do not close the connection as idle. Comments go between the
6
+ * body's chunks, each a whole server-sent event.
7
+ */
8
+ export function withKeepAlive(body, intervalMs) {
9
+ const reader = body.getReader();
10
+ let pending;
11
+ return new ReadableStream({
12
+ pull: async (controller) => {
13
+ pending ??= reader.read();
14
+ let timer;
15
+ const quiet = new Promise((resolve) => {
16
+ timer = setTimeout(() => resolve('quiet'), intervalMs);
17
+ });
18
+ try {
19
+ const next = await Promise.race([pending, quiet]);
20
+ if (next === 'quiet') {
21
+ controller.enqueue(KEEP_ALIVE);
22
+ return;
23
+ }
24
+ pending = undefined;
25
+ if (next.done) {
26
+ controller.close();
27
+ }
28
+ else {
29
+ controller.enqueue(next.value);
30
+ }
31
+ }
32
+ finally {
33
+ clearTimeout(timer);
34
+ }
35
+ },
36
+ cancel: (reason) => reader.cancel(reason),
37
+ });
38
+ }
@@ -0,0 +1,14 @@
1
+ import type { ServerResponse } from 'node:http';
2
+ /**
3
+ * The Node response behind the platform's: Express's and the Node adapter's are Node responses; a Fastify reply is
4
+ * hijacked when the body starts (`open()`), with the headers set on it so far (CORS) copied to its raw response.
5
+ */
6
+ export declare function toNodeResponse(response: unknown): {
7
+ res: ServerResponse;
8
+ open(): void;
9
+ };
10
+ /**
11
+ * Writes `response` to the Node response: status and headers, then the body as it streams, respecting backpressure.
12
+ * A client that goes away cancels the body (which aborts the call that produces it).
13
+ */
14
+ export declare function writeWebResponse(response: Response, res: ServerResponse): Promise<void>;
@@ -0,0 +1,104 @@
1
+ import { AiConfigurationError } from '../errors/ai.errors.js';
2
+ function isFastifyReply(value) {
3
+ const reply = value;
4
+ return typeof reply?.hijack === 'function' && typeof reply.raw?.writeHead === 'function';
5
+ }
6
+ function isServerResponse(value) {
7
+ const response = value;
8
+ return typeof response?.writeHead === 'function' && typeof response.on === 'function';
9
+ }
10
+ /**
11
+ * The Node response behind the platform's: Express's and the Node adapter's are Node responses; a Fastify reply is
12
+ * hijacked when the body starts (`open()`), with the headers set on it so far (CORS) copied to its raw response.
13
+ */
14
+ export function toNodeResponse(response) {
15
+ if (isFastifyReply(response)) {
16
+ return {
17
+ res: response.raw,
18
+ open: () => {
19
+ const headers = response.getHeaders();
20
+ response.hijack();
21
+ for (const [name, value] of Object.entries(headers)) {
22
+ if (value !== undefined && !response.raw.hasHeader(name)) {
23
+ response.raw.setHeader(name, value);
24
+ }
25
+ }
26
+ },
27
+ };
28
+ }
29
+ if (isServerResponse(response)) {
30
+ return { res: response, open: () => { } };
31
+ }
32
+ throw new AiConfigurationError('Pass the response that @Res() injects (Express, Fastify or the Node adapter) to pipeUIMessageStreamToResponse() ' +
33
+ 'and pipeTextStreamToResponse().');
34
+ }
35
+ /**
36
+ * Writes `response` to the Node response: status and headers, then the body as it streams, respecting backpressure.
37
+ * A client that goes away cancels the body (which aborts the call that produces it).
38
+ */
39
+ export async function writeWebResponse(response, res) {
40
+ if (res.headersSent || res.destroyed) {
41
+ await response.body?.cancel().catch(() => { });
42
+ return;
43
+ }
44
+ const headers = {};
45
+ response.headers.forEach((value, name) => {
46
+ if (name !== 'set-cookie') {
47
+ headers[name] = value;
48
+ }
49
+ });
50
+ const cookies = response.headers.getSetCookie();
51
+ if (cookies.length > 0) {
52
+ headers['set-cookie'] = cookies;
53
+ }
54
+ for (const [name, value] of Object.entries(headers)) {
55
+ res.setHeader(name, value);
56
+ }
57
+ res.writeHead(response.status);
58
+ if (!response.body) {
59
+ res.end();
60
+ return;
61
+ }
62
+ // The client should see the stream open now, not with its first event.
63
+ res.flushHeaders();
64
+ const reader = response.body.getReader();
65
+ let gone = false;
66
+ let release;
67
+ const onClose = () => {
68
+ if (!res.writableFinished) {
69
+ gone = true;
70
+ release?.();
71
+ reader.cancel().catch(() => { });
72
+ }
73
+ };
74
+ res.once('close', onClose);
75
+ try {
76
+ for (;;) {
77
+ const next = await reader.read();
78
+ if (next.done || gone) {
79
+ break;
80
+ }
81
+ if (!res.write(next.value)) {
82
+ await new Promise((resolve) => {
83
+ release = resolve;
84
+ res.once('drain', resolve);
85
+ });
86
+ release = undefined;
87
+ }
88
+ }
89
+ if (gone) {
90
+ // The client went away: the socket may be half-open still, and nothing more will be written to it.
91
+ res.destroy();
92
+ }
93
+ else {
94
+ res.end();
95
+ }
96
+ }
97
+ catch {
98
+ // The body failed (a text stream whose call failed): the response ends early, as the client will see.
99
+ res.destroy();
100
+ }
101
+ finally {
102
+ res.off('close', onClose);
103
+ }
104
+ }
@@ -0,0 +1,13 @@
1
+ export { AiModule } from './ai.module.js';
2
+ export { AI_MODULE_OPTIONS, type AiModuleAsyncOptions, type AiModuleRootOptions, type AiOptionsFactory, } from './ai.module-definition.js';
3
+ export { DEFAULT_MODEL_NAME, getModelToken } from './ai.constants.js';
4
+ export type { AiBudget, AiCallDefaults, AiCallSettings, AiModelDefinition, AiModelPricing, AiModuleOptions, AiModuleStructure, } from './interfaces/index.js';
5
+ export { AiModels } from './models/ai-models.service.js';
6
+ export { AiService } from './services/ai.service.js';
7
+ export { AiTextStream, type AiStreamResponseOptions, type AiUIMessageStreamOptions, } from './runtime/text-stream.js';
8
+ export type { AiCallOptions, AiModelInfo, AiModelReference, AiObjectCallOptions, AiObjectResult, AiSchema, AiStep, AiTextResult, AiToolCall, AiToolChoice, AiToolResult, AiUsage, AiUsageEvent, InferSchemaOutput, } from './interfaces/index.js';
9
+ export * from './decorators/index.js';
10
+ export { AiExecutionContext, type AiContextType } from './context/ai-execution-context.js';
11
+ export { AiTools, type AiToolEntry } from './tools/ai-tools.service.js';
12
+ export type { AgentFunctionContext, AgentFunctionOptions, AiCaller, AiToolSelection } from './interfaces/index.js';
13
+ export * from './errors/index.js';
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ // Module and options
2
+ export { AiModule } from './ai.module.js';
3
+ export { AI_MODULE_OPTIONS, } from './ai.module-definition.js';
4
+ export { DEFAULT_MODEL_NAME, getModelToken } from './ai.constants.js';
5
+ // Models and model calls
6
+ export { AiModels } from './models/ai-models.service.js';
7
+ export { AiService } from './services/ai.service.js';
8
+ export { AiTextStream, } from './runtime/text-stream.js';
9
+ // Models by injection (`@InjectModel()`); agent functions (`@AgentFunction()`), which the model is offered as tools:
10
+ // what the methods receive, the execution context of their calls, and the registry
11
+ export * from './decorators/index.js';
12
+ export { AiExecutionContext } from './context/ai-execution-context.js';
13
+ export { AiTools } from './tools/ai-tools.service.js';
14
+ // Errors
15
+ export * from './errors/index.js';
@@ -0,0 +1,53 @@
1
+ import type { ModelMessage } from 'ai';
2
+ import type { AiSchema } from './ai-schema.interface.js';
3
+ /** The options of `@AgentFunction()`. */
4
+ export interface AgentFunctionOptions {
5
+ /**
6
+ * The name calls list it by in `tools`, and the model calls it by: 1 to 64 characters out of `A-Z a-z 0-9 _ -`, which
7
+ * is what model providers accept as a tool name. Default: the method's name.
8
+ */
9
+ name?: string;
10
+ /** What it does: the model picks the functions it calls by their names and descriptions. */
11
+ description?: string;
12
+ /**
13
+ * Its arguments: an object schema, whose JSON Schema the model is sent, and which validates every call before the
14
+ * method runs. Default: no arguments.
15
+ */
16
+ inputSchema?: AiSchema;
17
+ /** The scopes the caller must hold (`caller.scopes`): a call without them is refused before any guard runs. */
18
+ scopes?: readonly string[];
19
+ }
20
+ /**
21
+ * The second argument of an agent function, and `AiExecutionContext.getContext()` in its guards, interceptors and
22
+ * exception filters: who the call acts for (the call's `caller`), and the model's tool call.
23
+ */
24
+ export interface AgentFunctionContext<TRequest = any, TUser = any> {
25
+ /** The agent function's name. */
26
+ readonly name: string;
27
+ /**
28
+ * The HTTP platform's request the agent runs in (`caller.request`): Express's, Fastify's or the Node adapter's, with
29
+ * its headers and the `user` your authentication set on it. `undefined` where there is none, as in a queue job.
30
+ */
31
+ readonly request?: TRequest;
32
+ /** Who the call acts for where there is no request (`caller.user`), as in a queue job or a durable run. */
33
+ readonly user?: TUser;
34
+ /** The scopes the caller holds (`caller.scopes`), which the function's own `scopes` require. */
35
+ readonly scopes?: readonly string[];
36
+ /** Aborted when the call is: pass it on to `fetch()` and your database. */
37
+ readonly signal: AbortSignal;
38
+ /**
39
+ * In a streamed answer, sends the browser the call's progress, as a transient `data-tool-progress` chunk; elsewhere,
40
+ * does nothing.
41
+ */
42
+ reportProgress(progress: number, total?: number, message?: string): Promise<void>;
43
+ /** The model's id for this tool call, to tie the function's logs to the agent's conversation. */
44
+ readonly toolCallId: string;
45
+ /**
46
+ * In a durable run (`@nestjs/ai/workflows`): the same for every attempt of this call, including the one a process
47
+ * that died mid-call makes again. Pass it on to what the function changes (a payment provider's idempotency key), so
48
+ * the change happens once. `undefined` outside durable runs.
49
+ */
50
+ readonly idempotencyKey?: string;
51
+ /** The messages the model had read when it called the function, without the system prompt. */
52
+ readonly messages: readonly ModelMessage[];
53
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,65 @@
1
+ import type { LanguageModel, ModelMessage } from 'ai';
2
+ import type { AiBudget, AiCallSettings } from './ai-module-options.interface.js';
3
+ import type { AiSchema } from './ai-schema.interface.js';
4
+ import type { AiCaller, AiToolSelection } from './ai-tool.interface.js';
5
+ import type { AiUsageEvent } from './ai-usage.interface.js';
6
+ export type AiToolChoice = 'auto' | 'none' | 'required' | {
7
+ type: 'tool';
8
+ toolName: string;
9
+ };
10
+ /** A model: its name in `forRoot({ models })`, or a `LanguageModel`. */
11
+ export type AiModelReference = string | Exclude<LanguageModel, string>;
12
+ /** The options of `generateText()` and `streamText()`. */
13
+ export interface AiCallOptions extends AiCallSettings {
14
+ /** Default `'default'`. */
15
+ model?: AiModelReference;
16
+ /** The system prompt. */
17
+ instructions?: string;
18
+ /** The user's message; or `messages`, a whole conversation. */
19
+ prompt?: string;
20
+ messages?: ModelMessage[];
21
+ /**
22
+ * The agent functions (`@AgentFunction()` methods) the model may call, by name or by provider class (all its agent
23
+ * functions). The model is offered each as a tool, and only those listed here.
24
+ */
25
+ tools?: AiToolSelection;
26
+ /** Who the call acts for: what agent functions and their guards see. */
27
+ caller?: AiCaller;
28
+ toolChoice?: AiToolChoice;
29
+ /** Model calls this call may make while the model asks for tools. Default 10. */
30
+ maxSteps?: number;
31
+ /**
32
+ * Models tried in order when the model fails after its retries; `false` for none. Default: the model's own
33
+ * `fallback`.
34
+ */
35
+ fallback?: AiModelReference | ReadonlyArray<AiModelReference> | false;
36
+ /**
37
+ * Which failures move on to the next model (the `FallbackPolicy`'s `handleIf`). Default: any but the caller's
38
+ * abort, an answer that does not match the schema, and mistakes in the call.
39
+ */
40
+ fallbackIf?: (error: unknown) => boolean;
41
+ budget?: AiBudget;
42
+ /**
43
+ * Cancels the call: the model call in flight, the backoff, the agent functions running (through their context's
44
+ * `signal`).
45
+ */
46
+ abortSignal?: AbortSignal;
47
+ /** Names the call in usage events (`'triage'`). */
48
+ label?: string;
49
+ /** Called after every model call of this call that answered, after the module's `onUsage`. */
50
+ onUsage?: (event: AiUsageEvent) => void | Promise<void>;
51
+ topP?: number;
52
+ topK?: number;
53
+ seed?: number;
54
+ stopSequences?: string[];
55
+ presencePenalty?: number;
56
+ frequencyPenalty?: number;
57
+ }
58
+ /** The options of `generateObject()`. */
59
+ export interface AiObjectCallOptions<S extends AiSchema = AiSchema> extends AiCallOptions {
60
+ /** What the answer must be. The model is sent its JSON Schema, and its answer is validated by it. */
61
+ schema: S;
62
+ /** A name and a description of the object, which some providers pass on to the model. */
63
+ schemaName?: string;
64
+ schemaDescription?: string;
65
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,88 @@
1
+ import type { Duration, ResiliencePolicy, RetryOptions } from '@nestjs/resilience';
2
+ import type { LanguageModel } from 'ai';
3
+ import type { AiUsageEvent } from './ai-usage.interface.js';
4
+ /** Prices per million tokens, in a unit of your choice: what `cost` is reported in. */
5
+ export interface AiModelPricing {
6
+ input: number;
7
+ output: number;
8
+ /** Input tokens read from the prompt cache. Default: `input`. */
9
+ cachedInput?: number;
10
+ }
11
+ /** Limits on one call, over every step it makes. */
12
+ export interface AiBudget {
13
+ /** Total tokens, input and output. */
14
+ maxTokens?: number;
15
+ /** In the unit of the models' `pricing`. A model without pricing counts as free. */
16
+ maxCost?: number;
17
+ }
18
+ /** Settings a model, the module's `defaults` and each call can set; the call's win, then the model's. */
19
+ export interface AiCallSettings {
20
+ /**
21
+ * The longest a model call may take to answer: its whole response for `generateText()` and `generateObject()`,
22
+ * its first chunk for `streamText()`, until its tools start for a step that calls them. Applied to each attempt,
23
+ * as a `TimeoutPolicy`. Default `'60s'`; `false` for none.
24
+ */
25
+ timeout?: Duration | false;
26
+ /**
27
+ * Retries of a failed model call, as `@nestjs/resilience`'s `RetryPolicy` takes them: `attempts` (default 3, the
28
+ * first included), `backoff` (default from `'1s'`, doubling, up to `'30s'`, full jitter), `retryIf`. Retried by
29
+ * default: what the provider marks retryable (408, 409, 429, 5xx and network failures) and timeouts; a
30
+ * `retry-after` the provider sends is honored, and one longer than `backoff.maxDelay` moves on to the fallback.
31
+ * `false` for none.
32
+ */
33
+ retry?: RetryOptions | false;
34
+ /**
35
+ * A policy of your own (`ResiliencePolicy.wrap(breaker, retry, timeout)`), or the name of a preset of
36
+ * `ResilienceService` (`ResilienceModule.forRoot({ presets })`), in place of `retry` and `timeout`: a circuit
37
+ * breaker or a bulkhead shared with the rest of the application. Fallback models are applied around it.
38
+ */
39
+ resilience?: ResiliencePolicy | string;
40
+ /** Generation settings passed to the model. */
41
+ maxOutputTokens?: number;
42
+ temperature?: number;
43
+ /** Provider-specific options, by provider name (`{ anthropic: { ... } }`). */
44
+ providerOptions?: Record<string, Record<string, any>>;
45
+ /** HTTP headers sent to the provider. */
46
+ headers?: Record<string, string | undefined>;
47
+ }
48
+ export interface AiModelDefinition extends AiCallSettings {
49
+ model: LanguageModel;
50
+ pricing?: AiModelPricing;
51
+ /** The models tried, in order, when this one fails after its retries: names of other models. */
52
+ fallback?: string | string[];
53
+ }
54
+ /** Defaults for every call. `maxSteps` and `budget` are also those of durable runs (`AiAgents.run()`). */
55
+ export interface AiCallDefaults extends AiCallSettings {
56
+ /** Model calls one call may make while the model asks for tools. Default 10 (25 for a durable run). */
57
+ maxSteps?: number;
58
+ budget?: AiBudget;
59
+ }
60
+ /** `forRoot()`'s options, and what the `forRootAsync()` factory returns. */
61
+ export interface AiModuleOptions {
62
+ /**
63
+ * The models, by name: a `LanguageModel` (`anthropic('claude-opus-5-5')`, a gateway id such as
64
+ * `'openai/gpt-5'`), or a definition with its pricing, fallback and settings. Calls that name no model use
65
+ * `default`.
66
+ */
67
+ models: Record<string, LanguageModel | AiModelDefinition>;
68
+ defaults?: AiCallDefaults;
69
+ /** Called after every model call that answered, with its tokens and cost. Errors it throws are logged. */
70
+ onUsage?: (event: AiUsageEvent) => void | Promise<void>;
71
+ /**
72
+ * The modules whose providers are searched for agent functions (`@AgentFunction()` methods). Default: every module
73
+ * of the application.
74
+ */
75
+ include?: Function[];
76
+ }
77
+ /** What only the top level of `forRoot()` and `forRootAsync()` takes. */
78
+ export interface AiModuleStructure {
79
+ /**
80
+ * Model names `@InjectModel()` may inject, beyond those it was seen asking for when the module was defined (the
81
+ * classes the module's file imports): for classes loaded later, such as lazily loaded modules.
82
+ */
83
+ modelNames?: string[];
84
+ }
85
+ /** What a class passed to `forRootAsync({ useClass })` implements. */
86
+ export interface AiOptionsFactory {
87
+ createAiOptions(): AiModuleOptions | Promise<AiModuleOptions>;
88
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,54 @@
1
+ import type { FinishReason, ModelMessage } from 'ai';
2
+ import type { AiUsage } from './ai-usage.interface.js';
3
+ /** Which model answered. */
4
+ export interface AiModelInfo {
5
+ /** Its name in `forRoot({ models })`; `undefined` for a `LanguageModel` passed to the call. */
6
+ name?: string;
7
+ provider: string;
8
+ modelId: string;
9
+ }
10
+ export interface AiToolCall {
11
+ toolCallId: string;
12
+ toolName: string;
13
+ input: unknown;
14
+ }
15
+ export interface AiToolResult extends AiToolCall {
16
+ /** What the tool returned; absent when it failed. */
17
+ output?: unknown;
18
+ /** What the model was told about a failure. */
19
+ error?: string;
20
+ }
21
+ /** One model call of a text generation, with the tool calls it made and their results. */
22
+ export interface AiStep {
23
+ index: number;
24
+ model: AiModelInfo;
25
+ text: string;
26
+ toolCalls: AiToolCall[];
27
+ toolResults: AiToolResult[];
28
+ finishReason: FinishReason;
29
+ usage: AiUsage;
30
+ cost?: number;
31
+ /** Attempts made for this step, over every model tried. */
32
+ attempts: number;
33
+ }
34
+ export interface AiTextResult {
35
+ /** The text of the last step. */
36
+ text: string;
37
+ /** The last step's: `tool-calls` when `maxSteps` ran out while the model still asked for tools. */
38
+ finishReason: FinishReason;
39
+ steps: AiStep[];
40
+ /** Summed over the steps. */
41
+ usage: AiUsage;
42
+ /** Summed over the steps whose model has `pricing`; `undefined` when none had. */
43
+ cost?: number;
44
+ toolCalls: AiToolCall[];
45
+ toolResults: AiToolResult[];
46
+ /** The assistant and tool messages of every step, to append to a conversation. */
47
+ responseMessages: ModelMessage[];
48
+ /** The model of the last step. */
49
+ model: AiModelInfo;
50
+ }
51
+ export interface AiObjectResult<T> extends AiTextResult {
52
+ /** The answer, validated by the schema. */
53
+ object: T;
54
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * A schema the package accepts: a Standard Schema that also produces JSON Schema (`~standard.jsonSchema`), as
3
+ * `@nestjs/mcp`'s schemas are, so that one schema serves a method's `@AgentFunction()` and its `@Tool()`. Zod 4.2+
4
+ * and ArkType schemas are, as they are; Valibot through
5
+ * `toStandardJsonSchema()` from `@valibot/to-json-schema`; a JSON Schema document through `fromJsonSchema()` from
6
+ * `@modelcontextprotocol/server`. The model is sent the JSON Schema, and what it answers is validated by the schema.
7
+ *
8
+ * The shape of the [Standard Schema](https://standardschema.dev) interfaces, declared here so that the package has no
9
+ * dependency for them.
10
+ */
11
+ export interface AiSchema<Input = any, Output = Input> {
12
+ readonly '~standard': {
13
+ readonly version: 1;
14
+ readonly vendor: string;
15
+ readonly types?: {
16
+ readonly input: Input;
17
+ readonly output: Output;
18
+ } | undefined;
19
+ readonly validate: (value: unknown, options?: {
20
+ readonly libraryOptions?: Record<string, unknown> | undefined;
21
+ } | undefined) => AiSchemaResult<Output> | Promise<AiSchemaResult<Output>>;
22
+ readonly jsonSchema: {
23
+ readonly input: (options: AiJsonSchemaOptions) => Record<string, unknown>;
24
+ readonly output: (options: AiJsonSchemaOptions) => Record<string, unknown>;
25
+ };
26
+ };
27
+ }
28
+ export interface AiJsonSchemaOptions {
29
+ readonly target: 'draft-2020-12' | 'draft-07' | 'openapi-3.0' | ({} & string);
30
+ readonly libraryOptions?: Record<string, unknown> | undefined;
31
+ }
32
+ export type AiSchemaResult<Output> = {
33
+ readonly value: Output;
34
+ readonly issues?: undefined;
35
+ } | {
36
+ readonly issues: ReadonlyArray<{
37
+ readonly message: string;
38
+ readonly path?: ReadonlyArray<PropertyKey | {
39
+ readonly key: PropertyKey;
40
+ }> | undefined;
41
+ }>;
42
+ };
43
+ /** The type a schema validates to. */
44
+ export type InferSchemaOutput<S extends AiSchema> = NonNullable<S['~standard']['types']>['output'];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Who an agent acts for. Agent functions receive it in their context (`AgentFunctionContext`), and guards read it
3
+ * there, as a route's guards read the request.
4
+ *
5
+ * ```ts
6
+ * caller: { request } // in a controller: the request's user, headers, session
7
+ * caller: { user: job.data.user, scopes } // in a queue job
8
+ * ```
9
+ */
10
+ export interface AiCaller<TUser = any, TRequest = any> {
11
+ /** The HTTP platform's request the agent runs in (Express, Fastify, the Node adapter). */
12
+ request?: TRequest;
13
+ /** The user, where there is no request (a queue job, a workflow); in a request, it is `request.user`. */
14
+ user?: TUser;
15
+ /** Scopes the caller holds, checked against an agent function's `scopes`. */
16
+ scopes?: readonly string[];
17
+ }
18
+ /**
19
+ * What a call's `tools` lists: agent function names, and provider classes (every agent function of the class). The
20
+ * model is offered each as a tool.
21
+ */
22
+ export type AiToolSelection = ReadonlyArray<string | (abstract new (...args: any[]) => unknown)>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ import type { AiModelInfo } from './ai-result.interface.js';
2
+ /** Tokens a model call used. A count the provider did not report is 0. */
3
+ export interface AiUsage {
4
+ /** Every input token, cached ones included. */
5
+ inputTokens: number;
6
+ outputTokens: number;
7
+ totalTokens: number;
8
+ /** The part of `inputTokens` read from the provider's prompt cache. */
9
+ cachedInputTokens: number;
10
+ /** The part of `outputTokens` spent on reasoning. */
11
+ reasoningTokens: number;
12
+ }
13
+ /** One model call that answered: a step of `generateText()`, `generateObject()` or `streamText()`. */
14
+ export interface AiUsageEvent {
15
+ /** The call's `label`, to tell calls apart (`'triage'`). */
16
+ label?: string;
17
+ model: AiModelInfo;
18
+ /** 0-based step of the call: a call that uses tools makes several model calls. */
19
+ step: number;
20
+ /** 1-based attempt of this model for this step. */
21
+ attempt: number;
22
+ /** Whether it was a fallback model. */
23
+ fallback: boolean;
24
+ stream: boolean;
25
+ usage: AiUsage;
26
+ /** In the unit of the model's `pricing`; `undefined` without one. */
27
+ cost?: number;
28
+ durationMs: number;
29
+ finishReason: string;
30
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ export * from './agent-function.interface.js';
2
+ export * from './ai-call-options.interface.js';
3
+ export * from './ai-module-options.interface.js';
4
+ export * from './ai-result.interface.js';
5
+ export * from './ai-schema.interface.js';
6
+ export * from './ai-tool.interface.js';
7
+ export * from './ai-usage.interface.js';
@@ -0,0 +1,7 @@
1
+ export * from './agent-function.interface.js';
2
+ export * from './ai-call-options.interface.js';
3
+ export * from './ai-module-options.interface.js';
4
+ export * from './ai-result.interface.js';
5
+ export * from './ai-schema.interface.js';
6
+ export * from './ai-tool.interface.js';
7
+ export * from './ai-usage.interface.js';
@@ -0,0 +1,29 @@
1
+ import type { LanguageModel } from 'ai';
2
+ import type { AiModelReference } from '../interfaces/ai-call-options.interface.js';
3
+ import type { AiCallSettings, AiModelPricing, AiModuleOptions } from '../interfaces/ai-module-options.interface.js';
4
+ import type { AiModelInfo } from '../interfaces/ai-result.interface.js';
5
+ /** A model, as calls use it. Internal. */
6
+ export interface ResolvedModel {
7
+ info: AiModelInfo;
8
+ model: LanguageModel;
9
+ pricing?: AiModelPricing;
10
+ settings: AiCallSettings;
11
+ /** The names of the models tried after it. */
12
+ fallback: string[];
13
+ }
14
+ /** The configured models, by name. */
15
+ export declare class AiModels {
16
+ private readonly models;
17
+ constructor(options: AiModuleOptions, overrides?: Record<string, LanguageModel> | null);
18
+ /** The names of the configured models. */
19
+ names(): string[];
20
+ /** The `LanguageModel` called `name`, for code that calls `ai` directly. */
21
+ get(name?: string): LanguageModel;
22
+ /** Whether a model called `name` is configured. */
23
+ has(name: string): boolean;
24
+ /** @internal What `@InjectModel(name)` injects into `inquirer`; a name that is not configured fails at startup. */
25
+ injected(name: string, inquirer: unknown): LanguageModel;
26
+ /** @internal A name, or a `LanguageModel` given to a call (with no settings of its own). */
27
+ resolve(reference: AiModelReference | undefined): ResolvedModel;
28
+ private known;
29
+ }