@canonmsg/agent-sdk 12.3.1 → 12.4.1
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 +19 -15
- package/dist/chunks/{chunk-SKFI2MJA.js → chunk-6PKXASSK.js} +42 -4
- package/dist/chunks/{chunk-5MI6Q3VS.js → chunk-GWQF4WFT.js} +4 -0
- package/dist/chunks/{chunk-HI2SVCUL.js → chunk-NXL4C2R6.js} +315 -60
- package/dist/chunks/{mls-crypto-D5YAGYJ3.js → mls-crypto-LGPCXM3K.js} +1 -1
- package/dist/cli.js +38 -24
- package/dist/index.d.ts +2 -0
- package/dist/index.js +9 -3
- package/dist/internal/backend-contracts/endpointContentPolicy.d.ts +5 -0
- package/dist/internal/endpoint/mls-dev-groups.d.ts +8 -0
- package/dist/media.js +2 -2
- package/dist/mls/darwin-arm64/canon-mls-custody +0 -0
- package/dist/mls/linux-arm64/canon-mls-custody +0 -0
- package/dist/mls/linux-x64/canon-mls-custody +0 -0
- package/dist/runner/mls-bundled.d.ts +25 -0
- package/dist/runner/mls-managed.d.ts +31 -0
- package/dist/runner/mls.d.ts +13 -6
- package/package.json +2 -2
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
BoundedFileReadError,
|
|
4
4
|
CanonClient,
|
|
5
5
|
MAX_CANON_MEDIA_BYTES,
|
|
6
|
+
NodeMlsDevCustodyError,
|
|
6
7
|
RUNTIME_NEW_SESSION_ACTION,
|
|
7
8
|
RUNTIME_STOP_ACTION,
|
|
8
9
|
RUNTIME_STOP_AND_DROP_ACTION,
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
sendMessageWithRetryChunked,
|
|
30
31
|
splitTextByUtf8Bytes,
|
|
31
32
|
verifyCanonRuntimeConnection
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-6PKXASSK.js";
|
|
33
34
|
import {
|
|
34
35
|
CONNECTOR_RELAY_ANSWER_WITHIN_MS,
|
|
35
36
|
CONNECTOR_RELAY_INSTALLATION_PATTERN,
|
|
@@ -58,7 +59,7 @@ import {
|
|
|
58
59
|
parseMlsDevGroupHead,
|
|
59
60
|
parseMlsDevGroupRoster,
|
|
60
61
|
resolveAllowedUploadMimeType
|
|
61
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-GWQF4WFT.js";
|
|
62
63
|
|
|
63
64
|
// src/runner/types.ts
|
|
64
65
|
var DriverSessionError = class extends Error {
|
|
@@ -464,6 +465,8 @@ var GUEST_ITEMS = /* @__PURE__ */ new Set([
|
|
|
464
465
|
"subAgentActivity",
|
|
465
466
|
"sleep"
|
|
466
467
|
]);
|
|
468
|
+
var OWN_LISTINGS = /* @__PURE__ */ new Set(["list_mcp_resources", "list_mcp_resource_templates"]);
|
|
469
|
+
var GUEST = "Only your owner can let you use tools in this conversation, and this turn holds a message from someone else: you cannot read files, run commands or use any tool but the canon MCP server's. Answer from the conversation and what you already know, and say so when something needs your owner.";
|
|
467
470
|
var RISKY = /\brm\s+-[a-z]*[rf]|\bgit\s+(reset\s+--hard|push\s+(-f|--force))|\bdrop\s+(table|database)\b|\bmkfs\b|\bdd\s+if=/i;
|
|
468
471
|
var IMAGE = /\.(png|jpe?g|gif|webp)$/i;
|
|
469
472
|
var isRecord2 = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isRecord");
|
|
@@ -750,10 +753,11 @@ function codexDriver(options) {
|
|
|
750
753
|
settle(new Error(`Codex ended the turn ${ended.status === "interrupted" ? "interrupted" : `with an error${detail ? `: ${oneLine2(detail, 300)}` : ""}`}`));
|
|
751
754
|
}, "conclude");
|
|
752
755
|
const guard = /* @__PURE__ */ __name((item) => {
|
|
753
|
-
if (!guest || GUEST_ITEMS.has(text(item.type)) || item.type === "mcpToolCall" && item.server === CANON) return;
|
|
756
|
+
if (!guest || GUEST_ITEMS.has(text(item.type)) || item.type === "mcpToolCall" && (item.server === CANON || item.server === "codex" && OWN_LISTINGS.has(text(item.tool)))) return;
|
|
754
757
|
interrupt();
|
|
755
758
|
entry.close();
|
|
756
|
-
|
|
759
|
+
const what = item.type === "mcpToolCall" ? `mcpToolCall (${describe(item)})` : text(item.type) || "an unknown item";
|
|
760
|
+
settle(new DriverSessionError(`Codex started ${what} in a turn holding someone other than the owner's message`));
|
|
757
761
|
}, "guard");
|
|
758
762
|
const link = rpc(child, {
|
|
759
763
|
notify(method, params) {
|
|
@@ -813,6 +817,7 @@ function codexDriver(options) {
|
|
|
813
817
|
}
|
|
814
818
|
if (turn.signal.aborted) return finish();
|
|
815
819
|
const started = await link.call("turn/start", { threadId, input: [
|
|
820
|
+
...guest ? [{ type: "text", text: GUEST, text_elements: [] }] : [],
|
|
816
821
|
{ type: "text", text: turn.prompt, text_elements: [] },
|
|
817
822
|
// Images go to the model as images; every attachment's path is also in the prompt for Codex to read.
|
|
818
823
|
...turn.files.filter((file) => IMAGE.test(file)).map((path) => ({ type: "localImage", path }))
|
|
@@ -1485,7 +1490,7 @@ async function loadMlsDevConfiguration(filePath, input) {
|
|
|
1485
1490
|
return { configuration, custody: custody2, close: /* @__PURE__ */ __name(() => custody2.close(), "close") };
|
|
1486
1491
|
}
|
|
1487
1492
|
__name(loadMlsDevConfiguration, "loadMlsDevConfiguration");
|
|
1488
|
-
var MLS_SETUP_ACTIONS = ["status", "provision", "enroll", "renew", "publish", "refresh"];
|
|
1493
|
+
var MLS_SETUP_ACTIONS = ["status", "setup", "provision", "enroll", "renew", "publish", "refresh"];
|
|
1489
1494
|
function mlsDevRoomPackageId(identity, room) {
|
|
1490
1495
|
const hex = createHash4("sha256").update(JSON.stringify([
|
|
1491
1496
|
"canon.mls.dev-agent-room-package.v1",
|
|
@@ -1498,25 +1503,37 @@ function mlsDevRoomPackageId(identity, room) {
|
|
|
1498
1503
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-4${hex.slice(13, 16)}-8${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
|
|
1499
1504
|
}
|
|
1500
1505
|
__name(mlsDevRoomPackageId, "mlsDevRoomPackageId");
|
|
1501
|
-
async function runMlsDevSetup(endpoint, action, room, provision) {
|
|
1506
|
+
async function runMlsDevSetup(endpoint, action, room, provision, provisioned) {
|
|
1502
1507
|
const identity = await endpoint.ready();
|
|
1503
|
-
|
|
1508
|
+
const { environmentId } = identity, devices = endpoint.mlsDevDevice;
|
|
1509
|
+
if (!isMlsEnvironmentId(environmentId) || !devices || !endpoint.mlsDevKeyPackages || !endpoint.mlsDevGroups) throw new Error("MLS_DEV_SETUP_UNAVAILABLE");
|
|
1504
1510
|
if ((action === "publish" || action === "refresh") !== !!room) throw new Error("MLS_DEV_SETUP_ARGUMENTS_INVALID");
|
|
1505
|
-
|
|
1511
|
+
const enroll = /* @__PURE__ */ __name(async () => {
|
|
1512
|
+
await devices.enroll();
|
|
1513
|
+
if ((await devices.read()).status !== "credential_committed") await devices.renew();
|
|
1514
|
+
}, "enroll");
|
|
1515
|
+
const provisionDevice = /* @__PURE__ */ __name(async (unlessProvisioned) => {
|
|
1506
1516
|
if (!provision || identity.ownershipVersion === void 0) throw new Error("MLS_DEV_SETUP_UNAVAILABLE");
|
|
1507
|
-
const device2 = await
|
|
1517
|
+
const device2 = await devices.read();
|
|
1508
1518
|
if (device2.registration || device2.status !== "absent") throw new Error("MLS_DEV_SETUP_ALREADY_PROVISIONED");
|
|
1509
|
-
|
|
1519
|
+
const context = {
|
|
1510
1520
|
version: 1,
|
|
1511
|
-
environmentId
|
|
1521
|
+
environmentId,
|
|
1512
1522
|
installationId: identity.installationId,
|
|
1513
1523
|
principal: { type: "ai_agent", id: await endpoint.mlsPrincipalId(), ownershipVersion: identity.ownershipVersion },
|
|
1514
1524
|
revision: 0
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1525
|
+
};
|
|
1526
|
+
if (!unlessProvisioned || !provisioned?.(context)) await provision(context);
|
|
1527
|
+
}, "provisionDevice");
|
|
1528
|
+
if (action === "setup") {
|
|
1529
|
+
const { status } = await devices.read();
|
|
1530
|
+
if (status === "revoked") throw new Error("MLS_DEV_SETUP_REVOKED");
|
|
1531
|
+
if (status === "absent") await provisionDevice(true);
|
|
1532
|
+
if (status === "registered") await devices.ensureReady();
|
|
1533
|
+
else if (status !== "credential_committed") await enroll();
|
|
1534
|
+
} else if (action === "provision") await provisionDevice(false);
|
|
1535
|
+
else if (action === "enroll") await enroll();
|
|
1536
|
+
else if (action === "renew") await devices.renew();
|
|
1520
1537
|
else if (action === "publish") {
|
|
1521
1538
|
const keyPackageId = mlsDevRoomPackageId(identity, room);
|
|
1522
1539
|
await endpoint.mlsDevKeyPackages.prepare({ keyPackageId });
|
|
@@ -1525,7 +1542,7 @@ async function runMlsDevSetup(endpoint, action, room, provision) {
|
|
|
1525
1542
|
const group = await endpoint.mlsDevGroups.refresh(room);
|
|
1526
1543
|
if (group?.status !== "active" || await endpoint.mlsDevGroups.readRecoveryFailure(room)) throw new Error("MLS_DEV_SETUP_ROOM_NOT_READY");
|
|
1527
1544
|
}
|
|
1528
|
-
const device = await
|
|
1545
|
+
const device = await devices.read();
|
|
1529
1546
|
return {
|
|
1530
1547
|
version: 1,
|
|
1531
1548
|
action,
|
|
@@ -1541,12 +1558,238 @@ async function runMlsDevSetup(endpoint, action, room, provision) {
|
|
|
1541
1558
|
}
|
|
1542
1559
|
__name(runMlsDevSetup, "runMlsDevSetup");
|
|
1543
1560
|
|
|
1561
|
+
// src/runner/mls-bundled.ts
|
|
1562
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
1563
|
+
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
1564
|
+
import { dirname as dirname4, join as join2 } from "node:path";
|
|
1565
|
+
import { fileURLToPath } from "node:url";
|
|
1566
|
+
|
|
1567
|
+
// mls-custody.json
|
|
1568
|
+
var mls_custody_default = {
|
|
1569
|
+
schemaVersion: 1,
|
|
1570
|
+
release: "mls-custody-cadb937436ce",
|
|
1571
|
+
protocolVersion: 1,
|
|
1572
|
+
rustVersion: "rustc 1.91.0 (f8297e351 2025-10-28)",
|
|
1573
|
+
sourceHashes: {
|
|
1574
|
+
"mls/native/Cargo.toml": "f93b48329951d5a11ef6d5830ff7c375cb847543bdb1c98a6fd8a8d02026db89",
|
|
1575
|
+
"mls/native/Cargo.lock": "9c2e9a3bb0f79c14540942c091124cba4aa262ee14cef2cdd5490653cd4656f3",
|
|
1576
|
+
"mls/native/src/lib.rs": "8e586bfaedc5fe376febbda78c32f8383aaa2ac92868000dd4c84ca083731571",
|
|
1577
|
+
"mls/native/src/bin/canon-mls-custody.rs": "3ab54102bfe315e425b6c3cf0aa7feb66e44d047e135336b0291305507062459",
|
|
1578
|
+
"mls/native/src/portable/mod.rs": "3005b60f7777a841347421ad96eb631b72063e85cebe96afd1c11fef095b0e34",
|
|
1579
|
+
"mls/native/src/portable/json.rs": "d4e68556a051ffe9008686036597b1fd8239ae66fad67bd848c3f0e16bf8ccaf",
|
|
1580
|
+
"mls/native/src/portable/vault.rs": "14b9ff1e10ec4058e39a46511a489c7e82a9836e4175a768ac5d4b69c1dba8e5",
|
|
1581
|
+
"mls/native/src/portable/tests.rs": "7eadba2a49ed044470bb567d9b93fba44b64dc117b1da50a22187cff3dccb64e",
|
|
1582
|
+
"mls/native/portable/build.mjs": "84c422a8a8aa6a7ec112a358bdeef080201aa4ea9a91f6d5726b05f46fa2a10c",
|
|
1583
|
+
"mls/core/open.rs": "8cdc03882f3b84dca72ab06afd437f162de01a0fe21327b019f17867dd59f5d0",
|
|
1584
|
+
"mls/core/protocol.rs": "7f3e021d6e4f1cc130b5dd3c98e0b0fa23edf813c72802c3fa3f8fb9e431c947",
|
|
1585
|
+
"mls/core/fault_storage.rs": "fdd6672a21f6ffee657142755637824541a5090b4f8a5fb4902f482556fb2793",
|
|
1586
|
+
"mls/core/mls_environment.rs": "390d11ee82ef8b108a7fffc7bb193ac7f3e470aa14e9643d029007aaaa29c4e4",
|
|
1587
|
+
"mls/core/dev_identity.rs": "97df6bdb9daab66f0e3d4ca3b49bf9954fa06ac032c927d9ae6c83509b0166bd",
|
|
1588
|
+
"mls/core/dev_key_package.rs": "3e7011fe8ab3044d80d84d04944068dbcf683141fcaba8a7a00bd2cfd103de72",
|
|
1589
|
+
"mls/core/dev_application.rs": "fafe245ace38e384da265bab2c12fef6b77c86b2c20477d00563ab891a54f94b",
|
|
1590
|
+
"mls/core/dev_group.rs": "1d519a5d15394bbc163aef00e0ddacb9bb87631beaf8a13e52c76d628749152b",
|
|
1591
|
+
"packages/test-fixtures/src/mlsDevEnrollmentProofV1.json": "50d7896e0a3a25b420412e84484e64f1e49480a3f298ee2d125f2f9188382810",
|
|
1592
|
+
"packages/test-fixtures/src/mlsDevCredentialV1.json": "24cd23af794b8a6e35caf050995020c6584b806de060969db4536f44b1188780",
|
|
1593
|
+
"packages/test-fixtures/src/mlsDevCredentialReconciliationV1.json": "bd4bbb3a2e5dc7921867a2e5936d1da77d536740b4360012c1f741f9caed2826",
|
|
1594
|
+
"packages/test-fixtures/src/mlsDevGroupV1.json": "10b7c0da00cfd3ecfb3c9e7f0118bc574be613cc82d97268766ba271c464ca9d",
|
|
1595
|
+
"packages/test-fixtures/src/mlsDevApplicationV1.json": "77c05e728acb7793a70c03a6857bc8b0e522e586b117241432460eec05ae3673",
|
|
1596
|
+
"packages/test-fixtures/src/mlsDevInteractionV1.json": "045ee34e1b5e126b67da94705b3f03a1d265774d7889ec3f4f272dd06ecef676"
|
|
1597
|
+
},
|
|
1598
|
+
platforms: {
|
|
1599
|
+
"darwin-arm64": {
|
|
1600
|
+
target: "aarch64-apple-darwin",
|
|
1601
|
+
sha256: "918ae350f1d7bd339c4eee548f6668943217f5fa66022bb93f41a02992dd296c",
|
|
1602
|
+
bytes: 2932976,
|
|
1603
|
+
unitTestsPassed: 95,
|
|
1604
|
+
commit: "cdc6ce8fd9d7a47bc5c796d19a72828e4cc9db06",
|
|
1605
|
+
builder: {
|
|
1606
|
+
macos: "26.3.1",
|
|
1607
|
+
sdk: "26.4",
|
|
1608
|
+
linker: "@(#)PROGRAM:ld PROJECT:ld-1266.8"
|
|
1609
|
+
}
|
|
1610
|
+
},
|
|
1611
|
+
"linux-x64": {
|
|
1612
|
+
target: "x86_64-unknown-linux-gnu",
|
|
1613
|
+
sha256: "1c5a12d0213c53bdf59b5f36a7390a4b4c17f8a53c95e760ad8cb4905297d256",
|
|
1614
|
+
bytes: 3389816,
|
|
1615
|
+
unitTestsPassed: 95,
|
|
1616
|
+
commit: "cdc6ce8fd9d7a47bc5c796d19a72828e4cc9db06",
|
|
1617
|
+
builder: {
|
|
1618
|
+
image: "quay.io/pypa/manylinux_2_28_x86_64@sha256:e0adf18521ad35192df733a6c62d35df7801957d24e0470238aacecfab2188a3",
|
|
1619
|
+
dockerfileSha256: "fe8d4895b8bd304954441fd27c6273c8c00baa10a1ad912d3c3851b193b8ad75"
|
|
1620
|
+
}
|
|
1621
|
+
},
|
|
1622
|
+
"linux-arm64": {
|
|
1623
|
+
target: "aarch64-unknown-linux-gnu",
|
|
1624
|
+
sha256: "371c5754cf0c437f561e8c49b3ea654c037311b951e11b1c5a29fb6b91656619",
|
|
1625
|
+
bytes: 3234232,
|
|
1626
|
+
unitTestsPassed: 95,
|
|
1627
|
+
commit: "cdc6ce8fd9d7a47bc5c796d19a72828e4cc9db06",
|
|
1628
|
+
builder: {
|
|
1629
|
+
image: "quay.io/pypa/manylinux_2_28_aarch64@sha256:a3e02308c822fb6ce0d12248b0c941817ba5e1a1bc9e7bb5929f29c50eaa40a9",
|
|
1630
|
+
dockerfileSha256: "fe8d4895b8bd304954441fd27c6273c8c00baa10a1ad912d3c3851b193b8ad75"
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
|
|
1636
|
+
// src/runner/mls-bundled.ts
|
|
1637
|
+
var MLS_ENVIRONMENT_PINS = {
|
|
1638
|
+
"canon-prod-v1": {
|
|
1639
|
+
issuerKeys: [{
|
|
1640
|
+
keyVersion: "projects/canonmail-prod/locations/europe-west1/keyRings/canon-mls/cryptoKeys/device-issuer/cryptoKeyVersions/1",
|
|
1641
|
+
signaturePublicKey: "AYLEqY7gKOhQvRALb-31lz82XinehW2_gl0jKC-G8Pk"
|
|
1642
|
+
}],
|
|
1643
|
+
receiptKeys: [{
|
|
1644
|
+
keyVersion: "projects/canonmail-prod/locations/europe-west1/keyRings/canon-mls/cryptoKeys/feed-receipt/cryptoKeyVersions/1",
|
|
1645
|
+
signaturePublicKey: "sRi4mvMbFTL-LKzXilIJedefSqtqrF8Q-deM2AUSt40"
|
|
1646
|
+
}]
|
|
1647
|
+
},
|
|
1648
|
+
"canon-dev-v1": {
|
|
1649
|
+
// Dev signs with version 2 and still trusts version 1 until 2026-11-07.
|
|
1650
|
+
issuerKeys: [
|
|
1651
|
+
{
|
|
1652
|
+
keyVersion: "projects/canonmail-dev/locations/europe-west1/keyRings/canon-mls/cryptoKeys/device-issuer/cryptoKeyVersions/1",
|
|
1653
|
+
signaturePublicKey: "Hm1ULJGsF9MIQbHYIWmpkK3j2dPcFzeJ71xbYVsPZNs"
|
|
1654
|
+
},
|
|
1655
|
+
{
|
|
1656
|
+
keyVersion: "projects/canonmail-dev/locations/europe-west1/keyRings/canon-mls/cryptoKeys/device-issuer/cryptoKeyVersions/2",
|
|
1657
|
+
signaturePublicKey: "G2fwJdPQXP6Ar68LJveXQ_WAOtdtcsiyKdeEVb-9Gcw"
|
|
1658
|
+
}
|
|
1659
|
+
],
|
|
1660
|
+
receiptKeys: [{
|
|
1661
|
+
keyVersion: "projects/canonmail-dev/locations/europe-west1/keyRings/canon-mls/cryptoKeys/feed-receipt/cryptoKeyVersions/1",
|
|
1662
|
+
signaturePublicKey: "LSRMjRHH73Q4ExPFSTaU_KTvr8wQ4Cp9vtaBBrVZvig"
|
|
1663
|
+
}]
|
|
1664
|
+
}
|
|
1665
|
+
};
|
|
1666
|
+
function packageRoot() {
|
|
1667
|
+
for (let directory = dirname4(fileURLToPath(import.meta.url)); ; directory = dirname4(directory)) {
|
|
1668
|
+
const manifest = join2(directory, "package.json");
|
|
1669
|
+
if (existsSync(manifest) && JSON.parse(readFileSync2(manifest, "utf8")).name === "@canonmsg/agent-sdk") return directory;
|
|
1670
|
+
if (dirname4(directory) === directory) return void 0;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
__name(packageRoot, "packageRoot");
|
|
1674
|
+
function bundledMlsCustodyHelper() {
|
|
1675
|
+
const platform = `${process.platform}-${process.arch}`;
|
|
1676
|
+
const pin = mls_custody_default.platforms[platform];
|
|
1677
|
+
const root = pin && packageRoot();
|
|
1678
|
+
const path = root && join2(root, "dist", "mls", platform, "canon-mls-custody");
|
|
1679
|
+
if (!pin || !path || !existsSync(path)) return void 0;
|
|
1680
|
+
if (createHash5("sha256").update(readFileSync2(path)).digest("hex") !== pin.sha256) {
|
|
1681
|
+
throw new Error(`${path} is not the custody helper this package pins; reinstall @canonmsg/agent-sdk.`);
|
|
1682
|
+
}
|
|
1683
|
+
return { path, sha256: pin.sha256 };
|
|
1684
|
+
}
|
|
1685
|
+
__name(bundledMlsCustodyHelper, "bundledMlsCustodyHelper");
|
|
1686
|
+
|
|
1687
|
+
// src/runner/mls-managed.ts
|
|
1688
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
1689
|
+
import { chmodSync, copyFileSync, existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync as renameSync2 } from "node:fs";
|
|
1690
|
+
import { dirname as dirname5, join as join3 } from "node:path";
|
|
1691
|
+
var sha256 = /* @__PURE__ */ __name((bytes) => createHash6("sha256").update(bytes).digest("hex"), "sha256");
|
|
1692
|
+
function managedMlsDevice(options) {
|
|
1693
|
+
const { environmentId } = options;
|
|
1694
|
+
const helper = options.helper ?? bundledMlsCustodyHelper();
|
|
1695
|
+
if (!helper) {
|
|
1696
|
+
throw new Error(`@canonmsg/agent-sdk ships no MLS custody helper for ${process.platform}-${process.arch}: build one from mls/native in the Canon repository and give the runner --mls-dev-config <path> (docs/design/mls-dev-agent-host.md).`);
|
|
1697
|
+
}
|
|
1698
|
+
const pins = options.pins ?? MLS_ENVIRONMENT_PINS[environmentId];
|
|
1699
|
+
const configuration = parseMlsDevClientConfiguration({
|
|
1700
|
+
version: 1,
|
|
1701
|
+
environmentId,
|
|
1702
|
+
enabled: true,
|
|
1703
|
+
issuerKeys: pins.issuerKeys,
|
|
1704
|
+
receiptKeys: pins.receiptKeys
|
|
1705
|
+
});
|
|
1706
|
+
const root = join3(options.home, "mls", environmentId);
|
|
1707
|
+
const directory = /* @__PURE__ */ __name((context) => join3(root, sha256(Buffer.from(JSON.stringify([
|
|
1708
|
+
context.installationId,
|
|
1709
|
+
context.principal.type,
|
|
1710
|
+
context.principal.id,
|
|
1711
|
+
"ownershipVersion" in context.principal ? context.principal.ownershipVersion : null
|
|
1712
|
+
]))).slice(0, 32)), "directory");
|
|
1713
|
+
const vault = /* @__PURE__ */ __name((context) => join3(directory(context), "vault", "vault.bin"), "vault");
|
|
1714
|
+
let executable;
|
|
1715
|
+
function install() {
|
|
1716
|
+
const target = join3(root, "bin", helper.sha256, "canon-mls-custody");
|
|
1717
|
+
if (existsSync2(target) && sha256(readFileSync3(target)) === helper.sha256) return target;
|
|
1718
|
+
mkdirSync3(dirname5(target), { recursive: true, mode: 448 });
|
|
1719
|
+
const temporary = `${target}.${process.pid}.tmp`;
|
|
1720
|
+
copyFileSync(helper.path, temporary);
|
|
1721
|
+
chmodSync(temporary, 448);
|
|
1722
|
+
if (sha256(readFileSync3(temporary)) !== helper.sha256) throw new Error(`${helper.path} is not the pinned custody helper`);
|
|
1723
|
+
renameSync2(temporary, target);
|
|
1724
|
+
return target;
|
|
1725
|
+
}
|
|
1726
|
+
__name(install, "install");
|
|
1727
|
+
const devices = /* @__PURE__ */ new Map();
|
|
1728
|
+
function device(context, provisioning) {
|
|
1729
|
+
const key = directory(context);
|
|
1730
|
+
let found = devices.get(key);
|
|
1731
|
+
if (!found) {
|
|
1732
|
+
found = (async () => {
|
|
1733
|
+
if (!provisioning && !existsSync2(vault(context))) throw new NodeMlsDevCustodyError();
|
|
1734
|
+
mkdirSync3(dirname5(vault(context)), { recursive: true, mode: 448 });
|
|
1735
|
+
const unlock = join3(key, "unlock");
|
|
1736
|
+
if (provisioning) privateKey(unlock, 32);
|
|
1737
|
+
const text3 = `${JSON.stringify({
|
|
1738
|
+
version: 1,
|
|
1739
|
+
environmentId,
|
|
1740
|
+
context: {
|
|
1741
|
+
version: 1,
|
|
1742
|
+
environmentId: context.environmentId,
|
|
1743
|
+
principal: context.principal,
|
|
1744
|
+
installationId: context.installationId
|
|
1745
|
+
},
|
|
1746
|
+
vaultPath: vault(context),
|
|
1747
|
+
issuerKeys: configuration.issuerKeys,
|
|
1748
|
+
receiptKeys: configuration.receiptKeys
|
|
1749
|
+
}, null, 2)}
|
|
1750
|
+
`;
|
|
1751
|
+
const file = join3(key, "native.json");
|
|
1752
|
+
if (!existsSync2(file) || readFileSync3(file, "utf8") !== text3) writeDurable(file, text3);
|
|
1753
|
+
return createPortableNodeMlsDevCustody({
|
|
1754
|
+
executablePath: executable ??= install(),
|
|
1755
|
+
executableSha256: helper.sha256,
|
|
1756
|
+
configurationPath: file,
|
|
1757
|
+
configurationSha256: sha256(Buffer.from(text3)),
|
|
1758
|
+
secretSource: { kind: "managed-file", path: unlock },
|
|
1759
|
+
...options.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs }
|
|
1760
|
+
});
|
|
1761
|
+
})();
|
|
1762
|
+
devices.set(key, found);
|
|
1763
|
+
found.catch(() => {
|
|
1764
|
+
if (devices.get(key) === found) devices.delete(key);
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1767
|
+
return found;
|
|
1768
|
+
}
|
|
1769
|
+
__name(device, "device");
|
|
1770
|
+
const custody2 = {
|
|
1771
|
+
prepareProtected: /* @__PURE__ */ __name((context, ...rest) => device(context, false).then((open4) => open4.prepareProtected(context, ...rest)), "prepareProtected"),
|
|
1772
|
+
prepareProtectedKeyPackage: /* @__PURE__ */ __name((context, ...rest) => device(context, false).then((open4) => open4.prepareProtectedKeyPackage(context, ...rest)), "prepareProtectedKeyPackage"),
|
|
1773
|
+
prepareProtectedGroup: /* @__PURE__ */ __name((identity, ...rest) => device(identity, false).then((open4) => open4.prepareProtectedGroup(identity, ...rest)), "prepareProtectedGroup")
|
|
1774
|
+
};
|
|
1775
|
+
return {
|
|
1776
|
+
configuration,
|
|
1777
|
+
custody: custody2,
|
|
1778
|
+
provision: /* @__PURE__ */ __name((context) => device(context, true).then((open4) => open4.provision(context)), "provision"),
|
|
1779
|
+
provisioned: /* @__PURE__ */ __name((context) => existsSync2(vault(context)), "provisioned"),
|
|
1780
|
+
async close() {
|
|
1781
|
+
await Promise.allSettled([...devices.values()].map((open4) => open4.then((custody3) => custody3.close())));
|
|
1782
|
+
}
|
|
1783
|
+
};
|
|
1784
|
+
}
|
|
1785
|
+
__name(managedMlsDevice, "managedMlsDevice");
|
|
1786
|
+
|
|
1544
1787
|
// src/runner/relay.ts
|
|
1545
1788
|
import { createHmac as createHmac2, timingSafeEqual } from "node:crypto";
|
|
1546
|
-
import { closeSync as closeSync3, constants as constants5, fsyncSync as fsyncSync2, mkdirSync as
|
|
1789
|
+
import { closeSync as closeSync3, constants as constants5, fsyncSync as fsyncSync2, mkdirSync as mkdirSync4, openSync as openSync3, renameSync as renameSync3, writeSync as writeSync2 } from "node:fs";
|
|
1547
1790
|
import { lstat as lstat2, open as open3, realpath as realpath4 } from "node:fs/promises";
|
|
1548
1791
|
import { createServer } from "node:http";
|
|
1549
|
-
import { isAbsolute as isAbsolute2, join as
|
|
1792
|
+
import { isAbsolute as isAbsolute2, join as join4, resolve as resolve2 } from "node:path";
|
|
1550
1793
|
var TOLERANCE_S = 300;
|
|
1551
1794
|
function relaySecretKey(secret) {
|
|
1552
1795
|
if (typeof secret !== "string" || !/^whsec_[A-Za-z0-9+/]+={0,2}$/.test(secret)) throw new Error("The relay channel secret must be a whsec_ value");
|
|
@@ -1715,8 +1958,8 @@ async function loadRelayConfiguration(path, input) {
|
|
|
1715
1958
|
return { environmentId: value.environmentId, agentId: value.agentId, listen: { host: listen.host, port: listen.port }, secret };
|
|
1716
1959
|
}
|
|
1717
1960
|
__name(loadRelayConfiguration, "loadRelayConfiguration");
|
|
1718
|
-
var relayDirectory = /* @__PURE__ */ __name((home) =>
|
|
1719
|
-
var credentialFile = /* @__PURE__ */ __name((home) =>
|
|
1961
|
+
var relayDirectory = /* @__PURE__ */ __name((home) => join4(home, "relay"), "relayDirectory");
|
|
1962
|
+
var credentialFile = /* @__PURE__ */ __name((home) => join4(relayDirectory(home), "credential.json"), "credentialFile");
|
|
1720
1963
|
async function readRelayCredential(home, relay) {
|
|
1721
1964
|
const path = credentialFile(home);
|
|
1722
1965
|
if (!await lstat2(path).then(() => true, () => false)) return void 0;
|
|
@@ -1742,7 +1985,7 @@ function writeRelayCredential(home, relay, delivery) {
|
|
|
1742
1985
|
generation: delivery.generation,
|
|
1743
1986
|
credential: delivery.credential
|
|
1744
1987
|
};
|
|
1745
|
-
|
|
1988
|
+
mkdirSync4(relayDirectory(home), { recursive: true, mode: 448 });
|
|
1746
1989
|
const file = credentialFile(home);
|
|
1747
1990
|
const temporary = `${file}.${process.pid}.tmp`;
|
|
1748
1991
|
const fd = openSync3(temporary, "w", 384);
|
|
@@ -1752,23 +1995,23 @@ function writeRelayCredential(home, relay, delivery) {
|
|
|
1752
1995
|
} finally {
|
|
1753
1996
|
closeSync3(fd);
|
|
1754
1997
|
}
|
|
1755
|
-
|
|
1998
|
+
renameSync3(temporary, file);
|
|
1756
1999
|
return value;
|
|
1757
2000
|
}
|
|
1758
2001
|
__name(writeRelayCredential, "writeRelayCredential");
|
|
1759
2002
|
function relayRunnerHome(home, installationId) {
|
|
1760
2003
|
if (!CONNECTOR_RELAY_INSTALLATION_PATTERN.test(installationId)) throw new Error("Invalid relay installation");
|
|
1761
|
-
const directory =
|
|
1762
|
-
|
|
2004
|
+
const directory = join4(relayDirectory(home), installationId.slice(CONNECTOR_RELAY_INSTALLATION_PREFIX.length));
|
|
2005
|
+
mkdirSync4(directory, { recursive: true, mode: 448 });
|
|
1763
2006
|
return directory;
|
|
1764
2007
|
}
|
|
1765
2008
|
__name(relayRunnerHome, "relayRunnerHome");
|
|
1766
2009
|
|
|
1767
2010
|
// src/runner/runner.ts
|
|
1768
|
-
import { createHash as
|
|
1769
|
-
import { readFileSync as
|
|
2011
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
2012
|
+
import { readFileSync as readFileSync5, rmSync as rmSync3 } from "node:fs";
|
|
1770
2013
|
import { realpath as realpath5, stat as stat2 } from "node:fs/promises";
|
|
1771
|
-
import { basename as basename3, isAbsolute as isAbsolute3, join as
|
|
2014
|
+
import { basename as basename3, isAbsolute as isAbsolute3, join as join6, sep } from "node:path";
|
|
1772
2015
|
|
|
1773
2016
|
// ../agent-tools/src/communication-tool.ts
|
|
1774
2017
|
var CANON_COMMUNICATE_TOOL_NAME = "communicate";
|
|
@@ -2262,10 +2505,10 @@ function createLivePublisher(options) {
|
|
|
2262
2505
|
__name(createLivePublisher, "createLivePublisher");
|
|
2263
2506
|
|
|
2264
2507
|
// src/runner/mls-ask.ts
|
|
2265
|
-
import { createHash as
|
|
2266
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
2267
|
-
import { join as
|
|
2268
|
-
var
|
|
2508
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
2509
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync4, rmSync as rmSync2 } from "node:fs";
|
|
2510
|
+
import { join as join5 } from "node:path";
|
|
2511
|
+
var sha2562 = /* @__PURE__ */ __name((value) => createHash7("sha256").update(value).digest("hex"), "sha256");
|
|
2269
2512
|
var pause = /* @__PURE__ */ __name((ms) => new Promise((resolve3) => {
|
|
2270
2513
|
setTimeout(resolve3, ms).unref?.();
|
|
2271
2514
|
}), "pause");
|
|
@@ -2319,10 +2562,10 @@ function createMlsAsks(options, approvalScope2) {
|
|
|
2319
2562
|
});
|
|
2320
2563
|
}
|
|
2321
2564
|
});
|
|
2322
|
-
const file = /* @__PURE__ */ __name((conversationId, requestId) =>
|
|
2565
|
+
const file = /* @__PURE__ */ __name((conversationId, requestId) => join5(options.directory, `${sha2562(JSON.stringify([conversationId, requestId])).slice(0, 32)}.json`), "file");
|
|
2323
2566
|
const save = /* @__PURE__ */ __name((journal) => writeDurable(file(journal.conversationId, journal.requestId), JSON.stringify(journal)), "save");
|
|
2324
2567
|
const forget = /* @__PURE__ */ __name((journal) => rmSync2(file(journal.conversationId, journal.requestId), { force: true }), "forget");
|
|
2325
|
-
const operationOf = /* @__PURE__ */ __name((conversationId, messageId) => `runner-mls-ask:${
|
|
2568
|
+
const operationOf = /* @__PURE__ */ __name((conversationId, messageId) => `runner-mls-ask:${sha2562(JSON.stringify([conversationId, messageId])).slice(0, 48)}`, "operationOf");
|
|
2326
2569
|
const withdrawalOf = /* @__PURE__ */ __name((journal) => operationOf(journal.conversationId, `${journal.requestId}:withdraw`), "withdrawalOf");
|
|
2327
2570
|
const audienceChanged = /* @__PURE__ */ __name((error) => codeOf(error) === "MLS_DEV_AUDIENCE_CHANGED", "audienceChanged");
|
|
2328
2571
|
const sameHead = /* @__PURE__ */ __name((a, b) => JSON.stringify(a.head) === JSON.stringify(b.head), "sameHead");
|
|
@@ -2663,11 +2906,11 @@ function createMlsAsks(options, approvalScope2) {
|
|
|
2663
2906
|
for (const name of names) {
|
|
2664
2907
|
let journal;
|
|
2665
2908
|
try {
|
|
2666
|
-
journal = JSON.parse(
|
|
2909
|
+
journal = JSON.parse(readFileSync4(join5(options.directory, name), "utf8"));
|
|
2667
2910
|
if (journal.version !== 1 || typeof journal.conversationId !== "string" || typeof journal.requestId !== "string" || !Array.isArray(journal.sends) || journal.sends.some((sent) => typeof sent?.operationId !== "string" || typeof sent.messageId !== "string")) throw new Error();
|
|
2668
2911
|
for (const sent of journal.sends) sent.audience = snapshotMlsAudience(sent.audience);
|
|
2669
2912
|
} catch {
|
|
2670
|
-
rmSync2(
|
|
2913
|
+
rmSync2(join5(options.directory, name), { force: true });
|
|
2671
2914
|
continue;
|
|
2672
2915
|
}
|
|
2673
2916
|
try {
|
|
@@ -2825,7 +3068,7 @@ function answerText(answer) {
|
|
|
2825
3068
|
return answer.text?.trim() ? answer.text : "They answered with an empty message.";
|
|
2826
3069
|
}
|
|
2827
3070
|
__name(answerText, "answerText");
|
|
2828
|
-
var
|
|
3071
|
+
var sha2563 = /* @__PURE__ */ __name((value) => createHash8("sha256").update(value).digest("hex"), "sha256");
|
|
2829
3072
|
var toolText = /* @__PURE__ */ __name((text3, isError = false) => ({ content: [{ type: "text", text: text3 }], ...isError ? { isError } : {} }), "toolText");
|
|
2830
3073
|
var turnEnded2 = /* @__PURE__ */ __name(() => new DOMException("This turn has ended", "AbortError"), "turnEnded");
|
|
2831
3074
|
function within(promise, ms) {
|
|
@@ -2841,9 +3084,10 @@ var pause2 = /* @__PURE__ */ __name((ms) => new Promise((resolve3) => {
|
|
|
2841
3084
|
}), "pause");
|
|
2842
3085
|
var audienceOf = /* @__PURE__ */ __name((room) => room?.memberIds ? { memberIds: [...room.memberIds], ...typeof room.membershipRevision === "number" ? { membershipRevision: room.membershipRevision } : {} } : null, "audienceOf");
|
|
2843
3086
|
var inert = /* @__PURE__ */ __name((value) => value.replace(/\s+/g, " ").trim(), "inert");
|
|
3087
|
+
var OWNER_MARK = " [your owner]";
|
|
2844
3088
|
var TRUSTED_MARK = " [trusted teammate agent]";
|
|
2845
3089
|
var speaker = /* @__PURE__ */ __name((name) => inert(name).replace(/\[/g, "(").replace(/\]/g, ")"), "speaker");
|
|
2846
|
-
var defused = /* @__PURE__ */ __name((text3) => text3.replace(/\[(\s*trusted\s+teammate\s+agent\s*)\]/gi, "($1)").replace(/\[(\s*(?:end\s+of\s+)?owner['\u2019]s\s+(?:private\s+note|errand)\s*)\]/gi, "($1)"), "defused");
|
|
3090
|
+
var defused = /* @__PURE__ */ __name((text3) => text3.replace(/\[(\s*(?:trusted\s+teammate\s+agent|your\s+owner)\s*)\]/gi, "($1)").replace(/\[(\s*(?:end\s+of\s+)?owner['\u2019]s\s+(?:private\s+note|errand)\s*)\]/gi, "($1)"), "defused");
|
|
2847
3091
|
var NOTE_OPEN = "[owner's private note] Your owner left this for you on the machine you run on. It is not a message in this conversation: no one in it sees it, and it was not posted.";
|
|
2848
3092
|
var NOTE_CLOSE = "[end of owner's private note]";
|
|
2849
3093
|
var ERRAND_OPEN = "[owner's errand]";
|
|
@@ -2858,8 +3102,8 @@ var errandCommunicate = /* @__PURE__ */ __name((contact) => ({
|
|
|
2858
3102
|
properties: { action: { const: "start_conversation" }, principalId: { type: "string", minLength: 1 }, text: { type: "string", minLength: 1 } }
|
|
2859
3103
|
}] : []] }
|
|
2860
3104
|
}), "errandCommunicate");
|
|
2861
|
-
var promptLine = /* @__PURE__ */ __name((message2, name, media,
|
|
2862
|
-
`${speaker(name)}${
|
|
3105
|
+
var promptLine = /* @__PURE__ */ __name((message2, name, media, mark = "") => [
|
|
3106
|
+
`${speaker(name)}${mark}: ${defused(renderCanonHostInboundContent(message2, media?.files))}`,
|
|
2863
3107
|
...(media?.failed ?? []).map((label) => `[Attachment "${defused(inert(label))}" could not be downloaded]`)
|
|
2864
3108
|
].join("\n"), "promptLine");
|
|
2865
3109
|
var inputMessage = /* @__PURE__ */ __name((message2, trusted = false) => Object.freeze({
|
|
@@ -2896,7 +3140,7 @@ function approvalScope(request) {
|
|
|
2896
3140
|
if (request.scopeKey !== void 0 && /^[A-Za-z0-9_:-]{1,64}$/.test(request.scopeKey)) return request.scopeKey;
|
|
2897
3141
|
const key = request.scopeKey ?? request.title;
|
|
2898
3142
|
const slug = key.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 40) || "approval";
|
|
2899
|
-
return `${slug}-${
|
|
3143
|
+
return `${slug}-${sha2563(JSON.stringify([request.scopeKey === void 0 ? "title" : "scope", key])).slice(0, 16)}`;
|
|
2900
3144
|
}
|
|
2901
3145
|
__name(approvalScope, "approvalScope");
|
|
2902
3146
|
var MAX_GROUP_PARTS = 100;
|
|
@@ -3053,7 +3297,7 @@ async function createRunner(options) {
|
|
|
3053
3297
|
const dispose = /* @__PURE__ */ __name((inputs, kind, reason) => Promise.allSettled(inputs.map((input) => input.handle[kind](reason))).then(() => void 0), "dispose");
|
|
3054
3298
|
const settle = /* @__PURE__ */ __name(async (ids, reason) => (await Promise.allSettled(ids.map((id) => endpoint.setInboundState(id, "settled", reason)))).every(({ status }) => status === "fulfilled"), "settle");
|
|
3055
3299
|
const queued = /* @__PURE__ */ __name((turn) => turn.inputs.filter((input) => input.handle.phase === "queued"), "queued");
|
|
3056
|
-
const turnId = /* @__PURE__ */ __name((roomId, inputs) => `turn-${
|
|
3300
|
+
const turnId = /* @__PURE__ */ __name((roomId, inputs) => `turn-${sha2563(JSON.stringify([roomId, ...inputs.map((input) => [input.id, input.generation])])).slice(0, 32)}`, "turnId");
|
|
3057
3301
|
const livePublisher = /* @__PURE__ */ __name((current, turn, mode) => createLivePublisher({
|
|
3058
3302
|
client,
|
|
3059
3303
|
conversationId: current.id,
|
|
@@ -3069,7 +3313,7 @@ async function createRunner(options) {
|
|
|
3069
3313
|
current.lane = current.lane.then(publish2).catch(() => void 0);
|
|
3070
3314
|
}, "enqueue")
|
|
3071
3315
|
}), "livePublisher");
|
|
3072
|
-
const stateFile = /* @__PURE__ */ __name((session) =>
|
|
3316
|
+
const stateFile = /* @__PURE__ */ __name((session) => join6(home, "runner", options.environmentId, agentId, "state", driver.name, `${sha2563(JSON.stringify([scope, session]))}.json`), "stateFile");
|
|
3073
3317
|
const resetSession = /* @__PURE__ */ __name(async (session) => {
|
|
3074
3318
|
rmSync3(stateFile(session), { force: true });
|
|
3075
3319
|
mlsAsks?.endSession(session);
|
|
@@ -3189,6 +3433,7 @@ ${error instanceof Error ? error.message : String(error)}`;
|
|
|
3189
3433
|
const verified = {
|
|
3190
3434
|
id: message2.id,
|
|
3191
3435
|
senderId: message2.senderId,
|
|
3436
|
+
...message2.senderName ? { senderName: message2.senderName } : {},
|
|
3192
3437
|
senderType: fromAgent ? "ai_agent" : "human",
|
|
3193
3438
|
isOwner: !fromAgent && message2.senderId === ownerId,
|
|
3194
3439
|
text: message2.text ?? void 0,
|
|
@@ -3399,7 +3644,7 @@ ${error instanceof Error ? error.message : String(error)}`;
|
|
|
3399
3644
|
return check;
|
|
3400
3645
|
}
|
|
3401
3646
|
__name(reaudience, "reaudience");
|
|
3402
|
-
const inboundMedia = /* @__PURE__ */ __name((conversationId) => ({ agentId: "inbound", conversationId, rootDir:
|
|
3647
|
+
const inboundMedia = /* @__PURE__ */ __name((conversationId) => ({ agentId: "inbound", conversationId, rootDir: join6(home, "runner", options.environmentId, agentId) }), "inboundMedia");
|
|
3403
3648
|
async function materialize(current, turn) {
|
|
3404
3649
|
if (driver.capabilities.remote) return;
|
|
3405
3650
|
for (const { payload: { message: message2 } } of turn.inputs) {
|
|
@@ -3450,7 +3695,7 @@ ${error instanceof Error ? error.message : String(error)}`;
|
|
|
3450
3695
|
ask_question: /* @__PURE__ */ __name(async (args) => {
|
|
3451
3696
|
const question = questionOf(args);
|
|
3452
3697
|
if (typeof question === "string") return { result: toolText(question, true) };
|
|
3453
|
-
const key =
|
|
3698
|
+
const key = sha2563(JSON.stringify(question));
|
|
3454
3699
|
const waiting = questions.get(key);
|
|
3455
3700
|
const entry = waiting?.waiting ? waiting : { id: `canon:ask_question:${asked += 1}`, waiting: true };
|
|
3456
3701
|
questions.set(key, entry);
|
|
@@ -3768,7 +4013,7 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
3768
4013
|
messageId: `${root}-part-${index + 1}`,
|
|
3769
4014
|
metadata: buildChunkedMessagePartMetadata({ groupId: root, metadata: options2.metadata, index: index + 1, count: bodies.length })
|
|
3770
4015
|
} }));
|
|
3771
|
-
return client.prepareMessageGroup(record.conversationId, root, parts, { signal, ...replaces ? { operationId:
|
|
4016
|
+
return client.prepareMessageGroup(record.conversationId, root, parts, { signal, ...replaces ? { operationId: sha2563(JSON.stringify([root, ...attachments.map((attachment) => attachment.uploadId)])), replacesOperationId: replaces } : {} }).then((group2) => ({ ...group2, count: parts.length }));
|
|
3772
4017
|
}, "register");
|
|
3773
4018
|
const original = await register(record.attachments);
|
|
3774
4019
|
let group = original;
|
|
@@ -3891,7 +4136,7 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
3891
4136
|
return { items, refused: refused2 };
|
|
3892
4137
|
}
|
|
3893
4138
|
__name(admitItems, "admitItems");
|
|
3894
|
-
const encryptedOperation = /* @__PURE__ */ __name((audience, messageId) => `runner-mls:${
|
|
4139
|
+
const encryptedOperation = /* @__PURE__ */ __name((audience, messageId) => `runner-mls:${sha2563(JSON.stringify([audience.conversationId, messageId])).slice(0, 48)}`, "encryptedOperation");
|
|
3895
4140
|
function forgetGuard(audience, messageId, sent) {
|
|
3896
4141
|
if (sent === "pending") return;
|
|
3897
4142
|
const operationId = encryptedOperation(audience, messageId);
|
|
@@ -3919,7 +4164,7 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
3919
4164
|
...turn.contexts.length ? { errands: Object.freeze(turn.contexts.map(({ record }) => errandFacts(record))) } : {},
|
|
3920
4165
|
...turn.errand ? { errand: errandFacts(turn.errand.record) } : {}
|
|
3921
4166
|
});
|
|
3922
|
-
const line = /* @__PURE__ */ __name((message2,
|
|
4167
|
+
const line = /* @__PURE__ */ __name((message2, mark = "") => promptLine(message2, message2.senderId === agentId ? "You" : message2.senderName ?? message2.senderId, turn.media.get(message2.id), mark), "line");
|
|
3923
4168
|
const open4 = /* @__PURE__ */ __name(() => turn.open && !turn.controller.signal.aborted, "open");
|
|
3924
4169
|
const live = /* @__PURE__ */ __name(() => open4() && !turn.silenced, "live");
|
|
3925
4170
|
return {
|
|
@@ -3929,7 +4174,7 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
3929
4174
|
...turn.notes.flatMap((note) => [NOTE_OPEN, defused(note.text), NOTE_CLOSE, ""]),
|
|
3930
4175
|
...turn.contexts.flatMap((context) => [...contextPrompt(context, !!turn.mls), ""]),
|
|
3931
4176
|
...history.length ? ["Earlier in this conversation (context, not new requests):", ...history.map((message2) => line(message2)), "", "New messages:"] : turn.notes.length || turn.contexts.length ? ["New messages:"] : [],
|
|
3932
|
-
...turn.inputs.map(({ payload: { message: message2 } }) => line(message2, trustedSender(message2)))
|
|
4177
|
+
...turn.inputs.map(({ payload: { message: message2 } }) => line(message2, message2.isOwner === true ? OWNER_MARK : trustedSender(message2) ? TRUSTED_MARK : ""))
|
|
3933
4178
|
].join("\n"),
|
|
3934
4179
|
input,
|
|
3935
4180
|
files: turn.inputs.flatMap(({ payload: { message: message2 } }) => turn.media.get(message2.id)?.files.map((file) => file.path) ?? []),
|
|
@@ -3989,7 +4234,7 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
3989
4234
|
}));
|
|
3990
4235
|
const secret = request.kind === "text" && request.secret === true;
|
|
3991
4236
|
const responder = secret || sender.type !== "human" ? ownerId : sender.id;
|
|
3992
|
-
const requestId = turn.mls ? keyed().request(roomId, turn.id, request.id) : `ask-${
|
|
4237
|
+
const requestId = turn.mls ? keyed().request(roomId, turn.id, request.id) : `ask-${sha2563(JSON.stringify([turn.id, request.id])).slice(0, 32)}`;
|
|
3993
4238
|
const expiresAt = Date.now() + askExpiryMs;
|
|
3994
4239
|
if (turn.mls) {
|
|
3995
4240
|
return await mlsAsks.ask({
|
|
@@ -4061,7 +4306,7 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
4061
4306
|
const file = stateFile(session);
|
|
4062
4307
|
let data = {};
|
|
4063
4308
|
try {
|
|
4064
|
-
data = JSON.parse(
|
|
4309
|
+
data = JSON.parse(readFileSync5(file, "utf8"));
|
|
4065
4310
|
} catch {
|
|
4066
4311
|
}
|
|
4067
4312
|
const save = /* @__PURE__ */ __name((next) => {
|
|
@@ -4278,7 +4523,7 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
4278
4523
|
log(`Errand ${id} (tell) kept for the next turn in ${conversationId}.`);
|
|
4279
4524
|
return true;
|
|
4280
4525
|
}
|
|
4281
|
-
const turnId2 = `turn-${
|
|
4526
|
+
const turnId2 = `turn-${sha2563(JSON.stringify(["canon.runner.errand", id])).slice(0, 32)}`;
|
|
4282
4527
|
const record = {
|
|
4283
4528
|
version: 1,
|
|
4284
4529
|
turnId: turnId2,
|
|
@@ -4347,7 +4592,7 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
4347
4592
|
pump();
|
|
4348
4593
|
}
|
|
4349
4594
|
__name(enqueueErrand, "enqueueErrand");
|
|
4350
|
-
const errandTurnId = /* @__PURE__ */ __name((id) => `turn-${
|
|
4595
|
+
const errandTurnId = /* @__PURE__ */ __name((id) => `turn-${sha2563(JSON.stringify(["canon.runner.errand-turn", id])).slice(0, 32)}`, "errandTurnId");
|
|
4351
4596
|
const errandFacts = /* @__PURE__ */ __name((record) => Object.freeze({
|
|
4352
4597
|
id: record.id,
|
|
4353
4598
|
why: record.why,
|
|
@@ -4683,7 +4928,7 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
4683
4928
|
client = new CanonClient(options.apiKey, connection.apiBaseUrl, {
|
|
4684
4929
|
environmentId: connection.environmentId,
|
|
4685
4930
|
streamUrl: connection.streamUrl,
|
|
4686
|
-
stateDirectory:
|
|
4931
|
+
stateDirectory: join6(home, "endpoint"),
|
|
4687
4932
|
...options.client ? { client: options.client } : {},
|
|
4688
4933
|
// Below Canon's client floor nothing can work, wherever the refusal surfaces: a query, an operation or the stream.
|
|
4689
4934
|
...options.onFatal ? { onClientUpdateRequired: /* @__PURE__ */ __name((error) => options.onFatal(error), "onClientUpdateRequired") } : {},
|
|
@@ -4704,7 +4949,14 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
4704
4949
|
if (options.wake !== void 0) await client.configureWake(options.wake);
|
|
4705
4950
|
mlsOn = !!(endpoint.mlsDevDevice && endpoint.mlsDevGroups);
|
|
4706
4951
|
if (!mlsOn && (await endpoint.capabilities().catch(() => null))?.mls?.roomMode === "default") {
|
|
4707
|
-
throw new Error("Canon encrypts every new conversation here, and this runner has no MLS device:
|
|
4952
|
+
throw new Error("Canon encrypts every new conversation here, and this runner has no MLS device: give it mls (managedMlsDevice, or an operator's configuration: --mls-dev-config <path>).");
|
|
4953
|
+
}
|
|
4954
|
+
if (mlsOn && options.mls?.provisioned && (await endpoint.mlsDevDevice.read()).status !== "credential_committed") {
|
|
4955
|
+
log("Setting up this agent's MLS device");
|
|
4956
|
+
const device = await runMlsDevSetup(endpoint, "setup", void 0, options.mls.provision, options.mls.provisioned).catch((error) => {
|
|
4957
|
+
throw new Error(`Could not set up this agent's MLS device: ${error instanceof Error ? error.message : String(error)}`);
|
|
4958
|
+
});
|
|
4959
|
+
log(`MLS device ${device.deviceId} is ${device.status}`);
|
|
4708
4960
|
}
|
|
4709
4961
|
if (mlsOn) await endpoint.mlsDevDevice.ensureReady().catch(warn("MLS device not ready; encrypted rooms wait for it"));
|
|
4710
4962
|
const keepPool = /* @__PURE__ */ __name(() => endpoint.mlsDevDevice.read().then(async (view) => {
|
|
@@ -4721,23 +4973,23 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
4721
4973
|
}
|
|
4722
4974
|
scope = JSON.stringify([identity.environmentId, agentId, identity.ownershipVersion ?? 0, identity.installationId]);
|
|
4723
4975
|
if (mlsOn) {
|
|
4724
|
-
mlsIds = createMlsIds(privateKey(
|
|
4976
|
+
mlsIds = createMlsIds(privateKey(join6(home, "runner", options.environmentId, agentId, "mls-ids", `${sha2563(scope).slice(0, 32)}.key`), MLS_ID_KEY_BYTES));
|
|
4725
4977
|
mlsAsks = createMlsAsks({
|
|
4726
4978
|
endpoint,
|
|
4727
4979
|
agentId,
|
|
4728
|
-
directory:
|
|
4980
|
+
directory: join6(home, "runner", options.environmentId, agentId, "asks", sha2563(scope).slice(0, 32)),
|
|
4729
4981
|
assertAudience,
|
|
4730
4982
|
sessionForDestructive: options.sessionApprovalForDestructive === true,
|
|
4731
4983
|
log
|
|
4732
4984
|
}, approvalScope);
|
|
4733
4985
|
}
|
|
4734
|
-
journal = createCompletedOutputJournal(
|
|
4986
|
+
journal = createCompletedOutputJournal(join6(home, "runner", options.environmentId, agentId, "finals"), scope, {
|
|
4735
4987
|
label: "agent runner",
|
|
4736
4988
|
validate: /* @__PURE__ */ __name((record) => typeof record.text === "string" && typeof record.options?.messageId === "string" && Array.isArray(record.inputs) && typeof record.notice === "boolean" && (record.attachments === void 0 || Array.isArray(record.attachments)) && (record.flows === void 0 || Array.isArray(record.flows) && record.flows.length === record.attachments?.length) && (record.mls === void 0 || !!record.mls && typeof record.mls === "object") && (record.errand === void 0 || typeof record.errand === "string"), "validate")
|
|
4737
4989
|
});
|
|
4738
4990
|
if (!options.relay && !driver.capabilities.remote) {
|
|
4739
4991
|
errands = errandJournal(errandsDirectory(home, options.environmentId, agentId));
|
|
4740
|
-
errandScope =
|
|
4992
|
+
errandScope = sha2563(scope).slice(0, 32);
|
|
4741
4993
|
const pending = errands.list().filter((record) => record.kind === "tell" && record.status === "pending").sort((a, b) => (a.createdAt ?? "").localeCompare(b.createdAt ?? "") || a.id.localeCompare(b.id));
|
|
4742
4994
|
for (const note of pending) {
|
|
4743
4995
|
if (note.scope === errandScope) notes.set(note.conversationId, [...notes.get(note.conversationId) ?? [], note]);
|
|
@@ -4858,7 +5110,7 @@ ${JSON.stringify(result, null, 2)}`);
|
|
|
4858
5110
|
throw new ConnectorRelayError(400, "CONNECTOR_RELAY_INVALID", "A send needs a messageId and 1 byte to 32 KiB of text");
|
|
4859
5111
|
}
|
|
4860
5112
|
const deadline = options2.deadline ?? Date.now() + CONNECTOR_RELAY_ANSWER_WITHIN_MS;
|
|
4861
|
-
const id = `relay-send-${
|
|
5113
|
+
const id = `relay-send-${sha2563(JSON.stringify([conversationId, messageId])).slice(0, 32)}`;
|
|
4862
5114
|
let entry = relaySends.get(id);
|
|
4863
5115
|
if (!entry) relaySends.set(id, entry = prepareRelaySend(conversationId, id, text3, deadline));
|
|
4864
5116
|
const prepared = await beforeDeadline(entry.ready, deadline);
|
|
@@ -4903,6 +5155,9 @@ export {
|
|
|
4903
5155
|
MLS_SETUP_ACTIONS,
|
|
4904
5156
|
mlsDevRoomPackageId,
|
|
4905
5157
|
runMlsDevSetup,
|
|
5158
|
+
MLS_ENVIRONMENT_PINS,
|
|
5159
|
+
bundledMlsCustodyHelper,
|
|
5160
|
+
managedMlsDevice,
|
|
4906
5161
|
startRelayChannel,
|
|
4907
5162
|
loadRelayConfiguration,
|
|
4908
5163
|
readRelayCredential,
|