@cilow/sdk 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +412 -199
  2. package/dist/client.d.mts +224 -0
  3. package/dist/client.d.ts +224 -0
  4. package/dist/client.js +509 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/client.mjs +505 -0
  7. package/dist/client.mjs.map +1 -0
  8. package/dist/index.d.mts +94 -390
  9. package/dist/index.d.ts +94 -390
  10. package/dist/index.js +745 -350
  11. package/dist/index.js.map +1 -0
  12. package/dist/index.mjs +732 -318
  13. package/dist/index.mjs.map +1 -0
  14. package/dist/providers/langchain.js +821 -0
  15. package/dist/providers/langchain.js.map +1 -0
  16. package/dist/providers/langchain.mjs +816 -0
  17. package/dist/providers/langchain.mjs.map +1 -0
  18. package/dist/providers/openai.js +737 -0
  19. package/dist/providers/openai.js.map +1 -0
  20. package/dist/providers/openai.mjs +732 -0
  21. package/dist/providers/openai.mjs.map +1 -0
  22. package/dist/providers/vercel.js +866 -0
  23. package/dist/providers/vercel.js.map +1 -0
  24. package/dist/providers/vercel.mjs +860 -0
  25. package/dist/providers/vercel.mjs.map +1 -0
  26. package/dist/react/hooks.d.mts +327 -0
  27. package/dist/react/hooks.d.ts +327 -0
  28. package/dist/react/hooks.js +1183 -0
  29. package/dist/react/hooks.js.map +1 -0
  30. package/dist/react/hooks.mjs +1172 -0
  31. package/dist/react/hooks.mjs.map +1 -0
  32. package/dist/types.d.mts +494 -0
  33. package/dist/types.d.ts +494 -0
  34. package/dist/types.js +18 -0
  35. package/dist/types.js.map +1 -0
  36. package/dist/types.mjs +14 -0
  37. package/dist/types.mjs.map +1 -0
  38. package/dist/websocket.d.mts +160 -0
  39. package/dist/websocket.d.ts +160 -0
  40. package/dist/websocket.js +342 -0
  41. package/dist/websocket.js.map +1 -0
  42. package/dist/websocket.mjs +339 -0
  43. package/dist/websocket.mjs.map +1 -0
  44. package/package.json +90 -31
  45. package/LICENSE +0 -21
@@ -0,0 +1,1183 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ // src/react/hooks.tsx
7
+
8
+ // src/client.ts
9
+ async function fetchWithRetry(url, options, config) {
10
+ const controller = new AbortController();
11
+ const timeoutId = setTimeout(() => controller.abort(), config.timeout);
12
+ let lastError = null;
13
+ for (let attempt = 0; attempt <= config.retries; attempt++) {
14
+ try {
15
+ const response = await fetch(url, {
16
+ ...options,
17
+ signal: controller.signal
18
+ });
19
+ clearTimeout(timeoutId);
20
+ if (!response.ok) {
21
+ const errorBody = await response.text();
22
+ let apiError;
23
+ try {
24
+ apiError = JSON.parse(errorBody);
25
+ } catch {
26
+ apiError = {
27
+ code: `HTTP_${response.status}`,
28
+ message: errorBody || response.statusText
29
+ };
30
+ }
31
+ throw new CilowApiError(apiError.message, apiError.code, response.status, apiError.details);
32
+ }
33
+ return response;
34
+ } catch (error) {
35
+ lastError = error;
36
+ if (error instanceof CilowApiError) {
37
+ throw error;
38
+ }
39
+ if (config.debug) {
40
+ console.warn(`Cilow API request failed (attempt ${attempt + 1}/${config.retries + 1}):`, error);
41
+ }
42
+ if (attempt < config.retries) {
43
+ await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 100));
44
+ }
45
+ }
46
+ }
47
+ clearTimeout(timeoutId);
48
+ throw lastError || new Error("Request failed");
49
+ }
50
+ var CilowApiError = class extends Error {
51
+ constructor(message, code, statusCode, details) {
52
+ super(message);
53
+ this.code = code;
54
+ this.statusCode = statusCode;
55
+ this.details = details;
56
+ this.name = "CilowApiError";
57
+ }
58
+ };
59
+ var CilowClient = class {
60
+ constructor(config) {
61
+ this.baseUrl = config.apiUrl.replace(/\/$/, "");
62
+ this.apiKey = config.apiKey;
63
+ this.timeout = config.timeout ?? 3e4;
64
+ this.retries = config.retries ?? 3;
65
+ this.debug = config.debug ?? false;
66
+ const authHeaders = this.apiKey.startsWith("cilow_") ? { "X-API-Key": this.apiKey } : { Authorization: `Bearer ${this.apiKey}` };
67
+ this.headers = {
68
+ "Content-Type": "application/json",
69
+ ...authHeaders,
70
+ ...config.headers
71
+ };
72
+ }
73
+ /**
74
+ * Make an API request
75
+ */
76
+ async request(method, path, body, queryParams) {
77
+ let url = `${this.baseUrl}${path}`;
78
+ if (queryParams) {
79
+ const params = new URLSearchParams();
80
+ for (const [key, value] of Object.entries(queryParams)) {
81
+ if (value !== void 0) {
82
+ params.append(key, String(value));
83
+ }
84
+ }
85
+ const queryString = params.toString();
86
+ if (queryString) {
87
+ url += `?${queryString}`;
88
+ }
89
+ }
90
+ if (this.debug) {
91
+ console.log(`Cilow API: ${method} ${url}`);
92
+ }
93
+ const response = await fetchWithRetry(
94
+ url,
95
+ {
96
+ method,
97
+ headers: this.headers,
98
+ body: body ? JSON.stringify(body) : void 0
99
+ },
100
+ { timeout: this.timeout, retries: this.retries, debug: this.debug }
101
+ );
102
+ const text = await response.text();
103
+ if (!text) {
104
+ return void 0;
105
+ }
106
+ return JSON.parse(text);
107
+ }
108
+ // ===========================================================================
109
+ // Simple API (remember, recall, forget)
110
+ // ===========================================================================
111
+ /**
112
+ * Store a memory (simple API)
113
+ *
114
+ * @param content - The content to remember
115
+ * @param options - Optional configuration
116
+ * @returns The created memory ID
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * await cilow.remember("User prefers dark mode", {
121
+ * tags: ["preference"],
122
+ * userId: "user-123"
123
+ * });
124
+ * ```
125
+ */
126
+ async remember(content, options) {
127
+ const response = await this.request("POST", "/api/v1/memory/add", {
128
+ content,
129
+ tags: options?.tags ?? [],
130
+ user_id: options?.userId,
131
+ session_id: options?.sessionId,
132
+ metadata: options?.metadata,
133
+ type: options?.tier
134
+ });
135
+ return response.memory_id || response.id || "";
136
+ }
137
+ /**
138
+ * Search memories (simple API)
139
+ *
140
+ * @param query - Search query text
141
+ * @param options - Search options
142
+ * @returns Array of search results
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * const memories = await cilow.recall("user preferences", {
147
+ * limit: 10,
148
+ * tags: ["preference"]
149
+ * });
150
+ * ```
151
+ */
152
+ async recall(query, options) {
153
+ const response = await this.request("POST", "/api/v1/memory/search", {
154
+ query,
155
+ limit: options?.limit ?? 10,
156
+ min_score: options?.minRelevance ?? 0.3,
157
+ tags: options?.tags,
158
+ user_id: options?.userId
159
+ });
160
+ return (response.results ?? []).map((r) => ({
161
+ memory: {
162
+ id: r.memory_id,
163
+ content: r.content,
164
+ tags: r.tags ?? [],
165
+ tier: "hot",
166
+ status: "active",
167
+ accessCount: 0,
168
+ tokenCount: Math.ceil(r.content.length / 4),
169
+ metadata: {},
170
+ createdAt: r.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
171
+ updatedAt: r.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
172
+ lastAccessedAt: (/* @__PURE__ */ new Date()).toISOString()
173
+ },
174
+ score: r.similarity,
175
+ highlights: []
176
+ }));
177
+ }
178
+ /**
179
+ * Delete memories (simple API)
180
+ *
181
+ * @param filter - Filter criteria for deletion
182
+ * @returns Number of memories deleted
183
+ *
184
+ * @example
185
+ * ```typescript
186
+ * // Delete by tags
187
+ * await cilow.forget({ tags: ["temporary"] });
188
+ *
189
+ * // Delete by user
190
+ * await cilow.forget({ userId: "user-123" });
191
+ *
192
+ * // Delete specific memory
193
+ * await cilow.forget({ memoryId: "mem-abc" });
194
+ * ```
195
+ */
196
+ async forget(filter) {
197
+ if (filter.memoryId) {
198
+ await this.deleteMemory(filter.memoryId);
199
+ return 1;
200
+ }
201
+ const response = await this.request("DELETE", "/api/v1/memories/bulk", {
202
+ filter_tags: filter.tags,
203
+ user_id: filter.userId,
204
+ session_id: filter.sessionId,
205
+ older_than: filter.olderThan
206
+ });
207
+ return response.deleted ?? 0;
208
+ }
209
+ // ===========================================================================
210
+ // Memory CRUD Operations
211
+ // ===========================================================================
212
+ /**
213
+ * Create a new memory
214
+ */
215
+ async createMemory(content, options) {
216
+ return this.request("POST", "/api/v1/memories", {
217
+ content,
218
+ tags: options?.tags ?? [],
219
+ user_id: options?.userId,
220
+ session_id: options?.sessionId,
221
+ metadata: options?.metadata,
222
+ tier: options?.tier
223
+ });
224
+ }
225
+ /**
226
+ * Get a memory by ID
227
+ */
228
+ async getMemory(memoryId) {
229
+ return this.request("GET", `/api/v1/memories/${memoryId}`);
230
+ }
231
+ /**
232
+ * Update a memory
233
+ */
234
+ async updateMemory(memoryId, updates) {
235
+ return this.request("PATCH", `/api/v1/memories/${memoryId}`, {
236
+ content: updates.content,
237
+ tags: updates.tags,
238
+ metadata: updates.metadata,
239
+ tier: updates.tier
240
+ });
241
+ }
242
+ /**
243
+ * Delete a memory
244
+ */
245
+ async deleteMemory(memoryId) {
246
+ await this.request("DELETE", `/api/v1/memories/${memoryId}`);
247
+ }
248
+ /**
249
+ * List memories with pagination
250
+ */
251
+ async listMemories(options) {
252
+ const response = await this.request(
253
+ "GET",
254
+ "/api/v1/memory/list",
255
+ void 0,
256
+ {
257
+ limit: options?.limit ?? 20,
258
+ offset: options?.offset ?? 0,
259
+ user_id: options?.userId,
260
+ session_id: options?.sessionId,
261
+ tags: options?.tags?.join(","),
262
+ type: options?.tier
263
+ }
264
+ );
265
+ const items = (response.memories ?? []).map((m) => ({
266
+ id: m.memory_id || m.id || "",
267
+ content: m.content,
268
+ tags: m.tags ?? [],
269
+ createdAt: m.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
270
+ tier: m.type || "hot"
271
+ }));
272
+ const limit = options?.limit ?? 20;
273
+ const offset = options?.offset ?? 0;
274
+ const total = response.total ?? items.length;
275
+ return {
276
+ items,
277
+ total,
278
+ limit,
279
+ offset,
280
+ hasMore: offset + items.length < total
281
+ };
282
+ }
283
+ // ===========================================================================
284
+ // Search Operations
285
+ // ===========================================================================
286
+ /**
287
+ * Search memories with full options
288
+ */
289
+ async searchMemories(query) {
290
+ const response = await this.request("POST", "/api/v1/memories/search", {
291
+ text: query.text,
292
+ limit: query.limit ?? 10,
293
+ min_relevance: query.minRelevance ?? 0.3,
294
+ filter_tags: query.tags,
295
+ user_id: query.userId,
296
+ session_id: query.sessionId,
297
+ tier: query.tier,
298
+ created_after: query.createdAfter,
299
+ created_before: query.createdBefore,
300
+ include_archived: query.includeArchived,
301
+ mode: query.mode ?? "hybrid"
302
+ });
303
+ return response.results ?? [];
304
+ }
305
+ /**
306
+ * Advanced search with reranking and boosts
307
+ */
308
+ async advancedSearch(query) {
309
+ const response = await this.request("POST", "/api/v1/memories/search/advanced", {
310
+ text: query.text,
311
+ limit: query.limit ?? 10,
312
+ min_relevance: query.minRelevance ?? 0.3,
313
+ filter_tags: query.tags,
314
+ required_tags: query.requiredTags,
315
+ excluded_tags: query.excludedTags,
316
+ user_id: query.userId,
317
+ session_id: query.sessionId,
318
+ recency_boost: query.recencyBoost,
319
+ frequency_boost: query.frequencyBoost,
320
+ metadata_filters: query.metadataFilters,
321
+ reranker: query.reranker
322
+ });
323
+ return response.results ?? [];
324
+ }
325
+ /**
326
+ * Get context for AI applications
327
+ */
328
+ async getContext(query, options) {
329
+ const maxTokens = options?.maxTokens ?? 4e3;
330
+ const tokensPerChar = 0.25;
331
+ const results = await this.searchMemories({
332
+ text: query,
333
+ limit: 30,
334
+ minRelevance: 0.3,
335
+ userId: options?.userId,
336
+ tags: options?.tags
337
+ });
338
+ let context = "";
339
+ let estimatedTokens = 0;
340
+ const memoryIds = [];
341
+ const scores = [];
342
+ for (const result of results) {
343
+ const memoryText = `[Relevance: ${(result.score * 100).toFixed(0)}%]
344
+ ${result.memory.content}
345
+
346
+ `;
347
+ const memoryTokens = Math.ceil(memoryText.length * tokensPerChar);
348
+ if (estimatedTokens + memoryTokens > maxTokens) break;
349
+ context += memoryText;
350
+ estimatedTokens += memoryTokens;
351
+ memoryIds.push(result.memory.id);
352
+ scores.push(result.score);
353
+ }
354
+ return {
355
+ context: context.trim(),
356
+ memoriesUsed: memoryIds.length,
357
+ estimatedTokens,
358
+ memoryIds,
359
+ scores
360
+ };
361
+ }
362
+ // ===========================================================================
363
+ // Conversation Operations
364
+ // ===========================================================================
365
+ /**
366
+ * Store a conversation turn
367
+ */
368
+ async storeConversation(turn) {
369
+ const content = `User: ${turn.userMessage}
370
+
371
+ Assistant: ${turn.assistantResponse}`;
372
+ const tags = ["conversation"];
373
+ if (turn.sessionId) {
374
+ tags.push(`session:${turn.sessionId}`);
375
+ }
376
+ return this.remember(content, {
377
+ tags,
378
+ userId: turn.userId,
379
+ sessionId: turn.sessionId,
380
+ metadata: {
381
+ type: "conversation",
382
+ ...turn.metadata
383
+ }
384
+ });
385
+ }
386
+ /**
387
+ * Get conversation history for a session
388
+ */
389
+ async getConversationHistory(sessionId, options) {
390
+ const response = await this.listMemories({
391
+ sessionId,
392
+ tags: ["conversation"],
393
+ limit: options?.limit ?? 50,
394
+ offset: options?.offset ?? 0
395
+ });
396
+ return response.items;
397
+ }
398
+ // ===========================================================================
399
+ // Graph Operations
400
+ // ===========================================================================
401
+ /**
402
+ * Get a graph node
403
+ */
404
+ async getGraphNode(nodeId) {
405
+ return this.request("GET", `/api/v1/graph/nodes/${nodeId}`);
406
+ }
407
+ /**
408
+ * Create a graph node
409
+ */
410
+ async createGraphNode(type, name, properties) {
411
+ return this.request("POST", "/api/v1/graph/nodes", {
412
+ type,
413
+ name,
414
+ properties: properties ?? {}
415
+ });
416
+ }
417
+ /**
418
+ * Create a graph edge
419
+ */
420
+ async createGraphEdge(sourceId, targetId, type, properties) {
421
+ return this.request("POST", "/api/v1/graph/edges", {
422
+ source_id: sourceId,
423
+ target_id: targetId,
424
+ type,
425
+ properties: properties ?? {}
426
+ });
427
+ }
428
+ /**
429
+ * Traverse the graph from a starting node
430
+ */
431
+ async traverseGraph(options) {
432
+ return this.request("POST", "/api/v1/graph/traverse", {
433
+ start_node_id: options.startNodeId,
434
+ max_depth: options.maxDepth ?? 3,
435
+ relationship_types: options.relationshipTypes,
436
+ limit: options.limit ?? 100,
437
+ direction: options.direction ?? "both"
438
+ });
439
+ }
440
+ /**
441
+ * Get related nodes for a memory
442
+ */
443
+ async getRelatedNodes(memoryId) {
444
+ const response = await this.request(
445
+ "GET",
446
+ `/api/v1/memories/${memoryId}/related-nodes`
447
+ );
448
+ return response.nodes ?? [];
449
+ }
450
+ // ===========================================================================
451
+ // Statistics & Admin
452
+ // ===========================================================================
453
+ /**
454
+ * Get memory statistics
455
+ */
456
+ async getStats() {
457
+ return this.request("GET", "/api/v1/stats");
458
+ }
459
+ /**
460
+ * Get all tags with counts
461
+ */
462
+ async getTags() {
463
+ const response = await this.request("GET", "/api/v1/tags");
464
+ return response.tags ?? [];
465
+ }
466
+ /**
467
+ * Get user statistics
468
+ */
469
+ async getUserStats(userId) {
470
+ return this.request("GET", `/api/v1/users/${userId}/stats`);
471
+ }
472
+ /**
473
+ * Health check
474
+ */
475
+ async healthCheck() {
476
+ return this.request("GET", "/health");
477
+ }
478
+ // ===========================================================================
479
+ // Batch Operations
480
+ // ===========================================================================
481
+ /**
482
+ * Batch create memories
483
+ */
484
+ async batchCreate(items) {
485
+ const response = await this.request("POST", "/api/v1/memories/batch", {
486
+ memories: items.map((item) => ({
487
+ content: item.content,
488
+ tags: item.options?.tags ?? [],
489
+ user_id: item.options?.userId,
490
+ session_id: item.options?.sessionId,
491
+ metadata: item.options?.metadata
492
+ }))
493
+ });
494
+ return response.ids ?? [];
495
+ }
496
+ /**
497
+ * Batch delete memories
498
+ */
499
+ async batchDelete(memoryIds) {
500
+ const response = await this.request("DELETE", "/api/v1/memories/batch", {
501
+ ids: memoryIds
502
+ });
503
+ return response.deleted ?? 0;
504
+ }
505
+ };
506
+
507
+ // src/websocket.ts
508
+ var CilowWebSocket = class {
509
+ constructor(config) {
510
+ this.ws = null;
511
+ this.state = "disconnected";
512
+ this.reconnectCount = 0;
513
+ this.heartbeatTimer = null;
514
+ this.reconnectTimer = null;
515
+ this.messageQueue = [];
516
+ this.subscriptions = [];
517
+ this.listeners = /* @__PURE__ */ new Map();
518
+ this.allListeners = /* @__PURE__ */ new Set();
519
+ const httpUrl = config.apiUrl.replace(/\/$/, "");
520
+ this.wsUrl = config.wsUrl ?? httpUrl.replace(/^http/, "ws") + "/ws";
521
+ this.apiKey = config.apiKey;
522
+ this.reconnectAttempts = config.reconnectAttempts ?? 5;
523
+ this.reconnectDelay = config.reconnectDelay ?? 1e3;
524
+ this.heartbeatInterval = config.heartbeatInterval ?? 3e4;
525
+ this.messageQueueSize = config.messageQueueSize ?? 100;
526
+ }
527
+ /**
528
+ * Get current connection state
529
+ */
530
+ get connectionState() {
531
+ return this.state;
532
+ }
533
+ /**
534
+ * Check if connected
535
+ */
536
+ get isConnected() {
537
+ return this.state === "connected";
538
+ }
539
+ /**
540
+ * Connect to the WebSocket server
541
+ */
542
+ async connect() {
543
+ if (this.state === "connected" || this.state === "connecting") {
544
+ return;
545
+ }
546
+ this.state = "connecting";
547
+ this.emitStatusEvent("connecting");
548
+ return new Promise((resolve, reject) => {
549
+ try {
550
+ const url = new URL(this.wsUrl);
551
+ url.searchParams.set("token", this.apiKey);
552
+ this.ws = new WebSocket(url.toString());
553
+ this.ws.onopen = () => {
554
+ this.state = "connected";
555
+ this.reconnectCount = 0;
556
+ this.emitStatusEvent("connected");
557
+ this.startHeartbeat();
558
+ this.flushMessageQueue();
559
+ this.resubscribe();
560
+ resolve();
561
+ };
562
+ this.ws.onclose = (event) => {
563
+ this.handleClose(event);
564
+ };
565
+ this.ws.onerror = (error) => {
566
+ if (this.state === "connecting") {
567
+ reject(new Error("WebSocket connection failed"));
568
+ }
569
+ this.handleError(error);
570
+ };
571
+ this.ws.onmessage = (event) => {
572
+ this.handleMessage(event);
573
+ };
574
+ } catch (error) {
575
+ this.state = "disconnected";
576
+ reject(error);
577
+ }
578
+ });
579
+ }
580
+ /**
581
+ * Disconnect from the WebSocket server
582
+ */
583
+ disconnect() {
584
+ this.stopHeartbeat();
585
+ this.clearReconnectTimer();
586
+ if (this.ws) {
587
+ this.ws.onclose = null;
588
+ this.ws.close(1e3, "Client disconnect");
589
+ this.ws = null;
590
+ }
591
+ this.state = "disconnected";
592
+ this.emitStatusEvent("disconnected", "Client initiated disconnect");
593
+ }
594
+ /**
595
+ * Subscribe to events with optional filter
596
+ */
597
+ subscribe(filter) {
598
+ if (filter) {
599
+ this.subscriptions.push(filter);
600
+ }
601
+ if (this.isConnected) {
602
+ this.sendSubscription(filter);
603
+ }
604
+ }
605
+ /**
606
+ * Unsubscribe from events
607
+ */
608
+ unsubscribe(filter) {
609
+ if (filter) {
610
+ this.subscriptions = this.subscriptions.filter(
611
+ (s) => s.userId !== filter.userId || s.sessionId !== filter.sessionId || JSON.stringify(s.tags) !== JSON.stringify(filter.tags)
612
+ );
613
+ } else {
614
+ this.subscriptions = [];
615
+ }
616
+ if (this.isConnected) {
617
+ this.send({
618
+ type: "unsubscribe",
619
+ filter
620
+ });
621
+ }
622
+ }
623
+ /**
624
+ * Add event listener for specific event type
625
+ */
626
+ on(eventType, listener) {
627
+ if (!this.listeners.has(eventType)) {
628
+ this.listeners.set(eventType, /* @__PURE__ */ new Set());
629
+ }
630
+ this.listeners.get(eventType).add(listener);
631
+ return () => {
632
+ this.listeners.get(eventType)?.delete(listener);
633
+ };
634
+ }
635
+ /**
636
+ * Add listener for all events
637
+ */
638
+ onAny(listener) {
639
+ this.allListeners.add(listener);
640
+ return () => {
641
+ this.allListeners.delete(listener);
642
+ };
643
+ }
644
+ /**
645
+ * Remove event listener
646
+ */
647
+ off(eventType, listener) {
648
+ this.listeners.get(eventType)?.delete(listener);
649
+ }
650
+ /**
651
+ * Remove all listeners for an event type
652
+ */
653
+ offAll(eventType) {
654
+ if (eventType) {
655
+ this.listeners.delete(eventType);
656
+ } else {
657
+ this.listeners.clear();
658
+ this.allListeners.clear();
659
+ }
660
+ }
661
+ /**
662
+ * Listen for memory created events
663
+ */
664
+ onMemoryCreated(listener) {
665
+ return this.on("memory.created", listener);
666
+ }
667
+ /**
668
+ * Listen for memory updated events
669
+ */
670
+ onMemoryUpdated(listener) {
671
+ return this.on("memory.updated", listener);
672
+ }
673
+ /**
674
+ * Listen for memory deleted events
675
+ */
676
+ onMemoryDeleted(listener) {
677
+ return this.on("memory.deleted", listener);
678
+ }
679
+ /**
680
+ * Listen for memory tier changed events
681
+ */
682
+ onMemoryTierChanged(listener) {
683
+ return this.on("memory.tier_changed", listener);
684
+ }
685
+ /**
686
+ * Listen for graph node created events
687
+ */
688
+ onGraphNodeCreated(listener) {
689
+ return this.on("graph.node_created", listener);
690
+ }
691
+ /**
692
+ * Listen for graph edge created events
693
+ */
694
+ onGraphEdgeCreated(listener) {
695
+ return this.on("graph.edge_created", listener);
696
+ }
697
+ /**
698
+ * Listen for connection status changes
699
+ */
700
+ onConnectionStatus(listener) {
701
+ return this.on("connection.status", listener);
702
+ }
703
+ /**
704
+ * Wait for specific event (one-time)
705
+ */
706
+ once(eventType, timeout) {
707
+ return new Promise((resolve, reject) => {
708
+ const timeoutId = timeout ? setTimeout(() => {
709
+ unsubscribe();
710
+ reject(new Error(`Timeout waiting for event: ${eventType}`));
711
+ }, timeout) : null;
712
+ const unsubscribe = this.on(eventType, (event) => {
713
+ if (timeoutId) clearTimeout(timeoutId);
714
+ unsubscribe();
715
+ resolve(event);
716
+ });
717
+ });
718
+ }
719
+ // ===========================================================================
720
+ // Private Methods
721
+ // ===========================================================================
722
+ send(message) {
723
+ const data = JSON.stringify(message);
724
+ if (this.isConnected && this.ws) {
725
+ this.ws.send(data);
726
+ } else {
727
+ if (this.messageQueue.length >= this.messageQueueSize) {
728
+ this.messageQueue.shift();
729
+ }
730
+ this.messageQueue.push(data);
731
+ }
732
+ }
733
+ sendSubscription(filter) {
734
+ this.send({
735
+ type: "subscribe",
736
+ filter: filter ?? {}
737
+ });
738
+ }
739
+ resubscribe() {
740
+ for (const filter of this.subscriptions) {
741
+ this.sendSubscription(filter);
742
+ }
743
+ }
744
+ flushMessageQueue() {
745
+ while (this.messageQueue.length > 0 && this.isConnected && this.ws) {
746
+ const message = this.messageQueue.shift();
747
+ if (message) {
748
+ this.ws.send(message);
749
+ }
750
+ }
751
+ }
752
+ handleMessage(event) {
753
+ try {
754
+ const data = JSON.parse(event.data);
755
+ this.emit(data);
756
+ } catch (error) {
757
+ console.error("Failed to parse WebSocket message:", error);
758
+ }
759
+ }
760
+ handleClose(event) {
761
+ this.stopHeartbeat();
762
+ if (event.code === 1e3) {
763
+ this.state = "disconnected";
764
+ this.emitStatusEvent("disconnected", "Connection closed normally");
765
+ return;
766
+ }
767
+ if (this.reconnectCount < this.reconnectAttempts) {
768
+ this.state = "reconnecting";
769
+ this.emitStatusEvent("reconnecting", `Reconnecting (attempt ${this.reconnectCount + 1}/${this.reconnectAttempts})`);
770
+ this.scheduleReconnect();
771
+ } else {
772
+ this.state = "disconnected";
773
+ this.emitStatusEvent("disconnected", "Max reconnection attempts reached");
774
+ }
775
+ }
776
+ handleError(_error) {
777
+ console.error("WebSocket error occurred");
778
+ }
779
+ scheduleReconnect() {
780
+ this.clearReconnectTimer();
781
+ const delay = this.reconnectDelay * Math.pow(2, this.reconnectCount);
782
+ this.reconnectCount++;
783
+ this.reconnectTimer = setTimeout(async () => {
784
+ try {
785
+ await this.connect();
786
+ } catch {
787
+ }
788
+ }, delay);
789
+ }
790
+ clearReconnectTimer() {
791
+ if (this.reconnectTimer) {
792
+ clearTimeout(this.reconnectTimer);
793
+ this.reconnectTimer = null;
794
+ }
795
+ }
796
+ startHeartbeat() {
797
+ this.stopHeartbeat();
798
+ this.heartbeatTimer = setInterval(() => {
799
+ if (this.isConnected) {
800
+ this.send({ type: "ping" });
801
+ }
802
+ }, this.heartbeatInterval);
803
+ }
804
+ stopHeartbeat() {
805
+ if (this.heartbeatTimer) {
806
+ clearInterval(this.heartbeatTimer);
807
+ this.heartbeatTimer = null;
808
+ }
809
+ }
810
+ emit(event) {
811
+ const typeListeners = this.listeners.get(event.type);
812
+ if (typeListeners) {
813
+ for (const listener of typeListeners) {
814
+ try {
815
+ listener(event);
816
+ } catch (error) {
817
+ console.error("Error in event listener:", error);
818
+ }
819
+ }
820
+ }
821
+ for (const listener of this.allListeners) {
822
+ try {
823
+ listener(event);
824
+ } catch (error) {
825
+ console.error("Error in event listener:", error);
826
+ }
827
+ }
828
+ }
829
+ emitStatusEvent(status, reason) {
830
+ const event = {
831
+ type: "connection.status",
832
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
833
+ status: status === "connecting" ? "reconnecting" : status,
834
+ reason
835
+ };
836
+ this.emit(event);
837
+ }
838
+ };
839
+ var CilowContext = react.createContext(null);
840
+ function CilowProvider({
841
+ children,
842
+ userId: initialUserId,
843
+ sessionId: initialSessionId,
844
+ enableWebSocket = false,
845
+ ...config
846
+ }) {
847
+ const [userId, setUserId] = react.useState(initialUserId);
848
+ const [sessionId, setSessionId] = react.useState(initialSessionId);
849
+ const [isConnected, setIsConnected] = react.useState(false);
850
+ const client = react.useMemo(() => new CilowClient(config), [config.apiUrl, config.apiKey]);
851
+ const ws = react.useMemo(() => {
852
+ if (!enableWebSocket) return null;
853
+ return new CilowWebSocket(config);
854
+ }, [enableWebSocket, config.apiUrl, config.apiKey]);
855
+ react.useEffect(() => {
856
+ if (!ws) return;
857
+ const connectWs = async () => {
858
+ try {
859
+ await ws.connect();
860
+ setIsConnected(true);
861
+ } catch (error) {
862
+ console.error("Failed to connect WebSocket:", error);
863
+ }
864
+ };
865
+ connectWs();
866
+ const unsubscribe = ws.onConnectionStatus((event) => {
867
+ setIsConnected(event.status === "connected");
868
+ });
869
+ return () => {
870
+ unsubscribe();
871
+ ws.disconnect();
872
+ };
873
+ }, [ws]);
874
+ react.useEffect(() => {
875
+ if (!ws || !userId) return;
876
+ ws.subscribe({ userId });
877
+ }, [ws, userId]);
878
+ const value = react.useMemo(
879
+ () => ({
880
+ client,
881
+ ws,
882
+ userId,
883
+ sessionId,
884
+ setUserId,
885
+ setSessionId,
886
+ isConnected
887
+ }),
888
+ [client, ws, userId, sessionId, isConnected]
889
+ );
890
+ return /* @__PURE__ */ jsxRuntime.jsx(CilowContext.Provider, { value, children });
891
+ }
892
+ function useCilow() {
893
+ const context = react.useContext(CilowContext);
894
+ if (!context) {
895
+ throw new Error("useCilow must be used within a CilowProvider");
896
+ }
897
+ return context;
898
+ }
899
+ function useMemory() {
900
+ const { client, userId, sessionId } = useCilow();
901
+ const [isLoading, setIsLoading] = react.useState(false);
902
+ const [error, setError] = react.useState(null);
903
+ const remember = react.useCallback(
904
+ async (content, options) => {
905
+ setIsLoading(true);
906
+ setError(null);
907
+ try {
908
+ const memoryId = await client.remember(content, {
909
+ ...options,
910
+ userId: options?.userId ?? userId,
911
+ sessionId: options?.sessionId ?? sessionId
912
+ });
913
+ return memoryId;
914
+ } catch (err) {
915
+ const error2 = err instanceof Error ? err : new Error(String(err));
916
+ setError(error2);
917
+ throw error2;
918
+ } finally {
919
+ setIsLoading(false);
920
+ }
921
+ },
922
+ [client, userId, sessionId]
923
+ );
924
+ const forget = react.useCallback(
925
+ async (filter) => {
926
+ setIsLoading(true);
927
+ setError(null);
928
+ try {
929
+ const count = await client.forget({
930
+ ...filter,
931
+ userId
932
+ });
933
+ return count;
934
+ } catch (err) {
935
+ const error2 = err instanceof Error ? err : new Error(String(err));
936
+ setError(error2);
937
+ throw error2;
938
+ } finally {
939
+ setIsLoading(false);
940
+ }
941
+ },
942
+ [client, userId]
943
+ );
944
+ const getMemory = react.useCallback(
945
+ async (memoryId) => {
946
+ setIsLoading(true);
947
+ setError(null);
948
+ try {
949
+ return await client.getMemory(memoryId);
950
+ } catch (err) {
951
+ const error2 = err instanceof Error ? err : new Error(String(err));
952
+ setError(error2);
953
+ throw error2;
954
+ } finally {
955
+ setIsLoading(false);
956
+ }
957
+ },
958
+ [client]
959
+ );
960
+ return { remember, forget, getMemory, isLoading, error };
961
+ }
962
+ function useRecall() {
963
+ const { client, userId } = useCilow();
964
+ const [data, setData] = react.useState([]);
965
+ const [isLoading, setIsLoading] = react.useState(false);
966
+ const [error, setError] = react.useState(null);
967
+ const search = react.useCallback(
968
+ async (query, options) => {
969
+ setIsLoading(true);
970
+ setError(null);
971
+ try {
972
+ const results = await client.recall(query, {
973
+ ...options,
974
+ userId
975
+ });
976
+ setData(results);
977
+ } catch (err) {
978
+ const error2 = err instanceof Error ? err : new Error(String(err));
979
+ setError(error2);
980
+ setData([]);
981
+ } finally {
982
+ setIsLoading(false);
983
+ }
984
+ },
985
+ [client, userId]
986
+ );
987
+ const clear = react.useCallback(() => {
988
+ setData([]);
989
+ setError(null);
990
+ }, []);
991
+ return { data, search, clear, isLoading, error };
992
+ }
993
+ function useMemorySubscription(options) {
994
+ const { ws, isConnected } = useCilow();
995
+ const [latestEvent, setLatestEvent] = react.useState(null);
996
+ const [events, setEvents] = react.useState([]);
997
+ react.useEffect(() => {
998
+ if (!ws) return;
999
+ const unsubscribers = [];
1000
+ const handleEvent = (event) => {
1001
+ setLatestEvent(event);
1002
+ setEvents((prev) => [...prev, event]);
1003
+ };
1004
+ const eventTypes = options?.eventTypes ?? [
1005
+ "memory.created",
1006
+ "memory.updated",
1007
+ "memory.deleted"
1008
+ ];
1009
+ for (const eventType of eventTypes) {
1010
+ if (eventType === "memory.created") {
1011
+ unsubscribers.push(ws.onMemoryCreated(handleEvent));
1012
+ } else if (eventType === "memory.updated") {
1013
+ unsubscribers.push(ws.onMemoryUpdated(handleEvent));
1014
+ } else if (eventType === "memory.deleted") {
1015
+ unsubscribers.push(ws.onMemoryDeleted(handleEvent));
1016
+ }
1017
+ }
1018
+ if (options?.userId || options?.sessionId || options?.tags) {
1019
+ ws.subscribe({
1020
+ userId: options.userId,
1021
+ sessionId: options.sessionId,
1022
+ tags: options.tags
1023
+ });
1024
+ }
1025
+ return () => {
1026
+ unsubscribers.forEach((unsub) => unsub());
1027
+ };
1028
+ }, [ws, options?.userId, options?.sessionId, options?.tags, options?.eventTypes]);
1029
+ const clearEvents = react.useCallback(() => {
1030
+ setEvents([]);
1031
+ setLatestEvent(null);
1032
+ }, []);
1033
+ return { latestEvent, events, isConnected, clearEvents };
1034
+ }
1035
+ function useMemoryContext() {
1036
+ const { client, userId } = useCilow();
1037
+ const [context, setContext] = react.useState("");
1038
+ const [memoriesUsed, setMemoriesUsed] = react.useState(0);
1039
+ const [isLoading, setIsLoading] = react.useState(false);
1040
+ const [error, setError] = react.useState(null);
1041
+ const getContext = react.useCallback(
1042
+ async (query, options) => {
1043
+ setIsLoading(true);
1044
+ setError(null);
1045
+ try {
1046
+ const result = await client.getContext(query, {
1047
+ ...options,
1048
+ userId
1049
+ });
1050
+ setContext(result.context);
1051
+ setMemoriesUsed(result.memoriesUsed);
1052
+ return { context: result.context, memoriesUsed: result.memoriesUsed };
1053
+ } catch (err) {
1054
+ const error2 = err instanceof Error ? err : new Error(String(err));
1055
+ setError(error2);
1056
+ throw error2;
1057
+ } finally {
1058
+ setIsLoading(false);
1059
+ }
1060
+ },
1061
+ [client, userId]
1062
+ );
1063
+ const clearContext = react.useCallback(() => {
1064
+ setContext("");
1065
+ setMemoriesUsed(0);
1066
+ }, []);
1067
+ return { getContext, context, memoriesUsed, clearContext, isLoading, error };
1068
+ }
1069
+ function useMemoryStats() {
1070
+ const { client } = useCilow();
1071
+ const [stats, setStats] = react.useState(null);
1072
+ const [isLoading, setIsLoading] = react.useState(false);
1073
+ const [error, setError] = react.useState(null);
1074
+ const refresh = react.useCallback(async () => {
1075
+ setIsLoading(true);
1076
+ setError(null);
1077
+ try {
1078
+ const newStats = await client.getStats();
1079
+ setStats(newStats);
1080
+ } catch (err) {
1081
+ const error2 = err instanceof Error ? err : new Error(String(err));
1082
+ setError(error2);
1083
+ } finally {
1084
+ setIsLoading(false);
1085
+ }
1086
+ }, [client]);
1087
+ react.useEffect(() => {
1088
+ refresh();
1089
+ }, [refresh]);
1090
+ return { stats, refresh, isLoading, error };
1091
+ }
1092
+ function useConversation() {
1093
+ const { client, userId, sessionId } = useCilow();
1094
+ const [isLoading, setIsLoading] = react.useState(false);
1095
+ const [error, setError] = react.useState(null);
1096
+ const [storedCount, setStoredCount] = react.useState(0);
1097
+ const storeConversation = react.useCallback(
1098
+ async (userMessage, assistantResponse, metadata) => {
1099
+ setIsLoading(true);
1100
+ setError(null);
1101
+ try {
1102
+ const memoryId = await client.storeConversation({
1103
+ userMessage,
1104
+ assistantResponse,
1105
+ userId: userId ?? "anonymous",
1106
+ sessionId,
1107
+ metadata
1108
+ });
1109
+ setStoredCount((c) => c + 1);
1110
+ return memoryId;
1111
+ } catch (err) {
1112
+ const error2 = err instanceof Error ? err : new Error(String(err));
1113
+ setError(error2);
1114
+ throw error2;
1115
+ } finally {
1116
+ setIsLoading(false);
1117
+ }
1118
+ },
1119
+ [client, userId, sessionId]
1120
+ );
1121
+ return { storeConversation, storedCount, isLoading, error };
1122
+ }
1123
+ function useDebounce(value, delay) {
1124
+ const [debouncedValue, setDebouncedValue] = react.useState(value);
1125
+ react.useEffect(() => {
1126
+ const timer = setTimeout(() => setDebouncedValue(value), delay);
1127
+ return () => clearTimeout(timer);
1128
+ }, [value, delay]);
1129
+ return debouncedValue;
1130
+ }
1131
+ function useDebouncedSearch(options) {
1132
+ const { client, userId } = useCilow();
1133
+ const [query, setQuery] = react.useState("");
1134
+ const [results, setResults] = react.useState([]);
1135
+ const [isLoading, setIsLoading] = react.useState(false);
1136
+ const [error, setError] = react.useState(null);
1137
+ const debouncedQuery = useDebounce(query, options?.delay ?? 300);
1138
+ const minLength = options?.minLength ?? 2;
1139
+ const limit = options?.limit ?? 10;
1140
+ react.useEffect(() => {
1141
+ if (debouncedQuery.length < minLength) {
1142
+ setResults([]);
1143
+ return;
1144
+ }
1145
+ const search = async () => {
1146
+ setIsLoading(true);
1147
+ setError(null);
1148
+ try {
1149
+ const searchResults = await client.recall(debouncedQuery, {
1150
+ limit,
1151
+ userId
1152
+ });
1153
+ setResults(searchResults);
1154
+ } catch (err) {
1155
+ const error2 = err instanceof Error ? err : new Error(String(err));
1156
+ setError(error2);
1157
+ setResults([]);
1158
+ } finally {
1159
+ setIsLoading(false);
1160
+ }
1161
+ };
1162
+ search();
1163
+ }, [debouncedQuery, client, userId, limit, minLength]);
1164
+ const clear = react.useCallback(() => {
1165
+ setQuery("");
1166
+ setResults([]);
1167
+ setError(null);
1168
+ }, []);
1169
+ return { query, setQuery, results, clear, isLoading, error };
1170
+ }
1171
+
1172
+ exports.CilowProvider = CilowProvider;
1173
+ exports.useCilow = useCilow;
1174
+ exports.useConversation = useConversation;
1175
+ exports.useDebounce = useDebounce;
1176
+ exports.useDebouncedSearch = useDebouncedSearch;
1177
+ exports.useMemory = useMemory;
1178
+ exports.useMemoryContext = useMemoryContext;
1179
+ exports.useMemoryStats = useMemoryStats;
1180
+ exports.useMemorySubscription = useMemorySubscription;
1181
+ exports.useRecall = useRecall;
1182
+ //# sourceMappingURL=hooks.js.map
1183
+ //# sourceMappingURL=hooks.js.map