@ouro.bot/cli 0.1.0-alpha.989 → 0.1.0-alpha.990
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/changelog.json +11 -0
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
- package/deploy/unraid/sanctuary.xml +1 -1
- package/dist/a2a/client.js +38 -6
- package/dist/a2a/outbox-client.js +2 -0
- package/dist/a2a/outbox-wire.js +12 -1
- package/dist/a2a/refusals.js +11 -1
- package/dist/a2a/relay-client.js +106 -0
- package/dist/a2a/relay-config-vault.js +64 -0
- package/dist/a2a/relay-contacts.js +120 -0
- package/dist/a2a/relay-inbox.js +360 -0
- package/dist/a2a/relay-retirements.js +89 -0
- package/dist/a2a/seen-ledger.js +7 -3
- package/dist/a2a/server.js +189 -171
- package/dist/a2a/transport.js +74 -19
- package/dist/repertoire/guardrails.js +4 -0
- package/dist/repertoire/tools-a2a.js +55 -12
- package/dist/senses/a2a-entry.js +8 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -44,6 +44,7 @@ const client_1 = require("../a2a/client");
|
|
|
44
44
|
const onboarding_1 = require("../a2a/onboarding");
|
|
45
45
|
const identity_2 = require("../a2a/identity");
|
|
46
46
|
const transport_1 = require("../a2a/transport");
|
|
47
|
+
const relay_contacts_1 = require("../a2a/relay-contacts");
|
|
47
48
|
const delegation_stores_1 = require("../a2a/delegation-stores");
|
|
48
49
|
const mission_result_wire_1 = require("../a2a/mission-result-wire");
|
|
49
50
|
const outboundTaskTokens = new Map();
|
|
@@ -190,9 +191,10 @@ async function sealEnvelopeToPeer(input) {
|
|
|
190
191
|
message: "sealing outbound A2A envelope to a DID-keyed peer",
|
|
191
192
|
meta: { selfDid: input.self.did, peerDid: input.did, rung: reachability.rung, friendsKind: input.friendsKind },
|
|
192
193
|
});
|
|
194
|
+
const relay = relayTransportFor(input);
|
|
193
195
|
const result = await (0, a2a_client_1.sendShare)({
|
|
194
196
|
sodium: input.sodium,
|
|
195
|
-
transport:
|
|
197
|
+
transport: relay.transport,
|
|
196
198
|
fromIdentity: input.self,
|
|
197
199
|
toPeer: { a2a: input.peer.agentMeta?.a2a },
|
|
198
200
|
recipientDid: input.did,
|
|
@@ -204,6 +206,36 @@ async function sealEnvelopeToPeer(input) {
|
|
|
204
206
|
if (!result.ok) {
|
|
205
207
|
throw new Error(`sealed send failed (${result.reason})`);
|
|
206
208
|
}
|
|
209
|
+
return relay.delivered();
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* The transport for one send to a DID-keyed peer: direct first, then the relay contact the peer shared (if cached). A
|
|
213
|
+
* relay that refuses the contact marks it stale. After a direct delivery, the peer is online, so its contact is
|
|
214
|
+
* refreshed in the background when it is missing, stale or a day old.
|
|
215
|
+
*/
|
|
216
|
+
function relayTransportFor(input) {
|
|
217
|
+
const cached = (0, relay_contacts_1.readRelayContact)(input.agentRoot, input.did);
|
|
218
|
+
let delivery = { rung: "direct", directMayHaveArrived: false };
|
|
219
|
+
const transport = (0, transport_1.makeA2ATransport)({
|
|
220
|
+
...(cached?.contact ? { relayContact: cached.contact } : {}),
|
|
221
|
+
onRelayContactRefused: () => (0, relay_contacts_1.markRelayContactStale)(input.agentRoot, input.did),
|
|
222
|
+
onDelivered: (rung, detail) => {
|
|
223
|
+
delivery = { rung, directMayHaveArrived: detail?.directMayHaveArrived ?? false };
|
|
224
|
+
const endpointUrl = input.peer.agentMeta?.a2a?.endpointUrl;
|
|
225
|
+
if (rung !== "direct" || !endpointUrl || !(0, relay_contacts_1.relayContactNeedsRefresh)(cached, Date.now()))
|
|
226
|
+
return;
|
|
227
|
+
const cardUrl = input.peer.agentMeta?.a2a?.cardUrl ?? new URL("/.well-known/agent-card.json", endpointUrl).toString();
|
|
228
|
+
void (0, relay_contacts_1.refreshRelayContact)({ agentRoot: input.agentRoot, peerDid: input.did, cardUrl, identity: input.self });
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
return { transport, delivered: () => delivery };
|
|
232
|
+
}
|
|
233
|
+
/** The tool wording for a sealed delivery. */
|
|
234
|
+
function deliveryText(peerName, did, delivery, what = "sealed message") {
|
|
235
|
+
if (delivery.rung === "direct")
|
|
236
|
+
return `${what} delivered to ${peerName} (${did}) over the direct rung.`;
|
|
237
|
+
const head = delivery.directMayHaveArrived ? `direct delivery to ${peerName} (${did}) failed and the ${what} may have arrived; a copy` : `${peerName} (${did}) is not reachable directly; the ${what}`;
|
|
238
|
+
return `${head} is queued at ${peerName}'s relay and is delivered when ${peerName} comes back online.`;
|
|
207
239
|
}
|
|
208
240
|
/**
|
|
209
241
|
* Seal an outbound free-text message to a DID-keyed peer over the `direct` rung. The
|
|
@@ -221,8 +253,8 @@ async function sealAndSendToPeer(input) {
|
|
|
221
253
|
note: input.message,
|
|
222
254
|
issuedAt: new Date().toISOString(),
|
|
223
255
|
};
|
|
224
|
-
await sealEnvelopeToPeer({
|
|
225
|
-
|
|
256
|
+
return await sealEnvelopeToPeer({
|
|
257
|
+
agentRoot: input.agentRoot, self,
|
|
226
258
|
sodium, peer: input.peer, did: input.did, envelope, friendsKind: "coordination",
|
|
227
259
|
});
|
|
228
260
|
}
|
|
@@ -389,14 +421,17 @@ exports.a2aToolDefinitions = [
|
|
|
389
421
|
const did = peerDid(peer);
|
|
390
422
|
if (did) {
|
|
391
423
|
try {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
424
|
+
/* v8 ignore next -- in-turn a2a_send_message always carries a bundle agentRoot; the ambient-name fallback is defensive @preserve */
|
|
425
|
+
const agentName = agentNameFromRoot(ctx?.agentRoot) ?? "ouro-agent";
|
|
426
|
+
const delivery = await sealAndSendToPeer({
|
|
427
|
+
agentName,
|
|
428
|
+
/* v8 ignore next -- same defensive ambient fallback as agentName @preserve */
|
|
429
|
+
agentRoot: ctx?.agentRoot ?? (0, identity_1.getAgentRoot)(agentName),
|
|
395
430
|
peer,
|
|
396
431
|
did,
|
|
397
432
|
message: args.message,
|
|
398
433
|
});
|
|
399
|
-
return
|
|
434
|
+
return deliveryText(peer.name, did, delivery);
|
|
400
435
|
}
|
|
401
436
|
catch (error) {
|
|
402
437
|
return `A2A sealed send error: ${error instanceof Error ? error.message : /* v8 ignore next -- defensive non-Error transport failures @preserve */ String(error)}`;
|
|
@@ -534,8 +569,10 @@ exports.a2aToolDefinitions = [
|
|
|
534
569
|
}
|
|
535
570
|
const requestId = prepared.envelope.task?.requestId;
|
|
536
571
|
// Seal + send the coordination envelope to the peer over direct.
|
|
537
|
-
await sealEnvelopeToPeer({
|
|
538
|
-
|
|
572
|
+
const delivery = await sealEnvelopeToPeer({
|
|
573
|
+
/* v8 ignore next -- in-turn coordinate always carries a bundle agentRoot; the ambient fallback is defensive @preserve */
|
|
574
|
+
agentRoot: ctx?.agentRoot ?? (0, identity_1.getAgentRoot)(agentName),
|
|
575
|
+
self,
|
|
539
576
|
sodium, peer, did,
|
|
540
577
|
envelope: prepared.envelope,
|
|
541
578
|
friendsKind: "coordination",
|
|
@@ -546,7 +583,8 @@ exports.a2aToolDefinitions = [
|
|
|
546
583
|
message: "coordination delegated + sealed to peer",
|
|
547
584
|
meta: { tool: "coordinate", peerDid: did, missionKey: args.mission_key, requestId },
|
|
548
585
|
});
|
|
549
|
-
|
|
586
|
+
const queued = delivery.rung === "relay" ? ` ${deliveryText(peer.name, did, delivery, "delegation")}` : "";
|
|
587
|
+
return `coordinated: delegated "${args.task_summary}" to ${peer.name} on mission ${args.mission_key} (requestId ${requestId}).${queued}`;
|
|
550
588
|
}
|
|
551
589
|
catch (error) {
|
|
552
590
|
return `coordinate error: ${error instanceof Error ? error.message : /* v8 ignore next -- defensive non-Error failures @preserve */ String(error)}`;
|
|
@@ -686,8 +724,13 @@ exports.a2aToolDefinitions = [
|
|
|
686
724
|
message: "delivering sealed mission result over the direct rung",
|
|
687
725
|
meta: { selfDid: self.did, toDid: delegatorDid, requestId: args.request_id },
|
|
688
726
|
});
|
|
689
|
-
|
|
690
|
-
|
|
727
|
+
/* v8 ignore next -- in-turn send_result always carries a bundle agentRoot; the ambient fallback is defensive @preserve */
|
|
728
|
+
const relay = relayTransportFor({ agentRoot: ctx?.agentRoot ?? (0, identity_1.getAgentRoot)(agentName), self, peer: delegator, did: delegatorDid });
|
|
729
|
+
await relay.transport.send({ rung: "direct", address: endpointUrl }, message);
|
|
730
|
+
const delivery = relay.delivered();
|
|
731
|
+
return delivery.rung === "direct"
|
|
732
|
+
? `result sent to ${delegator.name} (${delegatorDid}) for requestId ${args.request_id}.`
|
|
733
|
+
: `${deliveryText(delegator.name, delegatorDid, delivery, "result")} (requestId ${args.request_id})`;
|
|
691
734
|
}
|
|
692
735
|
catch (error) {
|
|
693
736
|
return `send_result error: ${error instanceof Error ? error.message : /* v8 ignore next -- defensive non-Error failures @preserve */ String(error)}`;
|
package/dist/senses/a2a-entry.js
CHANGED
|
@@ -62,8 +62,9 @@ Promise.all([
|
|
|
62
62
|
Promise.resolve().then(() => __importStar(require("../heart/machine-identity"))),
|
|
63
63
|
Promise.resolve().then(() => __importStar(require("@ouro.bot/friends/a2a-client"))),
|
|
64
64
|
Promise.resolve().then(() => __importStar(require("../a2a/escalation-wiring"))),
|
|
65
|
+
Promise.resolve().then(() => __importStar(require("../a2a/relay-config-vault"))),
|
|
65
66
|
])
|
|
66
|
-
.then(async ([{ startA2AServer }, { loadOrMintA2AIdentity, readStoredA2ASeed, publishOwnA2ADid }, { waitForRuntimeCredentialBootstrap, readMachineRuntimeCredentialConfig, refreshMachineRuntimeCredentialConfig, mergeMachineRuntimeCredentialConfig }, { loadOrCreateMachineIdentity }, { ready }, { escalationOptionsFor, sendOwnerNoticeViaTelegram },]) => {
|
|
67
|
+
.then(async ([{ startA2AServer }, { loadOrMintA2AIdentity, readStoredA2ASeed, publishOwnA2ADid }, { waitForRuntimeCredentialBootstrap, readMachineRuntimeCredentialConfig, refreshMachineRuntimeCredentialConfig, mergeMachineRuntimeCredentialConfig }, { loadOrCreateMachineIdentity }, { ready }, { escalationOptionsFor, sendOwnerNoticeViaTelegram }, { relayConfigFrom, vaultRelayConfigStore },]) => {
|
|
67
68
|
const os = await Promise.resolve().then(() => __importStar(require("node:os")));
|
|
68
69
|
// Wait for the daemon to deliver the machine-local runtime config (carrying the
|
|
69
70
|
// a2a identity seed) into the in-memory cache before we read or mint identity.
|
|
@@ -94,6 +95,7 @@ Promise.all([
|
|
|
94
95
|
},
|
|
95
96
|
});
|
|
96
97
|
publishOwnA2ADid((0, identity_1.getAgentRoot)(agentName), identity.did);
|
|
98
|
+
const relaySettings = relayConfigFrom(machineConfig);
|
|
97
99
|
const rawPort = argValue("--port");
|
|
98
100
|
const port = rawPort ? Number.parseInt(rawPort, 10) : undefined;
|
|
99
101
|
await startA2AServer({
|
|
@@ -113,6 +115,11 @@ Promise.all([
|
|
|
113
115
|
} : {}),
|
|
114
116
|
...escalationOptionsFor(agentName, (notice) => sendOwnerNoticeViaTelegram(agentName, notice)),
|
|
115
117
|
notifyOwner: (notice) => sendOwnerNoticeViaTelegram(agentName, notice),
|
|
118
|
+
// A friends-relay inbox for messages sent while this agent is offline, when the operator set a2a.relay.url
|
|
119
|
+
// (or registrations on relays it moved away from still have to be drained and removed).
|
|
120
|
+
...(relaySettings.url || relaySettings.previousRegistrations?.length
|
|
121
|
+
? { relay: { config: vaultRelayConfigStore(agentName, machineId), notifyOwner: (notice) => sendOwnerNoticeViaTelegram(agentName, notice) } }
|
|
122
|
+
: {}),
|
|
116
123
|
...(argValue("--host") ? { host: argValue("--host") } : {}),
|
|
117
124
|
...(Number.isInteger(port) ? { port } : {}),
|
|
118
125
|
...(argValue("--base-url") ? { baseUrl: argValue("--base-url") } : {}),
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouro.bot/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.990",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@ouro.bot/cli",
|
|
9
|
-
"version": "0.1.0-alpha.
|
|
9
|
+
"version": "0.1.0-alpha.990",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
12
12
|
"@azure/identity": "^4.13.0",
|