@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
package/dist/index.mjs CHANGED
@@ -1,449 +1,863 @@
1
- // src/errors.ts
2
- var CilowError = class _CilowError extends Error {
3
- constructor(message, statusCode, details) {
1
+ // src/client.ts
2
+ async function fetchWithRetry(url, options, config) {
3
+ const controller = new AbortController();
4
+ const timeoutId = setTimeout(() => controller.abort(), config.timeout);
5
+ let lastError = null;
6
+ for (let attempt = 0; attempt <= config.retries; attempt++) {
7
+ try {
8
+ const response = await fetch(url, {
9
+ ...options,
10
+ signal: controller.signal
11
+ });
12
+ clearTimeout(timeoutId);
13
+ if (!response.ok) {
14
+ const errorBody = await response.text();
15
+ let apiError;
16
+ try {
17
+ apiError = JSON.parse(errorBody);
18
+ } catch {
19
+ apiError = {
20
+ code: `HTTP_${response.status}`,
21
+ message: errorBody || response.statusText
22
+ };
23
+ }
24
+ throw new CilowApiError(apiError.message, apiError.code, response.status, apiError.details);
25
+ }
26
+ return response;
27
+ } catch (error) {
28
+ lastError = error;
29
+ if (error instanceof CilowApiError) {
30
+ throw error;
31
+ }
32
+ if (config.debug) {
33
+ console.warn(`Cilow API request failed (attempt ${attempt + 1}/${config.retries + 1}):`, error);
34
+ }
35
+ if (attempt < config.retries) {
36
+ await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 100));
37
+ }
38
+ }
39
+ }
40
+ clearTimeout(timeoutId);
41
+ throw lastError || new Error("Request failed");
42
+ }
43
+ var CilowApiError = class extends Error {
44
+ constructor(message, code, statusCode, details) {
4
45
  super(message);
5
- this.name = "CilowError";
46
+ this.code = code;
6
47
  this.statusCode = statusCode;
7
48
  this.details = details;
8
- Object.setPrototypeOf(this, _CilowError.prototype);
49
+ this.name = "CilowApiError";
9
50
  }
10
51
  };
11
- var ConnectionError = class _ConnectionError extends CilowError {
12
- constructor(message, details) {
13
- super(message, void 0, details);
14
- this.name = "ConnectionError";
15
- Object.setPrototypeOf(this, _ConnectionError.prototype);
16
- }
17
- };
18
- var AuthenticationError = class _AuthenticationError extends CilowError {
19
- constructor(message = "Invalid API key or unauthorized", details) {
20
- super(message, 401, details);
21
- this.name = "AuthenticationError";
22
- Object.setPrototypeOf(this, _AuthenticationError.prototype);
23
- }
24
- };
25
- var NotFoundError = class _NotFoundError extends CilowError {
26
- constructor(message = "Resource not found", details) {
27
- super(message, 404, details);
28
- this.name = "NotFoundError";
29
- Object.setPrototypeOf(this, _NotFoundError.prototype);
30
- }
31
- };
32
- var ValidationError = class _ValidationError extends CilowError {
33
- constructor(message = "Validation error", details) {
34
- super(message, 422, details);
35
- this.name = "ValidationError";
36
- Object.setPrototypeOf(this, _ValidationError.prototype);
37
- }
38
- };
39
- var RateLimitError = class _RateLimitError extends CilowError {
40
- constructor(message = "Rate limit exceeded", retryAfter, details) {
41
- super(message, 429, details);
42
- this.name = "RateLimitError";
43
- this.retryAfter = retryAfter;
44
- Object.setPrototypeOf(this, _RateLimitError.prototype);
45
- }
46
- };
47
-
48
- // src/client.ts
49
- function toCamelCase(obj) {
50
- if (Array.isArray(obj)) {
51
- return obj.map((item) => toCamelCase(item));
52
- }
53
- if (obj !== null && typeof obj === "object") {
54
- return Object.entries(obj).reduce((acc, [key, value]) => {
55
- const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
56
- acc[camelKey] = toCamelCase(value);
57
- return acc;
58
- }, {});
59
- }
60
- return obj;
61
- }
62
- function toSnakeCase(obj) {
63
- if (Array.isArray(obj)) {
64
- return obj.map((item) => toSnakeCase(item));
65
- }
66
- if (obj !== null && typeof obj === "object") {
67
- return Object.entries(obj).reduce((acc, [key, value]) => {
68
- const snakeKey = key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
69
- acc[snakeKey] = toSnakeCase(value);
70
- return acc;
71
- }, {});
72
- }
73
- return obj;
74
- }
75
52
  var CilowClient = class {
76
- constructor(config = {}) {
77
- this.baseUrl = (config.baseUrl ?? "http://localhost:8080").replace(/\/$/, "");
53
+ constructor(config) {
54
+ this.baseUrl = config.apiUrl.replace(/\/$/, "");
78
55
  this.apiKey = config.apiKey;
79
- this.accessToken = config.accessToken;
80
56
  this.timeout = config.timeout ?? 3e4;
57
+ this.retries = config.retries ?? 3;
58
+ this.debug = config.debug ?? false;
59
+ const authHeaders = this.apiKey.startsWith("cilow_") ? { "X-API-Key": this.apiKey } : { Authorization: `Bearer ${this.apiKey}` };
60
+ this.headers = {
61
+ "Content-Type": "application/json",
62
+ ...authHeaders,
63
+ ...config.headers
64
+ };
81
65
  }
82
66
  /**
83
- * Set the JWT access token for Bearer authentication
84
- */
85
- setAccessToken(token) {
86
- this.accessToken = token;
87
- }
88
- /**
89
- * Make API request with error handling
67
+ * Make an API request
90
68
  */
91
- async request(method, endpoint, data, useAuth = true) {
92
- const url = `${this.baseUrl}/api/v1${endpoint}`;
93
- const headers = {
94
- "Content-Type": "application/json"
95
- };
96
- if (useAuth) {
97
- if (this.apiKey) {
98
- headers["X-API-Key"] = this.apiKey;
69
+ async request(method, path, body, queryParams) {
70
+ let url = `${this.baseUrl}${path}`;
71
+ if (queryParams) {
72
+ const params = new URLSearchParams();
73
+ for (const [key, value] of Object.entries(queryParams)) {
74
+ if (value !== void 0) {
75
+ params.append(key, String(value));
76
+ }
99
77
  }
100
- if (this.accessToken) {
101
- headers["Authorization"] = `Bearer ${this.accessToken}`;
78
+ const queryString = params.toString();
79
+ if (queryString) {
80
+ url += `?${queryString}`;
102
81
  }
103
82
  }
104
- const controller = new AbortController();
105
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
106
- try {
107
- const response = await fetch(url, {
83
+ if (this.debug) {
84
+ console.log(`Cilow API: ${method} ${url}`);
85
+ }
86
+ const response = await fetchWithRetry(
87
+ url,
88
+ {
108
89
  method,
109
- headers,
110
- body: data ? JSON.stringify(toSnakeCase(data)) : void 0,
111
- signal: controller.signal
112
- });
113
- clearTimeout(timeoutId);
114
- if (!response.ok) {
115
- const errorText = await response.text();
116
- switch (response.status) {
117
- case 401:
118
- throw new AuthenticationError("Invalid API key or unauthorized");
119
- case 404:
120
- throw new NotFoundError(`Resource not found: ${endpoint}`);
121
- case 422:
122
- throw new ValidationError(`Validation error: ${errorText}`);
123
- case 429:
124
- const retryAfter = response.headers.get("Retry-After");
125
- throw new RateLimitError(
126
- "Rate limit exceeded",
127
- retryAfter ? parseInt(retryAfter, 10) : void 0
128
- );
129
- default:
130
- throw new CilowError(`API error ${response.status}: ${errorText}`, response.status);
131
- }
132
- }
133
- const json = await response.json();
134
- return toCamelCase(json);
135
- } catch (error) {
136
- clearTimeout(timeoutId);
137
- if (error instanceof CilowError) {
138
- throw error;
139
- }
140
- if (error instanceof Error) {
141
- if (error.name === "AbortError") {
142
- throw new ConnectionError("Request timeout");
143
- }
144
- throw new ConnectionError(`Failed to connect to Cilow API: ${error.message}`);
145
- }
146
- throw new ConnectionError("Unknown error occurred");
90
+ headers: this.headers,
91
+ body: body ? JSON.stringify(body) : void 0
92
+ },
93
+ { timeout: this.timeout, retries: this.retries, debug: this.debug }
94
+ );
95
+ const text = await response.text();
96
+ if (!text) {
97
+ return void 0;
147
98
  }
99
+ return JSON.parse(text);
148
100
  }
149
101
  // ===========================================================================
150
- // Health & Status
102
+ // Simple API (remember, recall, forget)
151
103
  // ===========================================================================
152
104
  /**
153
- * Check API server health
154
- */
155
- async healthCheck() {
156
- const response = await fetch(`${this.baseUrl}/health`);
157
- const json = await response.json();
158
- return toCamelCase(json);
105
+ * Store a memory (simple API)
106
+ *
107
+ * @param content - The content to remember
108
+ * @param options - Optional configuration
109
+ * @returns The created memory ID
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * await cilow.remember("User prefers dark mode", {
114
+ * tags: ["preference"],
115
+ * userId: "user-123"
116
+ * });
117
+ * ```
118
+ */
119
+ async remember(content, options) {
120
+ const response = await this.request("POST", "/api/v1/memory/add", {
121
+ content,
122
+ tags: options?.tags ?? [],
123
+ user_id: options?.userId,
124
+ session_id: options?.sessionId,
125
+ metadata: options?.metadata,
126
+ type: options?.tier
127
+ });
128
+ return response.memory_id || response.id || "";
129
+ }
130
+ /**
131
+ * Search memories (simple API)
132
+ *
133
+ * @param query - Search query text
134
+ * @param options - Search options
135
+ * @returns Array of search results
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * const memories = await cilow.recall("user preferences", {
140
+ * limit: 10,
141
+ * tags: ["preference"]
142
+ * });
143
+ * ```
144
+ */
145
+ async recall(query, options) {
146
+ const response = await this.request("POST", "/api/v1/memory/search", {
147
+ query,
148
+ limit: options?.limit ?? 10,
149
+ min_score: options?.minRelevance ?? 0.3,
150
+ tags: options?.tags,
151
+ user_id: options?.userId
152
+ });
153
+ return (response.results ?? []).map((r) => ({
154
+ memory: {
155
+ id: r.memory_id,
156
+ content: r.content,
157
+ tags: r.tags ?? [],
158
+ tier: "hot",
159
+ status: "active",
160
+ accessCount: 0,
161
+ tokenCount: Math.ceil(r.content.length / 4),
162
+ metadata: {},
163
+ createdAt: r.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
164
+ updatedAt: r.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
165
+ lastAccessedAt: (/* @__PURE__ */ new Date()).toISOString()
166
+ },
167
+ score: r.similarity,
168
+ highlights: []
169
+ }));
170
+ }
171
+ /**
172
+ * Delete memories (simple API)
173
+ *
174
+ * @param filter - Filter criteria for deletion
175
+ * @returns Number of memories deleted
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * // Delete by tags
180
+ * await cilow.forget({ tags: ["temporary"] });
181
+ *
182
+ * // Delete by user
183
+ * await cilow.forget({ userId: "user-123" });
184
+ *
185
+ * // Delete specific memory
186
+ * await cilow.forget({ memoryId: "mem-abc" });
187
+ * ```
188
+ */
189
+ async forget(filter) {
190
+ if (filter.memoryId) {
191
+ await this.deleteMemory(filter.memoryId);
192
+ return 1;
193
+ }
194
+ const response = await this.request("DELETE", "/api/v1/memories/bulk", {
195
+ filter_tags: filter.tags,
196
+ user_id: filter.userId,
197
+ session_id: filter.sessionId,
198
+ older_than: filter.olderThan
199
+ });
200
+ return response.deleted ?? 0;
159
201
  }
160
202
  // ===========================================================================
161
- // Memory Operations
203
+ // Memory CRUD Operations
162
204
  // ===========================================================================
163
205
  /**
164
- * Add a new memory to the system
206
+ * Create a new memory
165
207
  */
166
- async addMemory(options) {
167
- const response = await this.request("POST", "/memory/add", options);
168
- return response.memoryId;
208
+ async createMemory(content, options) {
209
+ return this.request("POST", "/api/v1/memories", {
210
+ content,
211
+ tags: options?.tags ?? [],
212
+ user_id: options?.userId,
213
+ session_id: options?.sessionId,
214
+ metadata: options?.metadata,
215
+ tier: options?.tier
216
+ });
169
217
  }
170
218
  /**
171
219
  * Get a memory by ID
172
220
  */
173
- async getMemory(memoryId, userId) {
174
- const endpoint = userId ? `/memory/${memoryId}?user_id=${userId}` : `/memory/${memoryId}`;
175
- return this.request("GET", endpoint);
221
+ async getMemory(memoryId) {
222
+ return this.request("GET", `/api/v1/memories/${memoryId}`);
176
223
  }
177
224
  /**
178
- * Update an existing memory
225
+ * Update a memory
179
226
  */
180
- async updateMemory(memoryId, options) {
181
- return this.request("PUT", `/memory/${memoryId}`, options);
227
+ async updateMemory(memoryId, updates) {
228
+ return this.request("PATCH", `/api/v1/memories/${memoryId}`, {
229
+ content: updates.content,
230
+ tags: updates.tags,
231
+ metadata: updates.metadata,
232
+ tier: updates.tier
233
+ });
182
234
  }
183
235
  /**
184
236
  * Delete a memory
185
237
  */
186
238
  async deleteMemory(memoryId) {
187
- await this.request("DELETE", `/memory/${memoryId}`);
188
- return true;
239
+ await this.request("DELETE", `/api/v1/memories/${memoryId}`);
189
240
  }
190
241
  /**
191
- * Search memories with semantic similarity
242
+ * List memories with pagination
192
243
  */
193
- async searchMemories(options) {
244
+ async listMemories(options) {
194
245
  const response = await this.request(
195
- "POST",
196
- "/memory/search",
197
- options
246
+ "GET",
247
+ "/api/v1/memory/list",
248
+ void 0,
249
+ {
250
+ limit: options?.limit ?? 20,
251
+ offset: options?.offset ?? 0,
252
+ user_id: options?.userId,
253
+ session_id: options?.sessionId,
254
+ tags: options?.tags?.join(","),
255
+ type: options?.tier
256
+ }
198
257
  );
199
- return Array.isArray(response) ? response : response.memories ?? [];
258
+ const items = (response.memories ?? []).map((m) => ({
259
+ id: m.memory_id || m.id || "",
260
+ content: m.content,
261
+ tags: m.tags ?? [],
262
+ createdAt: m.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
263
+ tier: m.type || "hot"
264
+ }));
265
+ const limit = options?.limit ?? 20;
266
+ const offset = options?.offset ?? 0;
267
+ const total = response.total ?? items.length;
268
+ return {
269
+ items,
270
+ total,
271
+ limit,
272
+ offset,
273
+ hasMore: offset + items.length < total
274
+ };
275
+ }
276
+ // ===========================================================================
277
+ // Search Operations
278
+ // ===========================================================================
279
+ /**
280
+ * Search memories with full options
281
+ */
282
+ async searchMemories(query) {
283
+ const response = await this.request("POST", "/api/v1/memories/search", {
284
+ text: query.text,
285
+ limit: query.limit ?? 10,
286
+ min_relevance: query.minRelevance ?? 0.3,
287
+ filter_tags: query.tags,
288
+ user_id: query.userId,
289
+ session_id: query.sessionId,
290
+ tier: query.tier,
291
+ created_after: query.createdAfter,
292
+ created_before: query.createdBefore,
293
+ include_archived: query.includeArchived,
294
+ mode: query.mode ?? "hybrid"
295
+ });
296
+ return response.results ?? [];
297
+ }
298
+ /**
299
+ * Advanced search with reranking and boosts
300
+ */
301
+ async advancedSearch(query) {
302
+ const response = await this.request("POST", "/api/v1/memories/search/advanced", {
303
+ text: query.text,
304
+ limit: query.limit ?? 10,
305
+ min_relevance: query.minRelevance ?? 0.3,
306
+ filter_tags: query.tags,
307
+ required_tags: query.requiredTags,
308
+ excluded_tags: query.excludedTags,
309
+ user_id: query.userId,
310
+ session_id: query.sessionId,
311
+ recency_boost: query.recencyBoost,
312
+ frequency_boost: query.frequencyBoost,
313
+ metadata_filters: query.metadataFilters,
314
+ reranker: query.reranker
315
+ });
316
+ return response.results ?? [];
317
+ }
318
+ /**
319
+ * Get context for AI applications
320
+ */
321
+ async getContext(query, options) {
322
+ const maxTokens = options?.maxTokens ?? 4e3;
323
+ const tokensPerChar = 0.25;
324
+ const results = await this.searchMemories({
325
+ text: query,
326
+ limit: 30,
327
+ minRelevance: 0.3,
328
+ userId: options?.userId,
329
+ tags: options?.tags
330
+ });
331
+ let context = "";
332
+ let estimatedTokens = 0;
333
+ const memoryIds = [];
334
+ const scores = [];
335
+ for (const result of results) {
336
+ const memoryText = `[Relevance: ${(result.score * 100).toFixed(0)}%]
337
+ ${result.memory.content}
338
+
339
+ `;
340
+ const memoryTokens = Math.ceil(memoryText.length * tokensPerChar);
341
+ if (estimatedTokens + memoryTokens > maxTokens) break;
342
+ context += memoryText;
343
+ estimatedTokens += memoryTokens;
344
+ memoryIds.push(result.memory.id);
345
+ scores.push(result.score);
346
+ }
347
+ return {
348
+ context: context.trim(),
349
+ memoriesUsed: memoryIds.length,
350
+ estimatedTokens,
351
+ memoryIds,
352
+ scores
353
+ };
200
354
  }
355
+ // ===========================================================================
356
+ // Conversation Operations
357
+ // ===========================================================================
201
358
  /**
202
- * Get memory system statistics
359
+ * Store a conversation turn
203
360
  */
204
- async getMemoryStats() {
205
- return this.request("GET", "/memory/stats");
361
+ async storeConversation(turn) {
362
+ const content = `User: ${turn.userMessage}
363
+
364
+ Assistant: ${turn.assistantResponse}`;
365
+ const tags = ["conversation"];
366
+ if (turn.sessionId) {
367
+ tags.push(`session:${turn.sessionId}`);
368
+ }
369
+ return this.remember(content, {
370
+ tags,
371
+ userId: turn.userId,
372
+ sessionId: turn.sessionId,
373
+ metadata: {
374
+ type: "conversation",
375
+ ...turn.metadata
376
+ }
377
+ });
206
378
  }
207
379
  /**
208
- * List memories with pagination
380
+ * Get conversation history for a session
209
381
  */
210
- async listMemories(options) {
211
- const params = new URLSearchParams();
212
- if (options?.limit) params.set("limit", options.limit.toString());
213
- if (options?.offset) params.set("offset", options.offset.toString());
214
- if (options?.tags) params.set("tags", options.tags.join(","));
215
- if (options?.userId) params.set("user_id", options.userId);
216
- const endpoint = params.toString() ? `/memory/list?${params}` : "/memory/list";
217
- const response = await this.request("GET", endpoint);
218
- return Array.isArray(response) ? response : response.memories ?? [];
382
+ async getConversationHistory(sessionId, options) {
383
+ const response = await this.listMemories({
384
+ sessionId,
385
+ tags: ["conversation"],
386
+ limit: options?.limit ?? 50,
387
+ offset: options?.offset ?? 0
388
+ });
389
+ return response.items;
219
390
  }
220
391
  // ===========================================================================
221
- // Vector Operations
392
+ // Graph Operations
222
393
  // ===========================================================================
223
394
  /**
224
- * Store a vector embedding directly
395
+ * Get a graph node
225
396
  */
226
- async storeVector(options) {
227
- const response = await this.request(
228
- "POST",
229
- "/vectors",
230
- options
231
- );
232
- return response.vectorId ?? response.id ?? "";
397
+ async getGraphNode(nodeId) {
398
+ return this.request("GET", `/api/v1/graph/nodes/${nodeId}`);
233
399
  }
234
400
  /**
235
- * Search for similar vectors
401
+ * Create a graph node
236
402
  */
237
- async searchVectors(options) {
238
- const response = await this.request("POST", "/vectors/search", options);
239
- return response;
403
+ async createGraphNode(type, name, properties) {
404
+ return this.request("POST", "/api/v1/graph/nodes", {
405
+ type,
406
+ name,
407
+ properties: properties ?? {}
408
+ });
240
409
  }
241
410
  /**
242
- * Get a vector by ID
411
+ * Create a graph edge
243
412
  */
244
- async getVector(vectorId) {
245
- return this.request("GET", `/vectors/${vectorId}`);
413
+ async createGraphEdge(sourceId, targetId, type, properties) {
414
+ return this.request("POST", "/api/v1/graph/edges", {
415
+ source_id: sourceId,
416
+ target_id: targetId,
417
+ type,
418
+ properties: properties ?? {}
419
+ });
246
420
  }
247
421
  /**
248
- * Delete a vector
422
+ * Traverse the graph from a starting node
249
423
  */
250
- async deleteVector(vectorId) {
251
- await this.request("DELETE", `/vectors/${vectorId}`);
252
- return true;
424
+ async traverseGraph(options) {
425
+ return this.request("POST", "/api/v1/graph/traverse", {
426
+ start_node_id: options.startNodeId,
427
+ max_depth: options.maxDepth ?? 3,
428
+ relationship_types: options.relationshipTypes,
429
+ limit: options.limit ?? 100,
430
+ direction: options.direction ?? "both"
431
+ });
253
432
  }
254
- // ===========================================================================
255
- // Graph Operations
256
- // ===========================================================================
257
433
  /**
258
- * Query the knowledge graph with natural language
434
+ * Get related nodes for a memory
259
435
  */
260
- async queryGraph(query, limit = 10) {
436
+ async getRelatedNodes(memoryId) {
261
437
  const response = await this.request(
262
- "POST",
263
- "/graph/query",
264
- { query, limit }
438
+ "GET",
439
+ `/api/v1/memories/${memoryId}/related-nodes`
265
440
  );
266
- return Array.isArray(response) ? response : response.results ?? [];
441
+ return response.nodes ?? [];
267
442
  }
443
+ // ===========================================================================
444
+ // Statistics & Admin
445
+ // ===========================================================================
268
446
  /**
269
- * Add a node to the knowledge graph
447
+ * Get memory statistics
270
448
  */
271
- async addGraphNode(options) {
272
- const response = await this.request(
273
- "POST",
274
- "/graph/nodes",
275
- options
276
- );
277
- return response.nodeId ?? response.id ?? "";
449
+ async getStats() {
450
+ return this.request("GET", "/api/v1/stats");
278
451
  }
279
452
  /**
280
- * Get a graph node by ID
453
+ * Get all tags with counts
281
454
  */
282
- async getGraphNode(nodeId) {
283
- return this.request("GET", `/graph/nodes/${nodeId}`);
455
+ async getTags() {
456
+ const response = await this.request("GET", "/api/v1/tags");
457
+ return response.tags ?? [];
284
458
  }
285
459
  /**
286
- * Delete a graph node
460
+ * Get user statistics
287
461
  */
288
- async deleteGraphNode(nodeId) {
289
- await this.request("DELETE", `/graph/nodes/${nodeId}`);
290
- return true;
462
+ async getUserStats(userId) {
463
+ return this.request("GET", `/api/v1/users/${userId}/stats`);
291
464
  }
292
465
  /**
293
- * Get knowledge graph statistics
466
+ * Health check
294
467
  */
295
- async getGraphStats() {
296
- return this.request("GET", "/graph/stats");
468
+ async healthCheck() {
469
+ return this.request("GET", "/health");
297
470
  }
298
471
  // ===========================================================================
299
- // Agent Operations
472
+ // Batch Operations
300
473
  // ===========================================================================
301
474
  /**
302
- * Create a new AI agent
475
+ * Batch create memories
476
+ */
477
+ async batchCreate(items) {
478
+ const response = await this.request("POST", "/api/v1/memories/batch", {
479
+ memories: items.map((item) => ({
480
+ content: item.content,
481
+ tags: item.options?.tags ?? [],
482
+ user_id: item.options?.userId,
483
+ session_id: item.options?.sessionId,
484
+ metadata: item.options?.metadata
485
+ }))
486
+ });
487
+ return response.ids ?? [];
488
+ }
489
+ /**
490
+ * Batch delete memories
303
491
  */
304
- async createAgent(options) {
305
- const response = await this.request("POST", "/agents/create", {
306
- name: options.name,
307
- type: options.agentType ?? "react",
308
- config: options.config
492
+ async batchDelete(memoryIds) {
493
+ const response = await this.request("DELETE", "/api/v1/memories/batch", {
494
+ ids: memoryIds
309
495
  });
310
- return response.agentId;
496
+ return response.deleted ?? 0;
497
+ }
498
+ };
499
+ function createClient(config) {
500
+ return new CilowClient(config);
501
+ }
502
+
503
+ // src/types.ts
504
+ function isMemoryEvent(event) {
505
+ return event.type.startsWith("memory.");
506
+ }
507
+ function isGraphEvent(event) {
508
+ return event.type.startsWith("graph.");
509
+ }
510
+ function isApiError(obj) {
511
+ return typeof obj === "object" && obj !== null && "code" in obj && "message" in obj;
512
+ }
513
+
514
+ // src/websocket.ts
515
+ var CilowWebSocket = class {
516
+ constructor(config) {
517
+ this.ws = null;
518
+ this.state = "disconnected";
519
+ this.reconnectCount = 0;
520
+ this.heartbeatTimer = null;
521
+ this.reconnectTimer = null;
522
+ this.messageQueue = [];
523
+ this.subscriptions = [];
524
+ this.listeners = /* @__PURE__ */ new Map();
525
+ this.allListeners = /* @__PURE__ */ new Set();
526
+ const httpUrl = config.apiUrl.replace(/\/$/, "");
527
+ this.wsUrl = config.wsUrl ?? httpUrl.replace(/^http/, "ws") + "/ws";
528
+ this.apiKey = config.apiKey;
529
+ this.reconnectAttempts = config.reconnectAttempts ?? 5;
530
+ this.reconnectDelay = config.reconnectDelay ?? 1e3;
531
+ this.heartbeatInterval = config.heartbeatInterval ?? 3e4;
532
+ this.messageQueueSize = config.messageQueueSize ?? 100;
311
533
  }
312
534
  /**
313
- * Get agent details
535
+ * Get current connection state
314
536
  */
315
- async getAgent(agentId) {
316
- return this.request("GET", `/agents/${agentId}`);
537
+ get connectionState() {
538
+ return this.state;
317
539
  }
318
540
  /**
319
- * Execute a task with an AI agent
541
+ * Check if connected
320
542
  */
321
- async executeTask(agentId, options) {
322
- return this.request("POST", `/agents/${agentId}/execute`, options);
543
+ get isConnected() {
544
+ return this.state === "connected";
323
545
  }
324
- // ===========================================================================
325
- // Fact Extraction
326
- // ===========================================================================
327
546
  /**
328
- * Extract facts from content using intelligent extraction
547
+ * Connect to the WebSocket server
329
548
  */
330
- async extractFacts(content, sourceContext) {
331
- const response = await this.request("POST", "/memory/extract", {
332
- content,
333
- sourceContext
549
+ async connect() {
550
+ if (this.state === "connected" || this.state === "connecting") {
551
+ return;
552
+ }
553
+ this.state = "connecting";
554
+ this.emitStatusEvent("connecting");
555
+ return new Promise((resolve, reject) => {
556
+ try {
557
+ const url = new URL(this.wsUrl);
558
+ url.searchParams.set("token", this.apiKey);
559
+ this.ws = new WebSocket(url.toString());
560
+ this.ws.onopen = () => {
561
+ this.state = "connected";
562
+ this.reconnectCount = 0;
563
+ this.emitStatusEvent("connected");
564
+ this.startHeartbeat();
565
+ this.flushMessageQueue();
566
+ this.resubscribe();
567
+ resolve();
568
+ };
569
+ this.ws.onclose = (event) => {
570
+ this.handleClose(event);
571
+ };
572
+ this.ws.onerror = (error) => {
573
+ if (this.state === "connecting") {
574
+ reject(new Error("WebSocket connection failed"));
575
+ }
576
+ this.handleError(error);
577
+ };
578
+ this.ws.onmessage = (event) => {
579
+ this.handleMessage(event);
580
+ };
581
+ } catch (error) {
582
+ this.state = "disconnected";
583
+ reject(error);
584
+ }
334
585
  });
335
- return response.facts ?? [];
336
586
  }
337
- // ===========================================================================
338
- // Authentication Operations
339
- // ===========================================================================
340
587
  /**
341
- * Register a new user account
588
+ * Disconnect from the WebSocket server
342
589
  */
343
- async register(email, password, name) {
344
- const response = await this.request(
345
- "POST",
346
- "/auth/register",
347
- { email, password, name },
348
- false
349
- );
350
- this.accessToken = response.accessToken;
351
- return response;
590
+ disconnect() {
591
+ this.stopHeartbeat();
592
+ this.clearReconnectTimer();
593
+ if (this.ws) {
594
+ this.ws.onclose = null;
595
+ this.ws.close(1e3, "Client disconnect");
596
+ this.ws = null;
597
+ }
598
+ this.state = "disconnected";
599
+ this.emitStatusEvent("disconnected", "Client initiated disconnect");
352
600
  }
353
601
  /**
354
- * Login with email and password
602
+ * Subscribe to events with optional filter
355
603
  */
356
- async login(email, password) {
357
- const response = await this.request(
358
- "POST",
359
- "/auth/login",
360
- { email, password },
361
- false
362
- );
363
- this.accessToken = response.accessToken;
364
- return response;
604
+ subscribe(filter) {
605
+ if (filter) {
606
+ this.subscriptions.push(filter);
607
+ }
608
+ if (this.isConnected) {
609
+ this.sendSubscription(filter);
610
+ }
365
611
  }
366
612
  /**
367
- * Refresh the current access token
613
+ * Unsubscribe from events
368
614
  */
369
- async refreshToken() {
370
- const response = await this.request("POST", "/auth/refresh");
371
- this.accessToken = response.accessToken;
372
- return response;
615
+ unsubscribe(filter) {
616
+ if (filter) {
617
+ this.subscriptions = this.subscriptions.filter(
618
+ (s) => s.userId !== filter.userId || s.sessionId !== filter.sessionId || JSON.stringify(s.tags) !== JSON.stringify(filter.tags)
619
+ );
620
+ } else {
621
+ this.subscriptions = [];
622
+ }
623
+ if (this.isConnected) {
624
+ this.send({
625
+ type: "unsubscribe",
626
+ filter
627
+ });
628
+ }
373
629
  }
374
630
  /**
375
- * Get the currently authenticated user
631
+ * Add event listener for specific event type
376
632
  */
377
- async getCurrentUser() {
378
- return this.request("GET", "/auth/me");
633
+ on(eventType, listener) {
634
+ if (!this.listeners.has(eventType)) {
635
+ this.listeners.set(eventType, /* @__PURE__ */ new Set());
636
+ }
637
+ this.listeners.get(eventType).add(listener);
638
+ return () => {
639
+ this.listeners.get(eventType)?.delete(listener);
640
+ };
379
641
  }
380
642
  /**
381
- * Logout and invalidate current session
643
+ * Add listener for all events
382
644
  */
383
- async logout() {
384
- await this.request("POST", "/auth/logout");
385
- this.accessToken = void 0;
386
- return true;
645
+ onAny(listener) {
646
+ this.allListeners.add(listener);
647
+ return () => {
648
+ this.allListeners.delete(listener);
649
+ };
387
650
  }
388
651
  /**
389
- * Create a new API key for programmatic access
652
+ * Remove event listener
390
653
  */
391
- async createApiKey(options) {
392
- const response = await this.request("POST", "/auth/api-keys", options);
393
- return {
394
- keyId: response.keyId ?? response.id ?? "",
395
- name: response.name,
396
- key: response.apiKey ?? response.key,
397
- permissions: response.permissions ?? [],
398
- expiresAt: response.expiresAt,
399
- isActive: true
400
- };
654
+ off(eventType, listener) {
655
+ this.listeners.get(eventType)?.delete(listener);
401
656
  }
402
657
  /**
403
- * List all API keys for the current user
658
+ * Remove all listeners for an event type
404
659
  */
405
- async listApiKeys() {
406
- const response = await this.request("GET", "/auth/api-keys");
407
- return Array.isArray(response) ? response : response.keys ?? [];
660
+ offAll(eventType) {
661
+ if (eventType) {
662
+ this.listeners.delete(eventType);
663
+ } else {
664
+ this.listeners.clear();
665
+ this.allListeners.clear();
666
+ }
408
667
  }
409
668
  /**
410
- * Revoke an API key
669
+ * Listen for memory created events
411
670
  */
412
- async revokeApiKey(keyId) {
413
- await this.request("DELETE", `/auth/api-keys/${keyId}`);
414
- return true;
671
+ onMemoryCreated(listener) {
672
+ return this.on("memory.created", listener);
415
673
  }
416
674
  /**
417
- * List all active sessions for the current user
675
+ * Listen for memory updated events
418
676
  */
419
- async listSessions() {
420
- const response = await this.request(
421
- "GET",
422
- "/auth/sessions"
423
- );
424
- return Array.isArray(response) ? response : response.sessions ?? [];
677
+ onMemoryUpdated(listener) {
678
+ return this.on("memory.updated", listener);
679
+ }
680
+ /**
681
+ * Listen for memory deleted events
682
+ */
683
+ onMemoryDeleted(listener) {
684
+ return this.on("memory.deleted", listener);
685
+ }
686
+ /**
687
+ * Listen for memory tier changed events
688
+ */
689
+ onMemoryTierChanged(listener) {
690
+ return this.on("memory.tier_changed", listener);
425
691
  }
426
692
  /**
427
- * Revoke a specific session
693
+ * Listen for graph node created events
428
694
  */
429
- async revokeSession(sessionId) {
430
- await this.request("DELETE", `/auth/sessions/${sessionId}`);
431
- return true;
695
+ onGraphNodeCreated(listener) {
696
+ return this.on("graph.node_created", listener);
432
697
  }
433
698
  /**
434
- * Revoke all sessions except the current one
699
+ * Listen for graph edge created events
435
700
  */
436
- async revokeAllSessions() {
437
- await this.request("DELETE", "/auth/sessions");
438
- return true;
701
+ onGraphEdgeCreated(listener) {
702
+ return this.on("graph.edge_created", listener);
703
+ }
704
+ /**
705
+ * Listen for connection status changes
706
+ */
707
+ onConnectionStatus(listener) {
708
+ return this.on("connection.status", listener);
709
+ }
710
+ /**
711
+ * Wait for specific event (one-time)
712
+ */
713
+ once(eventType, timeout) {
714
+ return new Promise((resolve, reject) => {
715
+ const timeoutId = timeout ? setTimeout(() => {
716
+ unsubscribe();
717
+ reject(new Error(`Timeout waiting for event: ${eventType}`));
718
+ }, timeout) : null;
719
+ const unsubscribe = this.on(eventType, (event) => {
720
+ if (timeoutId) clearTimeout(timeoutId);
721
+ unsubscribe();
722
+ resolve(event);
723
+ });
724
+ });
725
+ }
726
+ // ===========================================================================
727
+ // Private Methods
728
+ // ===========================================================================
729
+ send(message) {
730
+ const data = JSON.stringify(message);
731
+ if (this.isConnected && this.ws) {
732
+ this.ws.send(data);
733
+ } else {
734
+ if (this.messageQueue.length >= this.messageQueueSize) {
735
+ this.messageQueue.shift();
736
+ }
737
+ this.messageQueue.push(data);
738
+ }
739
+ }
740
+ sendSubscription(filter) {
741
+ this.send({
742
+ type: "subscribe",
743
+ filter: filter ?? {}
744
+ });
745
+ }
746
+ resubscribe() {
747
+ for (const filter of this.subscriptions) {
748
+ this.sendSubscription(filter);
749
+ }
750
+ }
751
+ flushMessageQueue() {
752
+ while (this.messageQueue.length > 0 && this.isConnected && this.ws) {
753
+ const message = this.messageQueue.shift();
754
+ if (message) {
755
+ this.ws.send(message);
756
+ }
757
+ }
758
+ }
759
+ handleMessage(event) {
760
+ try {
761
+ const data = JSON.parse(event.data);
762
+ this.emit(data);
763
+ } catch (error) {
764
+ console.error("Failed to parse WebSocket message:", error);
765
+ }
766
+ }
767
+ handleClose(event) {
768
+ this.stopHeartbeat();
769
+ if (event.code === 1e3) {
770
+ this.state = "disconnected";
771
+ this.emitStatusEvent("disconnected", "Connection closed normally");
772
+ return;
773
+ }
774
+ if (this.reconnectCount < this.reconnectAttempts) {
775
+ this.state = "reconnecting";
776
+ this.emitStatusEvent("reconnecting", `Reconnecting (attempt ${this.reconnectCount + 1}/${this.reconnectAttempts})`);
777
+ this.scheduleReconnect();
778
+ } else {
779
+ this.state = "disconnected";
780
+ this.emitStatusEvent("disconnected", "Max reconnection attempts reached");
781
+ }
782
+ }
783
+ handleError(_error) {
784
+ console.error("WebSocket error occurred");
785
+ }
786
+ scheduleReconnect() {
787
+ this.clearReconnectTimer();
788
+ const delay = this.reconnectDelay * Math.pow(2, this.reconnectCount);
789
+ this.reconnectCount++;
790
+ this.reconnectTimer = setTimeout(async () => {
791
+ try {
792
+ await this.connect();
793
+ } catch {
794
+ }
795
+ }, delay);
796
+ }
797
+ clearReconnectTimer() {
798
+ if (this.reconnectTimer) {
799
+ clearTimeout(this.reconnectTimer);
800
+ this.reconnectTimer = null;
801
+ }
802
+ }
803
+ startHeartbeat() {
804
+ this.stopHeartbeat();
805
+ this.heartbeatTimer = setInterval(() => {
806
+ if (this.isConnected) {
807
+ this.send({ type: "ping" });
808
+ }
809
+ }, this.heartbeatInterval);
810
+ }
811
+ stopHeartbeat() {
812
+ if (this.heartbeatTimer) {
813
+ clearInterval(this.heartbeatTimer);
814
+ this.heartbeatTimer = null;
815
+ }
816
+ }
817
+ emit(event) {
818
+ const typeListeners = this.listeners.get(event.type);
819
+ if (typeListeners) {
820
+ for (const listener of typeListeners) {
821
+ try {
822
+ listener(event);
823
+ } catch (error) {
824
+ console.error("Error in event listener:", error);
825
+ }
826
+ }
827
+ }
828
+ for (const listener of this.allListeners) {
829
+ try {
830
+ listener(event);
831
+ } catch (error) {
832
+ console.error("Error in event listener:", error);
833
+ }
834
+ }
835
+ }
836
+ emitStatusEvent(status, reason) {
837
+ const event = {
838
+ type: "connection.status",
839
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
840
+ status: status === "connecting" ? "reconnecting" : status,
841
+ reason
842
+ };
843
+ this.emit(event);
439
844
  }
440
845
  };
441
- export {
442
- AuthenticationError,
443
- CilowClient,
444
- CilowError,
445
- ConnectionError,
446
- NotFoundError,
447
- RateLimitError,
448
- ValidationError
846
+ function createWebSocket(config) {
847
+ return new CilowWebSocket(config);
848
+ }
849
+
850
+ // src/index.ts
851
+ var Cilow = class extends CilowClient {
852
+ constructor(config) {
853
+ super(config);
854
+ }
449
855
  };
856
+ function createCilow(config) {
857
+ return new Cilow(config);
858
+ }
859
+ var src_default = Cilow;
860
+
861
+ export { Cilow, CilowApiError, CilowClient, CilowWebSocket, createCilow, createClient, createWebSocket, src_default as default, isApiError, isGraphEvent, isMemoryEvent };
862
+ //# sourceMappingURL=index.mjs.map
863
+ //# sourceMappingURL=index.mjs.map