clawlet 0.4.0 → 0.5.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/package.json +1 -1
- package/src/agent.eval.test.ts +9 -2
- package/src/agent.ts +13 -8
- package/src/evals/skill_sandbox_execution.yaml +7 -7
- package/src/memory.ts +14 -5
- package/src/storage.ts +7 -2
package/package.json
CHANGED
package/src/agent.eval.test.ts
CHANGED
|
@@ -94,8 +94,15 @@ const runTestCaseFile = async (filename: string) => {
|
|
|
94
94
|
onError: (e) => { throw e; }
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
-
(
|
|
98
|
-
|
|
97
|
+
await (new Promise((resolve, reject) => {
|
|
98
|
+
agent.addInput({
|
|
99
|
+
onMessage: async (handler : (text: string, label: string) => Promise<void>) => {
|
|
100
|
+
await handler(data.input, 'test');
|
|
101
|
+
resolve(true);
|
|
102
|
+
},
|
|
103
|
+
start: () => {}
|
|
104
|
+
})
|
|
105
|
+
}));
|
|
99
106
|
|
|
100
107
|
// 3. ASSERTIONS
|
|
101
108
|
|
package/src/agent.ts
CHANGED
|
@@ -24,7 +24,7 @@ const GENERATE_TEXT_MAX_STEPS = 30;
|
|
|
24
24
|
// --- ADAPTER INTERFACES ---
|
|
25
25
|
|
|
26
26
|
export interface InputAdapter {
|
|
27
|
-
onMessage(handler: (text: string, label: string) => void): void;
|
|
27
|
+
onMessage(handler: (text: string, label: string) => Promise<void>): void;
|
|
28
28
|
start(): void;
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -194,7 +194,6 @@ export class Agent {
|
|
|
194
194
|
private tools: ReturnType<typeof createTools>;
|
|
195
195
|
private inputAdapters: InputAdapter[] = [];
|
|
196
196
|
private outputAdapters: OutputAdapter[] = [];
|
|
197
|
-
private inputQueue: { text: string; label: string }[] = [];
|
|
198
197
|
private processing = false;
|
|
199
198
|
private initialized = false;
|
|
200
199
|
private bootstrapPrompt: string | null = null;
|
|
@@ -207,9 +206,9 @@ export class Agent {
|
|
|
207
206
|
|
|
208
207
|
addInput(adapter: InputAdapter): this {
|
|
209
208
|
this.inputAdapters.push(adapter);
|
|
210
|
-
adapter.onMessage((text, label) => {
|
|
211
|
-
this.
|
|
212
|
-
this.processQueue();
|
|
209
|
+
adapter.onMessage(async (text, label) => {
|
|
210
|
+
await this.memory.queue.push("main-session", { text, label });
|
|
211
|
+
await this.processQueue();
|
|
213
212
|
});
|
|
214
213
|
return this;
|
|
215
214
|
}
|
|
@@ -224,6 +223,7 @@ export class Agent {
|
|
|
224
223
|
for (const adapter of this.inputAdapters) {
|
|
225
224
|
adapter.start();
|
|
226
225
|
}
|
|
226
|
+
await this.processQueue();
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
private async init() {
|
|
@@ -284,11 +284,17 @@ export class Agent {
|
|
|
284
284
|
|
|
285
285
|
|
|
286
286
|
private async processQueue() {
|
|
287
|
-
if (this.processing
|
|
287
|
+
if (this.processing) return;
|
|
288
|
+
if (await this.memory.queue.empty("main-session")) return ;
|
|
288
289
|
if (!this.initialized) await this.init();
|
|
289
290
|
this.processing = true;
|
|
290
291
|
|
|
291
|
-
const
|
|
292
|
+
const queuedItem = await this.memory.queue.pop("main-session");
|
|
293
|
+
if (!queuedItem) {
|
|
294
|
+
this.processing = false;
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const { text, label } = queuedItem;
|
|
292
298
|
|
|
293
299
|
for (const out of this.outputAdapters) {
|
|
294
300
|
out.onAgentStart(label);
|
|
@@ -364,6 +370,5 @@ export class Agent {
|
|
|
364
370
|
}
|
|
365
371
|
|
|
366
372
|
this.processing = false;
|
|
367
|
-
this.processQueue();
|
|
368
373
|
}
|
|
369
374
|
}
|
|
@@ -3,17 +3,17 @@ description: "Agent should use an installed skill instead of hallucinating the a
|
|
|
3
3
|
|
|
4
4
|
setup:
|
|
5
5
|
files:
|
|
6
|
+
IDENTITY.md: "I am a bot"
|
|
7
|
+
USER.md: "Mr X"
|
|
8
|
+
SOUL.md: "I will not install skills, I will check if they are available and use them but before I install them: I will ask first."
|
|
6
9
|
# Simulate an already installed skill file
|
|
7
|
-
skills/
|
|
8
|
-
permissions:
|
|
9
|
-
calculator:
|
|
10
|
-
allowed: true
|
|
10
|
+
skills/oracle/SKILL.md: "I am an oracle. If somebody asks a question, I will answer with 42. Make sure that they tell that the oracle told them."
|
|
11
11
|
|
|
12
|
-
input: "Ask the '
|
|
12
|
+
input: "Ask the 'oracle' skill, what is the answer to my question."
|
|
13
13
|
|
|
14
14
|
validate:
|
|
15
15
|
response:
|
|
16
|
-
contains_any: ["
|
|
16
|
+
contains_any: ["oracle", "42"]
|
|
17
17
|
llm_eval: |
|
|
18
|
-
Does the agent response reference the
|
|
18
|
+
Does the agent response reference the oracle skill?
|
|
19
19
|
The response should indicate the agent attempted to delegate to the skill rather than answering entirely on its own.
|
package/src/memory.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { createStorage, type Storage } from "unstorage";
|
|
|
2
2
|
import fsDriver from "unstorage/drivers/fs";
|
|
3
3
|
import { generateText, type LanguageModel, type ModelMessage } from "ai";
|
|
4
4
|
import path from "path";
|
|
5
|
-
import { LibSqlKeyValueStorage, LibSqlListStorage } from "./storage.js";
|
|
5
|
+
import { LibSqlKeyValueStorage, LibSqlListStorage, LibSqlFiFoStorage } from "./storage.js";
|
|
6
6
|
import { logger } from './logger.js';
|
|
7
7
|
import memoryDriver from 'unstorage/drivers/memory';
|
|
8
8
|
|
|
@@ -21,17 +21,22 @@ export class AgentMemory {
|
|
|
21
21
|
// 3. Workspace (Unstorage - ./workspace)
|
|
22
22
|
public workspace: Storage;
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
// 4. Fifo Queue (libSQL - file:queue.db)
|
|
25
|
+
public queue: LibSqlFiFoStorage<{ text: string, label: string}>;
|
|
26
|
+
|
|
27
|
+
private constructor(secrets: LibSqlKeyValueStorage, history: LibSqlListStorage<ModelMessage>, workspace: Storage, queue: LibSqlFiFoStorage<{ text: string, label: string}>) {
|
|
25
28
|
this.secrets = secrets;
|
|
26
29
|
this.history = history;
|
|
27
|
-
this.workspace = workspace
|
|
30
|
+
this.workspace = workspace;
|
|
31
|
+
this.queue = queue;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
static async createInMemory() {
|
|
31
35
|
return new AgentMemory(
|
|
32
36
|
await LibSqlKeyValueStorage.create(':memory:'),
|
|
33
37
|
await LibSqlListStorage.create<ModelMessage>(':memory:'),
|
|
34
|
-
createStorage({ driver: memoryDriver() })
|
|
38
|
+
createStorage({ driver: memoryDriver() }),
|
|
39
|
+
await LibSqlFiFoStorage.create(':memory:')
|
|
35
40
|
);
|
|
36
41
|
}
|
|
37
42
|
|
|
@@ -47,7 +52,11 @@ export class AgentMemory {
|
|
|
47
52
|
),
|
|
48
53
|
createStorage({
|
|
49
54
|
driver: fsDriver({ base: path.join(process.cwd(), "workspace") })
|
|
50
|
-
})
|
|
55
|
+
}),
|
|
56
|
+
await LibSqlFiFoStorage.create(
|
|
57
|
+
process.env.QUEUE_DB_URL || "file:queue.db",
|
|
58
|
+
process.env.QUEUE_AUTH_TOKEN
|
|
59
|
+
)
|
|
51
60
|
);
|
|
52
61
|
}
|
|
53
62
|
|
package/src/storage.ts
CHANGED
|
@@ -152,9 +152,14 @@ export class LibSqlFiFoStorage<T> {
|
|
|
152
152
|
private client: Client;
|
|
153
153
|
private tableName = 'queue_items';
|
|
154
154
|
|
|
155
|
-
constructor(url: string, authToken?: string) {
|
|
155
|
+
private constructor(url: string, authToken?: string) {
|
|
156
156
|
this.client = authToken ? createClient({ url, authToken }) : createClient({ url });
|
|
157
|
-
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
static async create<T>(url: string, authToken?: string): Promise<LibSqlFiFoStorage<T>> {
|
|
160
|
+
const storage = new LibSqlFiFoStorage<T>(url, authToken);
|
|
161
|
+
await storage.init();
|
|
162
|
+
return storage;
|
|
158
163
|
}
|
|
159
164
|
|
|
160
165
|
private async init(): Promise<void> {
|