@mgvdev/nestjs-ai 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +655 -0
  3. package/dist/ai-module-options.interface-B5X4AFLC.d.cts +192 -0
  4. package/dist/ai-module-options.interface-Ca6y_MY2.d.ts +192 -0
  5. package/dist/conversation-store.interface-CtQY-qcc.d.cts +30 -0
  6. package/dist/conversation-store.interface-CtQY-qcc.d.ts +30 -0
  7. package/dist/index.cjs +3209 -0
  8. package/dist/index.cjs.map +1 -0
  9. package/dist/index.d.cts +1441 -0
  10. package/dist/index.d.ts +1441 -0
  11. package/dist/index.js +3163 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/stream-to-socket-fJphU0WN.d.cts +47 -0
  14. package/dist/stream-to-socket-fJphU0WN.d.ts +47 -0
  15. package/dist/testing.cjs +2395 -0
  16. package/dist/testing.cjs.map +1 -0
  17. package/dist/testing.d.cts +46 -0
  18. package/dist/testing.d.ts +46 -0
  19. package/dist/testing.js +2391 -0
  20. package/dist/testing.js.map +1 -0
  21. package/dist/typeorm.cjs +115 -0
  22. package/dist/typeorm.cjs.map +1 -0
  23. package/dist/typeorm.d.cts +44 -0
  24. package/dist/typeorm.d.ts +44 -0
  25. package/dist/typeorm.js +113 -0
  26. package/dist/typeorm.js.map +1 -0
  27. package/dist/websocket.cjs +154 -0
  28. package/dist/websocket.cjs.map +1 -0
  29. package/dist/websocket.d.cts +25 -0
  30. package/dist/websocket.d.ts +25 -0
  31. package/dist/websocket.js +152 -0
  32. package/dist/websocket.js.map +1 -0
  33. package/documentation/README.md +44 -0
  34. package/documentation/agents-and-tools.md +102 -0
  35. package/documentation/api-reference.md +117 -0
  36. package/documentation/configuration.md +87 -0
  37. package/documentation/content-safety.md +51 -0
  38. package/documentation/embeddings-and-rag.md +105 -0
  39. package/documentation/evals-and-testing.md +56 -0
  40. package/documentation/getting-started.md +96 -0
  41. package/documentation/guardrails-events-telemetry.md +72 -0
  42. package/documentation/jobs-and-realtime.md +69 -0
  43. package/documentation/memory.md +101 -0
  44. package/documentation/multimodal.md +49 -0
  45. package/documentation/orchestration-and-mcp.md +68 -0
  46. package/documentation/prompts.md +51 -0
  47. package/documentation/reliability.md +90 -0
  48. package/documentation/structured-output-and-streaming.md +81 -0
  49. package/package.json +146 -0
  50. package/skill/nestjs-ai/SKILL.md +154 -0
@@ -0,0 +1,113 @@
1
+ import { PrimaryGeneratedColumn, Index, Column, Entity } from 'typeorm';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
5
+ function _ts_decorate(decorators, target, key, desc) {
6
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
7
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
8
+ 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;
9
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
10
+ }
11
+ __name(_ts_decorate, "_ts_decorate");
12
+ function _ts_metadata(k, v) {
13
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
14
+ }
15
+ __name(_ts_metadata, "_ts_metadata");
16
+ var ConversationMessageEntity = class {
17
+ static {
18
+ __name(this, "ConversationMessageEntity");
19
+ }
20
+ id;
21
+ conversationId;
22
+ role;
23
+ /** Message content stored as JSON to preserve structured parts. */
24
+ content;
25
+ position;
26
+ createdAt;
27
+ };
28
+ _ts_decorate([
29
+ PrimaryGeneratedColumn("uuid"),
30
+ _ts_metadata("design:type", String)
31
+ ], ConversationMessageEntity.prototype, "id", void 0);
32
+ _ts_decorate([
33
+ Index(),
34
+ Column(),
35
+ _ts_metadata("design:type", String)
36
+ ], ConversationMessageEntity.prototype, "conversationId", void 0);
37
+ _ts_decorate([
38
+ Column(),
39
+ _ts_metadata("design:type", String)
40
+ ], ConversationMessageEntity.prototype, "role", void 0);
41
+ _ts_decorate([
42
+ Column({
43
+ type: "simple-json"
44
+ }),
45
+ _ts_metadata("design:type", Object)
46
+ ], ConversationMessageEntity.prototype, "content", void 0);
47
+ _ts_decorate([
48
+ Column({
49
+ type: "bigint"
50
+ }),
51
+ _ts_metadata("design:type", Number)
52
+ ], ConversationMessageEntity.prototype, "position", void 0);
53
+ _ts_decorate([
54
+ Column({
55
+ type: "datetime",
56
+ default: /* @__PURE__ */ __name(() => "CURRENT_TIMESTAMP", "default")
57
+ }),
58
+ _ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
59
+ ], ConversationMessageEntity.prototype, "createdAt", void 0);
60
+ ConversationMessageEntity = _ts_decorate([
61
+ Entity("ai_conversation_messages")
62
+ ], ConversationMessageEntity);
63
+
64
+ // src/memory/adapters/typeorm/typeorm-conversation.store.ts
65
+ var TypeOrmConversationStore = class {
66
+ static {
67
+ __name(this, "TypeOrmConversationStore");
68
+ }
69
+ repository;
70
+ constructor(repository) {
71
+ this.repository = repository;
72
+ }
73
+ async load(conversationId) {
74
+ const rows = await this.repository.find({
75
+ where: {
76
+ conversationId
77
+ },
78
+ order: {
79
+ position: "ASC"
80
+ }
81
+ });
82
+ return rows.map((row) => ({
83
+ role: row.role,
84
+ content: row.content
85
+ }));
86
+ }
87
+ async append(conversationId, messages) {
88
+ if (messages.length === 0) {
89
+ return;
90
+ }
91
+ const base = await this.repository.count({
92
+ where: {
93
+ conversationId
94
+ }
95
+ });
96
+ const entities = messages.map((message, index) => this.repository.create({
97
+ conversationId,
98
+ role: message.role,
99
+ content: message.content,
100
+ position: base + index
101
+ }));
102
+ await this.repository.save(entities);
103
+ }
104
+ async clear(conversationId) {
105
+ await this.repository.delete({
106
+ conversationId
107
+ });
108
+ }
109
+ };
110
+
111
+ export { ConversationMessageEntity, TypeOrmConversationStore };
112
+ //# sourceMappingURL=typeorm.js.map
113
+ //# sourceMappingURL=typeorm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/memory/adapters/typeorm/conversation-message.entity.ts","../src/memory/adapters/typeorm/typeorm-conversation.store.ts"],"names":["ConversationMessageEntity","id","conversationId","role","content","position","createdAt","type","default","TypeOrmConversationStore","repository","load","rows","find","where","order","map","row","append","messages","length","base","count","entities","message","index","create","save","clear","delete"],"mappings":";;;;;;;;;;;;;;;AAQO,IAAMA,4BAAN,MAAMA;AAAAA,EAAAA;;;AAEXC,EAAAA,EAAAA;AAIAC,EAAAA,cAAAA;AAGAC,EAAAA,IAAAA;;AAIAC,EAAAA,OAAAA;AAGAC,EAAAA,QAAAA;AAGAC,EAAAA,SAAAA;AACF;;;;;;;;;;;;;;;;IARYC,IAAAA,EAAM;;;;;;IAGNA,IAAAA,EAAM;;;;;;IAGNA,IAAAA,EAAM,UAAA;AAAYC,IAAAA,OAAAA,+BAAe,mBAAA,EAAN,SAAA;;;;;;;;;ACLhC,IAAMC,2BAAN,MAAMA;EAhBb;;;;AAiBE,EAAA,WAAA,CACmBC,UAAAA,EACjB;SADiBA,UAAAA,GAAAA,UAAAA;AAChB,EAAA;AAEH,EAAA,MAAMC,KAAKT,cAAAA,EAA8C;AACvD,IAAA,MAAMU,IAAAA,GAAO,MAAM,IAAA,CAAKF,UAAAA,CAAWG,IAAAA,CAAK;MACtCC,KAAAA,EAAO;AAAEZ,QAAAA;AAAe,OAAA;MACxBa,KAAAA,EAAO;QAAEV,QAAAA,EAAU;AAAM;KAC3B,CAAA;AACA,IAAA,OAAOO,IAAAA,CAAKI,GAAAA,CAAI,CAACC,GAAAA,MAAS;AACxBd,MAAAA,IAAAA,EAAMc,GAAAA,CAAId,IAAAA;AACVC,MAAAA,OAAAA,EAASa,GAAAA,CAAIb;KACf,CAAA,CAAA;AACF,EAAA;EAEA,MAAMc,MAAAA,CACJhB,gBACAiB,QAAAA,EACe;AACf,IAAA,IAAIA,QAAAA,CAASC,WAAW,CAAA,EAAG;AACzB,MAAA;AACF,IAAA;AACA,IAAA,MAAMC,IAAAA,GAAO,MAAM,IAAA,CAAKX,UAAAA,CAAWY,KAAAA,CAAM;MAAER,KAAAA,EAAO;AAAEZ,QAAAA;AAAe;KAAE,CAAA;AACrE,IAAA,MAAMqB,QAAAA,GAAWJ,SAASH,GAAAA,CAAI,CAACQ,SAASC,KAAAA,KACtC,IAAA,CAAKf,WAAWgB,MAAAA,CAAO;AACrBxB,MAAAA,cAAAA;AACAC,MAAAA,IAAAA,EAAMqB,OAAAA,CAAQrB,IAAAA;AACdC,MAAAA,OAAAA,EAASoB,OAAAA,CAAQpB,OAAAA;AACjBC,MAAAA,QAAAA,EAAUgB,IAAAA,GAAOI;AACnB,KAAA,CAAA,CAAA;AAEF,IAAA,MAAM,IAAA,CAAKf,UAAAA,CAAWiB,IAAAA,CAAKJ,QAAAA,CAAAA;AAC7B,EAAA;AAEA,EAAA,MAAMK,MAAM1B,cAAAA,EAAuC;AACjD,IAAA,MAAM,IAAA,CAAKQ,WAAWmB,MAAAA,CAAO;AAAE3B,MAAAA;KAAe,CAAA;AAChD,EAAA;AACF","file":"typeorm.js","sourcesContent":["import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';\n\n/**\n * Persisted conversation message. Register this entity in your TypeORM\n * `DataSource` (`entities: [ConversationMessageEntity]`) and wire\n * `TypeOrmConversationStore` as the module's `conversationStore`.\n */\n@Entity('ai_conversation_messages')\nexport class ConversationMessageEntity {\n @PrimaryGeneratedColumn('uuid')\n id!: string;\n\n @Index()\n @Column()\n conversationId!: string;\n\n @Column()\n role!: string;\n\n /** Message content stored as JSON to preserve structured parts. */\n @Column({ type: 'simple-json' })\n content!: unknown;\n\n @Column({ type: 'bigint' })\n position!: number;\n\n @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })\n createdAt!: Date;\n}\n","import type { Repository } from 'typeorm';\nimport type { AiMessage } from '../../../messages/message.types.js';\nimport type { ConversationStore } from '../../conversation-store.interface.js';\nimport { ConversationMessageEntity } from './conversation-message.entity.js';\n\n/**\n * TypeORM-backed conversation store. Framework-agnostic: pass a\n * `Repository<ConversationMessageEntity>` (obtain it via `@nestjs/typeorm`'s\n * `getRepositoryToken` in a factory provider). Messages are ordered by an\n * append-only `position` column.\n *\n * @example\n * ```ts\n * AiModule.forRoot({\n * conversationStore: {\n * useFactory: (repo) => new TypeOrmConversationStore(repo),\n * inject: [getRepositoryToken(ConversationMessageEntity)],\n * },\n * })\n * ```\n */\nexport class TypeOrmConversationStore implements ConversationStore {\n constructor(\n private readonly repository: Repository<ConversationMessageEntity>,\n ) {}\n\n async load(conversationId: string): Promise<AiMessage[]> {\n const rows = await this.repository.find({\n where: { conversationId },\n order: { position: 'ASC' },\n });\n return rows.map((row) => ({\n role: row.role,\n content: row.content,\n })) as AiMessage[];\n }\n\n async append(\n conversationId: string,\n messages: AiMessage[],\n ): Promise<void> {\n if (messages.length === 0) {\n return;\n }\n const base = await this.repository.count({ where: { conversationId } });\n const entities = messages.map((message, index) =>\n this.repository.create({\n conversationId,\n role: message.role,\n content: message.content,\n position: base + index,\n }),\n );\n await this.repository.save(entities);\n }\n\n async clear(conversationId: string): Promise<void> {\n await this.repository.delete({ conversationId });\n }\n}\n"]}
@@ -0,0 +1,154 @@
1
+ 'use strict';
2
+
3
+ var websockets = require('@nestjs/websockets');
4
+ var common = require('@nestjs/common');
5
+ var core = require('@nestjs/core');
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
+
10
+ // src/ai.constants.ts
11
+ var AGENT_METADATA = /* @__PURE__ */ Symbol("nestjs-ai:agent");
12
+
13
+ // src/agent/orchestration/agent-registry.ts
14
+ function _ts_decorate(decorators, target, key, desc) {
15
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
+ 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;
18
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
19
+ }
20
+ __name(_ts_decorate, "_ts_decorate");
21
+ function _ts_metadata(k, v) {
22
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
23
+ }
24
+ __name(_ts_metadata, "_ts_metadata");
25
+ var AgentRegistry = class {
26
+ static {
27
+ __name(this, "AgentRegistry");
28
+ }
29
+ discovery;
30
+ agents = /* @__PURE__ */ new Map();
31
+ constructor(discovery) {
32
+ this.discovery = discovery;
33
+ }
34
+ onModuleInit() {
35
+ for (const wrapper of this.discovery.getProviders()) {
36
+ const instance = wrapper.instance;
37
+ const ctor = instance?.constructor;
38
+ if (instance && ctor && Reflect.getMetadata(AGENT_METADATA, ctor)) {
39
+ this.agents.set(ctor.name, {
40
+ name: ctor.name,
41
+ instance,
42
+ target: ctor
43
+ });
44
+ }
45
+ }
46
+ }
47
+ /** Returns an agent instance by class name. */
48
+ get(name) {
49
+ return this.agents.get(name)?.instance;
50
+ }
51
+ /** Returns an agent instance by its class. */
52
+ getByClass(target) {
53
+ return this.agents.get(target.name)?.instance;
54
+ }
55
+ /** All discovered agents. */
56
+ all() {
57
+ return [
58
+ ...this.agents.values()
59
+ ];
60
+ }
61
+ };
62
+ AgentRegistry = _ts_decorate([
63
+ common.Injectable(),
64
+ _ts_metadata("design:type", Function),
65
+ _ts_metadata("design:paramtypes", [
66
+ typeof core.DiscoveryService === "undefined" ? Object : core.DiscoveryService
67
+ ])
68
+ ], AgentRegistry);
69
+
70
+ // src/websocket/stream-to-socket.ts
71
+ async function streamAgentToSocket(stream, socket, options = {}) {
72
+ const chunkEvent = options.chunkEvent ?? "agent:chunk";
73
+ const doneEvent = options.doneEvent ?? "agent:done";
74
+ const errorEvent = options.errorEvent ?? "agent:error";
75
+ try {
76
+ let text = "";
77
+ for await (const delta of stream.textStream) {
78
+ text += delta;
79
+ socket.emit(chunkEvent, {
80
+ delta
81
+ });
82
+ }
83
+ socket.emit(doneEvent, {
84
+ text
85
+ });
86
+ return text;
87
+ } catch (error) {
88
+ socket.emit(errorEvent, {
89
+ message: error instanceof Error ? error.message : String(error)
90
+ });
91
+ throw error;
92
+ }
93
+ }
94
+ __name(streamAgentToSocket, "streamAgentToSocket");
95
+
96
+ // src/websocket/agent.gateway.ts
97
+ function _ts_decorate2(decorators, target, key, desc) {
98
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
99
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
100
+ 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;
101
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
102
+ }
103
+ __name(_ts_decorate2, "_ts_decorate");
104
+ function _ts_metadata2(k, v) {
105
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
106
+ }
107
+ __name(_ts_metadata2, "_ts_metadata");
108
+ function _ts_param(paramIndex, decorator) {
109
+ return function(target, key) {
110
+ decorator(target, key, paramIndex);
111
+ };
112
+ }
113
+ __name(_ts_param, "_ts_param");
114
+ exports.AgentGateway = class AgentGateway {
115
+ static {
116
+ __name(this, "AgentGateway");
117
+ }
118
+ agents;
119
+ constructor(agents) {
120
+ this.agents = agents;
121
+ }
122
+ async run(message, client) {
123
+ const agent = this.agents.get(message.agent);
124
+ if (!agent) {
125
+ client.emit("agent:error", {
126
+ message: `Unknown agent "${message.agent}".`
127
+ });
128
+ return;
129
+ }
130
+ await streamAgentToSocket(agent.stream(message.input), client);
131
+ }
132
+ };
133
+ _ts_decorate2([
134
+ websockets.SubscribeMessage("agent:run"),
135
+ _ts_param(0, websockets.MessageBody()),
136
+ _ts_param(1, websockets.ConnectedSocket()),
137
+ _ts_metadata2("design:type", Function),
138
+ _ts_metadata2("design:paramtypes", [
139
+ typeof AgentRunMessage === "undefined" ? Object : AgentRunMessage,
140
+ typeof SocketLike === "undefined" ? Object : SocketLike
141
+ ]),
142
+ _ts_metadata2("design:returntype", Promise)
143
+ ], exports.AgentGateway.prototype, "run", null);
144
+ exports.AgentGateway = _ts_decorate2([
145
+ websockets.WebSocketGateway(),
146
+ _ts_metadata2("design:type", Function),
147
+ _ts_metadata2("design:paramtypes", [
148
+ typeof AgentRegistry === "undefined" ? Object : AgentRegistry
149
+ ])
150
+ ], exports.AgentGateway);
151
+
152
+ exports.streamAgentToSocket = streamAgentToSocket;
153
+ //# sourceMappingURL=websocket.cjs.map
154
+ //# sourceMappingURL=websocket.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ai.constants.ts","../src/agent/orchestration/agent-registry.ts","../src/websocket/stream-to-socket.ts","../src/websocket/agent.gateway.ts"],"names":["AGENT_METADATA","AgentRegistry","agents","Map","discovery","onModuleInit","wrapper","getProviders","instance","ctor","Reflect","getMetadata","set","name","target","get","getByClass","all","values","streamAgentToSocket","stream","socket","options","chunkEvent","doneEvent","errorEvent","text","delta","textStream","emit","error","message","Error","String","AgentGateway","run","client","agent","input"],"mappings":"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","file":"websocket.cjs","sourcesContent":["/**\n * Dependency-injection tokens used across the module.\n */\nexport const AI_MODULE_OPTIONS = Symbol('AI_MODULE_OPTIONS');\nexport const CONVERSATION_STORE = Symbol('CONVERSATION_STORE');\nexport const VECTOR_STORE = Symbol('VECTOR_STORE');\nexport const AI_CACHE = Symbol('AI_CACHE');\nexport const APPROVAL_GATE = Symbol('APPROVAL_GATE');\nexport const AGENT_QUEUE = Symbol('AGENT_QUEUE');\nexport const RATE_LIMITER = Symbol('RATE_LIMITER');\nexport const RERANKER = Symbol('RERANKER');\n\n/**\n * Reflect metadata keys for the `@Tool` and `@Agent` decorators.\n */\nexport const TOOL_METADATA = Symbol('nestjs-ai:tool');\nexport const AGENT_METADATA = Symbol('nestjs-ai:agent');\nexport const GUARDRAIL_METADATA = Symbol('nestjs-ai:guardrail');\n\n/**\n * Default number of tool-calling steps allowed before an agent run stops.\n */\nexport const DEFAULT_MAX_STEPS = 5;\n","import { Injectable, type OnModuleInit, type Type } from '@nestjs/common';\nimport { DiscoveryService } from '@nestjs/core';\nimport { AGENT_METADATA } from '../../ai.constants.js';\n\n/** A discovered agent instance and its class. */\nexport interface AgentEntry {\n name: string;\n instance: any;\n target: Type<any>;\n}\n\n/**\n * Indexes every `@Agent`-decorated provider by class name, enabling\n * multi-agent orchestration (supervisor/handoff) and background-job resolution.\n */\n@Injectable()\nexport class AgentRegistry implements OnModuleInit {\n private readonly agents = new Map<string, AgentEntry>();\n\n constructor(private readonly discovery: DiscoveryService) {}\n\n onModuleInit(): void {\n for (const wrapper of this.discovery.getProviders()) {\n const instance = wrapper.instance;\n const ctor = instance?.constructor as Type<any> | undefined;\n if (instance && ctor && Reflect.getMetadata(AGENT_METADATA, ctor)) {\n this.agents.set(ctor.name, { name: ctor.name, instance, target: ctor });\n }\n }\n }\n\n /** Returns an agent instance by class name. */\n get(name: string): any | undefined {\n return this.agents.get(name)?.instance;\n }\n\n /** Returns an agent instance by its class. */\n getByClass(target: Type<any>): any | undefined {\n return this.agents.get(target.name)?.instance;\n }\n\n /** All discovered agents. */\n all(): AgentEntry[] {\n return [...this.agents.values()];\n }\n}\n","/** Minimal socket shape (compatible with socket.io's `Socket`). */\nexport interface SocketLike {\n emit(event: string, payload?: unknown): void;\n}\n\n/** A stream result exposing a text stream (from agent `.stream()`). */\nexport interface TextStreamLike {\n textStream: AsyncIterable<string>;\n}\n\nexport interface StreamToSocketOptions {\n chunkEvent?: string;\n doneEvent?: string;\n errorEvent?: string;\n}\n\n/**\n * Forwards an agent text stream to a socket: emits `chunkEvent` per delta, then\n * `doneEvent` with the full text; emits `errorEvent` and rethrows on failure.\n * Framework-agnostic — the WebSocket gateway is thin glue over this.\n */\nexport async function streamAgentToSocket(\n stream: TextStreamLike,\n socket: SocketLike,\n options: StreamToSocketOptions = {},\n): Promise<string> {\n const chunkEvent = options.chunkEvent ?? 'agent:chunk';\n const doneEvent = options.doneEvent ?? 'agent:done';\n const errorEvent = options.errorEvent ?? 'agent:error';\n\n try {\n let text = '';\n for await (const delta of stream.textStream) {\n text += delta;\n socket.emit(chunkEvent, { delta });\n }\n socket.emit(doneEvent, { text });\n return text;\n } catch (error) {\n socket.emit(errorEvent, {\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n}\n","import {\n ConnectedSocket,\n MessageBody,\n SubscribeMessage,\n WebSocketGateway,\n} from '@nestjs/websockets';\nimport { AgentRegistry } from '../agent/orchestration/agent-registry.js';\nimport {\n streamAgentToSocket,\n type SocketLike,\n} from './stream-to-socket.js';\n\n/** Payload for the `agent:run` message. */\nexport interface AgentRunMessage {\n agent: string;\n input: string;\n}\n\n/**\n * WebSocket gateway that streams agent responses over socket.io. Client emits\n * `agent:run { agent, input }`; the server streams `agent:chunk { delta }` then\n * `agent:done { text }`. Requires the optional peers `@nestjs/websockets`,\n * `@nestjs/platform-socket.io`, and `socket.io`.\n *\n * Published under `@mgvdev/nestjs-ai/websocket`.\n */\n@WebSocketGateway()\nexport class AgentGateway {\n constructor(private readonly agents: AgentRegistry) {}\n\n @SubscribeMessage('agent:run')\n async run(\n @MessageBody() message: AgentRunMessage,\n @ConnectedSocket() client: SocketLike,\n ): Promise<void> {\n const agent = this.agents.get(message.agent);\n if (!agent) {\n client.emit('agent:error', {\n message: `Unknown agent \"${message.agent}\".`,\n });\n return;\n }\n await streamAgentToSocket(agent.stream(message.input), client);\n }\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import { A as AgentRegistry, S as SocketLike } from './stream-to-socket-fJphU0WN.cjs';
2
+ export { b as StreamToSocketOptions, T as TextStreamLike, s as streamAgentToSocket } from './stream-to-socket-fJphU0WN.cjs';
3
+ import '@nestjs/common';
4
+ import '@nestjs/core';
5
+
6
+ /** Payload for the `agent:run` message. */
7
+ interface AgentRunMessage {
8
+ agent: string;
9
+ input: string;
10
+ }
11
+ /**
12
+ * WebSocket gateway that streams agent responses over socket.io. Client emits
13
+ * `agent:run { agent, input }`; the server streams `agent:chunk { delta }` then
14
+ * `agent:done { text }`. Requires the optional peers `@nestjs/websockets`,
15
+ * `@nestjs/platform-socket.io`, and `socket.io`.
16
+ *
17
+ * Published under `@mgvdev/nestjs-ai/websocket`.
18
+ */
19
+ declare class AgentGateway {
20
+ private readonly agents;
21
+ constructor(agents: AgentRegistry);
22
+ run(message: AgentRunMessage, client: SocketLike): Promise<void>;
23
+ }
24
+
25
+ export { AgentGateway, type AgentRunMessage, SocketLike };
@@ -0,0 +1,25 @@
1
+ import { A as AgentRegistry, S as SocketLike } from './stream-to-socket-fJphU0WN.js';
2
+ export { b as StreamToSocketOptions, T as TextStreamLike, s as streamAgentToSocket } from './stream-to-socket-fJphU0WN.js';
3
+ import '@nestjs/common';
4
+ import '@nestjs/core';
5
+
6
+ /** Payload for the `agent:run` message. */
7
+ interface AgentRunMessage {
8
+ agent: string;
9
+ input: string;
10
+ }
11
+ /**
12
+ * WebSocket gateway that streams agent responses over socket.io. Client emits
13
+ * `agent:run { agent, input }`; the server streams `agent:chunk { delta }` then
14
+ * `agent:done { text }`. Requires the optional peers `@nestjs/websockets`,
15
+ * `@nestjs/platform-socket.io`, and `socket.io`.
16
+ *
17
+ * Published under `@mgvdev/nestjs-ai/websocket`.
18
+ */
19
+ declare class AgentGateway {
20
+ private readonly agents;
21
+ constructor(agents: AgentRegistry);
22
+ run(message: AgentRunMessage, client: SocketLike): Promise<void>;
23
+ }
24
+
25
+ export { AgentGateway, type AgentRunMessage, SocketLike };
@@ -0,0 +1,152 @@
1
+ import { SubscribeMessage, MessageBody, ConnectedSocket, WebSocketGateway } from '@nestjs/websockets';
2
+ import { Injectable } from '@nestjs/common';
3
+ import { DiscoveryService } from '@nestjs/core';
4
+
5
+ var __defProp = Object.defineProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+
8
+ // src/ai.constants.ts
9
+ var AGENT_METADATA = /* @__PURE__ */ Symbol("nestjs-ai:agent");
10
+
11
+ // src/agent/orchestration/agent-registry.ts
12
+ function _ts_decorate(decorators, target, key, desc) {
13
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
14
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
15
+ 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;
16
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
17
+ }
18
+ __name(_ts_decorate, "_ts_decorate");
19
+ function _ts_metadata(k, v) {
20
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
21
+ }
22
+ __name(_ts_metadata, "_ts_metadata");
23
+ var AgentRegistry = class {
24
+ static {
25
+ __name(this, "AgentRegistry");
26
+ }
27
+ discovery;
28
+ agents = /* @__PURE__ */ new Map();
29
+ constructor(discovery) {
30
+ this.discovery = discovery;
31
+ }
32
+ onModuleInit() {
33
+ for (const wrapper of this.discovery.getProviders()) {
34
+ const instance = wrapper.instance;
35
+ const ctor = instance?.constructor;
36
+ if (instance && ctor && Reflect.getMetadata(AGENT_METADATA, ctor)) {
37
+ this.agents.set(ctor.name, {
38
+ name: ctor.name,
39
+ instance,
40
+ target: ctor
41
+ });
42
+ }
43
+ }
44
+ }
45
+ /** Returns an agent instance by class name. */
46
+ get(name) {
47
+ return this.agents.get(name)?.instance;
48
+ }
49
+ /** Returns an agent instance by its class. */
50
+ getByClass(target) {
51
+ return this.agents.get(target.name)?.instance;
52
+ }
53
+ /** All discovered agents. */
54
+ all() {
55
+ return [
56
+ ...this.agents.values()
57
+ ];
58
+ }
59
+ };
60
+ AgentRegistry = _ts_decorate([
61
+ Injectable(),
62
+ _ts_metadata("design:type", Function),
63
+ _ts_metadata("design:paramtypes", [
64
+ typeof DiscoveryService === "undefined" ? Object : DiscoveryService
65
+ ])
66
+ ], AgentRegistry);
67
+
68
+ // src/websocket/stream-to-socket.ts
69
+ async function streamAgentToSocket(stream, socket, options = {}) {
70
+ const chunkEvent = options.chunkEvent ?? "agent:chunk";
71
+ const doneEvent = options.doneEvent ?? "agent:done";
72
+ const errorEvent = options.errorEvent ?? "agent:error";
73
+ try {
74
+ let text = "";
75
+ for await (const delta of stream.textStream) {
76
+ text += delta;
77
+ socket.emit(chunkEvent, {
78
+ delta
79
+ });
80
+ }
81
+ socket.emit(doneEvent, {
82
+ text
83
+ });
84
+ return text;
85
+ } catch (error) {
86
+ socket.emit(errorEvent, {
87
+ message: error instanceof Error ? error.message : String(error)
88
+ });
89
+ throw error;
90
+ }
91
+ }
92
+ __name(streamAgentToSocket, "streamAgentToSocket");
93
+
94
+ // src/websocket/agent.gateway.ts
95
+ function _ts_decorate2(decorators, target, key, desc) {
96
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
97
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
98
+ 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;
99
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
100
+ }
101
+ __name(_ts_decorate2, "_ts_decorate");
102
+ function _ts_metadata2(k, v) {
103
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
104
+ }
105
+ __name(_ts_metadata2, "_ts_metadata");
106
+ function _ts_param(paramIndex, decorator) {
107
+ return function(target, key) {
108
+ decorator(target, key, paramIndex);
109
+ };
110
+ }
111
+ __name(_ts_param, "_ts_param");
112
+ var AgentGateway = class {
113
+ static {
114
+ __name(this, "AgentGateway");
115
+ }
116
+ agents;
117
+ constructor(agents) {
118
+ this.agents = agents;
119
+ }
120
+ async run(message, client) {
121
+ const agent = this.agents.get(message.agent);
122
+ if (!agent) {
123
+ client.emit("agent:error", {
124
+ message: `Unknown agent "${message.agent}".`
125
+ });
126
+ return;
127
+ }
128
+ await streamAgentToSocket(agent.stream(message.input), client);
129
+ }
130
+ };
131
+ _ts_decorate2([
132
+ SubscribeMessage("agent:run"),
133
+ _ts_param(0, MessageBody()),
134
+ _ts_param(1, ConnectedSocket()),
135
+ _ts_metadata2("design:type", Function),
136
+ _ts_metadata2("design:paramtypes", [
137
+ typeof AgentRunMessage === "undefined" ? Object : AgentRunMessage,
138
+ typeof SocketLike === "undefined" ? Object : SocketLike
139
+ ]),
140
+ _ts_metadata2("design:returntype", Promise)
141
+ ], AgentGateway.prototype, "run", null);
142
+ AgentGateway = _ts_decorate2([
143
+ WebSocketGateway(),
144
+ _ts_metadata2("design:type", Function),
145
+ _ts_metadata2("design:paramtypes", [
146
+ typeof AgentRegistry === "undefined" ? Object : AgentRegistry
147
+ ])
148
+ ], AgentGateway);
149
+
150
+ export { AgentGateway, streamAgentToSocket };
151
+ //# sourceMappingURL=websocket.js.map
152
+ //# sourceMappingURL=websocket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ai.constants.ts","../src/agent/orchestration/agent-registry.ts","../src/websocket/stream-to-socket.ts","../src/websocket/agent.gateway.ts"],"names":["AGENT_METADATA","AgentRegistry","agents","Map","discovery","onModuleInit","wrapper","getProviders","instance","ctor","Reflect","getMetadata","set","name","target","get","getByClass","all","values","streamAgentToSocket","stream","socket","options","chunkEvent","doneEvent","errorEvent","text","delta","textStream","emit","error","message","Error","String","AgentGateway","run","client","agent","input"],"mappings":"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","file":"websocket.js","sourcesContent":["/**\n * Dependency-injection tokens used across the module.\n */\nexport const AI_MODULE_OPTIONS = Symbol('AI_MODULE_OPTIONS');\nexport const CONVERSATION_STORE = Symbol('CONVERSATION_STORE');\nexport const VECTOR_STORE = Symbol('VECTOR_STORE');\nexport const AI_CACHE = Symbol('AI_CACHE');\nexport const APPROVAL_GATE = Symbol('APPROVAL_GATE');\nexport const AGENT_QUEUE = Symbol('AGENT_QUEUE');\nexport const RATE_LIMITER = Symbol('RATE_LIMITER');\nexport const RERANKER = Symbol('RERANKER');\n\n/**\n * Reflect metadata keys for the `@Tool` and `@Agent` decorators.\n */\nexport const TOOL_METADATA = Symbol('nestjs-ai:tool');\nexport const AGENT_METADATA = Symbol('nestjs-ai:agent');\nexport const GUARDRAIL_METADATA = Symbol('nestjs-ai:guardrail');\n\n/**\n * Default number of tool-calling steps allowed before an agent run stops.\n */\nexport const DEFAULT_MAX_STEPS = 5;\n","import { Injectable, type OnModuleInit, type Type } from '@nestjs/common';\nimport { DiscoveryService } from '@nestjs/core';\nimport { AGENT_METADATA } from '../../ai.constants.js';\n\n/** A discovered agent instance and its class. */\nexport interface AgentEntry {\n name: string;\n instance: any;\n target: Type<any>;\n}\n\n/**\n * Indexes every `@Agent`-decorated provider by class name, enabling\n * multi-agent orchestration (supervisor/handoff) and background-job resolution.\n */\n@Injectable()\nexport class AgentRegistry implements OnModuleInit {\n private readonly agents = new Map<string, AgentEntry>();\n\n constructor(private readonly discovery: DiscoveryService) {}\n\n onModuleInit(): void {\n for (const wrapper of this.discovery.getProviders()) {\n const instance = wrapper.instance;\n const ctor = instance?.constructor as Type<any> | undefined;\n if (instance && ctor && Reflect.getMetadata(AGENT_METADATA, ctor)) {\n this.agents.set(ctor.name, { name: ctor.name, instance, target: ctor });\n }\n }\n }\n\n /** Returns an agent instance by class name. */\n get(name: string): any | undefined {\n return this.agents.get(name)?.instance;\n }\n\n /** Returns an agent instance by its class. */\n getByClass(target: Type<any>): any | undefined {\n return this.agents.get(target.name)?.instance;\n }\n\n /** All discovered agents. */\n all(): AgentEntry[] {\n return [...this.agents.values()];\n }\n}\n","/** Minimal socket shape (compatible with socket.io's `Socket`). */\nexport interface SocketLike {\n emit(event: string, payload?: unknown): void;\n}\n\n/** A stream result exposing a text stream (from agent `.stream()`). */\nexport interface TextStreamLike {\n textStream: AsyncIterable<string>;\n}\n\nexport interface StreamToSocketOptions {\n chunkEvent?: string;\n doneEvent?: string;\n errorEvent?: string;\n}\n\n/**\n * Forwards an agent text stream to a socket: emits `chunkEvent` per delta, then\n * `doneEvent` with the full text; emits `errorEvent` and rethrows on failure.\n * Framework-agnostic — the WebSocket gateway is thin glue over this.\n */\nexport async function streamAgentToSocket(\n stream: TextStreamLike,\n socket: SocketLike,\n options: StreamToSocketOptions = {},\n): Promise<string> {\n const chunkEvent = options.chunkEvent ?? 'agent:chunk';\n const doneEvent = options.doneEvent ?? 'agent:done';\n const errorEvent = options.errorEvent ?? 'agent:error';\n\n try {\n let text = '';\n for await (const delta of stream.textStream) {\n text += delta;\n socket.emit(chunkEvent, { delta });\n }\n socket.emit(doneEvent, { text });\n return text;\n } catch (error) {\n socket.emit(errorEvent, {\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n}\n","import {\n ConnectedSocket,\n MessageBody,\n SubscribeMessage,\n WebSocketGateway,\n} from '@nestjs/websockets';\nimport { AgentRegistry } from '../agent/orchestration/agent-registry.js';\nimport {\n streamAgentToSocket,\n type SocketLike,\n} from './stream-to-socket.js';\n\n/** Payload for the `agent:run` message. */\nexport interface AgentRunMessage {\n agent: string;\n input: string;\n}\n\n/**\n * WebSocket gateway that streams agent responses over socket.io. Client emits\n * `agent:run { agent, input }`; the server streams `agent:chunk { delta }` then\n * `agent:done { text }`. Requires the optional peers `@nestjs/websockets`,\n * `@nestjs/platform-socket.io`, and `socket.io`.\n *\n * Published under `@mgvdev/nestjs-ai/websocket`.\n */\n@WebSocketGateway()\nexport class AgentGateway {\n constructor(private readonly agents: AgentRegistry) {}\n\n @SubscribeMessage('agent:run')\n async run(\n @MessageBody() message: AgentRunMessage,\n @ConnectedSocket() client: SocketLike,\n ): Promise<void> {\n const agent = this.agents.get(message.agent);\n if (!agent) {\n client.emit('agent:error', {\n message: `Unknown agent \"${message.agent}\".`,\n });\n return;\n }\n await streamAgentToSocket(agent.stream(message.input), client);\n }\n}\n"]}
@@ -0,0 +1,44 @@
1
+ # @mgvdev/nestjs-ai — Documentation
2
+
3
+ A NestJS toolkit over the [Vercel AI SDK](https://ai-sdk.dev) (v7): DI-native
4
+ agents, tools, structured output, streaming, embeddings, RAG, multimodal,
5
+ prompts, guardrails, orchestration, MCP, and production features (cost, rate
6
+ limiting, memory, evals).
7
+
8
+ ## Table of contents
9
+
10
+ 1. [Getting started](./getting-started.md)
11
+ 2. [Configuration](./configuration.md)
12
+ 3. [Agents & tools](./agents-and-tools.md)
13
+ 4. [Structured output & streaming](./structured-output-and-streaming.md)
14
+ 5. [Embeddings & RAG](./embeddings-and-rag.md)
15
+ 6. [Multimodal (image / speech / transcription)](./multimodal.md)
16
+ 7. [Prompt registry](./prompts.md)
17
+ 8. [Memory (conversation & semantic)](./memory.md)
18
+ 9. [Guardrails, events & telemetry](./guardrails-events-telemetry.md)
19
+ 10. [Content safety (PII & moderation)](./content-safety.md)
20
+ 11. [Orchestration & MCP](./orchestration-and-mcp.md)
21
+ 12. [Reliability (fallback, retry, cache, rate limit, budgets)](./reliability.md)
22
+ 13. [Background jobs & realtime](./jobs-and-realtime.md)
23
+ 14. [Evals & testing](./evals-and-testing.md)
24
+ 15. [API reference](./api-reference.md)
25
+
26
+ ## Entry points
27
+
28
+ | Import | Contents |
29
+ | --- | --- |
30
+ | `@mgvdev/nestjs-ai` | Everything except the adapters below |
31
+ | `@mgvdev/nestjs-ai/typeorm` | `TypeOrmConversationStore`, `ConversationMessageEntity` |
32
+ | `@mgvdev/nestjs-ai/websocket` | `AgentGateway` |
33
+ | `@mgvdev/nestjs-ai/testing` | `createTestingAiModule`, `createMockModel` |
34
+
35
+ ## Peer dependencies
36
+
37
+ **Required:** `@nestjs/common`, `@nestjs/core`, `ai`, `zod`, `reflect-metadata`, `rxjs`.
38
+
39
+ **Optional** (install per feature): `@ai-sdk/openai` · `@ai-sdk/anthropic` ·
40
+ `@ai-sdk/google` · `@ai-sdk/cohere` (reranking) · `@nestjs/event-emitter`
41
+ (events) · `@nestjs/typeorm` + `typeorm` (TypeORM store) · `bullmq` (jobs) ·
42
+ `pg` (pgvector) · `@qdrant/js-client-rest` · `@pinecone-database/pinecone` ·
43
+ `@nestjs/websockets` + `@nestjs/platform-socket.io` + `socket.io` (realtime) ·
44
+ `@modelcontextprotocol/sdk` (MCP) · `msw` (testing).
@@ -0,0 +1,102 @@
1
+ # Agents & tools
2
+
3
+ ## Tools
4
+
5
+ A tool is a method on an injectable provider, decorated with `@Tool`. It keeps
6
+ full access to injected dependencies.
7
+
8
+ ```ts
9
+ @Injectable()
10
+ export class WeatherTools {
11
+ constructor(private readonly api: WeatherApi) {}
12
+
13
+ @Tool({
14
+ name: 'get_weather', // optional; defaults to the method name
15
+ description: 'Get the weather for a city',
16
+ schema: z.object({ city: z.string() }),
17
+ requiresApproval: false, // gate behind an ApprovalGate when true
18
+ })
19
+ getWeather({ city }: { city: string }) {
20
+ return this.api.lookup(city); // return value is fed back to the model
21
+ }
22
+ }
23
+ ```
24
+
25
+ - **`schema`** is a Zod schema for the arguments; the method receives the parsed object.
26
+ - The return value (any JSON-serializable value) is returned to the model.
27
+ - Tools are discovered automatically once the class is a registered provider.
28
+
29
+ ### `ToolRegistry`
30
+
31
+ Introspect discovered tools:
32
+
33
+ ```ts
34
+ constructor(private readonly tools: ToolRegistry) {}
35
+ this.tools.getAll(); // ToolEntry[]
36
+ this.tools.getByName('get_weather');
37
+ this.tools.buildToolSet([WeatherTools, 'get_weather']); // for AiService
38
+ ```
39
+
40
+ ## Agents
41
+
42
+ Extend `AiAgent` and annotate with `@Agent`.
43
+
44
+ ```ts
45
+ @Agent({
46
+ model: 'openai:gpt-4o', // string | string[] (fallback)
47
+ system: 'You are a helpful assistant.',
48
+ tools: [WeatherTools], // @Tool providers and/or @Agent sub-agents
49
+ maxSteps: 5, // tool-calling loop bound
50
+ output: z.object({ answer: z.string() }), // optional structured output
51
+ })
52
+ export class SupportAgent extends AiAgent {}
53
+ ```
54
+
55
+ ### Running
56
+
57
+ ```ts
58
+ const { text, usage, steps, toolCalls } = await agent.run('Weather in Paris?');
59
+ const { object } = await agent.run<Shape>(input); // when `output`/`schema` set
60
+ const stream = agent.stream('Hi'); // Vercel stream result
61
+ ```
62
+
63
+ ### `AgentRunOptions`
64
+
65
+ ```ts
66
+ await agent.run(input, {
67
+ model, // override model / fallback chain
68
+ system, // override system prompt
69
+ systemPrompt: { name, vars, version }, // resolve from PromptRegistry
70
+ conversationId, // load + persist history
71
+ maxSteps,
72
+ schema, // structured output for this call
73
+ temperature,
74
+ maxRetries,
75
+ recall: { query?, topK? }, // prepend semantic-memory context
76
+ abortSignal,
77
+ });
78
+ ```
79
+
80
+ `run()` returns an `AgentResult`: `{ text, object?, steps?, toolCalls?, usage?, finishReason?, messages }`.
81
+
82
+ ## The raw facade — `AiService`
83
+
84
+ When you don't want an agent class:
85
+
86
+ ```ts
87
+ const { text } = await this.ai.generateText({
88
+ model: 'openai:gpt-4o',
89
+ tools: [WeatherTools], // tool provider classes and/or names
90
+ prompt: 'Weather in Paris?',
91
+ });
92
+ ```
93
+
94
+ `AiService` mirrors `generateText` / `streamText` / `generateObject` /
95
+ `streamObject`, resolving `model` strings and `tools` references for you.
96
+
97
+ ## How the tool loop works
98
+
99
+ `run()` calls the model with the resolved tools and `stopWhen: stepCountIs(maxSteps)`.
100
+ When the model emits a tool call, the SDK executes the matching `@Tool` method on
101
+ its DI instance, feeds the result back, and continues until the model produces a
102
+ final answer or `maxSteps` is reached.