@moxt-ai/mobius 0.0.25 → 0.0.26
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/cli.js +466 -173
- package/dist/cli.js.map +4 -4
- package/dist/index.js +465 -172
- 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/relay-connection/connect.d.ts.map +1 -1
- package/dist/relay-connection/connect.js +16 -8
- 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/session-event-outbox.d.ts +2 -1
- package/dist/relay-connection/session-event-outbox.d.ts.map +1 -1
- package/dist/relay-connection/session-event-outbox.js +48 -8
- 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 +182 -146
- package/dist/run-daemon.js.map +1 -1
- package/dist/runtime.js +465 -172
- package/dist/runtime.js.map +4 -4
- package/package.json +1 -1
package/dist/runtime.js
CHANGED
|
@@ -1450,7 +1450,53 @@ import { fetch } from "undici";
|
|
|
1450
1450
|
|
|
1451
1451
|
// src/network/environment-proxy.ts
|
|
1452
1452
|
import { EnvHttpProxyAgent } from "undici";
|
|
1453
|
+
var configuredHttpProxy = process.env["http_proxy"] ?? process.env["HTTP_PROXY"] ?? "";
|
|
1454
|
+
var configuredHttpsProxy = process.env["https_proxy"] ?? process.env["HTTPS_PROXY"] ?? configuredHttpProxy;
|
|
1453
1455
|
var environmentProxyDispatcher = new EnvHttpProxyAgent();
|
|
1456
|
+
function bypassesProxy(target) {
|
|
1457
|
+
const noProxy = process.env["no_proxy"] ?? process.env["NO_PROXY"] ?? "";
|
|
1458
|
+
if (noProxy === "*") {
|
|
1459
|
+
return true;
|
|
1460
|
+
}
|
|
1461
|
+
const hostname4 = target.hostname.replace(/^\[|\]$/gu, "").toLowerCase();
|
|
1462
|
+
const defaultPort = target.protocol === "wss:" || target.protocol === "https:" ? 443 : 80;
|
|
1463
|
+
const port = Number.parseInt(target.port, 10) || defaultPort;
|
|
1464
|
+
for (const rawEntry of noProxy.split(/[,\s]/u)) {
|
|
1465
|
+
if (rawEntry.length === 0) {
|
|
1466
|
+
continue;
|
|
1467
|
+
}
|
|
1468
|
+
const parsed = rawEntry.match(/^(.+):(\d+)$/u);
|
|
1469
|
+
const entryHostname = (parsed?.[1] ?? rawEntry).replace(/^\*?\./u, "").toLowerCase();
|
|
1470
|
+
const entryPort = parsed?.[2] === void 0 ? 0 : Number.parseInt(parsed[2], 10);
|
|
1471
|
+
if (entryPort !== 0 && entryPort !== port) {
|
|
1472
|
+
continue;
|
|
1473
|
+
}
|
|
1474
|
+
if (hostname4 === entryHostname || hostname4.endsWith(`.${entryHostname}`)) {
|
|
1475
|
+
return true;
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
return false;
|
|
1479
|
+
}
|
|
1480
|
+
function sanitizedProxyOrigin(proxyUrl) {
|
|
1481
|
+
try {
|
|
1482
|
+
return new URL(proxyUrl).origin;
|
|
1483
|
+
} catch {
|
|
1484
|
+
return "configured-invalid-url";
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
function describeEnvironmentProxyRoute(target) {
|
|
1488
|
+
if (bypassesProxy(target)) {
|
|
1489
|
+
return { proxyRoute: "direct" };
|
|
1490
|
+
}
|
|
1491
|
+
const proxyUrl = target.protocol === "wss:" || target.protocol === "https:" ? configuredHttpsProxy : configuredHttpProxy;
|
|
1492
|
+
if (proxyUrl.length === 0) {
|
|
1493
|
+
return { proxyRoute: "direct" };
|
|
1494
|
+
}
|
|
1495
|
+
return {
|
|
1496
|
+
proxyOrigin: sanitizedProxyOrigin(proxyUrl),
|
|
1497
|
+
proxyRoute: "proxy"
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1454
1500
|
|
|
1455
1501
|
// src/agent-installation/managed-agent-archive.ts
|
|
1456
1502
|
var ARCHIVE_DOWNLOAD_LIMIT_BYTES = 128 * 1024 * 1024;
|
|
@@ -22967,6 +23013,7 @@ var encode4 = (message, schema) => {
|
|
|
22967
23013
|
}
|
|
22968
23014
|
return JSON.stringify(decoded.data);
|
|
22969
23015
|
};
|
|
23016
|
+
var decodeSessionEventEnvelope = (encoded) => decode5(encoded, eventEnvelopeSchema);
|
|
22970
23017
|
var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
|
|
22971
23018
|
var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
|
|
22972
23019
|
var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSchema);
|
|
@@ -28616,9 +28663,11 @@ import { WebSocket } from "undici";
|
|
|
28616
28663
|
var CONNECTION_TIMEOUT_MILLISECONDS = 15e3;
|
|
28617
28664
|
var RelayConnectionError = class extends Error {
|
|
28618
28665
|
code;
|
|
28619
|
-
|
|
28666
|
+
diagnosticDetails;
|
|
28667
|
+
constructor(code, message, diagnosticDetails = {}, options = {}) {
|
|
28620
28668
|
super(message, options);
|
|
28621
28669
|
this.code = code;
|
|
28670
|
+
this.diagnosticDetails = diagnosticDetails;
|
|
28622
28671
|
this.name = "RelayConnectionError";
|
|
28623
28672
|
}
|
|
28624
28673
|
};
|
|
@@ -28656,16 +28705,34 @@ function connectRelay(url2, signal) {
|
|
|
28656
28705
|
};
|
|
28657
28706
|
const onAbort = () => {
|
|
28658
28707
|
fail(
|
|
28659
|
-
new RelayConnectionError(
|
|
28660
|
-
|
|
28661
|
-
|
|
28708
|
+
new RelayConnectionError(
|
|
28709
|
+
"relay_connection_cancelled",
|
|
28710
|
+
"Relay connection was cancelled",
|
|
28711
|
+
{
|
|
28712
|
+
cancellation: "requested"
|
|
28713
|
+
},
|
|
28714
|
+
{ cause: signal.reason }
|
|
28715
|
+
)
|
|
28662
28716
|
);
|
|
28663
28717
|
};
|
|
28664
|
-
const onClose = () => {
|
|
28665
|
-
fail(
|
|
28718
|
+
const onClose = (event) => {
|
|
28719
|
+
fail(
|
|
28720
|
+
new RelayConnectionError("relay_connection_closed", "Relay connection closed before it was ready", {
|
|
28721
|
+
closeCode: event.code.toString(),
|
|
28722
|
+
closeReason: event.reason
|
|
28723
|
+
})
|
|
28724
|
+
);
|
|
28666
28725
|
};
|
|
28667
|
-
const onError = () => {
|
|
28668
|
-
|
|
28726
|
+
const onError = (event) => {
|
|
28727
|
+
const cause = Reflect.get(event, "error");
|
|
28728
|
+
fail(
|
|
28729
|
+
new RelayConnectionError(
|
|
28730
|
+
"relay_connection_failed",
|
|
28731
|
+
"Relay connection failed",
|
|
28732
|
+
{},
|
|
28733
|
+
{ cause: cause ?? event }
|
|
28734
|
+
)
|
|
28735
|
+
);
|
|
28669
28736
|
};
|
|
28670
28737
|
const onOpen = () => {
|
|
28671
28738
|
if (finished) {
|
|
@@ -28676,7 +28743,11 @@ function connectRelay(url2, signal) {
|
|
|
28676
28743
|
resolve6(socket);
|
|
28677
28744
|
};
|
|
28678
28745
|
function onTimeout() {
|
|
28679
|
-
fail(
|
|
28746
|
+
fail(
|
|
28747
|
+
new RelayConnectionError("relay_connection_timeout", "Relay connection timed out", {
|
|
28748
|
+
timeoutMilliseconds: CONNECTION_TIMEOUT_MILLISECONDS.toString()
|
|
28749
|
+
})
|
|
28750
|
+
);
|
|
28680
28751
|
}
|
|
28681
28752
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
28682
28753
|
socket.addEventListener("close", onClose, { once: true });
|
|
@@ -28688,6 +28759,142 @@ function connectRelay(url2, signal) {
|
|
|
28688
28759
|
});
|
|
28689
28760
|
}
|
|
28690
28761
|
|
|
28762
|
+
// src/relay-connection/diagnostics.ts
|
|
28763
|
+
var MAX_DIAGNOSTIC_TEXT_LENGTH = 256;
|
|
28764
|
+
function sanitizeDiagnosticText(value) {
|
|
28765
|
+
const printable = Array.from(value, (character) => {
|
|
28766
|
+
const code = character.charCodeAt(0);
|
|
28767
|
+
return code < 32 || code === 127 ? " " : character;
|
|
28768
|
+
}).join("");
|
|
28769
|
+
const withoutSecrets = printable.replace(/([?&](?:access_token|authorization|credential|key|secret|token)=)[^&\s]*/giu, "$1[redacted]").replace(/(?:https?|wss?):\/\/[^\s)]+/giu, (encodedUrl) => {
|
|
28770
|
+
try {
|
|
28771
|
+
return new URL(encodedUrl).origin;
|
|
28772
|
+
} catch {
|
|
28773
|
+
return "[redacted-url]";
|
|
28774
|
+
}
|
|
28775
|
+
});
|
|
28776
|
+
return withoutSecrets.slice(0, MAX_DIAGNOSTIC_TEXT_LENGTH);
|
|
28777
|
+
}
|
|
28778
|
+
function addFailureDetails(details, failure) {
|
|
28779
|
+
let current = failure;
|
|
28780
|
+
for (let depth = 0; depth < 3 && current instanceof Error; depth += 1) {
|
|
28781
|
+
const prefix = depth === 0 ? "failure" : `cause${depth.toString()}`;
|
|
28782
|
+
details[`${prefix}Name`] = current.name;
|
|
28783
|
+
details[`${prefix}Message`] = sanitizeDiagnosticText(current.message);
|
|
28784
|
+
const code = Reflect.get(current, "code");
|
|
28785
|
+
if (typeof code === "string" || typeof code === "number") {
|
|
28786
|
+
details[`${prefix}Code`] = String(code);
|
|
28787
|
+
}
|
|
28788
|
+
const statusCode = Reflect.get(current, "statusCode");
|
|
28789
|
+
if (typeof statusCode === "string" || typeof statusCode === "number") {
|
|
28790
|
+
details[`${prefix}StatusCode`] = String(statusCode);
|
|
28791
|
+
}
|
|
28792
|
+
const diagnosticDetails = Reflect.get(current, "diagnosticDetails");
|
|
28793
|
+
if (typeof diagnosticDetails === "object" && diagnosticDetails !== null) {
|
|
28794
|
+
for (const [key, value] of Object.entries(diagnosticDetails)) {
|
|
28795
|
+
if (typeof value === "string") {
|
|
28796
|
+
details[key] = sanitizeDiagnosticText(value);
|
|
28797
|
+
}
|
|
28798
|
+
}
|
|
28799
|
+
}
|
|
28800
|
+
current = current.cause;
|
|
28801
|
+
}
|
|
28802
|
+
}
|
|
28803
|
+
var RelayConnectionDiagnostics = class {
|
|
28804
|
+
#audit;
|
|
28805
|
+
#channelId;
|
|
28806
|
+
#lastClosedEpoch = 0;
|
|
28807
|
+
#lastFailedEpoch = 0;
|
|
28808
|
+
#relayOrigin;
|
|
28809
|
+
#route;
|
|
28810
|
+
constructor(audit, channelId, relayUrl) {
|
|
28811
|
+
this.#audit = audit;
|
|
28812
|
+
this.#channelId = channelId;
|
|
28813
|
+
this.#relayOrigin = relayUrl.origin;
|
|
28814
|
+
this.#route = describeEnvironmentProxyRoute(relayUrl);
|
|
28815
|
+
}
|
|
28816
|
+
catalogFailed = (failure) => {
|
|
28817
|
+
const details = { ...this.#route, relayOrigin: this.#relayOrigin };
|
|
28818
|
+
addFailureDetails(details, failure);
|
|
28819
|
+
this.#record("agent_catalog_publish_failed", "catalog", details, true);
|
|
28820
|
+
};
|
|
28821
|
+
connectionClosed = (connectionEpoch, code, reason, source) => {
|
|
28822
|
+
if (this.#lastClosedEpoch === connectionEpoch) {
|
|
28823
|
+
return;
|
|
28824
|
+
}
|
|
28825
|
+
this.#lastClosedEpoch = connectionEpoch;
|
|
28826
|
+
this.#record(
|
|
28827
|
+
"relay_connection_closed",
|
|
28828
|
+
connectionEpoch.toString(),
|
|
28829
|
+
{
|
|
28830
|
+
closeCode: code.toString(),
|
|
28831
|
+
closeReason: sanitizeDiagnosticText(reason),
|
|
28832
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
28833
|
+
relayOrigin: this.#relayOrigin,
|
|
28834
|
+
source,
|
|
28835
|
+
...this.#route
|
|
28836
|
+
},
|
|
28837
|
+
true
|
|
28838
|
+
);
|
|
28839
|
+
};
|
|
28840
|
+
connectionFailed = (connectionEpoch, failure, source) => {
|
|
28841
|
+
if (this.#lastFailedEpoch === connectionEpoch) {
|
|
28842
|
+
return;
|
|
28843
|
+
}
|
|
28844
|
+
this.#lastFailedEpoch = connectionEpoch;
|
|
28845
|
+
const details = {
|
|
28846
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
28847
|
+
relayOrigin: this.#relayOrigin,
|
|
28848
|
+
source,
|
|
28849
|
+
...this.#route
|
|
28850
|
+
};
|
|
28851
|
+
addFailureDetails(details, failure);
|
|
28852
|
+
this.#record("relay_connection_failed", connectionEpoch.toString(), details, true);
|
|
28853
|
+
};
|
|
28854
|
+
connectionOpened = (connectionEpoch) => {
|
|
28855
|
+
this.#record(
|
|
28856
|
+
"relay_connection_opened",
|
|
28857
|
+
connectionEpoch.toString(),
|
|
28858
|
+
{
|
|
28859
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
28860
|
+
relayOrigin: this.#relayOrigin,
|
|
28861
|
+
...this.#route
|
|
28862
|
+
},
|
|
28863
|
+
false
|
|
28864
|
+
);
|
|
28865
|
+
};
|
|
28866
|
+
heartbeatTimedOut = (connectionEpoch, heartbeatId, timeoutMilliseconds) => {
|
|
28867
|
+
this.#record(
|
|
28868
|
+
"relay_heartbeat_timed_out",
|
|
28869
|
+
connectionEpoch.toString(),
|
|
28870
|
+
{
|
|
28871
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
28872
|
+
heartbeatId,
|
|
28873
|
+
relayOrigin: this.#relayOrigin,
|
|
28874
|
+
timeoutMilliseconds: timeoutMilliseconds.toString(),
|
|
28875
|
+
...this.#route
|
|
28876
|
+
},
|
|
28877
|
+
true
|
|
28878
|
+
);
|
|
28879
|
+
};
|
|
28880
|
+
#record = (event, commandId, details, warning) => {
|
|
28881
|
+
this.#audit.record({
|
|
28882
|
+
commandId,
|
|
28883
|
+
details,
|
|
28884
|
+
event,
|
|
28885
|
+
sessionId: this.#channelId
|
|
28886
|
+
});
|
|
28887
|
+
const encoded = JSON.stringify({ channelId: this.#channelId, event, ...details });
|
|
28888
|
+
if (warning) {
|
|
28889
|
+
process.stderr.write(`Mobius relay diagnostic ${encoded}
|
|
28890
|
+
`);
|
|
28891
|
+
return;
|
|
28892
|
+
}
|
|
28893
|
+
process.stdout.write(`Mobius relay diagnostic ${encoded}
|
|
28894
|
+
`);
|
|
28895
|
+
};
|
|
28896
|
+
};
|
|
28897
|
+
|
|
28691
28898
|
// src/relay-connection/liveness.ts
|
|
28692
28899
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
28693
28900
|
var HEARTBEAT_ACK_TIMEOUT_MILLISECONDS = 1e4;
|
|
@@ -28764,9 +28971,10 @@ var RelayConnectionLiveness = class {
|
|
|
28764
28971
|
if (!(this.#state instanceof AwaitingHeartbeatAckState)) {
|
|
28765
28972
|
throw new Error("Heartbeat timeout occurred in an invalid state");
|
|
28766
28973
|
}
|
|
28974
|
+
const heartbeatId = this.#state.heartbeatId;
|
|
28767
28975
|
this.#state.timeout.cancel();
|
|
28768
28976
|
this.#state = new FinishedRelayLivenessState();
|
|
28769
|
-
this.#transport.unresponsive();
|
|
28977
|
+
this.#transport.unresponsive(heartbeatId, HEARTBEAT_ACK_TIMEOUT_MILLISECONDS);
|
|
28770
28978
|
};
|
|
28771
28979
|
#sendHeartbeat = () => {
|
|
28772
28980
|
if (this.#state instanceof WaitingForHeartbeatState) {
|
|
@@ -28815,6 +29023,7 @@ var SessionEventOutbox = class {
|
|
|
28815
29023
|
ordinal INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
28816
29024
|
event_id TEXT NOT NULL UNIQUE,
|
|
28817
29025
|
session_id TEXT NOT NULL,
|
|
29026
|
+
source_key TEXT NOT NULL,
|
|
28818
29027
|
envelope_json TEXT NOT NULL
|
|
28819
29028
|
) STRICT;
|
|
28820
29029
|
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
|
|
@@ -28842,6 +29051,27 @@ var SessionEventOutbox = class {
|
|
|
28842
29051
|
)
|
|
28843
29052
|
) STRICT;
|
|
28844
29053
|
`);
|
|
29054
|
+
const outboxColumns = this.#database.prepare("PRAGMA table_info(relay_session_event_outbox)").all();
|
|
29055
|
+
const hasSourceKey = outboxColumns.some(
|
|
29056
|
+
(column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "source_key"
|
|
29057
|
+
);
|
|
29058
|
+
if (!hasSourceKey) {
|
|
29059
|
+
this.#database.exec(`
|
|
29060
|
+
ALTER TABLE relay_session_event_outbox
|
|
29061
|
+
ADD COLUMN source_key TEXT NOT NULL DEFAULT '';
|
|
29062
|
+
`);
|
|
29063
|
+
}
|
|
29064
|
+
this.#database.exec(`
|
|
29065
|
+
UPDATE relay_session_event_outbox
|
|
29066
|
+
SET source_key = CASE json_extract(envelope_json, '$.source.kind')
|
|
29067
|
+
WHEN 'attempt' THEN
|
|
29068
|
+
'attempt:' || session_id || ':' || json_extract(envelope_json, '$.source.attemptId')
|
|
29069
|
+
ELSE 'runtime:' || session_id
|
|
29070
|
+
END
|
|
29071
|
+
WHERE source_key = '';
|
|
29072
|
+
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_source_order
|
|
29073
|
+
ON relay_session_event_outbox(source_key, ordinal);
|
|
29074
|
+
`);
|
|
28845
29075
|
}
|
|
28846
29076
|
claimExecution = (commandId, sessionId, commandJson) => {
|
|
28847
29077
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
@@ -28899,12 +29129,10 @@ var SessionEventOutbox = class {
|
|
|
28899
29129
|
const state = typeof row === "object" && row !== null ? Reflect.get(row, "state") : void 0;
|
|
28900
29130
|
return state === "succeeded" || state === "failed" || state === "cancelled";
|
|
28901
29131
|
};
|
|
28902
|
-
acknowledge = (acknowledgement) =>
|
|
28903
|
-
|
|
28904
|
-
`DELETE FROM relay_session_event_outbox
|
|
29132
|
+
acknowledge = (acknowledgement) => this.#database.prepare(
|
|
29133
|
+
`DELETE FROM relay_session_event_outbox
|
|
28905
29134
|
WHERE event_id = ? AND session_id = ?`
|
|
28906
|
-
|
|
28907
|
-
};
|
|
29135
|
+
).run(acknowledgement.eventId, acknowledgement.sessionId).changes === 1;
|
|
28908
29136
|
quarantine = (rejection) => {
|
|
28909
29137
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
28910
29138
|
try {
|
|
@@ -28971,9 +29199,9 @@ var SessionEventOutbox = class {
|
|
|
28971
29199
|
).run(sourceKey, nextSourceSeq + 1);
|
|
28972
29200
|
this.#database.prepare(
|
|
28973
29201
|
`INSERT INTO relay_session_event_outbox (
|
|
28974
|
-
event_id, session_id, envelope_json
|
|
28975
|
-
) VALUES (?, ?, ?)`
|
|
28976
|
-
).run(envelope2.eventId, envelope2.sessionId, encoded);
|
|
29202
|
+
event_id, session_id, source_key, envelope_json
|
|
29203
|
+
) VALUES (?, ?, ?, ?)`
|
|
29204
|
+
).run(envelope2.eventId, envelope2.sessionId, sourceKey, encoded);
|
|
28977
29205
|
this.#database.exec("COMMIT");
|
|
28978
29206
|
return encoded;
|
|
28979
29207
|
} catch (error61) {
|
|
@@ -28986,6 +29214,27 @@ var SessionEventOutbox = class {
|
|
|
28986
29214
|
FROM relay_session_event_outbox
|
|
28987
29215
|
ORDER BY ordinal`
|
|
28988
29216
|
).all().map(readPendingEnvelope);
|
|
29217
|
+
pendingBatch = (limit) => {
|
|
29218
|
+
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
29219
|
+
throw new Error("Session event replay batch limit must be a positive integer");
|
|
29220
|
+
}
|
|
29221
|
+
return this.#database.prepare(
|
|
29222
|
+
`WITH ranked_events AS (
|
|
29223
|
+
SELECT ordinal,
|
|
29224
|
+
ROW_NUMBER() OVER (
|
|
29225
|
+
PARTITION BY source_key
|
|
29226
|
+
ORDER BY ordinal
|
|
29227
|
+
) AS source_position
|
|
29228
|
+
FROM relay_session_event_outbox
|
|
29229
|
+
)
|
|
29230
|
+
SELECT outbox.envelope_json
|
|
29231
|
+
FROM ranked_events AS ranked
|
|
29232
|
+
INNER JOIN relay_session_event_outbox AS outbox
|
|
29233
|
+
ON outbox.ordinal = ranked.ordinal
|
|
29234
|
+
ORDER BY ranked.source_position, outbox.ordinal
|
|
29235
|
+
LIMIT ?`
|
|
29236
|
+
).all(limit).map(readPendingEnvelope);
|
|
29237
|
+
};
|
|
28989
29238
|
};
|
|
28990
29239
|
function isDaemonExecutionState(value) {
|
|
28991
29240
|
return value === "cancelled" || value === "dispatching" || value === "failed" || value === "running" || value === "succeeded";
|
|
@@ -29002,7 +29251,7 @@ var systemDaemonTimer = new SystemDaemonTimer();
|
|
|
29002
29251
|
|
|
29003
29252
|
// src/run-daemon.ts
|
|
29004
29253
|
var RELAY_RECONNECT_DELAY_MILLISECONDS = 500;
|
|
29005
|
-
var
|
|
29254
|
+
var AGENT_ACTIVITY_COALESCING_MILLISECONDS = 100;
|
|
29006
29255
|
var ACTIVE_TURN_RECONCILIATION_TIMEOUT_MILLISECONDS = 2e4;
|
|
29007
29256
|
var ACTIVE_TURN_RECONCILIATION_CLOSE_CODE = 4009;
|
|
29008
29257
|
function botIpcSocketPath() {
|
|
@@ -29011,54 +29260,6 @@ function botIpcSocketPath() {
|
|
|
29011
29260
|
}
|
|
29012
29261
|
return join15("/tmp", `mobius-bot-${randomUUID4()}.sock`);
|
|
29013
29262
|
}
|
|
29014
|
-
var RelayConnectionRefreshState = class {
|
|
29015
|
-
};
|
|
29016
|
-
var ScheduledRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29017
|
-
};
|
|
29018
|
-
var DueRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29019
|
-
};
|
|
29020
|
-
var FinishedRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29021
|
-
};
|
|
29022
|
-
var RelayConnectionRefresh = class {
|
|
29023
|
-
#isSafe;
|
|
29024
|
-
#refresh;
|
|
29025
|
-
#scheduledTask;
|
|
29026
|
-
#state = new ScheduledRelayConnectionRefreshState();
|
|
29027
|
-
constructor(timer, isSafe, refresh) {
|
|
29028
|
-
this.#isSafe = isSafe;
|
|
29029
|
-
this.#refresh = refresh;
|
|
29030
|
-
this.#scheduledTask = timer.schedule(this.#request, RELAY_CONNECTION_REFRESH_MILLISECONDS);
|
|
29031
|
-
}
|
|
29032
|
-
afterTurnFinished = () => {
|
|
29033
|
-
if (this.#state instanceof DueRelayConnectionRefreshState) {
|
|
29034
|
-
this.#request();
|
|
29035
|
-
return;
|
|
29036
|
-
}
|
|
29037
|
-
if (this.#state instanceof ScheduledRelayConnectionRefreshState || this.#state instanceof FinishedRelayConnectionRefreshState) {
|
|
29038
|
-
return;
|
|
29039
|
-
}
|
|
29040
|
-
throw new Error("Unknown relay connection refresh state");
|
|
29041
|
-
};
|
|
29042
|
-
close = () => {
|
|
29043
|
-
this.#scheduledTask.cancel();
|
|
29044
|
-
this.#state = new FinishedRelayConnectionRefreshState();
|
|
29045
|
-
};
|
|
29046
|
-
#request = () => {
|
|
29047
|
-
if (this.#state instanceof FinishedRelayConnectionRefreshState) {
|
|
29048
|
-
return;
|
|
29049
|
-
}
|
|
29050
|
-
if (!(this.#state instanceof ScheduledRelayConnectionRefreshState) && !(this.#state instanceof DueRelayConnectionRefreshState)) {
|
|
29051
|
-
throw new Error("Unknown relay connection refresh state");
|
|
29052
|
-
}
|
|
29053
|
-
if (!this.#isSafe()) {
|
|
29054
|
-
this.#state = new DueRelayConnectionRefreshState();
|
|
29055
|
-
return;
|
|
29056
|
-
}
|
|
29057
|
-
this.#state = new FinishedRelayConnectionRefreshState();
|
|
29058
|
-
this.#scheduledTask.cancel();
|
|
29059
|
-
this.#refresh();
|
|
29060
|
-
};
|
|
29061
|
-
};
|
|
29062
29263
|
var DaemonAcpObserver = class {
|
|
29063
29264
|
#record;
|
|
29064
29265
|
constructor(record2) {
|
|
@@ -29323,7 +29524,8 @@ var DaemonSessionEventConnectionState = class {
|
|
|
29323
29524
|
};
|
|
29324
29525
|
var DisconnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
|
|
29325
29526
|
disconnect = () => this;
|
|
29326
|
-
|
|
29527
|
+
matches = () => false;
|
|
29528
|
+
send = () => false;
|
|
29327
29529
|
};
|
|
29328
29530
|
var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
|
|
29329
29531
|
#socket;
|
|
@@ -29332,38 +29534,155 @@ var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectio
|
|
|
29332
29534
|
this.#socket = socket;
|
|
29333
29535
|
}
|
|
29334
29536
|
disconnect = (socket) => socket === this.#socket ? new DisconnectedDaemonSessionEventState() : this;
|
|
29537
|
+
matches = (socket) => socket === this.#socket;
|
|
29335
29538
|
send = (message) => {
|
|
29336
|
-
if (this.#socket.readyState
|
|
29337
|
-
|
|
29338
|
-
|
|
29339
|
-
|
|
29340
|
-
|
|
29539
|
+
if (this.#socket.readyState !== WebSocket2.OPEN) {
|
|
29540
|
+
return false;
|
|
29541
|
+
}
|
|
29542
|
+
try {
|
|
29543
|
+
this.#socket.send(message);
|
|
29544
|
+
return true;
|
|
29545
|
+
} catch {
|
|
29546
|
+
return false;
|
|
29341
29547
|
}
|
|
29342
29548
|
};
|
|
29343
29549
|
};
|
|
29550
|
+
var SESSION_EVENT_REPLAY_WINDOW = 4;
|
|
29344
29551
|
var DaemonSessionEventPublisher = class {
|
|
29345
29552
|
#outbox;
|
|
29553
|
+
#inFlightEventIds = /* @__PURE__ */ new Set();
|
|
29346
29554
|
#connection = new DisconnectedDaemonSessionEventState();
|
|
29347
29555
|
constructor(outbox) {
|
|
29348
29556
|
this.#outbox = outbox;
|
|
29349
29557
|
}
|
|
29350
29558
|
connect = (socket) => {
|
|
29351
|
-
|
|
29352
|
-
this.#
|
|
29353
|
-
|
|
29354
|
-
connection.send(pending);
|
|
29355
|
-
}
|
|
29559
|
+
this.#connection = new ConnectedDaemonSessionEventState(socket);
|
|
29560
|
+
this.#inFlightEventIds.clear();
|
|
29561
|
+
this.#publishNextBatch();
|
|
29356
29562
|
};
|
|
29357
29563
|
disconnect = (socket) => {
|
|
29564
|
+
if (!this.#connection.matches(socket)) {
|
|
29565
|
+
return;
|
|
29566
|
+
}
|
|
29358
29567
|
this.#connection = this.#connection.disconnect(socket);
|
|
29568
|
+
this.#inFlightEventIds.clear();
|
|
29359
29569
|
};
|
|
29360
29570
|
recordAttempt = (sessionId, payload, attemptId) => {
|
|
29361
|
-
this.#
|
|
29571
|
+
this.#outbox.enqueue(sessionId, payload, attemptId);
|
|
29572
|
+
this.#publishNextBatch();
|
|
29362
29573
|
};
|
|
29363
29574
|
recordRuntime = (sessionId, payload) => {
|
|
29364
|
-
this.#
|
|
29575
|
+
this.#outbox.enqueue(sessionId, payload);
|
|
29576
|
+
this.#publishNextBatch();
|
|
29577
|
+
};
|
|
29578
|
+
acknowledge = (acknowledgement) => {
|
|
29579
|
+
if (!this.#outbox.acknowledge(acknowledgement)) {
|
|
29580
|
+
return;
|
|
29581
|
+
}
|
|
29582
|
+
this.#inFlightEventIds.delete(acknowledgement.eventId);
|
|
29583
|
+
this.#publishNextBatch();
|
|
29584
|
+
};
|
|
29585
|
+
quarantine = (rejection) => {
|
|
29586
|
+
const quarantined = this.#outbox.quarantine(rejection);
|
|
29587
|
+
if (!quarantined) {
|
|
29588
|
+
return false;
|
|
29589
|
+
}
|
|
29590
|
+
this.#inFlightEventIds.delete(rejection.eventId);
|
|
29591
|
+
this.#publishNextBatch();
|
|
29592
|
+
return true;
|
|
29593
|
+
};
|
|
29594
|
+
#publishNextBatch = () => {
|
|
29595
|
+
if (this.#inFlightEventIds.size > 0) {
|
|
29596
|
+
return;
|
|
29597
|
+
}
|
|
29598
|
+
const batch = this.#outbox.pendingBatch(SESSION_EVENT_REPLAY_WINDOW);
|
|
29599
|
+
for (const encoded of batch) {
|
|
29600
|
+
const envelope2 = decodeSessionEventEnvelope(encoded);
|
|
29601
|
+
if (!this.#connection.send(encoded)) {
|
|
29602
|
+
this.#inFlightEventIds.clear();
|
|
29603
|
+
return;
|
|
29604
|
+
}
|
|
29605
|
+
this.#inFlightEventIds.add(envelope2.eventId);
|
|
29606
|
+
}
|
|
29607
|
+
};
|
|
29608
|
+
};
|
|
29609
|
+
var CoalescingDaemonActivityPublisher = class {
|
|
29610
|
+
#pending = /* @__PURE__ */ new Map();
|
|
29611
|
+
#publish;
|
|
29612
|
+
#publishedActivityIds = /* @__PURE__ */ new Set();
|
|
29613
|
+
#scheduled = /* @__PURE__ */ new Map();
|
|
29614
|
+
#timer;
|
|
29615
|
+
constructor(timer, publish) {
|
|
29616
|
+
this.#publish = publish;
|
|
29617
|
+
this.#timer = timer;
|
|
29618
|
+
}
|
|
29619
|
+
flush = () => {
|
|
29620
|
+
const activities = [...this.#pending.values()].sort((left, right) => left.sequence - right.sequence);
|
|
29621
|
+
for (const task of this.#scheduled.values()) {
|
|
29622
|
+
task.cancel();
|
|
29623
|
+
}
|
|
29624
|
+
this.#pending.clear();
|
|
29625
|
+
this.#scheduled.clear();
|
|
29626
|
+
for (const activity of activities) {
|
|
29627
|
+
this.#publish(activity);
|
|
29628
|
+
}
|
|
29629
|
+
};
|
|
29630
|
+
record = (activity) => {
|
|
29631
|
+
if (activity.status !== "pending" && activity.status !== "running") {
|
|
29632
|
+
this.#discardPending(activity.activityId);
|
|
29633
|
+
this.#publishedActivityIds.add(activity.activityId);
|
|
29634
|
+
this.#publish(activity);
|
|
29635
|
+
return Promise.resolve();
|
|
29636
|
+
}
|
|
29637
|
+
if (!this.#publishedActivityIds.has(activity.activityId)) {
|
|
29638
|
+
this.#publishedActivityIds.add(activity.activityId);
|
|
29639
|
+
this.#publish(activity);
|
|
29640
|
+
return Promise.resolve();
|
|
29641
|
+
}
|
|
29642
|
+
this.#pending.set(activity.activityId, activity);
|
|
29643
|
+
if (!this.#scheduled.has(activity.activityId)) {
|
|
29644
|
+
this.#scheduled.set(
|
|
29645
|
+
activity.activityId,
|
|
29646
|
+
this.#timer.schedule(
|
|
29647
|
+
() => this.#flushActivity(activity.activityId),
|
|
29648
|
+
AGENT_ACTIVITY_COALESCING_MILLISECONDS
|
|
29649
|
+
)
|
|
29650
|
+
);
|
|
29651
|
+
}
|
|
29652
|
+
return Promise.resolve();
|
|
29653
|
+
};
|
|
29654
|
+
#discardPending = (activityId) => {
|
|
29655
|
+
this.#scheduled.get(activityId)?.cancel();
|
|
29656
|
+
this.#scheduled.delete(activityId);
|
|
29657
|
+
this.#pending.delete(activityId);
|
|
29658
|
+
};
|
|
29659
|
+
#flushActivity = (activityId) => {
|
|
29660
|
+
const activity = this.#pending.get(activityId);
|
|
29661
|
+
this.#discardPending(activityId);
|
|
29662
|
+
if (activity !== void 0) {
|
|
29663
|
+
this.#publish(activity);
|
|
29664
|
+
}
|
|
29365
29665
|
};
|
|
29366
29666
|
};
|
|
29667
|
+
function encodeDaemonActivity(command, activity) {
|
|
29668
|
+
return encodeAgentActivityEvent({
|
|
29669
|
+
activityId: activity.activityId,
|
|
29670
|
+
activityType: activity.activityType,
|
|
29671
|
+
commandId: command.commandId,
|
|
29672
|
+
content: activity.content,
|
|
29673
|
+
detail: activity.detail,
|
|
29674
|
+
input: activity.input,
|
|
29675
|
+
kind: AGENT_ACTIVITY_KIND,
|
|
29676
|
+
locations: activity.locations,
|
|
29677
|
+
name: activity.name,
|
|
29678
|
+
output: activity.output,
|
|
29679
|
+
sequence: activity.sequence,
|
|
29680
|
+
sessionId: command.sessionId,
|
|
29681
|
+
status: activity.status,
|
|
29682
|
+
title: activity.title,
|
|
29683
|
+
toolKind: activity.toolKind
|
|
29684
|
+
});
|
|
29685
|
+
}
|
|
29367
29686
|
function reportFailure(publisher, command, code, message, attemptId) {
|
|
29368
29687
|
publisher.recordAttempt(
|
|
29369
29688
|
command.sessionId,
|
|
@@ -29540,7 +29859,10 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
|
|
|
29540
29859
|
reportOperationFailure(socket, command.requestId, command.sessionId, error61);
|
|
29541
29860
|
}
|
|
29542
29861
|
}
|
|
29543
|
-
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, signal) {
|
|
29862
|
+
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, timer, signal) {
|
|
29863
|
+
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
29864
|
+
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
29865
|
+
});
|
|
29544
29866
|
try {
|
|
29545
29867
|
const resolved = await resolveSessionDirectories(
|
|
29546
29868
|
directories,
|
|
@@ -29597,30 +29919,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
29597
29919
|
cwd: resolved.cwd,
|
|
29598
29920
|
disposition: command.disposition,
|
|
29599
29921
|
images: attachments.images,
|
|
29600
|
-
onActivity:
|
|
29601
|
-
publisher.recordAttempt(
|
|
29602
|
-
command.sessionId,
|
|
29603
|
-
encodeAgentActivityEvent({
|
|
29604
|
-
activityId: activity.activityId,
|
|
29605
|
-
activityType: activity.activityType,
|
|
29606
|
-
commandId: command.commandId,
|
|
29607
|
-
content: activity.content,
|
|
29608
|
-
detail: activity.detail,
|
|
29609
|
-
input: activity.input,
|
|
29610
|
-
kind: AGENT_ACTIVITY_KIND,
|
|
29611
|
-
locations: activity.locations,
|
|
29612
|
-
name: activity.name,
|
|
29613
|
-
output: activity.output,
|
|
29614
|
-
sequence: activity.sequence,
|
|
29615
|
-
sessionId: command.sessionId,
|
|
29616
|
-
status: activity.status,
|
|
29617
|
-
title: activity.title,
|
|
29618
|
-
toolKind: activity.toolKind
|
|
29619
|
-
}),
|
|
29620
|
-
attemptId
|
|
29621
|
-
);
|
|
29622
|
-
return Promise.resolve();
|
|
29623
|
-
},
|
|
29922
|
+
onActivity: activities.record,
|
|
29624
29923
|
onText: (text, messageId) => {
|
|
29625
29924
|
publisher.recordAttempt(
|
|
29626
29925
|
command.sessionId,
|
|
@@ -29643,6 +29942,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
29643
29942
|
});
|
|
29644
29943
|
stopReason = result.stopReason;
|
|
29645
29944
|
}
|
|
29945
|
+
activities.flush();
|
|
29646
29946
|
publisher.recordAttempt(
|
|
29647
29947
|
command.sessionId,
|
|
29648
29948
|
encodeSessionCompletedEvent({
|
|
@@ -29660,6 +29960,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
29660
29960
|
sessionId: command.sessionId
|
|
29661
29961
|
});
|
|
29662
29962
|
} catch (error61) {
|
|
29963
|
+
activities.flush();
|
|
29663
29964
|
audit.record({
|
|
29664
29965
|
commandId: command.commandId,
|
|
29665
29966
|
event: "session_failed",
|
|
@@ -29698,7 +29999,10 @@ function botExecutionAgent(agent, contextHandle, socketPath) {
|
|
|
29698
29999
|
agent.capabilities
|
|
29699
30000
|
);
|
|
29700
30001
|
}
|
|
29701
|
-
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, signal) {
|
|
30002
|
+
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, timer, signal) {
|
|
30003
|
+
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
30004
|
+
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
30005
|
+
});
|
|
29702
30006
|
try {
|
|
29703
30007
|
const deadline = Date.parse(command.executionDeadlineAt);
|
|
29704
30008
|
const remaining = deadline - Date.now();
|
|
@@ -29782,30 +30086,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
29782
30086
|
commandId: command.commandId,
|
|
29783
30087
|
cwd: resolved.cwd,
|
|
29784
30088
|
images: attachments.images,
|
|
29785
|
-
onActivity:
|
|
29786
|
-
publisher.recordAttempt(
|
|
29787
|
-
command.sessionId,
|
|
29788
|
-
encodeAgentActivityEvent({
|
|
29789
|
-
activityId: activity.activityId,
|
|
29790
|
-
activityType: activity.activityType,
|
|
29791
|
-
commandId: command.commandId,
|
|
29792
|
-
content: activity.content,
|
|
29793
|
-
detail: activity.detail,
|
|
29794
|
-
input: activity.input,
|
|
29795
|
-
kind: AGENT_ACTIVITY_KIND,
|
|
29796
|
-
locations: activity.locations,
|
|
29797
|
-
name: activity.name,
|
|
29798
|
-
output: activity.output,
|
|
29799
|
-
sequence: activity.sequence,
|
|
29800
|
-
sessionId: command.sessionId,
|
|
29801
|
-
status: activity.status,
|
|
29802
|
-
title: activity.title,
|
|
29803
|
-
toolKind: activity.toolKind
|
|
29804
|
-
}),
|
|
29805
|
-
attemptId
|
|
29806
|
-
);
|
|
29807
|
-
return Promise.resolve();
|
|
29808
|
-
},
|
|
30089
|
+
onActivity: activities.record,
|
|
29809
30090
|
onText: (text, messageId) => {
|
|
29810
30091
|
publisher.recordAttempt(
|
|
29811
30092
|
command.sessionId,
|
|
@@ -29825,6 +30106,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
29825
30106
|
sessionId: command.sessionId,
|
|
29826
30107
|
signal: executionSignal
|
|
29827
30108
|
});
|
|
30109
|
+
activities.flush();
|
|
29828
30110
|
publisher.recordAttempt(
|
|
29829
30111
|
command.sessionId,
|
|
29830
30112
|
encodeSessionCompletedEvent({
|
|
@@ -29849,6 +30131,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
29849
30131
|
lease.release();
|
|
29850
30132
|
}
|
|
29851
30133
|
} catch (error61) {
|
|
30134
|
+
activities.flush();
|
|
29852
30135
|
const failure = Date.parse(command.executionDeadlineAt) <= Date.now() ? new LocalBotAuthorizationError("turn_expired", "The Bot execution deadline has expired", {
|
|
29853
30136
|
cause: error61
|
|
29854
30137
|
}) : error61;
|
|
@@ -29888,15 +30171,15 @@ function waitForRelayRetry(signal, timer) {
|
|
|
29888
30171
|
signal.addEventListener("abort", finish, { once: true });
|
|
29889
30172
|
});
|
|
29890
30173
|
}
|
|
29891
|
-
async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
|
|
30174
|
+
async function publishAgentCatalogUntilAvailable(config2, diagnostics, signal, timer) {
|
|
29892
30175
|
try {
|
|
29893
30176
|
await publishAgentCatalog(config2, signal);
|
|
29894
30177
|
return;
|
|
29895
|
-
} catch {
|
|
30178
|
+
} catch (error61) {
|
|
29896
30179
|
if (signal.aborted) {
|
|
29897
30180
|
return;
|
|
29898
30181
|
}
|
|
29899
|
-
|
|
30182
|
+
diagnostics.catalogFailed(error61);
|
|
29900
30183
|
}
|
|
29901
30184
|
while (!signal.aborted) {
|
|
29902
30185
|
await waitForRelayRetry(signal, timer);
|
|
@@ -29910,11 +30193,12 @@ async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
|
|
|
29910
30193
|
}
|
|
29911
30194
|
}
|
|
29912
30195
|
}
|
|
29913
|
-
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, onConnected, signal, timer) {
|
|
30196
|
+
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, connectionEpoch, diagnostics, onConnected, signal, timer) {
|
|
29914
30197
|
const relayUrl = new URL(config2.relayUrl);
|
|
29915
30198
|
relayUrl.searchParams.set("liveness", "1");
|
|
29916
30199
|
const socket = await connectRelay(relayUrl, signal);
|
|
29917
30200
|
const reconnectingTurns = [...activeTurns.values()];
|
|
30201
|
+
diagnostics.connectionOpened(connectionEpoch);
|
|
29918
30202
|
onConnected();
|
|
29919
30203
|
const connectionController = new AbortController();
|
|
29920
30204
|
const nativeRequests = /* @__PURE__ */ new Map();
|
|
@@ -29923,7 +30207,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
29923
30207
|
await new Promise((resolve6, reject) => {
|
|
29924
30208
|
let finished = false;
|
|
29925
30209
|
const cleanup = () => {
|
|
29926
|
-
connectionRefresh.close();
|
|
29927
30210
|
connectionLiveness.close();
|
|
29928
30211
|
signal.removeEventListener("abort", stop);
|
|
29929
30212
|
socket.removeEventListener("close", handleClose);
|
|
@@ -29941,61 +30224,70 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
29941
30224
|
cleanup();
|
|
29942
30225
|
resolve6();
|
|
29943
30226
|
};
|
|
29944
|
-
const rejectConnection = () => {
|
|
30227
|
+
const rejectConnection = (failure) => {
|
|
29945
30228
|
if (finished) {
|
|
29946
30229
|
return;
|
|
29947
30230
|
}
|
|
29948
30231
|
finished = true;
|
|
29949
30232
|
cleanup();
|
|
29950
|
-
reject(
|
|
30233
|
+
reject(failure);
|
|
29951
30234
|
};
|
|
29952
30235
|
const stop = () => {
|
|
30236
|
+
diagnostics.connectionClosed(connectionEpoch, 1e3, "Daemon stopped", "daemon_stop");
|
|
29953
30237
|
closeRelaySocket(socket, 1e3, "Daemon stopped");
|
|
29954
30238
|
resolveConnection();
|
|
29955
30239
|
};
|
|
29956
|
-
const
|
|
29957
|
-
|
|
29958
|
-
|
|
30240
|
+
const failAndClose = (failure, code, reason, source) => {
|
|
30241
|
+
diagnostics.connectionFailed(connectionEpoch, failure, source);
|
|
30242
|
+
diagnostics.connectionClosed(connectionEpoch, code, reason, source);
|
|
30243
|
+
closeRelaySocket(socket, code, reason);
|
|
30244
|
+
rejectConnection(failure);
|
|
29959
30245
|
};
|
|
29960
30246
|
const connectionLiveness = new RelayConnectionLiveness(timer, {
|
|
29961
30247
|
send: (message) => send(socket, message),
|
|
29962
|
-
unresponsive: () => {
|
|
30248
|
+
unresponsive: (heartbeatId, timeoutMilliseconds) => {
|
|
30249
|
+
diagnostics.heartbeatTimedOut(connectionEpoch, heartbeatId, timeoutMilliseconds);
|
|
30250
|
+
diagnostics.connectionClosed(
|
|
30251
|
+
connectionEpoch,
|
|
30252
|
+
4001,
|
|
30253
|
+
"Relay liveness check timed out",
|
|
30254
|
+
"heartbeat_timeout"
|
|
30255
|
+
);
|
|
29963
30256
|
closeRelaySocket(socket, 4001, "Relay liveness check timed out");
|
|
29964
30257
|
resolveConnection();
|
|
29965
30258
|
}
|
|
29966
30259
|
});
|
|
29967
|
-
const connectionRefresh = new RelayConnectionRefresh(
|
|
29968
|
-
timer,
|
|
29969
|
-
() => activeTurns.size === 0,
|
|
29970
|
-
refreshConnection
|
|
29971
|
-
);
|
|
29972
30260
|
signal.addEventListener("abort", stop, { once: true });
|
|
29973
|
-
const handleClose = () => {
|
|
30261
|
+
const handleClose = (event) => {
|
|
30262
|
+
diagnostics.connectionClosed(connectionEpoch, event.code, event.reason, "relay");
|
|
29974
30263
|
resolveConnection();
|
|
29975
30264
|
};
|
|
29976
|
-
const handleError = () => {
|
|
30265
|
+
const handleError = (event) => {
|
|
29977
30266
|
if (signal.aborted) {
|
|
29978
30267
|
resolveConnection();
|
|
29979
30268
|
return;
|
|
29980
30269
|
}
|
|
29981
|
-
|
|
30270
|
+
const cause = Reflect.get(event, "error");
|
|
30271
|
+
const failure = new Error("Relay WebSocket emitted an error", { cause: cause ?? event });
|
|
30272
|
+
diagnostics.connectionFailed(connectionEpoch, failure, "socket_error");
|
|
30273
|
+
diagnostics.connectionClosed(connectionEpoch, 1006, "WebSocket error", "socket_error");
|
|
30274
|
+
rejectConnection(failure);
|
|
29982
30275
|
};
|
|
29983
30276
|
const handleMessage = (event) => {
|
|
29984
30277
|
const encoded = event.data;
|
|
29985
30278
|
if (typeof encoded !== "string") {
|
|
29986
|
-
|
|
29987
|
-
rejectConnection();
|
|
30279
|
+
failAndClose(new Error("Relay sent a non-text message"), 4003, "Text message required", "protocol");
|
|
29988
30280
|
return;
|
|
29989
30281
|
}
|
|
29990
30282
|
try {
|
|
29991
30283
|
const kind = decodeMessageKind(encoded);
|
|
29992
30284
|
if (kind === SESSION_EVENT_ACK_KIND) {
|
|
29993
|
-
|
|
30285
|
+
publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
|
|
29994
30286
|
return;
|
|
29995
30287
|
}
|
|
29996
30288
|
if (kind === SESSION_EVENT_REJECTED_KIND) {
|
|
29997
30289
|
const rejection = decodeSessionEventRejection(encoded);
|
|
29998
|
-
if (
|
|
30290
|
+
if (publisher.quarantine(rejection)) {
|
|
29999
30291
|
audit.record({
|
|
30000
30292
|
commandId: rejection.eventId,
|
|
30001
30293
|
details: { code: rejection.code },
|
|
@@ -30374,6 +30666,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30374
30666
|
applicator,
|
|
30375
30667
|
ipc,
|
|
30376
30668
|
receipt2.attemptId,
|
|
30669
|
+
timer,
|
|
30377
30670
|
turn2.signal
|
|
30378
30671
|
).catch((error61) => {
|
|
30379
30672
|
console.error("Mobius daemon Bot turn failed", error61);
|
|
@@ -30383,7 +30676,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30383
30676
|
activeAttemptIds.delete(command2.sessionId);
|
|
30384
30677
|
}
|
|
30385
30678
|
turn2.finish();
|
|
30386
|
-
connectionRefresh.afterTurnFinished();
|
|
30387
30679
|
});
|
|
30388
30680
|
return;
|
|
30389
30681
|
}
|
|
@@ -30412,6 +30704,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30412
30704
|
audit,
|
|
30413
30705
|
sessions,
|
|
30414
30706
|
receipt.attemptId,
|
|
30707
|
+
timer,
|
|
30415
30708
|
turn.signal
|
|
30416
30709
|
).catch((error61) => {
|
|
30417
30710
|
console.error("Mobius daemon turn failed", error61);
|
|
@@ -30421,12 +30714,15 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30421
30714
|
activeAttemptIds.delete(command.sessionId);
|
|
30422
30715
|
}
|
|
30423
30716
|
turn.finish();
|
|
30424
|
-
connectionRefresh.afterTurnFinished();
|
|
30425
30717
|
});
|
|
30426
30718
|
} catch (error61) {
|
|
30427
30719
|
console.error("Mobius daemon rejected a message", error61);
|
|
30428
|
-
|
|
30429
|
-
|
|
30720
|
+
failAndClose(
|
|
30721
|
+
new Error("Relay sent an invalid protocol message", { cause: error61 }),
|
|
30722
|
+
4008,
|
|
30723
|
+
"Invalid protocol message",
|
|
30724
|
+
"protocol"
|
|
30725
|
+
);
|
|
30430
30726
|
}
|
|
30431
30727
|
};
|
|
30432
30728
|
socket.addEventListener("close", handleClose);
|
|
@@ -30438,21 +30734,18 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30438
30734
|
return;
|
|
30439
30735
|
}
|
|
30440
30736
|
publisher.connect(socket);
|
|
30441
|
-
void Promise.all(reconnectingTurns.map((turn) => turn.completion)).then(
|
|
30442
|
-
connectionRefresh.afterTurnFinished
|
|
30443
|
-
);
|
|
30444
30737
|
},
|
|
30445
30738
|
(error61) => {
|
|
30446
30739
|
if (finished) {
|
|
30447
30740
|
return;
|
|
30448
30741
|
}
|
|
30449
30742
|
console.error("Mobius daemon could not reconcile active Agent turns", error61);
|
|
30450
|
-
|
|
30451
|
-
|
|
30743
|
+
failAndClose(
|
|
30744
|
+
new Error("Active Agent turn reconciliation failed", { cause: error61 }),
|
|
30452
30745
|
ACTIVE_TURN_RECONCILIATION_CLOSE_CODE,
|
|
30453
|
-
"Active Agent turn reconciliation failed"
|
|
30746
|
+
"Active Agent turn reconciliation failed",
|
|
30747
|
+
"reconciliation"
|
|
30454
30748
|
);
|
|
30455
|
-
rejectConnection();
|
|
30456
30749
|
}
|
|
30457
30750
|
);
|
|
30458
30751
|
if (signal.aborted) {
|
|
@@ -30496,6 +30789,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
30496
30789
|
const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
|
|
30497
30790
|
const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
|
|
30498
30791
|
const installationObserver = new DaemonInstallationObserver();
|
|
30792
|
+
const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);
|
|
30499
30793
|
const nativeSessions = new NativeSessionService(config2, directories, sessions, audit);
|
|
30500
30794
|
const installations = new AgentInstallationManager(
|
|
30501
30795
|
specifications,
|
|
@@ -30503,7 +30797,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
30503
30797
|
installationObserver,
|
|
30504
30798
|
installationAudit
|
|
30505
30799
|
);
|
|
30506
|
-
let
|
|
30800
|
+
let connectionEpoch = 0;
|
|
30507
30801
|
let connectionAnnounced = false;
|
|
30508
30802
|
const announceConnection = () => {
|
|
30509
30803
|
if (connectionAnnounced) {
|
|
@@ -30519,10 +30813,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
30519
30813
|
`
|
|
30520
30814
|
);
|
|
30521
30815
|
};
|
|
30522
|
-
const catalogPublication = publishAgentCatalogUntilAvailable(config2, signal, timer);
|
|
30816
|
+
const catalogPublication = publishAgentCatalogUntilAvailable(config2, diagnostics, signal, timer);
|
|
30523
30817
|
try {
|
|
30524
30818
|
await ipc.listen(signal);
|
|
30525
30819
|
while (!signal.aborted) {
|
|
30820
|
+
connectionEpoch += 1;
|
|
30526
30821
|
try {
|
|
30527
30822
|
await runRelayConnection(
|
|
30528
30823
|
config2,
|
|
@@ -30540,19 +30835,17 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
30540
30835
|
ipc,
|
|
30541
30836
|
activeTurns,
|
|
30542
30837
|
activeAttemptIds,
|
|
30838
|
+
connectionEpoch,
|
|
30839
|
+
diagnostics,
|
|
30543
30840
|
announceConnection,
|
|
30544
30841
|
signal,
|
|
30545
30842
|
timer
|
|
30546
30843
|
);
|
|
30547
|
-
|
|
30548
|
-
} catch {
|
|
30844
|
+
} catch (error61) {
|
|
30549
30845
|
if (signal.aborted) {
|
|
30550
30846
|
return;
|
|
30551
30847
|
}
|
|
30552
|
-
|
|
30553
|
-
console.warn("Mobius daemon is waiting for the relay");
|
|
30554
|
-
retryAnnounced = true;
|
|
30555
|
-
}
|
|
30848
|
+
diagnostics.connectionFailed(connectionEpoch, error61, "connection");
|
|
30556
30849
|
}
|
|
30557
30850
|
await waitForRelayRetry(signal, timer);
|
|
30558
30851
|
}
|