@moxt-ai/mobius 0.0.25 → 0.0.27
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/agent-catalog/publish-agent-catalog.js +3 -3
- package/dist/agent-catalog/publish-agent-catalog.js.map +1 -1
- package/dist/cli.js +1194 -205
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1186 -204
- package/dist/index.js.map +4 -4
- package/dist/network/environment-proxy.d.ts +1 -0
- package/dist/network/environment-proxy.d.ts.map +1 -1
- package/dist/network/environment-proxy.js +47 -0
- package/dist/network/environment-proxy.js.map +1 -1
- package/dist/prompt-artifact-resolver.d.ts.map +1 -1
- package/dist/prompt-artifact-resolver.js +7 -4
- package/dist/prompt-artifact-resolver.js.map +1 -1
- package/dist/relay-connection/connect.d.ts.map +1 -1
- package/dist/relay-connection/connect.js +19 -14
- package/dist/relay-connection/connect.js.map +1 -1
- package/dist/relay-connection/diagnostics.d.ts +11 -0
- package/dist/relay-connection/diagnostics.d.ts.map +1 -0
- package/dist/relay-connection/diagnostics.js +122 -0
- package/dist/relay-connection/diagnostics.js.map +1 -0
- package/dist/relay-connection/liveness.d.ts +1 -1
- package/dist/relay-connection/liveness.d.ts.map +1 -1
- package/dist/relay-connection/liveness.js +2 -1
- package/dist/relay-connection/liveness.js.map +1 -1
- package/dist/relay-connection/runtime-authentication.d.ts +3 -0
- package/dist/relay-connection/runtime-authentication.d.ts.map +1 -0
- package/dist/relay-connection/runtime-authentication.js +14 -0
- package/dist/relay-connection/runtime-authentication.js.map +1 -0
- package/dist/relay-connection/session-event-outbox.d.ts +34 -3
- package/dist/relay-connection/session-event-outbox.d.ts.map +1 -1
- package/dist/relay-connection/session-event-outbox.js +404 -13
- package/dist/relay-connection/session-event-outbox.js.map +1 -1
- package/dist/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +437 -151
- package/dist/run-daemon.js.map +1 -1
- package/dist/runtime.js +1186 -204
- package/dist/runtime.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19340,6 +19340,9 @@ var SESSION_CANCEL_KIND = "session.cancel";
|
|
|
19340
19340
|
var RUNTIME_LIVENESS_READY_KIND = "runtime.liveness.ready";
|
|
19341
19341
|
var RUNTIME_HEARTBEAT_KIND = "runtime.heartbeat";
|
|
19342
19342
|
var RUNTIME_HEARTBEAT_ACK_KIND = "runtime.heartbeat.ack";
|
|
19343
|
+
var RUNTIME_DELIVERY_KIND = "runtime.delivery";
|
|
19344
|
+
var RUNTIME_DELIVERY_RECEIVED_KIND = "runtime.delivery.received";
|
|
19345
|
+
var RUNTIME_DELIVERY_COMMITTED_KIND = "runtime.delivery.committed";
|
|
19343
19346
|
var SESSION_STARTED_KIND = "session.started";
|
|
19344
19347
|
var AGENT_MESSAGE_DELTA_KIND = "agent.message.delta";
|
|
19345
19348
|
var AGENT_ACTIVITY_KIND = "agent.activity";
|
|
@@ -19362,6 +19365,7 @@ var DIRECTORY_IDENTIFIER_PATTERN2 = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/;
|
|
|
19362
19365
|
var MAX_PROMPT_LENGTH = 1e4;
|
|
19363
19366
|
var MAX_PROMPT_ATTACHMENT_LENGTH = 6e6;
|
|
19364
19367
|
var MAX_EVENT_TEXT_LENGTH = 1e5;
|
|
19368
|
+
var MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH = 8 * 1024 * 1024;
|
|
19365
19369
|
var ACTIVITY_TYPES = /* @__PURE__ */ new Set(["plan", "progress", "reasoning", "tool"]);
|
|
19366
19370
|
var ACTIVITY_STATUSES = /* @__PURE__ */ new Set(["pending", "running", "completed", "failed"]);
|
|
19367
19371
|
var TOOL_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -19640,6 +19644,37 @@ function decodeRuntimeHeartbeatAckEvent(encoded) {
|
|
|
19640
19644
|
kind: RUNTIME_HEARTBEAT_ACK_KIND
|
|
19641
19645
|
};
|
|
19642
19646
|
}
|
|
19647
|
+
function decodeRuntimeDelivery(encoded) {
|
|
19648
|
+
const value = parseJson2(encoded);
|
|
19649
|
+
assertExactKeys(value, ["deliveryId", "kind", "payload", "sessionId"]);
|
|
19650
|
+
assertKind(value, RUNTIME_DELIVERY_KIND);
|
|
19651
|
+
return {
|
|
19652
|
+
deliveryId: readIdentifier(value, "deliveryId"),
|
|
19653
|
+
kind: RUNTIME_DELIVERY_KIND,
|
|
19654
|
+
payload: readString(value, "payload", MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH),
|
|
19655
|
+
sessionId: readIdentifier(value, "sessionId")
|
|
19656
|
+
};
|
|
19657
|
+
}
|
|
19658
|
+
function decodeRuntimeDeliveryReceived(encoded) {
|
|
19659
|
+
const value = parseJson2(encoded);
|
|
19660
|
+
assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
|
|
19661
|
+
assertKind(value, RUNTIME_DELIVERY_RECEIVED_KIND);
|
|
19662
|
+
return {
|
|
19663
|
+
deliveryId: readIdentifier(value, "deliveryId"),
|
|
19664
|
+
kind: RUNTIME_DELIVERY_RECEIVED_KIND,
|
|
19665
|
+
sessionId: readIdentifier(value, "sessionId")
|
|
19666
|
+
};
|
|
19667
|
+
}
|
|
19668
|
+
function decodeRuntimeDeliveryCommitted(encoded) {
|
|
19669
|
+
const value = parseJson2(encoded);
|
|
19670
|
+
assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
|
|
19671
|
+
assertKind(value, RUNTIME_DELIVERY_COMMITTED_KIND);
|
|
19672
|
+
return {
|
|
19673
|
+
deliveryId: readIdentifier(value, "deliveryId"),
|
|
19674
|
+
kind: RUNTIME_DELIVERY_COMMITTED_KIND,
|
|
19675
|
+
sessionId: readIdentifier(value, "sessionId")
|
|
19676
|
+
};
|
|
19677
|
+
}
|
|
19643
19678
|
function decodeSessionStartedEvent(encoded) {
|
|
19644
19679
|
const value = parseJson2(encoded);
|
|
19645
19680
|
assertExactKeys(value, ["commandId", "kind", "attemptId", "sessionId"]);
|
|
@@ -19727,6 +19762,9 @@ function decodeSessionFailedEvent(encoded) {
|
|
|
19727
19762
|
function encodeRuntimeHeartbeatEvent(message) {
|
|
19728
19763
|
return JSON.stringify(decodeRuntimeHeartbeatEvent(JSON.stringify(message)));
|
|
19729
19764
|
}
|
|
19765
|
+
function encodeRuntimeDeliveryReceived(message) {
|
|
19766
|
+
return JSON.stringify(decodeRuntimeDeliveryReceived(JSON.stringify(message)));
|
|
19767
|
+
}
|
|
19730
19768
|
function encodeSessionStartedEvent(message) {
|
|
19731
19769
|
return JSON.stringify(decodeSessionStartedEvent(JSON.stringify(message)));
|
|
19732
19770
|
}
|
|
@@ -20425,7 +20463,8 @@ var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
|
|
|
20425
20463
|
var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
|
|
20426
20464
|
var SessionEventRejectionCode = {
|
|
20427
20465
|
SessionDeleted: "session_deleted",
|
|
20428
|
-
SessionNotFound: "session_not_found"
|
|
20466
|
+
SessionNotFound: "session_not_found",
|
|
20467
|
+
SessionRejected: "session_rejected"
|
|
20429
20468
|
};
|
|
20430
20469
|
var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
20431
20470
|
var CURSOR_PATTERN = /^[A-Za-z0-9_-]{1,512}$/;
|
|
@@ -20497,6 +20536,7 @@ var encode4 = (message, schema) => {
|
|
|
20497
20536
|
}
|
|
20498
20537
|
return JSON.stringify(decoded.data);
|
|
20499
20538
|
};
|
|
20539
|
+
var decodeSessionEventEnvelope = (encoded) => decode5(encoded, eventEnvelopeSchema);
|
|
20500
20540
|
var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
|
|
20501
20541
|
var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
|
|
20502
20542
|
var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSchema);
|
|
@@ -26286,7 +26326,53 @@ import { fetch as fetch2 } from "undici";
|
|
|
26286
26326
|
|
|
26287
26327
|
// src/network/environment-proxy.ts
|
|
26288
26328
|
import { EnvHttpProxyAgent } from "undici";
|
|
26329
|
+
var configuredHttpProxy = process.env["http_proxy"] ?? process.env["HTTP_PROXY"] ?? "";
|
|
26330
|
+
var configuredHttpsProxy = process.env["https_proxy"] ?? process.env["HTTPS_PROXY"] ?? configuredHttpProxy;
|
|
26289
26331
|
var environmentProxyDispatcher = new EnvHttpProxyAgent();
|
|
26332
|
+
function bypassesProxy(target) {
|
|
26333
|
+
const noProxy = process.env["no_proxy"] ?? process.env["NO_PROXY"] ?? "";
|
|
26334
|
+
if (noProxy === "*") {
|
|
26335
|
+
return true;
|
|
26336
|
+
}
|
|
26337
|
+
const hostname4 = target.hostname.replace(/^\[|\]$/gu, "").toLowerCase();
|
|
26338
|
+
const defaultPort = target.protocol === "wss:" || target.protocol === "https:" ? 443 : 80;
|
|
26339
|
+
const port = Number.parseInt(target.port, 10) || defaultPort;
|
|
26340
|
+
for (const rawEntry of noProxy.split(/[,\s]/u)) {
|
|
26341
|
+
if (rawEntry.length === 0) {
|
|
26342
|
+
continue;
|
|
26343
|
+
}
|
|
26344
|
+
const parsed = rawEntry.match(/^(.+):(\d+)$/u);
|
|
26345
|
+
const entryHostname = (parsed?.[1] ?? rawEntry).replace(/^\*?\./u, "").toLowerCase();
|
|
26346
|
+
const entryPort = parsed?.[2] === void 0 ? 0 : Number.parseInt(parsed[2], 10);
|
|
26347
|
+
if (entryPort !== 0 && entryPort !== port) {
|
|
26348
|
+
continue;
|
|
26349
|
+
}
|
|
26350
|
+
if (hostname4 === entryHostname || hostname4.endsWith(`.${entryHostname}`)) {
|
|
26351
|
+
return true;
|
|
26352
|
+
}
|
|
26353
|
+
}
|
|
26354
|
+
return false;
|
|
26355
|
+
}
|
|
26356
|
+
function sanitizedProxyOrigin(proxyUrl) {
|
|
26357
|
+
try {
|
|
26358
|
+
return new URL(proxyUrl).origin;
|
|
26359
|
+
} catch {
|
|
26360
|
+
return "configured-invalid-url";
|
|
26361
|
+
}
|
|
26362
|
+
}
|
|
26363
|
+
function describeEnvironmentProxyRoute(target) {
|
|
26364
|
+
if (bypassesProxy(target)) {
|
|
26365
|
+
return { proxyRoute: "direct" };
|
|
26366
|
+
}
|
|
26367
|
+
const proxyUrl = target.protocol === "wss:" || target.protocol === "https:" ? configuredHttpsProxy : configuredHttpProxy;
|
|
26368
|
+
if (proxyUrl.length === 0) {
|
|
26369
|
+
return { proxyRoute: "direct" };
|
|
26370
|
+
}
|
|
26371
|
+
return {
|
|
26372
|
+
proxyOrigin: sanitizedProxyOrigin(proxyUrl),
|
|
26373
|
+
proxyRoute: "proxy"
|
|
26374
|
+
};
|
|
26375
|
+
}
|
|
26290
26376
|
|
|
26291
26377
|
// src/agent-installation/managed-agent-archive.ts
|
|
26292
26378
|
var ARCHIVE_DOWNLOAD_LIMIT_BYTES = 128 * 1024 * 1024;
|
|
@@ -27421,12 +27507,12 @@ function decodePairingResponse(value, credentialField, expectedKeys) {
|
|
|
27421
27507
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
27422
27508
|
}
|
|
27423
27509
|
const channelId = value["channelId"];
|
|
27424
|
-
const
|
|
27510
|
+
const runtimeCredential2 = value[credentialField];
|
|
27425
27511
|
const runtimeId = value["runtimeId"];
|
|
27426
|
-
if (typeof channelId !== "string" || !IDENTIFIER_PATTERN6.test(channelId) || typeof
|
|
27512
|
+
if (typeof channelId !== "string" || !IDENTIFIER_PATTERN6.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN6.test(runtimeId)) {
|
|
27427
27513
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
27428
27514
|
}
|
|
27429
|
-
return { channelId, runtimeCredential, runtimeId };
|
|
27515
|
+
return { channelId, runtimeCredential: runtimeCredential2, runtimeId };
|
|
27430
27516
|
}
|
|
27431
27517
|
async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
|
|
27432
27518
|
const agents = localAgents.map((agent) => ({
|
|
@@ -27461,7 +27547,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
27461
27547
|
}
|
|
27462
27548
|
return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
|
|
27463
27549
|
}
|
|
27464
|
-
async function persistConnection(channelId, relayOrigin,
|
|
27550
|
+
async function persistConnection(channelId, relayOrigin, runtimeCredential2, defaultWorkspace, environment) {
|
|
27465
27551
|
const connectionsDirectory = join14(readStateDirectory(environment), "connections");
|
|
27466
27552
|
await mkdir4(connectionsDirectory, { mode: 448, recursive: true });
|
|
27467
27553
|
const connectionPath = join14(connectionsDirectory, `${channelId}.json`);
|
|
@@ -27473,7 +27559,7 @@ async function persistConnection(channelId, relayOrigin, runtimeCredential, defa
|
|
|
27473
27559
|
defaultWorkspace,
|
|
27474
27560
|
channelId,
|
|
27475
27561
|
relayOrigin: relayOrigin.toString(),
|
|
27476
|
-
runtimeCredential
|
|
27562
|
+
runtimeCredential: runtimeCredential2
|
|
27477
27563
|
},
|
|
27478
27564
|
null,
|
|
27479
27565
|
2
|
|
@@ -27490,16 +27576,16 @@ function decodeSavedConnection(value, expectedChannelId) {
|
|
|
27490
27576
|
}
|
|
27491
27577
|
const defaultWorkspace = value["defaultWorkspace"];
|
|
27492
27578
|
const channelId = value["channelId"];
|
|
27493
|
-
const
|
|
27579
|
+
const runtimeCredential2 = value["runtimeCredential"] ?? value["daemonToken"];
|
|
27494
27580
|
const relayOrigin = value["relayOrigin"];
|
|
27495
|
-
if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN6.test(channelId) || typeof
|
|
27581
|
+
if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN6.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof relayOrigin !== "string") {
|
|
27496
27582
|
throw new PairingClientError("invalid_connection", "The saved connection is invalid");
|
|
27497
27583
|
}
|
|
27498
27584
|
return {
|
|
27499
27585
|
defaultWorkspace,
|
|
27500
27586
|
channelId,
|
|
27501
27587
|
relayOrigin: parseRelayOrigin(relayOrigin),
|
|
27502
|
-
runtimeCredential
|
|
27588
|
+
runtimeCredential: runtimeCredential2
|
|
27503
27589
|
};
|
|
27504
27590
|
}
|
|
27505
27591
|
async function readSavedConnection(channelId, environment) {
|
|
@@ -27622,6 +27708,23 @@ import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
|
|
|
27622
27708
|
|
|
27623
27709
|
// src/agent-catalog/publish-agent-catalog.ts
|
|
27624
27710
|
import { fetch as fetch4 } from "undici";
|
|
27711
|
+
|
|
27712
|
+
// src/relay-connection/runtime-authentication.ts
|
|
27713
|
+
function runtimeCredential(relayUrl) {
|
|
27714
|
+
return relayUrl.searchParams.get("token") ?? "";
|
|
27715
|
+
}
|
|
27716
|
+
function runtimeAuthorization(relayUrl) {
|
|
27717
|
+
const credential = runtimeCredential(relayUrl);
|
|
27718
|
+
return credential.length === 0 ? {} : { authorization: `Bearer ${credential}` };
|
|
27719
|
+
}
|
|
27720
|
+
function relayHttpEndpoint(relayUrl) {
|
|
27721
|
+
const endpoint = new URL(relayUrl);
|
|
27722
|
+
endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
|
|
27723
|
+
endpoint.search = "";
|
|
27724
|
+
return endpoint;
|
|
27725
|
+
}
|
|
27726
|
+
|
|
27727
|
+
// src/agent-catalog/publish-agent-catalog.ts
|
|
27625
27728
|
var CATALOG_UPDATE_TIMEOUT_MILLISECONDS = 2e4;
|
|
27626
27729
|
var AgentCatalogPublishError = class extends Error {
|
|
27627
27730
|
code = "agent_catalog_update_failed";
|
|
@@ -27631,8 +27734,7 @@ var AgentCatalogPublishError = class extends Error {
|
|
|
27631
27734
|
}
|
|
27632
27735
|
};
|
|
27633
27736
|
function catalogEndpoint(config2) {
|
|
27634
|
-
const endpoint =
|
|
27635
|
-
endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
|
|
27737
|
+
const endpoint = relayHttpEndpoint(config2.relayUrl);
|
|
27636
27738
|
if (endpoint.pathname.endsWith("/daemon")) {
|
|
27637
27739
|
endpoint.pathname = `${endpoint.pathname.slice(0, -"/daemon".length)}/catalog`;
|
|
27638
27740
|
return endpoint;
|
|
@@ -27663,7 +27765,7 @@ async function publishAgentCatalog(config2, signal) {
|
|
|
27663
27765
|
installableAgents: catalog.installableAgents
|
|
27664
27766
|
}),
|
|
27665
27767
|
dispatcher: environmentProxyDispatcher,
|
|
27666
|
-
headers: { "content-type": "application/json" },
|
|
27768
|
+
headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
|
|
27667
27769
|
method: "PUT",
|
|
27668
27770
|
signal: requestSignal
|
|
27669
27771
|
});
|
|
@@ -29019,8 +29121,7 @@ function parseReference(resource) {
|
|
|
29019
29121
|
return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
|
|
29020
29122
|
}
|
|
29021
29123
|
function downloadUrl(config2, command, reference) {
|
|
29022
|
-
const url2 =
|
|
29023
|
-
url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
|
|
29124
|
+
const url2 = relayHttpEndpoint(config2.relayUrl);
|
|
29024
29125
|
let channelPath = "";
|
|
29025
29126
|
if (url2.pathname.endsWith("/daemon")) {
|
|
29026
29127
|
channelPath = url2.pathname.slice(0, -"/daemon".length);
|
|
@@ -29032,7 +29133,6 @@ function downloadUrl(config2, command, reference) {
|
|
|
29032
29133
|
channelPath = `${url2.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
|
|
29033
29134
|
}
|
|
29034
29135
|
url2.pathname = `${channelPath}/sessions/${encodeURIComponent(command.sessionId)}/commands/${encodeURIComponent(command.commandId)}/artifacts/${encodeURIComponent(reference.artifactId)}/content`;
|
|
29035
|
-
url2.searchParams.delete("liveness");
|
|
29036
29136
|
return url2;
|
|
29037
29137
|
}
|
|
29038
29138
|
async function responseBytes(response, expectedByteLength, signal) {
|
|
@@ -29083,7 +29183,11 @@ async function download(config2, command, reference, signal) {
|
|
|
29083
29183
|
try {
|
|
29084
29184
|
response = await fetch5(downloadUrl(config2, command, reference), {
|
|
29085
29185
|
dispatcher: environmentProxyDispatcher,
|
|
29086
|
-
headers: {
|
|
29186
|
+
headers: {
|
|
29187
|
+
accept: reference.resource.mimeType,
|
|
29188
|
+
"accept-encoding": "identity",
|
|
29189
|
+
...runtimeAuthorization(config2.relayUrl)
|
|
29190
|
+
},
|
|
29087
29191
|
signal: requestSignal
|
|
29088
29192
|
});
|
|
29089
29193
|
if (!response.ok) {
|
|
@@ -29181,9 +29285,11 @@ import { WebSocket } from "undici";
|
|
|
29181
29285
|
var CONNECTION_TIMEOUT_MILLISECONDS = 15e3;
|
|
29182
29286
|
var RelayConnectionError = class extends Error {
|
|
29183
29287
|
code;
|
|
29184
|
-
|
|
29288
|
+
diagnosticDetails;
|
|
29289
|
+
constructor(code, message, diagnosticDetails = {}, options = {}) {
|
|
29185
29290
|
super(message, options);
|
|
29186
29291
|
this.code = code;
|
|
29292
|
+
this.diagnosticDetails = diagnosticDetails;
|
|
29187
29293
|
this.name = "RelayConnectionError";
|
|
29188
29294
|
}
|
|
29189
29295
|
};
|
|
@@ -29191,12 +29297,8 @@ function connectRelay(url2, signal) {
|
|
|
29191
29297
|
signal.throwIfAborted();
|
|
29192
29298
|
return new Promise((resolve6, reject) => {
|
|
29193
29299
|
const endpoint = new URL(url2);
|
|
29194
|
-
const headers =
|
|
29195
|
-
|
|
29196
|
-
const runtimeCredential = endpoint.searchParams.get("token") ?? "";
|
|
29197
|
-
endpoint.searchParams.delete("token");
|
|
29198
|
-
headers["authorization"] = `Bearer ${runtimeCredential}`;
|
|
29199
|
-
}
|
|
29300
|
+
const headers = runtimeAuthorization(endpoint);
|
|
29301
|
+
endpoint.searchParams.delete("token");
|
|
29200
29302
|
const socket = new WebSocket(endpoint, {
|
|
29201
29303
|
dispatcher: environmentProxyDispatcher,
|
|
29202
29304
|
headers
|
|
@@ -29221,16 +29323,34 @@ function connectRelay(url2, signal) {
|
|
|
29221
29323
|
};
|
|
29222
29324
|
const onAbort = () => {
|
|
29223
29325
|
fail(
|
|
29224
|
-
new RelayConnectionError(
|
|
29225
|
-
|
|
29226
|
-
|
|
29326
|
+
new RelayConnectionError(
|
|
29327
|
+
"relay_connection_cancelled",
|
|
29328
|
+
"Relay connection was cancelled",
|
|
29329
|
+
{
|
|
29330
|
+
cancellation: "requested"
|
|
29331
|
+
},
|
|
29332
|
+
{ cause: signal.reason }
|
|
29333
|
+
)
|
|
29227
29334
|
);
|
|
29228
29335
|
};
|
|
29229
|
-
const onClose = () => {
|
|
29230
|
-
fail(
|
|
29336
|
+
const onClose = (event) => {
|
|
29337
|
+
fail(
|
|
29338
|
+
new RelayConnectionError("relay_connection_closed", "Relay connection closed before it was ready", {
|
|
29339
|
+
closeCode: event.code.toString(),
|
|
29340
|
+
closeReason: event.reason
|
|
29341
|
+
})
|
|
29342
|
+
);
|
|
29231
29343
|
};
|
|
29232
|
-
const onError = () => {
|
|
29233
|
-
|
|
29344
|
+
const onError = (event) => {
|
|
29345
|
+
const cause = Reflect.get(event, "error");
|
|
29346
|
+
fail(
|
|
29347
|
+
new RelayConnectionError(
|
|
29348
|
+
"relay_connection_failed",
|
|
29349
|
+
"Relay connection failed",
|
|
29350
|
+
{},
|
|
29351
|
+
{ cause: cause ?? event }
|
|
29352
|
+
)
|
|
29353
|
+
);
|
|
29234
29354
|
};
|
|
29235
29355
|
const onOpen = () => {
|
|
29236
29356
|
if (finished) {
|
|
@@ -29241,7 +29361,11 @@ function connectRelay(url2, signal) {
|
|
|
29241
29361
|
resolve6(socket);
|
|
29242
29362
|
};
|
|
29243
29363
|
function onTimeout() {
|
|
29244
|
-
fail(
|
|
29364
|
+
fail(
|
|
29365
|
+
new RelayConnectionError("relay_connection_timeout", "Relay connection timed out", {
|
|
29366
|
+
timeoutMilliseconds: CONNECTION_TIMEOUT_MILLISECONDS.toString()
|
|
29367
|
+
})
|
|
29368
|
+
);
|
|
29245
29369
|
}
|
|
29246
29370
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
29247
29371
|
socket.addEventListener("close", onClose, { once: true });
|
|
@@ -29253,6 +29377,142 @@ function connectRelay(url2, signal) {
|
|
|
29253
29377
|
});
|
|
29254
29378
|
}
|
|
29255
29379
|
|
|
29380
|
+
// src/relay-connection/diagnostics.ts
|
|
29381
|
+
var MAX_DIAGNOSTIC_TEXT_LENGTH = 256;
|
|
29382
|
+
function sanitizeDiagnosticText(value) {
|
|
29383
|
+
const printable = Array.from(value, (character) => {
|
|
29384
|
+
const code = character.charCodeAt(0);
|
|
29385
|
+
return code < 32 || code === 127 ? " " : character;
|
|
29386
|
+
}).join("");
|
|
29387
|
+
const withoutSecrets = printable.replace(/([?&](?:access_token|authorization|credential|key|secret|token)=)[^&\s]*/giu, "$1[redacted]").replace(/(?:https?|wss?):\/\/[^\s)]+/giu, (encodedUrl) => {
|
|
29388
|
+
try {
|
|
29389
|
+
return new URL(encodedUrl).origin;
|
|
29390
|
+
} catch {
|
|
29391
|
+
return "[redacted-url]";
|
|
29392
|
+
}
|
|
29393
|
+
});
|
|
29394
|
+
return withoutSecrets.slice(0, MAX_DIAGNOSTIC_TEXT_LENGTH);
|
|
29395
|
+
}
|
|
29396
|
+
function addFailureDetails(details, failure) {
|
|
29397
|
+
let current = failure;
|
|
29398
|
+
for (let depth = 0; depth < 3 && current instanceof Error; depth += 1) {
|
|
29399
|
+
const prefix = depth === 0 ? "failure" : `cause${depth.toString()}`;
|
|
29400
|
+
details[`${prefix}Name`] = current.name;
|
|
29401
|
+
details[`${prefix}Message`] = sanitizeDiagnosticText(current.message);
|
|
29402
|
+
const code = Reflect.get(current, "code");
|
|
29403
|
+
if (typeof code === "string" || typeof code === "number") {
|
|
29404
|
+
details[`${prefix}Code`] = String(code);
|
|
29405
|
+
}
|
|
29406
|
+
const statusCode = Reflect.get(current, "statusCode");
|
|
29407
|
+
if (typeof statusCode === "string" || typeof statusCode === "number") {
|
|
29408
|
+
details[`${prefix}StatusCode`] = String(statusCode);
|
|
29409
|
+
}
|
|
29410
|
+
const diagnosticDetails = Reflect.get(current, "diagnosticDetails");
|
|
29411
|
+
if (typeof diagnosticDetails === "object" && diagnosticDetails !== null) {
|
|
29412
|
+
for (const [key, value] of Object.entries(diagnosticDetails)) {
|
|
29413
|
+
if (typeof value === "string") {
|
|
29414
|
+
details[key] = sanitizeDiagnosticText(value);
|
|
29415
|
+
}
|
|
29416
|
+
}
|
|
29417
|
+
}
|
|
29418
|
+
current = current.cause;
|
|
29419
|
+
}
|
|
29420
|
+
}
|
|
29421
|
+
var RelayConnectionDiagnostics = class {
|
|
29422
|
+
#audit;
|
|
29423
|
+
#channelId;
|
|
29424
|
+
#lastClosedEpoch = 0;
|
|
29425
|
+
#lastFailedEpoch = 0;
|
|
29426
|
+
#relayOrigin;
|
|
29427
|
+
#route;
|
|
29428
|
+
constructor(audit, channelId, relayUrl) {
|
|
29429
|
+
this.#audit = audit;
|
|
29430
|
+
this.#channelId = channelId;
|
|
29431
|
+
this.#relayOrigin = relayUrl.origin;
|
|
29432
|
+
this.#route = describeEnvironmentProxyRoute(relayUrl);
|
|
29433
|
+
}
|
|
29434
|
+
catalogFailed = (failure) => {
|
|
29435
|
+
const details = { ...this.#route, relayOrigin: this.#relayOrigin };
|
|
29436
|
+
addFailureDetails(details, failure);
|
|
29437
|
+
this.#record("agent_catalog_publish_failed", "catalog", details, true);
|
|
29438
|
+
};
|
|
29439
|
+
connectionClosed = (connectionEpoch, code, reason, source) => {
|
|
29440
|
+
if (this.#lastClosedEpoch === connectionEpoch) {
|
|
29441
|
+
return;
|
|
29442
|
+
}
|
|
29443
|
+
this.#lastClosedEpoch = connectionEpoch;
|
|
29444
|
+
this.#record(
|
|
29445
|
+
"relay_connection_closed",
|
|
29446
|
+
connectionEpoch.toString(),
|
|
29447
|
+
{
|
|
29448
|
+
closeCode: code.toString(),
|
|
29449
|
+
closeReason: sanitizeDiagnosticText(reason),
|
|
29450
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29451
|
+
relayOrigin: this.#relayOrigin,
|
|
29452
|
+
source,
|
|
29453
|
+
...this.#route
|
|
29454
|
+
},
|
|
29455
|
+
true
|
|
29456
|
+
);
|
|
29457
|
+
};
|
|
29458
|
+
connectionFailed = (connectionEpoch, failure, source) => {
|
|
29459
|
+
if (this.#lastFailedEpoch === connectionEpoch) {
|
|
29460
|
+
return;
|
|
29461
|
+
}
|
|
29462
|
+
this.#lastFailedEpoch = connectionEpoch;
|
|
29463
|
+
const details = {
|
|
29464
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29465
|
+
relayOrigin: this.#relayOrigin,
|
|
29466
|
+
source,
|
|
29467
|
+
...this.#route
|
|
29468
|
+
};
|
|
29469
|
+
addFailureDetails(details, failure);
|
|
29470
|
+
this.#record("relay_connection_failed", connectionEpoch.toString(), details, true);
|
|
29471
|
+
};
|
|
29472
|
+
connectionOpened = (connectionEpoch) => {
|
|
29473
|
+
this.#record(
|
|
29474
|
+
"relay_connection_opened",
|
|
29475
|
+
connectionEpoch.toString(),
|
|
29476
|
+
{
|
|
29477
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29478
|
+
relayOrigin: this.#relayOrigin,
|
|
29479
|
+
...this.#route
|
|
29480
|
+
},
|
|
29481
|
+
false
|
|
29482
|
+
);
|
|
29483
|
+
};
|
|
29484
|
+
heartbeatTimedOut = (connectionEpoch, heartbeatId, timeoutMilliseconds) => {
|
|
29485
|
+
this.#record(
|
|
29486
|
+
"relay_heartbeat_timed_out",
|
|
29487
|
+
connectionEpoch.toString(),
|
|
29488
|
+
{
|
|
29489
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29490
|
+
heartbeatId,
|
|
29491
|
+
relayOrigin: this.#relayOrigin,
|
|
29492
|
+
timeoutMilliseconds: timeoutMilliseconds.toString(),
|
|
29493
|
+
...this.#route
|
|
29494
|
+
},
|
|
29495
|
+
true
|
|
29496
|
+
);
|
|
29497
|
+
};
|
|
29498
|
+
#record = (event, commandId, details, warning) => {
|
|
29499
|
+
this.#audit.record({
|
|
29500
|
+
commandId,
|
|
29501
|
+
details,
|
|
29502
|
+
event,
|
|
29503
|
+
sessionId: this.#channelId
|
|
29504
|
+
});
|
|
29505
|
+
const encoded = JSON.stringify({ channelId: this.#channelId, event, ...details });
|
|
29506
|
+
if (warning) {
|
|
29507
|
+
process.stderr.write(`Mobius relay diagnostic ${encoded}
|
|
29508
|
+
`);
|
|
29509
|
+
return;
|
|
29510
|
+
}
|
|
29511
|
+
process.stdout.write(`Mobius relay diagnostic ${encoded}
|
|
29512
|
+
`);
|
|
29513
|
+
};
|
|
29514
|
+
};
|
|
29515
|
+
|
|
29256
29516
|
// src/relay-connection/liveness.ts
|
|
29257
29517
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
29258
29518
|
var HEARTBEAT_ACK_TIMEOUT_MILLISECONDS = 1e4;
|
|
@@ -29329,9 +29589,10 @@ var RelayConnectionLiveness = class {
|
|
|
29329
29589
|
if (!(this.#state instanceof AwaitingHeartbeatAckState)) {
|
|
29330
29590
|
throw new Error("Heartbeat timeout occurred in an invalid state");
|
|
29331
29591
|
}
|
|
29592
|
+
const heartbeatId = this.#state.heartbeatId;
|
|
29332
29593
|
this.#state.timeout.cancel();
|
|
29333
29594
|
this.#state = new FinishedRelayLivenessState();
|
|
29334
|
-
this.#transport.unresponsive();
|
|
29595
|
+
this.#transport.unresponsive(heartbeatId, HEARTBEAT_ACK_TIMEOUT_MILLISECONDS);
|
|
29335
29596
|
};
|
|
29336
29597
|
#sendHeartbeat = () => {
|
|
29337
29598
|
if (this.#state instanceof WaitingForHeartbeatState) {
|
|
@@ -29360,6 +29621,42 @@ var RelayConnectionLiveness = class {
|
|
|
29360
29621
|
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
29361
29622
|
import { dirname as dirname7 } from "node:path";
|
|
29362
29623
|
import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
|
|
29624
|
+
var DEFAULT_OUTBOX_LIMITS = {
|
|
29625
|
+
criticalEventBytes: 136 * 1024 * 1024,
|
|
29626
|
+
criticalEventCount: 10128,
|
|
29627
|
+
runtimeDeliveryBytes: 64 * 1024 * 1024,
|
|
29628
|
+
runtimeDeliveryCount: 64,
|
|
29629
|
+
standardEventBytes: 128 * 1024 * 1024,
|
|
29630
|
+
standardEventCount: 1e4
|
|
29631
|
+
};
|
|
29632
|
+
var SessionEventOutboxCapacityError = class extends Error {
|
|
29633
|
+
code = "session_event_outbox_full";
|
|
29634
|
+
constructor() {
|
|
29635
|
+
super("The durable Session event outbox is full");
|
|
29636
|
+
this.name = "SessionEventOutboxCapacityError";
|
|
29637
|
+
}
|
|
29638
|
+
};
|
|
29639
|
+
var RuntimeDeliveryInboxCapacityError = class extends Error {
|
|
29640
|
+
code = "runtime_delivery_inbox_full";
|
|
29641
|
+
constructor() {
|
|
29642
|
+
super("The durable Runtime delivery inbox is full");
|
|
29643
|
+
this.name = "RuntimeDeliveryInboxCapacityError";
|
|
29644
|
+
}
|
|
29645
|
+
};
|
|
29646
|
+
var StoredRuntimeDelivery = class {
|
|
29647
|
+
deliveryId;
|
|
29648
|
+
duplicate;
|
|
29649
|
+
payload;
|
|
29650
|
+
sessionId;
|
|
29651
|
+
state;
|
|
29652
|
+
constructor(deliveryId, sessionId, payload, state, duplicate) {
|
|
29653
|
+
this.deliveryId = deliveryId;
|
|
29654
|
+
this.duplicate = duplicate;
|
|
29655
|
+
this.payload = payload;
|
|
29656
|
+
this.sessionId = sessionId;
|
|
29657
|
+
this.state = state;
|
|
29658
|
+
}
|
|
29659
|
+
};
|
|
29363
29660
|
function readPendingEnvelope(row) {
|
|
29364
29661
|
if (typeof row !== "object" || row === null || Array.isArray(row)) {
|
|
29365
29662
|
throw new Error("SQLite returned an invalid session event outbox row");
|
|
@@ -29370,9 +29667,26 @@ function readPendingEnvelope(row) {
|
|
|
29370
29667
|
}
|
|
29371
29668
|
return envelope2;
|
|
29372
29669
|
}
|
|
29670
|
+
function rowNumber(row, field) {
|
|
29671
|
+
const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
|
|
29672
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
29673
|
+
throw new Error(`SQLite returned an invalid ${field} value`);
|
|
29674
|
+
}
|
|
29675
|
+
return value;
|
|
29676
|
+
}
|
|
29677
|
+
function rowString2(row, field) {
|
|
29678
|
+
const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
|
|
29679
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
29680
|
+
throw new Error(`SQLite returned an invalid ${field} value`);
|
|
29681
|
+
}
|
|
29682
|
+
return value;
|
|
29683
|
+
}
|
|
29373
29684
|
var SessionEventOutbox = class {
|
|
29374
29685
|
#database;
|
|
29375
|
-
|
|
29686
|
+
#limits;
|
|
29687
|
+
constructor(path2, limits = DEFAULT_OUTBOX_LIMITS) {
|
|
29688
|
+
validateLimits(limits);
|
|
29689
|
+
this.#limits = limits;
|
|
29376
29690
|
mkdirSync3(dirname7(path2), { recursive: true });
|
|
29377
29691
|
this.#database = new DatabaseSync4(path2);
|
|
29378
29692
|
this.#database.exec(`
|
|
@@ -29380,6 +29694,8 @@ var SessionEventOutbox = class {
|
|
|
29380
29694
|
ordinal INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
29381
29695
|
event_id TEXT NOT NULL UNIQUE,
|
|
29382
29696
|
session_id TEXT NOT NULL,
|
|
29697
|
+
source_key TEXT NOT NULL,
|
|
29698
|
+
byte_length INTEGER NOT NULL,
|
|
29383
29699
|
envelope_json TEXT NOT NULL
|
|
29384
29700
|
) STRICT;
|
|
29385
29701
|
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
|
|
@@ -29390,7 +29706,7 @@ var SessionEventOutbox = class {
|
|
|
29390
29706
|
session_id TEXT NOT NULL,
|
|
29391
29707
|
envelope_json TEXT NOT NULL,
|
|
29392
29708
|
rejection_code TEXT NOT NULL CHECK (
|
|
29393
|
-
rejection_code IN ('session_deleted', 'session_not_found')
|
|
29709
|
+
rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
|
|
29394
29710
|
)
|
|
29395
29711
|
) STRICT;
|
|
29396
29712
|
CREATE TABLE IF NOT EXISTS relay_session_event_sources (
|
|
@@ -29406,6 +29722,92 @@ var SessionEventOutbox = class {
|
|
|
29406
29722
|
state IN ('dispatching', 'running', 'succeeded', 'failed', 'cancelled')
|
|
29407
29723
|
)
|
|
29408
29724
|
) STRICT;
|
|
29725
|
+
CREATE TABLE IF NOT EXISTS relay_session_event_outbox_state (
|
|
29726
|
+
singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
|
|
29727
|
+
event_count INTEGER NOT NULL,
|
|
29728
|
+
total_bytes INTEGER NOT NULL
|
|
29729
|
+
) STRICT;
|
|
29730
|
+
INSERT OR IGNORE INTO relay_session_event_outbox_state (
|
|
29731
|
+
singleton, event_count, total_bytes
|
|
29732
|
+
) VALUES (1, 0, 0);
|
|
29733
|
+
CREATE TABLE IF NOT EXISTS relay_runtime_deliveries (
|
|
29734
|
+
delivery_id TEXT PRIMARY KEY,
|
|
29735
|
+
session_id TEXT NOT NULL,
|
|
29736
|
+
payload_json TEXT NOT NULL,
|
|
29737
|
+
payload_bytes INTEGER NOT NULL,
|
|
29738
|
+
state TEXT NOT NULL CHECK (
|
|
29739
|
+
state IN ('received', 'relay_committed', 'processed')
|
|
29740
|
+
),
|
|
29741
|
+
received_at INTEGER NOT NULL
|
|
29742
|
+
) STRICT;
|
|
29743
|
+
`);
|
|
29744
|
+
const deadLetterTable = this.#database.prepare(
|
|
29745
|
+
`SELECT sql FROM sqlite_master
|
|
29746
|
+
WHERE type = 'table' AND name = 'relay_session_event_dead_letters'`
|
|
29747
|
+
).get();
|
|
29748
|
+
const deadLetterSql = typeof deadLetterTable === "object" && deadLetterTable !== null ? Reflect.get(deadLetterTable, "sql") : void 0;
|
|
29749
|
+
if (typeof deadLetterSql !== "string" || !deadLetterSql.includes("'session_rejected'")) {
|
|
29750
|
+
this.#database.exec(`
|
|
29751
|
+
BEGIN IMMEDIATE;
|
|
29752
|
+
ALTER TABLE relay_session_event_dead_letters
|
|
29753
|
+
RENAME TO relay_session_event_dead_letters_legacy;
|
|
29754
|
+
CREATE TABLE relay_session_event_dead_letters (
|
|
29755
|
+
ordinal INTEGER PRIMARY KEY,
|
|
29756
|
+
event_id TEXT NOT NULL UNIQUE,
|
|
29757
|
+
session_id TEXT NOT NULL,
|
|
29758
|
+
envelope_json TEXT NOT NULL,
|
|
29759
|
+
rejection_code TEXT NOT NULL CHECK (
|
|
29760
|
+
rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
|
|
29761
|
+
)
|
|
29762
|
+
) STRICT;
|
|
29763
|
+
INSERT INTO relay_session_event_dead_letters (
|
|
29764
|
+
ordinal, event_id, session_id, envelope_json, rejection_code
|
|
29765
|
+
)
|
|
29766
|
+
SELECT ordinal, event_id, session_id, envelope_json, rejection_code
|
|
29767
|
+
FROM relay_session_event_dead_letters_legacy;
|
|
29768
|
+
DROP TABLE relay_session_event_dead_letters_legacy;
|
|
29769
|
+
COMMIT;
|
|
29770
|
+
`);
|
|
29771
|
+
}
|
|
29772
|
+
const outboxColumns = this.#database.prepare("PRAGMA table_info(relay_session_event_outbox)").all();
|
|
29773
|
+
const hasSourceKey = outboxColumns.some(
|
|
29774
|
+
(column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "source_key"
|
|
29775
|
+
);
|
|
29776
|
+
if (!hasSourceKey) {
|
|
29777
|
+
this.#database.exec(`
|
|
29778
|
+
ALTER TABLE relay_session_event_outbox
|
|
29779
|
+
ADD COLUMN source_key TEXT NOT NULL DEFAULT '';
|
|
29780
|
+
`);
|
|
29781
|
+
}
|
|
29782
|
+
const hasByteLength = outboxColumns.some(
|
|
29783
|
+
(column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "byte_length"
|
|
29784
|
+
);
|
|
29785
|
+
if (!hasByteLength) {
|
|
29786
|
+
this.#database.exec(`
|
|
29787
|
+
ALTER TABLE relay_session_event_outbox
|
|
29788
|
+
ADD COLUMN byte_length INTEGER NOT NULL DEFAULT 0;
|
|
29789
|
+
`);
|
|
29790
|
+
}
|
|
29791
|
+
this.#database.exec(`
|
|
29792
|
+
UPDATE relay_session_event_outbox
|
|
29793
|
+
SET source_key = CASE json_extract(envelope_json, '$.source.kind')
|
|
29794
|
+
WHEN 'attempt' THEN
|
|
29795
|
+
'attempt:' || session_id || ':' || json_extract(envelope_json, '$.source.attemptId')
|
|
29796
|
+
ELSE 'runtime:' || session_id
|
|
29797
|
+
END
|
|
29798
|
+
WHERE source_key = '';
|
|
29799
|
+
UPDATE relay_session_event_outbox
|
|
29800
|
+
SET byte_length = length(CAST(envelope_json AS BLOB))
|
|
29801
|
+
WHERE byte_length = 0;
|
|
29802
|
+
UPDATE relay_session_event_outbox_state
|
|
29803
|
+
SET event_count = (SELECT COUNT(*) FROM relay_session_event_outbox),
|
|
29804
|
+
total_bytes = (
|
|
29805
|
+
SELECT COALESCE(SUM(byte_length), 0)
|
|
29806
|
+
FROM relay_session_event_outbox
|
|
29807
|
+
)
|
|
29808
|
+
WHERE singleton = 1;
|
|
29809
|
+
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_source_order
|
|
29810
|
+
ON relay_session_event_outbox(source_key, ordinal);
|
|
29409
29811
|
`);
|
|
29410
29812
|
}
|
|
29411
29813
|
claimExecution = (commandId, sessionId, commandJson) => {
|
|
@@ -29464,15 +29866,19 @@ var SessionEventOutbox = class {
|
|
|
29464
29866
|
const state = typeof row === "object" && row !== null ? Reflect.get(row, "state") : void 0;
|
|
29465
29867
|
return state === "succeeded" || state === "failed" || state === "cancelled";
|
|
29466
29868
|
};
|
|
29467
|
-
acknowledge = (acknowledgement) =>
|
|
29468
|
-
this.#database.prepare(
|
|
29469
|
-
`DELETE FROM relay_session_event_outbox
|
|
29470
|
-
WHERE event_id = ? AND session_id = ?`
|
|
29471
|
-
).run(acknowledgement.eventId, acknowledgement.sessionId);
|
|
29472
|
-
};
|
|
29869
|
+
acknowledge = (acknowledgement) => this.#removeAcknowledgedEvent(acknowledgement.eventId, acknowledgement.sessionId);
|
|
29473
29870
|
quarantine = (rejection) => {
|
|
29474
29871
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
29475
29872
|
try {
|
|
29873
|
+
const stored = this.#database.prepare(
|
|
29874
|
+
`SELECT byte_length FROM relay_session_event_outbox
|
|
29875
|
+
WHERE event_id = ? AND session_id = ?`
|
|
29876
|
+
).get(rejection.eventId, rejection.sessionId);
|
|
29877
|
+
if (stored === void 0) {
|
|
29878
|
+
this.#database.exec("COMMIT");
|
|
29879
|
+
return false;
|
|
29880
|
+
}
|
|
29881
|
+
const byteLength = rowNumber(stored, "byte_length");
|
|
29476
29882
|
const insertion = this.#database.prepare(
|
|
29477
29883
|
`INSERT INTO relay_session_event_dead_letters (
|
|
29478
29884
|
ordinal, event_id, session_id, envelope_json, rejection_code
|
|
@@ -29492,6 +29898,7 @@ var SessionEventOutbox = class {
|
|
|
29492
29898
|
if (deletion.changes !== 1) {
|
|
29493
29899
|
throw new Error("The rejected session event could not be removed from the durable outbox");
|
|
29494
29900
|
}
|
|
29901
|
+
this.#decrementEventState(byteLength);
|
|
29495
29902
|
this.#database.exec("COMMIT");
|
|
29496
29903
|
return true;
|
|
29497
29904
|
} catch (error61) {
|
|
@@ -29503,7 +29910,129 @@ var SessionEventOutbox = class {
|
|
|
29503
29910
|
this.#database.close();
|
|
29504
29911
|
};
|
|
29505
29912
|
enqueue = (sessionId, payload, attemptId = null) => {
|
|
29506
|
-
|
|
29913
|
+
return this.#enqueueBounded(
|
|
29914
|
+
sessionId,
|
|
29915
|
+
payload,
|
|
29916
|
+
attemptId ?? "",
|
|
29917
|
+
this.#limits.standardEventCount,
|
|
29918
|
+
this.#limits.standardEventBytes
|
|
29919
|
+
);
|
|
29920
|
+
};
|
|
29921
|
+
enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(
|
|
29922
|
+
sessionId,
|
|
29923
|
+
payload,
|
|
29924
|
+
attemptId,
|
|
29925
|
+
this.#limits.criticalEventCount,
|
|
29926
|
+
this.#limits.criticalEventBytes
|
|
29927
|
+
);
|
|
29928
|
+
claimRuntimeDelivery = (delivery) => {
|
|
29929
|
+
const payloadBytes = new TextEncoder().encode(delivery.payload).byteLength;
|
|
29930
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
29931
|
+
try {
|
|
29932
|
+
const existing = this.#database.prepare(
|
|
29933
|
+
`SELECT session_id, payload_json, state
|
|
29934
|
+
FROM relay_runtime_deliveries
|
|
29935
|
+
WHERE delivery_id = ?`
|
|
29936
|
+
).get(delivery.deliveryId);
|
|
29937
|
+
if (existing !== void 0) {
|
|
29938
|
+
const sessionId = rowString2(existing, "session_id");
|
|
29939
|
+
const payload = rowString2(existing, "payload_json");
|
|
29940
|
+
const state = runtimeDeliveryState(existing);
|
|
29941
|
+
if (sessionId !== delivery.sessionId || payload !== delivery.payload) {
|
|
29942
|
+
throw new Error("The Runtime delivery identity conflicts with its durable receipt");
|
|
29943
|
+
}
|
|
29944
|
+
this.#database.exec("COMMIT");
|
|
29945
|
+
return new StoredRuntimeDelivery(delivery.deliveryId, sessionId, payload, state, true);
|
|
29946
|
+
}
|
|
29947
|
+
const usage = this.#database.prepare(
|
|
29948
|
+
`SELECT COUNT(*) AS delivery_count,
|
|
29949
|
+
COALESCE(SUM(payload_bytes), 0) AS delivery_bytes
|
|
29950
|
+
FROM relay_runtime_deliveries`
|
|
29951
|
+
).get();
|
|
29952
|
+
if (rowNumber(usage, "delivery_count") + 1 > this.#limits.runtimeDeliveryCount || rowNumber(usage, "delivery_bytes") + payloadBytes > this.#limits.runtimeDeliveryBytes) {
|
|
29953
|
+
throw new RuntimeDeliveryInboxCapacityError();
|
|
29954
|
+
}
|
|
29955
|
+
this.#database.prepare(
|
|
29956
|
+
`INSERT INTO relay_runtime_deliveries (
|
|
29957
|
+
delivery_id, session_id, payload_json, payload_bytes, state, received_at
|
|
29958
|
+
) VALUES (?, ?, ?, ?, 'received', ?)`
|
|
29959
|
+
).run(delivery.deliveryId, delivery.sessionId, delivery.payload, payloadBytes, Date.now());
|
|
29960
|
+
this.#database.exec("COMMIT");
|
|
29961
|
+
return new StoredRuntimeDelivery(
|
|
29962
|
+
delivery.deliveryId,
|
|
29963
|
+
delivery.sessionId,
|
|
29964
|
+
delivery.payload,
|
|
29965
|
+
"received",
|
|
29966
|
+
false
|
|
29967
|
+
);
|
|
29968
|
+
} catch (error61) {
|
|
29969
|
+
this.#database.exec("ROLLBACK");
|
|
29970
|
+
throw error61;
|
|
29971
|
+
}
|
|
29972
|
+
};
|
|
29973
|
+
markRuntimeDeliveryCommitted = (deliveryId, sessionId) => {
|
|
29974
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
29975
|
+
try {
|
|
29976
|
+
const row = this.#database.prepare(
|
|
29977
|
+
`SELECT state FROM relay_runtime_deliveries
|
|
29978
|
+
WHERE delivery_id = ? AND session_id = ?`
|
|
29979
|
+
).get(deliveryId, sessionId);
|
|
29980
|
+
if (row === void 0) {
|
|
29981
|
+
this.#database.exec("COMMIT");
|
|
29982
|
+
return false;
|
|
29983
|
+
}
|
|
29984
|
+
const state = runtimeDeliveryState(row);
|
|
29985
|
+
if (state === "processed") {
|
|
29986
|
+
this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
|
|
29987
|
+
} else if (state === "received") {
|
|
29988
|
+
this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'relay_committed' WHERE delivery_id = ?`).run(deliveryId);
|
|
29989
|
+
}
|
|
29990
|
+
this.#database.exec("COMMIT");
|
|
29991
|
+
return true;
|
|
29992
|
+
} catch (error61) {
|
|
29993
|
+
this.#database.exec("ROLLBACK");
|
|
29994
|
+
throw error61;
|
|
29995
|
+
}
|
|
29996
|
+
};
|
|
29997
|
+
markRuntimeDeliveryProcessed = (deliveryId, sessionId) => {
|
|
29998
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
29999
|
+
try {
|
|
30000
|
+
const row = this.#database.prepare(
|
|
30001
|
+
`SELECT state FROM relay_runtime_deliveries
|
|
30002
|
+
WHERE delivery_id = ? AND session_id = ?`
|
|
30003
|
+
).get(deliveryId, sessionId);
|
|
30004
|
+
if (row === void 0) {
|
|
30005
|
+
this.#database.exec("COMMIT");
|
|
30006
|
+
return false;
|
|
30007
|
+
}
|
|
30008
|
+
const state = runtimeDeliveryState(row);
|
|
30009
|
+
if (state === "relay_committed") {
|
|
30010
|
+
this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
|
|
30011
|
+
} else if (state === "received") {
|
|
30012
|
+
this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'processed' WHERE delivery_id = ?`).run(deliveryId);
|
|
30013
|
+
}
|
|
30014
|
+
this.#database.exec("COMMIT");
|
|
30015
|
+
return true;
|
|
30016
|
+
} catch (error61) {
|
|
30017
|
+
this.#database.exec("ROLLBACK");
|
|
30018
|
+
throw error61;
|
|
30019
|
+
}
|
|
30020
|
+
};
|
|
30021
|
+
runtimeDeliveries = () => this.#database.prepare(
|
|
30022
|
+
`SELECT delivery_id, session_id, payload_json, state
|
|
30023
|
+
FROM relay_runtime_deliveries
|
|
30024
|
+
ORDER BY received_at, delivery_id`
|
|
30025
|
+
).all().map(
|
|
30026
|
+
(row) => new StoredRuntimeDelivery(
|
|
30027
|
+
rowString2(row, "delivery_id"),
|
|
30028
|
+
rowString2(row, "session_id"),
|
|
30029
|
+
rowString2(row, "payload_json"),
|
|
30030
|
+
runtimeDeliveryState(row),
|
|
30031
|
+
true
|
|
30032
|
+
)
|
|
30033
|
+
);
|
|
30034
|
+
#enqueueBounded = (sessionId, payload, attemptId, maximumEventCount, maximumEventBytes) => {
|
|
30035
|
+
const sourceKey = attemptId.length === 0 ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
|
|
29507
30036
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
29508
30037
|
try {
|
|
29509
30038
|
const row = this.#database.prepare(
|
|
@@ -29520,13 +30049,22 @@ var SessionEventOutbox = class {
|
|
|
29520
30049
|
kind: SESSION_EVENT_KIND,
|
|
29521
30050
|
payload,
|
|
29522
30051
|
sessionId,
|
|
29523
|
-
source: attemptId ===
|
|
30052
|
+
source: attemptId.length === 0 ? { kind: "runtime", sourceSeq: nextSourceSeq.toString() } : {
|
|
29524
30053
|
attemptId,
|
|
29525
30054
|
kind: "attempt",
|
|
29526
30055
|
sourceSeq: nextSourceSeq.toString()
|
|
29527
30056
|
}
|
|
29528
30057
|
};
|
|
29529
30058
|
const encoded = encodeSessionEventEnvelope(envelope2);
|
|
30059
|
+
const byteLength = new TextEncoder().encode(encoded).byteLength;
|
|
30060
|
+
const state = this.#database.prepare(
|
|
30061
|
+
`SELECT event_count, total_bytes
|
|
30062
|
+
FROM relay_session_event_outbox_state
|
|
30063
|
+
WHERE singleton = 1`
|
|
30064
|
+
).get();
|
|
30065
|
+
if (rowNumber(state, "event_count") + 1 > maximumEventCount || rowNumber(state, "total_bytes") + byteLength > maximumEventBytes) {
|
|
30066
|
+
throw new SessionEventOutboxCapacityError();
|
|
30067
|
+
}
|
|
29530
30068
|
this.#database.prepare(
|
|
29531
30069
|
`INSERT INTO relay_session_event_sources (
|
|
29532
30070
|
source_key, next_source_seq
|
|
@@ -29536,9 +30074,15 @@ var SessionEventOutbox = class {
|
|
|
29536
30074
|
).run(sourceKey, nextSourceSeq + 1);
|
|
29537
30075
|
this.#database.prepare(
|
|
29538
30076
|
`INSERT INTO relay_session_event_outbox (
|
|
29539
|
-
event_id, session_id, envelope_json
|
|
29540
|
-
) VALUES (?, ?, ?)`
|
|
29541
|
-
).run(envelope2.eventId, envelope2.sessionId, encoded);
|
|
30077
|
+
event_id, session_id, source_key, byte_length, envelope_json
|
|
30078
|
+
) VALUES (?, ?, ?, ?, ?)`
|
|
30079
|
+
).run(envelope2.eventId, envelope2.sessionId, sourceKey, byteLength, encoded);
|
|
30080
|
+
this.#database.prepare(
|
|
30081
|
+
`UPDATE relay_session_event_outbox_state
|
|
30082
|
+
SET event_count = event_count + 1,
|
|
30083
|
+
total_bytes = total_bytes + ?
|
|
30084
|
+
WHERE singleton = 1`
|
|
30085
|
+
).run(byteLength);
|
|
29542
30086
|
this.#database.exec("COMMIT");
|
|
29543
30087
|
return encoded;
|
|
29544
30088
|
} catch (error61) {
|
|
@@ -29546,12 +30090,132 @@ var SessionEventOutbox = class {
|
|
|
29546
30090
|
throw error61;
|
|
29547
30091
|
}
|
|
29548
30092
|
};
|
|
30093
|
+
#removeAcknowledgedEvent = (eventId, sessionId) => {
|
|
30094
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
30095
|
+
try {
|
|
30096
|
+
const stored = this.#database.prepare(
|
|
30097
|
+
`SELECT byte_length FROM relay_session_event_outbox
|
|
30098
|
+
WHERE event_id = ? AND session_id = ?`
|
|
30099
|
+
).get(eventId, sessionId);
|
|
30100
|
+
if (stored === void 0) {
|
|
30101
|
+
this.#database.exec("COMMIT");
|
|
30102
|
+
return false;
|
|
30103
|
+
}
|
|
30104
|
+
const byteLength = rowNumber(stored, "byte_length");
|
|
30105
|
+
const deletion = this.#database.prepare(
|
|
30106
|
+
`DELETE FROM relay_session_event_outbox
|
|
30107
|
+
WHERE event_id = ? AND session_id = ?`
|
|
30108
|
+
).run(eventId, sessionId);
|
|
30109
|
+
if (deletion.changes !== 1) {
|
|
30110
|
+
throw new Error("The acknowledged session event could not be removed from the durable outbox");
|
|
30111
|
+
}
|
|
30112
|
+
this.#decrementEventState(byteLength);
|
|
30113
|
+
this.#database.exec("COMMIT");
|
|
30114
|
+
return true;
|
|
30115
|
+
} catch (error61) {
|
|
30116
|
+
this.#database.exec("ROLLBACK");
|
|
30117
|
+
throw error61;
|
|
30118
|
+
}
|
|
30119
|
+
};
|
|
30120
|
+
#decrementEventState = (byteLength) => {
|
|
30121
|
+
const result = this.#database.prepare(
|
|
30122
|
+
`UPDATE relay_session_event_outbox_state
|
|
30123
|
+
SET event_count = event_count - 1,
|
|
30124
|
+
total_bytes = total_bytes - ?
|
|
30125
|
+
WHERE singleton = 1 AND event_count > 0 AND total_bytes >= ?`
|
|
30126
|
+
).run(byteLength, byteLength);
|
|
30127
|
+
if (result.changes !== 1) {
|
|
30128
|
+
throw new Error("The Session event outbox capacity state is inconsistent");
|
|
30129
|
+
}
|
|
30130
|
+
};
|
|
29549
30131
|
pending = () => this.#database.prepare(
|
|
29550
30132
|
`SELECT envelope_json
|
|
29551
30133
|
FROM relay_session_event_outbox
|
|
29552
30134
|
ORDER BY ordinal`
|
|
29553
30135
|
).all().map(readPendingEnvelope);
|
|
29554
|
-
|
|
30136
|
+
pendingBatch = (limit) => {
|
|
30137
|
+
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
30138
|
+
throw new Error("Session event replay batch limit must be a positive integer");
|
|
30139
|
+
}
|
|
30140
|
+
return this.#database.prepare(
|
|
30141
|
+
`WITH ranked_events AS (
|
|
30142
|
+
SELECT ordinal,
|
|
30143
|
+
ROW_NUMBER() OVER (
|
|
30144
|
+
PARTITION BY source_key
|
|
30145
|
+
ORDER BY ordinal
|
|
30146
|
+
) AS source_position
|
|
30147
|
+
FROM relay_session_event_outbox
|
|
30148
|
+
)
|
|
30149
|
+
SELECT outbox.envelope_json
|
|
30150
|
+
FROM ranked_events AS ranked
|
|
30151
|
+
INNER JOIN relay_session_event_outbox AS outbox
|
|
30152
|
+
ON outbox.ordinal = ranked.ordinal
|
|
30153
|
+
ORDER BY ranked.source_position, outbox.ordinal
|
|
30154
|
+
LIMIT ?`
|
|
30155
|
+
).all(limit).map(readPendingEnvelope);
|
|
30156
|
+
};
|
|
30157
|
+
pendingSourceHeads = (limit, excludedEventIds, excludedSourceKeys) => {
|
|
30158
|
+
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
30159
|
+
throw new Error("Session event replay batch limit must be a positive integer");
|
|
30160
|
+
}
|
|
30161
|
+
const exclusions = [];
|
|
30162
|
+
const parameters = [];
|
|
30163
|
+
if (excludedEventIds.length > 0) {
|
|
30164
|
+
exclusions.push(`event_id NOT IN (${excludedEventIds.map(() => "?").join(", ")})`);
|
|
30165
|
+
parameters.push(...excludedEventIds);
|
|
30166
|
+
}
|
|
30167
|
+
if (excludedSourceKeys.length > 0) {
|
|
30168
|
+
exclusions.push(`source_key NOT IN (${excludedSourceKeys.map(() => "?").join(", ")})`);
|
|
30169
|
+
parameters.push(...excludedSourceKeys);
|
|
30170
|
+
}
|
|
30171
|
+
parameters.push(limit.toString());
|
|
30172
|
+
const where = exclusions.length === 0 ? "" : `WHERE ${exclusions.join(" AND ")}`;
|
|
30173
|
+
return this.#database.prepare(
|
|
30174
|
+
`WITH available_events AS (
|
|
30175
|
+
SELECT ordinal, source_key
|
|
30176
|
+
FROM relay_session_event_outbox
|
|
30177
|
+
${where}
|
|
30178
|
+
), ranked_events AS (
|
|
30179
|
+
SELECT ordinal,
|
|
30180
|
+
ROW_NUMBER() OVER (
|
|
30181
|
+
PARTITION BY source_key
|
|
30182
|
+
ORDER BY ordinal
|
|
30183
|
+
) AS source_position
|
|
30184
|
+
FROM available_events
|
|
30185
|
+
)
|
|
30186
|
+
SELECT outbox.envelope_json
|
|
30187
|
+
FROM ranked_events AS ranked
|
|
30188
|
+
INNER JOIN relay_session_event_outbox AS outbox
|
|
30189
|
+
ON outbox.ordinal = ranked.ordinal
|
|
30190
|
+
WHERE ranked.source_position = 1
|
|
30191
|
+
ORDER BY outbox.ordinal
|
|
30192
|
+
LIMIT ?`
|
|
30193
|
+
).all(...parameters).map(readPendingEnvelope);
|
|
30194
|
+
};
|
|
30195
|
+
};
|
|
30196
|
+
function validateLimits(limits) {
|
|
30197
|
+
const values = [
|
|
30198
|
+
limits.criticalEventBytes,
|
|
30199
|
+
limits.criticalEventCount,
|
|
30200
|
+
limits.runtimeDeliveryBytes,
|
|
30201
|
+
limits.runtimeDeliveryCount,
|
|
30202
|
+
limits.standardEventBytes,
|
|
30203
|
+
limits.standardEventCount
|
|
30204
|
+
];
|
|
30205
|
+
if (values.some((value) => !Number.isSafeInteger(value) || value < 1)) {
|
|
30206
|
+
throw new Error("Session event outbox limits must be positive integers");
|
|
30207
|
+
}
|
|
30208
|
+
if (limits.criticalEventBytes < limits.standardEventBytes || limits.criticalEventCount < limits.standardEventCount) {
|
|
30209
|
+
throw new Error("Critical Session event capacity must include the standard capacity");
|
|
30210
|
+
}
|
|
30211
|
+
}
|
|
30212
|
+
function runtimeDeliveryState(row) {
|
|
30213
|
+
const state = rowString2(row, "state");
|
|
30214
|
+
if (state !== "received" && state !== "relay_committed" && state !== "processed") {
|
|
30215
|
+
throw new Error("SQLite returned an invalid Runtime delivery state");
|
|
30216
|
+
}
|
|
30217
|
+
return state;
|
|
30218
|
+
}
|
|
29555
30219
|
function isDaemonExecutionState(value) {
|
|
29556
30220
|
return value === "cancelled" || value === "dispatching" || value === "failed" || value === "running" || value === "succeeded";
|
|
29557
30221
|
}
|
|
@@ -29567,7 +30231,7 @@ var systemDaemonTimer = new SystemDaemonTimer();
|
|
|
29567
30231
|
|
|
29568
30232
|
// src/run-daemon.ts
|
|
29569
30233
|
var RELAY_RECONNECT_DELAY_MILLISECONDS = 500;
|
|
29570
|
-
var
|
|
30234
|
+
var AGENT_ACTIVITY_COALESCING_MILLISECONDS = 100;
|
|
29571
30235
|
var ACTIVE_TURN_RECONCILIATION_TIMEOUT_MILLISECONDS = 2e4;
|
|
29572
30236
|
var ACTIVE_TURN_RECONCILIATION_CLOSE_CODE = 4009;
|
|
29573
30237
|
function botIpcSocketPath() {
|
|
@@ -29576,54 +30240,6 @@ function botIpcSocketPath() {
|
|
|
29576
30240
|
}
|
|
29577
30241
|
return join16("/tmp", `mobius-bot-${randomUUID6()}.sock`);
|
|
29578
30242
|
}
|
|
29579
|
-
var RelayConnectionRefreshState = class {
|
|
29580
|
-
};
|
|
29581
|
-
var ScheduledRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29582
|
-
};
|
|
29583
|
-
var DueRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29584
|
-
};
|
|
29585
|
-
var FinishedRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29586
|
-
};
|
|
29587
|
-
var RelayConnectionRefresh = class {
|
|
29588
|
-
#isSafe;
|
|
29589
|
-
#refresh;
|
|
29590
|
-
#scheduledTask;
|
|
29591
|
-
#state = new ScheduledRelayConnectionRefreshState();
|
|
29592
|
-
constructor(timer, isSafe, refresh) {
|
|
29593
|
-
this.#isSafe = isSafe;
|
|
29594
|
-
this.#refresh = refresh;
|
|
29595
|
-
this.#scheduledTask = timer.schedule(this.#request, RELAY_CONNECTION_REFRESH_MILLISECONDS);
|
|
29596
|
-
}
|
|
29597
|
-
afterTurnFinished = () => {
|
|
29598
|
-
if (this.#state instanceof DueRelayConnectionRefreshState) {
|
|
29599
|
-
this.#request();
|
|
29600
|
-
return;
|
|
29601
|
-
}
|
|
29602
|
-
if (this.#state instanceof ScheduledRelayConnectionRefreshState || this.#state instanceof FinishedRelayConnectionRefreshState) {
|
|
29603
|
-
return;
|
|
29604
|
-
}
|
|
29605
|
-
throw new Error("Unknown relay connection refresh state");
|
|
29606
|
-
};
|
|
29607
|
-
close = () => {
|
|
29608
|
-
this.#scheduledTask.cancel();
|
|
29609
|
-
this.#state = new FinishedRelayConnectionRefreshState();
|
|
29610
|
-
};
|
|
29611
|
-
#request = () => {
|
|
29612
|
-
if (this.#state instanceof FinishedRelayConnectionRefreshState) {
|
|
29613
|
-
return;
|
|
29614
|
-
}
|
|
29615
|
-
if (!(this.#state instanceof ScheduledRelayConnectionRefreshState) && !(this.#state instanceof DueRelayConnectionRefreshState)) {
|
|
29616
|
-
throw new Error("Unknown relay connection refresh state");
|
|
29617
|
-
}
|
|
29618
|
-
if (!this.#isSafe()) {
|
|
29619
|
-
this.#state = new DueRelayConnectionRefreshState();
|
|
29620
|
-
return;
|
|
29621
|
-
}
|
|
29622
|
-
this.#state = new FinishedRelayConnectionRefreshState();
|
|
29623
|
-
this.#scheduledTask.cancel();
|
|
29624
|
-
this.#refresh();
|
|
29625
|
-
};
|
|
29626
|
-
};
|
|
29627
30243
|
var DaemonAcpObserver = class {
|
|
29628
30244
|
#record;
|
|
29629
30245
|
constructor(record2) {
|
|
@@ -29818,8 +30434,7 @@ var ActiveTurnReconciliationError = class extends Error {
|
|
|
29818
30434
|
}
|
|
29819
30435
|
};
|
|
29820
30436
|
function activeTurnReconciliationEndpoint(config2, turn) {
|
|
29821
|
-
const endpoint =
|
|
29822
|
-
endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
|
|
30437
|
+
const endpoint = relayHttpEndpoint(config2.relayUrl);
|
|
29823
30438
|
let channelPath = "";
|
|
29824
30439
|
if (endpoint.pathname.endsWith("/daemon")) {
|
|
29825
30440
|
channelPath = endpoint.pathname.slice(0, -"/daemon".length);
|
|
@@ -29831,7 +30446,6 @@ function activeTurnReconciliationEndpoint(config2, turn) {
|
|
|
29831
30446
|
channelPath = `${endpoint.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
|
|
29832
30447
|
}
|
|
29833
30448
|
endpoint.pathname = `${channelPath}/sessions/${encodeURIComponent(turn.command.sessionId)}/attempts/${encodeURIComponent(turn.attemptId)}/reconciliation`;
|
|
29834
|
-
endpoint.searchParams.delete("liveness");
|
|
29835
30449
|
return endpoint;
|
|
29836
30450
|
}
|
|
29837
30451
|
async function reconcileActiveTurn(config2, turn, signal) {
|
|
@@ -29843,7 +30457,7 @@ async function reconcileActiveTurn(config2, turn, signal) {
|
|
|
29843
30457
|
response = await fetch6(activeTurnReconciliationEndpoint(config2, turn), {
|
|
29844
30458
|
body: JSON.stringify({ outcome: { kind: "running" } }),
|
|
29845
30459
|
dispatcher: environmentProxyDispatcher,
|
|
29846
|
-
headers: { "content-type": "application/json" },
|
|
30460
|
+
headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
|
|
29847
30461
|
method: "POST",
|
|
29848
30462
|
signal: requestSignal
|
|
29849
30463
|
});
|
|
@@ -29888,7 +30502,8 @@ var DaemonSessionEventConnectionState = class {
|
|
|
29888
30502
|
};
|
|
29889
30503
|
var DisconnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
|
|
29890
30504
|
disconnect = () => this;
|
|
29891
|
-
|
|
30505
|
+
matches = () => false;
|
|
30506
|
+
send = () => false;
|
|
29892
30507
|
};
|
|
29893
30508
|
var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
|
|
29894
30509
|
#socket;
|
|
@@ -29897,38 +30512,210 @@ var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectio
|
|
|
29897
30512
|
this.#socket = socket;
|
|
29898
30513
|
}
|
|
29899
30514
|
disconnect = (socket) => socket === this.#socket ? new DisconnectedDaemonSessionEventState() : this;
|
|
30515
|
+
matches = (socket) => socket === this.#socket;
|
|
29900
30516
|
send = (message) => {
|
|
29901
|
-
if (this.#socket.readyState
|
|
29902
|
-
|
|
29903
|
-
|
|
29904
|
-
|
|
29905
|
-
|
|
30517
|
+
if (this.#socket.readyState !== WebSocket2.OPEN) {
|
|
30518
|
+
return false;
|
|
30519
|
+
}
|
|
30520
|
+
try {
|
|
30521
|
+
this.#socket.send(message);
|
|
30522
|
+
return true;
|
|
30523
|
+
} catch {
|
|
30524
|
+
return false;
|
|
29906
30525
|
}
|
|
29907
30526
|
};
|
|
29908
30527
|
};
|
|
30528
|
+
var SESSION_EVENT_REPLAY_WINDOW = 16;
|
|
30529
|
+
var SESSION_EVENT_SOURCE_REPLAY_WINDOW = 4;
|
|
30530
|
+
var SESSION_EVENT_REPLAY_BYTE_LIMIT = 32 * 1024 * 1024;
|
|
30531
|
+
var InFlightSessionEvent = class {
|
|
30532
|
+
byteLength;
|
|
30533
|
+
sourceKey;
|
|
30534
|
+
constructor(sourceKey, byteLength) {
|
|
30535
|
+
this.byteLength = byteLength;
|
|
30536
|
+
this.sourceKey = sourceKey;
|
|
30537
|
+
}
|
|
30538
|
+
};
|
|
30539
|
+
function sessionEventSourceKey(envelope2) {
|
|
30540
|
+
return envelope2.source.kind === "attempt" ? `attempt:${envelope2.sessionId}:${envelope2.source.attemptId}` : `runtime:${envelope2.sessionId}`;
|
|
30541
|
+
}
|
|
29909
30542
|
var DaemonSessionEventPublisher = class {
|
|
29910
30543
|
#outbox;
|
|
30544
|
+
#inFlightEvents = /* @__PURE__ */ new Map();
|
|
30545
|
+
#inFlightBytes = 0;
|
|
29911
30546
|
#connection = new DisconnectedDaemonSessionEventState();
|
|
29912
30547
|
constructor(outbox) {
|
|
29913
30548
|
this.#outbox = outbox;
|
|
29914
30549
|
}
|
|
29915
30550
|
connect = (socket) => {
|
|
29916
|
-
|
|
29917
|
-
this.#
|
|
29918
|
-
|
|
29919
|
-
connection.send(pending);
|
|
29920
|
-
}
|
|
30551
|
+
this.#connection = new ConnectedDaemonSessionEventState(socket);
|
|
30552
|
+
this.#clearInFlight();
|
|
30553
|
+
this.#publishNextBatch();
|
|
29921
30554
|
};
|
|
29922
30555
|
disconnect = (socket) => {
|
|
30556
|
+
if (!this.#connection.matches(socket)) {
|
|
30557
|
+
return;
|
|
30558
|
+
}
|
|
29923
30559
|
this.#connection = this.#connection.disconnect(socket);
|
|
30560
|
+
this.#clearInFlight();
|
|
29924
30561
|
};
|
|
29925
30562
|
recordAttempt = (sessionId, payload, attemptId) => {
|
|
29926
|
-
|
|
30563
|
+
const kind = decodeMessageKind(payload);
|
|
30564
|
+
if (kind === SESSION_COMPLETED_KIND || kind === SESSION_FAILED_KIND) {
|
|
30565
|
+
this.#outbox.enqueueCritical(sessionId, payload, attemptId);
|
|
30566
|
+
} else {
|
|
30567
|
+
this.#outbox.enqueue(sessionId, payload, attemptId);
|
|
30568
|
+
}
|
|
30569
|
+
this.#publishNextBatch();
|
|
29927
30570
|
};
|
|
29928
30571
|
recordRuntime = (sessionId, payload) => {
|
|
29929
|
-
this.#
|
|
30572
|
+
this.#outbox.enqueue(sessionId, payload);
|
|
30573
|
+
this.#publishNextBatch();
|
|
30574
|
+
};
|
|
30575
|
+
acknowledge = (acknowledgement) => {
|
|
30576
|
+
if (!this.#outbox.acknowledge(acknowledgement)) {
|
|
30577
|
+
return;
|
|
30578
|
+
}
|
|
30579
|
+
this.#removeInFlight(acknowledgement.eventId);
|
|
30580
|
+
this.#publishNextBatch();
|
|
30581
|
+
};
|
|
30582
|
+
quarantine = (rejection) => {
|
|
30583
|
+
const quarantined = this.#outbox.quarantine(rejection);
|
|
30584
|
+
if (!quarantined) {
|
|
30585
|
+
return false;
|
|
30586
|
+
}
|
|
30587
|
+
this.#removeInFlight(rejection.eventId);
|
|
30588
|
+
this.#publishNextBatch();
|
|
30589
|
+
return true;
|
|
30590
|
+
};
|
|
30591
|
+
#publishNextBatch = () => {
|
|
30592
|
+
while (this.#inFlightEvents.size < SESSION_EVENT_REPLAY_WINDOW) {
|
|
30593
|
+
const sourceCounts = /* @__PURE__ */ new Map();
|
|
30594
|
+
for (const inFlight of this.#inFlightEvents.values()) {
|
|
30595
|
+
sourceCounts.set(inFlight.sourceKey, (sourceCounts.get(inFlight.sourceKey) ?? 0) + 1);
|
|
30596
|
+
}
|
|
30597
|
+
const saturatedSources = [...sourceCounts.entries()].filter(([, count]) => count >= SESSION_EVENT_SOURCE_REPLAY_WINDOW).map(([sourceKey]) => sourceKey);
|
|
30598
|
+
const batch = this.#outbox.pendingSourceHeads(
|
|
30599
|
+
SESSION_EVENT_REPLAY_WINDOW - this.#inFlightEvents.size,
|
|
30600
|
+
[...this.#inFlightEvents.keys()],
|
|
30601
|
+
saturatedSources
|
|
30602
|
+
);
|
|
30603
|
+
let sent = 0;
|
|
30604
|
+
for (const encoded of batch) {
|
|
30605
|
+
const envelope2 = decodeSessionEventEnvelope(encoded);
|
|
30606
|
+
const sourceKey = sessionEventSourceKey(envelope2);
|
|
30607
|
+
const sourceCount = sourceCounts.get(sourceKey) ?? 0;
|
|
30608
|
+
if (sourceCount >= SESSION_EVENT_SOURCE_REPLAY_WINDOW) {
|
|
30609
|
+
continue;
|
|
30610
|
+
}
|
|
30611
|
+
const byteLength = new TextEncoder().encode(encoded).byteLength;
|
|
30612
|
+
if (this.#inFlightBytes + byteLength > SESSION_EVENT_REPLAY_BYTE_LIMIT) {
|
|
30613
|
+
continue;
|
|
30614
|
+
}
|
|
30615
|
+
if (!this.#connection.send(encoded)) {
|
|
30616
|
+
this.#clearInFlight();
|
|
30617
|
+
return;
|
|
30618
|
+
}
|
|
30619
|
+
this.#inFlightEvents.set(envelope2.eventId, new InFlightSessionEvent(sourceKey, byteLength));
|
|
30620
|
+
this.#inFlightBytes += byteLength;
|
|
30621
|
+
sourceCounts.set(sourceKey, sourceCount + 1);
|
|
30622
|
+
sent += 1;
|
|
30623
|
+
}
|
|
30624
|
+
if (sent === 0) {
|
|
30625
|
+
return;
|
|
30626
|
+
}
|
|
30627
|
+
}
|
|
30628
|
+
};
|
|
30629
|
+
#removeInFlight = (eventId) => {
|
|
30630
|
+
const inFlight = this.#inFlightEvents.get(eventId);
|
|
30631
|
+
if (inFlight === void 0) {
|
|
30632
|
+
return;
|
|
30633
|
+
}
|
|
30634
|
+
this.#inFlightEvents.delete(eventId);
|
|
30635
|
+
this.#inFlightBytes -= inFlight.byteLength;
|
|
30636
|
+
};
|
|
30637
|
+
#clearInFlight = () => {
|
|
30638
|
+
this.#inFlightEvents.clear();
|
|
30639
|
+
this.#inFlightBytes = 0;
|
|
29930
30640
|
};
|
|
29931
30641
|
};
|
|
30642
|
+
var CoalescingDaemonActivityPublisher = class {
|
|
30643
|
+
#pending = /* @__PURE__ */ new Map();
|
|
30644
|
+
#publish;
|
|
30645
|
+
#publishedActivityIds = /* @__PURE__ */ new Set();
|
|
30646
|
+
#scheduled = /* @__PURE__ */ new Map();
|
|
30647
|
+
#timer;
|
|
30648
|
+
constructor(timer, publish) {
|
|
30649
|
+
this.#publish = publish;
|
|
30650
|
+
this.#timer = timer;
|
|
30651
|
+
}
|
|
30652
|
+
flush = () => {
|
|
30653
|
+
const activities = [...this.#pending.values()].sort((left, right) => left.sequence - right.sequence);
|
|
30654
|
+
for (const task of this.#scheduled.values()) {
|
|
30655
|
+
task.cancel();
|
|
30656
|
+
}
|
|
30657
|
+
this.#pending.clear();
|
|
30658
|
+
this.#scheduled.clear();
|
|
30659
|
+
for (const activity of activities) {
|
|
30660
|
+
this.#publish(activity);
|
|
30661
|
+
}
|
|
30662
|
+
};
|
|
30663
|
+
record = (activity) => {
|
|
30664
|
+
if (activity.status !== "pending" && activity.status !== "running") {
|
|
30665
|
+
this.#discardPending(activity.activityId);
|
|
30666
|
+
this.#publishedActivityIds.add(activity.activityId);
|
|
30667
|
+
this.#publish(activity);
|
|
30668
|
+
return Promise.resolve();
|
|
30669
|
+
}
|
|
30670
|
+
if (!this.#publishedActivityIds.has(activity.activityId)) {
|
|
30671
|
+
this.#publishedActivityIds.add(activity.activityId);
|
|
30672
|
+
this.#publish(activity);
|
|
30673
|
+
return Promise.resolve();
|
|
30674
|
+
}
|
|
30675
|
+
this.#pending.set(activity.activityId, activity);
|
|
30676
|
+
if (!this.#scheduled.has(activity.activityId)) {
|
|
30677
|
+
this.#scheduled.set(
|
|
30678
|
+
activity.activityId,
|
|
30679
|
+
this.#timer.schedule(
|
|
30680
|
+
() => this.#flushActivity(activity.activityId),
|
|
30681
|
+
AGENT_ACTIVITY_COALESCING_MILLISECONDS
|
|
30682
|
+
)
|
|
30683
|
+
);
|
|
30684
|
+
}
|
|
30685
|
+
return Promise.resolve();
|
|
30686
|
+
};
|
|
30687
|
+
#discardPending = (activityId) => {
|
|
30688
|
+
this.#scheduled.get(activityId)?.cancel();
|
|
30689
|
+
this.#scheduled.delete(activityId);
|
|
30690
|
+
this.#pending.delete(activityId);
|
|
30691
|
+
};
|
|
30692
|
+
#flushActivity = (activityId) => {
|
|
30693
|
+
const activity = this.#pending.get(activityId);
|
|
30694
|
+
this.#discardPending(activityId);
|
|
30695
|
+
if (activity !== void 0) {
|
|
30696
|
+
this.#publish(activity);
|
|
30697
|
+
}
|
|
30698
|
+
};
|
|
30699
|
+
};
|
|
30700
|
+
function encodeDaemonActivity(command, activity) {
|
|
30701
|
+
return encodeAgentActivityEvent({
|
|
30702
|
+
activityId: activity.activityId,
|
|
30703
|
+
activityType: activity.activityType,
|
|
30704
|
+
commandId: command.commandId,
|
|
30705
|
+
content: activity.content,
|
|
30706
|
+
detail: activity.detail,
|
|
30707
|
+
input: activity.input,
|
|
30708
|
+
kind: AGENT_ACTIVITY_KIND,
|
|
30709
|
+
locations: activity.locations,
|
|
30710
|
+
name: activity.name,
|
|
30711
|
+
output: activity.output,
|
|
30712
|
+
sequence: activity.sequence,
|
|
30713
|
+
sessionId: command.sessionId,
|
|
30714
|
+
status: activity.status,
|
|
30715
|
+
title: activity.title,
|
|
30716
|
+
toolKind: activity.toolKind
|
|
30717
|
+
});
|
|
30718
|
+
}
|
|
29932
30719
|
function reportFailure(publisher, command, code, message, attemptId) {
|
|
29933
30720
|
publisher.recordAttempt(
|
|
29934
30721
|
command.sessionId,
|
|
@@ -30102,10 +30889,16 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
|
|
|
30102
30889
|
})
|
|
30103
30890
|
);
|
|
30104
30891
|
} catch (error61) {
|
|
30892
|
+
if (signal.aborted) {
|
|
30893
|
+
signal.throwIfAborted();
|
|
30894
|
+
}
|
|
30105
30895
|
reportOperationFailure(socket, command.requestId, command.sessionId, error61);
|
|
30106
30896
|
}
|
|
30107
30897
|
}
|
|
30108
|
-
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, signal) {
|
|
30898
|
+
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, timer, signal) {
|
|
30899
|
+
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
30900
|
+
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
30901
|
+
});
|
|
30109
30902
|
try {
|
|
30110
30903
|
const resolved = await resolveSessionDirectories(
|
|
30111
30904
|
directories,
|
|
@@ -30162,30 +30955,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30162
30955
|
cwd: resolved.cwd,
|
|
30163
30956
|
disposition: command.disposition,
|
|
30164
30957
|
images: attachments.images,
|
|
30165
|
-
onActivity:
|
|
30166
|
-
publisher.recordAttempt(
|
|
30167
|
-
command.sessionId,
|
|
30168
|
-
encodeAgentActivityEvent({
|
|
30169
|
-
activityId: activity.activityId,
|
|
30170
|
-
activityType: activity.activityType,
|
|
30171
|
-
commandId: command.commandId,
|
|
30172
|
-
content: activity.content,
|
|
30173
|
-
detail: activity.detail,
|
|
30174
|
-
input: activity.input,
|
|
30175
|
-
kind: AGENT_ACTIVITY_KIND,
|
|
30176
|
-
locations: activity.locations,
|
|
30177
|
-
name: activity.name,
|
|
30178
|
-
output: activity.output,
|
|
30179
|
-
sequence: activity.sequence,
|
|
30180
|
-
sessionId: command.sessionId,
|
|
30181
|
-
status: activity.status,
|
|
30182
|
-
title: activity.title,
|
|
30183
|
-
toolKind: activity.toolKind
|
|
30184
|
-
}),
|
|
30185
|
-
attemptId
|
|
30186
|
-
);
|
|
30187
|
-
return Promise.resolve();
|
|
30188
|
-
},
|
|
30958
|
+
onActivity: activities.record,
|
|
30189
30959
|
onText: (text, messageId) => {
|
|
30190
30960
|
publisher.recordAttempt(
|
|
30191
30961
|
command.sessionId,
|
|
@@ -30208,6 +30978,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30208
30978
|
});
|
|
30209
30979
|
stopReason = result.stopReason;
|
|
30210
30980
|
}
|
|
30981
|
+
activities.flush();
|
|
30211
30982
|
publisher.recordAttempt(
|
|
30212
30983
|
command.sessionId,
|
|
30213
30984
|
encodeSessionCompletedEvent({
|
|
@@ -30225,6 +30996,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30225
30996
|
sessionId: command.sessionId
|
|
30226
30997
|
});
|
|
30227
30998
|
} catch (error61) {
|
|
30999
|
+
activities.flush();
|
|
30228
31000
|
audit.record({
|
|
30229
31001
|
commandId: command.commandId,
|
|
30230
31002
|
event: "session_failed",
|
|
@@ -30263,7 +31035,10 @@ function botExecutionAgent(agent, contextHandle, socketPath) {
|
|
|
30263
31035
|
agent.capabilities
|
|
30264
31036
|
);
|
|
30265
31037
|
}
|
|
30266
|
-
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, signal) {
|
|
31038
|
+
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, timer, signal) {
|
|
31039
|
+
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
31040
|
+
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
31041
|
+
});
|
|
30267
31042
|
try {
|
|
30268
31043
|
const deadline = Date.parse(command.executionDeadlineAt);
|
|
30269
31044
|
const remaining = deadline - Date.now();
|
|
@@ -30347,30 +31122,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30347
31122
|
commandId: command.commandId,
|
|
30348
31123
|
cwd: resolved.cwd,
|
|
30349
31124
|
images: attachments.images,
|
|
30350
|
-
onActivity:
|
|
30351
|
-
publisher.recordAttempt(
|
|
30352
|
-
command.sessionId,
|
|
30353
|
-
encodeAgentActivityEvent({
|
|
30354
|
-
activityId: activity.activityId,
|
|
30355
|
-
activityType: activity.activityType,
|
|
30356
|
-
commandId: command.commandId,
|
|
30357
|
-
content: activity.content,
|
|
30358
|
-
detail: activity.detail,
|
|
30359
|
-
input: activity.input,
|
|
30360
|
-
kind: AGENT_ACTIVITY_KIND,
|
|
30361
|
-
locations: activity.locations,
|
|
30362
|
-
name: activity.name,
|
|
30363
|
-
output: activity.output,
|
|
30364
|
-
sequence: activity.sequence,
|
|
30365
|
-
sessionId: command.sessionId,
|
|
30366
|
-
status: activity.status,
|
|
30367
|
-
title: activity.title,
|
|
30368
|
-
toolKind: activity.toolKind
|
|
30369
|
-
}),
|
|
30370
|
-
attemptId
|
|
30371
|
-
);
|
|
30372
|
-
return Promise.resolve();
|
|
30373
|
-
},
|
|
31125
|
+
onActivity: activities.record,
|
|
30374
31126
|
onText: (text, messageId) => {
|
|
30375
31127
|
publisher.recordAttempt(
|
|
30376
31128
|
command.sessionId,
|
|
@@ -30390,6 +31142,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30390
31142
|
sessionId: command.sessionId,
|
|
30391
31143
|
signal: executionSignal
|
|
30392
31144
|
});
|
|
31145
|
+
activities.flush();
|
|
30393
31146
|
publisher.recordAttempt(
|
|
30394
31147
|
command.sessionId,
|
|
30395
31148
|
encodeSessionCompletedEvent({
|
|
@@ -30414,6 +31167,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30414
31167
|
lease.release();
|
|
30415
31168
|
}
|
|
30416
31169
|
} catch (error61) {
|
|
31170
|
+
activities.flush();
|
|
30417
31171
|
const failure = Date.parse(command.executionDeadlineAt) <= Date.now() ? new LocalBotAuthorizationError("turn_expired", "The Bot execution deadline has expired", {
|
|
30418
31172
|
cause: error61
|
|
30419
31173
|
}) : error61;
|
|
@@ -30453,15 +31207,15 @@ function waitForRelayRetry(signal, timer) {
|
|
|
30453
31207
|
signal.addEventListener("abort", finish, { once: true });
|
|
30454
31208
|
});
|
|
30455
31209
|
}
|
|
30456
|
-
async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
|
|
31210
|
+
async function publishAgentCatalogUntilAvailable(config2, diagnostics, signal, timer) {
|
|
30457
31211
|
try {
|
|
30458
31212
|
await publishAgentCatalog(config2, signal);
|
|
30459
31213
|
return;
|
|
30460
|
-
} catch {
|
|
31214
|
+
} catch (error61) {
|
|
30461
31215
|
if (signal.aborted) {
|
|
30462
31216
|
return;
|
|
30463
31217
|
}
|
|
30464
|
-
|
|
31218
|
+
diagnostics.catalogFailed(error61);
|
|
30465
31219
|
}
|
|
30466
31220
|
while (!signal.aborted) {
|
|
30467
31221
|
await waitForRelayRetry(signal, timer);
|
|
@@ -30475,11 +31229,13 @@ async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
|
|
|
30475
31229
|
}
|
|
30476
31230
|
}
|
|
30477
31231
|
}
|
|
30478
|
-
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, onConnected, signal, timer) {
|
|
31232
|
+
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, connectionEpoch, diagnostics, onConnected, signal, timer) {
|
|
30479
31233
|
const relayUrl = new URL(config2.relayUrl);
|
|
31234
|
+
relayUrl.searchParams.set("deliveryReceipts", "1");
|
|
30480
31235
|
relayUrl.searchParams.set("liveness", "1");
|
|
30481
31236
|
const socket = await connectRelay(relayUrl, signal);
|
|
30482
31237
|
const reconnectingTurns = [...activeTurns.values()];
|
|
31238
|
+
diagnostics.connectionOpened(connectionEpoch);
|
|
30483
31239
|
onConnected();
|
|
30484
31240
|
const connectionController = new AbortController();
|
|
30485
31241
|
const nativeRequests = /* @__PURE__ */ new Map();
|
|
@@ -30488,7 +31244,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30488
31244
|
await new Promise((resolve6, reject) => {
|
|
30489
31245
|
let finished = false;
|
|
30490
31246
|
const cleanup = () => {
|
|
30491
|
-
connectionRefresh.close();
|
|
30492
31247
|
connectionLiveness.close();
|
|
30493
31248
|
signal.removeEventListener("abort", stop);
|
|
30494
31249
|
socket.removeEventListener("close", handleClose);
|
|
@@ -30506,61 +31261,282 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30506
31261
|
cleanup();
|
|
30507
31262
|
resolve6();
|
|
30508
31263
|
};
|
|
30509
|
-
const rejectConnection = () => {
|
|
31264
|
+
const rejectConnection = (failure) => {
|
|
30510
31265
|
if (finished) {
|
|
30511
31266
|
return;
|
|
30512
31267
|
}
|
|
30513
31268
|
finished = true;
|
|
30514
31269
|
cleanup();
|
|
30515
|
-
reject(
|
|
31270
|
+
reject(failure);
|
|
30516
31271
|
};
|
|
30517
31272
|
const stop = () => {
|
|
31273
|
+
diagnostics.connectionClosed(connectionEpoch, 1e3, "Daemon stopped", "daemon_stop");
|
|
30518
31274
|
closeRelaySocket(socket, 1e3, "Daemon stopped");
|
|
30519
31275
|
resolveConnection();
|
|
30520
31276
|
};
|
|
30521
|
-
const
|
|
30522
|
-
|
|
30523
|
-
|
|
31277
|
+
const failAndClose = (failure, code, reason, source) => {
|
|
31278
|
+
diagnostics.connectionFailed(connectionEpoch, failure, source);
|
|
31279
|
+
diagnostics.connectionClosed(connectionEpoch, code, reason, source);
|
|
31280
|
+
closeRelaySocket(socket, code, reason);
|
|
31281
|
+
rejectConnection(failure);
|
|
31282
|
+
};
|
|
31283
|
+
const processingDeliveryIds = /* @__PURE__ */ new Set();
|
|
31284
|
+
const processDeliveredPrompt = async (delivery) => {
|
|
31285
|
+
const command = decodeSessionPromptCommand(delivery.payload);
|
|
31286
|
+
if (command.sessionId !== delivery.sessionId) {
|
|
31287
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31288
|
+
}
|
|
31289
|
+
const active = activeTurns.get(command.commandId);
|
|
31290
|
+
if (active !== void 0) {
|
|
31291
|
+
await active.completion;
|
|
31292
|
+
return;
|
|
31293
|
+
}
|
|
31294
|
+
const receipt = outbox.claimExecution(command.commandId, command.sessionId, delivery.payload);
|
|
31295
|
+
if (receipt.kind === "duplicate") {
|
|
31296
|
+
if (receipt.state === "running") {
|
|
31297
|
+
reportFailure(
|
|
31298
|
+
publisher,
|
|
31299
|
+
command,
|
|
31300
|
+
"agent_execution_interrupted",
|
|
31301
|
+
"The local Agent execution was interrupted before it completed",
|
|
31302
|
+
receipt.attemptId
|
|
31303
|
+
);
|
|
31304
|
+
outbox.transitionExecution(command.commandId, "failed");
|
|
31305
|
+
return;
|
|
31306
|
+
}
|
|
31307
|
+
if (receipt.state !== "dispatching") {
|
|
31308
|
+
return;
|
|
31309
|
+
}
|
|
31310
|
+
}
|
|
31311
|
+
const turn = new ActiveDaemonTurn(command, receipt.attemptId);
|
|
31312
|
+
activeTurns.set(command.commandId, turn);
|
|
31313
|
+
if (command.disposition !== SessionPromptDisposition.Steer) {
|
|
31314
|
+
activeAttemptIds.set(command.sessionId, receipt.attemptId);
|
|
31315
|
+
}
|
|
31316
|
+
try {
|
|
31317
|
+
await executePrompt(
|
|
31318
|
+
outbox,
|
|
31319
|
+
publisher,
|
|
31320
|
+
command,
|
|
31321
|
+
config2,
|
|
31322
|
+
directories,
|
|
31323
|
+
audit,
|
|
31324
|
+
sessions,
|
|
31325
|
+
receipt.attemptId,
|
|
31326
|
+
timer,
|
|
31327
|
+
turn.signal
|
|
31328
|
+
);
|
|
31329
|
+
} finally {
|
|
31330
|
+
activeTurns.delete(command.commandId);
|
|
31331
|
+
if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
|
|
31332
|
+
activeAttemptIds.delete(command.sessionId);
|
|
31333
|
+
}
|
|
31334
|
+
turn.finish();
|
|
31335
|
+
}
|
|
31336
|
+
};
|
|
31337
|
+
const processDeliveredPayload = async (delivery) => {
|
|
31338
|
+
const kind = decodeMessageKind(delivery.payload);
|
|
31339
|
+
if (kind === SESSION_CANCEL_KIND) {
|
|
31340
|
+
const cancellation = decodeSessionCancelCommand(delivery.payload);
|
|
31341
|
+
if (cancellation.sessionId !== delivery.sessionId) {
|
|
31342
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31343
|
+
}
|
|
31344
|
+
const turn = activeTurns.get(cancellation.commandId);
|
|
31345
|
+
if (turn === void 0 || !turn.matches(cancellation) || !turn.requestCancellation()) {
|
|
31346
|
+
return;
|
|
31347
|
+
}
|
|
31348
|
+
audit.record({
|
|
31349
|
+
commandId: cancellation.commandId,
|
|
31350
|
+
event: "session_cancellation_requested",
|
|
31351
|
+
sessionId: cancellation.sessionId
|
|
31352
|
+
});
|
|
31353
|
+
await sessions.cancelPrompt(cancellation.sessionId);
|
|
31354
|
+
return;
|
|
31355
|
+
}
|
|
31356
|
+
if (kind === SESSION_CONFIGURE_KIND) {
|
|
31357
|
+
const command = decodeSessionConfigureCommand(delivery.payload);
|
|
31358
|
+
if (command.sessionId !== delivery.sessionId) {
|
|
31359
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31360
|
+
}
|
|
31361
|
+
await executeSessionConfigure(
|
|
31362
|
+
publisher,
|
|
31363
|
+
socket,
|
|
31364
|
+
command,
|
|
31365
|
+
config2,
|
|
31366
|
+
directories,
|
|
31367
|
+
audit,
|
|
31368
|
+
sessions,
|
|
31369
|
+
connectionController.signal
|
|
31370
|
+
);
|
|
31371
|
+
return;
|
|
31372
|
+
}
|
|
31373
|
+
if (kind === SESSION_PERMISSION_RESPOND_KIND) {
|
|
31374
|
+
const command = decodeSessionPermissionRespondCommand(delivery.payload);
|
|
31375
|
+
if (command.sessionId !== delivery.sessionId) {
|
|
31376
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31377
|
+
}
|
|
31378
|
+
try {
|
|
31379
|
+
await sessions.respondPermission(command);
|
|
31380
|
+
audit.record({
|
|
31381
|
+
commandId: command.interactionId,
|
|
31382
|
+
event: "session_permission_resolved",
|
|
31383
|
+
sessionId: command.sessionId
|
|
31384
|
+
});
|
|
31385
|
+
} catch (error61) {
|
|
31386
|
+
reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
|
|
31387
|
+
}
|
|
31388
|
+
return;
|
|
31389
|
+
}
|
|
31390
|
+
if (kind === SESSION_ELICITATION_RESPOND_KIND) {
|
|
31391
|
+
const command = decodeSessionElicitationRespondCommand(delivery.payload);
|
|
31392
|
+
if (command.sessionId !== delivery.sessionId) {
|
|
31393
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31394
|
+
}
|
|
31395
|
+
try {
|
|
31396
|
+
await sessions.respondElicitation(command);
|
|
31397
|
+
audit.record({
|
|
31398
|
+
commandId: command.interactionId,
|
|
31399
|
+
event: "session_elicitation_resolved",
|
|
31400
|
+
sessionId: command.sessionId
|
|
31401
|
+
});
|
|
31402
|
+
} catch (error61) {
|
|
31403
|
+
reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
|
|
31404
|
+
}
|
|
31405
|
+
return;
|
|
31406
|
+
}
|
|
31407
|
+
if (kind === SESSION_PROMPT_KIND) {
|
|
31408
|
+
await processDeliveredPrompt(delivery);
|
|
31409
|
+
return;
|
|
31410
|
+
}
|
|
31411
|
+
throw new Error("Runtime delivery contains an unsupported protocol message");
|
|
31412
|
+
};
|
|
31413
|
+
const processRuntimeDelivery = (delivery, state) => {
|
|
31414
|
+
if (state === "processed" || processingDeliveryIds.has(delivery.deliveryId)) {
|
|
31415
|
+
return;
|
|
31416
|
+
}
|
|
31417
|
+
processingDeliveryIds.add(delivery.deliveryId);
|
|
31418
|
+
void processDeliveredPayload(delivery).then(() => {
|
|
31419
|
+
outbox.markRuntimeDeliveryProcessed(delivery.deliveryId, delivery.sessionId);
|
|
31420
|
+
}).catch((error61) => {
|
|
31421
|
+
if (connectionController.signal.aborted) {
|
|
31422
|
+
return;
|
|
31423
|
+
}
|
|
31424
|
+
console.error("Mobius daemon could not process a durable Runtime delivery", error61);
|
|
31425
|
+
failAndClose(
|
|
31426
|
+
new Error("Runtime delivery processing failed", { cause: error61 }),
|
|
31427
|
+
4008,
|
|
31428
|
+
"Invalid Runtime delivery",
|
|
31429
|
+
"delivery"
|
|
31430
|
+
);
|
|
31431
|
+
}).finally(() => processingDeliveryIds.delete(delivery.deliveryId));
|
|
31432
|
+
};
|
|
31433
|
+
const receiveRuntimeDelivery = (delivery) => {
|
|
31434
|
+
const payloadKind = decodeMessageKind(delivery.payload);
|
|
31435
|
+
let payloadSessionId = "";
|
|
31436
|
+
if (payloadKind === SESSION_CANCEL_KIND) {
|
|
31437
|
+
payloadSessionId = decodeSessionCancelCommand(delivery.payload).sessionId;
|
|
31438
|
+
} else if (payloadKind === SESSION_CONFIGURE_KIND) {
|
|
31439
|
+
payloadSessionId = decodeSessionConfigureCommand(delivery.payload).sessionId;
|
|
31440
|
+
} else if (payloadKind === SESSION_PERMISSION_RESPOND_KIND) {
|
|
31441
|
+
payloadSessionId = decodeSessionPermissionRespondCommand(delivery.payload).sessionId;
|
|
31442
|
+
} else if (payloadKind === SESSION_ELICITATION_RESPOND_KIND) {
|
|
31443
|
+
payloadSessionId = decodeSessionElicitationRespondCommand(delivery.payload).sessionId;
|
|
31444
|
+
} else if (payloadKind === SESSION_PROMPT_KIND) {
|
|
31445
|
+
payloadSessionId = decodeSessionPromptCommand(delivery.payload).sessionId;
|
|
31446
|
+
} else {
|
|
31447
|
+
throw new Error("Runtime delivery contains an unsupported protocol message");
|
|
31448
|
+
}
|
|
31449
|
+
if (payloadSessionId !== delivery.sessionId) {
|
|
31450
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31451
|
+
}
|
|
31452
|
+
const stored = outbox.claimRuntimeDelivery(delivery);
|
|
31453
|
+
send(
|
|
31454
|
+
socket,
|
|
31455
|
+
encodeRuntimeDeliveryReceived({
|
|
31456
|
+
deliveryId: delivery.deliveryId,
|
|
31457
|
+
kind: RUNTIME_DELIVERY_RECEIVED_KIND,
|
|
31458
|
+
sessionId: delivery.sessionId
|
|
31459
|
+
})
|
|
31460
|
+
);
|
|
31461
|
+
processRuntimeDelivery(delivery, stored.state);
|
|
31462
|
+
};
|
|
31463
|
+
const resumeRuntimeDeliveries = () => {
|
|
31464
|
+
for (const stored of outbox.runtimeDeliveries()) {
|
|
31465
|
+
const delivery = {
|
|
31466
|
+
deliveryId: stored.deliveryId,
|
|
31467
|
+
kind: RUNTIME_DELIVERY_KIND,
|
|
31468
|
+
payload: stored.payload,
|
|
31469
|
+
sessionId: stored.sessionId
|
|
31470
|
+
};
|
|
31471
|
+
if (stored.state !== "relay_committed") {
|
|
31472
|
+
send(
|
|
31473
|
+
socket,
|
|
31474
|
+
encodeRuntimeDeliveryReceived({
|
|
31475
|
+
deliveryId: stored.deliveryId,
|
|
31476
|
+
kind: RUNTIME_DELIVERY_RECEIVED_KIND,
|
|
31477
|
+
sessionId: stored.sessionId
|
|
31478
|
+
})
|
|
31479
|
+
);
|
|
31480
|
+
}
|
|
31481
|
+
processRuntimeDelivery(delivery, stored.state);
|
|
31482
|
+
}
|
|
30524
31483
|
};
|
|
30525
31484
|
const connectionLiveness = new RelayConnectionLiveness(timer, {
|
|
30526
31485
|
send: (message) => send(socket, message),
|
|
30527
|
-
unresponsive: () => {
|
|
31486
|
+
unresponsive: (heartbeatId, timeoutMilliseconds) => {
|
|
31487
|
+
diagnostics.heartbeatTimedOut(connectionEpoch, heartbeatId, timeoutMilliseconds);
|
|
31488
|
+
diagnostics.connectionClosed(
|
|
31489
|
+
connectionEpoch,
|
|
31490
|
+
4001,
|
|
31491
|
+
"Relay liveness check timed out",
|
|
31492
|
+
"heartbeat_timeout"
|
|
31493
|
+
);
|
|
30528
31494
|
closeRelaySocket(socket, 4001, "Relay liveness check timed out");
|
|
30529
31495
|
resolveConnection();
|
|
30530
31496
|
}
|
|
30531
31497
|
});
|
|
30532
|
-
const connectionRefresh = new RelayConnectionRefresh(
|
|
30533
|
-
timer,
|
|
30534
|
-
() => activeTurns.size === 0,
|
|
30535
|
-
refreshConnection
|
|
30536
|
-
);
|
|
30537
31498
|
signal.addEventListener("abort", stop, { once: true });
|
|
30538
|
-
const handleClose = () => {
|
|
31499
|
+
const handleClose = (event) => {
|
|
31500
|
+
diagnostics.connectionClosed(connectionEpoch, event.code, event.reason, "relay");
|
|
30539
31501
|
resolveConnection();
|
|
30540
31502
|
};
|
|
30541
|
-
const handleError = () => {
|
|
31503
|
+
const handleError = (event) => {
|
|
30542
31504
|
if (signal.aborted) {
|
|
30543
31505
|
resolveConnection();
|
|
30544
31506
|
return;
|
|
30545
31507
|
}
|
|
30546
|
-
|
|
31508
|
+
const cause = Reflect.get(event, "error");
|
|
31509
|
+
const failure = new Error("Relay WebSocket emitted an error", { cause: cause ?? event });
|
|
31510
|
+
diagnostics.connectionFailed(connectionEpoch, failure, "socket_error");
|
|
31511
|
+
diagnostics.connectionClosed(connectionEpoch, 1006, "WebSocket error", "socket_error");
|
|
31512
|
+
rejectConnection(failure);
|
|
30547
31513
|
};
|
|
30548
31514
|
const handleMessage = (event) => {
|
|
30549
31515
|
const encoded = event.data;
|
|
30550
31516
|
if (typeof encoded !== "string") {
|
|
30551
|
-
|
|
30552
|
-
rejectConnection();
|
|
31517
|
+
failAndClose(new Error("Relay sent a non-text message"), 4003, "Text message required", "protocol");
|
|
30553
31518
|
return;
|
|
30554
31519
|
}
|
|
30555
31520
|
try {
|
|
30556
31521
|
const kind = decodeMessageKind(encoded);
|
|
31522
|
+
if (kind === RUNTIME_DELIVERY_COMMITTED_KIND) {
|
|
31523
|
+
const committed = decodeRuntimeDeliveryCommitted(encoded);
|
|
31524
|
+
if (!outbox.markRuntimeDeliveryCommitted(committed.deliveryId, committed.sessionId)) {
|
|
31525
|
+
console.warn("Mobius daemon ignored confirmation for an unknown Runtime delivery");
|
|
31526
|
+
}
|
|
31527
|
+
return;
|
|
31528
|
+
}
|
|
31529
|
+
if (kind === RUNTIME_DELIVERY_KIND) {
|
|
31530
|
+
receiveRuntimeDelivery(decodeRuntimeDelivery(encoded));
|
|
31531
|
+
return;
|
|
31532
|
+
}
|
|
30557
31533
|
if (kind === SESSION_EVENT_ACK_KIND) {
|
|
30558
|
-
|
|
31534
|
+
publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
|
|
30559
31535
|
return;
|
|
30560
31536
|
}
|
|
30561
31537
|
if (kind === SESSION_EVENT_REJECTED_KIND) {
|
|
30562
31538
|
const rejection = decodeSessionEventRejection(encoded);
|
|
30563
|
-
if (
|
|
31539
|
+
if (publisher.quarantine(rejection)) {
|
|
30564
31540
|
audit.record({
|
|
30565
31541
|
commandId: rejection.eventId,
|
|
30566
31542
|
details: { code: rejection.code },
|
|
@@ -30939,6 +31915,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30939
31915
|
applicator,
|
|
30940
31916
|
ipc,
|
|
30941
31917
|
receipt2.attemptId,
|
|
31918
|
+
timer,
|
|
30942
31919
|
turn2.signal
|
|
30943
31920
|
).catch((error61) => {
|
|
30944
31921
|
console.error("Mobius daemon Bot turn failed", error61);
|
|
@@ -30948,7 +31925,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30948
31925
|
activeAttemptIds.delete(command2.sessionId);
|
|
30949
31926
|
}
|
|
30950
31927
|
turn2.finish();
|
|
30951
|
-
connectionRefresh.afterTurnFinished();
|
|
30952
31928
|
});
|
|
30953
31929
|
return;
|
|
30954
31930
|
}
|
|
@@ -30977,6 +31953,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30977
31953
|
audit,
|
|
30978
31954
|
sessions,
|
|
30979
31955
|
receipt.attemptId,
|
|
31956
|
+
timer,
|
|
30980
31957
|
turn.signal
|
|
30981
31958
|
).catch((error61) => {
|
|
30982
31959
|
console.error("Mobius daemon turn failed", error61);
|
|
@@ -30986,12 +31963,19 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30986
31963
|
activeAttemptIds.delete(command.sessionId);
|
|
30987
31964
|
}
|
|
30988
31965
|
turn.finish();
|
|
30989
|
-
connectionRefresh.afterTurnFinished();
|
|
30990
31966
|
});
|
|
30991
31967
|
} catch (error61) {
|
|
30992
31968
|
console.error("Mobius daemon rejected a message", error61);
|
|
30993
|
-
|
|
30994
|
-
|
|
31969
|
+
if (error61 instanceof RuntimeDeliveryInboxCapacityError) {
|
|
31970
|
+
failAndClose(error61, 4013, "Runtime delivery queue full", "delivery_backpressure");
|
|
31971
|
+
return;
|
|
31972
|
+
}
|
|
31973
|
+
failAndClose(
|
|
31974
|
+
new Error("Relay sent an invalid protocol message", { cause: error61 }),
|
|
31975
|
+
4008,
|
|
31976
|
+
"Invalid protocol message",
|
|
31977
|
+
"protocol"
|
|
31978
|
+
);
|
|
30995
31979
|
}
|
|
30996
31980
|
};
|
|
30997
31981
|
socket.addEventListener("close", handleClose);
|
|
@@ -31003,21 +31987,19 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31003
31987
|
return;
|
|
31004
31988
|
}
|
|
31005
31989
|
publisher.connect(socket);
|
|
31006
|
-
|
|
31007
|
-
connectionRefresh.afterTurnFinished
|
|
31008
|
-
);
|
|
31990
|
+
resumeRuntimeDeliveries();
|
|
31009
31991
|
},
|
|
31010
31992
|
(error61) => {
|
|
31011
31993
|
if (finished) {
|
|
31012
31994
|
return;
|
|
31013
31995
|
}
|
|
31014
31996
|
console.error("Mobius daemon could not reconcile active Agent turns", error61);
|
|
31015
|
-
|
|
31016
|
-
|
|
31997
|
+
failAndClose(
|
|
31998
|
+
new Error("Active Agent turn reconciliation failed", { cause: error61 }),
|
|
31017
31999
|
ACTIVE_TURN_RECONCILIATION_CLOSE_CODE,
|
|
31018
|
-
"Active Agent turn reconciliation failed"
|
|
32000
|
+
"Active Agent turn reconciliation failed",
|
|
32001
|
+
"reconciliation"
|
|
31019
32002
|
);
|
|
31020
|
-
rejectConnection();
|
|
31021
32003
|
}
|
|
31022
32004
|
);
|
|
31023
32005
|
if (signal.aborted) {
|
|
@@ -31061,6 +32043,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31061
32043
|
const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
|
|
31062
32044
|
const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
|
|
31063
32045
|
const installationObserver = new DaemonInstallationObserver();
|
|
32046
|
+
const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);
|
|
31064
32047
|
const nativeSessions = new NativeSessionService(config2, directories, sessions, audit);
|
|
31065
32048
|
const installations = new AgentInstallationManager(
|
|
31066
32049
|
specifications,
|
|
@@ -31068,7 +32051,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31068
32051
|
installationObserver,
|
|
31069
32052
|
installationAudit
|
|
31070
32053
|
);
|
|
31071
|
-
let
|
|
32054
|
+
let connectionEpoch = 0;
|
|
31072
32055
|
let connectionAnnounced = false;
|
|
31073
32056
|
const announceConnection = () => {
|
|
31074
32057
|
if (connectionAnnounced) {
|
|
@@ -31084,10 +32067,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31084
32067
|
`
|
|
31085
32068
|
);
|
|
31086
32069
|
};
|
|
31087
|
-
const catalogPublication = publishAgentCatalogUntilAvailable(config2, signal, timer);
|
|
32070
|
+
const catalogPublication = publishAgentCatalogUntilAvailable(config2, diagnostics, signal, timer);
|
|
31088
32071
|
try {
|
|
31089
32072
|
await ipc.listen(signal);
|
|
31090
32073
|
while (!signal.aborted) {
|
|
32074
|
+
connectionEpoch += 1;
|
|
31091
32075
|
try {
|
|
31092
32076
|
await runRelayConnection(
|
|
31093
32077
|
config2,
|
|
@@ -31105,19 +32089,17 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31105
32089
|
ipc,
|
|
31106
32090
|
activeTurns,
|
|
31107
32091
|
activeAttemptIds,
|
|
32092
|
+
connectionEpoch,
|
|
32093
|
+
diagnostics,
|
|
31108
32094
|
announceConnection,
|
|
31109
32095
|
signal,
|
|
31110
32096
|
timer
|
|
31111
32097
|
);
|
|
31112
|
-
|
|
31113
|
-
} catch {
|
|
32098
|
+
} catch (error61) {
|
|
31114
32099
|
if (signal.aborted) {
|
|
31115
32100
|
return;
|
|
31116
32101
|
}
|
|
31117
|
-
|
|
31118
|
-
console.warn("Mobius daemon is waiting for the relay");
|
|
31119
|
-
retryAnnounced = true;
|
|
31120
|
-
}
|
|
32102
|
+
diagnostics.connectionFailed(connectionEpoch, error61, "connection");
|
|
31121
32103
|
}
|
|
31122
32104
|
await waitForRelayRetry(signal, timer);
|
|
31123
32105
|
}
|