@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/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import { mkdir as mkdir5 } from "node:fs/promises";
|
|
|
11
11
|
// package.json
|
|
12
12
|
var package_default = {
|
|
13
13
|
name: "@moxt-ai/mobius",
|
|
14
|
-
version: "0.0.
|
|
14
|
+
version: "0.0.26",
|
|
15
15
|
description: "Mobius CLI for pairing and running local AI agent services.",
|
|
16
16
|
type: "module",
|
|
17
17
|
bin: {
|
|
@@ -1578,7 +1578,53 @@ import { fetch } from "undici";
|
|
|
1578
1578
|
|
|
1579
1579
|
// src/network/environment-proxy.ts
|
|
1580
1580
|
import { EnvHttpProxyAgent } from "undici";
|
|
1581
|
+
var configuredHttpProxy = process.env["http_proxy"] ?? process.env["HTTP_PROXY"] ?? "";
|
|
1582
|
+
var configuredHttpsProxy = process.env["https_proxy"] ?? process.env["HTTPS_PROXY"] ?? configuredHttpProxy;
|
|
1581
1583
|
var environmentProxyDispatcher = new EnvHttpProxyAgent();
|
|
1584
|
+
function bypassesProxy(target) {
|
|
1585
|
+
const noProxy = process.env["no_proxy"] ?? process.env["NO_PROXY"] ?? "";
|
|
1586
|
+
if (noProxy === "*") {
|
|
1587
|
+
return true;
|
|
1588
|
+
}
|
|
1589
|
+
const hostname4 = target.hostname.replace(/^\[|\]$/gu, "").toLowerCase();
|
|
1590
|
+
const defaultPort = target.protocol === "wss:" || target.protocol === "https:" ? 443 : 80;
|
|
1591
|
+
const port = Number.parseInt(target.port, 10) || defaultPort;
|
|
1592
|
+
for (const rawEntry of noProxy.split(/[,\s]/u)) {
|
|
1593
|
+
if (rawEntry.length === 0) {
|
|
1594
|
+
continue;
|
|
1595
|
+
}
|
|
1596
|
+
const parsed = rawEntry.match(/^(.+):(\d+)$/u);
|
|
1597
|
+
const entryHostname = (parsed?.[1] ?? rawEntry).replace(/^\*?\./u, "").toLowerCase();
|
|
1598
|
+
const entryPort = parsed?.[2] === void 0 ? 0 : Number.parseInt(parsed[2], 10);
|
|
1599
|
+
if (entryPort !== 0 && entryPort !== port) {
|
|
1600
|
+
continue;
|
|
1601
|
+
}
|
|
1602
|
+
if (hostname4 === entryHostname || hostname4.endsWith(`.${entryHostname}`)) {
|
|
1603
|
+
return true;
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
return false;
|
|
1607
|
+
}
|
|
1608
|
+
function sanitizedProxyOrigin(proxyUrl) {
|
|
1609
|
+
try {
|
|
1610
|
+
return new URL(proxyUrl).origin;
|
|
1611
|
+
} catch {
|
|
1612
|
+
return "configured-invalid-url";
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
function describeEnvironmentProxyRoute(target) {
|
|
1616
|
+
if (bypassesProxy(target)) {
|
|
1617
|
+
return { proxyRoute: "direct" };
|
|
1618
|
+
}
|
|
1619
|
+
const proxyUrl = target.protocol === "wss:" || target.protocol === "https:" ? configuredHttpsProxy : configuredHttpProxy;
|
|
1620
|
+
if (proxyUrl.length === 0) {
|
|
1621
|
+
return { proxyRoute: "direct" };
|
|
1622
|
+
}
|
|
1623
|
+
return {
|
|
1624
|
+
proxyOrigin: sanitizedProxyOrigin(proxyUrl),
|
|
1625
|
+
proxyRoute: "proxy"
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1582
1628
|
|
|
1583
1629
|
// src/agent-installation/managed-agent-archive.ts
|
|
1584
1630
|
var ARCHIVE_DOWNLOAD_LIMIT_BYTES = 128 * 1024 * 1024;
|
|
@@ -23205,6 +23251,7 @@ var encode4 = (message, schema) => {
|
|
|
23205
23251
|
}
|
|
23206
23252
|
return JSON.stringify(decoded.data);
|
|
23207
23253
|
};
|
|
23254
|
+
var decodeSessionEventEnvelope = (encoded) => decode5(encoded, eventEnvelopeSchema);
|
|
23208
23255
|
var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
|
|
23209
23256
|
var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
|
|
23210
23257
|
var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSchema);
|
|
@@ -29246,9 +29293,11 @@ import { WebSocket } from "undici";
|
|
|
29246
29293
|
var CONNECTION_TIMEOUT_MILLISECONDS = 15e3;
|
|
29247
29294
|
var RelayConnectionError = class extends Error {
|
|
29248
29295
|
code;
|
|
29249
|
-
|
|
29296
|
+
diagnosticDetails;
|
|
29297
|
+
constructor(code, message, diagnosticDetails = {}, options = {}) {
|
|
29250
29298
|
super(message, options);
|
|
29251
29299
|
this.code = code;
|
|
29300
|
+
this.diagnosticDetails = diagnosticDetails;
|
|
29252
29301
|
this.name = "RelayConnectionError";
|
|
29253
29302
|
}
|
|
29254
29303
|
};
|
|
@@ -29286,16 +29335,34 @@ function connectRelay(url2, signal) {
|
|
|
29286
29335
|
};
|
|
29287
29336
|
const onAbort = () => {
|
|
29288
29337
|
fail(
|
|
29289
|
-
new RelayConnectionError(
|
|
29290
|
-
|
|
29291
|
-
|
|
29338
|
+
new RelayConnectionError(
|
|
29339
|
+
"relay_connection_cancelled",
|
|
29340
|
+
"Relay connection was cancelled",
|
|
29341
|
+
{
|
|
29342
|
+
cancellation: "requested"
|
|
29343
|
+
},
|
|
29344
|
+
{ cause: signal.reason }
|
|
29345
|
+
)
|
|
29292
29346
|
);
|
|
29293
29347
|
};
|
|
29294
|
-
const onClose = () => {
|
|
29295
|
-
fail(
|
|
29348
|
+
const onClose = (event) => {
|
|
29349
|
+
fail(
|
|
29350
|
+
new RelayConnectionError("relay_connection_closed", "Relay connection closed before it was ready", {
|
|
29351
|
+
closeCode: event.code.toString(),
|
|
29352
|
+
closeReason: event.reason
|
|
29353
|
+
})
|
|
29354
|
+
);
|
|
29296
29355
|
};
|
|
29297
|
-
const onError = () => {
|
|
29298
|
-
|
|
29356
|
+
const onError = (event) => {
|
|
29357
|
+
const cause = Reflect.get(event, "error");
|
|
29358
|
+
fail(
|
|
29359
|
+
new RelayConnectionError(
|
|
29360
|
+
"relay_connection_failed",
|
|
29361
|
+
"Relay connection failed",
|
|
29362
|
+
{},
|
|
29363
|
+
{ cause: cause ?? event }
|
|
29364
|
+
)
|
|
29365
|
+
);
|
|
29299
29366
|
};
|
|
29300
29367
|
const onOpen = () => {
|
|
29301
29368
|
if (finished) {
|
|
@@ -29306,7 +29373,11 @@ function connectRelay(url2, signal) {
|
|
|
29306
29373
|
resolve5(socket);
|
|
29307
29374
|
};
|
|
29308
29375
|
function onTimeout() {
|
|
29309
|
-
fail(
|
|
29376
|
+
fail(
|
|
29377
|
+
new RelayConnectionError("relay_connection_timeout", "Relay connection timed out", {
|
|
29378
|
+
timeoutMilliseconds: CONNECTION_TIMEOUT_MILLISECONDS.toString()
|
|
29379
|
+
})
|
|
29380
|
+
);
|
|
29310
29381
|
}
|
|
29311
29382
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
29312
29383
|
socket.addEventListener("close", onClose, { once: true });
|
|
@@ -29318,6 +29389,142 @@ function connectRelay(url2, signal) {
|
|
|
29318
29389
|
});
|
|
29319
29390
|
}
|
|
29320
29391
|
|
|
29392
|
+
// src/relay-connection/diagnostics.ts
|
|
29393
|
+
var MAX_DIAGNOSTIC_TEXT_LENGTH = 256;
|
|
29394
|
+
function sanitizeDiagnosticText(value) {
|
|
29395
|
+
const printable = Array.from(value, (character) => {
|
|
29396
|
+
const code = character.charCodeAt(0);
|
|
29397
|
+
return code < 32 || code === 127 ? " " : character;
|
|
29398
|
+
}).join("");
|
|
29399
|
+
const withoutSecrets = printable.replace(/([?&](?:access_token|authorization|credential|key|secret|token)=)[^&\s]*/giu, "$1[redacted]").replace(/(?:https?|wss?):\/\/[^\s)]+/giu, (encodedUrl) => {
|
|
29400
|
+
try {
|
|
29401
|
+
return new URL(encodedUrl).origin;
|
|
29402
|
+
} catch {
|
|
29403
|
+
return "[redacted-url]";
|
|
29404
|
+
}
|
|
29405
|
+
});
|
|
29406
|
+
return withoutSecrets.slice(0, MAX_DIAGNOSTIC_TEXT_LENGTH);
|
|
29407
|
+
}
|
|
29408
|
+
function addFailureDetails(details, failure) {
|
|
29409
|
+
let current = failure;
|
|
29410
|
+
for (let depth = 0; depth < 3 && current instanceof Error; depth += 1) {
|
|
29411
|
+
const prefix = depth === 0 ? "failure" : `cause${depth.toString()}`;
|
|
29412
|
+
details[`${prefix}Name`] = current.name;
|
|
29413
|
+
details[`${prefix}Message`] = sanitizeDiagnosticText(current.message);
|
|
29414
|
+
const code = Reflect.get(current, "code");
|
|
29415
|
+
if (typeof code === "string" || typeof code === "number") {
|
|
29416
|
+
details[`${prefix}Code`] = String(code);
|
|
29417
|
+
}
|
|
29418
|
+
const statusCode = Reflect.get(current, "statusCode");
|
|
29419
|
+
if (typeof statusCode === "string" || typeof statusCode === "number") {
|
|
29420
|
+
details[`${prefix}StatusCode`] = String(statusCode);
|
|
29421
|
+
}
|
|
29422
|
+
const diagnosticDetails = Reflect.get(current, "diagnosticDetails");
|
|
29423
|
+
if (typeof diagnosticDetails === "object" && diagnosticDetails !== null) {
|
|
29424
|
+
for (const [key, value] of Object.entries(diagnosticDetails)) {
|
|
29425
|
+
if (typeof value === "string") {
|
|
29426
|
+
details[key] = sanitizeDiagnosticText(value);
|
|
29427
|
+
}
|
|
29428
|
+
}
|
|
29429
|
+
}
|
|
29430
|
+
current = current.cause;
|
|
29431
|
+
}
|
|
29432
|
+
}
|
|
29433
|
+
var RelayConnectionDiagnostics = class {
|
|
29434
|
+
#audit;
|
|
29435
|
+
#channelId;
|
|
29436
|
+
#lastClosedEpoch = 0;
|
|
29437
|
+
#lastFailedEpoch = 0;
|
|
29438
|
+
#relayOrigin;
|
|
29439
|
+
#route;
|
|
29440
|
+
constructor(audit, channelId, relayUrl) {
|
|
29441
|
+
this.#audit = audit;
|
|
29442
|
+
this.#channelId = channelId;
|
|
29443
|
+
this.#relayOrigin = relayUrl.origin;
|
|
29444
|
+
this.#route = describeEnvironmentProxyRoute(relayUrl);
|
|
29445
|
+
}
|
|
29446
|
+
catalogFailed = (failure) => {
|
|
29447
|
+
const details = { ...this.#route, relayOrigin: this.#relayOrigin };
|
|
29448
|
+
addFailureDetails(details, failure);
|
|
29449
|
+
this.#record("agent_catalog_publish_failed", "catalog", details, true);
|
|
29450
|
+
};
|
|
29451
|
+
connectionClosed = (connectionEpoch, code, reason, source) => {
|
|
29452
|
+
if (this.#lastClosedEpoch === connectionEpoch) {
|
|
29453
|
+
return;
|
|
29454
|
+
}
|
|
29455
|
+
this.#lastClosedEpoch = connectionEpoch;
|
|
29456
|
+
this.#record(
|
|
29457
|
+
"relay_connection_closed",
|
|
29458
|
+
connectionEpoch.toString(),
|
|
29459
|
+
{
|
|
29460
|
+
closeCode: code.toString(),
|
|
29461
|
+
closeReason: sanitizeDiagnosticText(reason),
|
|
29462
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29463
|
+
relayOrigin: this.#relayOrigin,
|
|
29464
|
+
source,
|
|
29465
|
+
...this.#route
|
|
29466
|
+
},
|
|
29467
|
+
true
|
|
29468
|
+
);
|
|
29469
|
+
};
|
|
29470
|
+
connectionFailed = (connectionEpoch, failure, source) => {
|
|
29471
|
+
if (this.#lastFailedEpoch === connectionEpoch) {
|
|
29472
|
+
return;
|
|
29473
|
+
}
|
|
29474
|
+
this.#lastFailedEpoch = connectionEpoch;
|
|
29475
|
+
const details = {
|
|
29476
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29477
|
+
relayOrigin: this.#relayOrigin,
|
|
29478
|
+
source,
|
|
29479
|
+
...this.#route
|
|
29480
|
+
};
|
|
29481
|
+
addFailureDetails(details, failure);
|
|
29482
|
+
this.#record("relay_connection_failed", connectionEpoch.toString(), details, true);
|
|
29483
|
+
};
|
|
29484
|
+
connectionOpened = (connectionEpoch) => {
|
|
29485
|
+
this.#record(
|
|
29486
|
+
"relay_connection_opened",
|
|
29487
|
+
connectionEpoch.toString(),
|
|
29488
|
+
{
|
|
29489
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29490
|
+
relayOrigin: this.#relayOrigin,
|
|
29491
|
+
...this.#route
|
|
29492
|
+
},
|
|
29493
|
+
false
|
|
29494
|
+
);
|
|
29495
|
+
};
|
|
29496
|
+
heartbeatTimedOut = (connectionEpoch, heartbeatId, timeoutMilliseconds) => {
|
|
29497
|
+
this.#record(
|
|
29498
|
+
"relay_heartbeat_timed_out",
|
|
29499
|
+
connectionEpoch.toString(),
|
|
29500
|
+
{
|
|
29501
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29502
|
+
heartbeatId,
|
|
29503
|
+
relayOrigin: this.#relayOrigin,
|
|
29504
|
+
timeoutMilliseconds: timeoutMilliseconds.toString(),
|
|
29505
|
+
...this.#route
|
|
29506
|
+
},
|
|
29507
|
+
true
|
|
29508
|
+
);
|
|
29509
|
+
};
|
|
29510
|
+
#record = (event, commandId, details, warning) => {
|
|
29511
|
+
this.#audit.record({
|
|
29512
|
+
commandId,
|
|
29513
|
+
details,
|
|
29514
|
+
event,
|
|
29515
|
+
sessionId: this.#channelId
|
|
29516
|
+
});
|
|
29517
|
+
const encoded = JSON.stringify({ channelId: this.#channelId, event, ...details });
|
|
29518
|
+
if (warning) {
|
|
29519
|
+
process.stderr.write(`Mobius relay diagnostic ${encoded}
|
|
29520
|
+
`);
|
|
29521
|
+
return;
|
|
29522
|
+
}
|
|
29523
|
+
process.stdout.write(`Mobius relay diagnostic ${encoded}
|
|
29524
|
+
`);
|
|
29525
|
+
};
|
|
29526
|
+
};
|
|
29527
|
+
|
|
29321
29528
|
// src/relay-connection/liveness.ts
|
|
29322
29529
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
29323
29530
|
var HEARTBEAT_ACK_TIMEOUT_MILLISECONDS = 1e4;
|
|
@@ -29394,9 +29601,10 @@ var RelayConnectionLiveness = class {
|
|
|
29394
29601
|
if (!(this.#state instanceof AwaitingHeartbeatAckState)) {
|
|
29395
29602
|
throw new Error("Heartbeat timeout occurred in an invalid state");
|
|
29396
29603
|
}
|
|
29604
|
+
const heartbeatId = this.#state.heartbeatId;
|
|
29397
29605
|
this.#state.timeout.cancel();
|
|
29398
29606
|
this.#state = new FinishedRelayLivenessState();
|
|
29399
|
-
this.#transport.unresponsive();
|
|
29607
|
+
this.#transport.unresponsive(heartbeatId, HEARTBEAT_ACK_TIMEOUT_MILLISECONDS);
|
|
29400
29608
|
};
|
|
29401
29609
|
#sendHeartbeat = () => {
|
|
29402
29610
|
if (this.#state instanceof WaitingForHeartbeatState) {
|
|
@@ -29445,6 +29653,7 @@ var SessionEventOutbox = class {
|
|
|
29445
29653
|
ordinal INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
29446
29654
|
event_id TEXT NOT NULL UNIQUE,
|
|
29447
29655
|
session_id TEXT NOT NULL,
|
|
29656
|
+
source_key TEXT NOT NULL,
|
|
29448
29657
|
envelope_json TEXT NOT NULL
|
|
29449
29658
|
) STRICT;
|
|
29450
29659
|
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
|
|
@@ -29472,6 +29681,27 @@ var SessionEventOutbox = class {
|
|
|
29472
29681
|
)
|
|
29473
29682
|
) STRICT;
|
|
29474
29683
|
`);
|
|
29684
|
+
const outboxColumns = this.#database.prepare("PRAGMA table_info(relay_session_event_outbox)").all();
|
|
29685
|
+
const hasSourceKey = outboxColumns.some(
|
|
29686
|
+
(column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "source_key"
|
|
29687
|
+
);
|
|
29688
|
+
if (!hasSourceKey) {
|
|
29689
|
+
this.#database.exec(`
|
|
29690
|
+
ALTER TABLE relay_session_event_outbox
|
|
29691
|
+
ADD COLUMN source_key TEXT NOT NULL DEFAULT '';
|
|
29692
|
+
`);
|
|
29693
|
+
}
|
|
29694
|
+
this.#database.exec(`
|
|
29695
|
+
UPDATE relay_session_event_outbox
|
|
29696
|
+
SET source_key = CASE json_extract(envelope_json, '$.source.kind')
|
|
29697
|
+
WHEN 'attempt' THEN
|
|
29698
|
+
'attempt:' || session_id || ':' || json_extract(envelope_json, '$.source.attemptId')
|
|
29699
|
+
ELSE 'runtime:' || session_id
|
|
29700
|
+
END
|
|
29701
|
+
WHERE source_key = '';
|
|
29702
|
+
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_source_order
|
|
29703
|
+
ON relay_session_event_outbox(source_key, ordinal);
|
|
29704
|
+
`);
|
|
29475
29705
|
}
|
|
29476
29706
|
claimExecution = (commandId, sessionId, commandJson) => {
|
|
29477
29707
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
@@ -29529,12 +29759,10 @@ var SessionEventOutbox = class {
|
|
|
29529
29759
|
const state = typeof row === "object" && row !== null ? Reflect.get(row, "state") : void 0;
|
|
29530
29760
|
return state === "succeeded" || state === "failed" || state === "cancelled";
|
|
29531
29761
|
};
|
|
29532
|
-
acknowledge = (acknowledgement) =>
|
|
29533
|
-
|
|
29534
|
-
`DELETE FROM relay_session_event_outbox
|
|
29762
|
+
acknowledge = (acknowledgement) => this.#database.prepare(
|
|
29763
|
+
`DELETE FROM relay_session_event_outbox
|
|
29535
29764
|
WHERE event_id = ? AND session_id = ?`
|
|
29536
|
-
|
|
29537
|
-
};
|
|
29765
|
+
).run(acknowledgement.eventId, acknowledgement.sessionId).changes === 1;
|
|
29538
29766
|
quarantine = (rejection) => {
|
|
29539
29767
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
29540
29768
|
try {
|
|
@@ -29601,9 +29829,9 @@ var SessionEventOutbox = class {
|
|
|
29601
29829
|
).run(sourceKey, nextSourceSeq + 1);
|
|
29602
29830
|
this.#database.prepare(
|
|
29603
29831
|
`INSERT INTO relay_session_event_outbox (
|
|
29604
|
-
event_id, session_id, envelope_json
|
|
29605
|
-
) VALUES (?, ?, ?)`
|
|
29606
|
-
).run(envelope2.eventId, envelope2.sessionId, encoded);
|
|
29832
|
+
event_id, session_id, source_key, envelope_json
|
|
29833
|
+
) VALUES (?, ?, ?, ?)`
|
|
29834
|
+
).run(envelope2.eventId, envelope2.sessionId, sourceKey, encoded);
|
|
29607
29835
|
this.#database.exec("COMMIT");
|
|
29608
29836
|
return encoded;
|
|
29609
29837
|
} catch (error61) {
|
|
@@ -29616,6 +29844,27 @@ var SessionEventOutbox = class {
|
|
|
29616
29844
|
FROM relay_session_event_outbox
|
|
29617
29845
|
ORDER BY ordinal`
|
|
29618
29846
|
).all().map(readPendingEnvelope);
|
|
29847
|
+
pendingBatch = (limit) => {
|
|
29848
|
+
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
29849
|
+
throw new Error("Session event replay batch limit must be a positive integer");
|
|
29850
|
+
}
|
|
29851
|
+
return this.#database.prepare(
|
|
29852
|
+
`WITH ranked_events AS (
|
|
29853
|
+
SELECT ordinal,
|
|
29854
|
+
ROW_NUMBER() OVER (
|
|
29855
|
+
PARTITION BY source_key
|
|
29856
|
+
ORDER BY ordinal
|
|
29857
|
+
) AS source_position
|
|
29858
|
+
FROM relay_session_event_outbox
|
|
29859
|
+
)
|
|
29860
|
+
SELECT outbox.envelope_json
|
|
29861
|
+
FROM ranked_events AS ranked
|
|
29862
|
+
INNER JOIN relay_session_event_outbox AS outbox
|
|
29863
|
+
ON outbox.ordinal = ranked.ordinal
|
|
29864
|
+
ORDER BY ranked.source_position, outbox.ordinal
|
|
29865
|
+
LIMIT ?`
|
|
29866
|
+
).all(limit).map(readPendingEnvelope);
|
|
29867
|
+
};
|
|
29619
29868
|
};
|
|
29620
29869
|
function isDaemonExecutionState(value) {
|
|
29621
29870
|
return value === "cancelled" || value === "dispatching" || value === "failed" || value === "running" || value === "succeeded";
|
|
@@ -29632,7 +29881,7 @@ var systemDaemonTimer = new SystemDaemonTimer();
|
|
|
29632
29881
|
|
|
29633
29882
|
// src/run-daemon.ts
|
|
29634
29883
|
var RELAY_RECONNECT_DELAY_MILLISECONDS = 500;
|
|
29635
|
-
var
|
|
29884
|
+
var AGENT_ACTIVITY_COALESCING_MILLISECONDS = 100;
|
|
29636
29885
|
var ACTIVE_TURN_RECONCILIATION_TIMEOUT_MILLISECONDS = 2e4;
|
|
29637
29886
|
var ACTIVE_TURN_RECONCILIATION_CLOSE_CODE = 4009;
|
|
29638
29887
|
function botIpcSocketPath() {
|
|
@@ -29641,54 +29890,6 @@ function botIpcSocketPath() {
|
|
|
29641
29890
|
}
|
|
29642
29891
|
return join16("/tmp", `mobius-bot-${randomUUID6()}.sock`);
|
|
29643
29892
|
}
|
|
29644
|
-
var RelayConnectionRefreshState = class {
|
|
29645
|
-
};
|
|
29646
|
-
var ScheduledRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29647
|
-
};
|
|
29648
|
-
var DueRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29649
|
-
};
|
|
29650
|
-
var FinishedRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29651
|
-
};
|
|
29652
|
-
var RelayConnectionRefresh = class {
|
|
29653
|
-
#isSafe;
|
|
29654
|
-
#refresh;
|
|
29655
|
-
#scheduledTask;
|
|
29656
|
-
#state = new ScheduledRelayConnectionRefreshState();
|
|
29657
|
-
constructor(timer, isSafe, refresh) {
|
|
29658
|
-
this.#isSafe = isSafe;
|
|
29659
|
-
this.#refresh = refresh;
|
|
29660
|
-
this.#scheduledTask = timer.schedule(this.#request, RELAY_CONNECTION_REFRESH_MILLISECONDS);
|
|
29661
|
-
}
|
|
29662
|
-
afterTurnFinished = () => {
|
|
29663
|
-
if (this.#state instanceof DueRelayConnectionRefreshState) {
|
|
29664
|
-
this.#request();
|
|
29665
|
-
return;
|
|
29666
|
-
}
|
|
29667
|
-
if (this.#state instanceof ScheduledRelayConnectionRefreshState || this.#state instanceof FinishedRelayConnectionRefreshState) {
|
|
29668
|
-
return;
|
|
29669
|
-
}
|
|
29670
|
-
throw new Error("Unknown relay connection refresh state");
|
|
29671
|
-
};
|
|
29672
|
-
close = () => {
|
|
29673
|
-
this.#scheduledTask.cancel();
|
|
29674
|
-
this.#state = new FinishedRelayConnectionRefreshState();
|
|
29675
|
-
};
|
|
29676
|
-
#request = () => {
|
|
29677
|
-
if (this.#state instanceof FinishedRelayConnectionRefreshState) {
|
|
29678
|
-
return;
|
|
29679
|
-
}
|
|
29680
|
-
if (!(this.#state instanceof ScheduledRelayConnectionRefreshState) && !(this.#state instanceof DueRelayConnectionRefreshState)) {
|
|
29681
|
-
throw new Error("Unknown relay connection refresh state");
|
|
29682
|
-
}
|
|
29683
|
-
if (!this.#isSafe()) {
|
|
29684
|
-
this.#state = new DueRelayConnectionRefreshState();
|
|
29685
|
-
return;
|
|
29686
|
-
}
|
|
29687
|
-
this.#state = new FinishedRelayConnectionRefreshState();
|
|
29688
|
-
this.#scheduledTask.cancel();
|
|
29689
|
-
this.#refresh();
|
|
29690
|
-
};
|
|
29691
|
-
};
|
|
29692
29893
|
var DaemonAcpObserver = class {
|
|
29693
29894
|
#record;
|
|
29694
29895
|
constructor(record2) {
|
|
@@ -29953,7 +30154,8 @@ var DaemonSessionEventConnectionState = class {
|
|
|
29953
30154
|
};
|
|
29954
30155
|
var DisconnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
|
|
29955
30156
|
disconnect = () => this;
|
|
29956
|
-
|
|
30157
|
+
matches = () => false;
|
|
30158
|
+
send = () => false;
|
|
29957
30159
|
};
|
|
29958
30160
|
var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
|
|
29959
30161
|
#socket;
|
|
@@ -29962,38 +30164,155 @@ var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectio
|
|
|
29962
30164
|
this.#socket = socket;
|
|
29963
30165
|
}
|
|
29964
30166
|
disconnect = (socket) => socket === this.#socket ? new DisconnectedDaemonSessionEventState() : this;
|
|
30167
|
+
matches = (socket) => socket === this.#socket;
|
|
29965
30168
|
send = (message) => {
|
|
29966
|
-
if (this.#socket.readyState
|
|
29967
|
-
|
|
29968
|
-
|
|
29969
|
-
|
|
29970
|
-
|
|
30169
|
+
if (this.#socket.readyState !== WebSocket2.OPEN) {
|
|
30170
|
+
return false;
|
|
30171
|
+
}
|
|
30172
|
+
try {
|
|
30173
|
+
this.#socket.send(message);
|
|
30174
|
+
return true;
|
|
30175
|
+
} catch {
|
|
30176
|
+
return false;
|
|
29971
30177
|
}
|
|
29972
30178
|
};
|
|
29973
30179
|
};
|
|
30180
|
+
var SESSION_EVENT_REPLAY_WINDOW = 4;
|
|
29974
30181
|
var DaemonSessionEventPublisher = class {
|
|
29975
30182
|
#outbox;
|
|
30183
|
+
#inFlightEventIds = /* @__PURE__ */ new Set();
|
|
29976
30184
|
#connection = new DisconnectedDaemonSessionEventState();
|
|
29977
30185
|
constructor(outbox) {
|
|
29978
30186
|
this.#outbox = outbox;
|
|
29979
30187
|
}
|
|
29980
30188
|
connect = (socket) => {
|
|
29981
|
-
|
|
29982
|
-
this.#
|
|
29983
|
-
|
|
29984
|
-
connection.send(pending);
|
|
29985
|
-
}
|
|
30189
|
+
this.#connection = new ConnectedDaemonSessionEventState(socket);
|
|
30190
|
+
this.#inFlightEventIds.clear();
|
|
30191
|
+
this.#publishNextBatch();
|
|
29986
30192
|
};
|
|
29987
30193
|
disconnect = (socket) => {
|
|
30194
|
+
if (!this.#connection.matches(socket)) {
|
|
30195
|
+
return;
|
|
30196
|
+
}
|
|
29988
30197
|
this.#connection = this.#connection.disconnect(socket);
|
|
30198
|
+
this.#inFlightEventIds.clear();
|
|
29989
30199
|
};
|
|
29990
30200
|
recordAttempt = (sessionId, payload, attemptId) => {
|
|
29991
|
-
this.#
|
|
30201
|
+
this.#outbox.enqueue(sessionId, payload, attemptId);
|
|
30202
|
+
this.#publishNextBatch();
|
|
29992
30203
|
};
|
|
29993
30204
|
recordRuntime = (sessionId, payload) => {
|
|
29994
|
-
this.#
|
|
30205
|
+
this.#outbox.enqueue(sessionId, payload);
|
|
30206
|
+
this.#publishNextBatch();
|
|
30207
|
+
};
|
|
30208
|
+
acknowledge = (acknowledgement) => {
|
|
30209
|
+
if (!this.#outbox.acknowledge(acknowledgement)) {
|
|
30210
|
+
return;
|
|
30211
|
+
}
|
|
30212
|
+
this.#inFlightEventIds.delete(acknowledgement.eventId);
|
|
30213
|
+
this.#publishNextBatch();
|
|
30214
|
+
};
|
|
30215
|
+
quarantine = (rejection) => {
|
|
30216
|
+
const quarantined = this.#outbox.quarantine(rejection);
|
|
30217
|
+
if (!quarantined) {
|
|
30218
|
+
return false;
|
|
30219
|
+
}
|
|
30220
|
+
this.#inFlightEventIds.delete(rejection.eventId);
|
|
30221
|
+
this.#publishNextBatch();
|
|
30222
|
+
return true;
|
|
30223
|
+
};
|
|
30224
|
+
#publishNextBatch = () => {
|
|
30225
|
+
if (this.#inFlightEventIds.size > 0) {
|
|
30226
|
+
return;
|
|
30227
|
+
}
|
|
30228
|
+
const batch = this.#outbox.pendingBatch(SESSION_EVENT_REPLAY_WINDOW);
|
|
30229
|
+
for (const encoded of batch) {
|
|
30230
|
+
const envelope2 = decodeSessionEventEnvelope(encoded);
|
|
30231
|
+
if (!this.#connection.send(encoded)) {
|
|
30232
|
+
this.#inFlightEventIds.clear();
|
|
30233
|
+
return;
|
|
30234
|
+
}
|
|
30235
|
+
this.#inFlightEventIds.add(envelope2.eventId);
|
|
30236
|
+
}
|
|
30237
|
+
};
|
|
30238
|
+
};
|
|
30239
|
+
var CoalescingDaemonActivityPublisher = class {
|
|
30240
|
+
#pending = /* @__PURE__ */ new Map();
|
|
30241
|
+
#publish;
|
|
30242
|
+
#publishedActivityIds = /* @__PURE__ */ new Set();
|
|
30243
|
+
#scheduled = /* @__PURE__ */ new Map();
|
|
30244
|
+
#timer;
|
|
30245
|
+
constructor(timer, publish) {
|
|
30246
|
+
this.#publish = publish;
|
|
30247
|
+
this.#timer = timer;
|
|
30248
|
+
}
|
|
30249
|
+
flush = () => {
|
|
30250
|
+
const activities = [...this.#pending.values()].sort((left, right) => left.sequence - right.sequence);
|
|
30251
|
+
for (const task of this.#scheduled.values()) {
|
|
30252
|
+
task.cancel();
|
|
30253
|
+
}
|
|
30254
|
+
this.#pending.clear();
|
|
30255
|
+
this.#scheduled.clear();
|
|
30256
|
+
for (const activity of activities) {
|
|
30257
|
+
this.#publish(activity);
|
|
30258
|
+
}
|
|
30259
|
+
};
|
|
30260
|
+
record = (activity) => {
|
|
30261
|
+
if (activity.status !== "pending" && activity.status !== "running") {
|
|
30262
|
+
this.#discardPending(activity.activityId);
|
|
30263
|
+
this.#publishedActivityIds.add(activity.activityId);
|
|
30264
|
+
this.#publish(activity);
|
|
30265
|
+
return Promise.resolve();
|
|
30266
|
+
}
|
|
30267
|
+
if (!this.#publishedActivityIds.has(activity.activityId)) {
|
|
30268
|
+
this.#publishedActivityIds.add(activity.activityId);
|
|
30269
|
+
this.#publish(activity);
|
|
30270
|
+
return Promise.resolve();
|
|
30271
|
+
}
|
|
30272
|
+
this.#pending.set(activity.activityId, activity);
|
|
30273
|
+
if (!this.#scheduled.has(activity.activityId)) {
|
|
30274
|
+
this.#scheduled.set(
|
|
30275
|
+
activity.activityId,
|
|
30276
|
+
this.#timer.schedule(
|
|
30277
|
+
() => this.#flushActivity(activity.activityId),
|
|
30278
|
+
AGENT_ACTIVITY_COALESCING_MILLISECONDS
|
|
30279
|
+
)
|
|
30280
|
+
);
|
|
30281
|
+
}
|
|
30282
|
+
return Promise.resolve();
|
|
30283
|
+
};
|
|
30284
|
+
#discardPending = (activityId) => {
|
|
30285
|
+
this.#scheduled.get(activityId)?.cancel();
|
|
30286
|
+
this.#scheduled.delete(activityId);
|
|
30287
|
+
this.#pending.delete(activityId);
|
|
30288
|
+
};
|
|
30289
|
+
#flushActivity = (activityId) => {
|
|
30290
|
+
const activity = this.#pending.get(activityId);
|
|
30291
|
+
this.#discardPending(activityId);
|
|
30292
|
+
if (activity !== void 0) {
|
|
30293
|
+
this.#publish(activity);
|
|
30294
|
+
}
|
|
29995
30295
|
};
|
|
29996
30296
|
};
|
|
30297
|
+
function encodeDaemonActivity(command, activity) {
|
|
30298
|
+
return encodeAgentActivityEvent({
|
|
30299
|
+
activityId: activity.activityId,
|
|
30300
|
+
activityType: activity.activityType,
|
|
30301
|
+
commandId: command.commandId,
|
|
30302
|
+
content: activity.content,
|
|
30303
|
+
detail: activity.detail,
|
|
30304
|
+
input: activity.input,
|
|
30305
|
+
kind: AGENT_ACTIVITY_KIND,
|
|
30306
|
+
locations: activity.locations,
|
|
30307
|
+
name: activity.name,
|
|
30308
|
+
output: activity.output,
|
|
30309
|
+
sequence: activity.sequence,
|
|
30310
|
+
sessionId: command.sessionId,
|
|
30311
|
+
status: activity.status,
|
|
30312
|
+
title: activity.title,
|
|
30313
|
+
toolKind: activity.toolKind
|
|
30314
|
+
});
|
|
30315
|
+
}
|
|
29997
30316
|
function reportFailure(publisher, command, code, message, attemptId) {
|
|
29998
30317
|
publisher.recordAttempt(
|
|
29999
30318
|
command.sessionId,
|
|
@@ -30170,7 +30489,10 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
|
|
|
30170
30489
|
reportOperationFailure(socket, command.requestId, command.sessionId, error61);
|
|
30171
30490
|
}
|
|
30172
30491
|
}
|
|
30173
|
-
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, signal) {
|
|
30492
|
+
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, timer, signal) {
|
|
30493
|
+
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
30494
|
+
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
30495
|
+
});
|
|
30174
30496
|
try {
|
|
30175
30497
|
const resolved = await resolveSessionDirectories(
|
|
30176
30498
|
directories,
|
|
@@ -30227,30 +30549,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30227
30549
|
cwd: resolved.cwd,
|
|
30228
30550
|
disposition: command.disposition,
|
|
30229
30551
|
images: attachments.images,
|
|
30230
|
-
onActivity:
|
|
30231
|
-
publisher.recordAttempt(
|
|
30232
|
-
command.sessionId,
|
|
30233
|
-
encodeAgentActivityEvent({
|
|
30234
|
-
activityId: activity.activityId,
|
|
30235
|
-
activityType: activity.activityType,
|
|
30236
|
-
commandId: command.commandId,
|
|
30237
|
-
content: activity.content,
|
|
30238
|
-
detail: activity.detail,
|
|
30239
|
-
input: activity.input,
|
|
30240
|
-
kind: AGENT_ACTIVITY_KIND,
|
|
30241
|
-
locations: activity.locations,
|
|
30242
|
-
name: activity.name,
|
|
30243
|
-
output: activity.output,
|
|
30244
|
-
sequence: activity.sequence,
|
|
30245
|
-
sessionId: command.sessionId,
|
|
30246
|
-
status: activity.status,
|
|
30247
|
-
title: activity.title,
|
|
30248
|
-
toolKind: activity.toolKind
|
|
30249
|
-
}),
|
|
30250
|
-
attemptId
|
|
30251
|
-
);
|
|
30252
|
-
return Promise.resolve();
|
|
30253
|
-
},
|
|
30552
|
+
onActivity: activities.record,
|
|
30254
30553
|
onText: (text, messageId) => {
|
|
30255
30554
|
publisher.recordAttempt(
|
|
30256
30555
|
command.sessionId,
|
|
@@ -30273,6 +30572,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30273
30572
|
});
|
|
30274
30573
|
stopReason = result.stopReason;
|
|
30275
30574
|
}
|
|
30575
|
+
activities.flush();
|
|
30276
30576
|
publisher.recordAttempt(
|
|
30277
30577
|
command.sessionId,
|
|
30278
30578
|
encodeSessionCompletedEvent({
|
|
@@ -30290,6 +30590,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30290
30590
|
sessionId: command.sessionId
|
|
30291
30591
|
});
|
|
30292
30592
|
} catch (error61) {
|
|
30593
|
+
activities.flush();
|
|
30293
30594
|
audit.record({
|
|
30294
30595
|
commandId: command.commandId,
|
|
30295
30596
|
event: "session_failed",
|
|
@@ -30328,7 +30629,10 @@ function botExecutionAgent(agent, contextHandle, socketPath) {
|
|
|
30328
30629
|
agent.capabilities
|
|
30329
30630
|
);
|
|
30330
30631
|
}
|
|
30331
|
-
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, signal) {
|
|
30632
|
+
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, timer, signal) {
|
|
30633
|
+
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
30634
|
+
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
30635
|
+
});
|
|
30332
30636
|
try {
|
|
30333
30637
|
const deadline = Date.parse(command.executionDeadlineAt);
|
|
30334
30638
|
const remaining = deadline - Date.now();
|
|
@@ -30412,30 +30716,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30412
30716
|
commandId: command.commandId,
|
|
30413
30717
|
cwd: resolved.cwd,
|
|
30414
30718
|
images: attachments.images,
|
|
30415
|
-
onActivity:
|
|
30416
|
-
publisher.recordAttempt(
|
|
30417
|
-
command.sessionId,
|
|
30418
|
-
encodeAgentActivityEvent({
|
|
30419
|
-
activityId: activity.activityId,
|
|
30420
|
-
activityType: activity.activityType,
|
|
30421
|
-
commandId: command.commandId,
|
|
30422
|
-
content: activity.content,
|
|
30423
|
-
detail: activity.detail,
|
|
30424
|
-
input: activity.input,
|
|
30425
|
-
kind: AGENT_ACTIVITY_KIND,
|
|
30426
|
-
locations: activity.locations,
|
|
30427
|
-
name: activity.name,
|
|
30428
|
-
output: activity.output,
|
|
30429
|
-
sequence: activity.sequence,
|
|
30430
|
-
sessionId: command.sessionId,
|
|
30431
|
-
status: activity.status,
|
|
30432
|
-
title: activity.title,
|
|
30433
|
-
toolKind: activity.toolKind
|
|
30434
|
-
}),
|
|
30435
|
-
attemptId
|
|
30436
|
-
);
|
|
30437
|
-
return Promise.resolve();
|
|
30438
|
-
},
|
|
30719
|
+
onActivity: activities.record,
|
|
30439
30720
|
onText: (text, messageId) => {
|
|
30440
30721
|
publisher.recordAttempt(
|
|
30441
30722
|
command.sessionId,
|
|
@@ -30455,6 +30736,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30455
30736
|
sessionId: command.sessionId,
|
|
30456
30737
|
signal: executionSignal
|
|
30457
30738
|
});
|
|
30739
|
+
activities.flush();
|
|
30458
30740
|
publisher.recordAttempt(
|
|
30459
30741
|
command.sessionId,
|
|
30460
30742
|
encodeSessionCompletedEvent({
|
|
@@ -30479,6 +30761,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30479
30761
|
lease.release();
|
|
30480
30762
|
}
|
|
30481
30763
|
} catch (error61) {
|
|
30764
|
+
activities.flush();
|
|
30482
30765
|
const failure = Date.parse(command.executionDeadlineAt) <= Date.now() ? new LocalBotAuthorizationError("turn_expired", "The Bot execution deadline has expired", {
|
|
30483
30766
|
cause: error61
|
|
30484
30767
|
}) : error61;
|
|
@@ -30518,15 +30801,15 @@ function waitForRelayRetry(signal, timer) {
|
|
|
30518
30801
|
signal.addEventListener("abort", finish, { once: true });
|
|
30519
30802
|
});
|
|
30520
30803
|
}
|
|
30521
|
-
async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
|
|
30804
|
+
async function publishAgentCatalogUntilAvailable(config2, diagnostics, signal, timer) {
|
|
30522
30805
|
try {
|
|
30523
30806
|
await publishAgentCatalog(config2, signal);
|
|
30524
30807
|
return;
|
|
30525
|
-
} catch {
|
|
30808
|
+
} catch (error61) {
|
|
30526
30809
|
if (signal.aborted) {
|
|
30527
30810
|
return;
|
|
30528
30811
|
}
|
|
30529
|
-
|
|
30812
|
+
diagnostics.catalogFailed(error61);
|
|
30530
30813
|
}
|
|
30531
30814
|
while (!signal.aborted) {
|
|
30532
30815
|
await waitForRelayRetry(signal, timer);
|
|
@@ -30540,11 +30823,12 @@ async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
|
|
|
30540
30823
|
}
|
|
30541
30824
|
}
|
|
30542
30825
|
}
|
|
30543
|
-
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, onConnected, signal, timer) {
|
|
30826
|
+
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, connectionEpoch, diagnostics, onConnected, signal, timer) {
|
|
30544
30827
|
const relayUrl = new URL(config2.relayUrl);
|
|
30545
30828
|
relayUrl.searchParams.set("liveness", "1");
|
|
30546
30829
|
const socket = await connectRelay(relayUrl, signal);
|
|
30547
30830
|
const reconnectingTurns = [...activeTurns.values()];
|
|
30831
|
+
diagnostics.connectionOpened(connectionEpoch);
|
|
30548
30832
|
onConnected();
|
|
30549
30833
|
const connectionController = new AbortController();
|
|
30550
30834
|
const nativeRequests = /* @__PURE__ */ new Map();
|
|
@@ -30553,7 +30837,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30553
30837
|
await new Promise((resolve5, reject) => {
|
|
30554
30838
|
let finished = false;
|
|
30555
30839
|
const cleanup = () => {
|
|
30556
|
-
connectionRefresh.close();
|
|
30557
30840
|
connectionLiveness.close();
|
|
30558
30841
|
signal.removeEventListener("abort", stop);
|
|
30559
30842
|
socket.removeEventListener("close", handleClose);
|
|
@@ -30571,61 +30854,70 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30571
30854
|
cleanup();
|
|
30572
30855
|
resolve5();
|
|
30573
30856
|
};
|
|
30574
|
-
const rejectConnection = () => {
|
|
30857
|
+
const rejectConnection = (failure) => {
|
|
30575
30858
|
if (finished) {
|
|
30576
30859
|
return;
|
|
30577
30860
|
}
|
|
30578
30861
|
finished = true;
|
|
30579
30862
|
cleanup();
|
|
30580
|
-
reject(
|
|
30863
|
+
reject(failure);
|
|
30581
30864
|
};
|
|
30582
30865
|
const stop = () => {
|
|
30866
|
+
diagnostics.connectionClosed(connectionEpoch, 1e3, "Daemon stopped", "daemon_stop");
|
|
30583
30867
|
closeRelaySocket(socket, 1e3, "Daemon stopped");
|
|
30584
30868
|
resolveConnection();
|
|
30585
30869
|
};
|
|
30586
|
-
const
|
|
30587
|
-
|
|
30588
|
-
|
|
30870
|
+
const failAndClose = (failure, code, reason, source) => {
|
|
30871
|
+
diagnostics.connectionFailed(connectionEpoch, failure, source);
|
|
30872
|
+
diagnostics.connectionClosed(connectionEpoch, code, reason, source);
|
|
30873
|
+
closeRelaySocket(socket, code, reason);
|
|
30874
|
+
rejectConnection(failure);
|
|
30589
30875
|
};
|
|
30590
30876
|
const connectionLiveness = new RelayConnectionLiveness(timer, {
|
|
30591
30877
|
send: (message) => send(socket, message),
|
|
30592
|
-
unresponsive: () => {
|
|
30878
|
+
unresponsive: (heartbeatId, timeoutMilliseconds) => {
|
|
30879
|
+
diagnostics.heartbeatTimedOut(connectionEpoch, heartbeatId, timeoutMilliseconds);
|
|
30880
|
+
diagnostics.connectionClosed(
|
|
30881
|
+
connectionEpoch,
|
|
30882
|
+
4001,
|
|
30883
|
+
"Relay liveness check timed out",
|
|
30884
|
+
"heartbeat_timeout"
|
|
30885
|
+
);
|
|
30593
30886
|
closeRelaySocket(socket, 4001, "Relay liveness check timed out");
|
|
30594
30887
|
resolveConnection();
|
|
30595
30888
|
}
|
|
30596
30889
|
});
|
|
30597
|
-
const connectionRefresh = new RelayConnectionRefresh(
|
|
30598
|
-
timer,
|
|
30599
|
-
() => activeTurns.size === 0,
|
|
30600
|
-
refreshConnection
|
|
30601
|
-
);
|
|
30602
30890
|
signal.addEventListener("abort", stop, { once: true });
|
|
30603
|
-
const handleClose = () => {
|
|
30891
|
+
const handleClose = (event) => {
|
|
30892
|
+
diagnostics.connectionClosed(connectionEpoch, event.code, event.reason, "relay");
|
|
30604
30893
|
resolveConnection();
|
|
30605
30894
|
};
|
|
30606
|
-
const handleError = () => {
|
|
30895
|
+
const handleError = (event) => {
|
|
30607
30896
|
if (signal.aborted) {
|
|
30608
30897
|
resolveConnection();
|
|
30609
30898
|
return;
|
|
30610
30899
|
}
|
|
30611
|
-
|
|
30900
|
+
const cause = Reflect.get(event, "error");
|
|
30901
|
+
const failure = new Error("Relay WebSocket emitted an error", { cause: cause ?? event });
|
|
30902
|
+
diagnostics.connectionFailed(connectionEpoch, failure, "socket_error");
|
|
30903
|
+
diagnostics.connectionClosed(connectionEpoch, 1006, "WebSocket error", "socket_error");
|
|
30904
|
+
rejectConnection(failure);
|
|
30612
30905
|
};
|
|
30613
30906
|
const handleMessage = (event) => {
|
|
30614
30907
|
const encoded = event.data;
|
|
30615
30908
|
if (typeof encoded !== "string") {
|
|
30616
|
-
|
|
30617
|
-
rejectConnection();
|
|
30909
|
+
failAndClose(new Error("Relay sent a non-text message"), 4003, "Text message required", "protocol");
|
|
30618
30910
|
return;
|
|
30619
30911
|
}
|
|
30620
30912
|
try {
|
|
30621
30913
|
const kind = decodeMessageKind(encoded);
|
|
30622
30914
|
if (kind === SESSION_EVENT_ACK_KIND) {
|
|
30623
|
-
|
|
30915
|
+
publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
|
|
30624
30916
|
return;
|
|
30625
30917
|
}
|
|
30626
30918
|
if (kind === SESSION_EVENT_REJECTED_KIND) {
|
|
30627
30919
|
const rejection = decodeSessionEventRejection(encoded);
|
|
30628
|
-
if (
|
|
30920
|
+
if (publisher.quarantine(rejection)) {
|
|
30629
30921
|
audit.record({
|
|
30630
30922
|
commandId: rejection.eventId,
|
|
30631
30923
|
details: { code: rejection.code },
|
|
@@ -31004,6 +31296,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31004
31296
|
applicator,
|
|
31005
31297
|
ipc,
|
|
31006
31298
|
receipt2.attemptId,
|
|
31299
|
+
timer,
|
|
31007
31300
|
turn2.signal
|
|
31008
31301
|
).catch((error61) => {
|
|
31009
31302
|
console.error("Mobius daemon Bot turn failed", error61);
|
|
@@ -31013,7 +31306,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31013
31306
|
activeAttemptIds.delete(command2.sessionId);
|
|
31014
31307
|
}
|
|
31015
31308
|
turn2.finish();
|
|
31016
|
-
connectionRefresh.afterTurnFinished();
|
|
31017
31309
|
});
|
|
31018
31310
|
return;
|
|
31019
31311
|
}
|
|
@@ -31042,6 +31334,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31042
31334
|
audit,
|
|
31043
31335
|
sessions,
|
|
31044
31336
|
receipt.attemptId,
|
|
31337
|
+
timer,
|
|
31045
31338
|
turn.signal
|
|
31046
31339
|
).catch((error61) => {
|
|
31047
31340
|
console.error("Mobius daemon turn failed", error61);
|
|
@@ -31051,12 +31344,15 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31051
31344
|
activeAttemptIds.delete(command.sessionId);
|
|
31052
31345
|
}
|
|
31053
31346
|
turn.finish();
|
|
31054
|
-
connectionRefresh.afterTurnFinished();
|
|
31055
31347
|
});
|
|
31056
31348
|
} catch (error61) {
|
|
31057
31349
|
console.error("Mobius daemon rejected a message", error61);
|
|
31058
|
-
|
|
31059
|
-
|
|
31350
|
+
failAndClose(
|
|
31351
|
+
new Error("Relay sent an invalid protocol message", { cause: error61 }),
|
|
31352
|
+
4008,
|
|
31353
|
+
"Invalid protocol message",
|
|
31354
|
+
"protocol"
|
|
31355
|
+
);
|
|
31060
31356
|
}
|
|
31061
31357
|
};
|
|
31062
31358
|
socket.addEventListener("close", handleClose);
|
|
@@ -31068,21 +31364,18 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31068
31364
|
return;
|
|
31069
31365
|
}
|
|
31070
31366
|
publisher.connect(socket);
|
|
31071
|
-
void Promise.all(reconnectingTurns.map((turn) => turn.completion)).then(
|
|
31072
|
-
connectionRefresh.afterTurnFinished
|
|
31073
|
-
);
|
|
31074
31367
|
},
|
|
31075
31368
|
(error61) => {
|
|
31076
31369
|
if (finished) {
|
|
31077
31370
|
return;
|
|
31078
31371
|
}
|
|
31079
31372
|
console.error("Mobius daemon could not reconcile active Agent turns", error61);
|
|
31080
|
-
|
|
31081
|
-
|
|
31373
|
+
failAndClose(
|
|
31374
|
+
new Error("Active Agent turn reconciliation failed", { cause: error61 }),
|
|
31082
31375
|
ACTIVE_TURN_RECONCILIATION_CLOSE_CODE,
|
|
31083
|
-
"Active Agent turn reconciliation failed"
|
|
31376
|
+
"Active Agent turn reconciliation failed",
|
|
31377
|
+
"reconciliation"
|
|
31084
31378
|
);
|
|
31085
|
-
rejectConnection();
|
|
31086
31379
|
}
|
|
31087
31380
|
);
|
|
31088
31381
|
if (signal.aborted) {
|
|
@@ -31126,6 +31419,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31126
31419
|
const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
|
|
31127
31420
|
const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
|
|
31128
31421
|
const installationObserver = new DaemonInstallationObserver();
|
|
31422
|
+
const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);
|
|
31129
31423
|
const nativeSessions = new NativeSessionService(config2, directories, sessions, audit);
|
|
31130
31424
|
const installations = new AgentInstallationManager(
|
|
31131
31425
|
specifications,
|
|
@@ -31133,7 +31427,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31133
31427
|
installationObserver,
|
|
31134
31428
|
installationAudit
|
|
31135
31429
|
);
|
|
31136
|
-
let
|
|
31430
|
+
let connectionEpoch = 0;
|
|
31137
31431
|
let connectionAnnounced = false;
|
|
31138
31432
|
const announceConnection = () => {
|
|
31139
31433
|
if (connectionAnnounced) {
|
|
@@ -31149,10 +31443,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31149
31443
|
`
|
|
31150
31444
|
);
|
|
31151
31445
|
};
|
|
31152
|
-
const catalogPublication = publishAgentCatalogUntilAvailable(config2, signal, timer);
|
|
31446
|
+
const catalogPublication = publishAgentCatalogUntilAvailable(config2, diagnostics, signal, timer);
|
|
31153
31447
|
try {
|
|
31154
31448
|
await ipc.listen(signal);
|
|
31155
31449
|
while (!signal.aborted) {
|
|
31450
|
+
connectionEpoch += 1;
|
|
31156
31451
|
try {
|
|
31157
31452
|
await runRelayConnection(
|
|
31158
31453
|
config2,
|
|
@@ -31170,19 +31465,17 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31170
31465
|
ipc,
|
|
31171
31466
|
activeTurns,
|
|
31172
31467
|
activeAttemptIds,
|
|
31468
|
+
connectionEpoch,
|
|
31469
|
+
diagnostics,
|
|
31173
31470
|
announceConnection,
|
|
31174
31471
|
signal,
|
|
31175
31472
|
timer
|
|
31176
31473
|
);
|
|
31177
|
-
|
|
31178
|
-
} catch {
|
|
31474
|
+
} catch (error61) {
|
|
31179
31475
|
if (signal.aborted) {
|
|
31180
31476
|
return;
|
|
31181
31477
|
}
|
|
31182
|
-
|
|
31183
|
-
console.warn("Mobius daemon is waiting for the relay");
|
|
31184
|
-
retryAnnounced = true;
|
|
31185
|
-
}
|
|
31478
|
+
diagnostics.connectionFailed(connectionEpoch, error61, "connection");
|
|
31186
31479
|
}
|
|
31187
31480
|
await waitForRelayRetry(signal, timer);
|
|
31188
31481
|
}
|