clawlet 0.5.0 → 0.5.2
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/package.json +1 -1
- package/src/agent.ts +70 -70
- package/src/storage.ts +23 -57
package/package.json
CHANGED
package/src/agent.ts
CHANGED
|
@@ -289,86 +289,86 @@ export class Agent {
|
|
|
289
289
|
if (!this.initialized) await this.init();
|
|
290
290
|
this.processing = true;
|
|
291
291
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
292
|
+
while (true) {
|
|
293
|
+
const queuedItem = await this.memory.queue.pop("main-session");
|
|
294
|
+
if (!queuedItem) {
|
|
295
|
+
this.processing = false;
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const { text, label } = queuedItem;
|
|
298
299
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
300
|
+
for (const out of this.outputAdapters) {
|
|
301
|
+
out.onAgentStart(label);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
this.messages = await this.memory.compactHistory("main-session", this.model);
|
|
302
305
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
break;
|
|
306
|
+
// Bootstrap: if bootstrapPrompt is set, run it instead of normal chat
|
|
307
|
+
// until the required files (SOUL.md, IDENTITY.md, USER.md) are created
|
|
308
|
+
const isFirstMessage = this.messages.length === 0;
|
|
309
|
+
let input: string;
|
|
310
|
+
if (this.bootstrapPrompt && isFirstMessage) {
|
|
311
|
+
input = `[BOOTSTRAP MODE] The workspace is not yet set up.\n\n` +
|
|
312
|
+
`${this.bootstrapPrompt}\n\n` +
|
|
313
|
+
`Use fs.writeFile to create each file in the workspace when the user provides the information.\n\n` +
|
|
314
|
+
`--- USER MESSAGE ---\n${text}`;
|
|
315
|
+
} else if (this.bootstrapPrompt) {
|
|
316
|
+
// Still in bootstrap mode (subsequent messages) — check if bootstrap is complete
|
|
317
|
+
const workspaceDir = path.join(process.cwd(), 'workspace');
|
|
318
|
+
const requiredFiles = ['SOUL.md', 'IDENTITY.md', 'USER.md'];
|
|
319
|
+
let allExist = true;
|
|
320
|
+
for (const file of requiredFiles) {
|
|
321
|
+
try {
|
|
322
|
+
await access(path.join(workspaceDir, file));
|
|
323
|
+
} catch {
|
|
324
|
+
allExist = false;
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
325
327
|
}
|
|
328
|
+
if (allExist) {
|
|
329
|
+
this.bootstrapPrompt = null;
|
|
330
|
+
console.log(` ✅ Bootstrap complete! SOUL.md, IDENTITY.md, and USER.md are now present.`);
|
|
331
|
+
}
|
|
332
|
+
input = text;
|
|
333
|
+
} else if (isFirstMessage) {
|
|
334
|
+
input = `[SYSTEM BOOT] This is a fresh session. Before responding to the user, you MUST execute the "Every Session" protocol from AGENTS.md NOW using your tools:\n` +
|
|
335
|
+
`1. Call fs.readFile for SOUL.md\n` +
|
|
336
|
+
`2. Call fs.readFile for USER.md\n` +
|
|
337
|
+
`3. Call fs.readFile for memory:${getTodayString()}.md (create it with fs.writeFile if it doesn't exist)\n` +
|
|
338
|
+
`4. Call fs.readFile for MEMORY.md\n` +
|
|
339
|
+
`Execute ALL of these tool calls first, then respond to the user's message below.\n\n` +
|
|
340
|
+
`--- USER MESSAGE ---\n${text}`;
|
|
341
|
+
} else {
|
|
342
|
+
input = text;
|
|
326
343
|
}
|
|
327
|
-
if (allExist) {
|
|
328
|
-
this.bootstrapPrompt = null;
|
|
329
|
-
console.log(` ✅ Bootstrap complete! SOUL.md, IDENTITY.md, and USER.md are now present.`);
|
|
330
|
-
}
|
|
331
|
-
input = text;
|
|
332
|
-
} else if (isFirstMessage) {
|
|
333
|
-
input = `[SYSTEM BOOT] This is a fresh session. Before responding to the user, you MUST execute the "Every Session" protocol from AGENTS.md NOW using your tools:\n` +
|
|
334
|
-
`1. Call fs.readFile for SOUL.md\n` +
|
|
335
|
-
`2. Call fs.readFile for USER.md\n` +
|
|
336
|
-
`3. Call fs.readFile for memory:${getTodayString()}.md (create it with fs.writeFile if it doesn't exist)\n` +
|
|
337
|
-
`4. Call fs.readFile for MEMORY.md\n` +
|
|
338
|
-
`Execute ALL of these tool calls first, then respond to the user's message below.\n\n` +
|
|
339
|
-
`--- USER MESSAGE ---\n${text}`;
|
|
340
|
-
} else {
|
|
341
|
-
input = text;
|
|
342
|
-
}
|
|
343
344
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
345
|
+
let fullResponse = "";
|
|
346
|
+
try {
|
|
347
|
+
const newMessages = await runAgent(input, this.memory, this.model, this.messages, this.tools, (chunk) => {
|
|
348
|
+
fullResponse += chunk;
|
|
349
|
+
for (const out of this.outputAdapters) {
|
|
350
|
+
out.onResponseChunk(chunk);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
for (const msg of newMessages) {
|
|
355
|
+
if (typeof msg.content !== "string") {
|
|
356
|
+
msg.content = msg.content.filter((part) => part.type !== 'reasoning');
|
|
357
|
+
}
|
|
358
|
+
await this.memory.history.push("main-session", msg);
|
|
350
359
|
}
|
|
351
|
-
});
|
|
352
360
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
msg.content = msg.content.filter((part) => part.type !== 'reasoning');
|
|
361
|
+
for (const out of this.outputAdapters) {
|
|
362
|
+
out.onResponseEnd(fullResponse);
|
|
356
363
|
}
|
|
357
|
-
await this.memory.history.push("main-session", msg);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
for (const out of this.outputAdapters) {
|
|
361
|
-
out.onResponseEnd(fullResponse);
|
|
362
|
-
}
|
|
363
364
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
365
|
+
// Compact history if it's grown past the threshold
|
|
366
|
+
this.messages = await this.memory.compactHistory("main-session", this.model);
|
|
367
|
+
} catch (error: any) {
|
|
368
|
+
for (const out of this.outputAdapters) {
|
|
369
|
+
out.onError(error);
|
|
370
|
+
}
|
|
369
371
|
}
|
|
370
372
|
}
|
|
371
|
-
|
|
372
|
-
this.processing = false;
|
|
373
373
|
}
|
|
374
374
|
}
|
package/src/storage.ts
CHANGED
|
@@ -104,23 +104,8 @@ export class LibSqlListStorage<T = any> {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
async replaceAll(name: string, items: T[]): Promise<void> {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
await tx.execute({
|
|
110
|
-
sql: `DELETE FROM ${this.tableName} WHERE name = ?`,
|
|
111
|
-
args: [name],
|
|
112
|
-
});
|
|
113
|
-
for (const item of items) {
|
|
114
|
-
await tx.execute({
|
|
115
|
-
sql: `INSERT INTO ${this.tableName} (name, item) VALUES (?, ?)`,
|
|
116
|
-
args: [name, JSON.stringify(item)]
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
await tx.commit();
|
|
120
|
-
} catch (e) {
|
|
121
|
-
await tx.rollback();
|
|
122
|
-
throw e;
|
|
123
|
-
}
|
|
107
|
+
this.clear(name);
|
|
108
|
+
this.pushMany(name, items);
|
|
124
109
|
}
|
|
125
110
|
|
|
126
111
|
async getAll(name: string): Promise<T[]> {
|
|
@@ -181,19 +166,9 @@ export class LibSqlFiFoStorage<T> {
|
|
|
181
166
|
}
|
|
182
167
|
|
|
183
168
|
public async pushMany(queue: string, items: T[]): Promise<void> {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
await tx.execute({
|
|
188
|
-
sql: `INSERT INTO ${this.tableName} (queue_name, value) VALUES (?, ?)`,
|
|
189
|
-
args: [queue, JSON.stringify(item)],
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
await tx.commit();
|
|
193
|
-
} catch (e) {
|
|
194
|
-
await tx.rollback();
|
|
195
|
-
throw e;
|
|
196
|
-
}
|
|
169
|
+
for (const item of items) {
|
|
170
|
+
this.push(queue, item);
|
|
171
|
+
}
|
|
197
172
|
}
|
|
198
173
|
|
|
199
174
|
public async empty(queue: string): Promise<boolean> {
|
|
@@ -201,33 +176,24 @@ export class LibSqlFiFoStorage<T> {
|
|
|
201
176
|
}
|
|
202
177
|
|
|
203
178
|
public async pop(queue: string): Promise<T | null> {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
await tx.commit();
|
|
225
|
-
|
|
226
|
-
return JSON.parse(row.value as string) as T;
|
|
227
|
-
} catch (e) {
|
|
228
|
-
await tx.rollback();
|
|
229
|
-
throw e;
|
|
230
|
-
}
|
|
179
|
+
const rs = await this.client.execute({
|
|
180
|
+
sql: `SELECT id, value FROM ${this.tableName} WHERE queue_name = ? ORDER BY id ASC LIMIT 1`,
|
|
181
|
+
args: [queue],
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
if (rs.rows.length === 0) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const row = rs.rows[0] as any;
|
|
189
|
+
const id = row.id;
|
|
190
|
+
|
|
191
|
+
await this.client.execute({
|
|
192
|
+
sql: `DELETE FROM ${this.tableName} WHERE id = ?`,
|
|
193
|
+
args: [id!],
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
return JSON.parse(row.value as string) as T;
|
|
231
197
|
}
|
|
232
198
|
|
|
233
199
|
public async count(queue: string): Promise<number> {
|