@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/index.js
CHANGED
|
@@ -20497,6 +20497,7 @@ var encode4 = (message, schema) => {
|
|
|
20497
20497
|
}
|
|
20498
20498
|
return JSON.stringify(decoded.data);
|
|
20499
20499
|
};
|
|
20500
|
+
var decodeSessionEventEnvelope = (encoded) => decode5(encoded, eventEnvelopeSchema);
|
|
20500
20501
|
var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
|
|
20501
20502
|
var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
|
|
20502
20503
|
var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSchema);
|
|
@@ -26286,7 +26287,53 @@ import { fetch as fetch2 } from "undici";
|
|
|
26286
26287
|
|
|
26287
26288
|
// src/network/environment-proxy.ts
|
|
26288
26289
|
import { EnvHttpProxyAgent } from "undici";
|
|
26290
|
+
var configuredHttpProxy = process.env["http_proxy"] ?? process.env["HTTP_PROXY"] ?? "";
|
|
26291
|
+
var configuredHttpsProxy = process.env["https_proxy"] ?? process.env["HTTPS_PROXY"] ?? configuredHttpProxy;
|
|
26289
26292
|
var environmentProxyDispatcher = new EnvHttpProxyAgent();
|
|
26293
|
+
function bypassesProxy(target) {
|
|
26294
|
+
const noProxy = process.env["no_proxy"] ?? process.env["NO_PROXY"] ?? "";
|
|
26295
|
+
if (noProxy === "*") {
|
|
26296
|
+
return true;
|
|
26297
|
+
}
|
|
26298
|
+
const hostname4 = target.hostname.replace(/^\[|\]$/gu, "").toLowerCase();
|
|
26299
|
+
const defaultPort = target.protocol === "wss:" || target.protocol === "https:" ? 443 : 80;
|
|
26300
|
+
const port = Number.parseInt(target.port, 10) || defaultPort;
|
|
26301
|
+
for (const rawEntry of noProxy.split(/[,\s]/u)) {
|
|
26302
|
+
if (rawEntry.length === 0) {
|
|
26303
|
+
continue;
|
|
26304
|
+
}
|
|
26305
|
+
const parsed = rawEntry.match(/^(.+):(\d+)$/u);
|
|
26306
|
+
const entryHostname = (parsed?.[1] ?? rawEntry).replace(/^\*?\./u, "").toLowerCase();
|
|
26307
|
+
const entryPort = parsed?.[2] === void 0 ? 0 : Number.parseInt(parsed[2], 10);
|
|
26308
|
+
if (entryPort !== 0 && entryPort !== port) {
|
|
26309
|
+
continue;
|
|
26310
|
+
}
|
|
26311
|
+
if (hostname4 === entryHostname || hostname4.endsWith(`.${entryHostname}`)) {
|
|
26312
|
+
return true;
|
|
26313
|
+
}
|
|
26314
|
+
}
|
|
26315
|
+
return false;
|
|
26316
|
+
}
|
|
26317
|
+
function sanitizedProxyOrigin(proxyUrl) {
|
|
26318
|
+
try {
|
|
26319
|
+
return new URL(proxyUrl).origin;
|
|
26320
|
+
} catch {
|
|
26321
|
+
return "configured-invalid-url";
|
|
26322
|
+
}
|
|
26323
|
+
}
|
|
26324
|
+
function describeEnvironmentProxyRoute(target) {
|
|
26325
|
+
if (bypassesProxy(target)) {
|
|
26326
|
+
return { proxyRoute: "direct" };
|
|
26327
|
+
}
|
|
26328
|
+
const proxyUrl = target.protocol === "wss:" || target.protocol === "https:" ? configuredHttpsProxy : configuredHttpProxy;
|
|
26329
|
+
if (proxyUrl.length === 0) {
|
|
26330
|
+
return { proxyRoute: "direct" };
|
|
26331
|
+
}
|
|
26332
|
+
return {
|
|
26333
|
+
proxyOrigin: sanitizedProxyOrigin(proxyUrl),
|
|
26334
|
+
proxyRoute: "proxy"
|
|
26335
|
+
};
|
|
26336
|
+
}
|
|
26290
26337
|
|
|
26291
26338
|
// src/agent-installation/managed-agent-archive.ts
|
|
26292
26339
|
var ARCHIVE_DOWNLOAD_LIMIT_BYTES = 128 * 1024 * 1024;
|
|
@@ -29181,9 +29228,11 @@ import { WebSocket } from "undici";
|
|
|
29181
29228
|
var CONNECTION_TIMEOUT_MILLISECONDS = 15e3;
|
|
29182
29229
|
var RelayConnectionError = class extends Error {
|
|
29183
29230
|
code;
|
|
29184
|
-
|
|
29231
|
+
diagnosticDetails;
|
|
29232
|
+
constructor(code, message, diagnosticDetails = {}, options = {}) {
|
|
29185
29233
|
super(message, options);
|
|
29186
29234
|
this.code = code;
|
|
29235
|
+
this.diagnosticDetails = diagnosticDetails;
|
|
29187
29236
|
this.name = "RelayConnectionError";
|
|
29188
29237
|
}
|
|
29189
29238
|
};
|
|
@@ -29221,16 +29270,34 @@ function connectRelay(url2, signal) {
|
|
|
29221
29270
|
};
|
|
29222
29271
|
const onAbort = () => {
|
|
29223
29272
|
fail(
|
|
29224
|
-
new RelayConnectionError(
|
|
29225
|
-
|
|
29226
|
-
|
|
29273
|
+
new RelayConnectionError(
|
|
29274
|
+
"relay_connection_cancelled",
|
|
29275
|
+
"Relay connection was cancelled",
|
|
29276
|
+
{
|
|
29277
|
+
cancellation: "requested"
|
|
29278
|
+
},
|
|
29279
|
+
{ cause: signal.reason }
|
|
29280
|
+
)
|
|
29227
29281
|
);
|
|
29228
29282
|
};
|
|
29229
|
-
const onClose = () => {
|
|
29230
|
-
fail(
|
|
29283
|
+
const onClose = (event) => {
|
|
29284
|
+
fail(
|
|
29285
|
+
new RelayConnectionError("relay_connection_closed", "Relay connection closed before it was ready", {
|
|
29286
|
+
closeCode: event.code.toString(),
|
|
29287
|
+
closeReason: event.reason
|
|
29288
|
+
})
|
|
29289
|
+
);
|
|
29231
29290
|
};
|
|
29232
|
-
const onError = () => {
|
|
29233
|
-
|
|
29291
|
+
const onError = (event) => {
|
|
29292
|
+
const cause = Reflect.get(event, "error");
|
|
29293
|
+
fail(
|
|
29294
|
+
new RelayConnectionError(
|
|
29295
|
+
"relay_connection_failed",
|
|
29296
|
+
"Relay connection failed",
|
|
29297
|
+
{},
|
|
29298
|
+
{ cause: cause ?? event }
|
|
29299
|
+
)
|
|
29300
|
+
);
|
|
29234
29301
|
};
|
|
29235
29302
|
const onOpen = () => {
|
|
29236
29303
|
if (finished) {
|
|
@@ -29241,7 +29308,11 @@ function connectRelay(url2, signal) {
|
|
|
29241
29308
|
resolve6(socket);
|
|
29242
29309
|
};
|
|
29243
29310
|
function onTimeout() {
|
|
29244
|
-
fail(
|
|
29311
|
+
fail(
|
|
29312
|
+
new RelayConnectionError("relay_connection_timeout", "Relay connection timed out", {
|
|
29313
|
+
timeoutMilliseconds: CONNECTION_TIMEOUT_MILLISECONDS.toString()
|
|
29314
|
+
})
|
|
29315
|
+
);
|
|
29245
29316
|
}
|
|
29246
29317
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
29247
29318
|
socket.addEventListener("close", onClose, { once: true });
|
|
@@ -29253,6 +29324,142 @@ function connectRelay(url2, signal) {
|
|
|
29253
29324
|
});
|
|
29254
29325
|
}
|
|
29255
29326
|
|
|
29327
|
+
// src/relay-connection/diagnostics.ts
|
|
29328
|
+
var MAX_DIAGNOSTIC_TEXT_LENGTH = 256;
|
|
29329
|
+
function sanitizeDiagnosticText(value) {
|
|
29330
|
+
const printable = Array.from(value, (character) => {
|
|
29331
|
+
const code = character.charCodeAt(0);
|
|
29332
|
+
return code < 32 || code === 127 ? " " : character;
|
|
29333
|
+
}).join("");
|
|
29334
|
+
const withoutSecrets = printable.replace(/([?&](?:access_token|authorization|credential|key|secret|token)=)[^&\s]*/giu, "$1[redacted]").replace(/(?:https?|wss?):\/\/[^\s)]+/giu, (encodedUrl) => {
|
|
29335
|
+
try {
|
|
29336
|
+
return new URL(encodedUrl).origin;
|
|
29337
|
+
} catch {
|
|
29338
|
+
return "[redacted-url]";
|
|
29339
|
+
}
|
|
29340
|
+
});
|
|
29341
|
+
return withoutSecrets.slice(0, MAX_DIAGNOSTIC_TEXT_LENGTH);
|
|
29342
|
+
}
|
|
29343
|
+
function addFailureDetails(details, failure) {
|
|
29344
|
+
let current = failure;
|
|
29345
|
+
for (let depth = 0; depth < 3 && current instanceof Error; depth += 1) {
|
|
29346
|
+
const prefix = depth === 0 ? "failure" : `cause${depth.toString()}`;
|
|
29347
|
+
details[`${prefix}Name`] = current.name;
|
|
29348
|
+
details[`${prefix}Message`] = sanitizeDiagnosticText(current.message);
|
|
29349
|
+
const code = Reflect.get(current, "code");
|
|
29350
|
+
if (typeof code === "string" || typeof code === "number") {
|
|
29351
|
+
details[`${prefix}Code`] = String(code);
|
|
29352
|
+
}
|
|
29353
|
+
const statusCode = Reflect.get(current, "statusCode");
|
|
29354
|
+
if (typeof statusCode === "string" || typeof statusCode === "number") {
|
|
29355
|
+
details[`${prefix}StatusCode`] = String(statusCode);
|
|
29356
|
+
}
|
|
29357
|
+
const diagnosticDetails = Reflect.get(current, "diagnosticDetails");
|
|
29358
|
+
if (typeof diagnosticDetails === "object" && diagnosticDetails !== null) {
|
|
29359
|
+
for (const [key, value] of Object.entries(diagnosticDetails)) {
|
|
29360
|
+
if (typeof value === "string") {
|
|
29361
|
+
details[key] = sanitizeDiagnosticText(value);
|
|
29362
|
+
}
|
|
29363
|
+
}
|
|
29364
|
+
}
|
|
29365
|
+
current = current.cause;
|
|
29366
|
+
}
|
|
29367
|
+
}
|
|
29368
|
+
var RelayConnectionDiagnostics = class {
|
|
29369
|
+
#audit;
|
|
29370
|
+
#channelId;
|
|
29371
|
+
#lastClosedEpoch = 0;
|
|
29372
|
+
#lastFailedEpoch = 0;
|
|
29373
|
+
#relayOrigin;
|
|
29374
|
+
#route;
|
|
29375
|
+
constructor(audit, channelId, relayUrl) {
|
|
29376
|
+
this.#audit = audit;
|
|
29377
|
+
this.#channelId = channelId;
|
|
29378
|
+
this.#relayOrigin = relayUrl.origin;
|
|
29379
|
+
this.#route = describeEnvironmentProxyRoute(relayUrl);
|
|
29380
|
+
}
|
|
29381
|
+
catalogFailed = (failure) => {
|
|
29382
|
+
const details = { ...this.#route, relayOrigin: this.#relayOrigin };
|
|
29383
|
+
addFailureDetails(details, failure);
|
|
29384
|
+
this.#record("agent_catalog_publish_failed", "catalog", details, true);
|
|
29385
|
+
};
|
|
29386
|
+
connectionClosed = (connectionEpoch, code, reason, source) => {
|
|
29387
|
+
if (this.#lastClosedEpoch === connectionEpoch) {
|
|
29388
|
+
return;
|
|
29389
|
+
}
|
|
29390
|
+
this.#lastClosedEpoch = connectionEpoch;
|
|
29391
|
+
this.#record(
|
|
29392
|
+
"relay_connection_closed",
|
|
29393
|
+
connectionEpoch.toString(),
|
|
29394
|
+
{
|
|
29395
|
+
closeCode: code.toString(),
|
|
29396
|
+
closeReason: sanitizeDiagnosticText(reason),
|
|
29397
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29398
|
+
relayOrigin: this.#relayOrigin,
|
|
29399
|
+
source,
|
|
29400
|
+
...this.#route
|
|
29401
|
+
},
|
|
29402
|
+
true
|
|
29403
|
+
);
|
|
29404
|
+
};
|
|
29405
|
+
connectionFailed = (connectionEpoch, failure, source) => {
|
|
29406
|
+
if (this.#lastFailedEpoch === connectionEpoch) {
|
|
29407
|
+
return;
|
|
29408
|
+
}
|
|
29409
|
+
this.#lastFailedEpoch = connectionEpoch;
|
|
29410
|
+
const details = {
|
|
29411
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29412
|
+
relayOrigin: this.#relayOrigin,
|
|
29413
|
+
source,
|
|
29414
|
+
...this.#route
|
|
29415
|
+
};
|
|
29416
|
+
addFailureDetails(details, failure);
|
|
29417
|
+
this.#record("relay_connection_failed", connectionEpoch.toString(), details, true);
|
|
29418
|
+
};
|
|
29419
|
+
connectionOpened = (connectionEpoch) => {
|
|
29420
|
+
this.#record(
|
|
29421
|
+
"relay_connection_opened",
|
|
29422
|
+
connectionEpoch.toString(),
|
|
29423
|
+
{
|
|
29424
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29425
|
+
relayOrigin: this.#relayOrigin,
|
|
29426
|
+
...this.#route
|
|
29427
|
+
},
|
|
29428
|
+
false
|
|
29429
|
+
);
|
|
29430
|
+
};
|
|
29431
|
+
heartbeatTimedOut = (connectionEpoch, heartbeatId, timeoutMilliseconds) => {
|
|
29432
|
+
this.#record(
|
|
29433
|
+
"relay_heartbeat_timed_out",
|
|
29434
|
+
connectionEpoch.toString(),
|
|
29435
|
+
{
|
|
29436
|
+
connectionEpoch: connectionEpoch.toString(),
|
|
29437
|
+
heartbeatId,
|
|
29438
|
+
relayOrigin: this.#relayOrigin,
|
|
29439
|
+
timeoutMilliseconds: timeoutMilliseconds.toString(),
|
|
29440
|
+
...this.#route
|
|
29441
|
+
},
|
|
29442
|
+
true
|
|
29443
|
+
);
|
|
29444
|
+
};
|
|
29445
|
+
#record = (event, commandId, details, warning) => {
|
|
29446
|
+
this.#audit.record({
|
|
29447
|
+
commandId,
|
|
29448
|
+
details,
|
|
29449
|
+
event,
|
|
29450
|
+
sessionId: this.#channelId
|
|
29451
|
+
});
|
|
29452
|
+
const encoded = JSON.stringify({ channelId: this.#channelId, event, ...details });
|
|
29453
|
+
if (warning) {
|
|
29454
|
+
process.stderr.write(`Mobius relay diagnostic ${encoded}
|
|
29455
|
+
`);
|
|
29456
|
+
return;
|
|
29457
|
+
}
|
|
29458
|
+
process.stdout.write(`Mobius relay diagnostic ${encoded}
|
|
29459
|
+
`);
|
|
29460
|
+
};
|
|
29461
|
+
};
|
|
29462
|
+
|
|
29256
29463
|
// src/relay-connection/liveness.ts
|
|
29257
29464
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
29258
29465
|
var HEARTBEAT_ACK_TIMEOUT_MILLISECONDS = 1e4;
|
|
@@ -29329,9 +29536,10 @@ var RelayConnectionLiveness = class {
|
|
|
29329
29536
|
if (!(this.#state instanceof AwaitingHeartbeatAckState)) {
|
|
29330
29537
|
throw new Error("Heartbeat timeout occurred in an invalid state");
|
|
29331
29538
|
}
|
|
29539
|
+
const heartbeatId = this.#state.heartbeatId;
|
|
29332
29540
|
this.#state.timeout.cancel();
|
|
29333
29541
|
this.#state = new FinishedRelayLivenessState();
|
|
29334
|
-
this.#transport.unresponsive();
|
|
29542
|
+
this.#transport.unresponsive(heartbeatId, HEARTBEAT_ACK_TIMEOUT_MILLISECONDS);
|
|
29335
29543
|
};
|
|
29336
29544
|
#sendHeartbeat = () => {
|
|
29337
29545
|
if (this.#state instanceof WaitingForHeartbeatState) {
|
|
@@ -29380,6 +29588,7 @@ var SessionEventOutbox = class {
|
|
|
29380
29588
|
ordinal INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
29381
29589
|
event_id TEXT NOT NULL UNIQUE,
|
|
29382
29590
|
session_id TEXT NOT NULL,
|
|
29591
|
+
source_key TEXT NOT NULL,
|
|
29383
29592
|
envelope_json TEXT NOT NULL
|
|
29384
29593
|
) STRICT;
|
|
29385
29594
|
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
|
|
@@ -29407,6 +29616,27 @@ var SessionEventOutbox = class {
|
|
|
29407
29616
|
)
|
|
29408
29617
|
) STRICT;
|
|
29409
29618
|
`);
|
|
29619
|
+
const outboxColumns = this.#database.prepare("PRAGMA table_info(relay_session_event_outbox)").all();
|
|
29620
|
+
const hasSourceKey = outboxColumns.some(
|
|
29621
|
+
(column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "source_key"
|
|
29622
|
+
);
|
|
29623
|
+
if (!hasSourceKey) {
|
|
29624
|
+
this.#database.exec(`
|
|
29625
|
+
ALTER TABLE relay_session_event_outbox
|
|
29626
|
+
ADD COLUMN source_key TEXT NOT NULL DEFAULT '';
|
|
29627
|
+
`);
|
|
29628
|
+
}
|
|
29629
|
+
this.#database.exec(`
|
|
29630
|
+
UPDATE relay_session_event_outbox
|
|
29631
|
+
SET source_key = CASE json_extract(envelope_json, '$.source.kind')
|
|
29632
|
+
WHEN 'attempt' THEN
|
|
29633
|
+
'attempt:' || session_id || ':' || json_extract(envelope_json, '$.source.attemptId')
|
|
29634
|
+
ELSE 'runtime:' || session_id
|
|
29635
|
+
END
|
|
29636
|
+
WHERE source_key = '';
|
|
29637
|
+
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_source_order
|
|
29638
|
+
ON relay_session_event_outbox(source_key, ordinal);
|
|
29639
|
+
`);
|
|
29410
29640
|
}
|
|
29411
29641
|
claimExecution = (commandId, sessionId, commandJson) => {
|
|
29412
29642
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
@@ -29464,12 +29694,10 @@ var SessionEventOutbox = class {
|
|
|
29464
29694
|
const state = typeof row === "object" && row !== null ? Reflect.get(row, "state") : void 0;
|
|
29465
29695
|
return state === "succeeded" || state === "failed" || state === "cancelled";
|
|
29466
29696
|
};
|
|
29467
|
-
acknowledge = (acknowledgement) =>
|
|
29468
|
-
|
|
29469
|
-
`DELETE FROM relay_session_event_outbox
|
|
29697
|
+
acknowledge = (acknowledgement) => this.#database.prepare(
|
|
29698
|
+
`DELETE FROM relay_session_event_outbox
|
|
29470
29699
|
WHERE event_id = ? AND session_id = ?`
|
|
29471
|
-
|
|
29472
|
-
};
|
|
29700
|
+
).run(acknowledgement.eventId, acknowledgement.sessionId).changes === 1;
|
|
29473
29701
|
quarantine = (rejection) => {
|
|
29474
29702
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
29475
29703
|
try {
|
|
@@ -29536,9 +29764,9 @@ var SessionEventOutbox = class {
|
|
|
29536
29764
|
).run(sourceKey, nextSourceSeq + 1);
|
|
29537
29765
|
this.#database.prepare(
|
|
29538
29766
|
`INSERT INTO relay_session_event_outbox (
|
|
29539
|
-
event_id, session_id, envelope_json
|
|
29540
|
-
) VALUES (?, ?, ?)`
|
|
29541
|
-
).run(envelope2.eventId, envelope2.sessionId, encoded);
|
|
29767
|
+
event_id, session_id, source_key, envelope_json
|
|
29768
|
+
) VALUES (?, ?, ?, ?)`
|
|
29769
|
+
).run(envelope2.eventId, envelope2.sessionId, sourceKey, encoded);
|
|
29542
29770
|
this.#database.exec("COMMIT");
|
|
29543
29771
|
return encoded;
|
|
29544
29772
|
} catch (error61) {
|
|
@@ -29551,6 +29779,27 @@ var SessionEventOutbox = class {
|
|
|
29551
29779
|
FROM relay_session_event_outbox
|
|
29552
29780
|
ORDER BY ordinal`
|
|
29553
29781
|
).all().map(readPendingEnvelope);
|
|
29782
|
+
pendingBatch = (limit) => {
|
|
29783
|
+
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
29784
|
+
throw new Error("Session event replay batch limit must be a positive integer");
|
|
29785
|
+
}
|
|
29786
|
+
return this.#database.prepare(
|
|
29787
|
+
`WITH ranked_events AS (
|
|
29788
|
+
SELECT ordinal,
|
|
29789
|
+
ROW_NUMBER() OVER (
|
|
29790
|
+
PARTITION BY source_key
|
|
29791
|
+
ORDER BY ordinal
|
|
29792
|
+
) AS source_position
|
|
29793
|
+
FROM relay_session_event_outbox
|
|
29794
|
+
)
|
|
29795
|
+
SELECT outbox.envelope_json
|
|
29796
|
+
FROM ranked_events AS ranked
|
|
29797
|
+
INNER JOIN relay_session_event_outbox AS outbox
|
|
29798
|
+
ON outbox.ordinal = ranked.ordinal
|
|
29799
|
+
ORDER BY ranked.source_position, outbox.ordinal
|
|
29800
|
+
LIMIT ?`
|
|
29801
|
+
).all(limit).map(readPendingEnvelope);
|
|
29802
|
+
};
|
|
29554
29803
|
};
|
|
29555
29804
|
function isDaemonExecutionState(value) {
|
|
29556
29805
|
return value === "cancelled" || value === "dispatching" || value === "failed" || value === "running" || value === "succeeded";
|
|
@@ -29567,7 +29816,7 @@ var systemDaemonTimer = new SystemDaemonTimer();
|
|
|
29567
29816
|
|
|
29568
29817
|
// src/run-daemon.ts
|
|
29569
29818
|
var RELAY_RECONNECT_DELAY_MILLISECONDS = 500;
|
|
29570
|
-
var
|
|
29819
|
+
var AGENT_ACTIVITY_COALESCING_MILLISECONDS = 100;
|
|
29571
29820
|
var ACTIVE_TURN_RECONCILIATION_TIMEOUT_MILLISECONDS = 2e4;
|
|
29572
29821
|
var ACTIVE_TURN_RECONCILIATION_CLOSE_CODE = 4009;
|
|
29573
29822
|
function botIpcSocketPath() {
|
|
@@ -29576,54 +29825,6 @@ function botIpcSocketPath() {
|
|
|
29576
29825
|
}
|
|
29577
29826
|
return join16("/tmp", `mobius-bot-${randomUUID6()}.sock`);
|
|
29578
29827
|
}
|
|
29579
|
-
var RelayConnectionRefreshState = class {
|
|
29580
|
-
};
|
|
29581
|
-
var ScheduledRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29582
|
-
};
|
|
29583
|
-
var DueRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29584
|
-
};
|
|
29585
|
-
var FinishedRelayConnectionRefreshState = class extends RelayConnectionRefreshState {
|
|
29586
|
-
};
|
|
29587
|
-
var RelayConnectionRefresh = class {
|
|
29588
|
-
#isSafe;
|
|
29589
|
-
#refresh;
|
|
29590
|
-
#scheduledTask;
|
|
29591
|
-
#state = new ScheduledRelayConnectionRefreshState();
|
|
29592
|
-
constructor(timer, isSafe, refresh) {
|
|
29593
|
-
this.#isSafe = isSafe;
|
|
29594
|
-
this.#refresh = refresh;
|
|
29595
|
-
this.#scheduledTask = timer.schedule(this.#request, RELAY_CONNECTION_REFRESH_MILLISECONDS);
|
|
29596
|
-
}
|
|
29597
|
-
afterTurnFinished = () => {
|
|
29598
|
-
if (this.#state instanceof DueRelayConnectionRefreshState) {
|
|
29599
|
-
this.#request();
|
|
29600
|
-
return;
|
|
29601
|
-
}
|
|
29602
|
-
if (this.#state instanceof ScheduledRelayConnectionRefreshState || this.#state instanceof FinishedRelayConnectionRefreshState) {
|
|
29603
|
-
return;
|
|
29604
|
-
}
|
|
29605
|
-
throw new Error("Unknown relay connection refresh state");
|
|
29606
|
-
};
|
|
29607
|
-
close = () => {
|
|
29608
|
-
this.#scheduledTask.cancel();
|
|
29609
|
-
this.#state = new FinishedRelayConnectionRefreshState();
|
|
29610
|
-
};
|
|
29611
|
-
#request = () => {
|
|
29612
|
-
if (this.#state instanceof FinishedRelayConnectionRefreshState) {
|
|
29613
|
-
return;
|
|
29614
|
-
}
|
|
29615
|
-
if (!(this.#state instanceof ScheduledRelayConnectionRefreshState) && !(this.#state instanceof DueRelayConnectionRefreshState)) {
|
|
29616
|
-
throw new Error("Unknown relay connection refresh state");
|
|
29617
|
-
}
|
|
29618
|
-
if (!this.#isSafe()) {
|
|
29619
|
-
this.#state = new DueRelayConnectionRefreshState();
|
|
29620
|
-
return;
|
|
29621
|
-
}
|
|
29622
|
-
this.#state = new FinishedRelayConnectionRefreshState();
|
|
29623
|
-
this.#scheduledTask.cancel();
|
|
29624
|
-
this.#refresh();
|
|
29625
|
-
};
|
|
29626
|
-
};
|
|
29627
29828
|
var DaemonAcpObserver = class {
|
|
29628
29829
|
#record;
|
|
29629
29830
|
constructor(record2) {
|
|
@@ -29888,7 +30089,8 @@ var DaemonSessionEventConnectionState = class {
|
|
|
29888
30089
|
};
|
|
29889
30090
|
var DisconnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
|
|
29890
30091
|
disconnect = () => this;
|
|
29891
|
-
|
|
30092
|
+
matches = () => false;
|
|
30093
|
+
send = () => false;
|
|
29892
30094
|
};
|
|
29893
30095
|
var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectionState {
|
|
29894
30096
|
#socket;
|
|
@@ -29897,38 +30099,155 @@ var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectio
|
|
|
29897
30099
|
this.#socket = socket;
|
|
29898
30100
|
}
|
|
29899
30101
|
disconnect = (socket) => socket === this.#socket ? new DisconnectedDaemonSessionEventState() : this;
|
|
30102
|
+
matches = (socket) => socket === this.#socket;
|
|
29900
30103
|
send = (message) => {
|
|
29901
|
-
if (this.#socket.readyState
|
|
29902
|
-
|
|
29903
|
-
|
|
29904
|
-
|
|
29905
|
-
|
|
30104
|
+
if (this.#socket.readyState !== WebSocket2.OPEN) {
|
|
30105
|
+
return false;
|
|
30106
|
+
}
|
|
30107
|
+
try {
|
|
30108
|
+
this.#socket.send(message);
|
|
30109
|
+
return true;
|
|
30110
|
+
} catch {
|
|
30111
|
+
return false;
|
|
29906
30112
|
}
|
|
29907
30113
|
};
|
|
29908
30114
|
};
|
|
30115
|
+
var SESSION_EVENT_REPLAY_WINDOW = 4;
|
|
29909
30116
|
var DaemonSessionEventPublisher = class {
|
|
29910
30117
|
#outbox;
|
|
30118
|
+
#inFlightEventIds = /* @__PURE__ */ new Set();
|
|
29911
30119
|
#connection = new DisconnectedDaemonSessionEventState();
|
|
29912
30120
|
constructor(outbox) {
|
|
29913
30121
|
this.#outbox = outbox;
|
|
29914
30122
|
}
|
|
29915
30123
|
connect = (socket) => {
|
|
29916
|
-
|
|
29917
|
-
this.#
|
|
29918
|
-
|
|
29919
|
-
connection.send(pending);
|
|
29920
|
-
}
|
|
30124
|
+
this.#connection = new ConnectedDaemonSessionEventState(socket);
|
|
30125
|
+
this.#inFlightEventIds.clear();
|
|
30126
|
+
this.#publishNextBatch();
|
|
29921
30127
|
};
|
|
29922
30128
|
disconnect = (socket) => {
|
|
30129
|
+
if (!this.#connection.matches(socket)) {
|
|
30130
|
+
return;
|
|
30131
|
+
}
|
|
29923
30132
|
this.#connection = this.#connection.disconnect(socket);
|
|
30133
|
+
this.#inFlightEventIds.clear();
|
|
29924
30134
|
};
|
|
29925
30135
|
recordAttempt = (sessionId, payload, attemptId) => {
|
|
29926
|
-
this.#
|
|
30136
|
+
this.#outbox.enqueue(sessionId, payload, attemptId);
|
|
30137
|
+
this.#publishNextBatch();
|
|
29927
30138
|
};
|
|
29928
30139
|
recordRuntime = (sessionId, payload) => {
|
|
29929
|
-
this.#
|
|
30140
|
+
this.#outbox.enqueue(sessionId, payload);
|
|
30141
|
+
this.#publishNextBatch();
|
|
30142
|
+
};
|
|
30143
|
+
acknowledge = (acknowledgement) => {
|
|
30144
|
+
if (!this.#outbox.acknowledge(acknowledgement)) {
|
|
30145
|
+
return;
|
|
30146
|
+
}
|
|
30147
|
+
this.#inFlightEventIds.delete(acknowledgement.eventId);
|
|
30148
|
+
this.#publishNextBatch();
|
|
30149
|
+
};
|
|
30150
|
+
quarantine = (rejection) => {
|
|
30151
|
+
const quarantined = this.#outbox.quarantine(rejection);
|
|
30152
|
+
if (!quarantined) {
|
|
30153
|
+
return false;
|
|
30154
|
+
}
|
|
30155
|
+
this.#inFlightEventIds.delete(rejection.eventId);
|
|
30156
|
+
this.#publishNextBatch();
|
|
30157
|
+
return true;
|
|
30158
|
+
};
|
|
30159
|
+
#publishNextBatch = () => {
|
|
30160
|
+
if (this.#inFlightEventIds.size > 0) {
|
|
30161
|
+
return;
|
|
30162
|
+
}
|
|
30163
|
+
const batch = this.#outbox.pendingBatch(SESSION_EVENT_REPLAY_WINDOW);
|
|
30164
|
+
for (const encoded of batch) {
|
|
30165
|
+
const envelope2 = decodeSessionEventEnvelope(encoded);
|
|
30166
|
+
if (!this.#connection.send(encoded)) {
|
|
30167
|
+
this.#inFlightEventIds.clear();
|
|
30168
|
+
return;
|
|
30169
|
+
}
|
|
30170
|
+
this.#inFlightEventIds.add(envelope2.eventId);
|
|
30171
|
+
}
|
|
30172
|
+
};
|
|
30173
|
+
};
|
|
30174
|
+
var CoalescingDaemonActivityPublisher = class {
|
|
30175
|
+
#pending = /* @__PURE__ */ new Map();
|
|
30176
|
+
#publish;
|
|
30177
|
+
#publishedActivityIds = /* @__PURE__ */ new Set();
|
|
30178
|
+
#scheduled = /* @__PURE__ */ new Map();
|
|
30179
|
+
#timer;
|
|
30180
|
+
constructor(timer, publish) {
|
|
30181
|
+
this.#publish = publish;
|
|
30182
|
+
this.#timer = timer;
|
|
30183
|
+
}
|
|
30184
|
+
flush = () => {
|
|
30185
|
+
const activities = [...this.#pending.values()].sort((left, right) => left.sequence - right.sequence);
|
|
30186
|
+
for (const task of this.#scheduled.values()) {
|
|
30187
|
+
task.cancel();
|
|
30188
|
+
}
|
|
30189
|
+
this.#pending.clear();
|
|
30190
|
+
this.#scheduled.clear();
|
|
30191
|
+
for (const activity of activities) {
|
|
30192
|
+
this.#publish(activity);
|
|
30193
|
+
}
|
|
30194
|
+
};
|
|
30195
|
+
record = (activity) => {
|
|
30196
|
+
if (activity.status !== "pending" && activity.status !== "running") {
|
|
30197
|
+
this.#discardPending(activity.activityId);
|
|
30198
|
+
this.#publishedActivityIds.add(activity.activityId);
|
|
30199
|
+
this.#publish(activity);
|
|
30200
|
+
return Promise.resolve();
|
|
30201
|
+
}
|
|
30202
|
+
if (!this.#publishedActivityIds.has(activity.activityId)) {
|
|
30203
|
+
this.#publishedActivityIds.add(activity.activityId);
|
|
30204
|
+
this.#publish(activity);
|
|
30205
|
+
return Promise.resolve();
|
|
30206
|
+
}
|
|
30207
|
+
this.#pending.set(activity.activityId, activity);
|
|
30208
|
+
if (!this.#scheduled.has(activity.activityId)) {
|
|
30209
|
+
this.#scheduled.set(
|
|
30210
|
+
activity.activityId,
|
|
30211
|
+
this.#timer.schedule(
|
|
30212
|
+
() => this.#flushActivity(activity.activityId),
|
|
30213
|
+
AGENT_ACTIVITY_COALESCING_MILLISECONDS
|
|
30214
|
+
)
|
|
30215
|
+
);
|
|
30216
|
+
}
|
|
30217
|
+
return Promise.resolve();
|
|
30218
|
+
};
|
|
30219
|
+
#discardPending = (activityId) => {
|
|
30220
|
+
this.#scheduled.get(activityId)?.cancel();
|
|
30221
|
+
this.#scheduled.delete(activityId);
|
|
30222
|
+
this.#pending.delete(activityId);
|
|
30223
|
+
};
|
|
30224
|
+
#flushActivity = (activityId) => {
|
|
30225
|
+
const activity = this.#pending.get(activityId);
|
|
30226
|
+
this.#discardPending(activityId);
|
|
30227
|
+
if (activity !== void 0) {
|
|
30228
|
+
this.#publish(activity);
|
|
30229
|
+
}
|
|
29930
30230
|
};
|
|
29931
30231
|
};
|
|
30232
|
+
function encodeDaemonActivity(command, activity) {
|
|
30233
|
+
return 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
|
+
}
|
|
29932
30251
|
function reportFailure(publisher, command, code, message, attemptId) {
|
|
29933
30252
|
publisher.recordAttempt(
|
|
29934
30253
|
command.sessionId,
|
|
@@ -30105,7 +30424,10 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
|
|
|
30105
30424
|
reportOperationFailure(socket, command.requestId, command.sessionId, error61);
|
|
30106
30425
|
}
|
|
30107
30426
|
}
|
|
30108
|
-
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, signal) {
|
|
30427
|
+
async function executePrompt(outbox, publisher, command, config2, directories, audit, sessions, attemptId, timer, signal) {
|
|
30428
|
+
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
30429
|
+
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
30430
|
+
});
|
|
30109
30431
|
try {
|
|
30110
30432
|
const resolved = await resolveSessionDirectories(
|
|
30111
30433
|
directories,
|
|
@@ -30162,30 +30484,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30162
30484
|
cwd: resolved.cwd,
|
|
30163
30485
|
disposition: command.disposition,
|
|
30164
30486
|
images: attachments.images,
|
|
30165
|
-
onActivity:
|
|
30166
|
-
publisher.recordAttempt(
|
|
30167
|
-
command.sessionId,
|
|
30168
|
-
encodeAgentActivityEvent({
|
|
30169
|
-
activityId: activity.activityId,
|
|
30170
|
-
activityType: activity.activityType,
|
|
30171
|
-
commandId: command.commandId,
|
|
30172
|
-
content: activity.content,
|
|
30173
|
-
detail: activity.detail,
|
|
30174
|
-
input: activity.input,
|
|
30175
|
-
kind: AGENT_ACTIVITY_KIND,
|
|
30176
|
-
locations: activity.locations,
|
|
30177
|
-
name: activity.name,
|
|
30178
|
-
output: activity.output,
|
|
30179
|
-
sequence: activity.sequence,
|
|
30180
|
-
sessionId: command.sessionId,
|
|
30181
|
-
status: activity.status,
|
|
30182
|
-
title: activity.title,
|
|
30183
|
-
toolKind: activity.toolKind
|
|
30184
|
-
}),
|
|
30185
|
-
attemptId
|
|
30186
|
-
);
|
|
30187
|
-
return Promise.resolve();
|
|
30188
|
-
},
|
|
30487
|
+
onActivity: activities.record,
|
|
30189
30488
|
onText: (text, messageId) => {
|
|
30190
30489
|
publisher.recordAttempt(
|
|
30191
30490
|
command.sessionId,
|
|
@@ -30208,6 +30507,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30208
30507
|
});
|
|
30209
30508
|
stopReason = result.stopReason;
|
|
30210
30509
|
}
|
|
30510
|
+
activities.flush();
|
|
30211
30511
|
publisher.recordAttempt(
|
|
30212
30512
|
command.sessionId,
|
|
30213
30513
|
encodeSessionCompletedEvent({
|
|
@@ -30225,6 +30525,7 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
30225
30525
|
sessionId: command.sessionId
|
|
30226
30526
|
});
|
|
30227
30527
|
} catch (error61) {
|
|
30528
|
+
activities.flush();
|
|
30228
30529
|
audit.record({
|
|
30229
30530
|
commandId: command.commandId,
|
|
30230
30531
|
event: "session_failed",
|
|
@@ -30263,7 +30564,10 @@ function botExecutionAgent(agent, contextHandle, socketPath) {
|
|
|
30263
30564
|
agent.capabilities
|
|
30264
30565
|
);
|
|
30265
30566
|
}
|
|
30266
|
-
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, signal) {
|
|
30567
|
+
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, timer, signal) {
|
|
30568
|
+
const activities = new CoalescingDaemonActivityPublisher(timer, (activity) => {
|
|
30569
|
+
publisher.recordAttempt(command.sessionId, encodeDaemonActivity(command, activity), attemptId);
|
|
30570
|
+
});
|
|
30267
30571
|
try {
|
|
30268
30572
|
const deadline = Date.parse(command.executionDeadlineAt);
|
|
30269
30573
|
const remaining = deadline - Date.now();
|
|
@@ -30347,30 +30651,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30347
30651
|
commandId: command.commandId,
|
|
30348
30652
|
cwd: resolved.cwd,
|
|
30349
30653
|
images: attachments.images,
|
|
30350
|
-
onActivity:
|
|
30351
|
-
publisher.recordAttempt(
|
|
30352
|
-
command.sessionId,
|
|
30353
|
-
encodeAgentActivityEvent({
|
|
30354
|
-
activityId: activity.activityId,
|
|
30355
|
-
activityType: activity.activityType,
|
|
30356
|
-
commandId: command.commandId,
|
|
30357
|
-
content: activity.content,
|
|
30358
|
-
detail: activity.detail,
|
|
30359
|
-
input: activity.input,
|
|
30360
|
-
kind: AGENT_ACTIVITY_KIND,
|
|
30361
|
-
locations: activity.locations,
|
|
30362
|
-
name: activity.name,
|
|
30363
|
-
output: activity.output,
|
|
30364
|
-
sequence: activity.sequence,
|
|
30365
|
-
sessionId: command.sessionId,
|
|
30366
|
-
status: activity.status,
|
|
30367
|
-
title: activity.title,
|
|
30368
|
-
toolKind: activity.toolKind
|
|
30369
|
-
}),
|
|
30370
|
-
attemptId
|
|
30371
|
-
);
|
|
30372
|
-
return Promise.resolve();
|
|
30373
|
-
},
|
|
30654
|
+
onActivity: activities.record,
|
|
30374
30655
|
onText: (text, messageId) => {
|
|
30375
30656
|
publisher.recordAttempt(
|
|
30376
30657
|
command.sessionId,
|
|
@@ -30390,6 +30671,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30390
30671
|
sessionId: command.sessionId,
|
|
30391
30672
|
signal: executionSignal
|
|
30392
30673
|
});
|
|
30674
|
+
activities.flush();
|
|
30393
30675
|
publisher.recordAttempt(
|
|
30394
30676
|
command.sessionId,
|
|
30395
30677
|
encodeSessionCompletedEvent({
|
|
@@ -30414,6 +30696,7 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
30414
30696
|
lease.release();
|
|
30415
30697
|
}
|
|
30416
30698
|
} catch (error61) {
|
|
30699
|
+
activities.flush();
|
|
30417
30700
|
const failure = Date.parse(command.executionDeadlineAt) <= Date.now() ? new LocalBotAuthorizationError("turn_expired", "The Bot execution deadline has expired", {
|
|
30418
30701
|
cause: error61
|
|
30419
30702
|
}) : error61;
|
|
@@ -30453,15 +30736,15 @@ function waitForRelayRetry(signal, timer) {
|
|
|
30453
30736
|
signal.addEventListener("abort", finish, { once: true });
|
|
30454
30737
|
});
|
|
30455
30738
|
}
|
|
30456
|
-
async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
|
|
30739
|
+
async function publishAgentCatalogUntilAvailable(config2, diagnostics, signal, timer) {
|
|
30457
30740
|
try {
|
|
30458
30741
|
await publishAgentCatalog(config2, signal);
|
|
30459
30742
|
return;
|
|
30460
|
-
} catch {
|
|
30743
|
+
} catch (error61) {
|
|
30461
30744
|
if (signal.aborted) {
|
|
30462
30745
|
return;
|
|
30463
30746
|
}
|
|
30464
|
-
|
|
30747
|
+
diagnostics.catalogFailed(error61);
|
|
30465
30748
|
}
|
|
30466
30749
|
while (!signal.aborted) {
|
|
30467
30750
|
await waitForRelayRetry(signal, timer);
|
|
@@ -30475,11 +30758,12 @@ async function publishAgentCatalogUntilAvailable(config2, signal, timer) {
|
|
|
30475
30758
|
}
|
|
30476
30759
|
}
|
|
30477
30760
|
}
|
|
30478
|
-
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, onConnected, signal, timer) {
|
|
30761
|
+
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, connectionEpoch, diagnostics, onConnected, signal, timer) {
|
|
30479
30762
|
const relayUrl = new URL(config2.relayUrl);
|
|
30480
30763
|
relayUrl.searchParams.set("liveness", "1");
|
|
30481
30764
|
const socket = await connectRelay(relayUrl, signal);
|
|
30482
30765
|
const reconnectingTurns = [...activeTurns.values()];
|
|
30766
|
+
diagnostics.connectionOpened(connectionEpoch);
|
|
30483
30767
|
onConnected();
|
|
30484
30768
|
const connectionController = new AbortController();
|
|
30485
30769
|
const nativeRequests = /* @__PURE__ */ new Map();
|
|
@@ -30488,7 +30772,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30488
30772
|
await new Promise((resolve6, reject) => {
|
|
30489
30773
|
let finished = false;
|
|
30490
30774
|
const cleanup = () => {
|
|
30491
|
-
connectionRefresh.close();
|
|
30492
30775
|
connectionLiveness.close();
|
|
30493
30776
|
signal.removeEventListener("abort", stop);
|
|
30494
30777
|
socket.removeEventListener("close", handleClose);
|
|
@@ -30506,61 +30789,70 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30506
30789
|
cleanup();
|
|
30507
30790
|
resolve6();
|
|
30508
30791
|
};
|
|
30509
|
-
const rejectConnection = () => {
|
|
30792
|
+
const rejectConnection = (failure) => {
|
|
30510
30793
|
if (finished) {
|
|
30511
30794
|
return;
|
|
30512
30795
|
}
|
|
30513
30796
|
finished = true;
|
|
30514
30797
|
cleanup();
|
|
30515
|
-
reject(
|
|
30798
|
+
reject(failure);
|
|
30516
30799
|
};
|
|
30517
30800
|
const stop = () => {
|
|
30801
|
+
diagnostics.connectionClosed(connectionEpoch, 1e3, "Daemon stopped", "daemon_stop");
|
|
30518
30802
|
closeRelaySocket(socket, 1e3, "Daemon stopped");
|
|
30519
30803
|
resolveConnection();
|
|
30520
30804
|
};
|
|
30521
|
-
const
|
|
30522
|
-
|
|
30523
|
-
|
|
30805
|
+
const failAndClose = (failure, code, reason, source) => {
|
|
30806
|
+
diagnostics.connectionFailed(connectionEpoch, failure, source);
|
|
30807
|
+
diagnostics.connectionClosed(connectionEpoch, code, reason, source);
|
|
30808
|
+
closeRelaySocket(socket, code, reason);
|
|
30809
|
+
rejectConnection(failure);
|
|
30524
30810
|
};
|
|
30525
30811
|
const connectionLiveness = new RelayConnectionLiveness(timer, {
|
|
30526
30812
|
send: (message) => send(socket, message),
|
|
30527
|
-
unresponsive: () => {
|
|
30813
|
+
unresponsive: (heartbeatId, timeoutMilliseconds) => {
|
|
30814
|
+
diagnostics.heartbeatTimedOut(connectionEpoch, heartbeatId, timeoutMilliseconds);
|
|
30815
|
+
diagnostics.connectionClosed(
|
|
30816
|
+
connectionEpoch,
|
|
30817
|
+
4001,
|
|
30818
|
+
"Relay liveness check timed out",
|
|
30819
|
+
"heartbeat_timeout"
|
|
30820
|
+
);
|
|
30528
30821
|
closeRelaySocket(socket, 4001, "Relay liveness check timed out");
|
|
30529
30822
|
resolveConnection();
|
|
30530
30823
|
}
|
|
30531
30824
|
});
|
|
30532
|
-
const connectionRefresh = new RelayConnectionRefresh(
|
|
30533
|
-
timer,
|
|
30534
|
-
() => activeTurns.size === 0,
|
|
30535
|
-
refreshConnection
|
|
30536
|
-
);
|
|
30537
30825
|
signal.addEventListener("abort", stop, { once: true });
|
|
30538
|
-
const handleClose = () => {
|
|
30826
|
+
const handleClose = (event) => {
|
|
30827
|
+
diagnostics.connectionClosed(connectionEpoch, event.code, event.reason, "relay");
|
|
30539
30828
|
resolveConnection();
|
|
30540
30829
|
};
|
|
30541
|
-
const handleError = () => {
|
|
30830
|
+
const handleError = (event) => {
|
|
30542
30831
|
if (signal.aborted) {
|
|
30543
30832
|
resolveConnection();
|
|
30544
30833
|
return;
|
|
30545
30834
|
}
|
|
30546
|
-
|
|
30835
|
+
const cause = Reflect.get(event, "error");
|
|
30836
|
+
const failure = new Error("Relay WebSocket emitted an error", { cause: cause ?? event });
|
|
30837
|
+
diagnostics.connectionFailed(connectionEpoch, failure, "socket_error");
|
|
30838
|
+
diagnostics.connectionClosed(connectionEpoch, 1006, "WebSocket error", "socket_error");
|
|
30839
|
+
rejectConnection(failure);
|
|
30547
30840
|
};
|
|
30548
30841
|
const handleMessage = (event) => {
|
|
30549
30842
|
const encoded = event.data;
|
|
30550
30843
|
if (typeof encoded !== "string") {
|
|
30551
|
-
|
|
30552
|
-
rejectConnection();
|
|
30844
|
+
failAndClose(new Error("Relay sent a non-text message"), 4003, "Text message required", "protocol");
|
|
30553
30845
|
return;
|
|
30554
30846
|
}
|
|
30555
30847
|
try {
|
|
30556
30848
|
const kind = decodeMessageKind(encoded);
|
|
30557
30849
|
if (kind === SESSION_EVENT_ACK_KIND) {
|
|
30558
|
-
|
|
30850
|
+
publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
|
|
30559
30851
|
return;
|
|
30560
30852
|
}
|
|
30561
30853
|
if (kind === SESSION_EVENT_REJECTED_KIND) {
|
|
30562
30854
|
const rejection = decodeSessionEventRejection(encoded);
|
|
30563
|
-
if (
|
|
30855
|
+
if (publisher.quarantine(rejection)) {
|
|
30564
30856
|
audit.record({
|
|
30565
30857
|
commandId: rejection.eventId,
|
|
30566
30858
|
details: { code: rejection.code },
|
|
@@ -30939,6 +31231,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30939
31231
|
applicator,
|
|
30940
31232
|
ipc,
|
|
30941
31233
|
receipt2.attemptId,
|
|
31234
|
+
timer,
|
|
30942
31235
|
turn2.signal
|
|
30943
31236
|
).catch((error61) => {
|
|
30944
31237
|
console.error("Mobius daemon Bot turn failed", error61);
|
|
@@ -30948,7 +31241,6 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30948
31241
|
activeAttemptIds.delete(command2.sessionId);
|
|
30949
31242
|
}
|
|
30950
31243
|
turn2.finish();
|
|
30951
|
-
connectionRefresh.afterTurnFinished();
|
|
30952
31244
|
});
|
|
30953
31245
|
return;
|
|
30954
31246
|
}
|
|
@@ -30977,6 +31269,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30977
31269
|
audit,
|
|
30978
31270
|
sessions,
|
|
30979
31271
|
receipt.attemptId,
|
|
31272
|
+
timer,
|
|
30980
31273
|
turn.signal
|
|
30981
31274
|
).catch((error61) => {
|
|
30982
31275
|
console.error("Mobius daemon turn failed", error61);
|
|
@@ -30986,12 +31279,15 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30986
31279
|
activeAttemptIds.delete(command.sessionId);
|
|
30987
31280
|
}
|
|
30988
31281
|
turn.finish();
|
|
30989
|
-
connectionRefresh.afterTurnFinished();
|
|
30990
31282
|
});
|
|
30991
31283
|
} catch (error61) {
|
|
30992
31284
|
console.error("Mobius daemon rejected a message", error61);
|
|
30993
|
-
|
|
30994
|
-
|
|
31285
|
+
failAndClose(
|
|
31286
|
+
new Error("Relay sent an invalid protocol message", { cause: error61 }),
|
|
31287
|
+
4008,
|
|
31288
|
+
"Invalid protocol message",
|
|
31289
|
+
"protocol"
|
|
31290
|
+
);
|
|
30995
31291
|
}
|
|
30996
31292
|
};
|
|
30997
31293
|
socket.addEventListener("close", handleClose);
|
|
@@ -31003,21 +31299,18 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
31003
31299
|
return;
|
|
31004
31300
|
}
|
|
31005
31301
|
publisher.connect(socket);
|
|
31006
|
-
void Promise.all(reconnectingTurns.map((turn) => turn.completion)).then(
|
|
31007
|
-
connectionRefresh.afterTurnFinished
|
|
31008
|
-
);
|
|
31009
31302
|
},
|
|
31010
31303
|
(error61) => {
|
|
31011
31304
|
if (finished) {
|
|
31012
31305
|
return;
|
|
31013
31306
|
}
|
|
31014
31307
|
console.error("Mobius daemon could not reconcile active Agent turns", error61);
|
|
31015
|
-
|
|
31016
|
-
|
|
31308
|
+
failAndClose(
|
|
31309
|
+
new Error("Active Agent turn reconciliation failed", { cause: error61 }),
|
|
31017
31310
|
ACTIVE_TURN_RECONCILIATION_CLOSE_CODE,
|
|
31018
|
-
"Active Agent turn reconciliation failed"
|
|
31311
|
+
"Active Agent turn reconciliation failed",
|
|
31312
|
+
"reconciliation"
|
|
31019
31313
|
);
|
|
31020
|
-
rejectConnection();
|
|
31021
31314
|
}
|
|
31022
31315
|
);
|
|
31023
31316
|
if (signal.aborted) {
|
|
@@ -31061,6 +31354,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31061
31354
|
const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
|
|
31062
31355
|
const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
|
|
31063
31356
|
const installationObserver = new DaemonInstallationObserver();
|
|
31357
|
+
const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);
|
|
31064
31358
|
const nativeSessions = new NativeSessionService(config2, directories, sessions, audit);
|
|
31065
31359
|
const installations = new AgentInstallationManager(
|
|
31066
31360
|
specifications,
|
|
@@ -31068,7 +31362,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31068
31362
|
installationObserver,
|
|
31069
31363
|
installationAudit
|
|
31070
31364
|
);
|
|
31071
|
-
let
|
|
31365
|
+
let connectionEpoch = 0;
|
|
31072
31366
|
let connectionAnnounced = false;
|
|
31073
31367
|
const announceConnection = () => {
|
|
31074
31368
|
if (connectionAnnounced) {
|
|
@@ -31084,10 +31378,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31084
31378
|
`
|
|
31085
31379
|
);
|
|
31086
31380
|
};
|
|
31087
|
-
const catalogPublication = publishAgentCatalogUntilAvailable(config2, signal, timer);
|
|
31381
|
+
const catalogPublication = publishAgentCatalogUntilAvailable(config2, diagnostics, signal, timer);
|
|
31088
31382
|
try {
|
|
31089
31383
|
await ipc.listen(signal);
|
|
31090
31384
|
while (!signal.aborted) {
|
|
31385
|
+
connectionEpoch += 1;
|
|
31091
31386
|
try {
|
|
31092
31387
|
await runRelayConnection(
|
|
31093
31388
|
config2,
|
|
@@ -31105,19 +31400,17 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31105
31400
|
ipc,
|
|
31106
31401
|
activeTurns,
|
|
31107
31402
|
activeAttemptIds,
|
|
31403
|
+
connectionEpoch,
|
|
31404
|
+
diagnostics,
|
|
31108
31405
|
announceConnection,
|
|
31109
31406
|
signal,
|
|
31110
31407
|
timer
|
|
31111
31408
|
);
|
|
31112
|
-
|
|
31113
|
-
} catch {
|
|
31409
|
+
} catch (error61) {
|
|
31114
31410
|
if (signal.aborted) {
|
|
31115
31411
|
return;
|
|
31116
31412
|
}
|
|
31117
|
-
|
|
31118
|
-
console.warn("Mobius daemon is waiting for the relay");
|
|
31119
|
-
retryAnnounced = true;
|
|
31120
|
-
}
|
|
31413
|
+
diagnostics.connectionFailed(connectionEpoch, error61, "connection");
|
|
31121
31414
|
}
|
|
31122
31415
|
await waitForRelayRetry(signal, timer);
|
|
31123
31416
|
}
|