agent-relay 11.8.4 → 11.8.5
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/dist/index.cjs +63 -13
- package/package.json +9 -9
package/dist/index.cjs
CHANGED
|
@@ -20644,8 +20644,13 @@ function placementActionName(capability) {
|
|
|
20644
20644
|
function placementActionInput(input, placement) {
|
|
20645
20645
|
const payload = { ...input ?? {} };
|
|
20646
20646
|
payload.capability = placement.capability;
|
|
20647
|
-
|
|
20648
|
-
|
|
20647
|
+
if (placement.node) {
|
|
20648
|
+
payload.node = placement.node;
|
|
20649
|
+
payload.target_node = placement.node;
|
|
20650
|
+
} else {
|
|
20651
|
+
delete payload.node;
|
|
20652
|
+
delete payload.target_node;
|
|
20653
|
+
}
|
|
20649
20654
|
if (placement.repo)
|
|
20650
20655
|
payload.repo = placement.repo;
|
|
20651
20656
|
if (placement.ttlMs > 0) {
|
|
@@ -20694,6 +20699,7 @@ var RelaycastMessagingClient = class {
|
|
|
20694
20699
|
agentClient;
|
|
20695
20700
|
selfNodeName;
|
|
20696
20701
|
placementTtlMs;
|
|
20702
|
+
placementSandboxOnly;
|
|
20697
20703
|
maxQueuedPlacements;
|
|
20698
20704
|
placementLog;
|
|
20699
20705
|
sessionRef;
|
|
@@ -20705,6 +20711,7 @@ var RelaycastMessagingClient = class {
|
|
|
20705
20711
|
this.agentClient = options.agentClient ?? (options.agentToken ? this.relaycast.as?.(options.agentToken, options.agentClientOptions) : void 0);
|
|
20706
20712
|
this.selfNodeName = options.selfNodeName;
|
|
20707
20713
|
this.placementTtlMs = options.placementTtlMs ?? 60 * 60 * 1e3;
|
|
20714
|
+
this.placementSandboxOnly = options.placementSandboxOnly ?? false;
|
|
20708
20715
|
this.maxQueuedPlacements = options.maxQueuedPlacements ?? 100;
|
|
20709
20716
|
this.placementLog = options.placementLog;
|
|
20710
20717
|
this.sessionRef = options.sessionRef === void 0 ? currentReplaySessionRef() : resolveReplaySessionRef(options.sessionRef);
|
|
@@ -21057,6 +21064,8 @@ var RelaycastMessagingClient = class {
|
|
|
21057
21064
|
const capability = nonEmptyPlacement(input.capability, "placement capability");
|
|
21058
21065
|
const repo = input.repo?.trim() || void 0;
|
|
21059
21066
|
const targetNode = this.resolvePlacementNode(input.node, input.selfNodeName);
|
|
21067
|
+
const sandboxOnly = input.sandboxOnly ?? this.placementSandboxOnly;
|
|
21068
|
+
const failFast = input.failFast ?? true;
|
|
21060
21069
|
const ttlMs = Math.max(0, input.ttlMs ?? input.ttlOverrideMs ?? this.placementTtlMs);
|
|
21061
21070
|
const pollIntervalMs = Math.max(25, input.pollIntervalMs ?? 1e3);
|
|
21062
21071
|
const startedAt = Date.now();
|
|
@@ -21065,19 +21074,22 @@ var RelaycastMessagingClient = class {
|
|
|
21065
21074
|
try {
|
|
21066
21075
|
while (true) {
|
|
21067
21076
|
attempts += 1;
|
|
21068
|
-
const decision = await this.selectPlacementNode({ capability, repo, targetNode });
|
|
21077
|
+
const decision = await this.selectPlacementNode({ capability, repo, targetNode, sandboxOnly });
|
|
21069
21078
|
if (decision.node) {
|
|
21070
21079
|
const actionName = input.actionName ?? placementActionName(capability);
|
|
21080
|
+
const clientMustTarget = Boolean(targetNode || repo || sandboxOnly);
|
|
21071
21081
|
const actionInput = placementActionInput(input.input, {
|
|
21072
21082
|
capability,
|
|
21073
|
-
node: decision.node.name,
|
|
21083
|
+
...clientMustTarget ? { node: decision.node.name } : {},
|
|
21074
21084
|
repo,
|
|
21075
21085
|
ttlMs
|
|
21076
21086
|
});
|
|
21077
21087
|
const ack = await this.commands.invoke(actionName, actionInput);
|
|
21088
|
+
const placedNode = clientMustTarget ? decision.node : await this.resolvePlacementAckNode(ack, capability);
|
|
21089
|
+
const placedNodeLabel = placedNode?.name ?? ack.dispatchedNodeId ?? ack.handlerNodeId ?? "engine-selected node";
|
|
21078
21090
|
const confirmation = input.confirm ? await this.confirmPlacementInvocation(actionName, ack, {
|
|
21079
21091
|
capability,
|
|
21080
|
-
node:
|
|
21092
|
+
node: placedNodeLabel,
|
|
21081
21093
|
repo,
|
|
21082
21094
|
attempts,
|
|
21083
21095
|
// Defaults and validation live in confirmPlacementInvocation
|
|
@@ -21087,10 +21099,10 @@ var RelaycastMessagingClient = class {
|
|
|
21087
21099
|
}) : void 0;
|
|
21088
21100
|
return {
|
|
21089
21101
|
...ack,
|
|
21090
|
-
node:
|
|
21102
|
+
...placedNode ? { node: placedNode } : {},
|
|
21091
21103
|
placement: {
|
|
21092
21104
|
capability,
|
|
21093
|
-
node:
|
|
21105
|
+
...placedNode ? { node: placedNode.name } : {},
|
|
21094
21106
|
...repo ? { repo } : {},
|
|
21095
21107
|
attempts,
|
|
21096
21108
|
queued,
|
|
@@ -21108,9 +21120,9 @@ var RelaycastMessagingClient = class {
|
|
|
21108
21120
|
attempts
|
|
21109
21121
|
});
|
|
21110
21122
|
}
|
|
21111
|
-
if (
|
|
21112
|
-
const code = decision.reconcileReason === "unmapped_repo" ? "unmapped_repo" : "placement_ttl_expired";
|
|
21113
|
-
const message = code === "unmapped_repo" ? `${decision.message}; no node maps the requested repo` : `${decision.message}; placement TTL expired`;
|
|
21123
|
+
if (failFast || Date.now() - startedAt >= ttlMs) {
|
|
21124
|
+
const code = failFast ? decision.reconcileReason === "unmapped_repo" ? "unmapped_repo" : decision.reconcileReason === "target_offline" ? "node_unavailable" : decision.reconcileReason === "sandbox_policy_mismatch" ? "sandbox_policy_mismatch" : "no_eligible_node" : decision.reconcileReason === "unmapped_repo" ? "unmapped_repo" : "placement_ttl_expired";
|
|
21125
|
+
const message = code === "unmapped_repo" ? `${decision.message}; no node maps the requested repo` : failFast ? `${decision.message}; placement failed fast` : `${decision.message}; placement TTL expired`;
|
|
21114
21126
|
await this.reconcilePlacement(input, {
|
|
21115
21127
|
action: "failed",
|
|
21116
21128
|
reason: decision.reconcileReason,
|
|
@@ -21270,9 +21282,17 @@ var RelaycastMessagingClient = class {
|
|
|
21270
21282
|
reconcileReason: "no_eligible_node"
|
|
21271
21283
|
};
|
|
21272
21284
|
}
|
|
21273
|
-
if (!node
|
|
21285
|
+
if (input.sandboxOnly && !this.nodeIsCloudSandbox(node)) {
|
|
21286
|
+
return {
|
|
21287
|
+
message: `Placement rejected: node "${node.name}" is not a Cloud sandbox`,
|
|
21288
|
+
hardFail: true,
|
|
21289
|
+
reason: "sandbox_policy_mismatch",
|
|
21290
|
+
reconcileReason: "sandbox_policy_mismatch"
|
|
21291
|
+
};
|
|
21292
|
+
}
|
|
21293
|
+
if (!this.nodeIsPlacementReady(node)) {
|
|
21274
21294
|
return {
|
|
21275
|
-
message: `Placement queued: target node "${node.name}" is
|
|
21295
|
+
message: `Placement queued: target node "${node.name}" is not placement-ready`,
|
|
21276
21296
|
reconcileReason: "target_offline"
|
|
21277
21297
|
};
|
|
21278
21298
|
}
|
|
@@ -21286,10 +21306,17 @@ var RelaycastMessagingClient = class {
|
|
|
21286
21306
|
}
|
|
21287
21307
|
const nodes = await this.nodes.list({ capability: input.capability });
|
|
21288
21308
|
const capable = nodes.filter((node) => this.nodeHasCapability(node, input.capability));
|
|
21289
|
-
const
|
|
21309
|
+
const policyEligible = input.sandboxOnly ? capable.filter((node) => this.nodeIsCloudSandbox(node)) : capable;
|
|
21310
|
+
const live = policyEligible.filter((node) => this.nodeIsPlacementReady(node));
|
|
21290
21311
|
const eligible = live.filter((node) => this.nodeMapsRepo(node, input.repo));
|
|
21291
21312
|
if (eligible[0])
|
|
21292
21313
|
return { node: eligible[0] };
|
|
21314
|
+
if (input.sandboxOnly) {
|
|
21315
|
+
return {
|
|
21316
|
+
message: `Placement queued: no placement-ready Cloud sandbox advertises capability "${input.capability}"`,
|
|
21317
|
+
reconcileReason: "sandbox_policy_mismatch"
|
|
21318
|
+
};
|
|
21319
|
+
}
|
|
21293
21320
|
if (input.repo && live.length > 0) {
|
|
21294
21321
|
return {
|
|
21295
21322
|
message: `Placement queued: no live node advertising "${input.capability}" maps repo "${input.repo}"`,
|
|
@@ -21304,6 +21331,29 @@ var RelaycastMessagingClient = class {
|
|
|
21304
21331
|
nodeHasCapability(node, capability) {
|
|
21305
21332
|
return node.capabilities.some((item) => item.name === capability);
|
|
21306
21333
|
}
|
|
21334
|
+
/** Return true only when the fresh roster reports a usable action handler. */
|
|
21335
|
+
nodeIsPlacementReady(node) {
|
|
21336
|
+
return node.status === "online" && node.live === true && node.handlersLive === true;
|
|
21337
|
+
}
|
|
21338
|
+
/** Match the stable Cloud JIT provenance tag without relying on disposable node names. */
|
|
21339
|
+
nodeIsCloudSandbox(node) {
|
|
21340
|
+
return Boolean(node.tags?.some((tag) => /^cloud:node-type:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?-jit$/.test(tag)));
|
|
21341
|
+
}
|
|
21342
|
+
async resolvePlacementAckNode(ack, capability) {
|
|
21343
|
+
const nodeId = ack.dispatchedNodeId ?? ack.handlerNodeId;
|
|
21344
|
+
if (nodeId) {
|
|
21345
|
+
try {
|
|
21346
|
+
const nodes = await this.nodes.list({ capability });
|
|
21347
|
+
return nodes.find((candidate) => candidate.id === nodeId || candidate.nodeId === nodeId);
|
|
21348
|
+
} catch (error51) {
|
|
21349
|
+
try {
|
|
21350
|
+
this.placementLog?.(`[placement] dispatch ${ack.invocationId ?? "unknown"} accepted by ${nodeId}, but roster metadata could not be refreshed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
21351
|
+
} catch {
|
|
21352
|
+
}
|
|
21353
|
+
}
|
|
21354
|
+
}
|
|
21355
|
+
return void 0;
|
|
21356
|
+
}
|
|
21307
21357
|
nodeMapsRepo(node, repo) {
|
|
21308
21358
|
if (!repo)
|
|
21309
21359
|
return true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-relay",
|
|
3
|
-
"version": "11.8.
|
|
3
|
+
"version": "11.8.5",
|
|
4
4
|
"description": "Real-time agent-to-agent communication system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
"pack:validate": "npm pack --dry-run"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@agent-relay/cloud": "11.8.
|
|
47
|
-
"@agent-relay/config": "11.8.
|
|
48
|
-
"@agent-relay/fleet": "11.8.
|
|
49
|
-
"@agent-relay/harness-driver": "11.8.
|
|
50
|
-
"@agent-relay/harnesses": "11.8.
|
|
51
|
-
"@agent-relay/sdk": "11.8.
|
|
52
|
-
"@agent-relay/session": "11.8.
|
|
53
|
-
"@agent-relay/utils": "11.8.
|
|
46
|
+
"@agent-relay/cloud": "11.8.5",
|
|
47
|
+
"@agent-relay/config": "11.8.5",
|
|
48
|
+
"@agent-relay/fleet": "11.8.5",
|
|
49
|
+
"@agent-relay/harness-driver": "11.8.5",
|
|
50
|
+
"@agent-relay/harnesses": "11.8.5",
|
|
51
|
+
"@agent-relay/sdk": "11.8.5",
|
|
52
|
+
"@agent-relay/session": "11.8.5",
|
|
53
|
+
"@agent-relay/utils": "11.8.5",
|
|
54
54
|
"@modelcontextprotocol/sdk": "^1.23.0",
|
|
55
55
|
"@relayfile/client": "^0.10.27",
|
|
56
56
|
"@relayflows/cli": "1.0.1",
|