supaclaw 1.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/LICENSE +21 -0
- package/README.md +871 -0
- package/SCHEMA.md +215 -0
- package/dist/clawdbot-integration.d.ts +171 -0
- package/dist/clawdbot-integration.js +339 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1815 -0
- package/dist/context-manager.d.ts +143 -0
- package/dist/context-manager.js +360 -0
- package/dist/error-handling.d.ts +100 -0
- package/dist/error-handling.js +301 -0
- package/dist/index.d.ts +735 -0
- package/dist/index.js +2256 -0
- package/dist/parsers.d.ts +115 -0
- package/dist/parsers.js +406 -0
- package/migrations/001_initial.sql +153 -0
- package/migrations/002_vector_search.sql +219 -0
- package/migrations/003_entity_relationships.sql +143 -0
- package/package.json +66 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Clawdbot Integration for OpenClaw Memory
|
|
4
|
+
*
|
|
5
|
+
* This module provides integration hooks for Clawdbot to:
|
|
6
|
+
* 1. Auto-log all messages to sessions
|
|
7
|
+
* 2. Replace memory_search with semantic recall
|
|
8
|
+
* 3. Replace memory_get with database queries
|
|
9
|
+
* 4. Inject relevant context into system prompts
|
|
10
|
+
* 5. Handle session lifecycle
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.ClawdbotMemoryIntegration = void 0;
|
|
14
|
+
exports.createClawdbotIntegration = createClawdbotIntegration;
|
|
15
|
+
exports.createLoggingMiddleware = createLoggingMiddleware;
|
|
16
|
+
const index_1 = require("./index");
|
|
17
|
+
class ClawdbotMemoryIntegration {
|
|
18
|
+
memory;
|
|
19
|
+
config;
|
|
20
|
+
activeSessions;
|
|
21
|
+
sessionTimeoutMs;
|
|
22
|
+
constructor(config) {
|
|
23
|
+
this.config = config;
|
|
24
|
+
this.memory = new index_1.OpenClawMemory({
|
|
25
|
+
supabaseUrl: config.supabaseUrl,
|
|
26
|
+
supabaseKey: config.supabaseKey,
|
|
27
|
+
agentId: config.agentId,
|
|
28
|
+
embeddingProvider: config.embeddingProvider || 'openai',
|
|
29
|
+
openaiApiKey: config.openaiApiKey
|
|
30
|
+
});
|
|
31
|
+
this.activeSessions = new Map();
|
|
32
|
+
this.sessionTimeoutMs = config.sessionTimeout || 30 * 60 * 1000; // 30 minutes default
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Initialize the memory system
|
|
36
|
+
*/
|
|
37
|
+
async initialize() {
|
|
38
|
+
await this.memory.initialize();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get or create a session for a chat/user
|
|
42
|
+
*/
|
|
43
|
+
async getOrCreateSession(chatId, context = {}) {
|
|
44
|
+
// Check if active session exists
|
|
45
|
+
const existing = this.activeSessions.get(chatId);
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
if (existing && (now - existing.lastActivity) < this.sessionTimeoutMs) {
|
|
48
|
+
// Update last activity
|
|
49
|
+
existing.lastActivity = now;
|
|
50
|
+
return existing.sessionId;
|
|
51
|
+
}
|
|
52
|
+
// End old session if it exists
|
|
53
|
+
if (existing) {
|
|
54
|
+
await this.endSession(chatId);
|
|
55
|
+
}
|
|
56
|
+
// Create new session
|
|
57
|
+
const session = await this.memory.startSession({
|
|
58
|
+
userId: context.userId || this.config.userId,
|
|
59
|
+
channel: context.channel,
|
|
60
|
+
metadata: {
|
|
61
|
+
chatId,
|
|
62
|
+
startedBy: 'clawdbot-integration'
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
this.activeSessions.set(chatId, {
|
|
66
|
+
sessionId: session.id,
|
|
67
|
+
lastActivity: now
|
|
68
|
+
});
|
|
69
|
+
return session.id;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Log a user message
|
|
73
|
+
*/
|
|
74
|
+
async logUserMessage(chatId, content, context = {}) {
|
|
75
|
+
if (!this.config.autoLog)
|
|
76
|
+
return;
|
|
77
|
+
const sessionId = await this.getOrCreateSession(chatId, context);
|
|
78
|
+
await this.memory.addMessage(sessionId, {
|
|
79
|
+
role: 'user',
|
|
80
|
+
content,
|
|
81
|
+
metadata: {
|
|
82
|
+
messageId: context.messageId,
|
|
83
|
+
timestamp: context.timestamp || new Date().toISOString(),
|
|
84
|
+
channel: context.channel
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Log an assistant message
|
|
90
|
+
*/
|
|
91
|
+
async logAssistantMessage(chatId, content, context = {}) {
|
|
92
|
+
if (!this.config.autoLog)
|
|
93
|
+
return;
|
|
94
|
+
const sessionId = await this.getOrCreateSession(chatId, context);
|
|
95
|
+
await this.memory.addMessage(sessionId, {
|
|
96
|
+
role: 'assistant',
|
|
97
|
+
content,
|
|
98
|
+
metadata: {
|
|
99
|
+
messageId: context.messageId,
|
|
100
|
+
timestamp: context.timestamp || new Date().toISOString(),
|
|
101
|
+
model: context.model,
|
|
102
|
+
channel: context.channel
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Log a system message
|
|
108
|
+
*/
|
|
109
|
+
async logSystemMessage(chatId, content, context = {}) {
|
|
110
|
+
if (!this.config.autoLog)
|
|
111
|
+
return;
|
|
112
|
+
const sessionId = await this.getOrCreateSession(chatId, context);
|
|
113
|
+
await this.memory.addMessage(sessionId, {
|
|
114
|
+
role: 'system',
|
|
115
|
+
content,
|
|
116
|
+
metadata: {
|
|
117
|
+
timestamp: context.timestamp || new Date().toISOString()
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Replace memory_search - semantic search for memories
|
|
123
|
+
*/
|
|
124
|
+
async memorySearch(query, opts = {}) {
|
|
125
|
+
const results = await this.memory.recall(query, {
|
|
126
|
+
userId: opts.userId || this.config.userId,
|
|
127
|
+
category: opts.category,
|
|
128
|
+
limit: opts.limit || 5,
|
|
129
|
+
minImportance: opts.minImportance || 0.5
|
|
130
|
+
});
|
|
131
|
+
return results.map(r => ({
|
|
132
|
+
content: r.content,
|
|
133
|
+
category: r.category,
|
|
134
|
+
importance: r.importance,
|
|
135
|
+
created_at: r.created_at
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Replace memory_get - get memories by category
|
|
140
|
+
*/
|
|
141
|
+
async memoryGet(opts = {}) {
|
|
142
|
+
const results = await this.memory.getMemories({
|
|
143
|
+
userId: opts.userId || this.config.userId,
|
|
144
|
+
category: opts.category,
|
|
145
|
+
limit: opts.limit || 10
|
|
146
|
+
});
|
|
147
|
+
return results.map(r => ({
|
|
148
|
+
content: r.content,
|
|
149
|
+
category: r.category,
|
|
150
|
+
importance: r.importance
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Build context for system prompt injection
|
|
155
|
+
*/
|
|
156
|
+
async buildContext(query, opts = {}) {
|
|
157
|
+
const parts = [];
|
|
158
|
+
// Include relevant memories
|
|
159
|
+
if (opts.includeMemories !== false) {
|
|
160
|
+
const memories = await this.memorySearch(query, {
|
|
161
|
+
limit: opts.maxMemories || 5
|
|
162
|
+
});
|
|
163
|
+
if (memories.length > 0) {
|
|
164
|
+
parts.push('## Relevant Context\n');
|
|
165
|
+
memories.forEach(m => {
|
|
166
|
+
parts.push(`- [${m.category || 'general'}] ${m.content}`);
|
|
167
|
+
});
|
|
168
|
+
parts.push('');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Include relevant learnings
|
|
172
|
+
if (opts.includeLearnings !== false) {
|
|
173
|
+
const learnings = await this.memory.getLearningRecommendations(query, opts.maxLearnings || 3);
|
|
174
|
+
if (learnings.length > 0) {
|
|
175
|
+
parts.push('## Past Learnings\n');
|
|
176
|
+
learnings.forEach(l => {
|
|
177
|
+
parts.push(`- [${l.category}] ${l.lesson}`);
|
|
178
|
+
if (l.action) {
|
|
179
|
+
parts.push(` Action: ${l.action}`);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
parts.push('');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Include recent messages from session
|
|
186
|
+
if (opts.includeRecentMessages && opts.chatId) {
|
|
187
|
+
const session = this.activeSessions.get(opts.chatId);
|
|
188
|
+
if (session) {
|
|
189
|
+
const messages = await this.memory.getMessages(session.sessionId, {
|
|
190
|
+
limit: opts.maxMessages || 10
|
|
191
|
+
});
|
|
192
|
+
if (messages.length > 0) {
|
|
193
|
+
parts.push('## Recent Conversation\n');
|
|
194
|
+
messages.slice(-5).forEach(m => {
|
|
195
|
+
const preview = m.content.length > 100
|
|
196
|
+
? m.content.substring(0, 100) + '...'
|
|
197
|
+
: m.content;
|
|
198
|
+
parts.push(`- ${m.role}: ${preview}`);
|
|
199
|
+
});
|
|
200
|
+
parts.push('');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return parts.join('\n');
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Store a memory
|
|
208
|
+
*/
|
|
209
|
+
async remember(content, opts = {}) {
|
|
210
|
+
let sessionId;
|
|
211
|
+
if (opts.chatId) {
|
|
212
|
+
const session = this.activeSessions.get(opts.chatId);
|
|
213
|
+
sessionId = session?.sessionId;
|
|
214
|
+
}
|
|
215
|
+
return await this.memory.remember({
|
|
216
|
+
content,
|
|
217
|
+
category: opts.category,
|
|
218
|
+
importance: opts.importance || 0.5,
|
|
219
|
+
userId: opts.userId || this.config.userId,
|
|
220
|
+
sessionId,
|
|
221
|
+
expiresAt: opts.expiresAt
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Record a learning
|
|
226
|
+
*/
|
|
227
|
+
async learn(learning) {
|
|
228
|
+
let sessionId;
|
|
229
|
+
if (learning.chatId) {
|
|
230
|
+
const session = this.activeSessions.get(learning.chatId);
|
|
231
|
+
sessionId = session?.sessionId;
|
|
232
|
+
}
|
|
233
|
+
return await this.memory.learn({
|
|
234
|
+
category: learning.category,
|
|
235
|
+
trigger: learning.trigger,
|
|
236
|
+
lesson: learning.lesson,
|
|
237
|
+
action: learning.action,
|
|
238
|
+
severity: learning.severity || 'info',
|
|
239
|
+
sessionId
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Create a task
|
|
244
|
+
*/
|
|
245
|
+
async createTask(task) {
|
|
246
|
+
return await this.memory.createTask({
|
|
247
|
+
...task,
|
|
248
|
+
userId: task.userId || this.config.userId
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Get upcoming tasks for reminders
|
|
253
|
+
*/
|
|
254
|
+
async getUpcomingTasks(hoursAhead = 24) {
|
|
255
|
+
return await this.memory.getTasksNeedingReminders({
|
|
256
|
+
userId: this.config.userId,
|
|
257
|
+
hoursAhead
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* End a session
|
|
262
|
+
*/
|
|
263
|
+
async endSession(chatId, opts = {}) {
|
|
264
|
+
const session = this.activeSessions.get(chatId);
|
|
265
|
+
if (!session)
|
|
266
|
+
return;
|
|
267
|
+
// End session with optional summary
|
|
268
|
+
await this.memory.endSession(session.sessionId, {
|
|
269
|
+
summary: opts.summary,
|
|
270
|
+
autoSummarize: opts.autoSummarize !== false // Default true
|
|
271
|
+
});
|
|
272
|
+
// Extract memories if requested
|
|
273
|
+
if (opts.extractMemories) {
|
|
274
|
+
await this.memory.extractMemoriesFromSession(session.sessionId, {
|
|
275
|
+
autoExtract: true,
|
|
276
|
+
minImportance: 0.6
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
this.activeSessions.delete(chatId);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* End all inactive sessions
|
|
283
|
+
*/
|
|
284
|
+
async cleanupInactiveSessions() {
|
|
285
|
+
const now = Date.now();
|
|
286
|
+
const toEnd = [];
|
|
287
|
+
this.activeSessions.forEach((session, chatId) => {
|
|
288
|
+
if (now - session.lastActivity >= this.sessionTimeoutMs) {
|
|
289
|
+
toEnd.push(chatId);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
for (const chatId of toEnd) {
|
|
293
|
+
await this.endSession(chatId, { autoSummarize: true });
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Heartbeat check - call this periodically (e.g., every 30 min)
|
|
298
|
+
*/
|
|
299
|
+
async heartbeat() {
|
|
300
|
+
// Clean up inactive sessions
|
|
301
|
+
await this.cleanupInactiveSessions();
|
|
302
|
+
// Get upcoming tasks
|
|
303
|
+
const upcomingTasks = await this.getUpcomingTasks(2); // Next 2 hours
|
|
304
|
+
return {
|
|
305
|
+
upcomingTasks,
|
|
306
|
+
inactiveSessions: this.activeSessions.size
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Get the underlying OpenClawMemory instance for advanced operations
|
|
311
|
+
*/
|
|
312
|
+
getMemory() {
|
|
313
|
+
return this.memory;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
exports.ClawdbotMemoryIntegration = ClawdbotMemoryIntegration;
|
|
317
|
+
/**
|
|
318
|
+
* Factory function to create integration instance
|
|
319
|
+
*/
|
|
320
|
+
function createClawdbotIntegration(config) {
|
|
321
|
+
return new ClawdbotMemoryIntegration(config);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Express/Koa-style middleware for auto-logging
|
|
325
|
+
*/
|
|
326
|
+
function createLoggingMiddleware(integration) {
|
|
327
|
+
return async (message) => {
|
|
328
|
+
const { chatId, role, content, context = {} } = message;
|
|
329
|
+
if (role === 'user') {
|
|
330
|
+
await integration.logUserMessage(chatId, content, context);
|
|
331
|
+
}
|
|
332
|
+
else if (role === 'assistant') {
|
|
333
|
+
await integration.logAssistantMessage(chatId, content, context);
|
|
334
|
+
}
|
|
335
|
+
else if (role === 'system') {
|
|
336
|
+
await integration.logSystemMessage(chatId, content, context);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
}
|
package/dist/cli.d.ts
ADDED