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