@sovant/sdk 1.3.0 → 1.4.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 +90 -6
- package/dist/index.cjs +301 -0
- package/dist/index.d.cts +207 -0
- package/dist/index.d.ts +103 -4
- package/dist/index.js +268 -220
- package/package.json +7 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -103,11 +103,12 @@ Sovant provides two ways to query memories:
|
|
|
103
103
|
Pure vector similarity search without profile logic. Behavior unchanged from previous versions.
|
|
104
104
|
|
|
105
105
|
```typescript
|
|
106
|
-
// Recall for conversational queries
|
|
107
|
-
const
|
|
106
|
+
// Recall for conversational queries (returns { results: [...], total, query_type })
|
|
107
|
+
const recall = await sv.memory.recall({
|
|
108
108
|
query: "what do you know about me?",
|
|
109
109
|
limit: 10
|
|
110
110
|
});
|
|
111
|
+
console.log(recall.results); // array of matching memories
|
|
111
112
|
|
|
112
113
|
// Search for topic discovery
|
|
113
114
|
const topics = await sv.memory.search({
|
|
@@ -116,11 +117,93 @@ const topics = await sv.memory.search({
|
|
|
116
117
|
});
|
|
117
118
|
```
|
|
118
119
|
|
|
120
|
+
## Working with Threads
|
|
121
|
+
|
|
122
|
+
Threads let you organize related memories into conversations or sessions. Each thread has a `title` and can contain multiple memories.
|
|
123
|
+
|
|
124
|
+
### Create a thread and store memories
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Create a new thread
|
|
128
|
+
const thread = await sv.threads.create({
|
|
129
|
+
title: "Project Alpha Discussion",
|
|
130
|
+
description: "Q1 planning meeting notes",
|
|
131
|
+
metadata: { project: "alpha", quarter: "Q1" }
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Store memories in the thread
|
|
135
|
+
await sv.memory.create({
|
|
136
|
+
data: "Decided to launch in March",
|
|
137
|
+
type: "journal",
|
|
138
|
+
thread_id: thread.id
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
await sv.memory.create({
|
|
142
|
+
data: "Budget approved: $50k",
|
|
143
|
+
type: "insight",
|
|
144
|
+
thread_id: thread.id
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Recall memories from this specific thread
|
|
148
|
+
const threadRecall = await sv.memory.recall({
|
|
149
|
+
query: "launch date",
|
|
150
|
+
thread_id: thread.id,
|
|
151
|
+
limit: 10
|
|
152
|
+
});
|
|
153
|
+
console.log(threadRecall.results); // thread-scoped matches
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### List and manage threads
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// List all threads
|
|
160
|
+
const { threads, total } = await sv.threads.list({
|
|
161
|
+
limit: 20,
|
|
162
|
+
offset: 0
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Get a specific thread with its memories
|
|
166
|
+
const result = await sv.threads.get(thread.id, {
|
|
167
|
+
include_memories: true,
|
|
168
|
+
limit: 50
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Update thread details
|
|
172
|
+
await sv.threads.update(thread.id, {
|
|
173
|
+
title: "Project Alpha - Q1 Launch",
|
|
174
|
+
status: "completed"
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Delete a thread (keeps memories by default)
|
|
178
|
+
await sv.threads.delete(thread.id);
|
|
179
|
+
|
|
180
|
+
// Delete a thread and all its memories
|
|
181
|
+
await sv.threads.delete(thread.id, true);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Default mode (without threads)
|
|
185
|
+
|
|
186
|
+
You can still use Sovant without threads - just omit `thread_id`:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// Store memory globally
|
|
190
|
+
await sv.memory.create({
|
|
191
|
+
data: "User prefers email notifications",
|
|
192
|
+
type: "preference"
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Recall from all memories
|
|
196
|
+
const recall = await sv.memory.recall({
|
|
197
|
+
query: "notification preferences"
|
|
198
|
+
});
|
|
199
|
+
console.log(recall.results);
|
|
200
|
+
```
|
|
201
|
+
|
|
119
202
|
## Features
|
|
120
203
|
|
|
121
204
|
- **Memory CRUD** — create, retrieve, update, delete memories
|
|
122
205
|
- **Semantic Search** — query memories with filters and topK ranking
|
|
123
|
-
- **Threads** —
|
|
206
|
+
- **Threads** — organize memories into conversations or sessions (fully supported in SDK)
|
|
124
207
|
- **Batch Operations (Beta)** — atomic multi-operation support
|
|
125
208
|
- **Compliance-ready** — audit trails, PDPA/GDPR-friendly by design
|
|
126
209
|
- **SDKs** — official TypeScript and Python SDKs, with REST API reference
|
|
@@ -153,13 +236,14 @@ const topics = await sv.memory.search({
|
|
|
153
236
|
## Status of Advanced Features
|
|
154
237
|
|
|
155
238
|
- **Batch API:** Available, marked Beta.
|
|
156
|
-
- **Threads:** Fully supported
|
|
239
|
+
- **Threads:** Fully supported in TypeScript SDK (v1.4.0+).
|
|
157
240
|
- **Webhooks, personalization, multi-channel sync:** Coming soon.
|
|
158
241
|
|
|
159
242
|
## Versioning & Changelog
|
|
160
243
|
|
|
161
|
-
- **Current release:** 1.
|
|
162
|
-
- Version 1.
|
|
244
|
+
- **Current release:** 1.4.0
|
|
245
|
+
- Version 1.4.0 adds full threads support (create, list, get, update, delete)
|
|
246
|
+
- Version 1.3.0 added hybrid recall with profile awareness
|
|
163
247
|
- See [CHANGELOG.md](./CHANGELOG.md) for details.
|
|
164
248
|
|
|
165
249
|
## License & Use
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"use strict";
|
|
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);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Sovant: () => Sovant,
|
|
24
|
+
SovantError: () => SovantError
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
var Sovant = class {
|
|
28
|
+
apiKey;
|
|
29
|
+
baseUrl;
|
|
30
|
+
timeout;
|
|
31
|
+
maxRetries;
|
|
32
|
+
retryDelay;
|
|
33
|
+
onRequest;
|
|
34
|
+
onResponse;
|
|
35
|
+
onError;
|
|
36
|
+
constructor(opts) {
|
|
37
|
+
if (!opts?.apiKey) throw new Error("Missing apiKey");
|
|
38
|
+
this.apiKey = opts.apiKey;
|
|
39
|
+
this.baseUrl = (opts.baseUrl ?? process.env.SOVANT_BASE_URL ?? "https://sovant.ai").replace(/\/+$/, "");
|
|
40
|
+
this.timeout = opts.timeoutMs ?? 3e4;
|
|
41
|
+
this.maxRetries = opts.maxRetries ?? 3;
|
|
42
|
+
this.retryDelay = opts.retryDelay ?? 1e3;
|
|
43
|
+
this.onRequest = opts.onRequest;
|
|
44
|
+
this.onResponse = opts.onResponse;
|
|
45
|
+
this.onError = opts.onError;
|
|
46
|
+
}
|
|
47
|
+
async req(path, init) {
|
|
48
|
+
const method = init.method || "GET";
|
|
49
|
+
const startTime = Date.now();
|
|
50
|
+
if (this.onRequest) {
|
|
51
|
+
try {
|
|
52
|
+
const body = init.body ? JSON.parse(init.body) : void 0;
|
|
53
|
+
this.onRequest({ method, path, body });
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
let lastError = null;
|
|
58
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
59
|
+
const ctl = new AbortController();
|
|
60
|
+
const timeoutId = setTimeout(() => ctl.abort(), this.timeout);
|
|
61
|
+
try {
|
|
62
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
63
|
+
...init,
|
|
64
|
+
headers: {
|
|
65
|
+
"content-type": "application/json",
|
|
66
|
+
authorization: `Bearer ${this.apiKey}`,
|
|
67
|
+
...init.headers || {}
|
|
68
|
+
},
|
|
69
|
+
signal: ctl.signal
|
|
70
|
+
});
|
|
71
|
+
clearTimeout(timeoutId);
|
|
72
|
+
const text = await res.text();
|
|
73
|
+
let body;
|
|
74
|
+
try {
|
|
75
|
+
body = text ? JSON.parse(text) : void 0;
|
|
76
|
+
} catch {
|
|
77
|
+
body = text;
|
|
78
|
+
}
|
|
79
|
+
if (!res.ok) {
|
|
80
|
+
const msg = body?.message || res.statusText;
|
|
81
|
+
const code = body?.code || `HTTP_${res.status}`;
|
|
82
|
+
const error = new SovantError(msg, code, res.status, body);
|
|
83
|
+
if (attempt < this.maxRetries && (res.status === 429 || res.status >= 500)) {
|
|
84
|
+
lastError = error;
|
|
85
|
+
const delay = this.retryDelay * Math.pow(2, attempt);
|
|
86
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (this.onError) {
|
|
90
|
+
try {
|
|
91
|
+
this.onError(error);
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
const duration = Date.now() - startTime;
|
|
98
|
+
if (this.onResponse) {
|
|
99
|
+
try {
|
|
100
|
+
this.onResponse({ method, path, status: res.status, duration });
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return body;
|
|
105
|
+
} catch (err) {
|
|
106
|
+
clearTimeout(timeoutId);
|
|
107
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
108
|
+
const error = new SovantError("Request timeout", "TIMEOUT", 408);
|
|
109
|
+
if (attempt < this.maxRetries) {
|
|
110
|
+
lastError = error;
|
|
111
|
+
const delay = this.retryDelay * Math.pow(2, attempt);
|
|
112
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
if (err instanceof Error) {
|
|
118
|
+
const error = new SovantError(err.message, "NETWORK_ERROR", 0);
|
|
119
|
+
if (attempt < this.maxRetries) {
|
|
120
|
+
lastError = error;
|
|
121
|
+
const delay = this.retryDelay * Math.pow(2, attempt);
|
|
122
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
throw err;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
throw lastError || new SovantError("Max retries exceeded", "MAX_RETRIES", 0);
|
|
131
|
+
}
|
|
132
|
+
memory = {
|
|
133
|
+
create: (input) => this.req("/api/v1/memory", {
|
|
134
|
+
method: "POST",
|
|
135
|
+
body: JSON.stringify({
|
|
136
|
+
content: typeof input.data === "string" ? input.data : JSON.stringify(input.data),
|
|
137
|
+
type: input.type || "journal",
|
|
138
|
+
ttl: input.ttl,
|
|
139
|
+
tags: input.tags,
|
|
140
|
+
metadata: input.metadata,
|
|
141
|
+
thread_id: input.thread_id
|
|
142
|
+
})
|
|
143
|
+
}),
|
|
144
|
+
get: (id) => this.req(`/api/v1/memories/${encodeURIComponent(id)}`, {
|
|
145
|
+
method: "GET"
|
|
146
|
+
}),
|
|
147
|
+
search: (q) => {
|
|
148
|
+
const params = new URLSearchParams();
|
|
149
|
+
if (q.query) params.append("query", q.query);
|
|
150
|
+
if (q.type) params.append("type", q.type);
|
|
151
|
+
if (q.tags) params.append("tags", q.tags.join(","));
|
|
152
|
+
if (q.thread_id) params.append("thread_id", q.thread_id);
|
|
153
|
+
if (q.limit) params.append("limit", q.limit.toString());
|
|
154
|
+
if (q.from_date) params.append("from_date", q.from_date);
|
|
155
|
+
if (q.to_date) params.append("to_date", q.to_date);
|
|
156
|
+
return this.req(`/api/v1/memory/search?${params.toString()}`, {
|
|
157
|
+
method: "GET"
|
|
158
|
+
});
|
|
159
|
+
},
|
|
160
|
+
update: (id, patch) => this.req(`/api/v1/memories/${encodeURIComponent(id)}`, {
|
|
161
|
+
method: "PATCH",
|
|
162
|
+
body: JSON.stringify({
|
|
163
|
+
content: patch.data ? typeof patch.data === "string" ? patch.data : JSON.stringify(patch.data) : void 0,
|
|
164
|
+
type: patch.type,
|
|
165
|
+
ttl: patch.ttl,
|
|
166
|
+
tags: patch.tags,
|
|
167
|
+
metadata: patch.metadata
|
|
168
|
+
})
|
|
169
|
+
}),
|
|
170
|
+
delete: (id) => this.req(`/api/v1/memories/${encodeURIComponent(id)}`, {
|
|
171
|
+
method: "DELETE"
|
|
172
|
+
}),
|
|
173
|
+
/**
|
|
174
|
+
* Batch create multiple memories in a single request
|
|
175
|
+
* @param memories Array of memory objects to create (max 100)
|
|
176
|
+
* @returns BatchResponse with individual results
|
|
177
|
+
*/
|
|
178
|
+
createBatch: (memories) => {
|
|
179
|
+
const operations = memories.map((mem) => ({
|
|
180
|
+
operation: "create",
|
|
181
|
+
data: {
|
|
182
|
+
content: typeof mem.data === "string" ? mem.data : JSON.stringify(mem.data),
|
|
183
|
+
type: mem.type || "journal",
|
|
184
|
+
tags: mem.tags,
|
|
185
|
+
metadata: mem.metadata,
|
|
186
|
+
thread_id: mem.thread_id
|
|
187
|
+
}
|
|
188
|
+
}));
|
|
189
|
+
return this.req("/api/v1/memory/batch", {
|
|
190
|
+
method: "POST",
|
|
191
|
+
body: JSON.stringify(operations)
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
/**
|
|
195
|
+
* Hybrid recall with profile awareness
|
|
196
|
+
* Uses multi-stage pipeline (profile fast-path + lexical + semantic)
|
|
197
|
+
* Guarantees profile facts (name/age/location) when available
|
|
198
|
+
*
|
|
199
|
+
* Use recall() for conversational queries ("who am I?", "what do you know about me?")
|
|
200
|
+
* Use search() for pure semantic topic lookup
|
|
201
|
+
*/
|
|
202
|
+
recall: (q) => {
|
|
203
|
+
const params = new URLSearchParams();
|
|
204
|
+
params.append("query", q.query);
|
|
205
|
+
if (q.thread_id) params.append("thread_id", q.thread_id);
|
|
206
|
+
if (q.limit) params.append("limit", q.limit.toString());
|
|
207
|
+
return this.req(`/api/v1/memory/recall?${params.toString()}`, {
|
|
208
|
+
method: "GET"
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
threads = {
|
|
213
|
+
/**
|
|
214
|
+
* Create a new thread
|
|
215
|
+
* @param input Thread creation parameters
|
|
216
|
+
* @returns Created thread with ID
|
|
217
|
+
*/
|
|
218
|
+
create: (input) => this.req("/api/v1/threads", {
|
|
219
|
+
method: "POST",
|
|
220
|
+
body: JSON.stringify({
|
|
221
|
+
title: input.title,
|
|
222
|
+
description: input.description,
|
|
223
|
+
metadata: input.metadata
|
|
224
|
+
})
|
|
225
|
+
}),
|
|
226
|
+
/**
|
|
227
|
+
* List threads with optional filtering
|
|
228
|
+
* @param params List parameters
|
|
229
|
+
* @returns Paginated thread list
|
|
230
|
+
*/
|
|
231
|
+
list: (params) => {
|
|
232
|
+
const query = new URLSearchParams();
|
|
233
|
+
if (params?.limit) query.append("limit", params.limit.toString());
|
|
234
|
+
if (params?.offset) query.append("offset", params.offset.toString());
|
|
235
|
+
if (params?.status) query.append("status", params.status);
|
|
236
|
+
return this.req(`/api/v1/threads?${query.toString()}`, {
|
|
237
|
+
method: "GET"
|
|
238
|
+
});
|
|
239
|
+
},
|
|
240
|
+
/**
|
|
241
|
+
* Get a thread by ID
|
|
242
|
+
* @param threadId Thread UUID
|
|
243
|
+
* @param options Optional parameters
|
|
244
|
+
* @returns Thread details
|
|
245
|
+
*/
|
|
246
|
+
get: (threadId, options) => {
|
|
247
|
+
const query = new URLSearchParams();
|
|
248
|
+
if (options?.include_memories) query.append("include_memories", "true");
|
|
249
|
+
if (options?.limit) query.append("limit", options.limit.toString());
|
|
250
|
+
return this.req(
|
|
251
|
+
`/api/v1/threads/${encodeURIComponent(threadId)}?${query.toString()}`,
|
|
252
|
+
{
|
|
253
|
+
method: "GET"
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
},
|
|
257
|
+
/**
|
|
258
|
+
* Update a thread
|
|
259
|
+
* @param threadId Thread UUID
|
|
260
|
+
* @param updates Fields to update
|
|
261
|
+
* @returns Updated thread
|
|
262
|
+
*/
|
|
263
|
+
update: (threadId, updates) => this.req(`/api/v1/threads/${encodeURIComponent(threadId)}`, {
|
|
264
|
+
method: "PUT",
|
|
265
|
+
body: JSON.stringify(updates)
|
|
266
|
+
}),
|
|
267
|
+
/**
|
|
268
|
+
* Delete a thread
|
|
269
|
+
* @param threadId Thread UUID
|
|
270
|
+
* @param deleteMemories If true, also delete associated memories
|
|
271
|
+
* @returns Deletion confirmation
|
|
272
|
+
*/
|
|
273
|
+
delete: (threadId, deleteMemories = false) => {
|
|
274
|
+
const query = new URLSearchParams();
|
|
275
|
+
if (deleteMemories) query.append("delete_memories", "true");
|
|
276
|
+
return this.req(
|
|
277
|
+
`/api/v1/threads/${encodeURIComponent(threadId)}?${query.toString()}`,
|
|
278
|
+
{
|
|
279
|
+
method: "DELETE"
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
var SovantError = class extends Error {
|
|
286
|
+
code;
|
|
287
|
+
status;
|
|
288
|
+
details;
|
|
289
|
+
constructor(message, code, status, details) {
|
|
290
|
+
super(message);
|
|
291
|
+
this.name = "SovantError";
|
|
292
|
+
this.code = code;
|
|
293
|
+
this.status = status;
|
|
294
|
+
this.details = details;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
298
|
+
0 && (module.exports = {
|
|
299
|
+
Sovant,
|
|
300
|
+
SovantError
|
|
301
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
type SovantClientOptions = {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
maxRetries?: number;
|
|
6
|
+
retryDelay?: number;
|
|
7
|
+
onRequest?: (req: {
|
|
8
|
+
method: string;
|
|
9
|
+
path: string;
|
|
10
|
+
body?: any;
|
|
11
|
+
}) => void;
|
|
12
|
+
onResponse?: (res: {
|
|
13
|
+
method: string;
|
|
14
|
+
path: string;
|
|
15
|
+
status: number;
|
|
16
|
+
duration: number;
|
|
17
|
+
}) => void;
|
|
18
|
+
onError?: (err: SovantError) => void;
|
|
19
|
+
};
|
|
20
|
+
declare class Sovant {
|
|
21
|
+
private apiKey;
|
|
22
|
+
private baseUrl;
|
|
23
|
+
private timeout;
|
|
24
|
+
private maxRetries;
|
|
25
|
+
private retryDelay;
|
|
26
|
+
private onRequest?;
|
|
27
|
+
private onResponse?;
|
|
28
|
+
private onError?;
|
|
29
|
+
constructor(opts: SovantClientOptions);
|
|
30
|
+
private req;
|
|
31
|
+
memory: {
|
|
32
|
+
create: <T = any>(input: {
|
|
33
|
+
data: T;
|
|
34
|
+
type?: "journal" | "insight" | "observation" | "task" | "preference";
|
|
35
|
+
ttl?: string;
|
|
36
|
+
tags?: string[];
|
|
37
|
+
metadata?: Record<string, any>;
|
|
38
|
+
thread_id?: string;
|
|
39
|
+
}) => Promise<unknown>;
|
|
40
|
+
get: (id: string) => Promise<unknown>;
|
|
41
|
+
search: (q: {
|
|
42
|
+
query?: string;
|
|
43
|
+
type?: string;
|
|
44
|
+
tags?: string[];
|
|
45
|
+
thread_id?: string;
|
|
46
|
+
limit?: number;
|
|
47
|
+
from_date?: string;
|
|
48
|
+
to_date?: string;
|
|
49
|
+
}) => Promise<unknown>;
|
|
50
|
+
update: <T = any>(id: string, patch: Partial<{
|
|
51
|
+
data: T;
|
|
52
|
+
type?: string;
|
|
53
|
+
ttl?: string;
|
|
54
|
+
tags?: string[];
|
|
55
|
+
metadata?: Record<string, any>;
|
|
56
|
+
}>) => Promise<unknown>;
|
|
57
|
+
delete: (id: string) => Promise<unknown>;
|
|
58
|
+
/**
|
|
59
|
+
* Batch create multiple memories in a single request
|
|
60
|
+
* @param memories Array of memory objects to create (max 100)
|
|
61
|
+
* @returns BatchResponse with individual results
|
|
62
|
+
*/
|
|
63
|
+
createBatch: <T = any>(memories: Array<{
|
|
64
|
+
data: T;
|
|
65
|
+
type?: "journal" | "insight" | "observation" | "task" | "preference";
|
|
66
|
+
tags?: string[];
|
|
67
|
+
metadata?: Record<string, any>;
|
|
68
|
+
thread_id?: string;
|
|
69
|
+
}>) => Promise<{
|
|
70
|
+
results: Array<{
|
|
71
|
+
success: boolean;
|
|
72
|
+
operation: string;
|
|
73
|
+
id?: string;
|
|
74
|
+
error?: {
|
|
75
|
+
code: string;
|
|
76
|
+
message: string;
|
|
77
|
+
};
|
|
78
|
+
index: number;
|
|
79
|
+
}>;
|
|
80
|
+
summary: {
|
|
81
|
+
total: number;
|
|
82
|
+
successful: number;
|
|
83
|
+
failed: number;
|
|
84
|
+
};
|
|
85
|
+
transaction_id: string;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* Hybrid recall with profile awareness
|
|
89
|
+
* Uses multi-stage pipeline (profile fast-path + lexical + semantic)
|
|
90
|
+
* Guarantees profile facts (name/age/location) when available
|
|
91
|
+
*
|
|
92
|
+
* Use recall() for conversational queries ("who am I?", "what do you know about me?")
|
|
93
|
+
* Use search() for pure semantic topic lookup
|
|
94
|
+
*/
|
|
95
|
+
recall: (q: {
|
|
96
|
+
query: string;
|
|
97
|
+
thread_id?: string;
|
|
98
|
+
limit?: number;
|
|
99
|
+
}) => Promise<unknown>;
|
|
100
|
+
};
|
|
101
|
+
threads: {
|
|
102
|
+
/**
|
|
103
|
+
* Create a new thread
|
|
104
|
+
* @param input Thread creation parameters
|
|
105
|
+
* @returns Created thread with ID
|
|
106
|
+
*/
|
|
107
|
+
create: (input: {
|
|
108
|
+
title: string;
|
|
109
|
+
description?: string;
|
|
110
|
+
metadata?: Record<string, any>;
|
|
111
|
+
}) => Promise<{
|
|
112
|
+
ok: boolean;
|
|
113
|
+
id: string;
|
|
114
|
+
title: string;
|
|
115
|
+
description?: string;
|
|
116
|
+
metadata?: Record<string, any>;
|
|
117
|
+
created_at: string;
|
|
118
|
+
updated_at: string;
|
|
119
|
+
}>;
|
|
120
|
+
/**
|
|
121
|
+
* List threads with optional filtering
|
|
122
|
+
* @param params List parameters
|
|
123
|
+
* @returns Paginated thread list
|
|
124
|
+
*/
|
|
125
|
+
list: (params?: {
|
|
126
|
+
limit?: number;
|
|
127
|
+
offset?: number;
|
|
128
|
+
status?: "active" | "archived" | "completed";
|
|
129
|
+
}) => Promise<{
|
|
130
|
+
threads: Array<{
|
|
131
|
+
id: string;
|
|
132
|
+
title: string;
|
|
133
|
+
description?: string;
|
|
134
|
+
metadata?: Record<string, any>;
|
|
135
|
+
created_at: string;
|
|
136
|
+
updated_at: string;
|
|
137
|
+
}>;
|
|
138
|
+
total: number;
|
|
139
|
+
limit: number;
|
|
140
|
+
offset: number;
|
|
141
|
+
has_more: boolean;
|
|
142
|
+
}>;
|
|
143
|
+
/**
|
|
144
|
+
* Get a thread by ID
|
|
145
|
+
* @param threadId Thread UUID
|
|
146
|
+
* @param options Optional parameters
|
|
147
|
+
* @returns Thread details
|
|
148
|
+
*/
|
|
149
|
+
get: (threadId: string, options?: {
|
|
150
|
+
include_memories?: boolean;
|
|
151
|
+
limit?: number;
|
|
152
|
+
}) => Promise<{
|
|
153
|
+
thread: {
|
|
154
|
+
id: string;
|
|
155
|
+
title: string;
|
|
156
|
+
description?: string;
|
|
157
|
+
status?: string;
|
|
158
|
+
metadata?: Record<string, any>;
|
|
159
|
+
created_at: string;
|
|
160
|
+
updated_at: string;
|
|
161
|
+
memory_ids?: string[];
|
|
162
|
+
memories?: any[];
|
|
163
|
+
};
|
|
164
|
+
}>;
|
|
165
|
+
/**
|
|
166
|
+
* Update a thread
|
|
167
|
+
* @param threadId Thread UUID
|
|
168
|
+
* @param updates Fields to update
|
|
169
|
+
* @returns Updated thread
|
|
170
|
+
*/
|
|
171
|
+
update: (threadId: string, updates: {
|
|
172
|
+
title?: string;
|
|
173
|
+
description?: string;
|
|
174
|
+
status?: "active" | "archived" | "completed";
|
|
175
|
+
metadata?: Record<string, any>;
|
|
176
|
+
}) => Promise<{
|
|
177
|
+
thread: {
|
|
178
|
+
id: string;
|
|
179
|
+
title: string;
|
|
180
|
+
description?: string;
|
|
181
|
+
status?: string;
|
|
182
|
+
metadata?: Record<string, any>;
|
|
183
|
+
created_at: string;
|
|
184
|
+
updated_at: string;
|
|
185
|
+
};
|
|
186
|
+
message: string;
|
|
187
|
+
}>;
|
|
188
|
+
/**
|
|
189
|
+
* Delete a thread
|
|
190
|
+
* @param threadId Thread UUID
|
|
191
|
+
* @param deleteMemories If true, also delete associated memories
|
|
192
|
+
* @returns Deletion confirmation
|
|
193
|
+
*/
|
|
194
|
+
delete: (threadId: string, deleteMemories?: boolean) => Promise<{
|
|
195
|
+
message: string;
|
|
196
|
+
memories_deleted: boolean;
|
|
197
|
+
}>;
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
declare class SovantError extends Error {
|
|
201
|
+
code: string;
|
|
202
|
+
status?: number;
|
|
203
|
+
details?: any;
|
|
204
|
+
constructor(message: string, code: string, status?: number, details?: any);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export { Sovant, type SovantClientOptions, SovantError };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
type SovantClientOptions = {
|
|
2
2
|
apiKey: string;
|
|
3
3
|
baseUrl?: string;
|
|
4
4
|
timeoutMs?: number;
|
|
@@ -17,7 +17,7 @@ export type SovantClientOptions = {
|
|
|
17
17
|
}) => void;
|
|
18
18
|
onError?: (err: SovantError) => void;
|
|
19
19
|
};
|
|
20
|
-
|
|
20
|
+
declare class Sovant {
|
|
21
21
|
private apiKey;
|
|
22
22
|
private baseUrl;
|
|
23
23
|
private timeout;
|
|
@@ -98,11 +98,110 @@ export declare class Sovant {
|
|
|
98
98
|
limit?: number;
|
|
99
99
|
}) => Promise<unknown>;
|
|
100
100
|
};
|
|
101
|
+
threads: {
|
|
102
|
+
/**
|
|
103
|
+
* Create a new thread
|
|
104
|
+
* @param input Thread creation parameters
|
|
105
|
+
* @returns Created thread with ID
|
|
106
|
+
*/
|
|
107
|
+
create: (input: {
|
|
108
|
+
title: string;
|
|
109
|
+
description?: string;
|
|
110
|
+
metadata?: Record<string, any>;
|
|
111
|
+
}) => Promise<{
|
|
112
|
+
ok: boolean;
|
|
113
|
+
id: string;
|
|
114
|
+
title: string;
|
|
115
|
+
description?: string;
|
|
116
|
+
metadata?: Record<string, any>;
|
|
117
|
+
created_at: string;
|
|
118
|
+
updated_at: string;
|
|
119
|
+
}>;
|
|
120
|
+
/**
|
|
121
|
+
* List threads with optional filtering
|
|
122
|
+
* @param params List parameters
|
|
123
|
+
* @returns Paginated thread list
|
|
124
|
+
*/
|
|
125
|
+
list: (params?: {
|
|
126
|
+
limit?: number;
|
|
127
|
+
offset?: number;
|
|
128
|
+
status?: "active" | "archived" | "completed";
|
|
129
|
+
}) => Promise<{
|
|
130
|
+
threads: Array<{
|
|
131
|
+
id: string;
|
|
132
|
+
title: string;
|
|
133
|
+
description?: string;
|
|
134
|
+
metadata?: Record<string, any>;
|
|
135
|
+
created_at: string;
|
|
136
|
+
updated_at: string;
|
|
137
|
+
}>;
|
|
138
|
+
total: number;
|
|
139
|
+
limit: number;
|
|
140
|
+
offset: number;
|
|
141
|
+
has_more: boolean;
|
|
142
|
+
}>;
|
|
143
|
+
/**
|
|
144
|
+
* Get a thread by ID
|
|
145
|
+
* @param threadId Thread UUID
|
|
146
|
+
* @param options Optional parameters
|
|
147
|
+
* @returns Thread details
|
|
148
|
+
*/
|
|
149
|
+
get: (threadId: string, options?: {
|
|
150
|
+
include_memories?: boolean;
|
|
151
|
+
limit?: number;
|
|
152
|
+
}) => Promise<{
|
|
153
|
+
thread: {
|
|
154
|
+
id: string;
|
|
155
|
+
title: string;
|
|
156
|
+
description?: string;
|
|
157
|
+
status?: string;
|
|
158
|
+
metadata?: Record<string, any>;
|
|
159
|
+
created_at: string;
|
|
160
|
+
updated_at: string;
|
|
161
|
+
memory_ids?: string[];
|
|
162
|
+
memories?: any[];
|
|
163
|
+
};
|
|
164
|
+
}>;
|
|
165
|
+
/**
|
|
166
|
+
* Update a thread
|
|
167
|
+
* @param threadId Thread UUID
|
|
168
|
+
* @param updates Fields to update
|
|
169
|
+
* @returns Updated thread
|
|
170
|
+
*/
|
|
171
|
+
update: (threadId: string, updates: {
|
|
172
|
+
title?: string;
|
|
173
|
+
description?: string;
|
|
174
|
+
status?: "active" | "archived" | "completed";
|
|
175
|
+
metadata?: Record<string, any>;
|
|
176
|
+
}) => Promise<{
|
|
177
|
+
thread: {
|
|
178
|
+
id: string;
|
|
179
|
+
title: string;
|
|
180
|
+
description?: string;
|
|
181
|
+
status?: string;
|
|
182
|
+
metadata?: Record<string, any>;
|
|
183
|
+
created_at: string;
|
|
184
|
+
updated_at: string;
|
|
185
|
+
};
|
|
186
|
+
message: string;
|
|
187
|
+
}>;
|
|
188
|
+
/**
|
|
189
|
+
* Delete a thread
|
|
190
|
+
* @param threadId Thread UUID
|
|
191
|
+
* @param deleteMemories If true, also delete associated memories
|
|
192
|
+
* @returns Deletion confirmation
|
|
193
|
+
*/
|
|
194
|
+
delete: (threadId: string, deleteMemories?: boolean) => Promise<{
|
|
195
|
+
message: string;
|
|
196
|
+
memories_deleted: boolean;
|
|
197
|
+
}>;
|
|
198
|
+
};
|
|
101
199
|
}
|
|
102
|
-
|
|
200
|
+
declare class SovantError extends Error {
|
|
103
201
|
code: string;
|
|
104
202
|
status?: number;
|
|
105
203
|
details?: any;
|
|
106
204
|
constructor(message: string, code: string, status?: number, details?: any);
|
|
107
205
|
}
|
|
108
|
-
|
|
206
|
+
|
|
207
|
+
export { Sovant, type SovantClientOptions, SovantError };
|
package/dist/index.js
CHANGED
|
@@ -1,227 +1,275 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var Sovant = class {
|
|
3
|
+
apiKey;
|
|
4
|
+
baseUrl;
|
|
5
|
+
timeout;
|
|
6
|
+
maxRetries;
|
|
7
|
+
retryDelay;
|
|
8
|
+
onRequest;
|
|
9
|
+
onResponse;
|
|
10
|
+
onError;
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
if (!opts?.apiKey) 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 ?? 3e4;
|
|
16
|
+
this.maxRetries = opts.maxRetries ?? 3;
|
|
17
|
+
this.retryDelay = opts.retryDelay ?? 1e3;
|
|
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
|
+
if (this.onRequest) {
|
|
26
|
+
try {
|
|
27
|
+
const body = init.body ? JSON.parse(init.body) : void 0;
|
|
28
|
+
this.onRequest({ method, path, body });
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
23
31
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
let lastError = null;
|
|
33
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
34
|
+
const ctl = new AbortController();
|
|
35
|
+
const timeoutId = setTimeout(() => ctl.abort(), this.timeout);
|
|
36
|
+
try {
|
|
37
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
38
|
+
...init,
|
|
39
|
+
headers: {
|
|
40
|
+
"content-type": "application/json",
|
|
41
|
+
authorization: `Bearer ${this.apiKey}`,
|
|
42
|
+
...init.headers || {}
|
|
43
|
+
},
|
|
44
|
+
signal: ctl.signal
|
|
45
|
+
});
|
|
46
|
+
clearTimeout(timeoutId);
|
|
47
|
+
const text = await res.text();
|
|
48
|
+
let body;
|
|
49
|
+
try {
|
|
50
|
+
body = text ? JSON.parse(text) : void 0;
|
|
51
|
+
} catch {
|
|
52
|
+
body = text;
|
|
34
53
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
54
|
+
if (!res.ok) {
|
|
55
|
+
const msg = body?.message || res.statusText;
|
|
56
|
+
const code = body?.code || `HTTP_${res.status}`;
|
|
57
|
+
const error = new SovantError(msg, code, res.status, body);
|
|
58
|
+
if (attempt < this.maxRetries && (res.status === 429 || res.status >= 500)) {
|
|
59
|
+
lastError = error;
|
|
60
|
+
const delay = this.retryDelay * Math.pow(2, attempt);
|
|
61
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (this.onError) {
|
|
39
65
|
try {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
headers: {
|
|
43
|
-
"content-type": "application/json",
|
|
44
|
-
authorization: `Bearer ${this.apiKey}`,
|
|
45
|
-
...(init.headers || {}),
|
|
46
|
-
},
|
|
47
|
-
signal: ctl.signal,
|
|
48
|
-
});
|
|
49
|
-
clearTimeout(timeoutId);
|
|
50
|
-
const text = await res.text();
|
|
51
|
-
let body;
|
|
52
|
-
try {
|
|
53
|
-
body = text ? JSON.parse(text) : undefined;
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
body = text;
|
|
57
|
-
}
|
|
58
|
-
if (!res.ok) {
|
|
59
|
-
const msg = body?.message || res.statusText;
|
|
60
|
-
const code = body?.code || `HTTP_${res.status}`;
|
|
61
|
-
const error = new SovantError(msg, code, res.status, body);
|
|
62
|
-
// Retry on 429 (rate limit) or 5xx errors
|
|
63
|
-
if (attempt < this.maxRetries &&
|
|
64
|
-
(res.status === 429 || res.status >= 500)) {
|
|
65
|
-
lastError = error;
|
|
66
|
-
const delay = this.retryDelay * Math.pow(2, attempt); // Exponential backoff
|
|
67
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
68
|
-
continue;
|
|
69
|
-
}
|
|
70
|
-
// Telemetry: onError hook
|
|
71
|
-
if (this.onError) {
|
|
72
|
-
try {
|
|
73
|
-
this.onError(error);
|
|
74
|
-
}
|
|
75
|
-
catch { }
|
|
76
|
-
}
|
|
77
|
-
throw error;
|
|
78
|
-
}
|
|
79
|
-
// Success - telemetry: onResponse hook
|
|
80
|
-
const duration = Date.now() - startTime;
|
|
81
|
-
if (this.onResponse) {
|
|
82
|
-
try {
|
|
83
|
-
this.onResponse({ method, path, status: res.status, duration });
|
|
84
|
-
}
|
|
85
|
-
catch { }
|
|
86
|
-
}
|
|
87
|
-
return body;
|
|
88
|
-
}
|
|
89
|
-
catch (err) {
|
|
90
|
-
clearTimeout(timeoutId);
|
|
91
|
-
// Handle abort/timeout errors
|
|
92
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
93
|
-
const error = new SovantError("Request timeout", "TIMEOUT", 408);
|
|
94
|
-
if (attempt < this.maxRetries) {
|
|
95
|
-
lastError = error;
|
|
96
|
-
const delay = this.retryDelay * Math.pow(2, attempt);
|
|
97
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
throw error;
|
|
101
|
-
}
|
|
102
|
-
// Network errors
|
|
103
|
-
if (err instanceof Error) {
|
|
104
|
-
const error = new SovantError(err.message, "NETWORK_ERROR", 0);
|
|
105
|
-
if (attempt < this.maxRetries) {
|
|
106
|
-
lastError = error;
|
|
107
|
-
const delay = this.retryDelay * Math.pow(2, attempt);
|
|
108
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
throw error;
|
|
112
|
-
}
|
|
113
|
-
throw err;
|
|
66
|
+
this.onError(error);
|
|
67
|
+
} catch {
|
|
114
68
|
}
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
const duration = Date.now() - startTime;
|
|
73
|
+
if (this.onResponse) {
|
|
74
|
+
try {
|
|
75
|
+
this.onResponse({ method, path, status: res.status, duration });
|
|
76
|
+
} catch {
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return body;
|
|
80
|
+
} catch (err) {
|
|
81
|
+
clearTimeout(timeoutId);
|
|
82
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
83
|
+
const error = new SovantError("Request timeout", "TIMEOUT", 408);
|
|
84
|
+
if (attempt < this.maxRetries) {
|
|
85
|
+
lastError = error;
|
|
86
|
+
const delay = this.retryDelay * Math.pow(2, attempt);
|
|
87
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
throw error;
|
|
115
91
|
}
|
|
116
|
-
|
|
117
|
-
|
|
92
|
+
if (err instanceof Error) {
|
|
93
|
+
const error = new SovantError(err.message, "NETWORK_ERROR", 0);
|
|
94
|
+
if (attempt < this.maxRetries) {
|
|
95
|
+
lastError = error;
|
|
96
|
+
const delay = this.retryDelay * Math.pow(2, attempt);
|
|
97
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
throw lastError || new SovantError("Max retries exceeded", "MAX_RETRIES", 0);
|
|
106
|
+
}
|
|
107
|
+
memory = {
|
|
108
|
+
create: (input) => this.req("/api/v1/memory", {
|
|
109
|
+
method: "POST",
|
|
110
|
+
body: JSON.stringify({
|
|
111
|
+
content: typeof input.data === "string" ? input.data : JSON.stringify(input.data),
|
|
112
|
+
type: input.type || "journal",
|
|
113
|
+
ttl: input.ttl,
|
|
114
|
+
tags: input.tags,
|
|
115
|
+
metadata: input.metadata,
|
|
116
|
+
thread_id: input.thread_id
|
|
117
|
+
})
|
|
118
|
+
}),
|
|
119
|
+
get: (id) => this.req(`/api/v1/memories/${encodeURIComponent(id)}`, {
|
|
120
|
+
method: "GET"
|
|
121
|
+
}),
|
|
122
|
+
search: (q) => {
|
|
123
|
+
const params = new URLSearchParams();
|
|
124
|
+
if (q.query) params.append("query", q.query);
|
|
125
|
+
if (q.type) params.append("type", q.type);
|
|
126
|
+
if (q.tags) params.append("tags", q.tags.join(","));
|
|
127
|
+
if (q.thread_id) params.append("thread_id", q.thread_id);
|
|
128
|
+
if (q.limit) params.append("limit", q.limit.toString());
|
|
129
|
+
if (q.from_date) params.append("from_date", q.from_date);
|
|
130
|
+
if (q.to_date) params.append("to_date", q.to_date);
|
|
131
|
+
return this.req(`/api/v1/memory/search?${params.toString()}`, {
|
|
132
|
+
method: "GET"
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
update: (id, patch) => this.req(`/api/v1/memories/${encodeURIComponent(id)}`, {
|
|
136
|
+
method: "PATCH",
|
|
137
|
+
body: JSON.stringify({
|
|
138
|
+
content: patch.data ? typeof patch.data === "string" ? patch.data : JSON.stringify(patch.data) : void 0,
|
|
139
|
+
type: patch.type,
|
|
140
|
+
ttl: patch.ttl,
|
|
141
|
+
tags: patch.tags,
|
|
142
|
+
metadata: patch.metadata
|
|
143
|
+
})
|
|
144
|
+
}),
|
|
145
|
+
delete: (id) => this.req(`/api/v1/memories/${encodeURIComponent(id)}`, {
|
|
146
|
+
method: "DELETE"
|
|
147
|
+
}),
|
|
148
|
+
/**
|
|
149
|
+
* Batch create multiple memories in a single request
|
|
150
|
+
* @param memories Array of memory objects to create (max 100)
|
|
151
|
+
* @returns BatchResponse with individual results
|
|
152
|
+
*/
|
|
153
|
+
createBatch: (memories) => {
|
|
154
|
+
const operations = memories.map((mem) => ({
|
|
155
|
+
operation: "create",
|
|
156
|
+
data: {
|
|
157
|
+
content: typeof mem.data === "string" ? mem.data : JSON.stringify(mem.data),
|
|
158
|
+
type: mem.type || "journal",
|
|
159
|
+
tags: mem.tags,
|
|
160
|
+
metadata: mem.metadata,
|
|
161
|
+
thread_id: mem.thread_id
|
|
162
|
+
}
|
|
163
|
+
}));
|
|
164
|
+
return this.req("/api/v1/memory/batch", {
|
|
165
|
+
method: "POST",
|
|
166
|
+
body: JSON.stringify(operations)
|
|
167
|
+
});
|
|
168
|
+
},
|
|
169
|
+
/**
|
|
170
|
+
* Hybrid recall with profile awareness
|
|
171
|
+
* Uses multi-stage pipeline (profile fast-path + lexical + semantic)
|
|
172
|
+
* Guarantees profile facts (name/age/location) when available
|
|
173
|
+
*
|
|
174
|
+
* Use recall() for conversational queries ("who am I?", "what do you know about me?")
|
|
175
|
+
* Use search() for pure semantic topic lookup
|
|
176
|
+
*/
|
|
177
|
+
recall: (q) => {
|
|
178
|
+
const params = new URLSearchParams();
|
|
179
|
+
params.append("query", q.query);
|
|
180
|
+
if (q.thread_id) params.append("thread_id", q.thread_id);
|
|
181
|
+
if (q.limit) params.append("limit", q.limit.toString());
|
|
182
|
+
return this.req(`/api/v1/memory/recall?${params.toString()}`, {
|
|
183
|
+
method: "GET"
|
|
184
|
+
});
|
|
118
185
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
method: "POST",
|
|
191
|
-
body: JSON.stringify(operations),
|
|
192
|
-
});
|
|
193
|
-
},
|
|
194
|
-
/**
|
|
195
|
-
* Hybrid recall with profile awareness
|
|
196
|
-
* Uses multi-stage pipeline (profile fast-path + lexical + semantic)
|
|
197
|
-
* Guarantees profile facts (name/age/location) when available
|
|
198
|
-
*
|
|
199
|
-
* Use recall() for conversational queries ("who am I?", "what do you know about me?")
|
|
200
|
-
* Use search() for pure semantic topic lookup
|
|
201
|
-
*/
|
|
202
|
-
recall: (q) => {
|
|
203
|
-
const params = new URLSearchParams();
|
|
204
|
-
params.append("query", q.query);
|
|
205
|
-
if (q.thread_id)
|
|
206
|
-
params.append("thread_id", q.thread_id);
|
|
207
|
-
if (q.limit)
|
|
208
|
-
params.append("limit", q.limit.toString());
|
|
209
|
-
return this.req(`/api/v1/memory/recall?${params.toString()}`, {
|
|
210
|
-
method: "GET",
|
|
211
|
-
});
|
|
212
|
-
},
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
export class SovantError extends Error {
|
|
216
|
-
code;
|
|
217
|
-
status;
|
|
218
|
-
details;
|
|
219
|
-
constructor(message, code, status, details) {
|
|
220
|
-
super(message);
|
|
221
|
-
this.name = "SovantError";
|
|
222
|
-
this.code = code;
|
|
223
|
-
this.status = status;
|
|
224
|
-
this.details = details;
|
|
186
|
+
};
|
|
187
|
+
threads = {
|
|
188
|
+
/**
|
|
189
|
+
* Create a new thread
|
|
190
|
+
* @param input Thread creation parameters
|
|
191
|
+
* @returns Created thread with ID
|
|
192
|
+
*/
|
|
193
|
+
create: (input) => this.req("/api/v1/threads", {
|
|
194
|
+
method: "POST",
|
|
195
|
+
body: JSON.stringify({
|
|
196
|
+
title: input.title,
|
|
197
|
+
description: input.description,
|
|
198
|
+
metadata: input.metadata
|
|
199
|
+
})
|
|
200
|
+
}),
|
|
201
|
+
/**
|
|
202
|
+
* List threads with optional filtering
|
|
203
|
+
* @param params List parameters
|
|
204
|
+
* @returns Paginated thread list
|
|
205
|
+
*/
|
|
206
|
+
list: (params) => {
|
|
207
|
+
const query = new URLSearchParams();
|
|
208
|
+
if (params?.limit) query.append("limit", params.limit.toString());
|
|
209
|
+
if (params?.offset) query.append("offset", params.offset.toString());
|
|
210
|
+
if (params?.status) query.append("status", params.status);
|
|
211
|
+
return this.req(`/api/v1/threads?${query.toString()}`, {
|
|
212
|
+
method: "GET"
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
/**
|
|
216
|
+
* Get a thread by ID
|
|
217
|
+
* @param threadId Thread UUID
|
|
218
|
+
* @param options Optional parameters
|
|
219
|
+
* @returns Thread details
|
|
220
|
+
*/
|
|
221
|
+
get: (threadId, options) => {
|
|
222
|
+
const query = new URLSearchParams();
|
|
223
|
+
if (options?.include_memories) query.append("include_memories", "true");
|
|
224
|
+
if (options?.limit) query.append("limit", options.limit.toString());
|
|
225
|
+
return this.req(
|
|
226
|
+
`/api/v1/threads/${encodeURIComponent(threadId)}?${query.toString()}`,
|
|
227
|
+
{
|
|
228
|
+
method: "GET"
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
},
|
|
232
|
+
/**
|
|
233
|
+
* Update a thread
|
|
234
|
+
* @param threadId Thread UUID
|
|
235
|
+
* @param updates Fields to update
|
|
236
|
+
* @returns Updated thread
|
|
237
|
+
*/
|
|
238
|
+
update: (threadId, updates) => this.req(`/api/v1/threads/${encodeURIComponent(threadId)}`, {
|
|
239
|
+
method: "PUT",
|
|
240
|
+
body: JSON.stringify(updates)
|
|
241
|
+
}),
|
|
242
|
+
/**
|
|
243
|
+
* Delete a thread
|
|
244
|
+
* @param threadId Thread UUID
|
|
245
|
+
* @param deleteMemories If true, also delete associated memories
|
|
246
|
+
* @returns Deletion confirmation
|
|
247
|
+
*/
|
|
248
|
+
delete: (threadId, deleteMemories = false) => {
|
|
249
|
+
const query = new URLSearchParams();
|
|
250
|
+
if (deleteMemories) query.append("delete_memories", "true");
|
|
251
|
+
return this.req(
|
|
252
|
+
`/api/v1/threads/${encodeURIComponent(threadId)}?${query.toString()}`,
|
|
253
|
+
{
|
|
254
|
+
method: "DELETE"
|
|
255
|
+
}
|
|
256
|
+
);
|
|
225
257
|
}
|
|
226
|
-
}
|
|
227
|
-
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
var SovantError = class extends Error {
|
|
261
|
+
code;
|
|
262
|
+
status;
|
|
263
|
+
details;
|
|
264
|
+
constructor(message, code, status, details) {
|
|
265
|
+
super(message);
|
|
266
|
+
this.name = "SovantError";
|
|
267
|
+
this.code = code;
|
|
268
|
+
this.status = status;
|
|
269
|
+
this.details = details;
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
export {
|
|
273
|
+
Sovant,
|
|
274
|
+
SovantError
|
|
275
|
+
};
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sovant/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Official Sovant Memory-as-a-Service SDK for JavaScript and TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
10
11
|
"import": "./dist/index.js",
|
|
11
|
-
"require": "./dist/index.cjs"
|
|
12
|
-
"types": "./dist/index.d.ts"
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
"LICENSE"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"build": "
|
|
22
|
-
"
|
|
21
|
+
"build": "tsup src/index.ts --format esm,cjs --dts --clean",
|
|
22
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
23
|
+
"prepublishOnly": "npm run typecheck && npm run build",
|
|
23
24
|
"lint": "eslint .",
|
|
24
25
|
"format": "prettier -w ."
|
|
25
26
|
},
|
|
@@ -48,6 +49,7 @@
|
|
|
48
49
|
"@types/node": "^24.10.0",
|
|
49
50
|
"eslint": "^9.9.0",
|
|
50
51
|
"prettier": "^3.3.3",
|
|
52
|
+
"tsup": "^8.5.1",
|
|
51
53
|
"typescript": "^5.6.2"
|
|
52
54
|
}
|
|
53
55
|
}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|