@snap-agent/core 0.1.3 → 0.1.5

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 (35) hide show
  1. package/dist/chunk-4NN3ADDP.mjs +0 -0
  2. package/dist/chunk-52OS4FTG.mjs +382 -0
  3. package/dist/chunk-5BAE6S5E.js +382 -0
  4. package/dist/chunk-BSSVNLSO.mjs +157 -0
  5. package/dist/chunk-DKNHIS7Z.js +2227 -0
  6. package/dist/chunk-DQRG2GHR.js +157 -0
  7. package/dist/chunk-GHRDUPHS.js +1 -0
  8. package/dist/chunk-JQK3HEJ5.mjs +268 -0
  9. package/dist/chunk-JRIKISMX.js +268 -0
  10. package/dist/dist-GSDAIZQP.js +1825 -0
  11. package/dist/dist-HTV3MRC3.js +3216 -0
  12. package/dist/{index-m2vDW79n.d.mts → index-Ek8b39d1.d.mts} +1 -173
  13. package/dist/{index-m2vDW79n.d.ts → index-Ek8b39d1.d.ts} +1 -173
  14. package/dist/index.d.mts +17 -8
  15. package/dist/index.d.ts +17 -8
  16. package/dist/index.js +1255 -9372
  17. package/dist/index.mjs +27 -9
  18. package/dist/storage/MemoryStorage.d.mts +46 -0
  19. package/dist/storage/MemoryStorage.d.ts +46 -0
  20. package/dist/storage/MemoryStorage.js +6 -0
  21. package/dist/storage/MemoryStorage.mjs +6 -0
  22. package/dist/storage/MongoDBStorage.d.mts +44 -0
  23. package/dist/storage/MongoDBStorage.d.ts +44 -0
  24. package/dist/storage/MongoDBStorage.js +6 -0
  25. package/dist/storage/MongoDBStorage.mjs +6 -0
  26. package/dist/storage/UpstashStorage.d.mts +91 -0
  27. package/dist/storage/UpstashStorage.d.ts +91 -0
  28. package/dist/storage/UpstashStorage.js +6 -0
  29. package/dist/storage/UpstashStorage.mjs +6 -0
  30. package/dist/storage/index.d.mts +4 -1
  31. package/dist/storage/index.d.ts +4 -1
  32. package/dist/storage/index.js +11 -827
  33. package/dist/storage/index.mjs +8 -3
  34. package/package.json +18 -3
  35. package/dist/chunk-FS7G3ID4.mjs +0 -803
File without changes
@@ -0,0 +1,382 @@
1
+ // src/storage/UpstashStorage.ts
2
+ var UpstashStorage = class {
3
+ constructor(config) {
4
+ this.url = config.url.replace(/\/$/, "");
5
+ this.token = config.token;
6
+ this.prefix = config.prefix || "snap-agent";
7
+ }
8
+ // ============================================================================
9
+ // Redis Commands via REST API
10
+ // ============================================================================
11
+ async command(cmd, ...args) {
12
+ const body = [cmd, ...args];
13
+ const response = await fetch(`${this.url}`, {
14
+ method: "POST",
15
+ headers: {
16
+ Authorization: `Bearer ${this.token}`,
17
+ "Content-Type": "application/json"
18
+ },
19
+ body: JSON.stringify(body)
20
+ });
21
+ if (!response.ok) {
22
+ const text = await response.text();
23
+ throw new Error(`Upstash Redis error: ${response.status} - ${text}`);
24
+ }
25
+ const data = await response.json();
26
+ if (data.error) {
27
+ throw new Error(`Upstash Redis error: ${data.error}`);
28
+ }
29
+ return data.result;
30
+ }
31
+ async pipeline(commands) {
32
+ const response = await fetch(`${this.url}/pipeline`, {
33
+ method: "POST",
34
+ headers: {
35
+ Authorization: `Bearer ${this.token}`,
36
+ "Content-Type": "application/json"
37
+ },
38
+ body: JSON.stringify(commands)
39
+ });
40
+ if (!response.ok) {
41
+ const text = await response.text();
42
+ throw new Error(`Upstash Redis pipeline error: ${response.status} - ${text}`);
43
+ }
44
+ const data = await response.json();
45
+ return data.map((item) => {
46
+ if (item.error) {
47
+ throw new Error(`Upstash Redis error: ${item.error}`);
48
+ }
49
+ return item.result;
50
+ });
51
+ }
52
+ // ============================================================================
53
+ // Key Generation
54
+ // ============================================================================
55
+ key(...parts) {
56
+ return `${this.prefix}:${parts.join(":")}`;
57
+ }
58
+ generateId() {
59
+ const timestamp = Date.now().toString(36);
60
+ const random = Math.random().toString(36).substring(2, 10);
61
+ return `${timestamp}${random}`;
62
+ }
63
+ // ============================================================================
64
+ // Agent Operations
65
+ // ============================================================================
66
+ async createAgent(config) {
67
+ const id = this.generateId();
68
+ const now = (/* @__PURE__ */ new Date()).toISOString();
69
+ const stored = {
70
+ id,
71
+ organizationId: config.organizationId,
72
+ userId: config.userId,
73
+ phone: config.phone,
74
+ name: config.name,
75
+ description: config.description,
76
+ instructions: config.instructions,
77
+ provider: config.provider,
78
+ model: config.model,
79
+ createdAt: now,
80
+ updatedAt: now,
81
+ files: JSON.stringify([]),
82
+ metadata: config.metadata ? JSON.stringify(config.metadata) : void 0
83
+ };
84
+ const fields = [];
85
+ for (const [key, value] of Object.entries(stored)) {
86
+ if (value !== void 0) {
87
+ fields.push(key, String(value));
88
+ }
89
+ }
90
+ await this.pipeline([
91
+ ["HSET", this.key("agent", id), ...fields],
92
+ ["SADD", this.key("agents:user", config.userId), id],
93
+ ...config.organizationId ? [["SADD", this.key("agents:org", config.organizationId), id]] : []
94
+ ]);
95
+ return id;
96
+ }
97
+ async getAgent(agentId) {
98
+ const data = await this.command(
99
+ "HGETALL",
100
+ this.key("agent", agentId)
101
+ );
102
+ if (!data || Object.keys(data).length === 0) {
103
+ return null;
104
+ }
105
+ return this.parseStoredAgent(data);
106
+ }
107
+ async updateAgent(agentId, updates) {
108
+ const fields = ["updatedAt", (/* @__PURE__ */ new Date()).toISOString()];
109
+ for (const [key, value] of Object.entries(updates)) {
110
+ if (value !== void 0) {
111
+ if (key === "metadata") {
112
+ fields.push(key, JSON.stringify(value));
113
+ } else {
114
+ fields.push(key, String(value));
115
+ }
116
+ }
117
+ }
118
+ await this.command("HSET", this.key("agent", agentId), ...fields);
119
+ }
120
+ async deleteAgent(agentId) {
121
+ const agent = await this.getAgent(agentId);
122
+ if (!agent) return;
123
+ const threadIds = await this.command(
124
+ "SMEMBERS",
125
+ this.key("threads:agent", agentId)
126
+ );
127
+ const commands = [
128
+ ["DEL", this.key("agent", agentId)],
129
+ ["SREM", this.key("agents:user", agent.userId), agentId]
130
+ ];
131
+ if (agent.organizationId) {
132
+ commands.push(["SREM", this.key("agents:org", agent.organizationId), agentId]);
133
+ }
134
+ for (const threadId of threadIds || []) {
135
+ commands.push(["DEL", this.key("thread", threadId)]);
136
+ }
137
+ commands.push(["DEL", this.key("threads:agent", agentId)]);
138
+ await this.pipeline(commands);
139
+ }
140
+ async listAgents(userId, organizationId) {
141
+ const indexKey = organizationId ? this.key("agents:org", organizationId) : this.key("agents:user", userId);
142
+ const agentIds = await this.command("SMEMBERS", indexKey);
143
+ if (!agentIds || agentIds.length === 0) {
144
+ return [];
145
+ }
146
+ const agents = [];
147
+ for (const id of agentIds) {
148
+ const agent = await this.getAgent(id);
149
+ if (agent) {
150
+ if (!organizationId || agent.userId === userId) {
151
+ agents.push(agent);
152
+ }
153
+ }
154
+ }
155
+ return agents.sort(
156
+ (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()
157
+ );
158
+ }
159
+ // ============================================================================
160
+ // Thread Operations
161
+ // ============================================================================
162
+ async createThread(config) {
163
+ const id = this.generateId();
164
+ const now = (/* @__PURE__ */ new Date()).toISOString();
165
+ const stored = {
166
+ id,
167
+ organizationId: config.organizationId,
168
+ agentId: config.agentId,
169
+ userId: config.userId,
170
+ endUserId: config.endUserId,
171
+ name: config.name,
172
+ createdAt: now,
173
+ updatedAt: now,
174
+ messages: JSON.stringify([]),
175
+ isPendingThread: "true",
176
+ metadata: config.metadata ? JSON.stringify(config.metadata) : void 0
177
+ };
178
+ const fields = [];
179
+ for (const [key, value] of Object.entries(stored)) {
180
+ if (value !== void 0) {
181
+ fields.push(key, String(value));
182
+ }
183
+ }
184
+ await this.pipeline([
185
+ ["HSET", this.key("thread", id), ...fields],
186
+ ["SADD", this.key("threads:agent", config.agentId), id],
187
+ ["SADD", this.key("threads:user", config.userId), id],
188
+ ...config.organizationId ? [["SADD", this.key("threads:org", config.organizationId), id]] : []
189
+ ]);
190
+ return id;
191
+ }
192
+ async getThread(threadId) {
193
+ const data = await this.command(
194
+ "HGETALL",
195
+ this.key("thread", threadId)
196
+ );
197
+ if (!data || Object.keys(data).length === 0) {
198
+ return null;
199
+ }
200
+ return this.parseStoredThread(data);
201
+ }
202
+ async updateThread(threadId, updates) {
203
+ const fields = ["updatedAt", (/* @__PURE__ */ new Date()).toISOString()];
204
+ for (const [key, value] of Object.entries(updates)) {
205
+ if (value !== void 0) {
206
+ if (key === "metadata") {
207
+ fields.push(key, JSON.stringify(value));
208
+ } else {
209
+ fields.push(key, String(value));
210
+ }
211
+ }
212
+ }
213
+ await this.command("HSET", this.key("thread", threadId), ...fields);
214
+ }
215
+ async deleteThread(threadId) {
216
+ const thread = await this.getThread(threadId);
217
+ if (!thread) return;
218
+ const commands = [
219
+ ["DEL", this.key("thread", threadId)],
220
+ ["SREM", this.key("threads:agent", thread.agentId), threadId],
221
+ ["SREM", this.key("threads:user", thread.userId), threadId]
222
+ ];
223
+ if (thread.organizationId) {
224
+ commands.push(["SREM", this.key("threads:org", thread.organizationId), threadId]);
225
+ }
226
+ await this.pipeline(commands);
227
+ }
228
+ async listThreads(filters) {
229
+ let indexKey;
230
+ if (filters.agentId) {
231
+ indexKey = this.key("threads:agent", filters.agentId);
232
+ } else if (filters.organizationId) {
233
+ indexKey = this.key("threads:org", filters.organizationId);
234
+ } else if (filters.userId) {
235
+ indexKey = this.key("threads:user", filters.userId);
236
+ } else {
237
+ return [];
238
+ }
239
+ const threadIds = await this.command("SMEMBERS", indexKey);
240
+ if (!threadIds || threadIds.length === 0) {
241
+ return [];
242
+ }
243
+ const threads = [];
244
+ for (const id of threadIds) {
245
+ const thread = await this.getThread(id);
246
+ if (thread) {
247
+ if (filters.userId && thread.userId !== filters.userId) continue;
248
+ if (filters.agentId && thread.agentId !== filters.agentId) continue;
249
+ if (filters.organizationId && thread.organizationId !== filters.organizationId) continue;
250
+ threads.push(thread);
251
+ }
252
+ }
253
+ return threads.sort(
254
+ (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()
255
+ );
256
+ }
257
+ // ============================================================================
258
+ // Message Operations
259
+ // ============================================================================
260
+ async addMessage(threadId, role, content, attachments) {
261
+ const thread = await this.getThread(threadId);
262
+ if (!thread) {
263
+ throw new Error(`Thread not found: ${threadId}`);
264
+ }
265
+ const messageId = this.generateId();
266
+ const message = {
267
+ id: messageId,
268
+ role,
269
+ content,
270
+ timestamp: /* @__PURE__ */ new Date(),
271
+ attachments
272
+ };
273
+ thread.messages.push(message);
274
+ await this.command(
275
+ "HSET",
276
+ this.key("thread", threadId),
277
+ "messages",
278
+ JSON.stringify(thread.messages),
279
+ "updatedAt",
280
+ (/* @__PURE__ */ new Date()).toISOString(),
281
+ "isPendingThread",
282
+ "false"
283
+ );
284
+ return messageId;
285
+ }
286
+ async getMessages(threadId, limit) {
287
+ const thread = await this.getThread(threadId);
288
+ if (!thread) return [];
289
+ const messages = [...thread.messages];
290
+ if (limit) {
291
+ return messages.slice(-limit);
292
+ }
293
+ return messages;
294
+ }
295
+ async getConversationContext(threadId, maxMessages = 20) {
296
+ const messages = await this.getMessages(threadId, maxMessages);
297
+ return messages.map((msg) => ({
298
+ role: msg.role,
299
+ content: msg.content
300
+ }));
301
+ }
302
+ // ============================================================================
303
+ // Helper Methods
304
+ // ============================================================================
305
+ parseStoredAgent(stored) {
306
+ return {
307
+ id: stored.id,
308
+ organizationId: stored.organizationId,
309
+ userId: stored.userId,
310
+ phone: stored.phone,
311
+ name: stored.name,
312
+ description: stored.description,
313
+ instructions: stored.instructions,
314
+ provider: stored.provider,
315
+ model: stored.model,
316
+ createdAt: new Date(stored.createdAt),
317
+ updatedAt: new Date(stored.updatedAt),
318
+ files: stored.files ? JSON.parse(stored.files) : [],
319
+ metadata: stored.metadata ? JSON.parse(stored.metadata) : void 0
320
+ };
321
+ }
322
+ parseStoredThread(stored) {
323
+ const messages = stored.messages ? JSON.parse(stored.messages) : [];
324
+ const parsedMessages = messages.map((msg) => ({
325
+ ...msg,
326
+ timestamp: new Date(msg.timestamp)
327
+ }));
328
+ return {
329
+ id: stored.id,
330
+ organizationId: stored.organizationId,
331
+ agentId: stored.agentId,
332
+ userId: stored.userId,
333
+ endUserId: stored.endUserId,
334
+ name: stored.name,
335
+ createdAt: new Date(stored.createdAt),
336
+ updatedAt: new Date(stored.updatedAt),
337
+ messages: parsedMessages,
338
+ isPendingThread: stored.isPendingThread === "true",
339
+ metadata: stored.metadata ? JSON.parse(stored.metadata) : void 0
340
+ };
341
+ }
342
+ // ============================================================================
343
+ // Utility Methods
344
+ // ============================================================================
345
+ /**
346
+ * Test connection to Upstash Redis
347
+ */
348
+ async ping() {
349
+ try {
350
+ const result = await this.command("PING");
351
+ return result === "PONG";
352
+ } catch {
353
+ return false;
354
+ }
355
+ }
356
+ /**
357
+ * Clear all data with this prefix (use with caution!)
358
+ */
359
+ async clear() {
360
+ const keys = await this.command("KEYS", `${this.prefix}:*`);
361
+ if (keys && keys.length > 0) {
362
+ await this.command("DEL", ...keys);
363
+ }
364
+ }
365
+ /**
366
+ * Get storage statistics
367
+ */
368
+ async getStats() {
369
+ const [agentKeys, threadKeys] = await this.pipeline([
370
+ ["KEYS", `${this.prefix}:agent:*`],
371
+ ["KEYS", `${this.prefix}:thread:*`]
372
+ ]);
373
+ return {
374
+ agents: agentKeys?.length || 0,
375
+ threads: threadKeys?.length || 0
376
+ };
377
+ }
378
+ };
379
+
380
+ export {
381
+ UpstashStorage
382
+ };