@lobu/cli 3.2.0 → 3.4.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 +12 -4
- package/dist/__tests__/chat.integration.test.d.ts +2 -0
- package/dist/__tests__/chat.integration.test.d.ts.map +1 -0
- package/dist/__tests__/chat.integration.test.js +337 -0
- package/dist/__tests__/chat.integration.test.js.map +1 -0
- package/dist/__tests__/init-memory.test.d.ts +2 -0
- package/dist/__tests__/init-memory.test.d.ts.map +1 -0
- package/dist/__tests__/init-memory.test.js +53 -0
- package/dist/__tests__/init-memory.test.js.map +1 -0
- package/dist/commands/chat.js +60 -18
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/connections/platforms.d.ts.map +1 -1
- package/dist/commands/connections/platforms.js +10 -0
- package/dist/commands/connections/platforms.js.map +1 -1
- package/dist/commands/eval.d.ts.map +1 -1
- package/dist/commands/eval.js +6 -2
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/init.d.ts +22 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +60 -29
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/providers/add.js +4 -4
- package/dist/commands/providers/add.js.map +1 -1
- package/dist/commands/providers/list.d.ts.map +1 -1
- package/dist/commands/providers/list.js +11 -12
- package/dist/commands/providers/list.js.map +1 -1
- package/dist/commands/providers/registry.d.ts +17 -0
- package/dist/commands/providers/registry.d.ts.map +1 -0
- package/dist/commands/{skills → providers}/registry.js +7 -12
- package/dist/commands/providers/registry.js.map +1 -0
- package/dist/commands/skills/add.d.ts.map +1 -1
- package/dist/commands/skills/add.js +2 -47
- package/dist/commands/skills/add.js.map +1 -1
- package/dist/commands/skills/info.d.ts.map +1 -1
- package/dist/commands/skills/info.js +3 -32
- package/dist/commands/skills/info.js.map +1 -1
- package/dist/commands/skills/list.d.ts.map +1 -1
- package/dist/commands/skills/list.js +5 -25
- package/dist/commands/skills/list.js.map +1 -1
- package/dist/commands/skills/search.d.ts.map +1 -1
- package/dist/commands/skills/search.js +2 -19
- package/dist/commands/skills/search.js.map +1 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +0 -8
- package/dist/commands/validate.js.map +1 -1
- package/dist/eval/client.d.ts +1 -0
- package/dist/eval/client.d.ts.map +1 -1
- package/dist/eval/client.js +2 -0
- package/dist/eval/client.js.map +1 -1
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/runner.js +6 -0
- package/dist/eval/runner.js.map +1 -1
- package/dist/eval/types.d.ts +2 -0
- package/dist/eval/types.d.ts.map +1 -1
- package/dist/eval/types.js +2 -0
- package/dist/eval/types.js.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/{system-skills.json → providers.json} +1 -71
- package/package.json +2 -2
- package/dist/commands/skills/registry.d.ts +0 -29
- package/dist/commands/skills/registry.d.ts.map +0 -1
- package/dist/commands/skills/registry.js.map +0 -1
package/README.md
CHANGED
|
@@ -20,14 +20,22 @@ Scaffold a new Lobu project with interactive prompts:
|
|
|
20
20
|
- **Gateway port** and optional **public URL** (for OAuth callbacks)
|
|
21
21
|
- **Admin password**
|
|
22
22
|
- **Worker network access** (isolated, allowlist, or unrestricted)
|
|
23
|
-
- **AI provider** selection from the
|
|
24
|
-
- **
|
|
23
|
+
- **AI provider** selection from the bundled provider registry + API key
|
|
24
|
+
- **Providers** to enable (from `config/providers.json`)
|
|
25
25
|
- **Messaging platform** (Telegram, Slack, Discord, or none)
|
|
26
|
-
- **
|
|
27
|
-
- **Memory plugin** configuration
|
|
26
|
+
- **Memory** selection (filesystem, Owletto Cloud, Owletto Local, or custom Owletto URL)
|
|
28
27
|
|
|
29
28
|
**Generates:** `docker-compose.yml`, `.env`, `Dockerfile.worker`, `lobu.toml`, `IDENTITY.md`, `.gitignore`, `README.md`
|
|
30
29
|
|
|
30
|
+
When Owletto memory is enabled, `lobu init` also scaffolds the file-first memory layout:
|
|
31
|
+
|
|
32
|
+
- `owletto.yaml`
|
|
33
|
+
- `models/`
|
|
34
|
+
- `data/`
|
|
35
|
+
- `[memory.owletto]` in `lobu.toml`
|
|
36
|
+
|
|
37
|
+
For Owletto Local or a custom Owletto deployment, `.env` keeps `MEMORY_URL` as the optional base MCP URL override.
|
|
38
|
+
|
|
31
39
|
## Usage
|
|
32
40
|
|
|
33
41
|
```bash
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/chat.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { afterEach, beforeAll, describe, expect, mock, test } from "bun:test";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const createInterfaceMock = mock(() => ({
|
|
4
|
+
question: (_prompt, callback) => callback("1"),
|
|
5
|
+
close: () => undefined,
|
|
6
|
+
}));
|
|
7
|
+
mock.module("node:readline", () => ({
|
|
8
|
+
createInterface: createInterfaceMock,
|
|
9
|
+
}));
|
|
10
|
+
let chatCommand;
|
|
11
|
+
const originalFetch = globalThis.fetch;
|
|
12
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
13
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
14
|
+
const originalConsoleError = console.error;
|
|
15
|
+
const originalToken = process.env.LOBU_API_TOKEN;
|
|
16
|
+
const exampleDir = join(import.meta.dir, "../../../../examples/careops");
|
|
17
|
+
function createSseResponse(events) {
|
|
18
|
+
const encoder = new TextEncoder();
|
|
19
|
+
const payload = events
|
|
20
|
+
.map(({ event, data }) => `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`)
|
|
21
|
+
.join("");
|
|
22
|
+
return new Response(new ReadableStream({
|
|
23
|
+
start(controller) {
|
|
24
|
+
controller.enqueue(encoder.encode(payload));
|
|
25
|
+
controller.close();
|
|
26
|
+
},
|
|
27
|
+
}), {
|
|
28
|
+
status: 200,
|
|
29
|
+
headers: { "Content-Type": "text/event-stream" },
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function captureTerminal(output) {
|
|
33
|
+
process.stdout.write = ((chunk, cb) => {
|
|
34
|
+
output.stdout.push(String(chunk));
|
|
35
|
+
if (typeof cb === "function") {
|
|
36
|
+
cb(null);
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
});
|
|
40
|
+
process.stderr.write = ((chunk, cb) => {
|
|
41
|
+
output.stderr.push(String(chunk));
|
|
42
|
+
if (typeof cb === "function") {
|
|
43
|
+
cb(null);
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
});
|
|
47
|
+
console.error = (...args) => {
|
|
48
|
+
output.stderr.push(args.map((arg) => String(arg)).join(" "));
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
beforeAll(async () => {
|
|
52
|
+
({ chatCommand } = await import("../commands/chat"));
|
|
53
|
+
});
|
|
54
|
+
afterEach(() => {
|
|
55
|
+
globalThis.fetch = originalFetch;
|
|
56
|
+
process.stdout.write = originalStdoutWrite;
|
|
57
|
+
process.stderr.write = originalStderrWrite;
|
|
58
|
+
console.error = originalConsoleError;
|
|
59
|
+
if (originalToken === undefined) {
|
|
60
|
+
delete process.env.LOBU_API_TOKEN;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
process.env.LOBU_API_TOKEN = originalToken;
|
|
64
|
+
}
|
|
65
|
+
mock.restore();
|
|
66
|
+
});
|
|
67
|
+
describe("chatCommand example integration", () => {
|
|
68
|
+
test("uses the hr example agent and completes approval plus login interaction flow", async () => {
|
|
69
|
+
process.env.LOBU_API_TOKEN = "cli-token";
|
|
70
|
+
const stdout = [];
|
|
71
|
+
const stderr = [];
|
|
72
|
+
const createBodies = [];
|
|
73
|
+
const approvalBodies = [];
|
|
74
|
+
captureTerminal({ stdout, stderr });
|
|
75
|
+
globalThis.fetch = mock(async (input, init) => {
|
|
76
|
+
const url = String(input);
|
|
77
|
+
if (url === "http://gateway.test/api/v1/agents" &&
|
|
78
|
+
init?.method === "POST") {
|
|
79
|
+
const body = JSON.parse(String(init.body));
|
|
80
|
+
createBodies.push(body);
|
|
81
|
+
return Response.json({
|
|
82
|
+
agentId: "session-1",
|
|
83
|
+
token: "session-token",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (url === "http://gateway.test/api/v1/agents/session-1/events" &&
|
|
87
|
+
!init?.method) {
|
|
88
|
+
return createSseResponse([
|
|
89
|
+
{
|
|
90
|
+
event: "output",
|
|
91
|
+
data: { content: "Starting request.\n" },
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
event: "tool-approval",
|
|
95
|
+
data: {
|
|
96
|
+
requestId: "approval-1",
|
|
97
|
+
mcpId: "github",
|
|
98
|
+
toolName: "delete_issue",
|
|
99
|
+
args: { issue_number: 42 },
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
event: "link-button",
|
|
104
|
+
data: {
|
|
105
|
+
label: "Connect GitHub",
|
|
106
|
+
url: "https://auth.example.com/device",
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
event: "question",
|
|
111
|
+
data: {
|
|
112
|
+
question: "Pick one",
|
|
113
|
+
options: ["A", "B"],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
event: "suggestion",
|
|
118
|
+
data: {
|
|
119
|
+
prompts: ["retry", "show me the details"],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
event: "complete",
|
|
124
|
+
data: {},
|
|
125
|
+
},
|
|
126
|
+
]);
|
|
127
|
+
}
|
|
128
|
+
if (url === "http://gateway.test/api/v1/agents/session-1/messages" &&
|
|
129
|
+
init?.method === "POST") {
|
|
130
|
+
return Response.json({ success: true });
|
|
131
|
+
}
|
|
132
|
+
if (url === "http://gateway.test/api/v1/agents/approve" &&
|
|
133
|
+
init?.method === "POST") {
|
|
134
|
+
const body = JSON.parse(String(init.body));
|
|
135
|
+
approvalBodies.push(body);
|
|
136
|
+
return Response.json({
|
|
137
|
+
result: {
|
|
138
|
+
content: [{ text: "Approved tool result." }],
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
throw new Error(`Unexpected fetch: ${url}`);
|
|
143
|
+
});
|
|
144
|
+
await chatCommand(exampleDir, "please run the workflow", {
|
|
145
|
+
gateway: "http://gateway.test",
|
|
146
|
+
new: true,
|
|
147
|
+
});
|
|
148
|
+
expect(createBodies).toEqual([
|
|
149
|
+
{
|
|
150
|
+
agentId: "careops",
|
|
151
|
+
forceNew: true,
|
|
152
|
+
},
|
|
153
|
+
]);
|
|
154
|
+
expect(approvalBodies).toEqual([
|
|
155
|
+
{
|
|
156
|
+
requestId: "approval-1",
|
|
157
|
+
decision: "1h",
|
|
158
|
+
},
|
|
159
|
+
]);
|
|
160
|
+
const stdoutText = stdout.join("");
|
|
161
|
+
const stderrText = stderr.join("");
|
|
162
|
+
expect(stdoutText).toContain("Starting request.");
|
|
163
|
+
expect(stdoutText).toContain("Approved tool result.");
|
|
164
|
+
expect(stderrText).toContain("Tool Approval Required");
|
|
165
|
+
expect(stderrText).toContain("github");
|
|
166
|
+
expect(stderrText).toContain('"event":"link-button"');
|
|
167
|
+
expect(stderrText).toContain("Connect GitHub");
|
|
168
|
+
expect(stderrText).toContain('"event":"question"');
|
|
169
|
+
expect(stderrText).toContain('"event":"suggestion"');
|
|
170
|
+
expect(createInterfaceMock).toHaveBeenCalledTimes(1);
|
|
171
|
+
});
|
|
172
|
+
test("prints structured file-uploaded events in platform mode", async () => {
|
|
173
|
+
process.env.LOBU_API_TOKEN = "cli-token";
|
|
174
|
+
const stdout = [];
|
|
175
|
+
const stderr = [];
|
|
176
|
+
captureTerminal({ stdout, stderr });
|
|
177
|
+
globalThis.fetch = mock(async (input, init) => {
|
|
178
|
+
const url = String(input);
|
|
179
|
+
if (url === "http://gateway.test/api/v1/agents/careops/messages" &&
|
|
180
|
+
init?.method === "POST") {
|
|
181
|
+
return Response.json({
|
|
182
|
+
success: true,
|
|
183
|
+
eventsUrl: "/api/v1/agents/careops/events?platform=telegram",
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
if (url ===
|
|
187
|
+
"http://gateway.test/api/v1/agents/careops/events?platform=telegram" &&
|
|
188
|
+
!init?.method) {
|
|
189
|
+
return createSseResponse([
|
|
190
|
+
{
|
|
191
|
+
event: "file-uploaded",
|
|
192
|
+
data: {
|
|
193
|
+
tool: "UploadUserFile",
|
|
194
|
+
platform: "telegram",
|
|
195
|
+
fileId: "file-123",
|
|
196
|
+
name: "e2e.txt",
|
|
197
|
+
permalink: "https://files.example/e2e.txt",
|
|
198
|
+
size: 8,
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
event: "output",
|
|
203
|
+
data: {
|
|
204
|
+
content: "Uploaded e2e.txt successfully.\n",
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
{ event: "complete", data: {} },
|
|
208
|
+
]);
|
|
209
|
+
}
|
|
210
|
+
throw new Error(`Unexpected fetch: ${url}`);
|
|
211
|
+
});
|
|
212
|
+
await chatCommand(exampleDir, "send me e2e.txt as a file", {
|
|
213
|
+
gateway: "http://gateway.test",
|
|
214
|
+
user: "telegram:chat-123",
|
|
215
|
+
});
|
|
216
|
+
expect(stdout.join("")).toContain("Uploaded e2e.txt successfully");
|
|
217
|
+
expect(stderr.join("")).toContain('"event":"file-uploaded"');
|
|
218
|
+
expect(stderr.join("")).toContain('"name":"e2e.txt"');
|
|
219
|
+
expect(stderr.join("")).toContain('"tool":"UploadUserFile"');
|
|
220
|
+
});
|
|
221
|
+
test("warns when a sandbox link is streamed without a file-uploaded event", async () => {
|
|
222
|
+
process.env.LOBU_API_TOKEN = "cli-token";
|
|
223
|
+
const stdout = [];
|
|
224
|
+
const stderr = [];
|
|
225
|
+
captureTerminal({ stdout, stderr });
|
|
226
|
+
globalThis.fetch = mock(async (input, init) => {
|
|
227
|
+
const url = String(input);
|
|
228
|
+
if (url === "http://gateway.test/api/v1/agents/careops/messages" &&
|
|
229
|
+
init?.method === "POST") {
|
|
230
|
+
return Response.json({
|
|
231
|
+
success: true,
|
|
232
|
+
eventsUrl: "/api/v1/agents/careops/events?platform=telegram",
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
if (url ===
|
|
236
|
+
"http://gateway.test/api/v1/agents/careops/events?platform=telegram" &&
|
|
237
|
+
!init?.method) {
|
|
238
|
+
return createSseResponse([
|
|
239
|
+
{
|
|
240
|
+
event: "output",
|
|
241
|
+
data: {
|
|
242
|
+
content: "[Download cli-proof.txt](sandbox:/workspace/cli-proof.txt)",
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
{ event: "complete", data: {} },
|
|
246
|
+
]);
|
|
247
|
+
}
|
|
248
|
+
throw new Error(`Unexpected fetch: ${url}`);
|
|
249
|
+
});
|
|
250
|
+
await chatCommand(exampleDir, "send me cli-proof.txt as a file", {
|
|
251
|
+
gateway: "http://gateway.test",
|
|
252
|
+
user: "telegram:chat-123",
|
|
253
|
+
});
|
|
254
|
+
expect(stdout.join("")).toContain("cli-proof.txt");
|
|
255
|
+
expect(stderr.join("")).toContain("no file-uploaded event was emitted");
|
|
256
|
+
});
|
|
257
|
+
test("streams raw output chunks without corrupting fragmented markdown", async () => {
|
|
258
|
+
process.env.LOBU_API_TOKEN = "cli-token";
|
|
259
|
+
const stdout = [];
|
|
260
|
+
const stderr = [];
|
|
261
|
+
captureTerminal({ stdout, stderr });
|
|
262
|
+
globalThis.fetch = mock(async (input, init) => {
|
|
263
|
+
const url = String(input);
|
|
264
|
+
if (url === "http://gateway.test/api/v1/agents/careops/messages" &&
|
|
265
|
+
init?.method === "POST") {
|
|
266
|
+
return Response.json({
|
|
267
|
+
success: true,
|
|
268
|
+
eventsUrl: "/api/v1/agents/careops/events?platform=telegram",
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
if (url ===
|
|
272
|
+
"http://gateway.test/api/v1/agents/careops/events?platform=telegram" &&
|
|
273
|
+
!init?.method) {
|
|
274
|
+
return createSseResponse([
|
|
275
|
+
{ event: "output", data: { content: "**Hello" } },
|
|
276
|
+
{ event: "output", data: { content: " world**" } },
|
|
277
|
+
{ event: "complete", data: {} },
|
|
278
|
+
]);
|
|
279
|
+
}
|
|
280
|
+
throw new Error(`Unexpected fetch: ${url}`);
|
|
281
|
+
});
|
|
282
|
+
await chatCommand(exampleDir, "say hello", {
|
|
283
|
+
gateway: "http://gateway.test",
|
|
284
|
+
user: "telegram:chat-123",
|
|
285
|
+
});
|
|
286
|
+
expect(stdout.join("")).toContain("**Hello world**");
|
|
287
|
+
expect(stderr.join("")).not.toContain("file-uploaded");
|
|
288
|
+
});
|
|
289
|
+
test("streams platform-mode output for image and voice requests from the example agent", async () => {
|
|
290
|
+
process.env.LOBU_API_TOKEN = "cli-token";
|
|
291
|
+
const stdout = [];
|
|
292
|
+
const stderr = [];
|
|
293
|
+
const messageBodies = [];
|
|
294
|
+
captureTerminal({ stdout, stderr });
|
|
295
|
+
globalThis.fetch = mock(async (input, init) => {
|
|
296
|
+
const url = String(input);
|
|
297
|
+
if (url === "http://gateway.test/api/v1/agents/careops/messages" &&
|
|
298
|
+
init?.method === "POST") {
|
|
299
|
+
const body = JSON.parse(String(init.body));
|
|
300
|
+
messageBodies.push(body);
|
|
301
|
+
return Response.json({
|
|
302
|
+
success: true,
|
|
303
|
+
eventsUrl: "/api/v1/agents/careops/events?platform=telegram",
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
if (url ===
|
|
307
|
+
"http://gateway.test/api/v1/agents/careops/events?platform=telegram" &&
|
|
308
|
+
!init?.method) {
|
|
309
|
+
return createSseResponse([
|
|
310
|
+
{
|
|
311
|
+
event: "output",
|
|
312
|
+
data: {
|
|
313
|
+
content: "Image sent successfully (generated with openai).\nVoice message sent successfully (generated with openai).\n",
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
{ event: "complete", data: {} },
|
|
317
|
+
]);
|
|
318
|
+
}
|
|
319
|
+
throw new Error(`Unexpected fetch: ${url}`);
|
|
320
|
+
});
|
|
321
|
+
await chatCommand(exampleDir, "send an image and a voice reply", {
|
|
322
|
+
gateway: "http://gateway.test",
|
|
323
|
+
user: "telegram:chat-123",
|
|
324
|
+
});
|
|
325
|
+
expect(messageBodies).toEqual([
|
|
326
|
+
{
|
|
327
|
+
platform: "telegram",
|
|
328
|
+
content: "send an image and a voice reply",
|
|
329
|
+
telegram: { chatId: "chat-123" },
|
|
330
|
+
},
|
|
331
|
+
]);
|
|
332
|
+
expect(stdout.join("")).toContain("Image sent successfully");
|
|
333
|
+
expect(stdout.join("")).toContain("Voice message sent successfully");
|
|
334
|
+
expect(stderr.join("")).not.toContain("Failed");
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
//# sourceMappingURL=chat.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.integration.test.js","sourceRoot":"","sources":["../../src/__tests__/chat.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-memory.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/init-memory.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { generateDockerCompose, generateLobuToml, generateOwlettoProjectLayout, } from "../commands/init";
|
|
6
|
+
describe("init memory scaffolding", () => {
|
|
7
|
+
let projectDir;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
projectDir = mkdtempSync(join(tmpdir(), "lobu-init-memory-"));
|
|
10
|
+
mkdirSync(join(projectDir, "agents", "support"), { recursive: true });
|
|
11
|
+
});
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
rmSync(projectDir, { recursive: true, force: true });
|
|
14
|
+
});
|
|
15
|
+
test("generateLobuToml writes the [memory.owletto] block when enabled", async () => {
|
|
16
|
+
await generateLobuToml(projectDir, {
|
|
17
|
+
agentName: "support",
|
|
18
|
+
allowedDomains: "github.com,.github.com",
|
|
19
|
+
includeOwlettoMemory: true,
|
|
20
|
+
});
|
|
21
|
+
const content = readFileSync(join(projectDir, "lobu.toml"), "utf-8");
|
|
22
|
+
expect(content).toContain("[memory.owletto]");
|
|
23
|
+
expect(content).toContain('config = "./owletto.yaml"');
|
|
24
|
+
expect(content).toContain('models = "./models"');
|
|
25
|
+
expect(content).toContain('data = "./data"');
|
|
26
|
+
});
|
|
27
|
+
test("generateOwlettoProjectLayout creates the new Owletto structure", async () => {
|
|
28
|
+
await generateOwlettoProjectLayout(projectDir, {
|
|
29
|
+
org: "support",
|
|
30
|
+
name: "Support",
|
|
31
|
+
});
|
|
32
|
+
const owlettoYaml = readFileSync(join(projectDir, "owletto.yaml"), "utf-8");
|
|
33
|
+
expect(owlettoYaml).toContain("version: 1");
|
|
34
|
+
expect(owlettoYaml).toContain("org: support");
|
|
35
|
+
expect(statSync(join(projectDir, "models")).isDirectory()).toBe(true);
|
|
36
|
+
expect(statSync(join(projectDir, "data", "entities")).isDirectory()).toBe(true);
|
|
37
|
+
expect(statSync(join(projectDir, "data", "relationships")).isDirectory()).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
test("generateDockerCompose keeps MEMORY_URL as an optional base override", () => {
|
|
40
|
+
const content = generateDockerCompose({
|
|
41
|
+
projectName: "support",
|
|
42
|
+
gatewayPort: "8080",
|
|
43
|
+
dockerfilePath: "./Dockerfile.worker",
|
|
44
|
+
deploymentMode: "embedded",
|
|
45
|
+
includeOwlettoLocal: true,
|
|
46
|
+
});
|
|
47
|
+
expect(content).toContain("Optional Owletto base MCP URL override");
|
|
48
|
+
expect(content).toContain("MEMORY_URL: ${MEMORY_URL:-}");
|
|
49
|
+
expect(content).toContain("owletto:");
|
|
50
|
+
expect(content).toContain("owletto-postgres:");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=init-memory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-memory.test.js","sourceRoot":"","sources":["../../src/__tests__/init-memory.test.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/chat.js
CHANGED
|
@@ -110,7 +110,7 @@ async function sendViaPlatform(gatewayUrl, authToken, opts) {
|
|
|
110
110
|
? result.eventsUrl
|
|
111
111
|
: `${gatewayUrl}${result.eventsUrl}`;
|
|
112
112
|
const sseController = new AbortController();
|
|
113
|
-
await streamResponse(sseUrl, authToken, sseController);
|
|
113
|
+
await streamResponse(sseUrl, authToken, sseController, result.messageId);
|
|
114
114
|
}
|
|
115
115
|
else {
|
|
116
116
|
console.log(chalk.dim(` Message sent via ${opts.platform}. Response will appear on the platform.\n`));
|
|
@@ -175,7 +175,29 @@ async function resolveAgentId(cwd) {
|
|
|
175
175
|
const ids = Object.keys(result.config.agents);
|
|
176
176
|
return ids[0];
|
|
177
177
|
}
|
|
178
|
-
async function
|
|
178
|
+
async function writeStdout(text) {
|
|
179
|
+
await new Promise((resolve, reject) => {
|
|
180
|
+
process.stdout.write(text, (error) => {
|
|
181
|
+
if (error) {
|
|
182
|
+
reject(error);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
resolve();
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
async function writeStderr(text) {
|
|
190
|
+
await new Promise((resolve, reject) => {
|
|
191
|
+
process.stderr.write(text, (error) => {
|
|
192
|
+
if (error) {
|
|
193
|
+
reject(error);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
resolve();
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
async function streamResponse(sseUrl, token, controller, expectedMessageId) {
|
|
179
201
|
const OVERALL_TIMEOUT_MS = 5 * 60 * 1000;
|
|
180
202
|
const IDLE_TIMEOUT_MS = 60 * 1000;
|
|
181
203
|
const overallTimer = setTimeout(() => controller.abort(), OVERALL_TIMEOUT_MS);
|
|
@@ -197,6 +219,8 @@ async function streamResponse(sseUrl, token, controller) {
|
|
|
197
219
|
const decoder = new TextDecoder();
|
|
198
220
|
let buffer = "";
|
|
199
221
|
let currentEvent = "";
|
|
222
|
+
let sawFileUploadedEvent = false;
|
|
223
|
+
let sawSandboxLink = false;
|
|
200
224
|
while (true) {
|
|
201
225
|
const { done, value } = await reader.read();
|
|
202
226
|
if (done)
|
|
@@ -213,14 +237,26 @@ async function streamResponse(sseUrl, token, controller) {
|
|
|
213
237
|
const data = parseJSON(line.slice(6));
|
|
214
238
|
if (!data)
|
|
215
239
|
continue;
|
|
240
|
+
if (expectedMessageId &&
|
|
241
|
+
currentEvent !== "connected" &&
|
|
242
|
+
currentEvent !== "ping" &&
|
|
243
|
+
typeof data.messageId === "string" &&
|
|
244
|
+
data.messageId !== expectedMessageId) {
|
|
245
|
+
currentEvent = "";
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
216
248
|
switch (currentEvent) {
|
|
217
249
|
case "output":
|
|
218
|
-
if (typeof data.content === "string")
|
|
219
|
-
|
|
250
|
+
if (typeof data.content === "string") {
|
|
251
|
+
if (data.content.includes("sandbox:/")) {
|
|
252
|
+
sawSandboxLink = true;
|
|
253
|
+
}
|
|
254
|
+
await writeStdout(data.content);
|
|
255
|
+
}
|
|
220
256
|
break;
|
|
221
257
|
case "ephemeral":
|
|
222
258
|
if (typeof data.content === "string") {
|
|
223
|
-
|
|
259
|
+
await writeStderr(`\n${renderMarkdown(data.content)}\n`);
|
|
224
260
|
}
|
|
225
261
|
controller.abort();
|
|
226
262
|
return;
|
|
@@ -231,23 +267,22 @@ async function streamResponse(sseUrl, token, controller) {
|
|
|
231
267
|
.map(([k, v]) => ` ${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`)
|
|
232
268
|
.join("\n")
|
|
233
269
|
: "";
|
|
234
|
-
|
|
235
|
-
const options = ["
|
|
270
|
+
await writeStderr(chalk.yellow(`\n Tool Approval Required\n ${data.mcpId} → ${data.toolName}\n${argsText}\n`));
|
|
271
|
+
const options = ["1h", "24h", "always", "deny"];
|
|
236
272
|
const optionLabels = {
|
|
237
|
-
once: "1 min",
|
|
238
273
|
"1h": "1h",
|
|
239
274
|
"24h": "24h",
|
|
240
275
|
always: "always",
|
|
241
276
|
deny: "deny always",
|
|
242
277
|
};
|
|
243
|
-
|
|
278
|
+
await writeStderr(`${options
|
|
244
279
|
.map((o, i) => ` ${chalk.bold(`${i + 1}`)}. ${o === "deny" ? chalk.red(optionLabels[o]) : chalk.green(optionLabels[o])}`)
|
|
245
|
-
.join("\n"));
|
|
280
|
+
.join("\n")}\n`);
|
|
246
281
|
const rl = createInterface({
|
|
247
282
|
input: process.stdin,
|
|
248
283
|
output: process.stderr,
|
|
249
284
|
});
|
|
250
|
-
const answer = await new Promise((resolve) => rl.question(chalk.dim("\n Choice (1-
|
|
285
|
+
const answer = await new Promise((resolve) => rl.question(chalk.dim("\n Choice (1-4): "), (a) => {
|
|
251
286
|
rl.close();
|
|
252
287
|
resolve(a.trim());
|
|
253
288
|
}));
|
|
@@ -270,27 +305,34 @@ async function streamResponse(sseUrl, token, controller) {
|
|
|
270
305
|
const text = result.result.content
|
|
271
306
|
.map((c) => c.text)
|
|
272
307
|
.join("\n");
|
|
273
|
-
|
|
308
|
+
await writeStdout(renderMarkdown(text));
|
|
274
309
|
}
|
|
275
|
-
|
|
310
|
+
await writeStderr(chalk.green(`\n Tool ${decision === "deny" ? "denied" : "approved"} (${decision})\n`));
|
|
276
311
|
}
|
|
277
312
|
else {
|
|
278
|
-
|
|
313
|
+
await writeStderr(chalk.red(`\n Approval failed: ${await approveRes.text()}\n`));
|
|
279
314
|
}
|
|
280
315
|
break;
|
|
281
316
|
}
|
|
282
317
|
case "link-button":
|
|
283
318
|
case "question":
|
|
284
319
|
case "suggestion":
|
|
285
|
-
|
|
320
|
+
case "file-uploaded":
|
|
321
|
+
if (currentEvent === "file-uploaded") {
|
|
322
|
+
sawFileUploadedEvent = true;
|
|
323
|
+
}
|
|
324
|
+
await writeStderr(`${JSON.stringify({ event: currentEvent, ...data })}\n`);
|
|
286
325
|
break;
|
|
287
326
|
case "complete":
|
|
288
|
-
|
|
327
|
+
await writeStdout("\n");
|
|
328
|
+
if (sawSandboxLink && !sawFileUploadedEvent) {
|
|
329
|
+
await writeStderr(chalk.red("\n Warning: assistant output contained a sandbox/local file link, but no file-uploaded event was emitted. Treat this as a failed file-delivery attempt.\n"));
|
|
330
|
+
}
|
|
289
331
|
controller.abort();
|
|
290
332
|
return;
|
|
291
333
|
case "error":
|
|
292
|
-
|
|
293
|
-
|
|
334
|
+
await writeStdout("\n");
|
|
335
|
+
await writeStderr(chalk.red(`\n Agent error: ${String(data.error)}\n`));
|
|
294
336
|
controller.abort();
|
|
295
337
|
return;
|
|
296
338
|
}
|