@snap-agent/core 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.
package/dist/index.mjs ADDED
@@ -0,0 +1,1284 @@
1
+ import {
2
+ MemoryStorage,
3
+ MongoDBStorage,
4
+ UpstashStorage
5
+ } from "./chunk-Y5TTFQWC.mjs";
6
+
7
+ // src/core/Agent.ts
8
+ import { generateText, streamText } from "ai";
9
+
10
+ // src/core/PluginManager.ts
11
+ var PluginManager = class {
12
+ constructor(plugins = []) {
13
+ this.plugins = plugins.sort((a, b) => {
14
+ const aPriority = a.priority ?? 100;
15
+ const bPriority = b.priority ?? 100;
16
+ return aPriority - bPriority;
17
+ });
18
+ }
19
+ // ============================================================================
20
+ // Plugin Getters by Type
21
+ // ============================================================================
22
+ getRAGPlugins() {
23
+ return this.plugins.filter((p) => p.type === "rag");
24
+ }
25
+ getToolPlugins() {
26
+ return this.plugins.filter((p) => p.type === "tool");
27
+ }
28
+ getMiddlewarePlugins() {
29
+ return this.plugins.filter((p) => p.type === "middleware");
30
+ }
31
+ getAnalyticsPlugins() {
32
+ return this.plugins.filter((p) => p.type === "analytics");
33
+ }
34
+ getAllPlugins() {
35
+ return [...this.plugins];
36
+ }
37
+ // ============================================================================
38
+ // RAG Plugin Execution
39
+ // ============================================================================
40
+ /**
41
+ * Execute all RAG plugins and merge their contexts
42
+ * Returns an array of context strings, one per plugin
43
+ */
44
+ async executeRAG(message, options) {
45
+ const ragPlugins = this.getRAGPlugins();
46
+ if (ragPlugins.length === 0) {
47
+ return { contexts: [], allMetadata: [] };
48
+ }
49
+ const results = await Promise.all(
50
+ ragPlugins.map(async (plugin) => {
51
+ try {
52
+ const context = await plugin.retrieveContext(message, options);
53
+ const formattedContext = plugin.formatContext ? plugin.formatContext(context) : context.content;
54
+ return {
55
+ context: formattedContext,
56
+ metadata: context.metadata || {},
57
+ pluginName: plugin.name
58
+ };
59
+ } catch (error) {
60
+ console.error(`RAG plugin "${plugin.name}" failed:`, error);
61
+ return {
62
+ context: "",
63
+ metadata: { error: error instanceof Error ? error.message : "Unknown error" },
64
+ pluginName: plugin.name
65
+ };
66
+ }
67
+ })
68
+ );
69
+ return {
70
+ contexts: results.map((r) => r.context).filter(Boolean),
71
+ allMetadata: results.map((r) => ({ [r.pluginName]: r.metadata }))
72
+ };
73
+ }
74
+ // ============================================================================
75
+ // Middleware Plugin Execution
76
+ // ============================================================================
77
+ /**
78
+ * Execute all middleware plugins before request
79
+ */
80
+ async executeBeforeRequest(messages, context) {
81
+ const middlewarePlugins = this.getMiddlewarePlugins();
82
+ let result = { messages, metadata: {} };
83
+ for (const plugin of middlewarePlugins) {
84
+ if (plugin.beforeRequest) {
85
+ try {
86
+ const pluginResult = await plugin.beforeRequest(result.messages, context);
87
+ result = { ...result, ...pluginResult };
88
+ } catch (error) {
89
+ console.error(`Middleware plugin "${plugin.name}" beforeRequest failed:`, error);
90
+ }
91
+ }
92
+ }
93
+ return result;
94
+ }
95
+ /**
96
+ * Execute all middleware plugins after response
97
+ */
98
+ async executeAfterResponse(response, context) {
99
+ const middlewarePlugins = this.getMiddlewarePlugins();
100
+ let result = { response, metadata: context.metadata };
101
+ for (const plugin of middlewarePlugins) {
102
+ if (plugin.afterResponse) {
103
+ try {
104
+ const pluginResult = await plugin.afterResponse(result.response, context);
105
+ result = { ...result, ...pluginResult };
106
+ } catch (error) {
107
+ console.error(`Middleware plugin "${plugin.name}" afterResponse failed:`, error);
108
+ }
109
+ }
110
+ }
111
+ return result;
112
+ }
113
+ // ============================================================================
114
+ // Analytics Plugin Execution
115
+ // ============================================================================
116
+ /**
117
+ * Track request in all analytics plugins
118
+ */
119
+ async trackRequest(data) {
120
+ const analyticsPlugins = this.getAnalyticsPlugins();
121
+ await Promise.all(
122
+ analyticsPlugins.map(async (plugin) => {
123
+ try {
124
+ await plugin.trackRequest(data);
125
+ } catch (error) {
126
+ console.error(`Analytics plugin "${plugin.name}" trackRequest failed:`, error);
127
+ }
128
+ })
129
+ );
130
+ }
131
+ /**
132
+ * Track response in all analytics plugins
133
+ */
134
+ async trackResponse(data) {
135
+ const analyticsPlugins = this.getAnalyticsPlugins();
136
+ await Promise.all(
137
+ analyticsPlugins.map(async (plugin) => {
138
+ try {
139
+ await plugin.trackResponse(data);
140
+ } catch (error) {
141
+ console.error(`Analytics plugin "${plugin.name}" trackResponse failed:`, error);
142
+ }
143
+ })
144
+ );
145
+ }
146
+ // ============================================================================
147
+ // Plugin Management
148
+ // ============================================================================
149
+ /**
150
+ * Check if any plugins of a specific type exist
151
+ */
152
+ hasPluginsOfType(type) {
153
+ return this.plugins.some((p) => p.type === type);
154
+ }
155
+ /**
156
+ * Get plugin by name
157
+ */
158
+ getPluginByName(name) {
159
+ return this.plugins.find((p) => p.name === name);
160
+ }
161
+ };
162
+
163
+ // src/types/index.ts
164
+ var AgentSDKError = class extends Error {
165
+ constructor(message) {
166
+ super(message);
167
+ this.name = "AgentSDKError";
168
+ }
169
+ };
170
+ var AgentNotFoundError = class extends AgentSDKError {
171
+ constructor(agentId) {
172
+ super(`Agent not found: ${agentId}`);
173
+ this.name = "AgentNotFoundError";
174
+ }
175
+ };
176
+ var ThreadNotFoundError = class extends AgentSDKError {
177
+ constructor(threadId) {
178
+ super(`Thread not found: ${threadId}`);
179
+ this.name = "ThreadNotFoundError";
180
+ }
181
+ };
182
+ var CouldNotCreateThreadError = class extends AgentSDKError {
183
+ constructor(threadId) {
184
+ super(`Could not create thread: ${threadId}`);
185
+ this.name = "CouldNotCreateThreadError";
186
+ }
187
+ };
188
+ var ProviderNotFoundError = class extends AgentSDKError {
189
+ constructor(provider) {
190
+ super(`Provider not configured: ${provider}`);
191
+ this.name = "ProviderNotFoundError";
192
+ }
193
+ };
194
+ var InvalidConfigError = class extends AgentSDKError {
195
+ constructor(message) {
196
+ super(`Invalid configuration: ${message}`);
197
+ this.name = "InvalidConfigError";
198
+ }
199
+ };
200
+
201
+ // src/core/Agent.ts
202
+ function extractTextContent(content) {
203
+ if (typeof content === "string") {
204
+ return content;
205
+ }
206
+ return content.map((part) => {
207
+ if ("text" in part) {
208
+ return part.text;
209
+ }
210
+ return "";
211
+ }).filter(Boolean).join(" ");
212
+ }
213
+ var Agent = class _Agent {
214
+ constructor(data, storage, providerFactory) {
215
+ this.data = data;
216
+ this.storage = storage;
217
+ this.providerFactory = providerFactory;
218
+ this.pluginManager = new PluginManager(data.plugins || []);
219
+ }
220
+ /**
221
+ * Create a new agent
222
+ */
223
+ static async create(config, storage, providerFactory) {
224
+ const agentId = await storage.createAgent(config);
225
+ const data = await storage.getAgent(agentId);
226
+ if (!data) {
227
+ throw new AgentNotFoundError(agentId);
228
+ }
229
+ return new _Agent(data, storage, providerFactory);
230
+ }
231
+ /**
232
+ * Load an existing agent by ID
233
+ */
234
+ static async load(agentId, storage, providerFactory) {
235
+ const data = await storage.getAgent(agentId);
236
+ if (!data) {
237
+ return null;
238
+ }
239
+ return new _Agent(data, storage, providerFactory);
240
+ }
241
+ /**
242
+ * Update agent properties
243
+ */
244
+ async update(updates) {
245
+ await this.storage.updateAgent(this.data.id, updates);
246
+ const updatedData = await this.storage.getAgent(this.data.id);
247
+ if (updatedData) {
248
+ this.data = updatedData;
249
+ }
250
+ }
251
+ /**
252
+ * Delete this agent
253
+ */
254
+ async delete() {
255
+ await this.storage.deleteAgent(this.data.id);
256
+ }
257
+ /**
258
+ * Add files to the agent
259
+ */
260
+ async addFiles(files) {
261
+ const currentFiles = [...this.data.files, ...files];
262
+ this.data.files = currentFiles;
263
+ this.data.updatedAt = /* @__PURE__ */ new Date();
264
+ }
265
+ /**
266
+ * Generate a text response with optional plugin support
267
+ */
268
+ async generateResponse(messages, options) {
269
+ const startTime = Date.now();
270
+ if (messages.length > 0) {
271
+ await this.pluginManager.trackRequest({
272
+ agentId: this.data.id,
273
+ threadId: options?.threadId,
274
+ message: extractTextContent(messages[messages.length - 1].content),
275
+ timestamp: /* @__PURE__ */ new Date()
276
+ });
277
+ }
278
+ const beforeResult = await this.pluginManager.executeBeforeRequest(messages, {
279
+ agentId: this.data.id,
280
+ threadId: options?.threadId
281
+ });
282
+ let systemPrompt = this.data.instructions;
283
+ let ragMetadata = [];
284
+ if (options?.useRAG && this.pluginManager.hasPluginsOfType("rag")) {
285
+ const lastMessage = messages[messages.length - 1];
286
+ const { contexts, allMetadata } = await this.pluginManager.executeRAG(
287
+ extractTextContent(lastMessage.content),
288
+ {
289
+ agentId: this.data.id,
290
+ threadId: options.threadId,
291
+ filters: options.ragFilters
292
+ }
293
+ );
294
+ if (contexts.length > 0) {
295
+ systemPrompt += "\n\n" + contexts.join("\n\n");
296
+ }
297
+ ragMetadata = allMetadata;
298
+ }
299
+ const model = await this.providerFactory.getModel(this.data.provider, this.data.model);
300
+ const { text } = await generateText({
301
+ model,
302
+ messages: beforeResult.messages,
303
+ system: systemPrompt
304
+ });
305
+ const afterResult = await this.pluginManager.executeAfterResponse(text, {
306
+ agentId: this.data.id,
307
+ threadId: options?.threadId,
308
+ metadata: beforeResult.metadata
309
+ });
310
+ const latency = Date.now() - startTime;
311
+ await this.pluginManager.trackResponse({
312
+ agentId: this.data.id,
313
+ threadId: options?.threadId,
314
+ response: afterResult.response,
315
+ latency,
316
+ timestamp: /* @__PURE__ */ new Date()
317
+ });
318
+ return {
319
+ text: afterResult.response,
320
+ metadata: {
321
+ ...afterResult.metadata,
322
+ ragMetadata,
323
+ latency
324
+ }
325
+ };
326
+ }
327
+ /**
328
+ * Stream a text response with optional plugin support
329
+ */
330
+ async streamResponse(messages, onChunk, onComplete, onError, options) {
331
+ try {
332
+ const startTime = Date.now();
333
+ if (messages.length > 0) {
334
+ await this.pluginManager.trackRequest({
335
+ agentId: this.data.id,
336
+ threadId: options?.threadId,
337
+ message: extractTextContent(messages[messages.length - 1].content),
338
+ timestamp: /* @__PURE__ */ new Date()
339
+ });
340
+ }
341
+ const beforeResult = await this.pluginManager.executeBeforeRequest(messages, {
342
+ agentId: this.data.id,
343
+ threadId: options?.threadId
344
+ });
345
+ let systemPrompt = this.data.instructions;
346
+ let ragMetadata = [];
347
+ if (options?.useRAG && this.pluginManager.hasPluginsOfType("rag")) {
348
+ const lastMessage = messages[messages.length - 1];
349
+ const { contexts, allMetadata } = await this.pluginManager.executeRAG(
350
+ extractTextContent(lastMessage.content),
351
+ {
352
+ agentId: this.data.id,
353
+ threadId: options.threadId,
354
+ filters: options.ragFilters
355
+ }
356
+ );
357
+ if (contexts.length > 0) {
358
+ systemPrompt += "\n\n" + contexts.join("\n\n");
359
+ }
360
+ ragMetadata = allMetadata;
361
+ }
362
+ const model = await this.providerFactory.getModel(this.data.provider, this.data.model);
363
+ const { textStream } = streamText({
364
+ model,
365
+ messages: beforeResult.messages,
366
+ system: systemPrompt
367
+ });
368
+ let fullText = "";
369
+ for await (const chunk of textStream) {
370
+ fullText += chunk;
371
+ onChunk(chunk);
372
+ }
373
+ const afterResult = await this.pluginManager.executeAfterResponse(fullText, {
374
+ agentId: this.data.id,
375
+ threadId: options?.threadId,
376
+ metadata: beforeResult.metadata
377
+ });
378
+ const latency = Date.now() - startTime;
379
+ await this.pluginManager.trackResponse({
380
+ agentId: this.data.id,
381
+ threadId: options?.threadId,
382
+ response: afterResult.response,
383
+ latency,
384
+ timestamp: /* @__PURE__ */ new Date()
385
+ });
386
+ if (onComplete) {
387
+ onComplete(afterResult.response, {
388
+ ...afterResult.metadata,
389
+ ragMetadata,
390
+ latency
391
+ });
392
+ }
393
+ } catch (error) {
394
+ if (onError) {
395
+ onError(error instanceof Error ? error : new Error("Unknown error"));
396
+ } else {
397
+ throw error;
398
+ }
399
+ }
400
+ }
401
+ /**
402
+ * Get agent ID
403
+ */
404
+ get id() {
405
+ return this.data.id;
406
+ }
407
+ /**
408
+ * Get agent name
409
+ */
410
+ get name() {
411
+ return this.data.name;
412
+ }
413
+ /**
414
+ * Get agent instructions
415
+ */
416
+ get instructions() {
417
+ return this.data.instructions;
418
+ }
419
+ /**
420
+ * Get agent provider
421
+ */
422
+ get provider() {
423
+ return this.data.provider;
424
+ }
425
+ /**
426
+ * Get agent model
427
+ */
428
+ get model() {
429
+ return this.data.model;
430
+ }
431
+ /**
432
+ * Get all plugins attached to this agent
433
+ */
434
+ get plugins() {
435
+ return this.data.plugins || [];
436
+ }
437
+ /**
438
+ * Add a plugin to this agent
439
+ */
440
+ addPlugin(plugin) {
441
+ this.data.plugins = [...this.data.plugins || [], plugin];
442
+ this.pluginManager = new PluginManager(this.data.plugins);
443
+ this.data.updatedAt = /* @__PURE__ */ new Date();
444
+ }
445
+ /**
446
+ * Remove a plugin by name
447
+ */
448
+ removePlugin(pluginName) {
449
+ this.data.plugins = (this.data.plugins || []).filter((p) => p.name !== pluginName);
450
+ this.pluginManager = new PluginManager(this.data.plugins);
451
+ this.data.updatedAt = /* @__PURE__ */ new Date();
452
+ }
453
+ /**
454
+ * Get all agent data
455
+ */
456
+ toJSON() {
457
+ return { ...this.data };
458
+ }
459
+ /**
460
+ * Ingest documents into RAG plugins
461
+ * Documents will be ingested into all RAG plugins that support ingestion
462
+ */
463
+ async ingestDocuments(documents, options) {
464
+ const ragPlugins = this.data.plugins?.filter((p) => p.type === "rag") || [];
465
+ const results = [];
466
+ for (const plugin of ragPlugins) {
467
+ if ("ingest" in plugin && typeof plugin.ingest === "function") {
468
+ const result = await plugin.ingest(documents, {
469
+ agentId: this.data.id,
470
+ ...options
471
+ });
472
+ results.push(result);
473
+ }
474
+ }
475
+ if (results.length === 0) {
476
+ throw new Error("No RAG plugins with ingestion support found");
477
+ }
478
+ return results;
479
+ }
480
+ /**
481
+ * Update a document in RAG plugins
482
+ */
483
+ async updateDocument(id, document, options) {
484
+ const ragPlugins = this.data.plugins?.filter((p) => p.type === "rag") || [];
485
+ let updated = false;
486
+ for (const plugin of ragPlugins) {
487
+ if ("update" in plugin && typeof plugin.update === "function") {
488
+ await plugin.update(id, document, {
489
+ agentId: this.data.id,
490
+ ...options
491
+ });
492
+ updated = true;
493
+ }
494
+ }
495
+ if (!updated) {
496
+ throw new Error("No RAG plugins with update support found");
497
+ }
498
+ }
499
+ /**
500
+ * Delete documents from RAG plugins
501
+ */
502
+ async deleteDocuments(ids, options) {
503
+ const ragPlugins = this.data.plugins?.filter((p) => p.type === "rag") || [];
504
+ let totalDeleted = 0;
505
+ for (const plugin of ragPlugins) {
506
+ if ("delete" in plugin && typeof plugin.delete === "function") {
507
+ const count = await plugin.delete(ids, {
508
+ agentId: this.data.id,
509
+ ...options
510
+ });
511
+ totalDeleted += count;
512
+ }
513
+ }
514
+ return totalDeleted;
515
+ }
516
+ /**
517
+ * Perform bulk operations on RAG plugins
518
+ */
519
+ async bulkDocumentOperations(operations, options) {
520
+ const ragPlugins = this.data.plugins?.filter((p) => p.type === "rag") || [];
521
+ const results = [];
522
+ for (const plugin of ragPlugins) {
523
+ if ("bulk" in plugin && typeof plugin.bulk === "function") {
524
+ const result = await plugin.bulk(operations, {
525
+ agentId: this.data.id,
526
+ ...options
527
+ });
528
+ results.push(result);
529
+ }
530
+ }
531
+ if (results.length === 0) {
532
+ throw new Error("No RAG plugins with bulk operation support found");
533
+ }
534
+ return results;
535
+ }
536
+ /**
537
+ * Ingest documents from a URL source (CSV, JSON, XML, API)
538
+ * Supports authentication, scheduling, and data transformation
539
+ */
540
+ async ingestFromUrl(source, options) {
541
+ const ragPlugins = this.data.plugins?.filter((p) => p.type === "rag") || [];
542
+ const results = [];
543
+ for (const plugin of ragPlugins) {
544
+ if ("ingestFromUrl" in plugin && typeof plugin.ingestFromUrl === "function") {
545
+ const result = await plugin.ingestFromUrl(source, {
546
+ agentId: this.data.id,
547
+ ...options
548
+ });
549
+ results.push(result);
550
+ }
551
+ }
552
+ if (results.length === 0) {
553
+ throw new Error("No RAG plugins with URL ingestion support found");
554
+ }
555
+ return results;
556
+ }
557
+ /**
558
+ * Handle webhook payload for real-time document updates
559
+ * Useful for product inventory updates, price changes, etc.
560
+ */
561
+ async handleWebhook(payload, source, options) {
562
+ const ragPlugins = this.data.plugins?.filter((p) => p.type === "rag") || [];
563
+ const results = [];
564
+ for (const plugin of ragPlugins) {
565
+ if ("handleWebhook" in plugin && typeof plugin.handleWebhook === "function") {
566
+ const result = await plugin.handleWebhook(payload, source, {
567
+ agentId: this.data.id,
568
+ ...options
569
+ });
570
+ results.push(result);
571
+ }
572
+ }
573
+ if (results.length === 0) {
574
+ throw new Error("No RAG plugins with webhook support found");
575
+ }
576
+ return results;
577
+ }
578
+ };
579
+
580
+ // src/core/Thread.ts
581
+ var Thread = class _Thread {
582
+ constructor(data, storage) {
583
+ this.data = data;
584
+ this.storage = storage;
585
+ }
586
+ /**
587
+ * Create a new thread
588
+ */
589
+ static async create(config, storage) {
590
+ const threadId = await storage.createThread(config);
591
+ const data = await storage.getThread(threadId);
592
+ if (!data) {
593
+ throw new CouldNotCreateThreadError(threadId);
594
+ }
595
+ return new _Thread(data, storage);
596
+ }
597
+ /**
598
+ * Load an existing thread by ID
599
+ */
600
+ static async load(threadId, storage) {
601
+ const data = await storage.getThread(threadId);
602
+ if (!data) {
603
+ return null;
604
+ }
605
+ return new _Thread(data, storage);
606
+ }
607
+ /**
608
+ * Update thread properties
609
+ */
610
+ async update(updates) {
611
+ await this.storage.updateThread(this.data.id, updates);
612
+ const updatedData = await this.storage.getThread(this.data.id);
613
+ if (updatedData) {
614
+ this.data = updatedData;
615
+ }
616
+ }
617
+ /**
618
+ * Delete this thread
619
+ */
620
+ async delete() {
621
+ await this.storage.deleteThread(this.data.id);
622
+ }
623
+ /**
624
+ * Add a message to the thread
625
+ */
626
+ async addMessage(role, content, attachments) {
627
+ const messageId = await this.storage.addMessage(
628
+ this.data.id,
629
+ role,
630
+ content,
631
+ attachments
632
+ );
633
+ const updatedData = await this.storage.getThread(this.data.id);
634
+ if (updatedData) {
635
+ this.data = updatedData;
636
+ }
637
+ return messageId;
638
+ }
639
+ /**
640
+ * Get messages from this thread
641
+ */
642
+ async getMessages(limit) {
643
+ return await this.storage.getMessages(this.data.id, limit);
644
+ }
645
+ /**
646
+ * Get conversation context for AI (formatted for Vercel AI SDK)
647
+ */
648
+ async getConversationContext(maxMessages = 20) {
649
+ const messages = await this.storage.getMessages(this.data.id, maxMessages);
650
+ return messages.map((msg) => ({
651
+ role: msg.role,
652
+ content: msg.content
653
+ }));
654
+ }
655
+ /**
656
+ * Update thread name
657
+ */
658
+ async updateName(name) {
659
+ await this.update({ name });
660
+ }
661
+ /**
662
+ * Update pending status
663
+ */
664
+ async updatePendingStatus(isPending) {
665
+ this.data.isPendingThread = isPending;
666
+ this.data.updatedAt = /* @__PURE__ */ new Date();
667
+ }
668
+ /**
669
+ * Get thread ID
670
+ */
671
+ get id() {
672
+ return this.data.id;
673
+ }
674
+ /**
675
+ * Get thread name
676
+ */
677
+ get name() {
678
+ return this.data.name;
679
+ }
680
+ /**
681
+ * Get agent ID
682
+ */
683
+ get agentId() {
684
+ return this.data.agentId;
685
+ }
686
+ /**
687
+ * Get messages (cached from last load)
688
+ */
689
+ get messages() {
690
+ return this.data.messages;
691
+ }
692
+ /**
693
+ * Check if thread is pending
694
+ */
695
+ get isPending() {
696
+ return this.data.isPendingThread;
697
+ }
698
+ /**
699
+ * Get all thread data
700
+ */
701
+ toJSON() {
702
+ return { ...this.data };
703
+ }
704
+ };
705
+
706
+ // src/providers/index.ts
707
+ import { createOpenAI } from "@ai-sdk/openai";
708
+ var ProviderFactory = class {
709
+ constructor(config) {
710
+ this.modelCache = /* @__PURE__ */ new Map();
711
+ this.config = config;
712
+ }
713
+ /**
714
+ * Get a language model for the specified provider and model
715
+ * Uses dynamic imports for edge runtime compatibility
716
+ */
717
+ async getModel(provider, modelName) {
718
+ const cacheKey = `${provider}:${modelName}`;
719
+ if (this.modelCache.has(cacheKey)) {
720
+ return this.modelCache.get(cacheKey);
721
+ }
722
+ let model;
723
+ switch (provider) {
724
+ case "openai": {
725
+ if (!this.config.openai?.apiKey) {
726
+ throw new ProviderNotFoundError("OpenAI API key not configured");
727
+ }
728
+ const openai = createOpenAI({
729
+ apiKey: this.config.openai.apiKey
730
+ });
731
+ model = openai(modelName);
732
+ break;
733
+ }
734
+ case "anthropic": {
735
+ if (!this.config.anthropic?.apiKey) {
736
+ throw new ProviderNotFoundError("Anthropic API key not configured");
737
+ }
738
+ try {
739
+ const { createAnthropic } = await import("./dist-JU54Y3G4.mjs");
740
+ const anthropic = createAnthropic({
741
+ apiKey: this.config.anthropic.apiKey
742
+ });
743
+ model = anthropic(modelName);
744
+ } catch (error) {
745
+ throw new ProviderNotFoundError(
746
+ "Anthropic provider not installed. Run: npm install @ai-sdk/anthropic"
747
+ );
748
+ }
749
+ break;
750
+ }
751
+ case "google": {
752
+ if (!this.config.google?.apiKey) {
753
+ throw new ProviderNotFoundError("Google API key not configured");
754
+ }
755
+ try {
756
+ const { createGoogleGenerativeAI } = await import("./dist-2CMI4QQD.mjs");
757
+ const google = createGoogleGenerativeAI({
758
+ apiKey: this.config.google.apiKey
759
+ });
760
+ model = google(modelName);
761
+ } catch (error) {
762
+ throw new ProviderNotFoundError(
763
+ "Google provider not installed. Run: npm install @ai-sdk/google"
764
+ );
765
+ }
766
+ break;
767
+ }
768
+ default:
769
+ throw new ProviderNotFoundError(`Unknown provider: ${provider}`);
770
+ }
771
+ this.modelCache.set(cacheKey, model);
772
+ return model;
773
+ }
774
+ /**
775
+ * Check if a provider is configured
776
+ */
777
+ isProviderConfigured(provider) {
778
+ switch (provider) {
779
+ case "openai":
780
+ return !!this.config.openai?.apiKey;
781
+ case "anthropic":
782
+ return !!this.config.anthropic?.apiKey;
783
+ case "google":
784
+ return !!this.config.google?.apiKey;
785
+ default:
786
+ return false;
787
+ }
788
+ }
789
+ /**
790
+ * Get list of configured providers
791
+ */
792
+ getConfiguredProviders() {
793
+ const providers = [];
794
+ if (this.config.openai?.apiKey) providers.push("openai");
795
+ if (this.config.anthropic?.apiKey) providers.push("anthropic");
796
+ if (this.config.google?.apiKey) providers.push("google");
797
+ return providers;
798
+ }
799
+ /**
800
+ * Clear the model cache
801
+ */
802
+ clearCache() {
803
+ this.modelCache.clear();
804
+ }
805
+ };
806
+ var Models = {
807
+ OpenAI: {
808
+ GPT4O: "gpt-4o",
809
+ GPT4O_MINI: "gpt-4o-mini",
810
+ GPT4_TURBO: "gpt-4-turbo",
811
+ GPT35_TURBO: "gpt-3.5-turbo"
812
+ },
813
+ Anthropic: {
814
+ CLAUDE_35_SONNET: "claude-3-5-sonnet-20241022",
815
+ CLAUDE_35_HAIKU: "claude-3-5-haiku-20241022",
816
+ CLAUDE_3_OPUS: "claude-3-opus-20240229"
817
+ },
818
+ Google: {
819
+ GEMINI_2_FLASH: "gemini-2.0-flash-exp",
820
+ GEMINI_15_PRO: "gemini-1.5-pro",
821
+ GEMINI_15_FLASH: "gemini-1.5-flash"
822
+ }
823
+ };
824
+
825
+ // src/inc/DefaultRAGPlugin.ts
826
+ var DefaultRAGPlugin = class {
827
+ constructor(config) {
828
+ this.name = "default-rag";
829
+ this.type = "rag";
830
+ this.documents = /* @__PURE__ */ new Map();
831
+ this.config = {
832
+ embeddingProvider: config.embeddingProvider || "openai",
833
+ embeddingModel: config.embeddingModel || "text-embedding-3-small",
834
+ limit: config.limit || 5,
835
+ embeddingProviderApiKey: config.embeddingProviderApiKey
836
+ };
837
+ }
838
+ /**
839
+ * Retrieve context for a message using semantic search
840
+ */
841
+ async retrieveContext(message, options) {
842
+ const agentDocs = this.documents.get(options.agentId) || [];
843
+ if (agentDocs.length === 0) {
844
+ return {
845
+ content: "",
846
+ sources: [],
847
+ metadata: { count: 0 }
848
+ };
849
+ }
850
+ const queryEmbedding = await this.generateEmbedding(message);
851
+ const scoredDocs = agentDocs.map((doc) => ({
852
+ ...doc,
853
+ score: this.cosineSimilarity(queryEmbedding, doc.embedding)
854
+ })).sort((a, b) => b.score - a.score).slice(0, this.config.limit);
855
+ const content = scoredDocs.map((doc, idx) => `[${idx + 1}] ${doc.content}`).join("\n\n");
856
+ return {
857
+ content,
858
+ sources: scoredDocs.map((doc) => ({
859
+ id: doc.id,
860
+ title: doc.metadata?.title,
861
+ score: doc.score,
862
+ type: "document",
863
+ ...doc.metadata
864
+ })),
865
+ metadata: {
866
+ count: scoredDocs.length,
867
+ totalDocuments: agentDocs.length
868
+ }
869
+ };
870
+ }
871
+ /**
872
+ * Ingest documents into the RAG system
873
+ */
874
+ async ingest(documents, options) {
875
+ if (!options?.agentId) {
876
+ return {
877
+ success: false,
878
+ indexed: 0,
879
+ failed: documents.length,
880
+ errors: [
881
+ {
882
+ id: "batch",
883
+ error: "agentId is required for document ingestion"
884
+ }
885
+ ]
886
+ };
887
+ }
888
+ let indexed = 0;
889
+ const errors = [];
890
+ const agentDocs = this.documents.get(options.agentId) || [];
891
+ for (const doc of documents) {
892
+ try {
893
+ const embedding = await this.generateEmbedding(doc.content);
894
+ const existingIdx = agentDocs.findIndex((d) => d.id === doc.id);
895
+ const storedDoc = {
896
+ ...doc,
897
+ embedding,
898
+ agentId: options.agentId,
899
+ createdAt: /* @__PURE__ */ new Date()
900
+ };
901
+ if (existingIdx >= 0) {
902
+ if (options.overwrite) {
903
+ agentDocs[existingIdx] = storedDoc;
904
+ indexed++;
905
+ } else if (!options.skipExisting) {
906
+ agentDocs[existingIdx] = storedDoc;
907
+ indexed++;
908
+ }
909
+ } else {
910
+ agentDocs.push(storedDoc);
911
+ indexed++;
912
+ }
913
+ } catch (error) {
914
+ errors.push({
915
+ id: doc.id,
916
+ error: error instanceof Error ? error.message : "Unknown error"
917
+ });
918
+ }
919
+ }
920
+ this.documents.set(options.agentId, agentDocs);
921
+ return {
922
+ success: errors.length === 0,
923
+ indexed,
924
+ failed: errors.length,
925
+ errors: errors.length > 0 ? errors : void 0,
926
+ metadata: {
927
+ totalDocuments: agentDocs.length
928
+ }
929
+ };
930
+ }
931
+ /**
932
+ * Update a single document
933
+ */
934
+ async update(id, document, options) {
935
+ if (!options?.agentId) {
936
+ throw new Error("agentId is required for document update");
937
+ }
938
+ const agentDocs = this.documents.get(options.agentId) || [];
939
+ const existingIdx = agentDocs.findIndex((d) => d.id === id);
940
+ if (existingIdx < 0) {
941
+ throw new Error(`Document not found: ${id}`);
942
+ }
943
+ const existing = agentDocs[existingIdx];
944
+ if (document.content && document.content !== existing.content) {
945
+ const embedding = await this.generateEmbedding(document.content);
946
+ agentDocs[existingIdx] = {
947
+ ...existing,
948
+ ...document,
949
+ content: document.content,
950
+ embedding
951
+ };
952
+ } else {
953
+ agentDocs[existingIdx] = {
954
+ ...existing,
955
+ ...document,
956
+ id: existing.id,
957
+ // Ensure ID doesn't change
958
+ content: existing.content,
959
+ // Ensure content doesn't change
960
+ embedding: existing.embedding
961
+ // Keep existing embedding
962
+ };
963
+ }
964
+ this.documents.set(options.agentId, agentDocs);
965
+ }
966
+ /**
967
+ * Delete document(s) by ID
968
+ */
969
+ async delete(ids, options) {
970
+ if (!options?.agentId) {
971
+ throw new Error("agentId is required for document deletion");
972
+ }
973
+ const agentDocs = this.documents.get(options.agentId) || [];
974
+ const idsArray = Array.isArray(ids) ? ids : [ids];
975
+ const initialCount = agentDocs.length;
976
+ const filtered = agentDocs.filter((doc) => !idsArray.includes(doc.id));
977
+ const deletedCount = initialCount - filtered.length;
978
+ this.documents.set(options.agentId, filtered);
979
+ return deletedCount;
980
+ }
981
+ /**
982
+ * Generate embedding using OpenAI
983
+ */
984
+ async generateEmbedding(text) {
985
+ const response = await fetch("https://api.openai.com/v1/embeddings", {
986
+ method: "POST",
987
+ headers: {
988
+ "Content-Type": "application/json",
989
+ Authorization: `Bearer ${this.config.embeddingProviderApiKey}`
990
+ },
991
+ body: JSON.stringify({
992
+ model: this.config.embeddingModel,
993
+ input: text
994
+ })
995
+ });
996
+ if (!response.ok) {
997
+ const error = await response.text();
998
+ throw new Error(`OpenAI API error: ${response.status} - ${error}`);
999
+ }
1000
+ const data = await response.json();
1001
+ return data.data[0].embedding;
1002
+ }
1003
+ /**
1004
+ * Calculate cosine similarity between two vectors
1005
+ */
1006
+ cosineSimilarity(a, b) {
1007
+ if (a.length !== b.length) {
1008
+ throw new Error("Vectors must have the same length");
1009
+ }
1010
+ let dotProduct = 0;
1011
+ let normA = 0;
1012
+ let normB = 0;
1013
+ for (let i = 0; i < a.length; i++) {
1014
+ dotProduct += a[i] * b[i];
1015
+ normA += a[i] * a[i];
1016
+ normB += b[i] * b[i];
1017
+ }
1018
+ normA = Math.sqrt(normA);
1019
+ normB = Math.sqrt(normB);
1020
+ if (normA === 0 || normB === 0) {
1021
+ return 0;
1022
+ }
1023
+ return dotProduct / (normA * normB);
1024
+ }
1025
+ /**
1026
+ * Get statistics about stored documents
1027
+ */
1028
+ getStats() {
1029
+ const stats = {
1030
+ totalAgents: this.documents.size,
1031
+ agentStats: {}
1032
+ };
1033
+ for (const [agentId, docs] of this.documents.entries()) {
1034
+ stats.agentStats[agentId] = {
1035
+ documentCount: docs.length
1036
+ };
1037
+ }
1038
+ return stats;
1039
+ }
1040
+ /**
1041
+ * Clear all documents for an agent
1042
+ */
1043
+ clearAgent(agentId) {
1044
+ this.documents.delete(agentId);
1045
+ }
1046
+ /**
1047
+ * Clear all documents
1048
+ */
1049
+ clearAll() {
1050
+ this.documents.clear();
1051
+ }
1052
+ };
1053
+
1054
+ // src/core/Client.ts
1055
+ var AgentClient = class {
1056
+ constructor(config) {
1057
+ this.validateConfig(config);
1058
+ this.storage = config.storage;
1059
+ this.providers = config.providers;
1060
+ this.providerFactory = new ProviderFactory(config.providers);
1061
+ }
1062
+ validateConfig(config) {
1063
+ if (!config.storage) {
1064
+ throw new InvalidConfigError("Storage adapter is required");
1065
+ }
1066
+ if (!config.providers || Object.keys(config.providers).length === 0) {
1067
+ throw new InvalidConfigError("At least one provider must be configured");
1068
+ }
1069
+ }
1070
+ // ============================================================================
1071
+ // Agent Operations
1072
+ // ============================================================================
1073
+ /**
1074
+ * Create a new agent
1075
+ */
1076
+ async createAgent(config) {
1077
+ const agentConfig = {
1078
+ ...config,
1079
+ provider: config.provider || "openai"
1080
+ };
1081
+ if (agentConfig.rag?.enabled) {
1082
+ const hasRAGPlugin = agentConfig.plugins?.some((p) => p.type === "rag");
1083
+ if (!hasRAGPlugin) {
1084
+ const embeddingProviderApiKey = agentConfig.rag.embeddingProviderApiKey || this.providers.openai?.apiKey;
1085
+ if (!embeddingProviderApiKey) {
1086
+ throw new InvalidConfigError(
1087
+ "RAG requires an embedding provider API key. Either configure OpenAI provider or set rag.embeddingProviderApiKey"
1088
+ );
1089
+ }
1090
+ const defaultRAGPlugin = new DefaultRAGPlugin({
1091
+ embeddingProviderApiKey,
1092
+ embeddingProvider: agentConfig.rag.embeddingProvider,
1093
+ embeddingModel: agentConfig.rag.embeddingModel,
1094
+ limit: agentConfig.rag.limit
1095
+ });
1096
+ agentConfig.plugins = [...agentConfig.plugins || [], defaultRAGPlugin];
1097
+ }
1098
+ }
1099
+ return await Agent.create(agentConfig, this.storage, this.providerFactory);
1100
+ }
1101
+ /**
1102
+ * Get an agent by ID
1103
+ */
1104
+ async getAgent(agentId) {
1105
+ const agent = await Agent.load(agentId, this.storage, this.providerFactory);
1106
+ if (!agent) {
1107
+ throw new AgentNotFoundError(agentId);
1108
+ }
1109
+ return agent;
1110
+ }
1111
+ /**
1112
+ * List agents for a user
1113
+ */
1114
+ async listAgents(userId, organizationId) {
1115
+ return await this.storage.listAgents(userId, organizationId);
1116
+ }
1117
+ /**
1118
+ * Delete an agent
1119
+ */
1120
+ async deleteAgent(agentId) {
1121
+ const agent = await this.getAgent(agentId);
1122
+ await agent.delete();
1123
+ }
1124
+ // ============================================================================
1125
+ // Thread Operations
1126
+ // ============================================================================
1127
+ /**
1128
+ * Create a new thread
1129
+ */
1130
+ async createThread(config) {
1131
+ await this.getAgent(config.agentId);
1132
+ return await Thread.create(config, this.storage);
1133
+ }
1134
+ /**
1135
+ * Get a thread by ID
1136
+ */
1137
+ async getThread(threadId) {
1138
+ if (!threadId) {
1139
+ throw new ThreadNotFoundError("Thread ID is required");
1140
+ }
1141
+ const thread = await Thread.load(threadId, this.storage);
1142
+ if (!thread) {
1143
+ throw new ThreadNotFoundError(threadId);
1144
+ }
1145
+ return thread;
1146
+ }
1147
+ /**
1148
+ * List threads by user or agent
1149
+ */
1150
+ async listThreads(filters) {
1151
+ return await this.storage.listThreads(filters);
1152
+ }
1153
+ /**
1154
+ * Delete a thread
1155
+ */
1156
+ async deleteThread(threadId) {
1157
+ const thread = await this.getThread(threadId);
1158
+ await thread.delete();
1159
+ }
1160
+ // ============================================================================
1161
+ // Chat Operations
1162
+ // ============================================================================
1163
+ /**
1164
+ * Send a message and get a response (non-streaming)
1165
+ */
1166
+ async chat(request) {
1167
+ const thread = await this.getThread(request.threadId);
1168
+ const agent = await this.getAgent(thread.agentId);
1169
+ await thread.addMessage("user", request.message, request.attachments);
1170
+ const contextLength = request.contextLength ?? 20;
1171
+ const messages = await thread.getConversationContext(contextLength);
1172
+ const result = await agent.generateResponse(messages, {
1173
+ useRAG: request.useRAG,
1174
+ ragFilters: request.ragFilters,
1175
+ threadId: thread.id
1176
+ });
1177
+ const messageId = await thread.addMessage("assistant", result.text);
1178
+ return {
1179
+ reply: result.text,
1180
+ messageId,
1181
+ threadId: thread.id,
1182
+ timestamp: /* @__PURE__ */ new Date(),
1183
+ metadata: result.metadata
1184
+ };
1185
+ }
1186
+ /**
1187
+ * Send a message and stream the response
1188
+ */
1189
+ async chatStream(request, callbacks) {
1190
+ try {
1191
+ const thread = await this.getThread(request.threadId);
1192
+ const agent = await this.getAgent(thread.agentId);
1193
+ await thread.addMessage("user", request.message, request.attachments);
1194
+ const contextLength = request.contextLength ?? 20;
1195
+ const messages = await thread.getConversationContext(contextLength);
1196
+ await agent.streamResponse(
1197
+ messages,
1198
+ callbacks.onChunk,
1199
+ async (fullResponse, metadata) => {
1200
+ await thread.addMessage("assistant", fullResponse);
1201
+ callbacks.onComplete(fullResponse, metadata);
1202
+ },
1203
+ callbacks.onError,
1204
+ {
1205
+ useRAG: request.useRAG,
1206
+ ragFilters: request.ragFilters,
1207
+ threadId: thread.id
1208
+ }
1209
+ );
1210
+ } catch (error) {
1211
+ callbacks.onError(
1212
+ error instanceof Error ? error : new Error("Unknown error")
1213
+ );
1214
+ }
1215
+ }
1216
+ /**
1217
+ * Generate a name for a thread based on its first message
1218
+ */
1219
+ async generateThreadName(firstMessage) {
1220
+ const providers = this.providerFactory.getConfiguredProviders();
1221
+ if (providers.length === 0) {
1222
+ throw new InvalidConfigError("No providers configured");
1223
+ }
1224
+ const model = await this.providerFactory.getModel(providers[0], "gpt-4o");
1225
+ const { generateText: generateText2 } = await import("ai");
1226
+ const { text } = await generateText2({
1227
+ model,
1228
+ messages: [
1229
+ {
1230
+ role: "user",
1231
+ content: `Generate a brief and clear title to identify this conversation thread, based solely on the following first user message:
1232
+ "${firstMessage}"
1233
+
1234
+ Requirements:
1235
+ - Maximum 4 words
1236
+ - Specific and concise
1237
+ - Avoid generic words like "query" or "question"
1238
+ - Reflect the main topic
1239
+ Return only the title without additional explanations.`
1240
+ }
1241
+ ],
1242
+ temperature: 0.3
1243
+ });
1244
+ return text.trim() || "New Chat";
1245
+ }
1246
+ // ============================================================================
1247
+ // Utility Methods
1248
+ // ============================================================================
1249
+ /**
1250
+ * Get list of configured providers
1251
+ */
1252
+ getConfiguredProviders() {
1253
+ return this.providerFactory.getConfiguredProviders();
1254
+ }
1255
+ /**
1256
+ * Check if a provider is configured
1257
+ */
1258
+ isProviderConfigured(provider) {
1259
+ return this.providerFactory.isProviderConfigured(provider);
1260
+ }
1261
+ };
1262
+
1263
+ // src/index.ts
1264
+ function createClient(config) {
1265
+ return new AgentClient(config);
1266
+ }
1267
+ export {
1268
+ Agent,
1269
+ AgentClient,
1270
+ AgentNotFoundError,
1271
+ AgentSDKError,
1272
+ DefaultRAGPlugin,
1273
+ InvalidConfigError,
1274
+ MemoryStorage,
1275
+ Models,
1276
+ MongoDBStorage,
1277
+ PluginManager,
1278
+ ProviderFactory,
1279
+ ProviderNotFoundError,
1280
+ Thread,
1281
+ ThreadNotFoundError,
1282
+ UpstashStorage,
1283
+ createClient
1284
+ };