@inetafrica/open-claudia 3.5.19 → 3.5.23
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/.env.example +8 -3
- package/CHANGELOG.md +37 -0
- package/README.md +5 -4
- package/bin/cli.js +6 -0
- package/bin/teach.js +78 -0
- package/bot.js +7 -0
- package/channels/kazee/adapter.js +30 -0
- package/core/actions.js +4 -0
- package/core/auth-flow.js +7 -2
- package/core/bot-apps.js +133 -0
- package/core/browser-control.js +540 -0
- package/core/browser-lock.js +51 -0
- package/core/browser-teach.js +1012 -0
- package/core/browser-view.js +5 -2
- package/core/cards.js +4 -2
- package/core/dream.js +132 -10
- package/core/handlers.js +16 -2
- package/core/limit-pickup.js +24 -20
- package/core/providers/claude.js +15 -8
- package/core/providers/events.js +25 -1
- package/core/providers/utility-policy.js +31 -6
- package/core/runner.js +203 -10
- package/core/scheduler.js +57 -0
- package/core/state.js +14 -0
- package/core/system-prompt.js +12 -2
- package/core/tool-guard.js +343 -0
- package/core/turn-journal.js +55 -2
- package/core/usage-limits.js +110 -0
- package/core/utility-agent.js +109 -15
- package/package.json +2 -2
- package/test-fixtures/fake-agent-cli.js +46 -2
- package/test-provider-boot-matrix.js +6 -2
- package/test-provider-capabilities.js +1 -1
- package/test-provider-claude.js +7 -5
- package/test-provider-events.js +43 -1
- package/test-provider-language.js +15 -1
- package/web.js +68 -0
package/web.js
CHANGED
|
@@ -375,6 +375,63 @@ async function liveChannels() {
|
|
|
375
375
|
|
|
376
376
|
const USER_ACCESS_ROUTES = new Set(["/api/auth/approve", "/api/auth/deny", "/api/auth/remove"]);
|
|
377
377
|
|
|
378
|
+
// Browser app routes (core/bot-apps.js, core/browser-control.js, core/browser-teach.js):
|
|
379
|
+
// POST /api/apps/check may this person open the app (C1)
|
|
380
|
+
// POST /api/browser/control GET /api/browser/control take / renew / release, status (C2)
|
|
381
|
+
// POST /api/browser/input the driver's input events (C3)
|
|
382
|
+
// POST /api/browser/teach Teach me: start / stop / cancel (C4)
|
|
383
|
+
// GET /api/browser/teach[/<id>[/pictures/<n>]]?userId= that person's recordings only
|
|
384
|
+
const BROWSER_APP_ROUTE = /^\/api\/(?:apps\/check|browser\/(?:control|input|teach))(?:[/?]|$)/;
|
|
385
|
+
const BROWSER_APP_MAX_BODY = 64 * 1024;
|
|
386
|
+
const BROWSER_APP_USER_ID = /^[A-Za-z0-9._:-]{1,100}$/;
|
|
387
|
+
|
|
388
|
+
async function handleBrowserApp(req, res, body) {
|
|
389
|
+
const send = (status, obj) => {
|
|
390
|
+
res.writeHead(status, { "Content-Type": "application/json", "Cache-Control": "no-store" });
|
|
391
|
+
return res.end(JSON.stringify(obj));
|
|
392
|
+
};
|
|
393
|
+
const answer = (result) => send(result.status, result.body);
|
|
394
|
+
const parsedUrl = new URL(req.url, "http://localhost");
|
|
395
|
+
const route = parsedUrl.pathname;
|
|
396
|
+
let parsed = {};
|
|
397
|
+
if (req.method === "POST") {
|
|
398
|
+
if (Buffer.byteLength(body || "") > BROWSER_APP_MAX_BODY) return send(413, { error: "too-large" });
|
|
399
|
+
try { parsed = JSON.parse(body || "{}"); } catch (e) { return send(400, { error: "bad-json" }); }
|
|
400
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return send(400, { error: "bad-json" });
|
|
401
|
+
}
|
|
402
|
+
const control = require("./core/browser-control");
|
|
403
|
+
if (route === "/api/apps/check" && req.method === "POST") return send(200, require("./core/bot-apps").checkAccess(parsed));
|
|
404
|
+
if (route === "/api/browser/control" && req.method === "POST") return answer(await control.control(parsed));
|
|
405
|
+
if (route === "/api/browser/control" && req.method === "GET") return answer(control.status());
|
|
406
|
+
if (route === "/api/browser/input" && req.method === "POST") return answer(await control.input(parsed));
|
|
407
|
+
if (route === "/api/browser/teach" && req.method === "POST") return answer(await control.teachAction(parsed));
|
|
408
|
+
if (req.method === "GET" && (route === "/api/browser/teach" || route.startsWith("/api/browser/teach/"))) {
|
|
409
|
+
const teach = require("./core/browser-teach");
|
|
410
|
+
const userId = parsedUrl.searchParams.get("userId") || "";
|
|
411
|
+
if (!BROWSER_APP_USER_ID.test(userId)) return send(400, { error: "userId required" });
|
|
412
|
+
if (route === "/api/browser/teach") return send(200, teach.listRecordings({ userId }));
|
|
413
|
+
const match = route.match(/^\/api\/browser\/teach\/([a-z0-9-]{1,64})(?:\/pictures\/(\d{1,4}))?$/);
|
|
414
|
+
if (!match) return send(404, { error: "not-found" });
|
|
415
|
+
if (!match[2]) {
|
|
416
|
+
const rec = teach.getRecording(match[1], { userId });
|
|
417
|
+
return rec ? send(200, rec) : send(404, { error: "not-found" });
|
|
418
|
+
}
|
|
419
|
+
const file = teach.picturePath(match[1], Number(match[2]), { userId });
|
|
420
|
+
if (!file) return send(404, { error: "not-found" });
|
|
421
|
+
let data;
|
|
422
|
+
// Deleted a moment ago (teach finish, cancel, the sweeper): gone, like any deleted picture.
|
|
423
|
+
try { data = fs.readFileSync(file); } catch (_) { return send(404, { error: "not-found" }); }
|
|
424
|
+
res.writeHead(200, {
|
|
425
|
+
"Content-Type": "image/jpeg",
|
|
426
|
+
"Content-Length": data.length,
|
|
427
|
+
"Cache-Control": "no-store",
|
|
428
|
+
"X-Content-Type-Options": "nosniff",
|
|
429
|
+
});
|
|
430
|
+
return res.end(data);
|
|
431
|
+
}
|
|
432
|
+
return send(404, { error: "Not found" });
|
|
433
|
+
}
|
|
434
|
+
|
|
378
435
|
async function handleAPI(req, res, body, dependencies = {}) {
|
|
379
436
|
const url = req.url;
|
|
380
437
|
|
|
@@ -643,6 +700,17 @@ async function handleAPI(req, res, body, dependencies = {}) {
|
|
|
643
700
|
return res.end(JSON.stringify({ content: loadLogs() }));
|
|
644
701
|
}
|
|
645
702
|
|
|
703
|
+
// Browser app in Kazee Chat (bot apps v1): who may open it, Take over, input and Teach me.
|
|
704
|
+
// Machine-to-machine for Agent Space, so the control token only: a dashboard session is
|
|
705
|
+
// refused, like /api/otp/mint.
|
|
706
|
+
if (BROWSER_APP_ROUTE.test(url)) {
|
|
707
|
+
if (!checkBearerAuth(req)) {
|
|
708
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
709
|
+
return res.end(JSON.stringify({ error: "Control token required" }));
|
|
710
|
+
}
|
|
711
|
+
return handleBrowserApp(req, res, body);
|
|
712
|
+
}
|
|
713
|
+
|
|
646
714
|
// Live view of the bot's own browser, watch-only (core/browser-view.js): the running
|
|
647
715
|
// agent-browser sessions, and one session's screen as server-sent events.
|
|
648
716
|
if (url.split("?")[0] === "/api/browser/sessions" && req.method === "GET") {
|