@moxt-ai/mobius 0.0.147 → 0.0.150
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 +731 -197
- package/dist/cli.js.map +4 -4
- package/dist/daemon-active-turn.d.ts +15 -2
- package/dist/daemon-active-turn.d.ts.map +1 -1
- package/dist/daemon-active-turn.js +63 -25
- package/dist/daemon-active-turn.js.map +1 -1
- package/dist/daemon-command-handler.js +3 -3
- package/dist/daemon-history-commands.d.ts +4 -7
- package/dist/daemon-history-commands.d.ts.map +1 -1
- package/dist/daemon-history-commands.js.map +1 -1
- package/dist/daemon-prompt-executor.d.ts +1 -1
- package/dist/daemon-prompt-executor.d.ts.map +1 -1
- package/dist/daemon-prompt-executor.js +1 -3
- package/dist/daemon-prompt-executor.js.map +1 -1
- package/dist/daemon-turn-registry.d.ts +18 -56
- package/dist/daemon-turn-registry.d.ts.map +1 -1
- package/dist/daemon-turn-registry.js +40 -1
- package/dist/daemon-turn-registry.js.map +1 -1
- package/dist/index.js +730 -196
- package/dist/index.js.map +4 -4
- package/dist/native-sessions/live-history-page.d.ts +4 -7
- package/dist/native-sessions/live-history-page.d.ts.map +1 -1
- package/dist/native-sessions/live-history-page.js +163 -107
- package/dist/native-sessions/live-history-page.js.map +1 -1
- package/dist/relay-connection/run-relay-connection.d.ts.map +1 -1
- package/dist/relay-connection/run-relay-connection.js +15 -2
- package/dist/relay-connection/run-relay-connection.js.map +1 -1
- package/dist/relay-connection/session-event-outbox.d.ts +19 -0
- package/dist/relay-connection/session-event-outbox.d.ts.map +1 -0
- package/dist/relay-connection/session-event-outbox.js +228 -0
- package/dist/relay-connection/session-event-outbox.js.map +1 -0
- package/dist/relay-connection/session-event-publisher.d.ts +10 -4
- package/dist/relay-connection/session-event-publisher.d.ts.map +1 -1
- package/dist/relay-connection/session-event-publisher.js +140 -32
- package/dist/relay-connection/session-event-publisher.js.map +1 -1
- package/dist/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +3 -1
- package/dist/run-daemon.js.map +1 -1
- package/dist/runtime.js +736 -202
- package/dist/runtime.js.map +4 -4
- package/package.json +1 -1
package/dist/runtime.js
CHANGED
|
@@ -20740,9 +20740,17 @@ function decodeSessionQueuedEvent(encoded) {
|
|
|
20740
20740
|
}
|
|
20741
20741
|
function decodeRuntimeLivenessReadyEvent(encoded) {
|
|
20742
20742
|
const value = parseJson2(encoded);
|
|
20743
|
-
assertExactKeys(value, ["kind"]);
|
|
20744
20743
|
assertKind(value, RUNTIME_LIVENESS_READY_KIND);
|
|
20745
|
-
|
|
20744
|
+
if (value["sessionEventDelivery"] === void 0) {
|
|
20745
|
+
assertExactKeys(value, ["kind"]);
|
|
20746
|
+
return { kind: RUNTIME_LIVENESS_READY_KIND };
|
|
20747
|
+
}
|
|
20748
|
+
assertExactKeys(value, ["kind", "sessionEventDelivery"]);
|
|
20749
|
+
const sessionEventDelivery = readString(value, "sessionEventDelivery", 32);
|
|
20750
|
+
if (sessionEventDelivery !== "reliable-v1") {
|
|
20751
|
+
throw new ProtocolMessageError("Unsupported Session event delivery mode");
|
|
20752
|
+
}
|
|
20753
|
+
return { kind: RUNTIME_LIVENESS_READY_KIND, sessionEventDelivery };
|
|
20746
20754
|
}
|
|
20747
20755
|
function decodeRuntimeHeartbeatEvent(encoded) {
|
|
20748
20756
|
const value = parseJson2(encoded);
|
|
@@ -21034,18 +21042,21 @@ var activeTurnMessageSchema = external_exports.discriminatedUnion("role", [
|
|
|
21034
21042
|
activeTurnAssistantMessageSchema
|
|
21035
21043
|
]);
|
|
21036
21044
|
var activeTurnSnapshotSchema = external_exports.strictObject({
|
|
21037
|
-
activities: external_exports.array(activeTurnActivitySchema).readonly(),
|
|
21038
21045
|
commandId: identifierStringSchema,
|
|
21039
|
-
content: external_exports.array(displayContentSchema).readonly(),
|
|
21040
|
-
prompt: external_exports.string().max(1e5),
|
|
21041
|
-
text: external_exports.string(),
|
|
21042
|
-
truncated: external_exports.boolean(),
|
|
21043
21046
|
epoch: identifierStringSchema,
|
|
21047
|
+
hasOlder: external_exports.boolean(),
|
|
21044
21048
|
interaction: external_exports.discriminatedUnion("kind", [sessionPermissionRequestedEventSchema, sessionElicitationRequestedEventSchema]).nullable(),
|
|
21045
21049
|
messages: external_exports.array(activeTurnMessageSchema).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
|
|
21046
21050
|
sequence: external_exports.number().int().nonnegative(),
|
|
21047
|
-
state: external_exports.literal("running")
|
|
21048
|
-
|
|
21051
|
+
state: external_exports.literal("running"),
|
|
21052
|
+
truncated: external_exports.boolean()
|
|
21053
|
+
}).readonly().refine(
|
|
21054
|
+
(snapshot) => snapshot.messages.reduce(
|
|
21055
|
+
(total, message) => total + message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0),
|
|
21056
|
+
0
|
|
21057
|
+
) <= SESSION_HISTORY_CHARACTER_LIMIT,
|
|
21058
|
+
"Active Turn snapshot content is too large"
|
|
21059
|
+
);
|
|
21049
21060
|
var identity = {
|
|
21050
21061
|
...envelope,
|
|
21051
21062
|
kind: external_exports.literal(NATIVE_SESSION_REQUEST_KIND),
|
|
@@ -21189,27 +21200,61 @@ var encodeNativeSessionCancel = (value) => JSON.stringify(nativeSessionCancelSch
|
|
|
21189
21200
|
|
|
21190
21201
|
// ../protocol/src/session-events.ts
|
|
21191
21202
|
var SESSION_EVENT_KIND = "session.event";
|
|
21192
|
-
var
|
|
21203
|
+
var SESSION_EVENT_ACK_KIND = "session.event.ack";
|
|
21204
|
+
var SESSION_EVENT_DEFERRED_KIND = "session.event.deferred";
|
|
21205
|
+
var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
|
|
21206
|
+
var SessionEventRejectionCode = {
|
|
21207
|
+
IdempotencyConflict: "idempotency_conflict",
|
|
21208
|
+
InvalidEvent: "invalid_event",
|
|
21209
|
+
RecordingRejected: "recording_rejected"
|
|
21210
|
+
};
|
|
21193
21211
|
var MAX_RECORDED_EVENT_LENGTH = 8 * 1024 * 1024;
|
|
21194
|
-
var
|
|
21212
|
+
var ephemeralEventEnvelopeSchema = external_exports.strictObject({
|
|
21195
21213
|
kind: external_exports.literal(SESSION_EVENT_KIND),
|
|
21196
21214
|
payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
|
|
21197
21215
|
sessionId: identifierStringSchema
|
|
21198
21216
|
}).readonly();
|
|
21199
|
-
var
|
|
21200
|
-
|
|
21217
|
+
var reliableDeliverySchema = external_exports.strictObject({
|
|
21218
|
+
eventId: identifierStringSchema,
|
|
21219
|
+
kind: external_exports.literal("reliable"),
|
|
21220
|
+
sourceSeq: external_exports.string().regex(/^(?:0|[1-9][0-9]*)$/u).max(40),
|
|
21221
|
+
streamId: identifierStringSchema
|
|
21222
|
+
}).readonly();
|
|
21223
|
+
var reliableEventEnvelopeSchema = external_exports.strictObject({
|
|
21224
|
+
delivery: reliableDeliverySchema,
|
|
21225
|
+
kind: external_exports.literal(SESSION_EVENT_KIND),
|
|
21201
21226
|
payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
|
|
21202
21227
|
sessionId: identifierStringSchema
|
|
21203
21228
|
}).readonly();
|
|
21229
|
+
var eventEnvelopeSchema = external_exports.union([ephemeralEventEnvelopeSchema, reliableEventEnvelopeSchema]).readonly();
|
|
21230
|
+
var acknowledgementOutcomeSchema = external_exports.discriminatedUnion("kind", [
|
|
21231
|
+
external_exports.strictObject({ kind: external_exports.literal("relayed") }).readonly(),
|
|
21232
|
+
external_exports.strictObject({
|
|
21233
|
+
kind: external_exports.literal("recorded"),
|
|
21234
|
+
providerId: identifierStringSchema,
|
|
21235
|
+
recordingEpoch: identifierStringSchema
|
|
21236
|
+
}).readonly()
|
|
21237
|
+
]);
|
|
21238
|
+
var eventAcknowledgementSchema = external_exports.strictObject({
|
|
21239
|
+
eventId: identifierStringSchema,
|
|
21240
|
+
kind: external_exports.literal(SESSION_EVENT_ACK_KIND),
|
|
21241
|
+
outcome: acknowledgementOutcomeSchema,
|
|
21242
|
+
sessionId: identifierStringSchema
|
|
21243
|
+
}).readonly();
|
|
21244
|
+
var eventDeferredSchema = external_exports.strictObject({
|
|
21245
|
+
eventId: identifierStringSchema,
|
|
21246
|
+
kind: external_exports.literal(SESSION_EVENT_DEFERRED_KIND),
|
|
21247
|
+
retryAfterMilliseconds: external_exports.number().int().min(100).max(6e4),
|
|
21248
|
+
sessionId: identifierStringSchema
|
|
21249
|
+
}).readonly();
|
|
21250
|
+
var eventRejectedSchema = external_exports.strictObject({
|
|
21251
|
+
code: external_exports.enum(SessionEventRejectionCode),
|
|
21252
|
+
eventId: identifierStringSchema,
|
|
21253
|
+
kind: external_exports.literal(SESSION_EVENT_REJECTED_KIND),
|
|
21254
|
+
sessionId: identifierStringSchema
|
|
21255
|
+
}).readonly();
|
|
21204
21256
|
var SESSION_QUEUE_CHANGED_KIND = "session.queue.changed";
|
|
21205
21257
|
var sessionQueueChangedSchema = external_exports.strictObject({ kind: external_exports.literal(SESSION_QUEUE_CHANGED_KIND), sessionId: identifierStringSchema }).readonly();
|
|
21206
|
-
var SESSION_TURN_UPDATED_KIND = "session.turn.updated";
|
|
21207
|
-
var sessionTurnUpdatedSchema = external_exports.strictObject({
|
|
21208
|
-
kind: external_exports.literal(SESSION_TURN_UPDATED_KIND),
|
|
21209
|
-
sessionId: identifierStringSchema,
|
|
21210
|
-
turn: activeTurnSnapshotSchema
|
|
21211
|
-
}).readonly();
|
|
21212
|
-
var decodeSessionTurnUpdatedEvent = (encoded) => decode5(encoded, sessionTurnUpdatedSchema);
|
|
21213
21258
|
function decode5(encoded, schema) {
|
|
21214
21259
|
let value;
|
|
21215
21260
|
try {
|
|
@@ -21236,11 +21281,15 @@ var encode4 = (message, schema) => {
|
|
|
21236
21281
|
};
|
|
21237
21282
|
var decodeSessionEventEnvelope = (encoded) => decode5(encoded, eventEnvelopeSchema);
|
|
21238
21283
|
var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
|
|
21284
|
+
var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
|
|
21285
|
+
var encodeSessionEventAcknowledgement = (message) => encode4(message, eventAcknowledgementSchema);
|
|
21286
|
+
var decodeSessionEventDeferred = (encoded) => decode5(encoded, eventDeferredSchema);
|
|
21287
|
+
var encodeSessionEventDeferred = (message) => encode4(message, eventDeferredSchema);
|
|
21288
|
+
var decodeSessionEventRejected = (encoded) => decode5(encoded, eventRejectedSchema);
|
|
21289
|
+
var encodeSessionEventRejected = (message) => encode4(message, eventRejectedSchema);
|
|
21239
21290
|
function decodeRecordedSessionEvent(encoded) {
|
|
21240
21291
|
const kind = decodeMessageKind(encoded);
|
|
21241
21292
|
switch (kind) {
|
|
21242
|
-
case SESSION_TURN_UPDATED_KIND:
|
|
21243
|
-
return decodeSessionTurnUpdatedEvent(encoded);
|
|
21244
21293
|
case SESSION_QUEUE_CHANGED_KIND:
|
|
21245
21294
|
return decode5(encoded, sessionQueueChangedSchema);
|
|
21246
21295
|
case AGENT_ACTIVITY_KIND:
|
|
@@ -21409,6 +21458,21 @@ var serviceToDaemonSignatures = {
|
|
|
21409
21458
|
encodeSessionElicitationRespondCommand,
|
|
21410
21459
|
decodeSessionElicitationRespondCommand
|
|
21411
21460
|
),
|
|
21461
|
+
[SESSION_EVENT_ACK_KIND]: defineMessageSignature(
|
|
21462
|
+
SESSION_EVENT_ACK_KIND,
|
|
21463
|
+
encodeSessionEventAcknowledgement,
|
|
21464
|
+
decodeSessionEventAcknowledgement
|
|
21465
|
+
),
|
|
21466
|
+
[SESSION_EVENT_DEFERRED_KIND]: defineMessageSignature(
|
|
21467
|
+
SESSION_EVENT_DEFERRED_KIND,
|
|
21468
|
+
encodeSessionEventDeferred,
|
|
21469
|
+
decodeSessionEventDeferred
|
|
21470
|
+
),
|
|
21471
|
+
[SESSION_EVENT_REJECTED_KIND]: defineMessageSignature(
|
|
21472
|
+
SESSION_EVENT_REJECTED_KIND,
|
|
21473
|
+
encodeSessionEventRejected,
|
|
21474
|
+
decodeSessionEventRejected
|
|
21475
|
+
),
|
|
21412
21476
|
[SESSION_LIVE_HISTORY_LOAD_KIND]: defineMessageSignature(
|
|
21413
21477
|
SESSION_LIVE_HISTORY_LOAD_KIND,
|
|
21414
21478
|
encodeSessionLiveHistoryLoad,
|
|
@@ -26703,7 +26767,7 @@ function createDaemonConfig(connection, agents = [], installableAgents = [], loc
|
|
|
26703
26767
|
}
|
|
26704
26768
|
|
|
26705
26769
|
// src/run-daemon.ts
|
|
26706
|
-
import { createHash as createHash5, randomUUID as
|
|
26770
|
+
import { createHash as createHash5, randomUUID as randomUUID7 } from "node:crypto";
|
|
26707
26771
|
import { join as join17 } from "node:path";
|
|
26708
26772
|
import { styleText } from "node:util";
|
|
26709
26773
|
|
|
@@ -37853,6 +37917,28 @@ var DaemonInstallationObserver = class {
|
|
|
37853
37917
|
|
|
37854
37918
|
// src/daemon-active-turn.ts
|
|
37855
37919
|
import { randomUUID } from "node:crypto";
|
|
37920
|
+
function activeMessageCharacters(message) {
|
|
37921
|
+
return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
|
|
37922
|
+
}
|
|
37923
|
+
var ACTIVE_TURN_TEXT_CHUNK_LIMIT = Math.floor(SESSION_HISTORY_CHARACTER_LIMIT / 2);
|
|
37924
|
+
function boundedRecoveryMessages(messages) {
|
|
37925
|
+
const selected = [];
|
|
37926
|
+
let remainingCharacters = SESSION_HISTORY_CHARACTER_LIMIT;
|
|
37927
|
+
for (let index = messages.length - 1; index >= 0 && selected.length < SESSION_HISTORY_MESSAGE_LIMIT; index -= 1) {
|
|
37928
|
+
const message = messages[index];
|
|
37929
|
+
if (message === void 0) {
|
|
37930
|
+
break;
|
|
37931
|
+
}
|
|
37932
|
+
const characters = activeMessageCharacters(message);
|
|
37933
|
+
if (characters <= remainingCharacters) {
|
|
37934
|
+
selected.unshift(message);
|
|
37935
|
+
remainingCharacters -= characters;
|
|
37936
|
+
continue;
|
|
37937
|
+
}
|
|
37938
|
+
break;
|
|
37939
|
+
}
|
|
37940
|
+
return { hasOlder: selected.length !== messages.length, messages: selected };
|
|
37941
|
+
}
|
|
37856
37942
|
var ActiveDaemonTurn = class {
|
|
37857
37943
|
attemptId;
|
|
37858
37944
|
command;
|
|
@@ -37860,9 +37946,7 @@ var ActiveDaemonTurn = class {
|
|
|
37860
37946
|
#finished = Promise.withResolvers();
|
|
37861
37947
|
#cancellationRequested = false;
|
|
37862
37948
|
#dispatch;
|
|
37863
|
-
#text = "";
|
|
37864
37949
|
#activities = /* @__PURE__ */ new Map();
|
|
37865
|
-
#content = /* @__PURE__ */ new Map();
|
|
37866
37950
|
#timeline;
|
|
37867
37951
|
#sequence = 0;
|
|
37868
37952
|
#interaction = null;
|
|
@@ -37909,9 +37993,17 @@ var ActiveDaemonTurn = class {
|
|
|
37909
37993
|
effectiveDisposition = () => this.#dispatch.kind === "promoted" ? SessionPromptDisposition.Steer : this.command.disposition;
|
|
37910
37994
|
recordEvent = (event) => {
|
|
37911
37995
|
if (event.kind === AGENT_MESSAGE_DELTA_KIND) {
|
|
37912
|
-
|
|
37996
|
+
const sequence = this.advance();
|
|
37913
37997
|
this.appendMessageText(event.messageId, event.text);
|
|
37914
|
-
return
|
|
37998
|
+
return {
|
|
37999
|
+
commandId: this.command.commandId,
|
|
38000
|
+
epoch: this.#epoch,
|
|
38001
|
+
kind: AGENT_MESSAGE_DELTA_KIND,
|
|
38002
|
+
messageId: event.messageId,
|
|
38003
|
+
sequence,
|
|
38004
|
+
sessionId: this.command.sessionId,
|
|
38005
|
+
text: event.text
|
|
38006
|
+
};
|
|
37915
38007
|
}
|
|
37916
38008
|
if (event.sessionId !== this.command.sessionId || "commandId" in event && event.commandId !== this.command.commandId) {
|
|
37917
38009
|
return event;
|
|
@@ -37958,7 +38050,6 @@ var ActiveDaemonTurn = class {
|
|
|
37958
38050
|
toolKind: previous?.toolKind ?? ""
|
|
37959
38051
|
});
|
|
37960
38052
|
} else if (event.kind === AGENT_CONTENT_KIND) {
|
|
37961
|
-
this.#content.set(event.contentId, event.content);
|
|
37962
38053
|
const target = this.#timeline.findLastIndex(
|
|
37963
38054
|
(entry) => entry.kind === "message" && entry.sourceMessageId === event.messageId
|
|
37964
38055
|
);
|
|
@@ -37984,7 +38075,7 @@ var ActiveDaemonTurn = class {
|
|
|
37984
38075
|
this.#interaction = null;
|
|
37985
38076
|
}
|
|
37986
38077
|
if (event.kind === AGENT_ACTIVITY_KIND || event.kind === AGENT_ACTIVITY_NARRATION_KIND || event.kind === AGENT_CONTENT_KIND) {
|
|
37987
|
-
|
|
38078
|
+
this.advance();
|
|
37988
38079
|
}
|
|
37989
38080
|
return event;
|
|
37990
38081
|
};
|
|
@@ -37993,7 +38084,7 @@ var ActiveDaemonTurn = class {
|
|
|
37993
38084
|
while (remaining.length > 0) {
|
|
37994
38085
|
const latest = this.#timeline.at(-1);
|
|
37995
38086
|
if (latest?.kind === "message" && latest.sourceMessageId === messageId) {
|
|
37996
|
-
const available =
|
|
38087
|
+
const available = ACTIVE_TURN_TEXT_CHUNK_LIMIT - latest.text.length;
|
|
37997
38088
|
if (available > 0) {
|
|
37998
38089
|
this.#timeline = [
|
|
37999
38090
|
...this.#timeline.slice(0, -1),
|
|
@@ -38010,21 +38101,22 @@ var ActiveDaemonTurn = class {
|
|
|
38010
38101
|
id: decodeIdentifier(randomUUID()),
|
|
38011
38102
|
kind: "message",
|
|
38012
38103
|
sourceMessageId: messageId,
|
|
38013
|
-
text: remaining.slice(0,
|
|
38104
|
+
text: remaining.slice(0, ACTIVE_TURN_TEXT_CHUNK_LIMIT)
|
|
38014
38105
|
}
|
|
38015
38106
|
];
|
|
38016
|
-
remaining = remaining.slice(
|
|
38107
|
+
remaining = remaining.slice(ACTIVE_TURN_TEXT_CHUNK_LIMIT);
|
|
38017
38108
|
}
|
|
38018
38109
|
}
|
|
38019
38110
|
recordSteeringPrompt = (command) => {
|
|
38020
38111
|
if (this.#dispatch.kind !== "running" || command.sessionId !== this.command.sessionId || command.targetCommandId !== this.command.commandId) {
|
|
38021
|
-
return
|
|
38112
|
+
return false;
|
|
38022
38113
|
}
|
|
38023
38114
|
this.#timeline = [
|
|
38024
38115
|
...this.#timeline,
|
|
38025
38116
|
{ id: decodeIdentifier(command.commandId), images: command.images, kind: "user", text: command.prompt }
|
|
38026
38117
|
];
|
|
38027
|
-
|
|
38118
|
+
this.advance();
|
|
38119
|
+
return true;
|
|
38028
38120
|
};
|
|
38029
38121
|
timelineMessages() {
|
|
38030
38122
|
return this.#timeline.flatMap((entry) => {
|
|
@@ -38046,32 +38138,39 @@ var ActiveDaemonTurn = class {
|
|
|
38046
38138
|
return activity2 === void 0 ? [] : [{ activities: [activity2], content: [], id: entry.id, role: "assistant", text: "" }];
|
|
38047
38139
|
});
|
|
38048
38140
|
}
|
|
38049
|
-
|
|
38050
|
-
this.#
|
|
38051
|
-
|
|
38052
|
-
if (turn === null) {
|
|
38053
|
-
throw new Error("Only a running turn can publish a snapshot");
|
|
38141
|
+
advance = () => {
|
|
38142
|
+
if (this.#dispatch.kind !== "running") {
|
|
38143
|
+
throw new Error("Only a running turn can advance its snapshot");
|
|
38054
38144
|
}
|
|
38055
|
-
|
|
38145
|
+
this.#sequence += 1;
|
|
38146
|
+
return this.#sequence;
|
|
38056
38147
|
};
|
|
38057
38148
|
snapshot = () => {
|
|
38058
38149
|
if (this.#dispatch.kind !== "running") {
|
|
38059
38150
|
return null;
|
|
38060
38151
|
}
|
|
38061
|
-
const
|
|
38062
|
-
const messages = completeMessages.slice(-SESSION_HISTORY_MESSAGE_LIMIT);
|
|
38152
|
+
const bounded2 = boundedRecoveryMessages(this.timelineMessages());
|
|
38063
38153
|
return {
|
|
38064
|
-
activities: [...this.#activities.values()].sort((left, right) => left.sequence - right.sequence),
|
|
38065
38154
|
commandId: decodeIdentifier(this.command.commandId),
|
|
38066
|
-
content: [...this.#content.values()],
|
|
38067
|
-
prompt: this.command.prompt,
|
|
38068
|
-
text: this.#text,
|
|
38069
|
-
truncated: messages.length !== completeMessages.length,
|
|
38070
38155
|
epoch: this.#epoch,
|
|
38156
|
+
hasOlder: bounded2.hasOlder,
|
|
38071
38157
|
interaction: this.#interaction,
|
|
38072
|
-
messages,
|
|
38158
|
+
messages: bounded2.messages,
|
|
38073
38159
|
sequence: this.#sequence,
|
|
38074
|
-
state: "running"
|
|
38160
|
+
state: "running",
|
|
38161
|
+
truncated: false
|
|
38162
|
+
};
|
|
38163
|
+
};
|
|
38164
|
+
recovery = () => {
|
|
38165
|
+
if (this.#dispatch.kind !== "running") {
|
|
38166
|
+
return null;
|
|
38167
|
+
}
|
|
38168
|
+
return {
|
|
38169
|
+
commandId: decodeIdentifier(this.command.commandId),
|
|
38170
|
+
epoch: this.#epoch,
|
|
38171
|
+
messages: this.timelineMessages(),
|
|
38172
|
+
state: "running",
|
|
38173
|
+
truncated: false
|
|
38075
38174
|
};
|
|
38076
38175
|
};
|
|
38077
38176
|
matches = (cancellation) => cancellation.commandId === this.command.commandId && cancellation.sessionId === this.command.sessionId;
|
|
@@ -38097,6 +38196,7 @@ var ActiveDaemonTurn = class {
|
|
|
38097
38196
|
};
|
|
38098
38197
|
|
|
38099
38198
|
// src/daemon-turn-registry.ts
|
|
38199
|
+
var COMPLETED_TURN_RECOVERY_LIMIT = 32;
|
|
38100
38200
|
var waitForTurnCompletion = (turn, waitSignal) => {
|
|
38101
38201
|
waitSignal.throwIfAborted();
|
|
38102
38202
|
return new Promise((resolve9, reject) => {
|
|
@@ -38123,6 +38223,7 @@ var waitForTurnCompletion = (turn, waitSignal) => {
|
|
|
38123
38223
|
};
|
|
38124
38224
|
var DaemonTurnRegistry = class {
|
|
38125
38225
|
#turns = /* @__PURE__ */ new Map();
|
|
38226
|
+
#completed = /* @__PURE__ */ new Map();
|
|
38126
38227
|
#operations;
|
|
38127
38228
|
constructor(operations) {
|
|
38128
38229
|
this.#operations = operations;
|
|
@@ -38134,7 +38235,22 @@ var DaemonTurnRegistry = class {
|
|
|
38134
38235
|
};
|
|
38135
38236
|
get = (commandId) => this.#turns.get(commandId);
|
|
38136
38237
|
finish = (turn) => {
|
|
38238
|
+
const recovery = turn.recovery();
|
|
38137
38239
|
this.#turns.delete(turn.command.commandId);
|
|
38240
|
+
if (recovery !== null) {
|
|
38241
|
+
this.#completed.delete(turn.command.sessionId);
|
|
38242
|
+
this.#completed.set(turn.command.sessionId, {
|
|
38243
|
+
command: turn.command,
|
|
38244
|
+
recovery: { ...recovery, state: "completed" }
|
|
38245
|
+
});
|
|
38246
|
+
while (this.#completed.size > COMPLETED_TURN_RECOVERY_LIMIT) {
|
|
38247
|
+
const oldestSessionId = this.#completed.keys().next().value;
|
|
38248
|
+
if (oldestSessionId === void 0) {
|
|
38249
|
+
break;
|
|
38250
|
+
}
|
|
38251
|
+
this.#completed.delete(oldestSessionId);
|
|
38252
|
+
}
|
|
38253
|
+
}
|
|
38138
38254
|
turn.finish();
|
|
38139
38255
|
};
|
|
38140
38256
|
recordEvent = (event) => {
|
|
@@ -38155,7 +38271,7 @@ var DaemonTurnRegistry = class {
|
|
|
38155
38271
|
};
|
|
38156
38272
|
recordSteeringPrompt = (command) => {
|
|
38157
38273
|
const target = this.#turns.get(command.targetCommandId);
|
|
38158
|
-
return target?.recordSteeringPrompt(command) ??
|
|
38274
|
+
return target?.recordSteeringPrompt(command) ?? false;
|
|
38159
38275
|
};
|
|
38160
38276
|
executionSnapshot = async (matches) => {
|
|
38161
38277
|
const matching = [];
|
|
@@ -38186,12 +38302,30 @@ var DaemonTurnRegistry = class {
|
|
|
38186
38302
|
}
|
|
38187
38303
|
return null;
|
|
38188
38304
|
};
|
|
38305
|
+
recovery = (matches) => {
|
|
38306
|
+
for (const turn of this.#turns.values()) {
|
|
38307
|
+
if (!matches(turn.command)) {
|
|
38308
|
+
continue;
|
|
38309
|
+
}
|
|
38310
|
+
const recovery = turn.recovery();
|
|
38311
|
+
if (recovery !== null) {
|
|
38312
|
+
return recovery;
|
|
38313
|
+
}
|
|
38314
|
+
}
|
|
38315
|
+
for (const completed of this.#completed.values()) {
|
|
38316
|
+
if (matches(completed.command)) {
|
|
38317
|
+
return completed.recovery;
|
|
38318
|
+
}
|
|
38319
|
+
}
|
|
38320
|
+
return null;
|
|
38321
|
+
};
|
|
38189
38322
|
close = async () => {
|
|
38190
38323
|
const turns = [...this.#turns.values()];
|
|
38191
38324
|
for (const turn of turns) {
|
|
38192
38325
|
turn.abortDaemon();
|
|
38193
38326
|
}
|
|
38194
38327
|
await Promise.all(turns.map((turn) => turn.completion));
|
|
38328
|
+
this.#completed.clear();
|
|
38195
38329
|
};
|
|
38196
38330
|
admitAndWait = async (turn, waitSignal, onQueued) => {
|
|
38197
38331
|
const command = turn.command;
|
|
@@ -40499,10 +40633,10 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
|
|
|
40499
40633
|
}
|
|
40500
40634
|
|
|
40501
40635
|
// src/native-sessions/live-history-page.ts
|
|
40502
|
-
function
|
|
40503
|
-
return Buffer.from(JSON.stringify(
|
|
40636
|
+
function encodeLiveHistoryCursor(cursor) {
|
|
40637
|
+
return Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
|
|
40504
40638
|
}
|
|
40505
|
-
function
|
|
40639
|
+
function decodeLiveHistoryCursor(cursor, sessionId) {
|
|
40506
40640
|
try {
|
|
40507
40641
|
if (!/^[A-Za-z0-9_-]{1,512}$/u.test(cursor)) {
|
|
40508
40642
|
throw new Error("Invalid cursor alphabet");
|
|
@@ -40512,14 +40646,32 @@ function liveHistoryEndIndex(cursor, sessionId) {
|
|
|
40512
40646
|
throw new Error("Invalid cursor shape");
|
|
40513
40647
|
}
|
|
40514
40648
|
const record2 = Object.fromEntries(Object.entries(value));
|
|
40515
|
-
|
|
40649
|
+
const keys = Object.keys(record2).sort().join(",");
|
|
40650
|
+
const legacyNative = keys === "endIndex,sessionId";
|
|
40651
|
+
const kind = legacyNative ? "native" : record2["kind"];
|
|
40652
|
+
if (keys !== "endIndex,kind,sessionId" && keys !== "endIndex,epoch,kind,sessionId" && !legacyNative || record2["sessionId"] !== sessionId || kind !== "active" && kind !== "native" || typeof record2["endIndex"] !== "number" || !Number.isSafeInteger(record2["endIndex"]) || record2["endIndex"] < 0) {
|
|
40516
40653
|
throw new Error("Invalid cursor target");
|
|
40517
40654
|
}
|
|
40518
|
-
|
|
40655
|
+
if (kind === "active") {
|
|
40656
|
+
if (keys !== "endIndex,epoch,kind,sessionId" || typeof record2["epoch"] !== "string") {
|
|
40657
|
+
throw new Error("Invalid active cursor target");
|
|
40658
|
+
}
|
|
40659
|
+
return { endIndex: record2["endIndex"], epoch: record2["epoch"], kind, sessionId };
|
|
40660
|
+
}
|
|
40661
|
+
if (keys !== "endIndex,kind,sessionId" && !legacyNative) {
|
|
40662
|
+
throw new Error("Invalid native cursor target");
|
|
40663
|
+
}
|
|
40664
|
+
return { endIndex: record2["endIndex"], kind, sessionId };
|
|
40519
40665
|
} catch (cause) {
|
|
40520
40666
|
throw new AcpExecutionError("The native Session history cursor is invalid", { cause }, "invalid_cursor");
|
|
40521
40667
|
}
|
|
40522
40668
|
}
|
|
40669
|
+
function activeHistoryCursor(sessionId, epoch, endIndex) {
|
|
40670
|
+
return encodeLiveHistoryCursor({ endIndex, epoch, kind: "active", sessionId });
|
|
40671
|
+
}
|
|
40672
|
+
function nativeHistoryCursor(sessionId, endIndex) {
|
|
40673
|
+
return encodeLiveHistoryCursor({ endIndex, kind: "native", sessionId });
|
|
40674
|
+
}
|
|
40523
40675
|
function liveHistoryCoveredTurnRanges(history) {
|
|
40524
40676
|
const ranges = [];
|
|
40525
40677
|
let historyIndex = history.messages.length;
|
|
@@ -40540,139 +40692,180 @@ function liveHistoryCoveredTurnRanges(history) {
|
|
|
40540
40692
|
function historyMessageCharacters(message) {
|
|
40541
40693
|
return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
|
|
40542
40694
|
}
|
|
40543
|
-
function
|
|
40695
|
+
function isNativeHistoryImageMimeType(mimeType) {
|
|
40696
|
+
return mimeType === "image/png" || mimeType === "image/jpeg" || mimeType === "image/gif" || mimeType === "image/webp";
|
|
40697
|
+
}
|
|
40698
|
+
function selectMessagesBefore(messages, endIndex, messageLimit, characterLimit) {
|
|
40544
40699
|
const selected = [];
|
|
40545
40700
|
let remainingCharacters = characterLimit;
|
|
40546
|
-
|
|
40701
|
+
let startIndex = endIndex;
|
|
40702
|
+
for (let index = endIndex - 1; index >= 0 && selected.length < messageLimit; index -= 1) {
|
|
40547
40703
|
const message = messages[index];
|
|
40548
40704
|
if (message === void 0) {
|
|
40549
40705
|
break;
|
|
40550
40706
|
}
|
|
40551
40707
|
const characters = historyMessageCharacters(message);
|
|
40552
|
-
if (characters
|
|
40553
|
-
|
|
40554
|
-
remainingCharacters -= characters;
|
|
40555
|
-
continue;
|
|
40556
|
-
}
|
|
40557
|
-
const structuredCharacters = characters - message.text.length;
|
|
40558
|
-
if (selected.length === 0 && structuredCharacters <= remainingCharacters) {
|
|
40559
|
-
const textCharacters = remainingCharacters - structuredCharacters;
|
|
40560
|
-
selected.unshift({ ...message, text: textCharacters === 0 ? "" : message.text.slice(-textCharacters) });
|
|
40561
|
-
remainingCharacters = 0;
|
|
40708
|
+
if (characters > remainingCharacters) {
|
|
40709
|
+
break;
|
|
40562
40710
|
}
|
|
40563
|
-
|
|
40711
|
+
selected.unshift(message);
|
|
40712
|
+
remainingCharacters -= characters;
|
|
40713
|
+
startIndex = index;
|
|
40564
40714
|
}
|
|
40565
|
-
|
|
40566
|
-
|
|
40567
|
-
|
|
40568
|
-
|
|
40569
|
-
|
|
40715
|
+
if (selected.length === 0 && endIndex > 0) {
|
|
40716
|
+
throw new AcpExecutionError(
|
|
40717
|
+
"A native Session history item exceeds the page budget",
|
|
40718
|
+
{},
|
|
40719
|
+
"history_item_too_large"
|
|
40720
|
+
);
|
|
40721
|
+
}
|
|
40722
|
+
return { characters: characterLimit - remainingCharacters, messages: selected, startIndex };
|
|
40570
40723
|
}
|
|
40571
40724
|
function nativeActiveMessage(message) {
|
|
40572
|
-
|
|
40573
|
-
|
|
40574
|
-
|
|
40575
|
-
|
|
40576
|
-
|
|
40577
|
-
|
|
40725
|
+
if (message.role === "assistant") {
|
|
40726
|
+
return {
|
|
40727
|
+
activities: message.activities,
|
|
40728
|
+
content: message.content,
|
|
40729
|
+
role: "assistant",
|
|
40730
|
+
text: message.text
|
|
40731
|
+
};
|
|
40732
|
+
}
|
|
40733
|
+
const images = (message.images ?? []).flatMap((image) => {
|
|
40734
|
+
if (image.data.length < 4 || image.data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/u.test(image.data) || !isNativeHistoryImageMimeType(image.mimeType)) {
|
|
40735
|
+
return [];
|
|
40736
|
+
}
|
|
40737
|
+
return [{ data: image.data, mimeType: image.mimeType, name: image.name }];
|
|
40738
|
+
});
|
|
40739
|
+
return { ...images.length === 0 ? {} : { images }, role: "user", text: message.text };
|
|
40740
|
+
}
|
|
40741
|
+
function nativeHistoryCoversCompletedRecovery(history, recovery) {
|
|
40742
|
+
const root = recovery.messages.find((message) => message.role === "user" && message.id === recovery.commandId);
|
|
40743
|
+
if (root === void 0) {
|
|
40744
|
+
return false;
|
|
40745
|
+
}
|
|
40746
|
+
const rootIndex = history.messages.findLastIndex(
|
|
40747
|
+
(message) => message.role === "user" && message.text === root.text
|
|
40748
|
+
);
|
|
40749
|
+
if (rootIndex < 0) {
|
|
40750
|
+
return false;
|
|
40751
|
+
}
|
|
40752
|
+
const nativeAssistant = history.messages.slice(rootIndex + 1).filter((message) => message.role === "assistant");
|
|
40753
|
+
if (nativeAssistant.length === 0) {
|
|
40754
|
+
return false;
|
|
40755
|
+
}
|
|
40756
|
+
const recoveryAssistant = recovery.messages.filter((message) => message.role === "assistant");
|
|
40757
|
+
const recoveryText = recoveryAssistant.map((message) => message.text).join("");
|
|
40758
|
+
const nativeText = nativeAssistant.map((message) => message.text).join("");
|
|
40759
|
+
if (recoveryText.length > 0 && !nativeText.includes(recoveryText)) {
|
|
40760
|
+
return false;
|
|
40761
|
+
}
|
|
40762
|
+
const nativeContent = new Set(
|
|
40763
|
+
nativeAssistant.flatMap((message) => message.content).map((content) => JSON.stringify(content))
|
|
40764
|
+
);
|
|
40765
|
+
return recoveryAssistant.flatMap((message) => message.content).every((content) => nativeContent.has(JSON.stringify(content)));
|
|
40578
40766
|
}
|
|
40579
|
-
function
|
|
40767
|
+
function historyBeforeActiveTurn(history, activeTurn) {
|
|
40580
40768
|
if (history.status === "unavailable") {
|
|
40581
|
-
|
|
40582
|
-
throw new AcpExecutionError("Unavailable native Session history has no cursor", {}, "invalid_cursor");
|
|
40583
|
-
}
|
|
40584
|
-
return { cause: history.cause, nextCursor: null, status: "unavailable" };
|
|
40769
|
+
return history;
|
|
40585
40770
|
}
|
|
40586
|
-
const
|
|
40771
|
+
const activeRoot = activeTurn.messages.find(
|
|
40772
|
+
(message) => message.role === "user" && message.id === activeTurn.commandId
|
|
40773
|
+
);
|
|
40774
|
+
const matchingActiveUserIndex = activeRoot === void 0 ? -1 : activeTurn.state === "completed" || history.messages.at(-1)?.role === "user" && history.messages.at(-1)?.text === activeRoot.text || history.coveredCommandIds.includes(activeTurn.commandId) ? history.messages.findLastIndex((message) => message.role === "user" && message.text === activeRoot.text) : -1;
|
|
40775
|
+
const activeUserIndex = matchingActiveUserIndex >= 0 ? matchingActiveUserIndex : liveHistoryCoveredTurnRanges(history).find((range) => range.commandId === activeTurn.commandId)?.userIndex ?? -1;
|
|
40776
|
+
if (activeUserIndex < 0) {
|
|
40777
|
+
return history;
|
|
40778
|
+
}
|
|
40779
|
+
return {
|
|
40780
|
+
...history,
|
|
40781
|
+
coveredCommandIds: history.coveredCommandIds.filter((id) => id !== activeTurn.commandId),
|
|
40782
|
+
coveredMessageIds: history.coveredMessageIds.filter(
|
|
40783
|
+
(id) => id !== `${activeTurn.commandId}:user` && id !== `${activeTurn.commandId}:agent`
|
|
40784
|
+
),
|
|
40785
|
+
messages: history.messages.slice(0, activeUserIndex)
|
|
40786
|
+
};
|
|
40787
|
+
}
|
|
40788
|
+
function paginateAvailableNativeHistory(history, sessionId, endIndex, limit, characterLimit) {
|
|
40587
40789
|
if (endIndex > history.messages.length) {
|
|
40588
40790
|
throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
|
|
40589
40791
|
}
|
|
40590
|
-
const
|
|
40792
|
+
const selected = selectMessagesBefore(history.messages, endIndex, limit, characterLimit);
|
|
40591
40793
|
const coveredMessageIds = new Set(history.coveredMessageIds);
|
|
40592
40794
|
const ranges = liveHistoryCoveredTurnRanges(history);
|
|
40593
40795
|
return {
|
|
40594
|
-
coveredCommandIds: ranges.filter((range) => range.userIndex >= startIndex && range.assistantEndIndex <= endIndex).map((range) => range.commandId),
|
|
40796
|
+
coveredCommandIds: ranges.filter((range) => range.userIndex >= selected.startIndex && range.assistantEndIndex <= endIndex).map((range) => range.commandId),
|
|
40595
40797
|
coveredMessageIds: ranges.flatMap((range) => [
|
|
40596
|
-
...range.userIndex >= startIndex && range.userIndex < endIndex && coveredMessageIds.has(`${range.commandId}:user`) ? [`${range.commandId}:user`] : [],
|
|
40597
|
-
...range.assistantStartIndex >= startIndex && range.assistantEndIndex <= endIndex && coveredMessageIds.has(`${range.commandId}:agent`) ? [`${range.commandId}:agent`] : []
|
|
40798
|
+
...range.userIndex >= selected.startIndex && range.userIndex < endIndex && coveredMessageIds.has(`${range.commandId}:user`) ? [`${range.commandId}:user`] : [],
|
|
40799
|
+
...range.assistantStartIndex >= selected.startIndex && range.assistantEndIndex <= endIndex && coveredMessageIds.has(`${range.commandId}:agent`) ? [`${range.commandId}:agent`] : []
|
|
40598
40800
|
]),
|
|
40599
|
-
messages:
|
|
40600
|
-
nextCursor: startIndex > 0 ?
|
|
40801
|
+
messages: selected.messages,
|
|
40802
|
+
nextCursor: selected.startIndex > 0 ? nativeHistoryCursor(sessionId, selected.startIndex) : null,
|
|
40601
40803
|
status: "available",
|
|
40602
40804
|
truncated: history.truncated
|
|
40603
40805
|
};
|
|
40604
40806
|
}
|
|
40605
|
-
function
|
|
40606
|
-
if (
|
|
40607
|
-
|
|
40807
|
+
function paginateNativeHistory(history, sessionId, cursor, limit) {
|
|
40808
|
+
if (cursor?.kind === "active") {
|
|
40809
|
+
throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
|
|
40608
40810
|
}
|
|
40609
40811
|
if (history.status === "unavailable") {
|
|
40610
|
-
|
|
40611
|
-
|
|
40612
|
-
|
|
40613
|
-
|
|
40614
|
-
);
|
|
40615
|
-
return {
|
|
40616
|
-
coveredCommandIds: [],
|
|
40617
|
-
coveredMessageIds: [],
|
|
40618
|
-
messages: bounded3.messages,
|
|
40619
|
-
nextCursor: null,
|
|
40620
|
-
status: "available",
|
|
40621
|
-
truncated: activeTurn.truncated || bounded3.truncated
|
|
40622
|
-
};
|
|
40812
|
+
if (cursor !== null) {
|
|
40813
|
+
throw new AcpExecutionError("Unavailable native Session history has no cursor", {}, "invalid_cursor");
|
|
40814
|
+
}
|
|
40815
|
+
return { cause: history.cause, nextCursor: null, status: "unavailable" };
|
|
40623
40816
|
}
|
|
40624
|
-
|
|
40625
|
-
|
|
40817
|
+
return paginateAvailableNativeHistory(
|
|
40818
|
+
history,
|
|
40819
|
+
sessionId,
|
|
40820
|
+
cursor?.endIndex ?? history.messages.length,
|
|
40821
|
+
limit,
|
|
40822
|
+
SESSION_HISTORY_CHARACTER_LIMIT
|
|
40626
40823
|
);
|
|
40627
|
-
|
|
40628
|
-
|
|
40629
|
-
|
|
40630
|
-
|
|
40631
|
-
const activeUserIndex = matchingActiveUserIndex >= 0 ? matchingActiveUserIndex : liveHistoryCoveredTurnRanges(history).find((range) => range.commandId === activeTurn.commandId)?.userIndex ?? -1;
|
|
40632
|
-
if (activeUserIndex >= 0) {
|
|
40633
|
-
history = {
|
|
40634
|
-
...history,
|
|
40635
|
-
coveredCommandIds: history.coveredCommandIds.filter((id) => id !== activeTurn.commandId),
|
|
40636
|
-
coveredMessageIds: history.coveredMessageIds.filter(
|
|
40637
|
-
(id) => id !== `${activeTurn.commandId}:user` && id !== `${activeTurn.commandId}:agent`
|
|
40638
|
-
),
|
|
40639
|
-
messages: history.messages.slice(0, activeUserIndex + 1)
|
|
40640
|
-
};
|
|
40641
|
-
}
|
|
40642
|
-
const latestNativeMessage = history.messages.at(-1);
|
|
40643
|
-
const firstActiveMessage = activeTurn.messages[0];
|
|
40644
|
-
const preserveNativeRoot = activeUserIndex >= 0 || firstActiveMessage?.role === "user" && latestNativeMessage?.role === "user" && latestNativeMessage.text === firstActiveMessage.text;
|
|
40645
|
-
const activeMessages = activeTurn.messages.slice(preserveNativeRoot ? 1 : 0).map(nativeActiveMessage);
|
|
40646
|
-
const bounded2 = boundedActiveMessages(activeMessages, limit, SESSION_HISTORY_CHARACTER_LIMIT);
|
|
40647
|
-
let historicalMessageCount = 0;
|
|
40648
|
-
let remainingCharacters = SESSION_HISTORY_CHARACTER_LIMIT - bounded2.characters;
|
|
40649
|
-
const historicalMessageLimit = Math.max(0, limit - bounded2.messages.length);
|
|
40650
|
-
for (let index = history.messages.length - 1; index >= 0 && historicalMessageCount < historicalMessageLimit; index -= 1) {
|
|
40651
|
-
const message = history.messages[index];
|
|
40652
|
-
if (message === void 0) {
|
|
40653
|
-
break;
|
|
40654
|
-
}
|
|
40655
|
-
const characters = historyMessageCharacters(message);
|
|
40656
|
-
if (characters > remainingCharacters) {
|
|
40657
|
-
break;
|
|
40658
|
-
}
|
|
40659
|
-
historicalMessageCount += 1;
|
|
40660
|
-
remainingCharacters -= characters;
|
|
40824
|
+
}
|
|
40825
|
+
function paginateActiveTurn(history, activeTurn, sessionId, endIndex, limit) {
|
|
40826
|
+
if (endIndex > activeTurn.messages.length) {
|
|
40827
|
+
throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
|
|
40661
40828
|
}
|
|
40662
|
-
const
|
|
40663
|
-
|
|
40664
|
-
|
|
40665
|
-
|
|
40666
|
-
|
|
40667
|
-
|
|
40668
|
-
|
|
40669
|
-
|
|
40829
|
+
const activeMessages = activeTurn.messages.map(nativeActiveMessage);
|
|
40830
|
+
const active = selectMessagesBefore(activeMessages, endIndex, limit, SESSION_HISTORY_CHARACTER_LIMIT);
|
|
40831
|
+
const historicalLimit = limit - active.messages.length;
|
|
40832
|
+
const historicalCharacterLimit = SESSION_HISTORY_CHARACTER_LIMIT - active.characters;
|
|
40833
|
+
const pendingHistoricalCursor = history.status === "available" && history.messages.length > 0 ? nativeHistoryCursor(sessionId, history.messages.length) : null;
|
|
40834
|
+
const latestHistoricalMessage = history.status === "available" ? history.messages.at(-1) : void 0;
|
|
40835
|
+
const historicalPageFits = latestHistoricalMessage === void 0 || historyMessageCharacters(latestHistoricalMessage) <= historicalCharacterLimit;
|
|
40836
|
+
const historical = active.startIndex === 0 && history.status === "available" && historicalLimit > 0 && historicalPageFits ? paginateAvailableNativeHistory(
|
|
40837
|
+
history,
|
|
40838
|
+
sessionId,
|
|
40839
|
+
history.messages.length,
|
|
40840
|
+
historicalLimit,
|
|
40841
|
+
historicalCharacterLimit
|
|
40842
|
+
) : null;
|
|
40670
40843
|
return {
|
|
40671
|
-
|
|
40672
|
-
|
|
40673
|
-
|
|
40844
|
+
coveredCommandIds: historical?.coveredCommandIds ?? [],
|
|
40845
|
+
coveredMessageIds: [
|
|
40846
|
+
...historical?.coveredMessageIds ?? [],
|
|
40847
|
+
...active.startIndex === 0 ? [`${activeTurn.commandId}:user`, `${activeTurn.commandId}:agent`] : []
|
|
40848
|
+
],
|
|
40849
|
+
messages: [...historical?.messages ?? [], ...active.messages],
|
|
40850
|
+
nextCursor: active.startIndex > 0 ? activeHistoryCursor(sessionId, activeTurn.epoch, active.startIndex) : historical === null ? pendingHistoricalCursor : historical.nextCursor,
|
|
40851
|
+
status: "available",
|
|
40852
|
+
truncated: activeTurn.truncated || (historical?.truncated ?? false)
|
|
40674
40853
|
};
|
|
40675
40854
|
}
|
|
40855
|
+
function paginateLiveSessionHistory(history, activeTurn, sessionId, encodedCursor, limit) {
|
|
40856
|
+
const cursor = encodedCursor === null ? null : decodeLiveHistoryCursor(encodedCursor, sessionId);
|
|
40857
|
+
if (activeTurn === null || activeTurn.state === "completed" && history.status === "available" && nativeHistoryCoversCompletedRecovery(history, activeTurn)) {
|
|
40858
|
+
return paginateNativeHistory(history, sessionId, cursor, limit);
|
|
40859
|
+
}
|
|
40860
|
+
const historical = historyBeforeActiveTurn(history, activeTurn);
|
|
40861
|
+
if (cursor?.kind === "native") {
|
|
40862
|
+
return paginateNativeHistory(historical, sessionId, cursor, limit);
|
|
40863
|
+
}
|
|
40864
|
+
if (cursor !== null && cursor.epoch !== activeTurn.epoch) {
|
|
40865
|
+
throw new AcpExecutionError("The active Turn history cursor is stale", {}, "stale_cursor");
|
|
40866
|
+
}
|
|
40867
|
+
return paginateActiveTurn(historical, activeTurn, sessionId, cursor?.endIndex ?? activeTurn.messages.length, limit);
|
|
40868
|
+
}
|
|
40676
40869
|
function mergeLiveSessionHistory(history, activeTurn, sessionId) {
|
|
40677
40870
|
const page = paginateLiveSessionHistory(history, activeTurn, sessionId, null, 1e3);
|
|
40678
40871
|
if (page.status === "unavailable") {
|
|
@@ -40683,7 +40876,7 @@ function mergeLiveSessionHistory(history, activeTurn, sessionId) {
|
|
|
40683
40876
|
coveredMessageIds: page.coveredMessageIds,
|
|
40684
40877
|
messages: page.messages,
|
|
40685
40878
|
status: "available",
|
|
40686
|
-
truncated: page.truncated
|
|
40879
|
+
truncated: page.truncated || page.nextCursor !== null
|
|
40687
40880
|
};
|
|
40688
40881
|
}
|
|
40689
40882
|
|
|
@@ -41202,15 +41395,13 @@ async function executePrompt({
|
|
|
41202
41395
|
});
|
|
41203
41396
|
operations.transitionExecution(command.commandId, "running");
|
|
41204
41397
|
if (availability.disposition === SessionPromptDisposition.Steer) {
|
|
41205
|
-
|
|
41206
|
-
if (updated === null) {
|
|
41398
|
+
if (!recordSteeringPrompt()) {
|
|
41207
41399
|
throw new AcpExecutionError(
|
|
41208
41400
|
"The steering target is unavailable",
|
|
41209
41401
|
{},
|
|
41210
41402
|
"prompt_queue_target_unavailable"
|
|
41211
41403
|
);
|
|
41212
41404
|
}
|
|
41213
|
-
publisher.publish(command.sessionId, updated);
|
|
41214
41405
|
}
|
|
41215
41406
|
const stream = activateAttempt();
|
|
41216
41407
|
publisher.publish(command.sessionId, {
|
|
@@ -41598,7 +41789,7 @@ function createDaemonCommandHandler({
|
|
|
41598
41789
|
resolveEnvironment: resolveAgentCatalogEnvironment
|
|
41599
41790
|
});
|
|
41600
41791
|
const queueChanged = (sessionId) => publisher.publish(sessionId, { kind: "session.queue.changed", sessionId });
|
|
41601
|
-
const
|
|
41792
|
+
const activeTurnRecovery = (sessionId) => activeTurns.recovery((command) => command.sessionId === sessionId);
|
|
41602
41793
|
const nativeRequestHandler = createNativeSessionRequestHandler({
|
|
41603
41794
|
audit,
|
|
41604
41795
|
diagnostics,
|
|
@@ -41619,7 +41810,7 @@ function createDaemonCommandHandler({
|
|
|
41619
41810
|
directories,
|
|
41620
41811
|
audit,
|
|
41621
41812
|
sessions,
|
|
41622
|
-
|
|
41813
|
+
activeTurnRecovery,
|
|
41623
41814
|
signal
|
|
41624
41815
|
);
|
|
41625
41816
|
return;
|
|
@@ -41633,7 +41824,7 @@ function createDaemonCommandHandler({
|
|
|
41633
41824
|
directories,
|
|
41634
41825
|
audit,
|
|
41635
41826
|
sessions,
|
|
41636
|
-
|
|
41827
|
+
activeTurnRecovery,
|
|
41637
41828
|
signal
|
|
41638
41829
|
);
|
|
41639
41830
|
return;
|
|
@@ -42125,6 +42316,7 @@ async function runRelayConnection({
|
|
|
42125
42316
|
}) {
|
|
42126
42317
|
const relayUrl = new URL(config2.relayUrl);
|
|
42127
42318
|
relayUrl.searchParams.set("liveness", "1");
|
|
42319
|
+
relayUrl.searchParams.set("sessionEventDelivery", "reliable-v1");
|
|
42128
42320
|
const socket = await connectRelay(relayUrl, signal);
|
|
42129
42321
|
diagnostics.connectionOpened(connectionEpoch);
|
|
42130
42322
|
const connectionController = new AbortController();
|
|
@@ -42244,6 +42436,10 @@ async function runRelayConnection({
|
|
|
42244
42436
|
const message = decodeServiceToDaemonMessage(encoded);
|
|
42245
42437
|
const kind = message.kind;
|
|
42246
42438
|
if (kind === RUNTIME_LIVENESS_READY_KIND) {
|
|
42439
|
+
publisher.connect(
|
|
42440
|
+
socket,
|
|
42441
|
+
message.sessionEventDelivery === "reliable-v1" ? "reliable" : "ephemeral"
|
|
42442
|
+
);
|
|
42247
42443
|
connectionLiveness.start();
|
|
42248
42444
|
return;
|
|
42249
42445
|
}
|
|
@@ -42251,6 +42447,18 @@ async function runRelayConnection({
|
|
|
42251
42447
|
connectionLiveness.acknowledge(message);
|
|
42252
42448
|
return;
|
|
42253
42449
|
}
|
|
42450
|
+
if (kind === SESSION_EVENT_ACK_KIND) {
|
|
42451
|
+
publisher.acknowledge(message);
|
|
42452
|
+
return;
|
|
42453
|
+
}
|
|
42454
|
+
if (kind === SESSION_EVENT_DEFERRED_KIND) {
|
|
42455
|
+
publisher.defer(message);
|
|
42456
|
+
return;
|
|
42457
|
+
}
|
|
42458
|
+
if (kind === SESSION_EVENT_REJECTED_KIND) {
|
|
42459
|
+
publisher.quarantine(message);
|
|
42460
|
+
return;
|
|
42461
|
+
}
|
|
42254
42462
|
commands.handle(message);
|
|
42255
42463
|
} catch (error62) {
|
|
42256
42464
|
console.error("Mobius daemon rejected a message", error62);
|
|
@@ -42265,7 +42473,6 @@ async function runRelayConnection({
|
|
|
42265
42473
|
socket.addEventListener("close", handleClose);
|
|
42266
42474
|
socket.addEventListener("error", handleError);
|
|
42267
42475
|
socket.addEventListener("message", handleMessage);
|
|
42268
|
-
publisher.connect(socket);
|
|
42269
42476
|
if (signal.aborted) {
|
|
42270
42477
|
stop();
|
|
42271
42478
|
}
|
|
@@ -42276,54 +42483,377 @@ async function runRelayConnection({
|
|
|
42276
42483
|
}
|
|
42277
42484
|
}
|
|
42278
42485
|
|
|
42486
|
+
// src/relay-connection/session-event-outbox.ts
|
|
42487
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
42488
|
+
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
42489
|
+
import { dirname as dirname5 } from "node:path";
|
|
42490
|
+
import { DatabaseSync } from "node:sqlite";
|
|
42491
|
+
var DEFAULT_STANDARD_EVENT_BYTES = 96 * 1024 * 1024;
|
|
42492
|
+
var DEFAULT_CRITICAL_EVENT_BYTES = 128 * 1024 * 1024;
|
|
42493
|
+
var MAX_DEAD_LETTERS = 1024;
|
|
42494
|
+
var DEFAULT_LIMITS = {
|
|
42495
|
+
criticalEventBytes: DEFAULT_CRITICAL_EVENT_BYTES,
|
|
42496
|
+
standardEventBytes: DEFAULT_STANDARD_EVENT_BYTES
|
|
42497
|
+
};
|
|
42498
|
+
var SessionEventOutboxCapacityError = class extends Error {
|
|
42499
|
+
code = "session_event_outbox_full";
|
|
42500
|
+
constructor() {
|
|
42501
|
+
super("The persistent Session event outbox is full");
|
|
42502
|
+
this.name = "SessionEventOutboxCapacityError";
|
|
42503
|
+
}
|
|
42504
|
+
};
|
|
42505
|
+
function rowNumber(row, field) {
|
|
42506
|
+
const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
|
|
42507
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
42508
|
+
throw new Error(`SQLite returned an invalid ${field} value`);
|
|
42509
|
+
}
|
|
42510
|
+
return value;
|
|
42511
|
+
}
|
|
42512
|
+
function rowString(row, field) {
|
|
42513
|
+
const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
|
|
42514
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
42515
|
+
throw new Error(`SQLite returned an invalid ${field} value`);
|
|
42516
|
+
}
|
|
42517
|
+
return value;
|
|
42518
|
+
}
|
|
42519
|
+
function validateLimits(limits) {
|
|
42520
|
+
if (!Number.isSafeInteger(limits.standardEventBytes) || limits.standardEventBytes < 1 || !Number.isSafeInteger(limits.criticalEventBytes) || limits.criticalEventBytes < limits.standardEventBytes) {
|
|
42521
|
+
throw new Error("Session event outbox limits are invalid");
|
|
42522
|
+
}
|
|
42523
|
+
}
|
|
42524
|
+
var SessionEventOutbox = class {
|
|
42525
|
+
#database;
|
|
42526
|
+
#limits;
|
|
42527
|
+
constructor(path2, limits = DEFAULT_LIMITS) {
|
|
42528
|
+
validateLimits(limits);
|
|
42529
|
+
mkdirSync3(dirname5(path2), { mode: 448, recursive: true });
|
|
42530
|
+
this.#limits = limits;
|
|
42531
|
+
this.#database = new DatabaseSync(path2);
|
|
42532
|
+
this.#database.exec("PRAGMA journal_mode = WAL; PRAGMA synchronous = FULL; PRAGMA busy_timeout = 5000;");
|
|
42533
|
+
this.#database.exec(`
|
|
42534
|
+
CREATE TABLE IF NOT EXISTS relay_session_event_outbox (
|
|
42535
|
+
ordinal INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
42536
|
+
event_id TEXT NOT NULL UNIQUE,
|
|
42537
|
+
session_id TEXT NOT NULL,
|
|
42538
|
+
source_seq INTEGER NOT NULL UNIQUE,
|
|
42539
|
+
byte_length INTEGER NOT NULL,
|
|
42540
|
+
envelope_json TEXT NOT NULL
|
|
42541
|
+
) STRICT;
|
|
42542
|
+
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
|
|
42543
|
+
ON relay_session_event_outbox(source_seq);
|
|
42544
|
+
CREATE TABLE IF NOT EXISTS relay_session_event_outbox_state (
|
|
42545
|
+
singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
|
|
42546
|
+
stream_id TEXT NOT NULL,
|
|
42547
|
+
next_source_seq INTEGER NOT NULL,
|
|
42548
|
+
total_bytes INTEGER NOT NULL
|
|
42549
|
+
) STRICT;
|
|
42550
|
+
CREATE TABLE IF NOT EXISTS relay_session_event_dead_letters (
|
|
42551
|
+
ordinal INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
42552
|
+
event_id TEXT NOT NULL UNIQUE,
|
|
42553
|
+
session_id TEXT NOT NULL,
|
|
42554
|
+
rejection_code TEXT NOT NULL,
|
|
42555
|
+
envelope_json TEXT NOT NULL
|
|
42556
|
+
) STRICT;
|
|
42557
|
+
`);
|
|
42558
|
+
this.#database.prepare(
|
|
42559
|
+
`INSERT OR IGNORE INTO relay_session_event_outbox_state (
|
|
42560
|
+
singleton, stream_id, next_source_seq, total_bytes
|
|
42561
|
+
) VALUES (1, ?, 1, 0)`
|
|
42562
|
+
).run(randomUUID6());
|
|
42563
|
+
}
|
|
42564
|
+
acknowledge = (acknowledgement) => this.#remove(acknowledgement.eventId, acknowledgement.sessionId);
|
|
42565
|
+
close = () => {
|
|
42566
|
+
this.#database.close();
|
|
42567
|
+
};
|
|
42568
|
+
enqueue = (sessionId, payload, critical) => {
|
|
42569
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
42570
|
+
try {
|
|
42571
|
+
const state = this.#database.prepare(
|
|
42572
|
+
`SELECT stream_id, next_source_seq, total_bytes
|
|
42573
|
+
FROM relay_session_event_outbox_state
|
|
42574
|
+
WHERE singleton = 1`
|
|
42575
|
+
).get();
|
|
42576
|
+
const sourceSeq = rowNumber(state, "next_source_seq");
|
|
42577
|
+
if (sourceSeq < 1 || !Number.isSafeInteger(sourceSeq + 1)) {
|
|
42578
|
+
throw new Error("The Session event source sequence is exhausted");
|
|
42579
|
+
}
|
|
42580
|
+
const envelope2 = {
|
|
42581
|
+
delivery: {
|
|
42582
|
+
eventId: randomUUID6(),
|
|
42583
|
+
kind: "reliable",
|
|
42584
|
+
sourceSeq: sourceSeq.toString(),
|
|
42585
|
+
streamId: rowString(state, "stream_id")
|
|
42586
|
+
},
|
|
42587
|
+
kind: SESSION_EVENT_KIND,
|
|
42588
|
+
payload,
|
|
42589
|
+
sessionId
|
|
42590
|
+
};
|
|
42591
|
+
const encoded = encodeSessionEventEnvelope(envelope2);
|
|
42592
|
+
const byteLength = Buffer.byteLength(encoded, "utf8");
|
|
42593
|
+
const maximumBytes = critical ? this.#limits.criticalEventBytes : this.#limits.standardEventBytes;
|
|
42594
|
+
if (rowNumber(state, "total_bytes") + byteLength > maximumBytes) {
|
|
42595
|
+
throw new SessionEventOutboxCapacityError();
|
|
42596
|
+
}
|
|
42597
|
+
this.#database.prepare(
|
|
42598
|
+
`INSERT INTO relay_session_event_outbox (
|
|
42599
|
+
event_id, session_id, source_seq, byte_length, envelope_json
|
|
42600
|
+
) VALUES (?, ?, ?, ?, ?)`
|
|
42601
|
+
).run(envelope2.delivery.eventId, sessionId, sourceSeq, byteLength, encoded);
|
|
42602
|
+
this.#database.prepare(
|
|
42603
|
+
`UPDATE relay_session_event_outbox_state
|
|
42604
|
+
SET next_source_seq = next_source_seq + 1,
|
|
42605
|
+
total_bytes = total_bytes + ?
|
|
42606
|
+
WHERE singleton = 1`
|
|
42607
|
+
).run(byteLength);
|
|
42608
|
+
this.#database.exec("COMMIT");
|
|
42609
|
+
return envelope2;
|
|
42610
|
+
} catch (error62) {
|
|
42611
|
+
this.#database.exec("ROLLBACK");
|
|
42612
|
+
throw error62;
|
|
42613
|
+
}
|
|
42614
|
+
};
|
|
42615
|
+
pending = (limit, excludedEventIds) => {
|
|
42616
|
+
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
42617
|
+
throw new Error("Session event replay limit must be a positive integer");
|
|
42618
|
+
}
|
|
42619
|
+
const exclusion = excludedEventIds.length === 0 ? "" : `WHERE event_id NOT IN (${excludedEventIds.map(() => "?").join(", ")})`;
|
|
42620
|
+
return this.#database.prepare(
|
|
42621
|
+
`SELECT envelope_json
|
|
42622
|
+
FROM relay_session_event_outbox
|
|
42623
|
+
${exclusion}
|
|
42624
|
+
ORDER BY source_seq
|
|
42625
|
+
LIMIT ?`
|
|
42626
|
+
).all(...excludedEventIds, limit).map((row) => {
|
|
42627
|
+
const envelope2 = decodeSessionEventEnvelope(rowString(row, "envelope_json"));
|
|
42628
|
+
if (!("delivery" in envelope2)) {
|
|
42629
|
+
throw new Error("SQLite returned an invalid reliable Session event envelope");
|
|
42630
|
+
}
|
|
42631
|
+
return envelope2;
|
|
42632
|
+
});
|
|
42633
|
+
};
|
|
42634
|
+
quarantine = (rejection) => {
|
|
42635
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
42636
|
+
try {
|
|
42637
|
+
const stored = this.#database.prepare(
|
|
42638
|
+
`SELECT byte_length, envelope_json
|
|
42639
|
+
FROM relay_session_event_outbox
|
|
42640
|
+
WHERE event_id = ? AND session_id = ?`
|
|
42641
|
+
).get(rejection.eventId, rejection.sessionId);
|
|
42642
|
+
if (stored === void 0) {
|
|
42643
|
+
this.#database.exec("COMMIT");
|
|
42644
|
+
return false;
|
|
42645
|
+
}
|
|
42646
|
+
this.#database.prepare(
|
|
42647
|
+
`INSERT INTO relay_session_event_dead_letters (
|
|
42648
|
+
event_id, session_id, rejection_code, envelope_json
|
|
42649
|
+
) VALUES (?, ?, ?, ?)`
|
|
42650
|
+
).run(rejection.eventId, rejection.sessionId, rejection.code, rowString(stored, "envelope_json"));
|
|
42651
|
+
this.#deleteStored(rejection.eventId, rejection.sessionId, rowNumber(stored, "byte_length"));
|
|
42652
|
+
this.#database.prepare(
|
|
42653
|
+
`DELETE FROM relay_session_event_dead_letters
|
|
42654
|
+
WHERE ordinal NOT IN (
|
|
42655
|
+
SELECT ordinal FROM relay_session_event_dead_letters
|
|
42656
|
+
ORDER BY ordinal DESC LIMIT ?
|
|
42657
|
+
)`
|
|
42658
|
+
).run(MAX_DEAD_LETTERS);
|
|
42659
|
+
this.#database.exec("COMMIT");
|
|
42660
|
+
return true;
|
|
42661
|
+
} catch (error62) {
|
|
42662
|
+
this.#database.exec("ROLLBACK");
|
|
42663
|
+
throw error62;
|
|
42664
|
+
}
|
|
42665
|
+
};
|
|
42666
|
+
#deleteStored = (eventId, sessionId, byteLength) => {
|
|
42667
|
+
const deletion = this.#database.prepare(
|
|
42668
|
+
`DELETE FROM relay_session_event_outbox
|
|
42669
|
+
WHERE event_id = ? AND session_id = ?`
|
|
42670
|
+
).run(eventId, sessionId);
|
|
42671
|
+
if (deletion.changes !== 1) {
|
|
42672
|
+
throw new Error("The Session event could not be removed from the outbox");
|
|
42673
|
+
}
|
|
42674
|
+
const state = this.#database.prepare(
|
|
42675
|
+
`UPDATE relay_session_event_outbox_state
|
|
42676
|
+
SET total_bytes = total_bytes - ?
|
|
42677
|
+
WHERE singleton = 1 AND total_bytes >= ?`
|
|
42678
|
+
).run(byteLength, byteLength);
|
|
42679
|
+
if (state.changes !== 1) {
|
|
42680
|
+
throw new Error("The Session event outbox capacity state is inconsistent");
|
|
42681
|
+
}
|
|
42682
|
+
};
|
|
42683
|
+
#remove = (eventId, sessionId) => {
|
|
42684
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
42685
|
+
try {
|
|
42686
|
+
const stored = this.#database.prepare(
|
|
42687
|
+
`SELECT byte_length
|
|
42688
|
+
FROM relay_session_event_outbox
|
|
42689
|
+
WHERE event_id = ? AND session_id = ?`
|
|
42690
|
+
).get(eventId, sessionId);
|
|
42691
|
+
if (stored === void 0) {
|
|
42692
|
+
this.#database.exec("COMMIT");
|
|
42693
|
+
return false;
|
|
42694
|
+
}
|
|
42695
|
+
this.#deleteStored(eventId, sessionId, rowNumber(stored, "byte_length"));
|
|
42696
|
+
this.#database.exec("COMMIT");
|
|
42697
|
+
return true;
|
|
42698
|
+
} catch (error62) {
|
|
42699
|
+
this.#database.exec("ROLLBACK");
|
|
42700
|
+
throw error62;
|
|
42701
|
+
}
|
|
42702
|
+
};
|
|
42703
|
+
};
|
|
42704
|
+
|
|
42279
42705
|
// src/relay-connection/session-event-publisher.ts
|
|
42280
42706
|
import { WebSocket as WebSocket9 } from "undici";
|
|
42281
|
-
var
|
|
42707
|
+
var SESSION_EVENT_REPLAY_WINDOW = 16;
|
|
42708
|
+
var SESSION_EVENT_REPLAY_BYTE_LIMIT = 32 * 1024 * 1024;
|
|
42709
|
+
function reservesSessionEventCapacity(event) {
|
|
42710
|
+
if (event.kind === SESSION_COMPLETED_KIND || event.kind === SESSION_FAILED_KIND) {
|
|
42711
|
+
return true;
|
|
42712
|
+
}
|
|
42713
|
+
return event.kind === AGENT_ACTIVITY_KIND && (event.activityType === "progress" || event.activityType === "reasoning") && (event.status === "completed" || event.status === "failed");
|
|
42714
|
+
}
|
|
42282
42715
|
var DaemonSessionEventPublisher = class {
|
|
42283
|
-
#
|
|
42284
|
-
#
|
|
42285
|
-
|
|
42286
|
-
|
|
42287
|
-
|
|
42716
|
+
#inFlight = /* @__PURE__ */ new Map();
|
|
42717
|
+
#outbox;
|
|
42718
|
+
#reportedCapacityKinds = /* @__PURE__ */ new Set();
|
|
42719
|
+
#timer;
|
|
42720
|
+
#connection = { kind: "disconnected" };
|
|
42721
|
+
#deferredReplay = null;
|
|
42722
|
+
#inFlightBytes = 0;
|
|
42723
|
+
constructor(outbox, timer) {
|
|
42724
|
+
this.#outbox = outbox;
|
|
42725
|
+
this.#timer = timer;
|
|
42726
|
+
}
|
|
42727
|
+
acknowledge = (acknowledgement) => {
|
|
42728
|
+
if (!this.#outbox.acknowledge(acknowledgement)) {
|
|
42729
|
+
return;
|
|
42730
|
+
}
|
|
42731
|
+
this.#removeInFlight(acknowledgement.eventId);
|
|
42732
|
+
this.#publishNextBatch();
|
|
42733
|
+
};
|
|
42734
|
+
close = () => {
|
|
42735
|
+
this.#deferredReplay?.cancel();
|
|
42736
|
+
this.#deferredReplay = null;
|
|
42737
|
+
this.#connection = { kind: "disconnected" };
|
|
42738
|
+
this.#clearInFlight();
|
|
42739
|
+
this.#outbox.close();
|
|
42740
|
+
};
|
|
42741
|
+
connect = (socket, delivery) => {
|
|
42742
|
+
this.#connection = { delivery, kind: "connected", socket };
|
|
42743
|
+
this.#clearInFlight();
|
|
42744
|
+
this.#publishNextBatch();
|
|
42745
|
+
};
|
|
42746
|
+
defer = (deferred) => {
|
|
42747
|
+
if (!this.#inFlight.has(deferred.eventId)) {
|
|
42748
|
+
return;
|
|
42749
|
+
}
|
|
42750
|
+
this.#clearInFlight();
|
|
42751
|
+
if (this.#deferredReplay !== null) {
|
|
42752
|
+
return;
|
|
42753
|
+
}
|
|
42754
|
+
this.#deferredReplay = this.#timer.schedule(() => {
|
|
42755
|
+
this.#deferredReplay = null;
|
|
42756
|
+
this.#publishNextBatch();
|
|
42757
|
+
}, deferred.retryAfterMilliseconds);
|
|
42288
42758
|
};
|
|
42289
42759
|
disconnect = (socket) => {
|
|
42290
|
-
if (this.#socket
|
|
42291
|
-
|
|
42760
|
+
if (this.#connection.kind !== "connected" || this.#connection.socket !== socket) {
|
|
42761
|
+
return;
|
|
42292
42762
|
}
|
|
42763
|
+
this.#connection = { kind: "disconnected" };
|
|
42764
|
+
this.#clearInFlight();
|
|
42293
42765
|
};
|
|
42294
42766
|
publish = (sessionId, event) => {
|
|
42295
|
-
|
|
42296
|
-
|
|
42297
|
-
|
|
42767
|
+
try {
|
|
42768
|
+
this.#outbox.enqueue(sessionId, encodeRecordedSessionEvent(event), reservesSessionEventCapacity(event));
|
|
42769
|
+
} catch (error62) {
|
|
42770
|
+
if (!(error62 instanceof SessionEventOutboxCapacityError)) {
|
|
42771
|
+
throw error62;
|
|
42772
|
+
}
|
|
42773
|
+
if (!this.#reportedCapacityKinds.has(event.kind)) {
|
|
42774
|
+
this.#reportedCapacityKinds.add(event.kind);
|
|
42775
|
+
console.warn(
|
|
42776
|
+
`Mobius daemon could not persist "${event.kind}" because the Session event outbox is full`
|
|
42777
|
+
);
|
|
42778
|
+
}
|
|
42298
42779
|
return;
|
|
42299
42780
|
}
|
|
42300
|
-
|
|
42301
|
-
|
|
42302
|
-
|
|
42303
|
-
|
|
42781
|
+
this.#publishNextBatch();
|
|
42782
|
+
};
|
|
42783
|
+
quarantine = (rejection) => {
|
|
42784
|
+
if (!this.#outbox.quarantine(rejection)) {
|
|
42304
42785
|
return;
|
|
42305
42786
|
}
|
|
42306
|
-
|
|
42307
|
-
|
|
42308
|
-
|
|
42309
|
-
kind: SESSION_EVENT_KIND,
|
|
42310
|
-
payload: encodeRecordedSessionEvent(event),
|
|
42311
|
-
sessionId
|
|
42312
|
-
})
|
|
42313
|
-
);
|
|
42314
|
-
} catch {
|
|
42315
|
-
this.#reportDrop();
|
|
42316
|
-
}
|
|
42787
|
+
this.#removeInFlight(rejection.eventId);
|
|
42788
|
+
console.error(`Mobius Relay rejected Session event ${rejection.eventId} with code ${rejection.code}`);
|
|
42789
|
+
this.#publishNextBatch();
|
|
42317
42790
|
};
|
|
42318
|
-
|
|
42319
|
-
this.#
|
|
42791
|
+
#clearInFlight = () => {
|
|
42792
|
+
this.#inFlight.clear();
|
|
42793
|
+
this.#inFlightBytes = 0;
|
|
42320
42794
|
};
|
|
42321
|
-
#
|
|
42322
|
-
if (this.#
|
|
42795
|
+
#publishNextBatch = () => {
|
|
42796
|
+
if (this.#deferredReplay !== null || this.#connection.kind !== "connected") {
|
|
42323
42797
|
return;
|
|
42324
42798
|
}
|
|
42325
|
-
this.#
|
|
42326
|
-
|
|
42799
|
+
while (this.#inFlight.size < SESSION_EVENT_REPLAY_WINDOW) {
|
|
42800
|
+
const batch = this.#outbox.pending(SESSION_EVENT_REPLAY_WINDOW - this.#inFlight.size, [
|
|
42801
|
+
...this.#inFlight.keys()
|
|
42802
|
+
]);
|
|
42803
|
+
let sent = 0;
|
|
42804
|
+
for (const envelope2 of batch) {
|
|
42805
|
+
const encoded = encodeDaemonToServiceMessage(
|
|
42806
|
+
this.#connection.delivery === "reliable" ? envelope2 : {
|
|
42807
|
+
kind: envelope2.kind,
|
|
42808
|
+
payload: envelope2.payload,
|
|
42809
|
+
sessionId: envelope2.sessionId
|
|
42810
|
+
}
|
|
42811
|
+
);
|
|
42812
|
+
const byteLength = Buffer.byteLength(encoded, "utf8");
|
|
42813
|
+
if (this.#inFlightBytes + byteLength > SESSION_EVENT_REPLAY_BYTE_LIMIT) {
|
|
42814
|
+
return;
|
|
42815
|
+
}
|
|
42816
|
+
if (!this.#send(encoded)) {
|
|
42817
|
+
this.#clearInFlight();
|
|
42818
|
+
return;
|
|
42819
|
+
}
|
|
42820
|
+
if (this.#connection.delivery === "ephemeral") {
|
|
42821
|
+
this.#outbox.acknowledge({
|
|
42822
|
+
eventId: envelope2.delivery.eventId,
|
|
42823
|
+
kind: "session.event.ack",
|
|
42824
|
+
outcome: { kind: "relayed" },
|
|
42825
|
+
sessionId: envelope2.sessionId
|
|
42826
|
+
});
|
|
42827
|
+
sent += 1;
|
|
42828
|
+
continue;
|
|
42829
|
+
}
|
|
42830
|
+
this.#inFlight.set(envelope2.delivery.eventId, { byteLength });
|
|
42831
|
+
this.#inFlightBytes += byteLength;
|
|
42832
|
+
sent += 1;
|
|
42833
|
+
}
|
|
42834
|
+
if (sent === 0) {
|
|
42835
|
+
return;
|
|
42836
|
+
}
|
|
42837
|
+
}
|
|
42838
|
+
};
|
|
42839
|
+
#removeInFlight = (eventId) => {
|
|
42840
|
+
const inFlight = this.#inFlight.get(eventId);
|
|
42841
|
+
if (inFlight === void 0) {
|
|
42842
|
+
return;
|
|
42843
|
+
}
|
|
42844
|
+
this.#inFlight.delete(eventId);
|
|
42845
|
+
this.#inFlightBytes -= inFlight.byteLength;
|
|
42846
|
+
};
|
|
42847
|
+
#send = (encoded) => {
|
|
42848
|
+
if (this.#connection.kind !== "connected" || this.#connection.socket.readyState !== WebSocket9.OPEN) {
|
|
42849
|
+
return false;
|
|
42850
|
+
}
|
|
42851
|
+
try {
|
|
42852
|
+
this.#connection.socket.send(encoded);
|
|
42853
|
+
return true;
|
|
42854
|
+
} catch {
|
|
42855
|
+
return false;
|
|
42856
|
+
}
|
|
42327
42857
|
};
|
|
42328
42858
|
};
|
|
42329
42859
|
|
|
@@ -42384,7 +42914,7 @@ async function installDetectedAgentIntegrations(config2, installations, signal)
|
|
|
42384
42914
|
{
|
|
42385
42915
|
agentId: agent.id,
|
|
42386
42916
|
kind: AGENT_INSTALL_REQUEST_KIND,
|
|
42387
|
-
requestId: `automatic-integration-${
|
|
42917
|
+
requestId: `automatic-integration-${randomUUID7()}`
|
|
42388
42918
|
},
|
|
42389
42919
|
signal
|
|
42390
42920
|
);
|
|
@@ -42406,7 +42936,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer, opti
|
|
|
42406
42936
|
join17(stateDirectory, "sessions", `${createHash5("sha256").update(config2.channelId).digest("hex")}.sqlite`)
|
|
42407
42937
|
);
|
|
42408
42938
|
const operations = new DaemonOperationState();
|
|
42409
|
-
const
|
|
42939
|
+
const channelHash = createHash5("sha256").update(config2.channelId).digest("hex");
|
|
42940
|
+
const publisher = new DaemonSessionEventPublisher(
|
|
42941
|
+
new SessionEventOutbox(join17(stateDirectory, "events", `${channelHash}.sqlite`)),
|
|
42942
|
+
timer
|
|
42943
|
+
);
|
|
42410
42944
|
const activeTurns = new DaemonTurnRegistry(operations);
|
|
42411
42945
|
const recordSessionEvent = (sessionId, event) => {
|
|
42412
42946
|
publisher.publish(sessionId, activeTurns.recordEvent(event));
|
|
@@ -42598,9 +43132,9 @@ import { basename as basename6, resolve as resolve7 } from "node:path";
|
|
|
42598
43132
|
import { fetch as fetch4 } from "undici";
|
|
42599
43133
|
|
|
42600
43134
|
// src/storage/runtime-installation-store.ts
|
|
42601
|
-
import { createHash as createHash6, randomUUID as
|
|
43135
|
+
import { createHash as createHash6, randomUUID as randomUUID8 } from "node:crypto";
|
|
42602
43136
|
import { mkdir as mkdir4, open as open5, readdir as readdir3, rename as rename3, unlink, writeFile as writeFile3 } from "node:fs/promises";
|
|
42603
|
-
import { dirname as
|
|
43137
|
+
import { dirname as dirname6, join as join18, resolve as resolve6 } from "node:path";
|
|
42604
43138
|
var APPLICATION_ID_PATTERN = /^[a-z][a-z0-9]*(?:[.-][a-z0-9]+){1,31}$/;
|
|
42605
43139
|
var CONNECTION_ID_PATTERN = /^mcn_[a-f0-9]{32}$/;
|
|
42606
43140
|
var INSTALLATION_ID_PATTERN = /^min_[a-f0-9]{32}$/;
|
|
@@ -42728,10 +43262,10 @@ function parseRelayOrigin(value) {
|
|
|
42728
43262
|
return origin;
|
|
42729
43263
|
}
|
|
42730
43264
|
function connectionId() {
|
|
42731
|
-
return `mcn_${
|
|
43265
|
+
return `mcn_${randomUUID8().replaceAll("-", "")}`;
|
|
42732
43266
|
}
|
|
42733
43267
|
function installationId() {
|
|
42734
|
-
return `min_${
|
|
43268
|
+
return `min_${randomUUID8().replaceAll("-", "")}`;
|
|
42735
43269
|
}
|
|
42736
43270
|
function channelIndexFileName(channelId) {
|
|
42737
43271
|
return `mci_${createHash6("sha256").update(channelId).digest("hex")}.json`;
|
|
@@ -42842,8 +43376,8 @@ async function readJsonFile(path2, signal, missingCode) {
|
|
|
42842
43376
|
}
|
|
42843
43377
|
async function writeJsonAtomically(path2, value, signal) {
|
|
42844
43378
|
signal.throwIfAborted();
|
|
42845
|
-
const directory =
|
|
42846
|
-
const temporaryPath = join18(directory, `.${
|
|
43379
|
+
const directory = dirname6(path2);
|
|
43380
|
+
const temporaryPath = join18(directory, `.${randomUUID8()}.tmp`);
|
|
42847
43381
|
try {
|
|
42848
43382
|
await mkdir4(directory, { mode: 448, recursive: true });
|
|
42849
43383
|
signal.throwIfAborted();
|