arisa 5.1.12 → 5.1.13
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.
|
@@ -76,7 +76,9 @@ el protocolo, la CLI y la documentación.
|
|
|
76
76
|
- Linux con systemd es la primera plataforma operativa soportada. Master y Slave
|
|
77
77
|
pueden coexistir en un host mediante homes, sockets, PID y logs separados.
|
|
78
78
|
- El usuario dedicado es la opción recomendada. El usuario actual está
|
|
79
|
-
permitido y root requiere
|
|
79
|
+
permitido y root requiere una elección explícita durante la instalación.
|
|
80
|
+
Una Slave elegida como root queda por defecto en modo host completo con todas
|
|
81
|
+
las capacidades v1; una política guardada posteriormente reemplaza ese default.
|
|
80
82
|
- Los jobs dirigidos a Slaves offline se rechazan en v1.
|
|
81
83
|
- La instalación remota acepta sólo tools del catálogo verificado y requiere
|
|
82
84
|
confirmación. Nunca se instala código silenciosamente como root.
|
|
@@ -565,9 +567,10 @@ Ejecutar Arisa Slave como:
|
|
|
565
567
|
```
|
|
566
568
|
|
|
567
569
|
Se admite elegir `root`. El perfil resultante y todos los informes de Master
|
|
568
|
-
deben mostrar que Slave tiene autoridad root.
|
|
569
|
-
|
|
570
|
-
|
|
570
|
+
deben mostrar que Slave tiene autoridad root. Elegir root instala por defecto un
|
|
571
|
+
perfil de host completo con raíz `/` y todas las capacidades v1, incluida
|
|
572
|
+
`process.exec`. Una política persistida después puede volver a restringir las
|
|
573
|
+
raíces y operaciones en la capa de aplicación.
|
|
571
574
|
|
|
572
575
|
Las restricciones de aplicación reducen el uso accidental, pero dejan de ser
|
|
573
576
|
una frontera de seguridad si el propio proceso de Slave resulta comprometido:
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
3
|
"repository": "https://github.com/clasen/Arisa.git",
|
|
4
|
-
"commit": "
|
|
4
|
+
"commit": "8438bffbc656de7f85e9a98fe7d8804b3c0224ea",
|
|
5
5
|
"tools": {
|
|
6
6
|
"master-slave": {
|
|
7
7
|
"files": {
|
|
8
|
-
"README.md": "
|
|
8
|
+
"README.md": "8533804fda909c2f7bb0d05d40e2d6be9ef9126215bde70cd0ac4dda4afe9c55",
|
|
9
9
|
"batch-runner.js": "be3939efe9c5800d3078c15a094f53db1094ef6e809d7826db7c47e3bec0c31b",
|
|
10
10
|
"chat-state-store.js": "50de39aa33432733bb688eb01968e314a32b169324a66d0f0089b2a19ed9c880",
|
|
11
11
|
"config.js": "ff1c1cb6701ae1da7a6eb1519ba96a416e48daa73c2155a6f93cf5d64f65cef8",
|
|
12
|
-
"index.js": "
|
|
12
|
+
"index.js": "8586303b3d1bf937932159adbe9b69c1031e6a393300e7d3aca93910ddfab082",
|
|
13
13
|
"lib/bootstrap-url.js": "f05925cc0f0dff0882f94f9908c6f2c80aa8632cd51f63389381dcbb0f73afb3",
|
|
14
14
|
"lib/encrypted-frames.js": "47e1b11fafdbbcdfd86a0993a47a774e4f37d6386edeaf8ec1c8511b109728cf",
|
|
15
15
|
"lib/handshake-crypto.js": "9728b117aad7de53f5f0e255c0fd865ee1a19633368730a7634334d374094578",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"master-domain.js": "10b7dfb43eb9939eb5baec54f742076cc73a2add6589a0ff57c51bc79c236faf",
|
|
21
21
|
"network-session.js": "db2d81a7ef47af29236d963b98e21414a11fef68e8b20895126eaad3f696ba3d",
|
|
22
22
|
"package.json": "8e9177238ba878dd4b51e32e0ed58a39c5789186c22b19ad7a43ab6caf9dc469",
|
|
23
|
-
"remote-runtime.js": "
|
|
23
|
+
"remote-runtime.js": "55dd7e577a822be17c2f337798a2d7f44ad0c5b6d68c46490e058282135c4658",
|
|
24
24
|
"slave-operations.js": "fec2e8addfff98f080284f24f722c1516124e5f6d12d8c03bb3c9cc0c475d1d6",
|
|
25
25
|
"state-store.js": "c56849a3f1b9c990128276e17963034a7836abacedc44f2e500d5732ebf9e451",
|
|
26
26
|
"test/batch-runner.test.js": "f14c6fddff5d6240008eef388df6a153e82490e534d06419d7bb267e4f4693a7",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"test/network-session.test.js": "2e459346cc9364be705bc5f54691245044588b2cd03ae77e2e870dee6dfbcca6",
|
|
32
32
|
"test/pairing-secret-store.test.js": "c51257365fd0b641c24768d710cdff2d1c5f8816bf90f66c2c01a226904cb43f",
|
|
33
33
|
"test/profile-catalog.test.js": "d8e297bee413d53ec13f2e1779c13f2e019cb8304976d567eab0e9f1ca36637c",
|
|
34
|
-
"test/remote-runtime.test.js": "
|
|
34
|
+
"test/remote-runtime.test.js": "1161bd653dc47b9b8219bf848d0d395ce390f2bb7b58ea41e3e4270b1d504798",
|
|
35
35
|
"test/slave-operations.test.js": "a84526ad7554c7d03192a68655b4637bec18750559a5c3436f7471e912ca74cc",
|
|
36
36
|
"tool.manifest.json": "abf24c67b1d9ef0331ded59e04dcc092772419e74691c0d753ab51b40286d6f6"
|
|
37
37
|
}
|
|
@@ -354,21 +354,23 @@ function buildStartupMessage(chatMeta = {}) {
|
|
|
354
354
|
}
|
|
355
355
|
|
|
356
356
|
export async function collectText(session, prompt, { logger, chatId, onSlowPrompt } = {}) {
|
|
357
|
-
|
|
357
|
+
const assistantMessages = [];
|
|
358
|
+
let assistantMessage = "";
|
|
358
359
|
let assistantErrorMessage = "";
|
|
359
|
-
let shouldSeparateAssistantMessage = false;
|
|
360
360
|
let slowPromptTimer = null;
|
|
361
|
+
const finishAssistantMessage = () => {
|
|
362
|
+
if (assistantMessage && !isSilentReply(assistantMessage)) {
|
|
363
|
+
assistantMessages.push(assistantMessage);
|
|
364
|
+
}
|
|
365
|
+
assistantMessage = "";
|
|
366
|
+
};
|
|
361
367
|
const unsubscribe = session.subscribe((event) => {
|
|
362
368
|
if (event.arisaPromptScoped === false) return;
|
|
363
369
|
if (event.type === "message_start" && event.message.role === "assistant") {
|
|
364
|
-
|
|
370
|
+
finishAssistantMessage();
|
|
365
371
|
}
|
|
366
372
|
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
|
|
367
|
-
|
|
368
|
-
text += "\n\n";
|
|
369
|
-
shouldSeparateAssistantMessage = false;
|
|
370
|
-
}
|
|
371
|
-
text += event.assistantMessageEvent.delta;
|
|
373
|
+
assistantMessage += event.assistantMessageEvent.delta;
|
|
372
374
|
}
|
|
373
375
|
if (event.type === "message_end" && event.message?.role === "assistant") {
|
|
374
376
|
if (event.message.stopReason === "error") {
|
|
@@ -377,6 +379,7 @@ export async function collectText(session, prompt, { logger, chatId, onSlowPromp
|
|
|
377
379
|
// Auto-compaction and retry can emit a transient error before a successful continuation.
|
|
378
380
|
assistantErrorMessage = "";
|
|
379
381
|
}
|
|
382
|
+
finishAssistantMessage();
|
|
380
383
|
}
|
|
381
384
|
const logMessage = sessionEventLogMessage(event);
|
|
382
385
|
if (logMessage) logger?.log("agent", `chat ${chatId} ${logMessage}`);
|
|
@@ -402,7 +405,8 @@ export async function collectText(session, prompt, { logger, chatId, onSlowPromp
|
|
|
402
405
|
throw new Error(assistantErrorMessage);
|
|
403
406
|
}
|
|
404
407
|
|
|
405
|
-
|
|
408
|
+
finishAssistantMessage();
|
|
409
|
+
return assistantMessages.join("\n\n").trim();
|
|
406
410
|
}
|
|
407
411
|
|
|
408
412
|
export function isSilentReply(text) {
|
|
@@ -59,6 +59,44 @@ test("collectText preserves the final assistant error", async () => {
|
|
|
59
59
|
await assert.rejects(() => collectText(session, "hello"), /terminal failure/);
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
+
test("collectText drops a standalone silent event reply before a steered response", async () => {
|
|
63
|
+
const session = createSession([
|
|
64
|
+
{ type: "message_start", message: { role: "assistant" } },
|
|
65
|
+
{
|
|
66
|
+
type: "message_update",
|
|
67
|
+
message: { role: "assistant" },
|
|
68
|
+
assistantMessageEvent: { type: "text_delta", delta: "NO_REPLY" }
|
|
69
|
+
},
|
|
70
|
+
{ type: "message_end", message: { role: "assistant", stopReason: "stop" } },
|
|
71
|
+
{ type: "message_start", message: { role: "assistant" } },
|
|
72
|
+
{
|
|
73
|
+
type: "message_update",
|
|
74
|
+
message: { role: "assistant" },
|
|
75
|
+
assistantMessageEvent: { type: "text_delta", delta: "The useful Telegram response." }
|
|
76
|
+
},
|
|
77
|
+
{ type: "message_end", message: { role: "assistant", stopReason: "stop" } }
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
assert.equal(await collectText(session, "event followed by a Telegram steer"), "The useful Telegram response.");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("collectText preserves useful text in the same message as a silent marker", async () => {
|
|
84
|
+
const session = createSession([
|
|
85
|
+
{ type: "message_start", message: { role: "assistant" } },
|
|
86
|
+
{
|
|
87
|
+
type: "message_update",
|
|
88
|
+
message: { role: "assistant" },
|
|
89
|
+
assistantMessageEvent: { type: "text_delta", delta: "NO_REPLY\n\nThis text belongs to the same response." }
|
|
90
|
+
},
|
|
91
|
+
{ type: "message_end", message: { role: "assistant", stopReason: "stop" } }
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
assert.equal(
|
|
95
|
+
await collectText(session, "one response that mentions the marker"),
|
|
96
|
+
"NO_REPLY\n\nThis text belongs to the same response."
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
62
100
|
test("recognizes standalone silent reply markers", () => {
|
|
63
101
|
assert.equal(isSilentReply("NO_REPLY"), true);
|
|
64
102
|
assert.equal(isSilentReply("No reply needed."), true);
|
|
@@ -3,6 +3,7 @@ import crypto from "node:crypto";
|
|
|
3
3
|
import { cp, mkdir, mkdtemp, readFile, rm, symlink, writeFile } from "node:fs/promises";
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
6
7
|
import test from "node:test";
|
|
7
8
|
import {
|
|
8
9
|
installBundledOfficialTool,
|
|
@@ -59,6 +60,16 @@ test("verifies the exact file set and digests", async (t) => {
|
|
|
59
60
|
await assert.rejects(() => verifyOfficialToolTree(source, files), /unexpected=extra.js/);
|
|
60
61
|
});
|
|
61
62
|
|
|
63
|
+
test("bundled master-slave lock matches the catalog source", async () => {
|
|
64
|
+
const lock = JSON.parse(await readFile(new URL("../src/official-tools.lock.json", import.meta.url), "utf8"));
|
|
65
|
+
const source = fileURLToPath(new URL("../../tools/master-slave/", import.meta.url));
|
|
66
|
+
|
|
67
|
+
assert.deepEqual(
|
|
68
|
+
await verifyOfficialToolTree(source, lock.tools["master-slave"].files),
|
|
69
|
+
{ files: Object.keys(lock.tools["master-slave"].files).length }
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
62
73
|
test("rejects symbolic links before deployment", async (t) => {
|
|
63
74
|
const { source, files } = await fixture(t);
|
|
64
75
|
await symlink(path.join(source, "index.js"), path.join(source, "link.js"));
|