@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
@@ -0,0 +1,54 @@
1
+ import type { AiModelInfo } from '../interfaces/ai-result.interface.js';
2
+ import type { AiUsage } from '../interfaces/ai-usage.interface.js';
3
+ /** The base class of the package's errors. */
4
+ export declare class AiError extends Error {
5
+ constructor(message: string, options?: ErrorOptions);
6
+ }
7
+ /**
8
+ * A model name, an agent function or an option the package cannot use. Thrown at startup or when the call is made.
9
+ */
10
+ export declare class AiConfigurationError extends AiError {
11
+ }
12
+ /** One failed attempt of a model call. */
13
+ export interface AiAttemptFailure {
14
+ model: AiModelInfo;
15
+ attempt: number;
16
+ error: unknown;
17
+ }
18
+ /** Every attempt of a model call failed, on every model tried. `cause` is the last error. */
19
+ export declare class AiModelError extends AiError {
20
+ readonly attempts: AiAttemptFailure[];
21
+ constructor(attempts: AiAttemptFailure[]);
22
+ }
23
+ /** The call would have started a model call over its `budget`. */
24
+ export declare class AiBudgetExceededError extends AiError {
25
+ readonly usage: AiUsage;
26
+ readonly cost: number | undefined;
27
+ readonly limit: {
28
+ maxTokens?: number;
29
+ maxCost?: number;
30
+ };
31
+ constructor(usage: AiUsage, cost: number | undefined, limit: {
32
+ maxTokens?: number;
33
+ maxCost?: number;
34
+ });
35
+ }
36
+ /** The model's answer to `generateObject()` is not JSON, or does not match the schema. */
37
+ export declare class AiOutputError extends AiError {
38
+ /** What the model answered. */
39
+ readonly text: string;
40
+ constructor(message: string,
41
+ /** What the model answered. */
42
+ text: string, options?: ErrorOptions);
43
+ }
44
+ /**
45
+ * What the model is told about a tool call that failed: a guard's refusal (`Forbidden resource`), an
46
+ * `HttpException`'s message, `Internal server error` for anything else. `toolName` is the agent function's name.
47
+ */
48
+ export declare class AiToolError extends AiError {
49
+ readonly toolName: string;
50
+ constructor(message: string, toolName: string, options?: ErrorOptions);
51
+ /** The model reads `String(error)`: the message alone, not the class name. */
52
+ toString(): string;
53
+ }
54
+ export declare function describeModel(model: AiModelInfo): string;
@@ -0,0 +1,62 @@
1
+ /** The base class of the package's errors. */
2
+ export class AiError extends Error {
3
+ constructor(message, options) {
4
+ super(message, options);
5
+ this.name = new.target.name;
6
+ }
7
+ }
8
+ /**
9
+ * A model name, an agent function or an option the package cannot use. Thrown at startup or when the call is made.
10
+ */
11
+ export class AiConfigurationError extends AiError {
12
+ }
13
+ /** Every attempt of a model call failed, on every model tried. `cause` is the last error. */
14
+ export class AiModelError extends AiError {
15
+ constructor(attempts) {
16
+ const last = attempts[attempts.length - 1];
17
+ const tried = [...new Set(attempts.map((attempt) => describeModel(attempt.model)))].join(', ');
18
+ super(`The model call failed after ${attempts.length} attempt(s) (${tried}): ${messageOf(last?.error)}`, {
19
+ cause: last?.error,
20
+ });
21
+ this.attempts = attempts;
22
+ }
23
+ }
24
+ /** The call would have started a model call over its `budget`. */
25
+ export class AiBudgetExceededError extends AiError {
26
+ constructor(usage, cost, limit) {
27
+ const spent = limit.maxCost !== undefined && cost !== undefined ? `cost ${cost}` : `${usage.totalTokens} tokens`;
28
+ super(`The call's budget is spent (${spent}), so it stopped before the next model call`);
29
+ this.usage = usage;
30
+ this.cost = cost;
31
+ this.limit = limit;
32
+ }
33
+ }
34
+ /** The model's answer to `generateObject()` is not JSON, or does not match the schema. */
35
+ export class AiOutputError extends AiError {
36
+ constructor(message,
37
+ /** What the model answered. */
38
+ text, options) {
39
+ super(message, options);
40
+ this.text = text;
41
+ }
42
+ }
43
+ /**
44
+ * What the model is told about a tool call that failed: a guard's refusal (`Forbidden resource`), an
45
+ * `HttpException`'s message, `Internal server error` for anything else. `toolName` is the agent function's name.
46
+ */
47
+ export class AiToolError extends AiError {
48
+ constructor(message, toolName, options) {
49
+ super(message, options);
50
+ this.toolName = toolName;
51
+ }
52
+ /** The model reads `String(error)`: the message alone, not the class name. */
53
+ toString() {
54
+ return this.message;
55
+ }
56
+ }
57
+ export function describeModel(model) {
58
+ return model.name ?? `${model.provider}:${model.modelId}`;
59
+ }
60
+ function messageOf(error) {
61
+ return error instanceof Error ? error.message : String(error);
62
+ }
@@ -0,0 +1 @@
1
+ export * from './ai.errors.js';
@@ -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,14 @@
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, getEmbeddingModelToken, getModelToken } from './ai.constants.js';
4
+ export type { AiBudget, AiCallDefaults, AiCallSettings, AiModelDefinition, AiModelPricing, AiModuleOptions, AiModuleStructure, AiResilienceSettings, } from './interfaces/index.js';
5
+ export { AiModels } from './models/ai-models.service.js';
6
+ export { AiEmbeddingModels } from './models/ai-embedding-models.service.js';
7
+ export { AiService } from './services/ai.service.js';
8
+ export { AiTextStream, type AiStreamResponseOptions, type AiUIMessageStreamOptions, } from './runtime/text-stream.js';
9
+ export type { AiCallOptions, AiEmbeddingCallOptions, AiEmbeddingModelDefinition, AiEmbeddingModelPricing, AiEmbeddingModelReference, AiEmbeddingSettings, AiEmbeddingUsageEvent, AiEmbedManyOptions, AiEmbedManyResult, AiEmbedOptions, AiEmbedResult, AiModelInfo, AiModelReference, AiObjectCallOptions, AiObjectResult, AiSchema, AiStep, AiTextResult, AiToolCall, AiToolChoice, AiToolResult, AiUsage, AiUsageEvent, InferSchemaOutput, } from './interfaces/index.js';
10
+ export * from './decorators/index.js';
11
+ export { AiExecutionContext, type AiContextType } from './context/ai-execution-context.js';
12
+ export { AiTools, type AiToolEntry } from './tools/ai-tools.service.js';
13
+ export type { AgentFunctionContext, AgentFunctionOptions, AiCaller, AiToolSelection } from './interfaces/index.js';
14
+ export * from './errors/index.js';
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
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, getEmbeddingModelToken, getModelToken } from './ai.constants.js';
5
+ // Models and model calls
6
+ export { AiModels } from './models/ai-models.service.js';
7
+ export { AiEmbeddingModels } from './models/ai-embedding-models.service.js';
8
+ export { AiService } from './services/ai.service.js';
9
+ export { AiTextStream, } from './runtime/text-stream.js';
10
+ // Models by injection (`@InjectModel()`); agent functions (`@AgentFunction()`), which the model is offered as tools:
11
+ // what the methods receive, the execution context of their calls, and the registry
12
+ export * from './decorators/index.js';
13
+ export { AiExecutionContext } from './context/ai-execution-context.js';
14
+ export { AiTools } from './tools/ai-tools.service.js';
15
+ // Errors
16
+ 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,79 @@
1
+ import type { EmbeddingModel, EmbeddingModelUsage, EmbedManyResult, EmbedResult } from 'ai';
2
+ import type { AiResilienceSettings } from './ai-module-options.interface.js';
3
+ import type { AiModelInfo } from './ai-result.interface.js';
4
+ /** Embedding settings, independent of language-model generation defaults. */
5
+ export interface AiEmbeddingSettings extends AiResilienceSettings {
6
+ /** Provider-specific options, by provider name. */
7
+ providerOptions?: Record<string, Record<string, any>>;
8
+ /** HTTP headers sent to the embedding provider. */
9
+ headers?: Record<string, string>;
10
+ /** Maximum concurrent SDK batch requests within one `embedMany()` operation. Default 4. */
11
+ maxParallelCalls?: number;
12
+ }
13
+ /** Price per million input tokens, in the unit used for reported `cost`. */
14
+ export interface AiEmbeddingModelPricing {
15
+ input: number;
16
+ }
17
+ /** A registered SDK embedding model with its own embedding settings. */
18
+ export interface AiEmbeddingModelDefinition extends AiEmbeddingSettings {
19
+ model: EmbeddingModel;
20
+ pricing?: AiEmbeddingModelPricing;
21
+ }
22
+ /** A registered embedding name, or an SDK embedding-model object passed directly to a call. */
23
+ export type AiEmbeddingModelReference = string | Exclude<EmbeddingModel, string>;
24
+ /** Options shared by single and batch embedding calls. */
25
+ export interface AiEmbeddingCallOptions extends AiEmbeddingSettings {
26
+ /** Name in `embeddingModels` (default `'default'`), or a direct SDK model object. */
27
+ model?: AiEmbeddingModelReference;
28
+ /**
29
+ * Cancels in-flight provider requests and retry backoff. `timeout` covers one provider request,
30
+ * so this is how to set a deadline for the whole operation (`AbortSignal.timeout(ms)`).
31
+ */
32
+ abortSignal?: AbortSignal;
33
+ /** Names this operation in usage and resilience events. */
34
+ label?: string;
35
+ /** Called after a successful operation, after the module's embedding usage listener. */
36
+ onEmbeddingUsage?: (event: AiEmbeddingUsageEvent) => void | Promise<void>;
37
+ }
38
+ export interface AiEmbedOptions extends AiEmbeddingCallOptions {
39
+ value: string;
40
+ }
41
+ export interface AiEmbedManyOptions extends AiEmbeddingCallOptions {
42
+ values: string[];
43
+ }
44
+ /** SDK single-embedding result with the resolved model and attempt count. */
45
+ export interface AiEmbedResult extends EmbedResult {
46
+ model: AiModelInfo;
47
+ /** Provider requests made, retries included. */
48
+ attempts: number;
49
+ /** Cost of the reported usage; absent without model pricing. */
50
+ cost?: number;
51
+ }
52
+ /**
53
+ * SDK batch result, in input order. A failed operation rejects rather than returning partial
54
+ * results.
55
+ */
56
+ export interface AiEmbedManyResult extends EmbedManyResult {
57
+ model: AiModelInfo;
58
+ /** Provider requests made, retries included. */
59
+ attempts: number;
60
+ /** Cost of the reported usage; absent without model pricing. */
61
+ cost?: number;
62
+ }
63
+ /**
64
+ * One successful embedding operation. Not a billing ledger: a provider may bill a request that
65
+ * timed out, and an operation that fails reports nothing, including the requests it completed.
66
+ * Input contents and output vectors are excluded.
67
+ */
68
+ export interface AiEmbeddingUsageEvent {
69
+ operation: 'embed' | 'embedMany';
70
+ label?: string;
71
+ model: AiModelInfo;
72
+ inputCount: number;
73
+ usage: EmbeddingModelUsage;
74
+ /** Provider requests made, retries included. */
75
+ attempts: number;
76
+ /** Total duration of the operation, including retries and backoff. */
77
+ durationMs: number;
78
+ cost?: number;
79
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,110 @@
1
+ import type { Duration, ResiliencePolicy, RetryOptions } from '@nestjs/resilience';
2
+ import type { EmbeddingModel, LanguageModel } from 'ai';
3
+ import type { AiUsageEvent } from './ai-usage.interface.js';
4
+ import type { AiEmbeddingModelDefinition, AiEmbeddingSettings, AiEmbeddingUsageEvent } from './ai-embedding.interface.js';
5
+ /** Prices per million tokens, in a unit of your choice: what `cost` is reported in. */
6
+ export interface AiModelPricing {
7
+ input: number;
8
+ output: number;
9
+ /** Input tokens read from the prompt cache. Default: `input`. */
10
+ cachedInput?: number;
11
+ }
12
+ /** Limits on one call, over every step it makes. */
13
+ export interface AiBudget {
14
+ /** Total tokens, input and output. */
15
+ maxTokens?: number;
16
+ /** In the unit of the models' `pricing`. A model without pricing counts as free. */
17
+ maxCost?: number;
18
+ }
19
+ /** Resilience settings shared by language-model and embedding calls. */
20
+ export interface AiResilienceSettings {
21
+ /**
22
+ * The longest a model call may take to answer: its whole response for `generateText()` and `generateObject()`,
23
+ * its first chunk for `streamText()`, until its tools start for a step that calls them, one provider request for
24
+ * an embedding. Applied to each attempt, as a `TimeoutPolicy`. Default `'60s'`; `false` for none.
25
+ */
26
+ timeout?: Duration | false;
27
+ /**
28
+ * Retries of a failed model call, as `@nestjs/resilience`'s `RetryPolicy` takes them: `attempts` (default 3, the
29
+ * first included), `backoff` (default from `'1s'`, doubling, up to `'30s'`, full jitter), `retryIf`. Retried by
30
+ * default: what the provider marks retryable (408, 409, 429, 5xx and network failures) and timeouts; a
31
+ * `retry-after` the provider sends is honored, and one longer than `backoff.maxDelay` moves on to the fallback.
32
+ * An embedding call has no fallback, and retries only the provider request that failed. `false` for none.
33
+ */
34
+ retry?: RetryOptions | false;
35
+ /**
36
+ * A policy of your own (`ResiliencePolicy.wrap(breaker, retry, timeout)`), or the name of a preset of
37
+ * `ResilienceService` (`ResilienceModule.forRoot({ presets })`), in place of `retry` and `timeout`: a circuit
38
+ * breaker or a bulkhead shared with the rest of the application. Fallback models are applied around it. An
39
+ * embedding call runs it around each provider request, so a bulkhead or a rate limit counts requests.
40
+ */
41
+ resilience?: ResiliencePolicy | string;
42
+ }
43
+ /** Settings a language model, the module's `defaults` and each call can set; the call's win, then the model's. */
44
+ export interface AiCallSettings extends AiResilienceSettings {
45
+ /** Generation settings passed to the model. */
46
+ maxOutputTokens?: number;
47
+ temperature?: number;
48
+ /** Provider-specific options, by provider name (`{ anthropic: { ... } }`). */
49
+ providerOptions?: Record<string, Record<string, any>>;
50
+ /** HTTP headers sent to the provider. */
51
+ headers?: Record<string, string | undefined>;
52
+ }
53
+ export interface AiModelDefinition extends AiCallSettings {
54
+ model: LanguageModel;
55
+ pricing?: AiModelPricing;
56
+ /** The models tried, in order, when this one fails after its retries: names of other models. */
57
+ fallback?: string | string[];
58
+ }
59
+ /** Defaults for language-model calls. `maxSteps` and `budget` are also those of durable runs (`AiAgents.run()`). */
60
+ export interface AiCallDefaults extends AiCallSettings {
61
+ /** Model calls one call may make while the model asks for tools. Default 10 (25 for a durable run). */
62
+ maxSteps?: number;
63
+ budget?: AiBudget;
64
+ }
65
+ /** `forRoot()`'s options, and what the `forRootAsync()` factory returns. */
66
+ export interface AiModuleOptions {
67
+ /**
68
+ * The models, by name: a `LanguageModel` (`anthropic('claude-opus-5-5')`, a gateway id such as
69
+ * `'openai/gpt-5'`), or a definition with its pricing, fallback and settings. Calls that name no model use
70
+ * `default`.
71
+ */
72
+ models?: Record<string, LanguageModel | AiModelDefinition>;
73
+ defaults?: AiCallDefaults;
74
+ /**
75
+ * Named embedding models, independent of `models`. At least one of the two registries must be
76
+ * nonempty.
77
+ */
78
+ embeddingModels?: Record<string, EmbeddingModel | AiEmbeddingModelDefinition>;
79
+ /**
80
+ * Embedding-only defaults. They do not inherit generation settings, headers or options from
81
+ * `defaults`.
82
+ */
83
+ embeddingDefaults?: AiEmbeddingSettings;
84
+ /** Called after every model call that answered, with its tokens and cost. Errors it throws are logged. */
85
+ onUsage?: (event: AiUsageEvent) => void | Promise<void>;
86
+ /** Called once after a successful embedding operation. Errors it throws are logged. */
87
+ onEmbeddingUsage?: (event: AiEmbeddingUsageEvent) => void | Promise<void>;
88
+ /**
89
+ * The modules whose providers are searched for agent functions (`@AgentFunction()` methods). Default: every module
90
+ * of the application.
91
+ */
92
+ include?: Function[];
93
+ }
94
+ /** What only the top level of `forRoot()` and `forRootAsync()` takes. */
95
+ export interface AiModuleStructure {
96
+ /**
97
+ * Model names `@InjectModel()` may inject, beyond those it was seen asking for when the module was defined (the
98
+ * classes the module's file imports): for classes loaded later, such as lazily loaded modules.
99
+ */
100
+ modelNames?: string[];
101
+ /**
102
+ * Embedding-model counterpart of `modelNames`, for injection sites loaded after module
103
+ * definition.
104
+ */
105
+ embeddingModelNames?: string[];
106
+ }
107
+ /** What a class passed to `forRootAsync({ useClass })` implements. */
108
+ export interface AiOptionsFactory {
109
+ createAiOptions(): AiModuleOptions | Promise<AiModuleOptions>;
110
+ }
@@ -0,0 +1 @@
1
+ export {};