@t0ken.ai/memoryx-openclaw-plugin 1.1.18 → 2.0.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/README.md +14 -0
- package/dist/index.d.ts +13 -43
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +173 -475
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -48,6 +48,20 @@ openclaw plugins install @t0ken.ai/memoryx-openclaw-plugin
|
|
|
48
48
|
openclaw gateway restart
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
## Update
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
openclaw plugins update @t0ken.ai/memoryx-openclaw-plugin
|
|
55
|
+
openclaw gateway restart
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Or update all plugins:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
openclaw plugins update --all
|
|
62
|
+
openclaw gateway restart
|
|
63
|
+
```
|
|
64
|
+
|
|
51
65
|
## Configuration
|
|
52
66
|
|
|
53
67
|
Edit `~/.openclaw/openclaw.json`:
|
package/dist/index.d.ts
CHANGED
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
* 3. Use dynamic import() for better-sqlite3: await import("better-sqlite3")
|
|
19
19
|
* 4. Use setImmediate() for deferred operations
|
|
20
20
|
*
|
|
21
|
-
*
|
|
21
|
+
* This version uses @t0ken.ai/memoryx-sdk with conversation preset:
|
|
22
|
+
* - maxTokens: 30000 (flush when reaching token limit)
|
|
23
|
+
* - intervalMs: 300000 (flush after 5 minutes idle)
|
|
22
24
|
*/
|
|
23
25
|
interface PluginConfig {
|
|
24
26
|
apiBaseUrl?: string;
|
|
@@ -40,44 +42,11 @@ interface RecallResult {
|
|
|
40
42
|
remainingQuota: number;
|
|
41
43
|
upgradeHint?: string;
|
|
42
44
|
}
|
|
43
|
-
declare class ConversationManager {
|
|
44
|
-
private currentConversationId;
|
|
45
|
-
private conversationCreatedAt;
|
|
46
|
-
private lastActivityAt;
|
|
47
|
-
private readonly ROUND_THRESHOLD;
|
|
48
|
-
private readonly TIMEOUT_MS;
|
|
49
|
-
constructor();
|
|
50
|
-
private generateId;
|
|
51
|
-
getConversationId(): string;
|
|
52
|
-
addMessage(role: string, content: string): Promise<boolean>;
|
|
53
|
-
shouldFlush(): Promise<boolean>;
|
|
54
|
-
startNewConversation(): void;
|
|
55
|
-
getStatus(): Promise<{
|
|
56
|
-
messageCount: number;
|
|
57
|
-
conversationId: string;
|
|
58
|
-
rounds: number;
|
|
59
|
-
}>;
|
|
60
|
-
}
|
|
61
45
|
declare class MemoryXPlugin {
|
|
62
|
-
private config;
|
|
63
|
-
private conversationManager;
|
|
64
|
-
private flushTimer;
|
|
65
|
-
private sendQueueTimer;
|
|
66
|
-
private readonly FLUSH_CHECK_INTERVAL;
|
|
67
|
-
private readonly SEND_QUEUE_INTERVAL;
|
|
68
|
-
private readonly MAX_RETRY_COUNT;
|
|
69
46
|
private pluginConfig;
|
|
70
47
|
private initialized;
|
|
71
48
|
constructor(pluginConfig?: PluginConfig);
|
|
72
|
-
init(): void
|
|
73
|
-
private get apiBase();
|
|
74
|
-
private loadConfig;
|
|
75
|
-
private saveConfig;
|
|
76
|
-
private autoRegister;
|
|
77
|
-
private getMachineFingerprint;
|
|
78
|
-
private startFlushTimer;
|
|
79
|
-
private startSendQueueTimer;
|
|
80
|
-
private processSendQueue;
|
|
49
|
+
init(): Promise<void>;
|
|
81
50
|
onMessage(role: string, content: string): Promise<boolean>;
|
|
82
51
|
recall(query: string, limit?: number): Promise<RecallResult>;
|
|
83
52
|
endConversation(): Promise<void>;
|
|
@@ -85,18 +54,19 @@ declare class MemoryXPlugin {
|
|
|
85
54
|
store(content: string): Promise<{
|
|
86
55
|
success: boolean;
|
|
87
56
|
task_id?: string;
|
|
88
|
-
duplicate?: boolean;
|
|
89
|
-
existing?: string;
|
|
90
57
|
}>;
|
|
91
58
|
list(limit?: number): Promise<any[]>;
|
|
92
59
|
getStatus(): Promise<{
|
|
93
60
|
initialized: boolean;
|
|
94
61
|
hasApiKey: boolean;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
62
|
+
queueStats: any;
|
|
63
|
+
}>;
|
|
64
|
+
getAccountInfo(): Promise<{
|
|
65
|
+
apiKey: string | null;
|
|
66
|
+
projectId: string;
|
|
67
|
+
userId: string | null;
|
|
68
|
+
apiBaseUrl: string;
|
|
69
|
+
initialized: boolean;
|
|
100
70
|
}>;
|
|
101
71
|
}
|
|
102
72
|
declare const _default: {
|
|
@@ -107,5 +77,5 @@ declare const _default: {
|
|
|
107
77
|
register(api: any, pluginConfig?: PluginConfig): void;
|
|
108
78
|
};
|
|
109
79
|
export default _default;
|
|
110
|
-
export { MemoryXPlugin
|
|
80
|
+
export { MemoryXPlugin };
|
|
111
81
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAkCH,UAAU,YAAY;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,YAAY;IAClB,QAAQ,EAAE,KAAK,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;IACH,eAAe,EAAE,KAAK,CAAC;QACnB,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;IACH,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAmCD,cAAM,aAAa;IACf,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,WAAW,CAAkB;gBAEzB,YAAY,CAAC,EAAE,YAAY;IAIjC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAad,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAiC1D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IA6B/D,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAUhC,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAc1C,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAcvE,IAAI,CAAC,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAiBxC,SAAS,IAAI,OAAO,CAAC;QAC9B,WAAW,EAAE,OAAO,CAAC;QACrB,SAAS,EAAE,OAAO,CAAC;QACnB,UAAU,EAAE,GAAG,CAAC;KACnB,CAAC;IAoBW,cAAc,IAAI,OAAO,CAAC;QACnC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,OAAO,CAAC;KACxB,CAAC;CAuBL;;;;;;kBAUiB,GAAG,iBAAiB,YAAY,GAAG,IAAI;;AANzD,wBA0XE;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -18,32 +18,17 @@
|
|
|
18
18
|
* 3. Use dynamic import() for better-sqlite3: await import("better-sqlite3")
|
|
19
19
|
* 4. Use setImmediate() for deferred operations
|
|
20
20
|
*
|
|
21
|
-
*
|
|
21
|
+
* This version uses @t0ken.ai/memoryx-sdk with conversation preset:
|
|
22
|
+
* - maxTokens: 30000 (flush when reaching token limit)
|
|
23
|
+
* - intervalMs: 300000 (flush after 5 minutes idle)
|
|
22
24
|
*/
|
|
23
25
|
import * as fs from "fs";
|
|
24
26
|
import * as path from "path";
|
|
25
27
|
import * as os from "os";
|
|
26
|
-
import * as crypto from "crypto";
|
|
27
|
-
import { getEncoding } from "js-tiktoken";
|
|
28
28
|
const DEFAULT_API_BASE = "https://t0ken.ai/api";
|
|
29
29
|
const PLUGIN_DIR = path.join(os.homedir(), ".openclaw", "extensions", "memoryx-openclaw-plugin");
|
|
30
30
|
let logStream = null;
|
|
31
31
|
let logStreamReady = false;
|
|
32
|
-
let tokenizer = null;
|
|
33
|
-
function getTokenizer() {
|
|
34
|
-
if (!tokenizer) {
|
|
35
|
-
tokenizer = getEncoding("cl100k_base");
|
|
36
|
-
}
|
|
37
|
-
return tokenizer;
|
|
38
|
-
}
|
|
39
|
-
function countTokens(text) {
|
|
40
|
-
try {
|
|
41
|
-
return getTokenizer().encode(text).length;
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
return Math.ceil(text.length / 4);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
32
|
function ensureDir() {
|
|
48
33
|
if (!fs.existsSync(PLUGIN_DIR)) {
|
|
49
34
|
fs.mkdirSync(PLUGIN_DIR, { recursive: true });
|
|
@@ -65,359 +50,58 @@ function log(message) {
|
|
|
65
50
|
}
|
|
66
51
|
});
|
|
67
52
|
}
|
|
68
|
-
|
|
69
|
-
let
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
CREATE INDEX IF NOT EXISTS idx_send_queue_created ON send_queue(conversation_created_at);
|
|
95
|
-
CREATE INDEX IF NOT EXISTS idx_send_queue_conversation ON send_queue(conversation_id);
|
|
96
|
-
`);
|
|
97
|
-
return db;
|
|
53
|
+
// Lazy-loaded SDK instance
|
|
54
|
+
let sdkInstance = null;
|
|
55
|
+
let sdkInitPromise = null;
|
|
56
|
+
async function getSDK(pluginConfig) {
|
|
57
|
+
if (sdkInstance)
|
|
58
|
+
return sdkInstance;
|
|
59
|
+
if (sdkInitPromise)
|
|
60
|
+
return sdkInitPromise;
|
|
61
|
+
sdkInitPromise = (async () => {
|
|
62
|
+
// Dynamic import SDK
|
|
63
|
+
const { MemoryXSDK } = await import("@t0ken.ai/memoryx-sdk");
|
|
64
|
+
// Use conversation preset: maxTokens: 30000, intervalMs: 300000 (5 min)
|
|
65
|
+
sdkInstance = new MemoryXSDK({
|
|
66
|
+
preset: 'conversation',
|
|
67
|
+
apiUrl: pluginConfig?.apiBaseUrl || DEFAULT_API_BASE,
|
|
68
|
+
autoRegister: true,
|
|
69
|
+
agentType: 'openclaw',
|
|
70
|
+
storageDir: PLUGIN_DIR
|
|
71
|
+
});
|
|
72
|
+
// Set debug mode
|
|
73
|
+
const { setDebug } = await import("@t0ken.ai/memoryx-sdk");
|
|
74
|
+
setDebug(true);
|
|
75
|
+
log("SDK initialized with conversation preset (30k tokens / 5min idle)");
|
|
76
|
+
return sdkInstance;
|
|
98
77
|
})();
|
|
99
|
-
return
|
|
100
|
-
}
|
|
101
|
-
class SQLiteStorage {
|
|
102
|
-
static async loadConfig() {
|
|
103
|
-
try {
|
|
104
|
-
const db = await getDb();
|
|
105
|
-
const row = db.prepare("SELECT value FROM config WHERE key = 'config'").get();
|
|
106
|
-
if (row) {
|
|
107
|
-
return JSON.parse(row.value);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
catch (e) {
|
|
111
|
-
log(`Failed to load config: ${e}`);
|
|
112
|
-
}
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
static async saveConfig(config) {
|
|
116
|
-
try {
|
|
117
|
-
const db = await getDb();
|
|
118
|
-
db.prepare("INSERT OR REPLACE INTO config (key, value) VALUES ('config', ?)").run(JSON.stringify(config));
|
|
119
|
-
}
|
|
120
|
-
catch (e) {
|
|
121
|
-
log(`Failed to save config: ${e}`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
static async addConversationToQueue(conversationId, conversationCreatedAt, messages) {
|
|
125
|
-
const db = await getDb();
|
|
126
|
-
const stmt = db.prepare(`
|
|
127
|
-
INSERT INTO send_queue (conversation_id, conversation_created_at, role, content, timestamp)
|
|
128
|
-
VALUES (?, ?, ?, ?, ?)
|
|
129
|
-
`);
|
|
130
|
-
for (const msg of messages) {
|
|
131
|
-
stmt.run(conversationId, conversationCreatedAt, msg.role, msg.content, msg.timestamp);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
static async getNextConversation() {
|
|
135
|
-
const db = await getDb();
|
|
136
|
-
const row = db.prepare(`
|
|
137
|
-
SELECT conversation_id, MIN(conversation_created_at) as conversation_created_at
|
|
138
|
-
FROM send_queue
|
|
139
|
-
GROUP BY conversation_id
|
|
140
|
-
ORDER BY MIN(conversation_created_at) ASC
|
|
141
|
-
LIMIT 1
|
|
142
|
-
`).get();
|
|
143
|
-
if (!row)
|
|
144
|
-
return null;
|
|
145
|
-
const messages = db.prepare(`
|
|
146
|
-
SELECT id, conversation_id, conversation_created_at, role, content, timestamp, retry_count
|
|
147
|
-
FROM send_queue
|
|
148
|
-
WHERE conversation_id = ?
|
|
149
|
-
ORDER BY id ASC
|
|
150
|
-
`).all(row.conversation_id);
|
|
151
|
-
return {
|
|
152
|
-
conversationId: row.conversation_id,
|
|
153
|
-
conversationCreatedAt: row.conversation_created_at,
|
|
154
|
-
messages
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
static async deleteConversation(conversationId) {
|
|
158
|
-
const db = await getDb();
|
|
159
|
-
db.prepare("DELETE FROM send_queue WHERE conversation_id = ?").run(conversationId);
|
|
160
|
-
}
|
|
161
|
-
static async incrementRetryByConversation(conversationId) {
|
|
162
|
-
const db = await getDb();
|
|
163
|
-
db.prepare("UPDATE send_queue SET retry_count = retry_count + 1 WHERE conversation_id = ?").run(conversationId);
|
|
164
|
-
}
|
|
165
|
-
static async getQueueStats(conversationId) {
|
|
166
|
-
const db = await getDb();
|
|
167
|
-
const rows = db.prepare(`
|
|
168
|
-
SELECT role FROM send_queue
|
|
169
|
-
WHERE conversation_id = ?
|
|
170
|
-
ORDER BY id ASC
|
|
171
|
-
`).all(conversationId);
|
|
172
|
-
let rounds = 0;
|
|
173
|
-
let lastRole = "";
|
|
174
|
-
for (const row of rows) {
|
|
175
|
-
if (row.role === "assistant" && lastRole === "user") {
|
|
176
|
-
rounds++;
|
|
177
|
-
}
|
|
178
|
-
lastRole = row.role;
|
|
179
|
-
}
|
|
180
|
-
return { count: rows.length, rounds };
|
|
181
|
-
}
|
|
182
|
-
static async clearOldConversations(maxAge = 7 * 24 * 60 * 60) {
|
|
183
|
-
const db = await getDb();
|
|
184
|
-
const cutoff = Math.floor(Date.now() / 1000) - maxAge;
|
|
185
|
-
db.prepare("DELETE FROM send_queue WHERE conversation_created_at < ?").run(cutoff);
|
|
186
|
-
}
|
|
187
|
-
static async getQueueLength() {
|
|
188
|
-
const db = await getDb();
|
|
189
|
-
const row = db.prepare("SELECT COUNT(DISTINCT conversation_id) as count FROM send_queue").get();
|
|
190
|
-
return row?.count || 0;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
class ConversationManager {
|
|
194
|
-
currentConversationId = "";
|
|
195
|
-
conversationCreatedAt = Math.floor(Date.now() / 1000);
|
|
196
|
-
lastActivityAt = Date.now();
|
|
197
|
-
ROUND_THRESHOLD = 2;
|
|
198
|
-
TIMEOUT_MS = 30 * 60 * 1000;
|
|
199
|
-
constructor() {
|
|
200
|
-
this.currentConversationId = this.generateId();
|
|
201
|
-
}
|
|
202
|
-
generateId() {
|
|
203
|
-
return `conv_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
204
|
-
}
|
|
205
|
-
getConversationId() {
|
|
206
|
-
return this.currentConversationId;
|
|
207
|
-
}
|
|
208
|
-
async addMessage(role, content) {
|
|
209
|
-
if (!content || content.length < 2) {
|
|
210
|
-
return false;
|
|
211
|
-
}
|
|
212
|
-
const db = await getDb();
|
|
213
|
-
db.prepare(`
|
|
214
|
-
INSERT INTO send_queue (conversation_id, conversation_created_at, role, content, timestamp)
|
|
215
|
-
VALUES (?, ?, ?, ?, ?)
|
|
216
|
-
`).run(this.currentConversationId, this.conversationCreatedAt, role, content, Date.now());
|
|
217
|
-
this.lastActivityAt = Date.now();
|
|
218
|
-
const stats = await SQLiteStorage.getQueueStats(this.currentConversationId);
|
|
219
|
-
return stats.rounds >= this.ROUND_THRESHOLD;
|
|
220
|
-
}
|
|
221
|
-
async shouldFlush() {
|
|
222
|
-
const stats = await SQLiteStorage.getQueueStats(this.currentConversationId);
|
|
223
|
-
if (stats.count === 0) {
|
|
224
|
-
return false;
|
|
225
|
-
}
|
|
226
|
-
if (stats.rounds >= this.ROUND_THRESHOLD) {
|
|
227
|
-
return true;
|
|
228
|
-
}
|
|
229
|
-
const elapsed = Date.now() - this.lastActivityAt;
|
|
230
|
-
if (elapsed > this.TIMEOUT_MS) {
|
|
231
|
-
return true;
|
|
232
|
-
}
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
startNewConversation() {
|
|
236
|
-
this.currentConversationId = this.generateId();
|
|
237
|
-
this.conversationCreatedAt = Math.floor(Date.now() / 1000);
|
|
238
|
-
this.lastActivityAt = Date.now();
|
|
239
|
-
}
|
|
240
|
-
async getStatus() {
|
|
241
|
-
const stats = await SQLiteStorage.getQueueStats(this.currentConversationId);
|
|
242
|
-
return {
|
|
243
|
-
messageCount: stats.count,
|
|
244
|
-
conversationId: this.currentConversationId,
|
|
245
|
-
rounds: stats.rounds
|
|
246
|
-
};
|
|
247
|
-
}
|
|
78
|
+
return sdkInitPromise;
|
|
248
79
|
}
|
|
249
80
|
class MemoryXPlugin {
|
|
250
|
-
|
|
251
|
-
apiKey: null,
|
|
252
|
-
projectId: "default",
|
|
253
|
-
userId: null,
|
|
254
|
-
initialized: false,
|
|
255
|
-
apiBaseUrl: DEFAULT_API_BASE
|
|
256
|
-
};
|
|
257
|
-
conversationManager = new ConversationManager();
|
|
258
|
-
flushTimer = null;
|
|
259
|
-
sendQueueTimer = null;
|
|
260
|
-
FLUSH_CHECK_INTERVAL = 30000;
|
|
261
|
-
SEND_QUEUE_INTERVAL = 5000;
|
|
262
|
-
MAX_RETRY_COUNT = 5;
|
|
263
|
-
pluginConfig = null;
|
|
81
|
+
pluginConfig;
|
|
264
82
|
initialized = false;
|
|
265
83
|
constructor(pluginConfig) {
|
|
266
|
-
this.pluginConfig = pluginConfig
|
|
267
|
-
if (pluginConfig?.apiBaseUrl) {
|
|
268
|
-
this.config.apiBaseUrl = pluginConfig.apiBaseUrl;
|
|
269
|
-
}
|
|
270
|
-
this.config.initialized = true;
|
|
84
|
+
this.pluginConfig = pluginConfig;
|
|
271
85
|
}
|
|
272
|
-
init() {
|
|
86
|
+
async init() {
|
|
273
87
|
if (this.initialized)
|
|
274
88
|
return;
|
|
275
89
|
this.initialized = true;
|
|
276
90
|
log("Async init started");
|
|
277
|
-
this.loadConfig().then(() => {
|
|
278
|
-
log(`Config loaded, apiKey: ${this.config.apiKey ? 'present' : 'missing'}`);
|
|
279
|
-
this.startFlushTimer();
|
|
280
|
-
this.startSendQueueTimer();
|
|
281
|
-
SQLiteStorage.clearOldConversations().catch(() => { });
|
|
282
|
-
this.processSendQueue();
|
|
283
|
-
if (!this.config.apiKey) {
|
|
284
|
-
log("Starting auto-register");
|
|
285
|
-
this.autoRegister().catch(e => log(`Auto-register failed: ${e}`));
|
|
286
|
-
}
|
|
287
|
-
}).catch(e => log(`Init failed: ${e}`));
|
|
288
|
-
}
|
|
289
|
-
get apiBase() {
|
|
290
|
-
return this.config.apiBaseUrl || DEFAULT_API_BASE;
|
|
291
|
-
}
|
|
292
|
-
async loadConfig() {
|
|
293
|
-
const stored = await SQLiteStorage.loadConfig();
|
|
294
|
-
if (stored) {
|
|
295
|
-
this.config = {
|
|
296
|
-
...this.config,
|
|
297
|
-
...stored,
|
|
298
|
-
apiBaseUrl: this.pluginConfig?.apiBaseUrl || stored.apiBaseUrl || this.config.apiBaseUrl
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
async saveConfig() {
|
|
303
|
-
await SQLiteStorage.saveConfig(this.config);
|
|
304
|
-
}
|
|
305
|
-
async autoRegister() {
|
|
306
91
|
try {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
method: "POST",
|
|
310
|
-
headers: { "Content-Type": "application/json" },
|
|
311
|
-
body: JSON.stringify({
|
|
312
|
-
machine_fingerprint: fingerprint,
|
|
313
|
-
agent_type: "openclaw",
|
|
314
|
-
agent_name: "openclaw-agent",
|
|
315
|
-
platform: os.platform(),
|
|
316
|
-
platform_version: os.release()
|
|
317
|
-
})
|
|
318
|
-
});
|
|
319
|
-
if (!response.ok) {
|
|
320
|
-
throw new Error(`Auto-register failed: ${response.status}`);
|
|
321
|
-
}
|
|
322
|
-
const data = await response.json();
|
|
323
|
-
this.config.apiKey = data.api_key;
|
|
324
|
-
this.config.projectId = String(data.project_id);
|
|
325
|
-
this.config.userId = data.agent_id;
|
|
326
|
-
await this.saveConfig();
|
|
327
|
-
log("Auto-registered successfully");
|
|
92
|
+
await getSDK(this.pluginConfig);
|
|
93
|
+
log("SDK ready");
|
|
328
94
|
}
|
|
329
95
|
catch (e) {
|
|
330
|
-
log(`
|
|
96
|
+
log(`Init failed: ${e}`);
|
|
331
97
|
}
|
|
332
98
|
}
|
|
333
|
-
getMachineFingerprint() {
|
|
334
|
-
const components = [
|
|
335
|
-
os.hostname(),
|
|
336
|
-
os.platform(),
|
|
337
|
-
os.arch(),
|
|
338
|
-
os.cpus()[0]?.model || "unknown",
|
|
339
|
-
os.totalmem()
|
|
340
|
-
];
|
|
341
|
-
const raw = components.join("|");
|
|
342
|
-
return crypto.createHash("sha256").update(raw).digest("hex").slice(0, 32);
|
|
343
|
-
}
|
|
344
|
-
startFlushTimer() {
|
|
345
|
-
this.flushTimer = setInterval(async () => {
|
|
346
|
-
if (await this.conversationManager.shouldFlush()) {
|
|
347
|
-
this.conversationManager.startNewConversation();
|
|
348
|
-
}
|
|
349
|
-
}, this.FLUSH_CHECK_INTERVAL);
|
|
350
|
-
}
|
|
351
|
-
startSendQueueTimer() {
|
|
352
|
-
this.sendQueueTimer = setInterval(() => {
|
|
353
|
-
this.processSendQueue();
|
|
354
|
-
}, this.SEND_QUEUE_INTERVAL);
|
|
355
|
-
}
|
|
356
|
-
async processSendQueue() {
|
|
357
|
-
if (isSending)
|
|
358
|
-
return;
|
|
359
|
-
if (!this.config.apiKey)
|
|
360
|
-
return;
|
|
361
|
-
isSending = true;
|
|
362
|
-
try {
|
|
363
|
-
await SQLiteStorage.clearOldConversations();
|
|
364
|
-
const conversation = await SQLiteStorage.getNextConversation();
|
|
365
|
-
if (!conversation) {
|
|
366
|
-
isSending = false;
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
const { conversationId, messages } = conversation;
|
|
370
|
-
const maxRetry = Math.max(...messages.map(m => m.retry_count));
|
|
371
|
-
if (maxRetry >= this.MAX_RETRY_COUNT) {
|
|
372
|
-
log(`Deleting conversation ${conversationId}: max retries exceeded`);
|
|
373
|
-
await SQLiteStorage.deleteConversation(conversationId);
|
|
374
|
-
isSending = false;
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
log(`Sending conversation ${conversationId} (${messages.length} messages)`);
|
|
378
|
-
try {
|
|
379
|
-
const response = await fetch(`${this.apiBase}/v1/conversations/flush`, {
|
|
380
|
-
method: "POST",
|
|
381
|
-
headers: {
|
|
382
|
-
"Content-Type": "application/json",
|
|
383
|
-
"X-API-Key": this.config.apiKey
|
|
384
|
-
},
|
|
385
|
-
body: JSON.stringify({
|
|
386
|
-
conversation_id: conversationId,
|
|
387
|
-
messages: messages.map(m => ({
|
|
388
|
-
role: m.role,
|
|
389
|
-
content: m.content,
|
|
390
|
-
timestamp: m.timestamp,
|
|
391
|
-
tokens: countTokens(m.content)
|
|
392
|
-
}))
|
|
393
|
-
})
|
|
394
|
-
});
|
|
395
|
-
if (response.ok) {
|
|
396
|
-
await SQLiteStorage.deleteConversation(conversationId);
|
|
397
|
-
const result = await response.json();
|
|
398
|
-
log(`Sent conversation ${conversationId}, extracted ${result.extracted_count || 0} memories`);
|
|
399
|
-
}
|
|
400
|
-
else {
|
|
401
|
-
await SQLiteStorage.incrementRetryByConversation(conversationId);
|
|
402
|
-
const errorData = await response.json().catch(() => ({}));
|
|
403
|
-
log(`Failed to send conversation ${conversationId}: ${response.status} ${JSON.stringify(errorData)}`);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
catch (e) {
|
|
407
|
-
await SQLiteStorage.incrementRetryByConversation(conversationId);
|
|
408
|
-
log(`Error sending conversation ${conversationId}: ${e}`);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
catch (e) {
|
|
412
|
-
log(`Process send queue failed: ${e}`);
|
|
413
|
-
}
|
|
414
|
-
isSending = false;
|
|
415
|
-
}
|
|
416
99
|
async onMessage(role, content) {
|
|
417
|
-
this.init();
|
|
100
|
+
await this.init();
|
|
418
101
|
if (!content || content.length < 2) {
|
|
419
102
|
return false;
|
|
420
103
|
}
|
|
104
|
+
// Skip short messages
|
|
421
105
|
const skipPatterns = [
|
|
422
106
|
/^[好的ok谢谢嗯啊哈哈你好hihello拜拜再见]{1,5}$/i,
|
|
423
107
|
/^[??!!。,,\s]{1,10}$/
|
|
@@ -427,59 +111,41 @@ class MemoryXPlugin {
|
|
|
427
111
|
return false;
|
|
428
112
|
}
|
|
429
113
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
114
|
+
try {
|
|
115
|
+
const sdk = await getSDK(this.pluginConfig);
|
|
116
|
+
if (role === 'user') {
|
|
117
|
+
await sdk.addUserMessage(content);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
await sdk.addAssistantMessage(content);
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
log(`onMessage failed: ${e}`);
|
|
126
|
+
return false;
|
|
433
127
|
}
|
|
434
|
-
return true;
|
|
435
128
|
}
|
|
436
129
|
async recall(query, limit = 5) {
|
|
437
|
-
this.init();
|
|
438
|
-
if (!this.config.apiKey || !query || query.length < 2) {
|
|
439
|
-
return { memories: [], relatedMemories: [], isLimited: false, remainingQuota: 0 };
|
|
440
|
-
}
|
|
130
|
+
await this.init();
|
|
441
131
|
try {
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
headers: {
|
|
445
|
-
"Content-Type": "application/json",
|
|
446
|
-
"X-API-Key": this.config.apiKey
|
|
447
|
-
},
|
|
448
|
-
body: JSON.stringify({
|
|
449
|
-
query,
|
|
450
|
-
project_id: this.config.projectId,
|
|
451
|
-
limit
|
|
452
|
-
})
|
|
453
|
-
});
|
|
454
|
-
if (!response.ok) {
|
|
455
|
-
const errorData = await response.json().catch(() => ({}));
|
|
456
|
-
if (response.status === 402 || response.status === 429) {
|
|
457
|
-
return {
|
|
458
|
-
memories: [],
|
|
459
|
-
relatedMemories: [],
|
|
460
|
-
isLimited: true,
|
|
461
|
-
remainingQuota: 0,
|
|
462
|
-
upgradeHint: errorData.detail || "云端查询配额已用尽,请升级到付费版"
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
throw new Error(`Search failed: ${response.status}`);
|
|
466
|
-
}
|
|
467
|
-
const data = await response.json();
|
|
132
|
+
const sdk = await getSDK(this.pluginConfig);
|
|
133
|
+
const result = await sdk.search(query, limit);
|
|
468
134
|
return {
|
|
469
|
-
memories: (
|
|
135
|
+
memories: (result.data || []).map((m) => ({
|
|
470
136
|
id: m.id,
|
|
471
|
-
content: m.
|
|
137
|
+
content: m.content || m.memory,
|
|
472
138
|
category: m.category || "other",
|
|
473
139
|
score: m.score || 0.5
|
|
474
140
|
})),
|
|
475
|
-
relatedMemories: (
|
|
141
|
+
relatedMemories: (result.related_memories || []).map((m) => ({
|
|
476
142
|
id: m.id,
|
|
477
|
-
content: m.
|
|
143
|
+
content: m.content || m.memory,
|
|
478
144
|
category: m.category || "other",
|
|
479
145
|
score: m.score || 0
|
|
480
146
|
})),
|
|
481
147
|
isLimited: false,
|
|
482
|
-
remainingQuota:
|
|
148
|
+
remainingQuota: result.remaining_quota ?? -1
|
|
483
149
|
};
|
|
484
150
|
}
|
|
485
151
|
catch (e) {
|
|
@@ -488,28 +154,22 @@ class MemoryXPlugin {
|
|
|
488
154
|
}
|
|
489
155
|
}
|
|
490
156
|
async endConversation() {
|
|
491
|
-
|
|
492
|
-
|
|
157
|
+
try {
|
|
158
|
+
const sdk = await getSDK(this.pluginConfig);
|
|
159
|
+
sdk.startNewConversation();
|
|
160
|
+
log("Conversation ended, starting new conversation");
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
log(`End conversation failed: ${e}`);
|
|
164
|
+
}
|
|
493
165
|
}
|
|
494
166
|
async forget(memoryId) {
|
|
495
|
-
this.init();
|
|
496
|
-
if (!this.config.apiKey) {
|
|
497
|
-
log("Forget failed: no API key");
|
|
498
|
-
return false;
|
|
499
|
-
}
|
|
167
|
+
await this.init();
|
|
500
168
|
try {
|
|
501
|
-
const
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
});
|
|
507
|
-
if (response.ok) {
|
|
508
|
-
log(`Forgot memory ${memoryId}`);
|
|
509
|
-
return true;
|
|
510
|
-
}
|
|
511
|
-
log(`Forget failed: ${response.status}`);
|
|
512
|
-
return false;
|
|
169
|
+
const sdk = await getSDK(this.pluginConfig);
|
|
170
|
+
await sdk.delete(memoryId);
|
|
171
|
+
log(`Forgot memory ${memoryId}`);
|
|
172
|
+
return true;
|
|
513
173
|
}
|
|
514
174
|
catch (e) {
|
|
515
175
|
log(`Forget failed: ${e}`);
|
|
@@ -517,32 +177,12 @@ class MemoryXPlugin {
|
|
|
517
177
|
}
|
|
518
178
|
}
|
|
519
179
|
async store(content) {
|
|
520
|
-
this.init();
|
|
521
|
-
if (!this.config.apiKey) {
|
|
522
|
-
log("Store failed: no API key");
|
|
523
|
-
return { success: false };
|
|
524
|
-
}
|
|
180
|
+
await this.init();
|
|
525
181
|
try {
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
"X-API-Key": this.config.apiKey
|
|
531
|
-
},
|
|
532
|
-
body: JSON.stringify({
|
|
533
|
-
content,
|
|
534
|
-
project_id: this.config.projectId,
|
|
535
|
-
metadata: { source: "function_call" }
|
|
536
|
-
})
|
|
537
|
-
});
|
|
538
|
-
if (!response.ok) {
|
|
539
|
-
const errorData = await response.json().catch(() => ({}));
|
|
540
|
-
log(`Store failed: ${response.status} ${JSON.stringify(errorData)}`);
|
|
541
|
-
return { success: false };
|
|
542
|
-
}
|
|
543
|
-
const data = await response.json();
|
|
544
|
-
log(`Stored memory, task_id: ${data.task_id}`);
|
|
545
|
-
return { success: true, task_id: data.task_id };
|
|
182
|
+
const sdk = await getSDK(this.pluginConfig);
|
|
183
|
+
const result = await sdk.addMemory(content);
|
|
184
|
+
log(`Stored memory, result: ${JSON.stringify(result)}`);
|
|
185
|
+
return { success: true, task_id: result?.task_id };
|
|
546
186
|
}
|
|
547
187
|
catch (e) {
|
|
548
188
|
log(`Store failed: ${e}`);
|
|
@@ -550,32 +190,13 @@ class MemoryXPlugin {
|
|
|
550
190
|
}
|
|
551
191
|
}
|
|
552
192
|
async list(limit = 10) {
|
|
553
|
-
this.init();
|
|
554
|
-
if (!this.config.apiKey) {
|
|
555
|
-
log("List failed: no API key");
|
|
556
|
-
return [];
|
|
557
|
-
}
|
|
193
|
+
await this.init();
|
|
558
194
|
try {
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
"Content-Type": "application/json",
|
|
563
|
-
"X-API-Key": this.config.apiKey
|
|
564
|
-
},
|
|
565
|
-
body: JSON.stringify({
|
|
566
|
-
query: "*",
|
|
567
|
-
project_id: this.config.projectId,
|
|
568
|
-
limit
|
|
569
|
-
})
|
|
570
|
-
});
|
|
571
|
-
if (!response.ok) {
|
|
572
|
-
log(`List failed: ${response.status}`);
|
|
573
|
-
return [];
|
|
574
|
-
}
|
|
575
|
-
const data = await response.json();
|
|
576
|
-
return (data.data || []).map((m) => ({
|
|
195
|
+
const sdk = await getSDK(this.pluginConfig);
|
|
196
|
+
const result = await sdk.list(limit, 0);
|
|
197
|
+
return (result.data || result.memories || []).map((m) => ({
|
|
577
198
|
id: m.id,
|
|
578
|
-
content: m.
|
|
199
|
+
content: m.content || m.memory,
|
|
579
200
|
category: m.category || "other"
|
|
580
201
|
}));
|
|
581
202
|
}
|
|
@@ -585,20 +206,54 @@ class MemoryXPlugin {
|
|
|
585
206
|
}
|
|
586
207
|
}
|
|
587
208
|
async getStatus() {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
209
|
+
try {
|
|
210
|
+
const sdk = await getSDK(this.pluginConfig);
|
|
211
|
+
const accountInfo = await sdk.getAccountInfo();
|
|
212
|
+
const queueStats = await sdk.getQueueStats();
|
|
213
|
+
return {
|
|
214
|
+
initialized: true,
|
|
215
|
+
hasApiKey: !!accountInfo?.apiKey,
|
|
216
|
+
queueStats
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
catch (e) {
|
|
220
|
+
return {
|
|
221
|
+
initialized: false,
|
|
222
|
+
hasApiKey: false,
|
|
223
|
+
queueStats: null
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
async getAccountInfo() {
|
|
228
|
+
await this.init();
|
|
229
|
+
try {
|
|
230
|
+
const sdk = await getSDK(this.pluginConfig);
|
|
231
|
+
const info = await sdk.getAccountInfo();
|
|
232
|
+
return {
|
|
233
|
+
apiKey: info?.apiKey || null,
|
|
234
|
+
projectId: info?.projectId || "default",
|
|
235
|
+
userId: info?.userId || null,
|
|
236
|
+
apiBaseUrl: info?.apiBaseUrl || DEFAULT_API_BASE,
|
|
237
|
+
initialized: true
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
catch (e) {
|
|
241
|
+
return {
|
|
242
|
+
apiKey: null,
|
|
243
|
+
projectId: "default",
|
|
244
|
+
userId: null,
|
|
245
|
+
apiBaseUrl: DEFAULT_API_BASE,
|
|
246
|
+
initialized: false
|
|
247
|
+
};
|
|
248
|
+
}
|
|
594
249
|
}
|
|
595
250
|
}
|
|
596
251
|
let plugin;
|
|
597
252
|
export default {
|
|
598
253
|
id: "memoryx-openclaw-plugin",
|
|
599
254
|
name: "MemoryX Realtime Plugin",
|
|
600
|
-
version: "
|
|
601
|
-
description: "Real-time memory capture and recall for OpenClaw",
|
|
255
|
+
version: "2.0.0",
|
|
256
|
+
description: "Real-time memory capture and recall for OpenClaw (powered by @t0ken.ai/memoryx-sdk)",
|
|
602
257
|
register(api, pluginConfig) {
|
|
603
258
|
api.logger.info("[MemoryX] Plugin registering...");
|
|
604
259
|
if (pluginConfig?.apiBaseUrl) {
|
|
@@ -760,12 +415,6 @@ export default {
|
|
|
760
415
|
details: { action: "stored", task_id: result.task_id }
|
|
761
416
|
};
|
|
762
417
|
}
|
|
763
|
-
else if (result.duplicate) {
|
|
764
|
-
return {
|
|
765
|
-
content: [{ type: "text", text: `Similar memory already exists: "${result.existing}"` }],
|
|
766
|
-
details: { action: "duplicate" }
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
418
|
else {
|
|
770
419
|
return {
|
|
771
420
|
content: [{ type: "text", text: "Failed to store memory. Please try again." }],
|
|
@@ -827,6 +476,55 @@ export default {
|
|
|
827
476
|
}
|
|
828
477
|
}
|
|
829
478
|
}, { name: "memoryx_list" });
|
|
479
|
+
api.registerTool({
|
|
480
|
+
name: "memoryx_account_info",
|
|
481
|
+
label: "MemoryX Account Info",
|
|
482
|
+
description: "Get MemoryX account information including API Key, Project ID, User ID, and API Base URL. Use when user asks about their MemoryX account, API key, project settings, or account status. Returns all stored account configuration from local database.",
|
|
483
|
+
parameters: {
|
|
484
|
+
type: "object",
|
|
485
|
+
properties: {}
|
|
486
|
+
},
|
|
487
|
+
async execute(_toolCallId, params) {
|
|
488
|
+
if (!plugin) {
|
|
489
|
+
return {
|
|
490
|
+
content: [{ type: "text", text: "MemoryX plugin not initialized." }],
|
|
491
|
+
details: { error: "not_initialized" }
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
try {
|
|
495
|
+
const accountInfo = await plugin.getAccountInfo();
|
|
496
|
+
if (!accountInfo) {
|
|
497
|
+
return {
|
|
498
|
+
content: [{ type: "text", text: "No account information found. The plugin may not be registered yet." }],
|
|
499
|
+
details: { error: "no_account" }
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
const lines = [
|
|
503
|
+
"MemoryX Account Information:",
|
|
504
|
+
`API Key: ${accountInfo.apiKey || 'Not set'}`,
|
|
505
|
+
`Project ID: ${accountInfo.projectId || 'default'}`,
|
|
506
|
+
`User ID: ${accountInfo.userId || 'Not set'}`,
|
|
507
|
+
`API Base URL: ${accountInfo.apiBaseUrl || DEFAULT_API_BASE}`,
|
|
508
|
+
`Initialized: ${accountInfo.initialized ? 'Yes' : 'No'}`
|
|
509
|
+
];
|
|
510
|
+
return {
|
|
511
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
512
|
+
details: {
|
|
513
|
+
apiKey: accountInfo.apiKey,
|
|
514
|
+
projectId: accountInfo.projectId,
|
|
515
|
+
userId: accountInfo.userId,
|
|
516
|
+
apiBaseUrl: accountInfo.apiBaseUrl
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
catch (error) {
|
|
521
|
+
return {
|
|
522
|
+
content: [{ type: "text", text: `Failed to get account info: ${error.message}` }],
|
|
523
|
+
details: { error: error.message }
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}, { name: "memoryx_account_info" });
|
|
830
528
|
api.on("message_received", async (event, ctx) => {
|
|
831
529
|
const { content } = event;
|
|
832
530
|
if (content && plugin) {
|
|
@@ -877,7 +575,7 @@ export default {
|
|
|
877
575
|
await plugin.endConversation();
|
|
878
576
|
}
|
|
879
577
|
});
|
|
880
|
-
api.logger.info("[MemoryX] Plugin registered successfully");
|
|
578
|
+
api.logger.info("[MemoryX] Plugin registered successfully (v2.0.0 with SDK)");
|
|
881
579
|
}
|
|
882
580
|
};
|
|
883
|
-
export { MemoryXPlugin
|
|
581
|
+
export { MemoryXPlugin };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@t0ken.ai/memoryx-openclaw-plugin",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "MemoryX real-time memory capture and recall plugin for OpenClaw",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "MemoryX real-time memory capture and recall plugin for OpenClaw (powered by @t0ken.ai/memoryx-sdk)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "MemoryX Team",
|
|
7
7
|
"license": "MIT",
|
|
@@ -31,12 +31,13 @@
|
|
|
31
31
|
]
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@types/better-sqlite3": "^7.6.0",
|
|
35
34
|
"@types/node": "^20.0.0",
|
|
36
35
|
"typescript": "^5.0.0"
|
|
37
36
|
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"better-sqlite3": "^11.0.0"
|
|
39
|
+
},
|
|
38
40
|
"dependencies": {
|
|
39
|
-
"
|
|
40
|
-
"js-tiktoken": "^1.0.21"
|
|
41
|
+
"@t0ken.ai/memoryx-sdk": "^1.0.0"
|
|
41
42
|
}
|
|
42
43
|
}
|