@sovant/sdk 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +71 -421
- package/dist/index.d.ts +102 -427
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +215 -843
- package/dist/index.js.map +1 -0
- package/package.json +22 -43
- package/CHANGELOG.md +0 -118
- package/dist/index.d.mts +0 -433
- package/dist/index.mjs +0 -821
package/dist/index.js
CHANGED
|
@@ -1,851 +1,223 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// src/errors.ts
|
|
32
|
-
var SovantError = class _SovantError extends Error {
|
|
33
|
-
constructor(message, code, status, requestId) {
|
|
34
|
-
super(message);
|
|
35
|
-
this.name = "SovantError";
|
|
36
|
-
this.code = code;
|
|
37
|
-
this.status = status;
|
|
38
|
-
this.requestId = requestId;
|
|
39
|
-
if (Error.captureStackTrace) {
|
|
40
|
-
Error.captureStackTrace(this, _SovantError);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
static fromResponse(status, body, requestId) {
|
|
44
|
-
const statusCodeMap = {
|
|
45
|
-
400: "bad_request",
|
|
46
|
-
401: "unauthorized",
|
|
47
|
-
403: "forbidden",
|
|
48
|
-
404: "not_found",
|
|
49
|
-
409: "conflict",
|
|
50
|
-
422: "validation_error",
|
|
51
|
-
429: "rate_limited",
|
|
52
|
-
500: "internal_error",
|
|
53
|
-
502: "bad_gateway",
|
|
54
|
-
503: "service_unavailable",
|
|
55
|
-
504: "gateway_timeout"
|
|
56
|
-
};
|
|
57
|
-
let message = "An error occurred";
|
|
58
|
-
let code = statusCodeMap[status] || "unknown_error";
|
|
59
|
-
if (body?.error) {
|
|
60
|
-
if (typeof body.error === "string") {
|
|
61
|
-
message = body.error;
|
|
62
|
-
} else if (body.error.message) {
|
|
63
|
-
message = body.error.message;
|
|
64
|
-
code = body.error.code || code;
|
|
65
|
-
}
|
|
66
|
-
} else if (body?.message) {
|
|
67
|
-
message = body.message;
|
|
68
|
-
} else if (typeof body === "string") {
|
|
69
|
-
message = body;
|
|
70
|
-
}
|
|
71
|
-
return new _SovantError(message, code, status, requestId);
|
|
72
|
-
}
|
|
73
|
-
toJSON() {
|
|
74
|
-
return {
|
|
75
|
-
name: this.name,
|
|
76
|
-
message: this.message,
|
|
77
|
-
code: this.code,
|
|
78
|
-
status: this.status,
|
|
79
|
-
requestId: this.requestId
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
var NetworkError = class _NetworkError extends SovantError {
|
|
84
|
-
constructor(message, cause) {
|
|
85
|
-
super(message, "network_error");
|
|
86
|
-
this.name = "NetworkError";
|
|
87
|
-
if (Error.captureStackTrace) {
|
|
88
|
-
Error.captureStackTrace(this, _NetworkError);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
var TimeoutError = class _TimeoutError extends SovantError {
|
|
93
|
-
constructor(message = "Request timed out") {
|
|
94
|
-
super(message, "timeout");
|
|
95
|
-
this.name = "TimeoutError";
|
|
96
|
-
if (Error.captureStackTrace) {
|
|
97
|
-
Error.captureStackTrace(this, _TimeoutError);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
// src/http.ts
|
|
103
|
-
var RETRY_STATUS_CODES = [429, 502, 503, 504];
|
|
104
|
-
var DEFAULT_TIMEOUT = 3e4;
|
|
105
|
-
var DEFAULT_MAX_RETRIES = 3;
|
|
106
|
-
var IDEMPOTENT_METHODS = ["GET", "DELETE"];
|
|
107
|
-
var HttpClient = class {
|
|
108
|
-
constructor(baseUrl, apiKey, globalOptions = {}) {
|
|
109
|
-
this.baseUrl = baseUrl;
|
|
110
|
-
this.apiKey = apiKey;
|
|
111
|
-
this.globalOptions = globalOptions;
|
|
112
|
-
}
|
|
113
|
-
async request(path, options = {}) {
|
|
114
|
-
const url = `${this.baseUrl}${path}`;
|
|
115
|
-
const timeout = options.timeout ?? this.globalOptions.timeout ?? DEFAULT_TIMEOUT;
|
|
116
|
-
const maxRetries = options.maxRetries ?? this.globalOptions.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
117
|
-
const debug = options.debug ?? this.globalOptions.debug ?? false;
|
|
118
|
-
const method = options.method || "GET";
|
|
119
|
-
const shouldRetry = IDEMPOTENT_METHODS.includes(method) || method === "GET";
|
|
120
|
-
let lastError;
|
|
121
|
-
let attempt = 0;
|
|
122
|
-
while (attempt <= maxRetries) {
|
|
123
|
-
try {
|
|
124
|
-
if (debug && attempt > 0) {
|
|
125
|
-
console.log(`[Sovant SDK] Retry attempt ${attempt} for ${method} ${url}`);
|
|
126
|
-
}
|
|
127
|
-
const response = await this.makeRequest(url, options, timeout, debug);
|
|
128
|
-
if (shouldRetry && RETRY_STATUS_CODES.includes(response.status) && attempt < maxRetries) {
|
|
129
|
-
const delay = this.calculateRetryDelay(attempt, response.headers["retry-after"]);
|
|
130
|
-
if (debug) {
|
|
131
|
-
console.log(`[Sovant SDK] Got ${response.status}, retrying after ${delay}ms...`);
|
|
132
|
-
}
|
|
133
|
-
await this.sleep(delay);
|
|
134
|
-
attempt++;
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
if (response.status >= 400) {
|
|
138
|
-
throw SovantError.fromResponse(response.status, response.data, response.requestId);
|
|
139
|
-
}
|
|
140
|
-
return response;
|
|
141
|
-
} catch (error) {
|
|
142
|
-
lastError = error;
|
|
143
|
-
if (error instanceof SovantError) {
|
|
144
|
-
if (error.status && error.status < 500) {
|
|
145
|
-
throw error;
|
|
146
|
-
}
|
|
147
|
-
if (!shouldRetry || attempt >= maxRetries) {
|
|
148
|
-
throw error;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (error instanceof TimeoutError || error instanceof NetworkError) {
|
|
152
|
-
if (shouldRetry && attempt < maxRetries) {
|
|
153
|
-
const delay = this.calculateRetryDelay(attempt);
|
|
154
|
-
if (debug) {
|
|
155
|
-
console.log(`[Sovant SDK] Network/Timeout error, retrying after ${delay}ms...`);
|
|
1
|
+
export class Sovant {
|
|
2
|
+
apiKey;
|
|
3
|
+
baseUrl;
|
|
4
|
+
timeout;
|
|
5
|
+
maxRetries;
|
|
6
|
+
retryDelay;
|
|
7
|
+
onRequest;
|
|
8
|
+
onResponse;
|
|
9
|
+
onError;
|
|
10
|
+
constructor(opts) {
|
|
11
|
+
if (!opts?.apiKey)
|
|
12
|
+
throw new Error("Missing apiKey");
|
|
13
|
+
this.apiKey = opts.apiKey;
|
|
14
|
+
this.baseUrl = (opts.baseUrl ?? process.env.SOVANT_BASE_URL ?? "https://sovant.ai").replace(/\/+$/, "");
|
|
15
|
+
this.timeout = opts.timeoutMs ?? 30000;
|
|
16
|
+
this.maxRetries = opts.maxRetries ?? 3;
|
|
17
|
+
this.retryDelay = opts.retryDelay ?? 1000;
|
|
18
|
+
this.onRequest = opts.onRequest;
|
|
19
|
+
this.onResponse = opts.onResponse;
|
|
20
|
+
this.onError = opts.onError;
|
|
21
|
+
}
|
|
22
|
+
async req(path, init) {
|
|
23
|
+
const method = init.method || 'GET';
|
|
24
|
+
const startTime = Date.now();
|
|
25
|
+
// Telemetry: onRequest hook
|
|
26
|
+
if (this.onRequest) {
|
|
27
|
+
try {
|
|
28
|
+
const body = init.body ? JSON.parse(init.body) : undefined;
|
|
29
|
+
this.onRequest({ method, path, body });
|
|
156
30
|
}
|
|
157
|
-
|
|
158
|
-
attempt++;
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
31
|
+
catch { }
|
|
161
32
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
async makeRequest(url, options, timeout, debug) {
|
|
168
|
-
const controller = new AbortController();
|
|
169
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
170
|
-
const headers = {
|
|
171
|
-
"x-sovant-api-key": this.apiKey,
|
|
172
|
-
"Content-Type": "application/json",
|
|
173
|
-
...options.headers
|
|
174
|
-
};
|
|
175
|
-
const fetchOptions = {
|
|
176
|
-
method: options.method || "GET",
|
|
177
|
-
headers,
|
|
178
|
-
signal: controller.signal
|
|
179
|
-
};
|
|
180
|
-
if (options.body !== void 0 && options.method !== "GET" && options.method !== "HEAD") {
|
|
181
|
-
fetchOptions.body = typeof options.body === "string" ? options.body : JSON.stringify(options.body);
|
|
182
|
-
}
|
|
183
|
-
if (debug) {
|
|
184
|
-
console.log(`[Sovant SDK] ${fetchOptions.method} ${url}`);
|
|
185
|
-
if (options.body) {
|
|
186
|
-
console.log("[Sovant SDK] Body:", options.body);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
try {
|
|
190
|
-
const response = await fetch(url, fetchOptions);
|
|
191
|
-
clearTimeout(timeoutId);
|
|
192
|
-
const responseHeaders = {};
|
|
193
|
-
response.headers.forEach((value, key) => {
|
|
194
|
-
responseHeaders[key.toLowerCase()] = value;
|
|
195
|
-
});
|
|
196
|
-
const requestId = responseHeaders["x-request-id"];
|
|
197
|
-
let data;
|
|
198
|
-
const contentType = responseHeaders["content-type"] || "";
|
|
199
|
-
if (response.status === 204) {
|
|
200
|
-
data = { ok: true };
|
|
201
|
-
} else if (contentType.includes("application/json")) {
|
|
202
|
-
const text = await response.text();
|
|
203
|
-
try {
|
|
204
|
-
data = text ? JSON.parse(text) : {};
|
|
205
|
-
} catch (e) {
|
|
206
|
-
data = { message: text };
|
|
207
|
-
}
|
|
208
|
-
} else {
|
|
209
|
-
data = await response.text();
|
|
210
|
-
}
|
|
211
|
-
if (debug) {
|
|
212
|
-
console.log(`[Sovant SDK] Response ${response.status}:`, data);
|
|
213
|
-
if (requestId) {
|
|
214
|
-
console.log(`[Sovant SDK] Request ID: ${requestId}`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return {
|
|
218
|
-
data,
|
|
219
|
-
status: response.status,
|
|
220
|
-
headers: responseHeaders,
|
|
221
|
-
requestId
|
|
222
|
-
};
|
|
223
|
-
} catch (error) {
|
|
224
|
-
clearTimeout(timeoutId);
|
|
225
|
-
if (error instanceof Error) {
|
|
226
|
-
if (error.name === "AbortError") {
|
|
227
|
-
throw new TimeoutError(`Request timed out after ${timeout}ms`);
|
|
228
|
-
}
|
|
229
|
-
throw new NetworkError(`Network request failed: ${error.message}`, error);
|
|
230
|
-
}
|
|
231
|
-
throw error;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
calculateRetryDelay(attempt, retryAfter) {
|
|
235
|
-
if (retryAfter) {
|
|
236
|
-
const retryAfterNum = parseInt(retryAfter, 10);
|
|
237
|
-
if (!isNaN(retryAfterNum)) {
|
|
238
|
-
return retryAfterNum * 1e3;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
const baseDelay = Math.min(1e3 * Math.pow(2, attempt), 1e4);
|
|
242
|
-
const jitter = Math.random() * baseDelay * 0.1;
|
|
243
|
-
return Math.floor(baseDelay + jitter);
|
|
244
|
-
}
|
|
245
|
-
sleep(ms) {
|
|
246
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
// src/sse-parser.ts
|
|
251
|
-
var SseParser = class {
|
|
252
|
-
constructor(onEvent) {
|
|
253
|
-
this.buffer = "";
|
|
254
|
-
this.onEvent = onEvent;
|
|
255
|
-
}
|
|
256
|
-
feed(chunk) {
|
|
257
|
-
if (!chunk) return;
|
|
258
|
-
this.buffer += chunk;
|
|
259
|
-
this.process();
|
|
260
|
-
}
|
|
261
|
-
process() {
|
|
262
|
-
let boundaryIndex = this.findBoundary(this.buffer);
|
|
263
|
-
while (boundaryIndex !== -1) {
|
|
264
|
-
const raw = this.buffer.slice(0, boundaryIndex);
|
|
265
|
-
this.buffer = this.buffer.slice(boundaryIndex + this.boundaryLength(this.buffer, boundaryIndex));
|
|
266
|
-
const lines = raw.split(/\r?\n/);
|
|
267
|
-
let eventName = "";
|
|
268
|
-
let dataLines = [];
|
|
269
|
-
let id;
|
|
270
|
-
for (const line of lines) {
|
|
271
|
-
if (!line) continue;
|
|
272
|
-
if (line.startsWith(":")) continue;
|
|
273
|
-
const idx = line.indexOf(":");
|
|
274
|
-
const field = idx === -1 ? line : line.slice(0, idx);
|
|
275
|
-
const value = idx === -1 ? "" : line.slice(idx + 1).replace(/^ /, "");
|
|
276
|
-
switch (field) {
|
|
277
|
-
case "event":
|
|
278
|
-
eventName = value;
|
|
279
|
-
break;
|
|
280
|
-
case "data":
|
|
281
|
-
dataLines.push(value);
|
|
282
|
-
break;
|
|
283
|
-
case "id":
|
|
284
|
-
id = value;
|
|
285
|
-
break;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
const data = dataLines.join("\n");
|
|
289
|
-
const ev = { type: "event", event: eventName || "message", data, id };
|
|
290
|
-
this.onEvent(ev);
|
|
291
|
-
if (ev.event === "message" || ev.event === "delta" || ev.event === "") {
|
|
292
|
-
this.onEvent({ type: "delta", data: data ?? "" });
|
|
293
|
-
}
|
|
294
|
-
boundaryIndex = this.findBoundary(this.buffer);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
findBoundary(buf) {
|
|
298
|
-
const n = buf.indexOf("\n\n");
|
|
299
|
-
const r = buf.indexOf("\r\n\r\n");
|
|
300
|
-
if (n === -1) return r;
|
|
301
|
-
if (r === -1) return n;
|
|
302
|
-
return Math.min(n, r);
|
|
303
|
-
}
|
|
304
|
-
boundaryLength(buf, start) {
|
|
305
|
-
if (buf.slice(start, start + 4) === "\r\n\r\n") return 4;
|
|
306
|
-
return 2;
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
// src/index.ts
|
|
311
|
-
var Sovant = class {
|
|
312
|
-
constructor(config) {
|
|
313
|
-
if (!config.apiKey) {
|
|
314
|
-
throw new Error("API key is required");
|
|
315
|
-
}
|
|
316
|
-
const baseUrl = (config.baseUrl || "https://sovant.ai").replace(/\/$/, "");
|
|
317
|
-
this.http = new HttpClient(baseUrl, config.apiKey, {
|
|
318
|
-
timeout: config.timeout || 3e4,
|
|
319
|
-
maxRetries: config.maxRetries || 3,
|
|
320
|
-
debug: config.debug || false
|
|
321
|
-
});
|
|
322
|
-
this.memory = new MemoryNamespace(this.http);
|
|
323
|
-
this.threads = new ThreadsNamespace(this.http);
|
|
324
|
-
this.chat = new ChatNamespace(this.http);
|
|
325
|
-
this.keys = new KeysNamespace(this.http);
|
|
326
|
-
this.recall = new RecallNamespace(this.http);
|
|
327
|
-
}
|
|
328
|
-
};
|
|
329
|
-
var MemoryNamespace = class {
|
|
330
|
-
constructor(http) {
|
|
331
|
-
this.http = http;
|
|
332
|
-
}
|
|
333
|
-
/**
|
|
334
|
-
* Create a new memory
|
|
335
|
-
*/
|
|
336
|
-
async create(input) {
|
|
337
|
-
const response = await this.http.request("/api/v1/memory", {
|
|
338
|
-
method: "POST",
|
|
339
|
-
body: input
|
|
340
|
-
});
|
|
341
|
-
const { ok, ...memory } = response.data;
|
|
342
|
-
return memory;
|
|
343
|
-
}
|
|
344
|
-
/**
|
|
345
|
-
* List memories with optional filters
|
|
346
|
-
*/
|
|
347
|
-
async list(params) {
|
|
348
|
-
const queryParams = new URLSearchParams();
|
|
349
|
-
if (params?.limit !== void 0) queryParams.append("limit", params.limit.toString());
|
|
350
|
-
if (params?.offset !== void 0) queryParams.append("offset", params.offset.toString());
|
|
351
|
-
if (params?.type) queryParams.append("type", params.type);
|
|
352
|
-
if (params?.thread_id) queryParams.append("thread_id", params.thread_id);
|
|
353
|
-
if (params?.is_archived !== void 0) queryParams.append("is_archived", params.is_archived.toString());
|
|
354
|
-
if (params?.tags && params.tags.length > 0) {
|
|
355
|
-
params.tags.forEach((tag) => queryParams.append("tags", tag));
|
|
356
|
-
}
|
|
357
|
-
const query = queryParams.toString();
|
|
358
|
-
const path = query ? `/api/v1/memory?${query}` : "/api/v1/memory";
|
|
359
|
-
const response = await this.http.request(path, {
|
|
360
|
-
method: "GET"
|
|
361
|
-
});
|
|
362
|
-
return response.data;
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Get a specific memory by ID
|
|
366
|
-
*/
|
|
367
|
-
async get(id) {
|
|
368
|
-
if (!id) throw new Error("Memory ID is required");
|
|
369
|
-
const response = await this.http.request(`/api/v1/memories/${id}`, {
|
|
370
|
-
method: "GET"
|
|
371
|
-
});
|
|
372
|
-
return response.data;
|
|
373
|
-
}
|
|
374
|
-
/**
|
|
375
|
-
* Update a memory (partial update using PATCH)
|
|
376
|
-
*/
|
|
377
|
-
async update(id, patch) {
|
|
378
|
-
if (!id) throw new Error("Memory ID is required");
|
|
379
|
-
const response = await this.http.request(`/api/v1/memories/${id}`, {
|
|
380
|
-
method: "PATCH",
|
|
381
|
-
body: patch
|
|
382
|
-
});
|
|
383
|
-
return response.data;
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* Replace a memory (full update using PUT)
|
|
387
|
-
*/
|
|
388
|
-
async put(id, body) {
|
|
389
|
-
if (!id) throw new Error("Memory ID is required");
|
|
390
|
-
if (!body.content) throw new Error("Content is required for PUT operation");
|
|
391
|
-
if (!body.type) throw new Error("Type is required for PUT operation");
|
|
392
|
-
const response = await this.http.request(`/api/v1/memories/${id}`, {
|
|
393
|
-
method: "PUT",
|
|
394
|
-
body
|
|
395
|
-
});
|
|
396
|
-
return response.data;
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Delete a memory
|
|
400
|
-
*/
|
|
401
|
-
async delete(id) {
|
|
402
|
-
if (!id) throw new Error("Memory ID is required");
|
|
403
|
-
const response = await this.http.request(`/api/v1/memories/${id}`, {
|
|
404
|
-
method: "DELETE"
|
|
405
|
-
});
|
|
406
|
-
return response.data;
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* Search memories using semantic search or filters
|
|
410
|
-
*/
|
|
411
|
-
async search(params) {
|
|
412
|
-
const queryParams = new URLSearchParams();
|
|
413
|
-
if (params.query) queryParams.append("query", params.query);
|
|
414
|
-
if (params.type) queryParams.append("type", params.type);
|
|
415
|
-
if (params.limit !== void 0) queryParams.append("limit", params.limit.toString());
|
|
416
|
-
if (params.thread_id) queryParams.append("thread_id", params.thread_id);
|
|
417
|
-
if (params.from_date) queryParams.append("from_date", params.from_date);
|
|
418
|
-
if (params.to_date) queryParams.append("to_date", params.to_date);
|
|
419
|
-
if (params.tags && params.tags.length > 0) {
|
|
420
|
-
params.tags.forEach((tag) => queryParams.append("tags", tag));
|
|
421
|
-
}
|
|
422
|
-
const query = queryParams.toString();
|
|
423
|
-
const path = `/api/v1/memory/search${query ? `?${query}` : ""}`;
|
|
424
|
-
const response = await this.http.request(path, {
|
|
425
|
-
method: "GET"
|
|
426
|
-
});
|
|
427
|
-
return response.data;
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Execute batch operations atomically
|
|
431
|
-
*/
|
|
432
|
-
async batch(body) {
|
|
433
|
-
if (!body.operations || body.operations.length === 0) {
|
|
434
|
-
throw new Error("At least one operation is required");
|
|
435
|
-
}
|
|
436
|
-
const apiBody = {
|
|
437
|
-
operations: body.operations.map((op) => ({
|
|
438
|
-
...op,
|
|
439
|
-
operation: op.op,
|
|
440
|
-
op: void 0
|
|
441
|
-
}))
|
|
442
|
-
};
|
|
443
|
-
const response = await this.http.request("/api/v1/memory/batch", {
|
|
444
|
-
method: "POST",
|
|
445
|
-
body: apiBody
|
|
446
|
-
});
|
|
447
|
-
return response.data;
|
|
448
|
-
}
|
|
449
|
-
};
|
|
450
|
-
var ThreadsNamespace = class {
|
|
451
|
-
constructor(http) {
|
|
452
|
-
this.http = http;
|
|
453
|
-
}
|
|
454
|
-
/**
|
|
455
|
-
* Create a new thread
|
|
456
|
-
*/
|
|
457
|
-
async create(input) {
|
|
458
|
-
const response = await this.http.request("/api/v1/threads", {
|
|
459
|
-
method: "POST",
|
|
460
|
-
body: input || {}
|
|
461
|
-
});
|
|
462
|
-
if (response.data.thread) {
|
|
463
|
-
return response.data.thread;
|
|
464
|
-
} else if (response.data.ok !== void 0) {
|
|
465
|
-
const { ok, ...thread } = response.data;
|
|
466
|
-
return thread;
|
|
467
|
-
} else {
|
|
468
|
-
return response.data;
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
/**
|
|
472
|
-
* List threads with pagination
|
|
473
|
-
*/
|
|
474
|
-
async list(params) {
|
|
475
|
-
const queryParams = new URLSearchParams();
|
|
476
|
-
if (params?.limit) queryParams.append("limit", params.limit.toString());
|
|
477
|
-
if (params?.offset) queryParams.append("offset", params.offset.toString());
|
|
478
|
-
const path = queryParams.toString() ? `/api/v1/threads?${queryParams.toString()}` : "/api/v1/threads";
|
|
479
|
-
const response = await this.http.request(path, {
|
|
480
|
-
method: "GET"
|
|
481
|
-
});
|
|
482
|
-
return response.data;
|
|
483
|
-
}
|
|
484
|
-
/**
|
|
485
|
-
* Get a thread by ID, optionally with memories
|
|
486
|
-
*/
|
|
487
|
-
async get(id, options) {
|
|
488
|
-
const queryParams = new URLSearchParams();
|
|
489
|
-
if (options?.includeMemories) queryParams.append("include", "memories");
|
|
490
|
-
if (options?.limit) queryParams.append("limit", options.limit.toString());
|
|
491
|
-
if (options?.offset) queryParams.append("offset", options.offset.toString());
|
|
492
|
-
const path = queryParams.toString() ? `/api/v1/threads/${id}?${queryParams.toString()}` : `/api/v1/threads/${id}`;
|
|
493
|
-
const response = await this.http.request(path, {
|
|
494
|
-
method: "GET"
|
|
495
|
-
});
|
|
496
|
-
return response.data;
|
|
497
|
-
}
|
|
498
|
-
/**
|
|
499
|
-
* Update a thread
|
|
500
|
-
*/
|
|
501
|
-
async update(id, input) {
|
|
502
|
-
const response = await this.http.request(`/api/v1/threads/${id}`, {
|
|
503
|
-
method: "PATCH",
|
|
504
|
-
body: input
|
|
505
|
-
});
|
|
506
|
-
const { ok, ...thread } = response.data;
|
|
507
|
-
return thread;
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Delete a thread (memories are unlinked, not deleted)
|
|
511
|
-
*/
|
|
512
|
-
async delete(id) {
|
|
513
|
-
const response = await this.http.request(
|
|
514
|
-
`/api/v1/threads/${id}`,
|
|
515
|
-
{
|
|
516
|
-
method: "DELETE"
|
|
517
|
-
}
|
|
518
|
-
);
|
|
519
|
-
return response.data;
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Link a memory to a thread
|
|
523
|
-
*/
|
|
524
|
-
async linkMemory(threadId, memoryId) {
|
|
525
|
-
const response = await this.http.request(
|
|
526
|
-
`/api/v1/threads/${threadId}/link`,
|
|
527
|
-
{
|
|
528
|
-
method: "POST",
|
|
529
|
-
body: { memory_id: memoryId }
|
|
530
|
-
}
|
|
531
|
-
);
|
|
532
|
-
return response.data;
|
|
533
|
-
}
|
|
534
|
-
};
|
|
535
|
-
var ChatNamespace = class {
|
|
536
|
-
constructor(http) {
|
|
537
|
-
this.http = http;
|
|
538
|
-
}
|
|
539
|
-
/**
|
|
540
|
-
* Create a new chat session
|
|
541
|
-
*/
|
|
542
|
-
async createSession(input) {
|
|
543
|
-
const response = await this.http.request("/api/v1/chat/sessions", {
|
|
544
|
-
method: "POST",
|
|
545
|
-
body: input || {}
|
|
546
|
-
});
|
|
547
|
-
return response.data;
|
|
548
|
-
}
|
|
549
|
-
/**
|
|
550
|
-
* Get a chat session by ID
|
|
551
|
-
*/
|
|
552
|
-
async getSession(sessionId) {
|
|
553
|
-
const response = await this.http.request(`/api/v1/chat/sessions/${sessionId}`, {
|
|
554
|
-
method: "GET"
|
|
555
|
-
});
|
|
556
|
-
return response.data;
|
|
557
|
-
}
|
|
558
|
-
/**
|
|
559
|
-
* List chat sessions
|
|
560
|
-
*/
|
|
561
|
-
async listSessions(params) {
|
|
562
|
-
const queryParams = new URLSearchParams();
|
|
563
|
-
if (params?.limit) queryParams.append("limit", params.limit.toString());
|
|
564
|
-
if (params?.offset) queryParams.append("offset", params.offset.toString());
|
|
565
|
-
const path = queryParams.toString() ? `/api/v1/chat/sessions?${queryParams.toString()}` : "/api/v1/chat/sessions";
|
|
566
|
-
const response = await this.http.request(path, {
|
|
567
|
-
method: "GET"
|
|
568
|
-
});
|
|
569
|
-
return response.data.sessions;
|
|
570
|
-
}
|
|
571
|
-
/**
|
|
572
|
-
* Get messages for a session
|
|
573
|
-
*/
|
|
574
|
-
async getMessages(sessionId, limit) {
|
|
575
|
-
const queryParams = new URLSearchParams();
|
|
576
|
-
if (limit) queryParams.append("limit", limit.toString());
|
|
577
|
-
const path = queryParams.toString() ? `/api/v1/chat/sessions/${sessionId}/messages?${queryParams.toString()}` : `/api/v1/chat/sessions/${sessionId}/messages`;
|
|
578
|
-
const response = await this.http.request(path, {
|
|
579
|
-
method: "GET"
|
|
580
|
-
});
|
|
581
|
-
return response.data.messages;
|
|
582
|
-
}
|
|
583
|
-
/**
|
|
584
|
-
* Send a message with SSE streaming
|
|
585
|
-
*/
|
|
586
|
-
async *sendMessage(sessionId, message, opts) {
|
|
587
|
-
const options = typeof message === "string" ? opts : message;
|
|
588
|
-
const messageText = typeof message === "string" ? message : message.message;
|
|
589
|
-
if (!messageText) {
|
|
590
|
-
yield { type: "error", data: "Message is required" };
|
|
591
|
-
return;
|
|
592
|
-
}
|
|
593
|
-
const body = {
|
|
594
|
-
message: messageText,
|
|
595
|
-
provider: options?.provider,
|
|
596
|
-
model: options?.model,
|
|
597
|
-
useMemory: options?.useMemory ?? true,
|
|
598
|
-
stream: options?.stream ?? true
|
|
599
|
-
};
|
|
600
|
-
const response = await fetch(`${this.http.baseUrl}/api/v1/chat/sessions/${sessionId}/messages`, {
|
|
601
|
-
method: "POST",
|
|
602
|
-
headers: {
|
|
603
|
-
"x-sovant-api-key": this.http.apiKey,
|
|
604
|
-
"content-type": "application/json",
|
|
605
|
-
"accept": "text/event-stream"
|
|
606
|
-
},
|
|
607
|
-
body: JSON.stringify(body),
|
|
608
|
-
signal: options?.signal
|
|
609
|
-
});
|
|
610
|
-
if (!response.ok) {
|
|
611
|
-
const error = await response.json().catch(() => ({ message: "Request failed" }));
|
|
612
|
-
yield { type: "error", data: error.message || "Request failed" };
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
const reader = response.body?.getReader();
|
|
616
|
-
if (!reader) {
|
|
617
|
-
yield { type: "error", data: "No response body" };
|
|
618
|
-
return;
|
|
619
|
-
}
|
|
620
|
-
const decoder = new TextDecoder();
|
|
621
|
-
const queue = [];
|
|
622
|
-
const parser = new SseParser((ev) => {
|
|
623
|
-
queue.push(ev);
|
|
624
|
-
});
|
|
625
|
-
try {
|
|
626
|
-
while (true) {
|
|
627
|
-
const { done, value } = await reader.read();
|
|
628
|
-
if (done) break;
|
|
629
|
-
const text = decoder.decode(value, { stream: true });
|
|
630
|
-
parser.feed(text);
|
|
631
|
-
while (queue.length > 0) {
|
|
632
|
-
const ev = queue.shift();
|
|
633
|
-
if (ev.type === "delta") {
|
|
33
|
+
let lastError = null;
|
|
34
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
35
|
+
const ctl = new AbortController();
|
|
36
|
+
const timeoutId = setTimeout(() => ctl.abort(), this.timeout);
|
|
634
37
|
try {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
38
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
39
|
+
...init,
|
|
40
|
+
headers: {
|
|
41
|
+
"content-type": "application/json",
|
|
42
|
+
"authorization": `Bearer ${this.apiKey}`,
|
|
43
|
+
...(init.headers || {})
|
|
44
|
+
},
|
|
45
|
+
signal: ctl.signal
|
|
46
|
+
});
|
|
47
|
+
clearTimeout(timeoutId);
|
|
48
|
+
const text = await res.text();
|
|
49
|
+
let body;
|
|
50
|
+
try {
|
|
51
|
+
body = text ? JSON.parse(text) : undefined;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
body = text;
|
|
55
|
+
}
|
|
56
|
+
if (!res.ok) {
|
|
57
|
+
const msg = body?.message || res.statusText;
|
|
58
|
+
const code = body?.code || `HTTP_${res.status}`;
|
|
59
|
+
const error = new SovantError(msg, code, res.status, body);
|
|
60
|
+
// Retry on 429 (rate limit) or 5xx errors
|
|
61
|
+
if (attempt < this.maxRetries && (res.status === 429 || res.status >= 500)) {
|
|
62
|
+
lastError = error;
|
|
63
|
+
const delay = this.retryDelay * Math.pow(2, attempt); // Exponential backoff
|
|
64
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Telemetry: onError hook
|
|
68
|
+
if (this.onError) {
|
|
69
|
+
try {
|
|
70
|
+
this.onError(error);
|
|
71
|
+
}
|
|
72
|
+
catch { }
|
|
73
|
+
}
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
// Success - telemetry: onResponse hook
|
|
77
|
+
const duration = Date.now() - startTime;
|
|
78
|
+
if (this.onResponse) {
|
|
79
|
+
try {
|
|
80
|
+
this.onResponse({ method, path, status: res.status, duration });
|
|
81
|
+
}
|
|
82
|
+
catch { }
|
|
83
|
+
}
|
|
84
|
+
return body;
|
|
645
85
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
86
|
+
catch (err) {
|
|
87
|
+
clearTimeout(timeoutId);
|
|
88
|
+
// Handle abort/timeout errors
|
|
89
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
90
|
+
const error = new SovantError('Request timeout', 'TIMEOUT', 408);
|
|
91
|
+
if (attempt < this.maxRetries) {
|
|
92
|
+
lastError = error;
|
|
93
|
+
const delay = this.retryDelay * Math.pow(2, attempt);
|
|
94
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
// Network errors
|
|
100
|
+
if (err instanceof Error) {
|
|
101
|
+
const error = new SovantError(err.message, 'NETWORK_ERROR', 0);
|
|
102
|
+
if (attempt < this.maxRetries) {
|
|
103
|
+
lastError = error;
|
|
104
|
+
const delay = this.retryDelay * Math.pow(2, attempt);
|
|
105
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
throw err;
|
|
653
111
|
}
|
|
654
|
-
}
|
|
655
112
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
if (pattern.test(sanitized)) {
|
|
752
|
-
const match = sanitized.match(pattern);
|
|
753
|
-
if (match) {
|
|
754
|
-
const location = match[1].trim().replace(/\s+/g, " ").replace(/\.$/, "");
|
|
755
|
-
return { entity: "location", value: location };
|
|
113
|
+
// If we exhausted retries, throw the last error
|
|
114
|
+
throw lastError || new SovantError('Max retries exceeded', 'MAX_RETRIES', 0);
|
|
115
|
+
}
|
|
116
|
+
memory = {
|
|
117
|
+
create: (input) => this.req("/api/v1/memory", {
|
|
118
|
+
method: "POST",
|
|
119
|
+
body: JSON.stringify({
|
|
120
|
+
content: typeof input.data === 'string' ? input.data : JSON.stringify(input.data),
|
|
121
|
+
type: input.type || 'journal',
|
|
122
|
+
ttl: input.ttl,
|
|
123
|
+
tags: input.tags,
|
|
124
|
+
metadata: input.metadata,
|
|
125
|
+
thread_id: input.thread_id
|
|
126
|
+
})
|
|
127
|
+
}),
|
|
128
|
+
get: (id) => this.req(`/api/v1/memories/${encodeURIComponent(id)}`, {
|
|
129
|
+
method: "GET"
|
|
130
|
+
}),
|
|
131
|
+
search: (q) => {
|
|
132
|
+
const params = new URLSearchParams();
|
|
133
|
+
if (q.query)
|
|
134
|
+
params.append('query', q.query);
|
|
135
|
+
if (q.type)
|
|
136
|
+
params.append('type', q.type);
|
|
137
|
+
if (q.tags)
|
|
138
|
+
params.append('tags', q.tags.join(','));
|
|
139
|
+
if (q.thread_id)
|
|
140
|
+
params.append('thread_id', q.thread_id);
|
|
141
|
+
if (q.limit)
|
|
142
|
+
params.append('limit', q.limit.toString());
|
|
143
|
+
if (q.from_date)
|
|
144
|
+
params.append('from_date', q.from_date);
|
|
145
|
+
if (q.to_date)
|
|
146
|
+
params.append('to_date', q.to_date);
|
|
147
|
+
return this.req(`/api/v1/memory/search?${params.toString()}`, {
|
|
148
|
+
method: "GET"
|
|
149
|
+
});
|
|
150
|
+
},
|
|
151
|
+
update: (id, patch) => this.req(`/api/v1/memories/${encodeURIComponent(id)}`, {
|
|
152
|
+
method: "PATCH",
|
|
153
|
+
body: JSON.stringify({
|
|
154
|
+
content: patch.data ? (typeof patch.data === 'string' ? patch.data : JSON.stringify(patch.data)) : undefined,
|
|
155
|
+
type: patch.type,
|
|
156
|
+
ttl: patch.ttl,
|
|
157
|
+
tags: patch.tags,
|
|
158
|
+
metadata: patch.metadata
|
|
159
|
+
})
|
|
160
|
+
}),
|
|
161
|
+
delete: (id) => this.req(`/api/v1/memories/${encodeURIComponent(id)}`, {
|
|
162
|
+
method: "DELETE"
|
|
163
|
+
}),
|
|
164
|
+
/**
|
|
165
|
+
* Batch create multiple memories in a single request
|
|
166
|
+
* @param memories Array of memory objects to create (max 100)
|
|
167
|
+
* @returns BatchResponse with individual results
|
|
168
|
+
*/
|
|
169
|
+
createBatch: (memories) => {
|
|
170
|
+
const operations = memories.map(mem => ({
|
|
171
|
+
operation: 'create',
|
|
172
|
+
data: {
|
|
173
|
+
content: typeof mem.data === 'string' ? mem.data : JSON.stringify(mem.data),
|
|
174
|
+
type: mem.type || 'journal',
|
|
175
|
+
tags: mem.tags,
|
|
176
|
+
metadata: mem.metadata,
|
|
177
|
+
thread_id: mem.thread_id
|
|
178
|
+
}
|
|
179
|
+
}));
|
|
180
|
+
return this.req("/api/v1/memory/batch", {
|
|
181
|
+
method: "POST",
|
|
182
|
+
body: JSON.stringify(operations)
|
|
183
|
+
});
|
|
184
|
+
},
|
|
185
|
+
/**
|
|
186
|
+
* Semantic search alias for search()
|
|
187
|
+
* Provides a more intuitive name for vector similarity search
|
|
188
|
+
*/
|
|
189
|
+
recall: (q) => {
|
|
190
|
+
const params = new URLSearchParams();
|
|
191
|
+
if (q.query)
|
|
192
|
+
params.append('query', q.query);
|
|
193
|
+
if (q.type)
|
|
194
|
+
params.append('type', q.type);
|
|
195
|
+
if (q.tags)
|
|
196
|
+
params.append('tags', q.tags.join(','));
|
|
197
|
+
if (q.thread_id)
|
|
198
|
+
params.append('thread_id', q.thread_id);
|
|
199
|
+
if (q.limit)
|
|
200
|
+
params.append('limit', q.limit.toString());
|
|
201
|
+
if (q.from_date)
|
|
202
|
+
params.append('from_date', q.from_date);
|
|
203
|
+
if (q.to_date)
|
|
204
|
+
params.append('to_date', q.to_date);
|
|
205
|
+
return this.req(`/api/v1/memory/search?${params.toString()}`, {
|
|
206
|
+
method: "GET"
|
|
207
|
+
});
|
|
756
208
|
}
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
if (/\bi\s+(like|love|prefer)\s+([^.!?]{2,})/i.test(sanitized)) {
|
|
760
|
-
const match = sanitized.match(/\bi\s+(like|love|prefer)\s+([^.!?]{2,})/i);
|
|
761
|
-
if (match) {
|
|
762
|
-
const pref = match[2].trim().replace(/\s+/g, " ").replace(/\.$/, "");
|
|
763
|
-
return { entity: "preference", value: pref };
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
return { entity: null };
|
|
767
|
-
}
|
|
768
|
-
/**
|
|
769
|
-
* Get profile facts from memories
|
|
770
|
-
*/
|
|
771
|
-
async getProfileFacts() {
|
|
772
|
-
const response = await this.http.request(
|
|
773
|
-
"/api/v1/memory/search?query=user%20name%20age%20location&limit=20",
|
|
774
|
-
{ method: "GET" }
|
|
775
|
-
);
|
|
776
|
-
const facts = {
|
|
777
|
-
preferences: []
|
|
778
209
|
};
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
if (/^user\s+location\s+is\s+(.+)$/i.test(content)) {
|
|
794
|
-
const match = content.match(/^user\s+location\s+is\s+(.+)$/i);
|
|
795
|
-
if (match && !facts.location) {
|
|
796
|
-
facts.location = match[1].trim();
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
if (/^user\s+(likes|loves|prefers)\s+(.+)$/i.test(content)) {
|
|
800
|
-
const match = content.match(/^user\s+(likes|loves|prefers)\s+(.+)$/i);
|
|
801
|
-
if (match) {
|
|
802
|
-
const pref = match[2].trim();
|
|
803
|
-
if (!facts.preferences?.includes(pref)) {
|
|
804
|
-
facts.preferences?.push(pref);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
return facts;
|
|
810
|
-
}
|
|
811
|
-
/**
|
|
812
|
-
* Save a profile fact in canonical form
|
|
813
|
-
*/
|
|
814
|
-
async saveProfileFact(kind, value) {
|
|
815
|
-
let content;
|
|
816
|
-
switch (kind) {
|
|
817
|
-
case "name":
|
|
818
|
-
content = `user name is ${value}`;
|
|
819
|
-
break;
|
|
820
|
-
case "age":
|
|
821
|
-
content = `user age is ${value}`;
|
|
822
|
-
break;
|
|
823
|
-
case "location":
|
|
824
|
-
content = `user location is ${value}`;
|
|
825
|
-
break;
|
|
826
|
-
case "preference":
|
|
827
|
-
content = `user likes ${value}`;
|
|
828
|
-
break;
|
|
829
|
-
default:
|
|
830
|
-
throw new Error(`Unknown profile entity: ${kind}`);
|
|
831
|
-
}
|
|
832
|
-
const response = await this.http.request("/api/v1/memory", {
|
|
833
|
-
method: "POST",
|
|
834
|
-
body: {
|
|
835
|
-
content,
|
|
836
|
-
type: "preference",
|
|
837
|
-
tags: ["profile", kind]
|
|
838
|
-
}
|
|
839
|
-
});
|
|
840
|
-
const { ok, ...memory } = response.data;
|
|
841
|
-
return memory;
|
|
842
|
-
}
|
|
843
|
-
};
|
|
844
|
-
var index_default = Sovant;
|
|
845
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
846
|
-
0 && (module.exports = {
|
|
847
|
-
NetworkError,
|
|
848
|
-
Sovant,
|
|
849
|
-
SovantError,
|
|
850
|
-
TimeoutError
|
|
851
|
-
});
|
|
210
|
+
}
|
|
211
|
+
export class SovantError extends Error {
|
|
212
|
+
code;
|
|
213
|
+
status;
|
|
214
|
+
details;
|
|
215
|
+
constructor(message, code, status, details) {
|
|
216
|
+
super(message);
|
|
217
|
+
this.name = "SovantError";
|
|
218
|
+
this.code = code;
|
|
219
|
+
this.status = status;
|
|
220
|
+
this.details = details;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=index.js.map
|