@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/index.js
CHANGED
|
@@ -20766,9 +20766,17 @@ function decodeSessionQueuedEvent(encoded) {
|
|
|
20766
20766
|
}
|
|
20767
20767
|
function decodeRuntimeLivenessReadyEvent(encoded) {
|
|
20768
20768
|
const value = parseJson2(encoded);
|
|
20769
|
-
assertExactKeys(value, ["kind"]);
|
|
20770
20769
|
assertKind(value, RUNTIME_LIVENESS_READY_KIND);
|
|
20771
|
-
|
|
20770
|
+
if (value["sessionEventDelivery"] === void 0) {
|
|
20771
|
+
assertExactKeys(value, ["kind"]);
|
|
20772
|
+
return { kind: RUNTIME_LIVENESS_READY_KIND };
|
|
20773
|
+
}
|
|
20774
|
+
assertExactKeys(value, ["kind", "sessionEventDelivery"]);
|
|
20775
|
+
const sessionEventDelivery = readString(value, "sessionEventDelivery", 32);
|
|
20776
|
+
if (sessionEventDelivery !== "reliable-v1") {
|
|
20777
|
+
throw new ProtocolMessageError("Unsupported Session event delivery mode");
|
|
20778
|
+
}
|
|
20779
|
+
return { kind: RUNTIME_LIVENESS_READY_KIND, sessionEventDelivery };
|
|
20772
20780
|
}
|
|
20773
20781
|
function decodeRuntimeHeartbeatEvent(encoded) {
|
|
20774
20782
|
const value = parseJson2(encoded);
|
|
@@ -21060,18 +21068,21 @@ var activeTurnMessageSchema = external_exports.discriminatedUnion("role", [
|
|
|
21060
21068
|
activeTurnAssistantMessageSchema
|
|
21061
21069
|
]);
|
|
21062
21070
|
var activeTurnSnapshotSchema = external_exports.strictObject({
|
|
21063
|
-
activities: external_exports.array(activeTurnActivitySchema).readonly(),
|
|
21064
21071
|
commandId: identifierStringSchema,
|
|
21065
|
-
content: external_exports.array(displayContentSchema).readonly(),
|
|
21066
|
-
prompt: external_exports.string().max(1e5),
|
|
21067
|
-
text: external_exports.string(),
|
|
21068
|
-
truncated: external_exports.boolean(),
|
|
21069
21072
|
epoch: identifierStringSchema,
|
|
21073
|
+
hasOlder: external_exports.boolean(),
|
|
21070
21074
|
interaction: external_exports.discriminatedUnion("kind", [sessionPermissionRequestedEventSchema, sessionElicitationRequestedEventSchema]).nullable(),
|
|
21071
21075
|
messages: external_exports.array(activeTurnMessageSchema).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
|
|
21072
21076
|
sequence: external_exports.number().int().nonnegative(),
|
|
21073
|
-
state: external_exports.literal("running")
|
|
21074
|
-
|
|
21077
|
+
state: external_exports.literal("running"),
|
|
21078
|
+
truncated: external_exports.boolean()
|
|
21079
|
+
}).readonly().refine(
|
|
21080
|
+
(snapshot) => snapshot.messages.reduce(
|
|
21081
|
+
(total, message) => total + message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0),
|
|
21082
|
+
0
|
|
21083
|
+
) <= SESSION_HISTORY_CHARACTER_LIMIT,
|
|
21084
|
+
"Active Turn snapshot content is too large"
|
|
21085
|
+
);
|
|
21075
21086
|
var identity = {
|
|
21076
21087
|
...envelope,
|
|
21077
21088
|
kind: external_exports.literal(NATIVE_SESSION_REQUEST_KIND),
|
|
@@ -21215,27 +21226,61 @@ var encodeNativeSessionCancel = (value) => JSON.stringify(nativeSessionCancelSch
|
|
|
21215
21226
|
|
|
21216
21227
|
// ../protocol/src/session-events.ts
|
|
21217
21228
|
var SESSION_EVENT_KIND = "session.event";
|
|
21218
|
-
var
|
|
21229
|
+
var SESSION_EVENT_ACK_KIND = "session.event.ack";
|
|
21230
|
+
var SESSION_EVENT_DEFERRED_KIND = "session.event.deferred";
|
|
21231
|
+
var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
|
|
21232
|
+
var SessionEventRejectionCode = {
|
|
21233
|
+
IdempotencyConflict: "idempotency_conflict",
|
|
21234
|
+
InvalidEvent: "invalid_event",
|
|
21235
|
+
RecordingRejected: "recording_rejected"
|
|
21236
|
+
};
|
|
21219
21237
|
var MAX_RECORDED_EVENT_LENGTH = 8 * 1024 * 1024;
|
|
21220
|
-
var
|
|
21238
|
+
var ephemeralEventEnvelopeSchema = external_exports.strictObject({
|
|
21221
21239
|
kind: external_exports.literal(SESSION_EVENT_KIND),
|
|
21222
21240
|
payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
|
|
21223
21241
|
sessionId: identifierStringSchema
|
|
21224
21242
|
}).readonly();
|
|
21225
|
-
var
|
|
21226
|
-
|
|
21243
|
+
var reliableDeliverySchema = external_exports.strictObject({
|
|
21244
|
+
eventId: identifierStringSchema,
|
|
21245
|
+
kind: external_exports.literal("reliable"),
|
|
21246
|
+
sourceSeq: external_exports.string().regex(/^(?:0|[1-9][0-9]*)$/u).max(40),
|
|
21247
|
+
streamId: identifierStringSchema
|
|
21248
|
+
}).readonly();
|
|
21249
|
+
var reliableEventEnvelopeSchema = external_exports.strictObject({
|
|
21250
|
+
delivery: reliableDeliverySchema,
|
|
21251
|
+
kind: external_exports.literal(SESSION_EVENT_KIND),
|
|
21227
21252
|
payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
|
|
21228
21253
|
sessionId: identifierStringSchema
|
|
21229
21254
|
}).readonly();
|
|
21255
|
+
var eventEnvelopeSchema = external_exports.union([ephemeralEventEnvelopeSchema, reliableEventEnvelopeSchema]).readonly();
|
|
21256
|
+
var acknowledgementOutcomeSchema = external_exports.discriminatedUnion("kind", [
|
|
21257
|
+
external_exports.strictObject({ kind: external_exports.literal("relayed") }).readonly(),
|
|
21258
|
+
external_exports.strictObject({
|
|
21259
|
+
kind: external_exports.literal("recorded"),
|
|
21260
|
+
providerId: identifierStringSchema,
|
|
21261
|
+
recordingEpoch: identifierStringSchema
|
|
21262
|
+
}).readonly()
|
|
21263
|
+
]);
|
|
21264
|
+
var eventAcknowledgementSchema = external_exports.strictObject({
|
|
21265
|
+
eventId: identifierStringSchema,
|
|
21266
|
+
kind: external_exports.literal(SESSION_EVENT_ACK_KIND),
|
|
21267
|
+
outcome: acknowledgementOutcomeSchema,
|
|
21268
|
+
sessionId: identifierStringSchema
|
|
21269
|
+
}).readonly();
|
|
21270
|
+
var eventDeferredSchema = external_exports.strictObject({
|
|
21271
|
+
eventId: identifierStringSchema,
|
|
21272
|
+
kind: external_exports.literal(SESSION_EVENT_DEFERRED_KIND),
|
|
21273
|
+
retryAfterMilliseconds: external_exports.number().int().min(100).max(6e4),
|
|
21274
|
+
sessionId: identifierStringSchema
|
|
21275
|
+
}).readonly();
|
|
21276
|
+
var eventRejectedSchema = external_exports.strictObject({
|
|
21277
|
+
code: external_exports.enum(SessionEventRejectionCode),
|
|
21278
|
+
eventId: identifierStringSchema,
|
|
21279
|
+
kind: external_exports.literal(SESSION_EVENT_REJECTED_KIND),
|
|
21280
|
+
sessionId: identifierStringSchema
|
|
21281
|
+
}).readonly();
|
|
21230
21282
|
var SESSION_QUEUE_CHANGED_KIND = "session.queue.changed";
|
|
21231
21283
|
var sessionQueueChangedSchema = external_exports.strictObject({ kind: external_exports.literal(SESSION_QUEUE_CHANGED_KIND), sessionId: identifierStringSchema }).readonly();
|
|
21232
|
-
var SESSION_TURN_UPDATED_KIND = "session.turn.updated";
|
|
21233
|
-
var sessionTurnUpdatedSchema = external_exports.strictObject({
|
|
21234
|
-
kind: external_exports.literal(SESSION_TURN_UPDATED_KIND),
|
|
21235
|
-
sessionId: identifierStringSchema,
|
|
21236
|
-
turn: activeTurnSnapshotSchema
|
|
21237
|
-
}).readonly();
|
|
21238
|
-
var decodeSessionTurnUpdatedEvent = (encoded) => decode5(encoded, sessionTurnUpdatedSchema);
|
|
21239
21284
|
function decode5(encoded, schema) {
|
|
21240
21285
|
let value;
|
|
21241
21286
|
try {
|
|
@@ -21262,11 +21307,15 @@ var encode4 = (message, schema) => {
|
|
|
21262
21307
|
};
|
|
21263
21308
|
var decodeSessionEventEnvelope = (encoded) => decode5(encoded, eventEnvelopeSchema);
|
|
21264
21309
|
var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSchema);
|
|
21310
|
+
var decodeSessionEventAcknowledgement = (encoded) => decode5(encoded, eventAcknowledgementSchema);
|
|
21311
|
+
var encodeSessionEventAcknowledgement = (message) => encode4(message, eventAcknowledgementSchema);
|
|
21312
|
+
var decodeSessionEventDeferred = (encoded) => decode5(encoded, eventDeferredSchema);
|
|
21313
|
+
var encodeSessionEventDeferred = (message) => encode4(message, eventDeferredSchema);
|
|
21314
|
+
var decodeSessionEventRejected = (encoded) => decode5(encoded, eventRejectedSchema);
|
|
21315
|
+
var encodeSessionEventRejected = (message) => encode4(message, eventRejectedSchema);
|
|
21265
21316
|
function decodeRecordedSessionEvent(encoded) {
|
|
21266
21317
|
const kind = decodeMessageKind(encoded);
|
|
21267
21318
|
switch (kind) {
|
|
21268
|
-
case SESSION_TURN_UPDATED_KIND:
|
|
21269
|
-
return decodeSessionTurnUpdatedEvent(encoded);
|
|
21270
21319
|
case SESSION_QUEUE_CHANGED_KIND:
|
|
21271
21320
|
return decode5(encoded, sessionQueueChangedSchema);
|
|
21272
21321
|
case AGENT_ACTIVITY_KIND:
|
|
@@ -21435,6 +21484,21 @@ var serviceToDaemonSignatures = {
|
|
|
21435
21484
|
encodeSessionElicitationRespondCommand,
|
|
21436
21485
|
decodeSessionElicitationRespondCommand
|
|
21437
21486
|
),
|
|
21487
|
+
[SESSION_EVENT_ACK_KIND]: defineMessageSignature(
|
|
21488
|
+
SESSION_EVENT_ACK_KIND,
|
|
21489
|
+
encodeSessionEventAcknowledgement,
|
|
21490
|
+
decodeSessionEventAcknowledgement
|
|
21491
|
+
),
|
|
21492
|
+
[SESSION_EVENT_DEFERRED_KIND]: defineMessageSignature(
|
|
21493
|
+
SESSION_EVENT_DEFERRED_KIND,
|
|
21494
|
+
encodeSessionEventDeferred,
|
|
21495
|
+
decodeSessionEventDeferred
|
|
21496
|
+
),
|
|
21497
|
+
[SESSION_EVENT_REJECTED_KIND]: defineMessageSignature(
|
|
21498
|
+
SESSION_EVENT_REJECTED_KIND,
|
|
21499
|
+
encodeSessionEventRejected,
|
|
21500
|
+
decodeSessionEventRejected
|
|
21501
|
+
),
|
|
21438
21502
|
[SESSION_LIVE_HISTORY_LOAD_KIND]: defineMessageSignature(
|
|
21439
21503
|
SESSION_LIVE_HISTORY_LOAD_KIND,
|
|
21440
21504
|
encodeSessionLiveHistoryLoad,
|
|
@@ -37527,7 +37591,7 @@ function isRuntimeRelayRevocation(closeCode, closeReason) {
|
|
|
37527
37591
|
}
|
|
37528
37592
|
|
|
37529
37593
|
// src/run-daemon.ts
|
|
37530
|
-
import { createHash as createHash6, randomUUID as
|
|
37594
|
+
import { createHash as createHash6, randomUUID as randomUUID8 } from "node:crypto";
|
|
37531
37595
|
import { join as join18 } from "node:path";
|
|
37532
37596
|
import { styleText } from "node:util";
|
|
37533
37597
|
|
|
@@ -38731,6 +38795,28 @@ var DaemonInstallationObserver = class {
|
|
|
38731
38795
|
|
|
38732
38796
|
// src/daemon-active-turn.ts
|
|
38733
38797
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
38798
|
+
function activeMessageCharacters(message) {
|
|
38799
|
+
return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
|
|
38800
|
+
}
|
|
38801
|
+
var ACTIVE_TURN_TEXT_CHUNK_LIMIT = Math.floor(SESSION_HISTORY_CHARACTER_LIMIT / 2);
|
|
38802
|
+
function boundedRecoveryMessages(messages) {
|
|
38803
|
+
const selected = [];
|
|
38804
|
+
let remainingCharacters = SESSION_HISTORY_CHARACTER_LIMIT;
|
|
38805
|
+
for (let index = messages.length - 1; index >= 0 && selected.length < SESSION_HISTORY_MESSAGE_LIMIT; index -= 1) {
|
|
38806
|
+
const message = messages[index];
|
|
38807
|
+
if (message === void 0) {
|
|
38808
|
+
break;
|
|
38809
|
+
}
|
|
38810
|
+
const characters = activeMessageCharacters(message);
|
|
38811
|
+
if (characters <= remainingCharacters) {
|
|
38812
|
+
selected.unshift(message);
|
|
38813
|
+
remainingCharacters -= characters;
|
|
38814
|
+
continue;
|
|
38815
|
+
}
|
|
38816
|
+
break;
|
|
38817
|
+
}
|
|
38818
|
+
return { hasOlder: selected.length !== messages.length, messages: selected };
|
|
38819
|
+
}
|
|
38734
38820
|
var ActiveDaemonTurn = class {
|
|
38735
38821
|
attemptId;
|
|
38736
38822
|
command;
|
|
@@ -38738,9 +38824,7 @@ var ActiveDaemonTurn = class {
|
|
|
38738
38824
|
#finished = Promise.withResolvers();
|
|
38739
38825
|
#cancellationRequested = false;
|
|
38740
38826
|
#dispatch;
|
|
38741
|
-
#text = "";
|
|
38742
38827
|
#activities = /* @__PURE__ */ new Map();
|
|
38743
|
-
#content = /* @__PURE__ */ new Map();
|
|
38744
38828
|
#timeline;
|
|
38745
38829
|
#sequence = 0;
|
|
38746
38830
|
#interaction = null;
|
|
@@ -38787,9 +38871,17 @@ var ActiveDaemonTurn = class {
|
|
|
38787
38871
|
effectiveDisposition = () => this.#dispatch.kind === "promoted" ? SessionPromptDisposition.Steer : this.command.disposition;
|
|
38788
38872
|
recordEvent = (event) => {
|
|
38789
38873
|
if (event.kind === AGENT_MESSAGE_DELTA_KIND) {
|
|
38790
|
-
|
|
38874
|
+
const sequence = this.advance();
|
|
38791
38875
|
this.appendMessageText(event.messageId, event.text);
|
|
38792
|
-
return
|
|
38876
|
+
return {
|
|
38877
|
+
commandId: this.command.commandId,
|
|
38878
|
+
epoch: this.#epoch,
|
|
38879
|
+
kind: AGENT_MESSAGE_DELTA_KIND,
|
|
38880
|
+
messageId: event.messageId,
|
|
38881
|
+
sequence,
|
|
38882
|
+
sessionId: this.command.sessionId,
|
|
38883
|
+
text: event.text
|
|
38884
|
+
};
|
|
38793
38885
|
}
|
|
38794
38886
|
if (event.sessionId !== this.command.sessionId || "commandId" in event && event.commandId !== this.command.commandId) {
|
|
38795
38887
|
return event;
|
|
@@ -38836,7 +38928,6 @@ var ActiveDaemonTurn = class {
|
|
|
38836
38928
|
toolKind: previous?.toolKind ?? ""
|
|
38837
38929
|
});
|
|
38838
38930
|
} else if (event.kind === AGENT_CONTENT_KIND) {
|
|
38839
|
-
this.#content.set(event.contentId, event.content);
|
|
38840
38931
|
const target = this.#timeline.findLastIndex(
|
|
38841
38932
|
(entry) => entry.kind === "message" && entry.sourceMessageId === event.messageId
|
|
38842
38933
|
);
|
|
@@ -38862,7 +38953,7 @@ var ActiveDaemonTurn = class {
|
|
|
38862
38953
|
this.#interaction = null;
|
|
38863
38954
|
}
|
|
38864
38955
|
if (event.kind === AGENT_ACTIVITY_KIND || event.kind === AGENT_ACTIVITY_NARRATION_KIND || event.kind === AGENT_CONTENT_KIND) {
|
|
38865
|
-
|
|
38956
|
+
this.advance();
|
|
38866
38957
|
}
|
|
38867
38958
|
return event;
|
|
38868
38959
|
};
|
|
@@ -38871,7 +38962,7 @@ var ActiveDaemonTurn = class {
|
|
|
38871
38962
|
while (remaining.length > 0) {
|
|
38872
38963
|
const latest = this.#timeline.at(-1);
|
|
38873
38964
|
if (latest?.kind === "message" && latest.sourceMessageId === messageId) {
|
|
38874
|
-
const available =
|
|
38965
|
+
const available = ACTIVE_TURN_TEXT_CHUNK_LIMIT - latest.text.length;
|
|
38875
38966
|
if (available > 0) {
|
|
38876
38967
|
this.#timeline = [
|
|
38877
38968
|
...this.#timeline.slice(0, -1),
|
|
@@ -38888,21 +38979,22 @@ var ActiveDaemonTurn = class {
|
|
|
38888
38979
|
id: decodeIdentifier(randomUUID2()),
|
|
38889
38980
|
kind: "message",
|
|
38890
38981
|
sourceMessageId: messageId,
|
|
38891
|
-
text: remaining.slice(0,
|
|
38982
|
+
text: remaining.slice(0, ACTIVE_TURN_TEXT_CHUNK_LIMIT)
|
|
38892
38983
|
}
|
|
38893
38984
|
];
|
|
38894
|
-
remaining = remaining.slice(
|
|
38985
|
+
remaining = remaining.slice(ACTIVE_TURN_TEXT_CHUNK_LIMIT);
|
|
38895
38986
|
}
|
|
38896
38987
|
}
|
|
38897
38988
|
recordSteeringPrompt = (command) => {
|
|
38898
38989
|
if (this.#dispatch.kind !== "running" || command.sessionId !== this.command.sessionId || command.targetCommandId !== this.command.commandId) {
|
|
38899
|
-
return
|
|
38990
|
+
return false;
|
|
38900
38991
|
}
|
|
38901
38992
|
this.#timeline = [
|
|
38902
38993
|
...this.#timeline,
|
|
38903
38994
|
{ id: decodeIdentifier(command.commandId), images: command.images, kind: "user", text: command.prompt }
|
|
38904
38995
|
];
|
|
38905
|
-
|
|
38996
|
+
this.advance();
|
|
38997
|
+
return true;
|
|
38906
38998
|
};
|
|
38907
38999
|
timelineMessages() {
|
|
38908
39000
|
return this.#timeline.flatMap((entry) => {
|
|
@@ -38924,32 +39016,39 @@ var ActiveDaemonTurn = class {
|
|
|
38924
39016
|
return activity2 === void 0 ? [] : [{ activities: [activity2], content: [], id: entry.id, role: "assistant", text: "" }];
|
|
38925
39017
|
});
|
|
38926
39018
|
}
|
|
38927
|
-
|
|
38928
|
-
this.#
|
|
38929
|
-
|
|
38930
|
-
if (turn === null) {
|
|
38931
|
-
throw new Error("Only a running turn can publish a snapshot");
|
|
39019
|
+
advance = () => {
|
|
39020
|
+
if (this.#dispatch.kind !== "running") {
|
|
39021
|
+
throw new Error("Only a running turn can advance its snapshot");
|
|
38932
39022
|
}
|
|
38933
|
-
|
|
39023
|
+
this.#sequence += 1;
|
|
39024
|
+
return this.#sequence;
|
|
38934
39025
|
};
|
|
38935
39026
|
snapshot = () => {
|
|
38936
39027
|
if (this.#dispatch.kind !== "running") {
|
|
38937
39028
|
return null;
|
|
38938
39029
|
}
|
|
38939
|
-
const
|
|
38940
|
-
const messages = completeMessages.slice(-SESSION_HISTORY_MESSAGE_LIMIT);
|
|
39030
|
+
const bounded2 = boundedRecoveryMessages(this.timelineMessages());
|
|
38941
39031
|
return {
|
|
38942
|
-
activities: [...this.#activities.values()].sort((left, right) => left.sequence - right.sequence),
|
|
38943
39032
|
commandId: decodeIdentifier(this.command.commandId),
|
|
38944
|
-
content: [...this.#content.values()],
|
|
38945
|
-
prompt: this.command.prompt,
|
|
38946
|
-
text: this.#text,
|
|
38947
|
-
truncated: messages.length !== completeMessages.length,
|
|
38948
39033
|
epoch: this.#epoch,
|
|
39034
|
+
hasOlder: bounded2.hasOlder,
|
|
38949
39035
|
interaction: this.#interaction,
|
|
38950
|
-
messages,
|
|
39036
|
+
messages: bounded2.messages,
|
|
38951
39037
|
sequence: this.#sequence,
|
|
38952
|
-
state: "running"
|
|
39038
|
+
state: "running",
|
|
39039
|
+
truncated: false
|
|
39040
|
+
};
|
|
39041
|
+
};
|
|
39042
|
+
recovery = () => {
|
|
39043
|
+
if (this.#dispatch.kind !== "running") {
|
|
39044
|
+
return null;
|
|
39045
|
+
}
|
|
39046
|
+
return {
|
|
39047
|
+
commandId: decodeIdentifier(this.command.commandId),
|
|
39048
|
+
epoch: this.#epoch,
|
|
39049
|
+
messages: this.timelineMessages(),
|
|
39050
|
+
state: "running",
|
|
39051
|
+
truncated: false
|
|
38953
39052
|
};
|
|
38954
39053
|
};
|
|
38955
39054
|
matches = (cancellation) => cancellation.commandId === this.command.commandId && cancellation.sessionId === this.command.sessionId;
|
|
@@ -38975,6 +39074,7 @@ var ActiveDaemonTurn = class {
|
|
|
38975
39074
|
};
|
|
38976
39075
|
|
|
38977
39076
|
// src/daemon-turn-registry.ts
|
|
39077
|
+
var COMPLETED_TURN_RECOVERY_LIMIT = 32;
|
|
38978
39078
|
var waitForTurnCompletion = (turn, waitSignal) => {
|
|
38979
39079
|
waitSignal.throwIfAborted();
|
|
38980
39080
|
return new Promise((resolve9, reject) => {
|
|
@@ -39001,6 +39101,7 @@ var waitForTurnCompletion = (turn, waitSignal) => {
|
|
|
39001
39101
|
};
|
|
39002
39102
|
var DaemonTurnRegistry = class {
|
|
39003
39103
|
#turns = /* @__PURE__ */ new Map();
|
|
39104
|
+
#completed = /* @__PURE__ */ new Map();
|
|
39004
39105
|
#operations;
|
|
39005
39106
|
constructor(operations) {
|
|
39006
39107
|
this.#operations = operations;
|
|
@@ -39012,7 +39113,22 @@ var DaemonTurnRegistry = class {
|
|
|
39012
39113
|
};
|
|
39013
39114
|
get = (commandId) => this.#turns.get(commandId);
|
|
39014
39115
|
finish = (turn) => {
|
|
39116
|
+
const recovery = turn.recovery();
|
|
39015
39117
|
this.#turns.delete(turn.command.commandId);
|
|
39118
|
+
if (recovery !== null) {
|
|
39119
|
+
this.#completed.delete(turn.command.sessionId);
|
|
39120
|
+
this.#completed.set(turn.command.sessionId, {
|
|
39121
|
+
command: turn.command,
|
|
39122
|
+
recovery: { ...recovery, state: "completed" }
|
|
39123
|
+
});
|
|
39124
|
+
while (this.#completed.size > COMPLETED_TURN_RECOVERY_LIMIT) {
|
|
39125
|
+
const oldestSessionId = this.#completed.keys().next().value;
|
|
39126
|
+
if (oldestSessionId === void 0) {
|
|
39127
|
+
break;
|
|
39128
|
+
}
|
|
39129
|
+
this.#completed.delete(oldestSessionId);
|
|
39130
|
+
}
|
|
39131
|
+
}
|
|
39016
39132
|
turn.finish();
|
|
39017
39133
|
};
|
|
39018
39134
|
recordEvent = (event) => {
|
|
@@ -39033,7 +39149,7 @@ var DaemonTurnRegistry = class {
|
|
|
39033
39149
|
};
|
|
39034
39150
|
recordSteeringPrompt = (command) => {
|
|
39035
39151
|
const target = this.#turns.get(command.targetCommandId);
|
|
39036
|
-
return target?.recordSteeringPrompt(command) ??
|
|
39152
|
+
return target?.recordSteeringPrompt(command) ?? false;
|
|
39037
39153
|
};
|
|
39038
39154
|
executionSnapshot = async (matches) => {
|
|
39039
39155
|
const matching = [];
|
|
@@ -39064,12 +39180,30 @@ var DaemonTurnRegistry = class {
|
|
|
39064
39180
|
}
|
|
39065
39181
|
return null;
|
|
39066
39182
|
};
|
|
39183
|
+
recovery = (matches) => {
|
|
39184
|
+
for (const turn of this.#turns.values()) {
|
|
39185
|
+
if (!matches(turn.command)) {
|
|
39186
|
+
continue;
|
|
39187
|
+
}
|
|
39188
|
+
const recovery = turn.recovery();
|
|
39189
|
+
if (recovery !== null) {
|
|
39190
|
+
return recovery;
|
|
39191
|
+
}
|
|
39192
|
+
}
|
|
39193
|
+
for (const completed of this.#completed.values()) {
|
|
39194
|
+
if (matches(completed.command)) {
|
|
39195
|
+
return completed.recovery;
|
|
39196
|
+
}
|
|
39197
|
+
}
|
|
39198
|
+
return null;
|
|
39199
|
+
};
|
|
39067
39200
|
close = async () => {
|
|
39068
39201
|
const turns = [...this.#turns.values()];
|
|
39069
39202
|
for (const turn of turns) {
|
|
39070
39203
|
turn.abortDaemon();
|
|
39071
39204
|
}
|
|
39072
39205
|
await Promise.all(turns.map((turn) => turn.completion));
|
|
39206
|
+
this.#completed.clear();
|
|
39073
39207
|
};
|
|
39074
39208
|
admitAndWait = async (turn, waitSignal, onQueued) => {
|
|
39075
39209
|
const command = turn.command;
|
|
@@ -41377,10 +41511,10 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
|
|
|
41377
41511
|
}
|
|
41378
41512
|
|
|
41379
41513
|
// src/native-sessions/live-history-page.ts
|
|
41380
|
-
function
|
|
41381
|
-
return Buffer.from(JSON.stringify(
|
|
41514
|
+
function encodeLiveHistoryCursor(cursor) {
|
|
41515
|
+
return Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
|
|
41382
41516
|
}
|
|
41383
|
-
function
|
|
41517
|
+
function decodeLiveHistoryCursor(cursor, sessionId) {
|
|
41384
41518
|
try {
|
|
41385
41519
|
if (!/^[A-Za-z0-9_-]{1,512}$/u.test(cursor)) {
|
|
41386
41520
|
throw new Error("Invalid cursor alphabet");
|
|
@@ -41390,14 +41524,32 @@ function liveHistoryEndIndex(cursor, sessionId) {
|
|
|
41390
41524
|
throw new Error("Invalid cursor shape");
|
|
41391
41525
|
}
|
|
41392
41526
|
const record2 = Object.fromEntries(Object.entries(value));
|
|
41393
|
-
|
|
41527
|
+
const keys = Object.keys(record2).sort().join(",");
|
|
41528
|
+
const legacyNative = keys === "endIndex,sessionId";
|
|
41529
|
+
const kind = legacyNative ? "native" : record2["kind"];
|
|
41530
|
+
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) {
|
|
41394
41531
|
throw new Error("Invalid cursor target");
|
|
41395
41532
|
}
|
|
41396
|
-
|
|
41533
|
+
if (kind === "active") {
|
|
41534
|
+
if (keys !== "endIndex,epoch,kind,sessionId" || typeof record2["epoch"] !== "string") {
|
|
41535
|
+
throw new Error("Invalid active cursor target");
|
|
41536
|
+
}
|
|
41537
|
+
return { endIndex: record2["endIndex"], epoch: record2["epoch"], kind, sessionId };
|
|
41538
|
+
}
|
|
41539
|
+
if (keys !== "endIndex,kind,sessionId" && !legacyNative) {
|
|
41540
|
+
throw new Error("Invalid native cursor target");
|
|
41541
|
+
}
|
|
41542
|
+
return { endIndex: record2["endIndex"], kind, sessionId };
|
|
41397
41543
|
} catch (cause) {
|
|
41398
41544
|
throw new AcpExecutionError("The native Session history cursor is invalid", { cause }, "invalid_cursor");
|
|
41399
41545
|
}
|
|
41400
41546
|
}
|
|
41547
|
+
function activeHistoryCursor(sessionId, epoch, endIndex) {
|
|
41548
|
+
return encodeLiveHistoryCursor({ endIndex, epoch, kind: "active", sessionId });
|
|
41549
|
+
}
|
|
41550
|
+
function nativeHistoryCursor(sessionId, endIndex) {
|
|
41551
|
+
return encodeLiveHistoryCursor({ endIndex, kind: "native", sessionId });
|
|
41552
|
+
}
|
|
41401
41553
|
function liveHistoryCoveredTurnRanges(history) {
|
|
41402
41554
|
const ranges = [];
|
|
41403
41555
|
let historyIndex = history.messages.length;
|
|
@@ -41418,139 +41570,180 @@ function liveHistoryCoveredTurnRanges(history) {
|
|
|
41418
41570
|
function historyMessageCharacters(message) {
|
|
41419
41571
|
return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
|
|
41420
41572
|
}
|
|
41421
|
-
function
|
|
41573
|
+
function isNativeHistoryImageMimeType(mimeType) {
|
|
41574
|
+
return mimeType === "image/png" || mimeType === "image/jpeg" || mimeType === "image/gif" || mimeType === "image/webp";
|
|
41575
|
+
}
|
|
41576
|
+
function selectMessagesBefore(messages, endIndex, messageLimit, characterLimit) {
|
|
41422
41577
|
const selected = [];
|
|
41423
41578
|
let remainingCharacters = characterLimit;
|
|
41424
|
-
|
|
41579
|
+
let startIndex = endIndex;
|
|
41580
|
+
for (let index = endIndex - 1; index >= 0 && selected.length < messageLimit; index -= 1) {
|
|
41425
41581
|
const message = messages[index];
|
|
41426
41582
|
if (message === void 0) {
|
|
41427
41583
|
break;
|
|
41428
41584
|
}
|
|
41429
41585
|
const characters = historyMessageCharacters(message);
|
|
41430
|
-
if (characters
|
|
41431
|
-
|
|
41432
|
-
remainingCharacters -= characters;
|
|
41433
|
-
continue;
|
|
41434
|
-
}
|
|
41435
|
-
const structuredCharacters = characters - message.text.length;
|
|
41436
|
-
if (selected.length === 0 && structuredCharacters <= remainingCharacters) {
|
|
41437
|
-
const textCharacters = remainingCharacters - structuredCharacters;
|
|
41438
|
-
selected.unshift({ ...message, text: textCharacters === 0 ? "" : message.text.slice(-textCharacters) });
|
|
41439
|
-
remainingCharacters = 0;
|
|
41586
|
+
if (characters > remainingCharacters) {
|
|
41587
|
+
break;
|
|
41440
41588
|
}
|
|
41441
|
-
|
|
41589
|
+
selected.unshift(message);
|
|
41590
|
+
remainingCharacters -= characters;
|
|
41591
|
+
startIndex = index;
|
|
41442
41592
|
}
|
|
41443
|
-
|
|
41444
|
-
|
|
41445
|
-
|
|
41446
|
-
|
|
41447
|
-
|
|
41593
|
+
if (selected.length === 0 && endIndex > 0) {
|
|
41594
|
+
throw new AcpExecutionError(
|
|
41595
|
+
"A native Session history item exceeds the page budget",
|
|
41596
|
+
{},
|
|
41597
|
+
"history_item_too_large"
|
|
41598
|
+
);
|
|
41599
|
+
}
|
|
41600
|
+
return { characters: characterLimit - remainingCharacters, messages: selected, startIndex };
|
|
41448
41601
|
}
|
|
41449
41602
|
function nativeActiveMessage(message) {
|
|
41450
|
-
|
|
41451
|
-
|
|
41452
|
-
|
|
41453
|
-
|
|
41454
|
-
|
|
41455
|
-
|
|
41603
|
+
if (message.role === "assistant") {
|
|
41604
|
+
return {
|
|
41605
|
+
activities: message.activities,
|
|
41606
|
+
content: message.content,
|
|
41607
|
+
role: "assistant",
|
|
41608
|
+
text: message.text
|
|
41609
|
+
};
|
|
41610
|
+
}
|
|
41611
|
+
const images = (message.images ?? []).flatMap((image) => {
|
|
41612
|
+
if (image.data.length < 4 || image.data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/u.test(image.data) || !isNativeHistoryImageMimeType(image.mimeType)) {
|
|
41613
|
+
return [];
|
|
41614
|
+
}
|
|
41615
|
+
return [{ data: image.data, mimeType: image.mimeType, name: image.name }];
|
|
41616
|
+
});
|
|
41617
|
+
return { ...images.length === 0 ? {} : { images }, role: "user", text: message.text };
|
|
41618
|
+
}
|
|
41619
|
+
function nativeHistoryCoversCompletedRecovery(history, recovery) {
|
|
41620
|
+
const root = recovery.messages.find((message) => message.role === "user" && message.id === recovery.commandId);
|
|
41621
|
+
if (root === void 0) {
|
|
41622
|
+
return false;
|
|
41623
|
+
}
|
|
41624
|
+
const rootIndex = history.messages.findLastIndex(
|
|
41625
|
+
(message) => message.role === "user" && message.text === root.text
|
|
41626
|
+
);
|
|
41627
|
+
if (rootIndex < 0) {
|
|
41628
|
+
return false;
|
|
41629
|
+
}
|
|
41630
|
+
const nativeAssistant = history.messages.slice(rootIndex + 1).filter((message) => message.role === "assistant");
|
|
41631
|
+
if (nativeAssistant.length === 0) {
|
|
41632
|
+
return false;
|
|
41633
|
+
}
|
|
41634
|
+
const recoveryAssistant = recovery.messages.filter((message) => message.role === "assistant");
|
|
41635
|
+
const recoveryText = recoveryAssistant.map((message) => message.text).join("");
|
|
41636
|
+
const nativeText = nativeAssistant.map((message) => message.text).join("");
|
|
41637
|
+
if (recoveryText.length > 0 && !nativeText.includes(recoveryText)) {
|
|
41638
|
+
return false;
|
|
41639
|
+
}
|
|
41640
|
+
const nativeContent = new Set(
|
|
41641
|
+
nativeAssistant.flatMap((message) => message.content).map((content) => JSON.stringify(content))
|
|
41642
|
+
);
|
|
41643
|
+
return recoveryAssistant.flatMap((message) => message.content).every((content) => nativeContent.has(JSON.stringify(content)));
|
|
41456
41644
|
}
|
|
41457
|
-
function
|
|
41645
|
+
function historyBeforeActiveTurn(history, activeTurn) {
|
|
41458
41646
|
if (history.status === "unavailable") {
|
|
41459
|
-
|
|
41460
|
-
throw new AcpExecutionError("Unavailable native Session history has no cursor", {}, "invalid_cursor");
|
|
41461
|
-
}
|
|
41462
|
-
return { cause: history.cause, nextCursor: null, status: "unavailable" };
|
|
41647
|
+
return history;
|
|
41463
41648
|
}
|
|
41464
|
-
const
|
|
41649
|
+
const activeRoot = activeTurn.messages.find(
|
|
41650
|
+
(message) => message.role === "user" && message.id === activeTurn.commandId
|
|
41651
|
+
);
|
|
41652
|
+
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;
|
|
41653
|
+
const activeUserIndex = matchingActiveUserIndex >= 0 ? matchingActiveUserIndex : liveHistoryCoveredTurnRanges(history).find((range) => range.commandId === activeTurn.commandId)?.userIndex ?? -1;
|
|
41654
|
+
if (activeUserIndex < 0) {
|
|
41655
|
+
return history;
|
|
41656
|
+
}
|
|
41657
|
+
return {
|
|
41658
|
+
...history,
|
|
41659
|
+
coveredCommandIds: history.coveredCommandIds.filter((id) => id !== activeTurn.commandId),
|
|
41660
|
+
coveredMessageIds: history.coveredMessageIds.filter(
|
|
41661
|
+
(id) => id !== `${activeTurn.commandId}:user` && id !== `${activeTurn.commandId}:agent`
|
|
41662
|
+
),
|
|
41663
|
+
messages: history.messages.slice(0, activeUserIndex)
|
|
41664
|
+
};
|
|
41665
|
+
}
|
|
41666
|
+
function paginateAvailableNativeHistory(history, sessionId, endIndex, limit, characterLimit) {
|
|
41465
41667
|
if (endIndex > history.messages.length) {
|
|
41466
41668
|
throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
|
|
41467
41669
|
}
|
|
41468
|
-
const
|
|
41670
|
+
const selected = selectMessagesBefore(history.messages, endIndex, limit, characterLimit);
|
|
41469
41671
|
const coveredMessageIds = new Set(history.coveredMessageIds);
|
|
41470
41672
|
const ranges = liveHistoryCoveredTurnRanges(history);
|
|
41471
41673
|
return {
|
|
41472
|
-
coveredCommandIds: ranges.filter((range) => range.userIndex >= startIndex && range.assistantEndIndex <= endIndex).map((range) => range.commandId),
|
|
41674
|
+
coveredCommandIds: ranges.filter((range) => range.userIndex >= selected.startIndex && range.assistantEndIndex <= endIndex).map((range) => range.commandId),
|
|
41473
41675
|
coveredMessageIds: ranges.flatMap((range) => [
|
|
41474
|
-
...range.userIndex >= startIndex && range.userIndex < endIndex && coveredMessageIds.has(`${range.commandId}:user`) ? [`${range.commandId}:user`] : [],
|
|
41475
|
-
...range.assistantStartIndex >= startIndex && range.assistantEndIndex <= endIndex && coveredMessageIds.has(`${range.commandId}:agent`) ? [`${range.commandId}:agent`] : []
|
|
41676
|
+
...range.userIndex >= selected.startIndex && range.userIndex < endIndex && coveredMessageIds.has(`${range.commandId}:user`) ? [`${range.commandId}:user`] : [],
|
|
41677
|
+
...range.assistantStartIndex >= selected.startIndex && range.assistantEndIndex <= endIndex && coveredMessageIds.has(`${range.commandId}:agent`) ? [`${range.commandId}:agent`] : []
|
|
41476
41678
|
]),
|
|
41477
|
-
messages:
|
|
41478
|
-
nextCursor: startIndex > 0 ?
|
|
41679
|
+
messages: selected.messages,
|
|
41680
|
+
nextCursor: selected.startIndex > 0 ? nativeHistoryCursor(sessionId, selected.startIndex) : null,
|
|
41479
41681
|
status: "available",
|
|
41480
41682
|
truncated: history.truncated
|
|
41481
41683
|
};
|
|
41482
41684
|
}
|
|
41483
|
-
function
|
|
41484
|
-
if (
|
|
41485
|
-
|
|
41685
|
+
function paginateNativeHistory(history, sessionId, cursor, limit) {
|
|
41686
|
+
if (cursor?.kind === "active") {
|
|
41687
|
+
throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
|
|
41486
41688
|
}
|
|
41487
41689
|
if (history.status === "unavailable") {
|
|
41488
|
-
|
|
41489
|
-
|
|
41490
|
-
|
|
41491
|
-
|
|
41492
|
-
);
|
|
41493
|
-
return {
|
|
41494
|
-
coveredCommandIds: [],
|
|
41495
|
-
coveredMessageIds: [],
|
|
41496
|
-
messages: bounded3.messages,
|
|
41497
|
-
nextCursor: null,
|
|
41498
|
-
status: "available",
|
|
41499
|
-
truncated: activeTurn.truncated || bounded3.truncated
|
|
41500
|
-
};
|
|
41690
|
+
if (cursor !== null) {
|
|
41691
|
+
throw new AcpExecutionError("Unavailable native Session history has no cursor", {}, "invalid_cursor");
|
|
41692
|
+
}
|
|
41693
|
+
return { cause: history.cause, nextCursor: null, status: "unavailable" };
|
|
41501
41694
|
}
|
|
41502
|
-
|
|
41503
|
-
|
|
41695
|
+
return paginateAvailableNativeHistory(
|
|
41696
|
+
history,
|
|
41697
|
+
sessionId,
|
|
41698
|
+
cursor?.endIndex ?? history.messages.length,
|
|
41699
|
+
limit,
|
|
41700
|
+
SESSION_HISTORY_CHARACTER_LIMIT
|
|
41504
41701
|
);
|
|
41505
|
-
|
|
41506
|
-
|
|
41507
|
-
|
|
41508
|
-
|
|
41509
|
-
const activeUserIndex = matchingActiveUserIndex >= 0 ? matchingActiveUserIndex : liveHistoryCoveredTurnRanges(history).find((range) => range.commandId === activeTurn.commandId)?.userIndex ?? -1;
|
|
41510
|
-
if (activeUserIndex >= 0) {
|
|
41511
|
-
history = {
|
|
41512
|
-
...history,
|
|
41513
|
-
coveredCommandIds: history.coveredCommandIds.filter((id) => id !== activeTurn.commandId),
|
|
41514
|
-
coveredMessageIds: history.coveredMessageIds.filter(
|
|
41515
|
-
(id) => id !== `${activeTurn.commandId}:user` && id !== `${activeTurn.commandId}:agent`
|
|
41516
|
-
),
|
|
41517
|
-
messages: history.messages.slice(0, activeUserIndex + 1)
|
|
41518
|
-
};
|
|
41519
|
-
}
|
|
41520
|
-
const latestNativeMessage = history.messages.at(-1);
|
|
41521
|
-
const firstActiveMessage = activeTurn.messages[0];
|
|
41522
|
-
const preserveNativeRoot = activeUserIndex >= 0 || firstActiveMessage?.role === "user" && latestNativeMessage?.role === "user" && latestNativeMessage.text === firstActiveMessage.text;
|
|
41523
|
-
const activeMessages = activeTurn.messages.slice(preserveNativeRoot ? 1 : 0).map(nativeActiveMessage);
|
|
41524
|
-
const bounded2 = boundedActiveMessages(activeMessages, limit, SESSION_HISTORY_CHARACTER_LIMIT);
|
|
41525
|
-
let historicalMessageCount = 0;
|
|
41526
|
-
let remainingCharacters = SESSION_HISTORY_CHARACTER_LIMIT - bounded2.characters;
|
|
41527
|
-
const historicalMessageLimit = Math.max(0, limit - bounded2.messages.length);
|
|
41528
|
-
for (let index = history.messages.length - 1; index >= 0 && historicalMessageCount < historicalMessageLimit; index -= 1) {
|
|
41529
|
-
const message = history.messages[index];
|
|
41530
|
-
if (message === void 0) {
|
|
41531
|
-
break;
|
|
41532
|
-
}
|
|
41533
|
-
const characters = historyMessageCharacters(message);
|
|
41534
|
-
if (characters > remainingCharacters) {
|
|
41535
|
-
break;
|
|
41536
|
-
}
|
|
41537
|
-
historicalMessageCount += 1;
|
|
41538
|
-
remainingCharacters -= characters;
|
|
41702
|
+
}
|
|
41703
|
+
function paginateActiveTurn(history, activeTurn, sessionId, endIndex, limit) {
|
|
41704
|
+
if (endIndex > activeTurn.messages.length) {
|
|
41705
|
+
throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
|
|
41539
41706
|
}
|
|
41540
|
-
const
|
|
41541
|
-
|
|
41542
|
-
|
|
41543
|
-
|
|
41544
|
-
|
|
41545
|
-
|
|
41546
|
-
|
|
41547
|
-
|
|
41707
|
+
const activeMessages = activeTurn.messages.map(nativeActiveMessage);
|
|
41708
|
+
const active = selectMessagesBefore(activeMessages, endIndex, limit, SESSION_HISTORY_CHARACTER_LIMIT);
|
|
41709
|
+
const historicalLimit = limit - active.messages.length;
|
|
41710
|
+
const historicalCharacterLimit = SESSION_HISTORY_CHARACTER_LIMIT - active.characters;
|
|
41711
|
+
const pendingHistoricalCursor = history.status === "available" && history.messages.length > 0 ? nativeHistoryCursor(sessionId, history.messages.length) : null;
|
|
41712
|
+
const latestHistoricalMessage = history.status === "available" ? history.messages.at(-1) : void 0;
|
|
41713
|
+
const historicalPageFits = latestHistoricalMessage === void 0 || historyMessageCharacters(latestHistoricalMessage) <= historicalCharacterLimit;
|
|
41714
|
+
const historical = active.startIndex === 0 && history.status === "available" && historicalLimit > 0 && historicalPageFits ? paginateAvailableNativeHistory(
|
|
41715
|
+
history,
|
|
41716
|
+
sessionId,
|
|
41717
|
+
history.messages.length,
|
|
41718
|
+
historicalLimit,
|
|
41719
|
+
historicalCharacterLimit
|
|
41720
|
+
) : null;
|
|
41548
41721
|
return {
|
|
41549
|
-
|
|
41550
|
-
|
|
41551
|
-
|
|
41722
|
+
coveredCommandIds: historical?.coveredCommandIds ?? [],
|
|
41723
|
+
coveredMessageIds: [
|
|
41724
|
+
...historical?.coveredMessageIds ?? [],
|
|
41725
|
+
...active.startIndex === 0 ? [`${activeTurn.commandId}:user`, `${activeTurn.commandId}:agent`] : []
|
|
41726
|
+
],
|
|
41727
|
+
messages: [...historical?.messages ?? [], ...active.messages],
|
|
41728
|
+
nextCursor: active.startIndex > 0 ? activeHistoryCursor(sessionId, activeTurn.epoch, active.startIndex) : historical === null ? pendingHistoricalCursor : historical.nextCursor,
|
|
41729
|
+
status: "available",
|
|
41730
|
+
truncated: activeTurn.truncated || (historical?.truncated ?? false)
|
|
41552
41731
|
};
|
|
41553
41732
|
}
|
|
41733
|
+
function paginateLiveSessionHistory(history, activeTurn, sessionId, encodedCursor, limit) {
|
|
41734
|
+
const cursor = encodedCursor === null ? null : decodeLiveHistoryCursor(encodedCursor, sessionId);
|
|
41735
|
+
if (activeTurn === null || activeTurn.state === "completed" && history.status === "available" && nativeHistoryCoversCompletedRecovery(history, activeTurn)) {
|
|
41736
|
+
return paginateNativeHistory(history, sessionId, cursor, limit);
|
|
41737
|
+
}
|
|
41738
|
+
const historical = historyBeforeActiveTurn(history, activeTurn);
|
|
41739
|
+
if (cursor?.kind === "native") {
|
|
41740
|
+
return paginateNativeHistory(historical, sessionId, cursor, limit);
|
|
41741
|
+
}
|
|
41742
|
+
if (cursor !== null && cursor.epoch !== activeTurn.epoch) {
|
|
41743
|
+
throw new AcpExecutionError("The active Turn history cursor is stale", {}, "stale_cursor");
|
|
41744
|
+
}
|
|
41745
|
+
return paginateActiveTurn(historical, activeTurn, sessionId, cursor?.endIndex ?? activeTurn.messages.length, limit);
|
|
41746
|
+
}
|
|
41554
41747
|
function mergeLiveSessionHistory(history, activeTurn, sessionId) {
|
|
41555
41748
|
const page = paginateLiveSessionHistory(history, activeTurn, sessionId, null, 1e3);
|
|
41556
41749
|
if (page.status === "unavailable") {
|
|
@@ -41561,7 +41754,7 @@ function mergeLiveSessionHistory(history, activeTurn, sessionId) {
|
|
|
41561
41754
|
coveredMessageIds: page.coveredMessageIds,
|
|
41562
41755
|
messages: page.messages,
|
|
41563
41756
|
status: "available",
|
|
41564
|
-
truncated: page.truncated
|
|
41757
|
+
truncated: page.truncated || page.nextCursor !== null
|
|
41565
41758
|
};
|
|
41566
41759
|
}
|
|
41567
41760
|
|
|
@@ -42080,15 +42273,13 @@ async function executePrompt({
|
|
|
42080
42273
|
});
|
|
42081
42274
|
operations.transitionExecution(command.commandId, "running");
|
|
42082
42275
|
if (availability.disposition === SessionPromptDisposition.Steer) {
|
|
42083
|
-
|
|
42084
|
-
if (updated === null) {
|
|
42276
|
+
if (!recordSteeringPrompt()) {
|
|
42085
42277
|
throw new AcpExecutionError(
|
|
42086
42278
|
"The steering target is unavailable",
|
|
42087
42279
|
{},
|
|
42088
42280
|
"prompt_queue_target_unavailable"
|
|
42089
42281
|
);
|
|
42090
42282
|
}
|
|
42091
|
-
publisher.publish(command.sessionId, updated);
|
|
42092
42283
|
}
|
|
42093
42284
|
const stream = activateAttempt();
|
|
42094
42285
|
publisher.publish(command.sessionId, {
|
|
@@ -42476,7 +42667,7 @@ function createDaemonCommandHandler({
|
|
|
42476
42667
|
resolveEnvironment: resolveAgentCatalogEnvironment
|
|
42477
42668
|
});
|
|
42478
42669
|
const queueChanged = (sessionId) => publisher.publish(sessionId, { kind: "session.queue.changed", sessionId });
|
|
42479
|
-
const
|
|
42670
|
+
const activeTurnRecovery = (sessionId) => activeTurns.recovery((command) => command.sessionId === sessionId);
|
|
42480
42671
|
const nativeRequestHandler = createNativeSessionRequestHandler({
|
|
42481
42672
|
audit,
|
|
42482
42673
|
diagnostics,
|
|
@@ -42497,7 +42688,7 @@ function createDaemonCommandHandler({
|
|
|
42497
42688
|
directories,
|
|
42498
42689
|
audit,
|
|
42499
42690
|
sessions,
|
|
42500
|
-
|
|
42691
|
+
activeTurnRecovery,
|
|
42501
42692
|
signal
|
|
42502
42693
|
);
|
|
42503
42694
|
return;
|
|
@@ -42511,7 +42702,7 @@ function createDaemonCommandHandler({
|
|
|
42511
42702
|
directories,
|
|
42512
42703
|
audit,
|
|
42513
42704
|
sessions,
|
|
42514
|
-
|
|
42705
|
+
activeTurnRecovery,
|
|
42515
42706
|
signal
|
|
42516
42707
|
);
|
|
42517
42708
|
return;
|
|
@@ -42983,6 +43174,7 @@ async function runRelayConnection({
|
|
|
42983
43174
|
}) {
|
|
42984
43175
|
const relayUrl = new URL(config2.relayUrl);
|
|
42985
43176
|
relayUrl.searchParams.set("liveness", "1");
|
|
43177
|
+
relayUrl.searchParams.set("sessionEventDelivery", "reliable-v1");
|
|
42986
43178
|
const socket = await connectRelay(relayUrl, signal);
|
|
42987
43179
|
diagnostics.connectionOpened(connectionEpoch);
|
|
42988
43180
|
const connectionController = new AbortController();
|
|
@@ -43102,6 +43294,10 @@ async function runRelayConnection({
|
|
|
43102
43294
|
const message = decodeServiceToDaemonMessage(encoded);
|
|
43103
43295
|
const kind = message.kind;
|
|
43104
43296
|
if (kind === RUNTIME_LIVENESS_READY_KIND) {
|
|
43297
|
+
publisher.connect(
|
|
43298
|
+
socket,
|
|
43299
|
+
message.sessionEventDelivery === "reliable-v1" ? "reliable" : "ephemeral"
|
|
43300
|
+
);
|
|
43105
43301
|
connectionLiveness.start();
|
|
43106
43302
|
return;
|
|
43107
43303
|
}
|
|
@@ -43109,6 +43305,18 @@ async function runRelayConnection({
|
|
|
43109
43305
|
connectionLiveness.acknowledge(message);
|
|
43110
43306
|
return;
|
|
43111
43307
|
}
|
|
43308
|
+
if (kind === SESSION_EVENT_ACK_KIND) {
|
|
43309
|
+
publisher.acknowledge(message);
|
|
43310
|
+
return;
|
|
43311
|
+
}
|
|
43312
|
+
if (kind === SESSION_EVENT_DEFERRED_KIND) {
|
|
43313
|
+
publisher.defer(message);
|
|
43314
|
+
return;
|
|
43315
|
+
}
|
|
43316
|
+
if (kind === SESSION_EVENT_REJECTED_KIND) {
|
|
43317
|
+
publisher.quarantine(message);
|
|
43318
|
+
return;
|
|
43319
|
+
}
|
|
43112
43320
|
commands.handle(message);
|
|
43113
43321
|
} catch (error62) {
|
|
43114
43322
|
console.error("Mobius daemon rejected a message", error62);
|
|
@@ -43123,7 +43331,6 @@ async function runRelayConnection({
|
|
|
43123
43331
|
socket.addEventListener("close", handleClose);
|
|
43124
43332
|
socket.addEventListener("error", handleError);
|
|
43125
43333
|
socket.addEventListener("message", handleMessage);
|
|
43126
|
-
publisher.connect(socket);
|
|
43127
43334
|
if (signal.aborted) {
|
|
43128
43335
|
stop();
|
|
43129
43336
|
}
|
|
@@ -43134,54 +43341,377 @@ async function runRelayConnection({
|
|
|
43134
43341
|
}
|
|
43135
43342
|
}
|
|
43136
43343
|
|
|
43344
|
+
// src/relay-connection/session-event-outbox.ts
|
|
43345
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
43346
|
+
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
43347
|
+
import { dirname as dirname6 } from "node:path";
|
|
43348
|
+
import { DatabaseSync } from "node:sqlite";
|
|
43349
|
+
var DEFAULT_STANDARD_EVENT_BYTES = 96 * 1024 * 1024;
|
|
43350
|
+
var DEFAULT_CRITICAL_EVENT_BYTES = 128 * 1024 * 1024;
|
|
43351
|
+
var MAX_DEAD_LETTERS = 1024;
|
|
43352
|
+
var DEFAULT_LIMITS = {
|
|
43353
|
+
criticalEventBytes: DEFAULT_CRITICAL_EVENT_BYTES,
|
|
43354
|
+
standardEventBytes: DEFAULT_STANDARD_EVENT_BYTES
|
|
43355
|
+
};
|
|
43356
|
+
var SessionEventOutboxCapacityError = class extends Error {
|
|
43357
|
+
code = "session_event_outbox_full";
|
|
43358
|
+
constructor() {
|
|
43359
|
+
super("The persistent Session event outbox is full");
|
|
43360
|
+
this.name = "SessionEventOutboxCapacityError";
|
|
43361
|
+
}
|
|
43362
|
+
};
|
|
43363
|
+
function rowNumber(row, field) {
|
|
43364
|
+
const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
|
|
43365
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
43366
|
+
throw new Error(`SQLite returned an invalid ${field} value`);
|
|
43367
|
+
}
|
|
43368
|
+
return value;
|
|
43369
|
+
}
|
|
43370
|
+
function rowString(row, field) {
|
|
43371
|
+
const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
|
|
43372
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
43373
|
+
throw new Error(`SQLite returned an invalid ${field} value`);
|
|
43374
|
+
}
|
|
43375
|
+
return value;
|
|
43376
|
+
}
|
|
43377
|
+
function validateLimits(limits) {
|
|
43378
|
+
if (!Number.isSafeInteger(limits.standardEventBytes) || limits.standardEventBytes < 1 || !Number.isSafeInteger(limits.criticalEventBytes) || limits.criticalEventBytes < limits.standardEventBytes) {
|
|
43379
|
+
throw new Error("Session event outbox limits are invalid");
|
|
43380
|
+
}
|
|
43381
|
+
}
|
|
43382
|
+
var SessionEventOutbox = class {
|
|
43383
|
+
#database;
|
|
43384
|
+
#limits;
|
|
43385
|
+
constructor(path2, limits = DEFAULT_LIMITS) {
|
|
43386
|
+
validateLimits(limits);
|
|
43387
|
+
mkdirSync3(dirname6(path2), { mode: 448, recursive: true });
|
|
43388
|
+
this.#limits = limits;
|
|
43389
|
+
this.#database = new DatabaseSync(path2);
|
|
43390
|
+
this.#database.exec("PRAGMA journal_mode = WAL; PRAGMA synchronous = FULL; PRAGMA busy_timeout = 5000;");
|
|
43391
|
+
this.#database.exec(`
|
|
43392
|
+
CREATE TABLE IF NOT EXISTS relay_session_event_outbox (
|
|
43393
|
+
ordinal INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
43394
|
+
event_id TEXT NOT NULL UNIQUE,
|
|
43395
|
+
session_id TEXT NOT NULL,
|
|
43396
|
+
source_seq INTEGER NOT NULL UNIQUE,
|
|
43397
|
+
byte_length INTEGER NOT NULL,
|
|
43398
|
+
envelope_json TEXT NOT NULL
|
|
43399
|
+
) STRICT;
|
|
43400
|
+
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
|
|
43401
|
+
ON relay_session_event_outbox(source_seq);
|
|
43402
|
+
CREATE TABLE IF NOT EXISTS relay_session_event_outbox_state (
|
|
43403
|
+
singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
|
|
43404
|
+
stream_id TEXT NOT NULL,
|
|
43405
|
+
next_source_seq INTEGER NOT NULL,
|
|
43406
|
+
total_bytes INTEGER NOT NULL
|
|
43407
|
+
) STRICT;
|
|
43408
|
+
CREATE TABLE IF NOT EXISTS relay_session_event_dead_letters (
|
|
43409
|
+
ordinal INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
43410
|
+
event_id TEXT NOT NULL UNIQUE,
|
|
43411
|
+
session_id TEXT NOT NULL,
|
|
43412
|
+
rejection_code TEXT NOT NULL,
|
|
43413
|
+
envelope_json TEXT NOT NULL
|
|
43414
|
+
) STRICT;
|
|
43415
|
+
`);
|
|
43416
|
+
this.#database.prepare(
|
|
43417
|
+
`INSERT OR IGNORE INTO relay_session_event_outbox_state (
|
|
43418
|
+
singleton, stream_id, next_source_seq, total_bytes
|
|
43419
|
+
) VALUES (1, ?, 1, 0)`
|
|
43420
|
+
).run(randomUUID7());
|
|
43421
|
+
}
|
|
43422
|
+
acknowledge = (acknowledgement) => this.#remove(acknowledgement.eventId, acknowledgement.sessionId);
|
|
43423
|
+
close = () => {
|
|
43424
|
+
this.#database.close();
|
|
43425
|
+
};
|
|
43426
|
+
enqueue = (sessionId, payload, critical) => {
|
|
43427
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
43428
|
+
try {
|
|
43429
|
+
const state = this.#database.prepare(
|
|
43430
|
+
`SELECT stream_id, next_source_seq, total_bytes
|
|
43431
|
+
FROM relay_session_event_outbox_state
|
|
43432
|
+
WHERE singleton = 1`
|
|
43433
|
+
).get();
|
|
43434
|
+
const sourceSeq = rowNumber(state, "next_source_seq");
|
|
43435
|
+
if (sourceSeq < 1 || !Number.isSafeInteger(sourceSeq + 1)) {
|
|
43436
|
+
throw new Error("The Session event source sequence is exhausted");
|
|
43437
|
+
}
|
|
43438
|
+
const envelope2 = {
|
|
43439
|
+
delivery: {
|
|
43440
|
+
eventId: randomUUID7(),
|
|
43441
|
+
kind: "reliable",
|
|
43442
|
+
sourceSeq: sourceSeq.toString(),
|
|
43443
|
+
streamId: rowString(state, "stream_id")
|
|
43444
|
+
},
|
|
43445
|
+
kind: SESSION_EVENT_KIND,
|
|
43446
|
+
payload,
|
|
43447
|
+
sessionId
|
|
43448
|
+
};
|
|
43449
|
+
const encoded = encodeSessionEventEnvelope(envelope2);
|
|
43450
|
+
const byteLength = Buffer.byteLength(encoded, "utf8");
|
|
43451
|
+
const maximumBytes = critical ? this.#limits.criticalEventBytes : this.#limits.standardEventBytes;
|
|
43452
|
+
if (rowNumber(state, "total_bytes") + byteLength > maximumBytes) {
|
|
43453
|
+
throw new SessionEventOutboxCapacityError();
|
|
43454
|
+
}
|
|
43455
|
+
this.#database.prepare(
|
|
43456
|
+
`INSERT INTO relay_session_event_outbox (
|
|
43457
|
+
event_id, session_id, source_seq, byte_length, envelope_json
|
|
43458
|
+
) VALUES (?, ?, ?, ?, ?)`
|
|
43459
|
+
).run(envelope2.delivery.eventId, sessionId, sourceSeq, byteLength, encoded);
|
|
43460
|
+
this.#database.prepare(
|
|
43461
|
+
`UPDATE relay_session_event_outbox_state
|
|
43462
|
+
SET next_source_seq = next_source_seq + 1,
|
|
43463
|
+
total_bytes = total_bytes + ?
|
|
43464
|
+
WHERE singleton = 1`
|
|
43465
|
+
).run(byteLength);
|
|
43466
|
+
this.#database.exec("COMMIT");
|
|
43467
|
+
return envelope2;
|
|
43468
|
+
} catch (error62) {
|
|
43469
|
+
this.#database.exec("ROLLBACK");
|
|
43470
|
+
throw error62;
|
|
43471
|
+
}
|
|
43472
|
+
};
|
|
43473
|
+
pending = (limit, excludedEventIds) => {
|
|
43474
|
+
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
43475
|
+
throw new Error("Session event replay limit must be a positive integer");
|
|
43476
|
+
}
|
|
43477
|
+
const exclusion = excludedEventIds.length === 0 ? "" : `WHERE event_id NOT IN (${excludedEventIds.map(() => "?").join(", ")})`;
|
|
43478
|
+
return this.#database.prepare(
|
|
43479
|
+
`SELECT envelope_json
|
|
43480
|
+
FROM relay_session_event_outbox
|
|
43481
|
+
${exclusion}
|
|
43482
|
+
ORDER BY source_seq
|
|
43483
|
+
LIMIT ?`
|
|
43484
|
+
).all(...excludedEventIds, limit).map((row) => {
|
|
43485
|
+
const envelope2 = decodeSessionEventEnvelope(rowString(row, "envelope_json"));
|
|
43486
|
+
if (!("delivery" in envelope2)) {
|
|
43487
|
+
throw new Error("SQLite returned an invalid reliable Session event envelope");
|
|
43488
|
+
}
|
|
43489
|
+
return envelope2;
|
|
43490
|
+
});
|
|
43491
|
+
};
|
|
43492
|
+
quarantine = (rejection) => {
|
|
43493
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
43494
|
+
try {
|
|
43495
|
+
const stored = this.#database.prepare(
|
|
43496
|
+
`SELECT byte_length, envelope_json
|
|
43497
|
+
FROM relay_session_event_outbox
|
|
43498
|
+
WHERE event_id = ? AND session_id = ?`
|
|
43499
|
+
).get(rejection.eventId, rejection.sessionId);
|
|
43500
|
+
if (stored === void 0) {
|
|
43501
|
+
this.#database.exec("COMMIT");
|
|
43502
|
+
return false;
|
|
43503
|
+
}
|
|
43504
|
+
this.#database.prepare(
|
|
43505
|
+
`INSERT INTO relay_session_event_dead_letters (
|
|
43506
|
+
event_id, session_id, rejection_code, envelope_json
|
|
43507
|
+
) VALUES (?, ?, ?, ?)`
|
|
43508
|
+
).run(rejection.eventId, rejection.sessionId, rejection.code, rowString(stored, "envelope_json"));
|
|
43509
|
+
this.#deleteStored(rejection.eventId, rejection.sessionId, rowNumber(stored, "byte_length"));
|
|
43510
|
+
this.#database.prepare(
|
|
43511
|
+
`DELETE FROM relay_session_event_dead_letters
|
|
43512
|
+
WHERE ordinal NOT IN (
|
|
43513
|
+
SELECT ordinal FROM relay_session_event_dead_letters
|
|
43514
|
+
ORDER BY ordinal DESC LIMIT ?
|
|
43515
|
+
)`
|
|
43516
|
+
).run(MAX_DEAD_LETTERS);
|
|
43517
|
+
this.#database.exec("COMMIT");
|
|
43518
|
+
return true;
|
|
43519
|
+
} catch (error62) {
|
|
43520
|
+
this.#database.exec("ROLLBACK");
|
|
43521
|
+
throw error62;
|
|
43522
|
+
}
|
|
43523
|
+
};
|
|
43524
|
+
#deleteStored = (eventId, sessionId, byteLength) => {
|
|
43525
|
+
const deletion = this.#database.prepare(
|
|
43526
|
+
`DELETE FROM relay_session_event_outbox
|
|
43527
|
+
WHERE event_id = ? AND session_id = ?`
|
|
43528
|
+
).run(eventId, sessionId);
|
|
43529
|
+
if (deletion.changes !== 1) {
|
|
43530
|
+
throw new Error("The Session event could not be removed from the outbox");
|
|
43531
|
+
}
|
|
43532
|
+
const state = this.#database.prepare(
|
|
43533
|
+
`UPDATE relay_session_event_outbox_state
|
|
43534
|
+
SET total_bytes = total_bytes - ?
|
|
43535
|
+
WHERE singleton = 1 AND total_bytes >= ?`
|
|
43536
|
+
).run(byteLength, byteLength);
|
|
43537
|
+
if (state.changes !== 1) {
|
|
43538
|
+
throw new Error("The Session event outbox capacity state is inconsistent");
|
|
43539
|
+
}
|
|
43540
|
+
};
|
|
43541
|
+
#remove = (eventId, sessionId) => {
|
|
43542
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
43543
|
+
try {
|
|
43544
|
+
const stored = this.#database.prepare(
|
|
43545
|
+
`SELECT byte_length
|
|
43546
|
+
FROM relay_session_event_outbox
|
|
43547
|
+
WHERE event_id = ? AND session_id = ?`
|
|
43548
|
+
).get(eventId, sessionId);
|
|
43549
|
+
if (stored === void 0) {
|
|
43550
|
+
this.#database.exec("COMMIT");
|
|
43551
|
+
return false;
|
|
43552
|
+
}
|
|
43553
|
+
this.#deleteStored(eventId, sessionId, rowNumber(stored, "byte_length"));
|
|
43554
|
+
this.#database.exec("COMMIT");
|
|
43555
|
+
return true;
|
|
43556
|
+
} catch (error62) {
|
|
43557
|
+
this.#database.exec("ROLLBACK");
|
|
43558
|
+
throw error62;
|
|
43559
|
+
}
|
|
43560
|
+
};
|
|
43561
|
+
};
|
|
43562
|
+
|
|
43137
43563
|
// src/relay-connection/session-event-publisher.ts
|
|
43138
43564
|
import { WebSocket as WebSocket9 } from "undici";
|
|
43139
|
-
var
|
|
43565
|
+
var SESSION_EVENT_REPLAY_WINDOW = 16;
|
|
43566
|
+
var SESSION_EVENT_REPLAY_BYTE_LIMIT = 32 * 1024 * 1024;
|
|
43567
|
+
function reservesSessionEventCapacity(event) {
|
|
43568
|
+
if (event.kind === SESSION_COMPLETED_KIND || event.kind === SESSION_FAILED_KIND) {
|
|
43569
|
+
return true;
|
|
43570
|
+
}
|
|
43571
|
+
return event.kind === AGENT_ACTIVITY_KIND && (event.activityType === "progress" || event.activityType === "reasoning") && (event.status === "completed" || event.status === "failed");
|
|
43572
|
+
}
|
|
43140
43573
|
var DaemonSessionEventPublisher = class {
|
|
43141
|
-
#
|
|
43142
|
-
#
|
|
43143
|
-
|
|
43144
|
-
|
|
43145
|
-
|
|
43574
|
+
#inFlight = /* @__PURE__ */ new Map();
|
|
43575
|
+
#outbox;
|
|
43576
|
+
#reportedCapacityKinds = /* @__PURE__ */ new Set();
|
|
43577
|
+
#timer;
|
|
43578
|
+
#connection = { kind: "disconnected" };
|
|
43579
|
+
#deferredReplay = null;
|
|
43580
|
+
#inFlightBytes = 0;
|
|
43581
|
+
constructor(outbox, timer) {
|
|
43582
|
+
this.#outbox = outbox;
|
|
43583
|
+
this.#timer = timer;
|
|
43584
|
+
}
|
|
43585
|
+
acknowledge = (acknowledgement) => {
|
|
43586
|
+
if (!this.#outbox.acknowledge(acknowledgement)) {
|
|
43587
|
+
return;
|
|
43588
|
+
}
|
|
43589
|
+
this.#removeInFlight(acknowledgement.eventId);
|
|
43590
|
+
this.#publishNextBatch();
|
|
43591
|
+
};
|
|
43592
|
+
close = () => {
|
|
43593
|
+
this.#deferredReplay?.cancel();
|
|
43594
|
+
this.#deferredReplay = null;
|
|
43595
|
+
this.#connection = { kind: "disconnected" };
|
|
43596
|
+
this.#clearInFlight();
|
|
43597
|
+
this.#outbox.close();
|
|
43598
|
+
};
|
|
43599
|
+
connect = (socket, delivery) => {
|
|
43600
|
+
this.#connection = { delivery, kind: "connected", socket };
|
|
43601
|
+
this.#clearInFlight();
|
|
43602
|
+
this.#publishNextBatch();
|
|
43603
|
+
};
|
|
43604
|
+
defer = (deferred) => {
|
|
43605
|
+
if (!this.#inFlight.has(deferred.eventId)) {
|
|
43606
|
+
return;
|
|
43607
|
+
}
|
|
43608
|
+
this.#clearInFlight();
|
|
43609
|
+
if (this.#deferredReplay !== null) {
|
|
43610
|
+
return;
|
|
43611
|
+
}
|
|
43612
|
+
this.#deferredReplay = this.#timer.schedule(() => {
|
|
43613
|
+
this.#deferredReplay = null;
|
|
43614
|
+
this.#publishNextBatch();
|
|
43615
|
+
}, deferred.retryAfterMilliseconds);
|
|
43146
43616
|
};
|
|
43147
43617
|
disconnect = (socket) => {
|
|
43148
|
-
if (this.#socket
|
|
43149
|
-
|
|
43618
|
+
if (this.#connection.kind !== "connected" || this.#connection.socket !== socket) {
|
|
43619
|
+
return;
|
|
43150
43620
|
}
|
|
43621
|
+
this.#connection = { kind: "disconnected" };
|
|
43622
|
+
this.#clearInFlight();
|
|
43151
43623
|
};
|
|
43152
43624
|
publish = (sessionId, event) => {
|
|
43153
|
-
|
|
43154
|
-
|
|
43155
|
-
|
|
43625
|
+
try {
|
|
43626
|
+
this.#outbox.enqueue(sessionId, encodeRecordedSessionEvent(event), reservesSessionEventCapacity(event));
|
|
43627
|
+
} catch (error62) {
|
|
43628
|
+
if (!(error62 instanceof SessionEventOutboxCapacityError)) {
|
|
43629
|
+
throw error62;
|
|
43630
|
+
}
|
|
43631
|
+
if (!this.#reportedCapacityKinds.has(event.kind)) {
|
|
43632
|
+
this.#reportedCapacityKinds.add(event.kind);
|
|
43633
|
+
console.warn(
|
|
43634
|
+
`Mobius daemon could not persist "${event.kind}" because the Session event outbox is full`
|
|
43635
|
+
);
|
|
43636
|
+
}
|
|
43156
43637
|
return;
|
|
43157
43638
|
}
|
|
43158
|
-
|
|
43159
|
-
|
|
43160
|
-
|
|
43161
|
-
|
|
43639
|
+
this.#publishNextBatch();
|
|
43640
|
+
};
|
|
43641
|
+
quarantine = (rejection) => {
|
|
43642
|
+
if (!this.#outbox.quarantine(rejection)) {
|
|
43162
43643
|
return;
|
|
43163
43644
|
}
|
|
43164
|
-
|
|
43165
|
-
|
|
43166
|
-
|
|
43167
|
-
kind: SESSION_EVENT_KIND,
|
|
43168
|
-
payload: encodeRecordedSessionEvent(event),
|
|
43169
|
-
sessionId
|
|
43170
|
-
})
|
|
43171
|
-
);
|
|
43172
|
-
} catch {
|
|
43173
|
-
this.#reportDrop();
|
|
43174
|
-
}
|
|
43645
|
+
this.#removeInFlight(rejection.eventId);
|
|
43646
|
+
console.error(`Mobius Relay rejected Session event ${rejection.eventId} with code ${rejection.code}`);
|
|
43647
|
+
this.#publishNextBatch();
|
|
43175
43648
|
};
|
|
43176
|
-
|
|
43177
|
-
this.#
|
|
43649
|
+
#clearInFlight = () => {
|
|
43650
|
+
this.#inFlight.clear();
|
|
43651
|
+
this.#inFlightBytes = 0;
|
|
43178
43652
|
};
|
|
43179
|
-
#
|
|
43180
|
-
if (this.#
|
|
43653
|
+
#publishNextBatch = () => {
|
|
43654
|
+
if (this.#deferredReplay !== null || this.#connection.kind !== "connected") {
|
|
43181
43655
|
return;
|
|
43182
43656
|
}
|
|
43183
|
-
this.#
|
|
43184
|
-
|
|
43657
|
+
while (this.#inFlight.size < SESSION_EVENT_REPLAY_WINDOW) {
|
|
43658
|
+
const batch = this.#outbox.pending(SESSION_EVENT_REPLAY_WINDOW - this.#inFlight.size, [
|
|
43659
|
+
...this.#inFlight.keys()
|
|
43660
|
+
]);
|
|
43661
|
+
let sent = 0;
|
|
43662
|
+
for (const envelope2 of batch) {
|
|
43663
|
+
const encoded = encodeDaemonToServiceMessage(
|
|
43664
|
+
this.#connection.delivery === "reliable" ? envelope2 : {
|
|
43665
|
+
kind: envelope2.kind,
|
|
43666
|
+
payload: envelope2.payload,
|
|
43667
|
+
sessionId: envelope2.sessionId
|
|
43668
|
+
}
|
|
43669
|
+
);
|
|
43670
|
+
const byteLength = Buffer.byteLength(encoded, "utf8");
|
|
43671
|
+
if (this.#inFlightBytes + byteLength > SESSION_EVENT_REPLAY_BYTE_LIMIT) {
|
|
43672
|
+
return;
|
|
43673
|
+
}
|
|
43674
|
+
if (!this.#send(encoded)) {
|
|
43675
|
+
this.#clearInFlight();
|
|
43676
|
+
return;
|
|
43677
|
+
}
|
|
43678
|
+
if (this.#connection.delivery === "ephemeral") {
|
|
43679
|
+
this.#outbox.acknowledge({
|
|
43680
|
+
eventId: envelope2.delivery.eventId,
|
|
43681
|
+
kind: "session.event.ack",
|
|
43682
|
+
outcome: { kind: "relayed" },
|
|
43683
|
+
sessionId: envelope2.sessionId
|
|
43684
|
+
});
|
|
43685
|
+
sent += 1;
|
|
43686
|
+
continue;
|
|
43687
|
+
}
|
|
43688
|
+
this.#inFlight.set(envelope2.delivery.eventId, { byteLength });
|
|
43689
|
+
this.#inFlightBytes += byteLength;
|
|
43690
|
+
sent += 1;
|
|
43691
|
+
}
|
|
43692
|
+
if (sent === 0) {
|
|
43693
|
+
return;
|
|
43694
|
+
}
|
|
43695
|
+
}
|
|
43696
|
+
};
|
|
43697
|
+
#removeInFlight = (eventId) => {
|
|
43698
|
+
const inFlight = this.#inFlight.get(eventId);
|
|
43699
|
+
if (inFlight === void 0) {
|
|
43700
|
+
return;
|
|
43701
|
+
}
|
|
43702
|
+
this.#inFlight.delete(eventId);
|
|
43703
|
+
this.#inFlightBytes -= inFlight.byteLength;
|
|
43704
|
+
};
|
|
43705
|
+
#send = (encoded) => {
|
|
43706
|
+
if (this.#connection.kind !== "connected" || this.#connection.socket.readyState !== WebSocket9.OPEN) {
|
|
43707
|
+
return false;
|
|
43708
|
+
}
|
|
43709
|
+
try {
|
|
43710
|
+
this.#connection.socket.send(encoded);
|
|
43711
|
+
return true;
|
|
43712
|
+
} catch {
|
|
43713
|
+
return false;
|
|
43714
|
+
}
|
|
43185
43715
|
};
|
|
43186
43716
|
};
|
|
43187
43717
|
|
|
@@ -43242,7 +43772,7 @@ async function installDetectedAgentIntegrations(config2, installations, signal)
|
|
|
43242
43772
|
{
|
|
43243
43773
|
agentId: agent.id,
|
|
43244
43774
|
kind: AGENT_INSTALL_REQUEST_KIND,
|
|
43245
|
-
requestId: `automatic-integration-${
|
|
43775
|
+
requestId: `automatic-integration-${randomUUID8()}`
|
|
43246
43776
|
},
|
|
43247
43777
|
signal
|
|
43248
43778
|
);
|
|
@@ -43264,7 +43794,11 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer, opti
|
|
|
43264
43794
|
join18(stateDirectory, "sessions", `${createHash6("sha256").update(config2.channelId).digest("hex")}.sqlite`)
|
|
43265
43795
|
);
|
|
43266
43796
|
const operations = new DaemonOperationState();
|
|
43267
|
-
const
|
|
43797
|
+
const channelHash = createHash6("sha256").update(config2.channelId).digest("hex");
|
|
43798
|
+
const publisher = new DaemonSessionEventPublisher(
|
|
43799
|
+
new SessionEventOutbox(join18(stateDirectory, "events", `${channelHash}.sqlite`)),
|
|
43800
|
+
timer
|
|
43801
|
+
);
|
|
43268
43802
|
const activeTurns = new DaemonTurnRegistry(operations);
|
|
43269
43803
|
const recordSessionEvent = (sessionId, event) => {
|
|
43270
43804
|
publisher.publish(sessionId, activeTurns.recordEvent(event));
|