@moxt-ai/mobius 0.0.147 → 0.0.149

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/index.js CHANGED
@@ -21060,18 +21060,21 @@ var activeTurnMessageSchema = external_exports.discriminatedUnion("role", [
21060
21060
  activeTurnAssistantMessageSchema
21061
21061
  ]);
21062
21062
  var activeTurnSnapshotSchema = external_exports.strictObject({
21063
- activities: external_exports.array(activeTurnActivitySchema).readonly(),
21064
21063
  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
21064
  epoch: identifierStringSchema,
21065
+ hasOlder: external_exports.boolean(),
21070
21066
  interaction: external_exports.discriminatedUnion("kind", [sessionPermissionRequestedEventSchema, sessionElicitationRequestedEventSchema]).nullable(),
21071
21067
  messages: external_exports.array(activeTurnMessageSchema).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
21072
21068
  sequence: external_exports.number().int().nonnegative(),
21073
- state: external_exports.literal("running")
21074
- }).readonly();
21069
+ state: external_exports.literal("running"),
21070
+ truncated: external_exports.boolean()
21071
+ }).readonly().refine(
21072
+ (snapshot) => snapshot.messages.reduce(
21073
+ (total, message) => total + message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0),
21074
+ 0
21075
+ ) <= SESSION_HISTORY_CHARACTER_LIMIT,
21076
+ "Active Turn snapshot content is too large"
21077
+ );
21075
21078
  var identity = {
21076
21079
  ...envelope,
21077
21080
  kind: external_exports.literal(NATIVE_SESSION_REQUEST_KIND),
@@ -21215,27 +21218,14 @@ var encodeNativeSessionCancel = (value) => JSON.stringify(nativeSessionCancelSch
21215
21218
 
21216
21219
  // ../protocol/src/session-events.ts
21217
21220
  var SESSION_EVENT_KIND = "session.event";
21218
- var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
21219
21221
  var MAX_RECORDED_EVENT_LENGTH = 8 * 1024 * 1024;
21220
21222
  var eventEnvelopeSchema = external_exports.strictObject({
21221
21223
  kind: external_exports.literal(SESSION_EVENT_KIND),
21222
21224
  payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
21223
21225
  sessionId: identifierStringSchema
21224
21226
  }).readonly();
21225
- var committedEventSchema = external_exports.strictObject({
21226
- kind: external_exports.literal(SESSION_EVENT_COMMITTED_KIND),
21227
- payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
21228
- sessionId: identifierStringSchema
21229
- }).readonly();
21230
21227
  var SESSION_QUEUE_CHANGED_KIND = "session.queue.changed";
21231
21228
  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
21229
  function decode5(encoded, schema) {
21240
21230
  let value;
21241
21231
  try {
@@ -21265,8 +21255,6 @@ var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSche
21265
21255
  function decodeRecordedSessionEvent(encoded) {
21266
21256
  const kind = decodeMessageKind(encoded);
21267
21257
  switch (kind) {
21268
- case SESSION_TURN_UPDATED_KIND:
21269
- return decodeSessionTurnUpdatedEvent(encoded);
21270
21258
  case SESSION_QUEUE_CHANGED_KIND:
21271
21259
  return decode5(encoded, sessionQueueChangedSchema);
21272
21260
  case AGENT_ACTIVITY_KIND:
@@ -38731,6 +38719,28 @@ var DaemonInstallationObserver = class {
38731
38719
 
38732
38720
  // src/daemon-active-turn.ts
38733
38721
  import { randomUUID as randomUUID2 } from "node:crypto";
38722
+ function activeMessageCharacters(message) {
38723
+ return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
38724
+ }
38725
+ var ACTIVE_TURN_TEXT_CHUNK_LIMIT = Math.floor(SESSION_HISTORY_CHARACTER_LIMIT / 2);
38726
+ function boundedRecoveryMessages(messages) {
38727
+ const selected = [];
38728
+ let remainingCharacters = SESSION_HISTORY_CHARACTER_LIMIT;
38729
+ for (let index = messages.length - 1; index >= 0 && selected.length < SESSION_HISTORY_MESSAGE_LIMIT; index -= 1) {
38730
+ const message = messages[index];
38731
+ if (message === void 0) {
38732
+ break;
38733
+ }
38734
+ const characters = activeMessageCharacters(message);
38735
+ if (characters <= remainingCharacters) {
38736
+ selected.unshift(message);
38737
+ remainingCharacters -= characters;
38738
+ continue;
38739
+ }
38740
+ break;
38741
+ }
38742
+ return { hasOlder: selected.length !== messages.length, messages: selected };
38743
+ }
38734
38744
  var ActiveDaemonTurn = class {
38735
38745
  attemptId;
38736
38746
  command;
@@ -38738,9 +38748,7 @@ var ActiveDaemonTurn = class {
38738
38748
  #finished = Promise.withResolvers();
38739
38749
  #cancellationRequested = false;
38740
38750
  #dispatch;
38741
- #text = "";
38742
38751
  #activities = /* @__PURE__ */ new Map();
38743
- #content = /* @__PURE__ */ new Map();
38744
38752
  #timeline;
38745
38753
  #sequence = 0;
38746
38754
  #interaction = null;
@@ -38787,9 +38795,17 @@ var ActiveDaemonTurn = class {
38787
38795
  effectiveDisposition = () => this.#dispatch.kind === "promoted" ? SessionPromptDisposition.Steer : this.command.disposition;
38788
38796
  recordEvent = (event) => {
38789
38797
  if (event.kind === AGENT_MESSAGE_DELTA_KIND) {
38790
- this.#text += event.text;
38798
+ const sequence = this.advance();
38791
38799
  this.appendMessageText(event.messageId, event.text);
38792
- return this.updated();
38800
+ return {
38801
+ commandId: this.command.commandId,
38802
+ epoch: this.#epoch,
38803
+ kind: AGENT_MESSAGE_DELTA_KIND,
38804
+ messageId: event.messageId,
38805
+ sequence,
38806
+ sessionId: this.command.sessionId,
38807
+ text: event.text
38808
+ };
38793
38809
  }
38794
38810
  if (event.sessionId !== this.command.sessionId || "commandId" in event && event.commandId !== this.command.commandId) {
38795
38811
  return event;
@@ -38836,7 +38852,6 @@ var ActiveDaemonTurn = class {
38836
38852
  toolKind: previous?.toolKind ?? ""
38837
38853
  });
38838
38854
  } else if (event.kind === AGENT_CONTENT_KIND) {
38839
- this.#content.set(event.contentId, event.content);
38840
38855
  const target = this.#timeline.findLastIndex(
38841
38856
  (entry) => entry.kind === "message" && entry.sourceMessageId === event.messageId
38842
38857
  );
@@ -38862,7 +38877,7 @@ var ActiveDaemonTurn = class {
38862
38877
  this.#interaction = null;
38863
38878
  }
38864
38879
  if (event.kind === AGENT_ACTIVITY_KIND || event.kind === AGENT_ACTIVITY_NARRATION_KIND || event.kind === AGENT_CONTENT_KIND) {
38865
- return this.updated();
38880
+ this.advance();
38866
38881
  }
38867
38882
  return event;
38868
38883
  };
@@ -38871,7 +38886,7 @@ var ActiveDaemonTurn = class {
38871
38886
  while (remaining.length > 0) {
38872
38887
  const latest = this.#timeline.at(-1);
38873
38888
  if (latest?.kind === "message" && latest.sourceMessageId === messageId) {
38874
- const available = SESSION_HISTORY_CHARACTER_LIMIT - latest.text.length;
38889
+ const available = ACTIVE_TURN_TEXT_CHUNK_LIMIT - latest.text.length;
38875
38890
  if (available > 0) {
38876
38891
  this.#timeline = [
38877
38892
  ...this.#timeline.slice(0, -1),
@@ -38888,21 +38903,22 @@ var ActiveDaemonTurn = class {
38888
38903
  id: decodeIdentifier(randomUUID2()),
38889
38904
  kind: "message",
38890
38905
  sourceMessageId: messageId,
38891
- text: remaining.slice(0, SESSION_HISTORY_CHARACTER_LIMIT)
38906
+ text: remaining.slice(0, ACTIVE_TURN_TEXT_CHUNK_LIMIT)
38892
38907
  }
38893
38908
  ];
38894
- remaining = remaining.slice(SESSION_HISTORY_CHARACTER_LIMIT);
38909
+ remaining = remaining.slice(ACTIVE_TURN_TEXT_CHUNK_LIMIT);
38895
38910
  }
38896
38911
  }
38897
38912
  recordSteeringPrompt = (command) => {
38898
38913
  if (this.#dispatch.kind !== "running" || command.sessionId !== this.command.sessionId || command.targetCommandId !== this.command.commandId) {
38899
- return null;
38914
+ return false;
38900
38915
  }
38901
38916
  this.#timeline = [
38902
38917
  ...this.#timeline,
38903
38918
  { id: decodeIdentifier(command.commandId), images: command.images, kind: "user", text: command.prompt }
38904
38919
  ];
38905
- return this.updated();
38920
+ this.advance();
38921
+ return true;
38906
38922
  };
38907
38923
  timelineMessages() {
38908
38924
  return this.#timeline.flatMap((entry) => {
@@ -38924,32 +38940,39 @@ var ActiveDaemonTurn = class {
38924
38940
  return activity2 === void 0 ? [] : [{ activities: [activity2], content: [], id: entry.id, role: "assistant", text: "" }];
38925
38941
  });
38926
38942
  }
38927
- updated = () => {
38928
- this.#sequence += 1;
38929
- const turn = this.snapshot();
38930
- if (turn === null) {
38931
- throw new Error("Only a running turn can publish a snapshot");
38943
+ advance = () => {
38944
+ if (this.#dispatch.kind !== "running") {
38945
+ throw new Error("Only a running turn can advance its snapshot");
38932
38946
  }
38933
- return { kind: "session.turn.updated", sessionId: this.command.sessionId, turn };
38947
+ this.#sequence += 1;
38948
+ return this.#sequence;
38934
38949
  };
38935
38950
  snapshot = () => {
38936
38951
  if (this.#dispatch.kind !== "running") {
38937
38952
  return null;
38938
38953
  }
38939
- const completeMessages = this.timelineMessages();
38940
- const messages = completeMessages.slice(-SESSION_HISTORY_MESSAGE_LIMIT);
38954
+ const bounded2 = boundedRecoveryMessages(this.timelineMessages());
38941
38955
  return {
38942
- activities: [...this.#activities.values()].sort((left, right) => left.sequence - right.sequence),
38943
38956
  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
38957
  epoch: this.#epoch,
38958
+ hasOlder: bounded2.hasOlder,
38949
38959
  interaction: this.#interaction,
38950
- messages,
38960
+ messages: bounded2.messages,
38951
38961
  sequence: this.#sequence,
38952
- state: "running"
38962
+ state: "running",
38963
+ truncated: false
38964
+ };
38965
+ };
38966
+ recovery = () => {
38967
+ if (this.#dispatch.kind !== "running") {
38968
+ return null;
38969
+ }
38970
+ return {
38971
+ commandId: decodeIdentifier(this.command.commandId),
38972
+ epoch: this.#epoch,
38973
+ messages: this.timelineMessages(),
38974
+ state: "running",
38975
+ truncated: false
38953
38976
  };
38954
38977
  };
38955
38978
  matches = (cancellation) => cancellation.commandId === this.command.commandId && cancellation.sessionId === this.command.sessionId;
@@ -38975,6 +38998,7 @@ var ActiveDaemonTurn = class {
38975
38998
  };
38976
38999
 
38977
39000
  // src/daemon-turn-registry.ts
39001
+ var COMPLETED_TURN_RECOVERY_LIMIT = 32;
38978
39002
  var waitForTurnCompletion = (turn, waitSignal) => {
38979
39003
  waitSignal.throwIfAborted();
38980
39004
  return new Promise((resolve9, reject) => {
@@ -39001,6 +39025,7 @@ var waitForTurnCompletion = (turn, waitSignal) => {
39001
39025
  };
39002
39026
  var DaemonTurnRegistry = class {
39003
39027
  #turns = /* @__PURE__ */ new Map();
39028
+ #completed = /* @__PURE__ */ new Map();
39004
39029
  #operations;
39005
39030
  constructor(operations) {
39006
39031
  this.#operations = operations;
@@ -39012,7 +39037,22 @@ var DaemonTurnRegistry = class {
39012
39037
  };
39013
39038
  get = (commandId) => this.#turns.get(commandId);
39014
39039
  finish = (turn) => {
39040
+ const recovery = turn.recovery();
39015
39041
  this.#turns.delete(turn.command.commandId);
39042
+ if (recovery !== null) {
39043
+ this.#completed.delete(turn.command.sessionId);
39044
+ this.#completed.set(turn.command.sessionId, {
39045
+ command: turn.command,
39046
+ recovery: { ...recovery, state: "completed" }
39047
+ });
39048
+ while (this.#completed.size > COMPLETED_TURN_RECOVERY_LIMIT) {
39049
+ const oldestSessionId = this.#completed.keys().next().value;
39050
+ if (oldestSessionId === void 0) {
39051
+ break;
39052
+ }
39053
+ this.#completed.delete(oldestSessionId);
39054
+ }
39055
+ }
39016
39056
  turn.finish();
39017
39057
  };
39018
39058
  recordEvent = (event) => {
@@ -39033,7 +39073,7 @@ var DaemonTurnRegistry = class {
39033
39073
  };
39034
39074
  recordSteeringPrompt = (command) => {
39035
39075
  const target = this.#turns.get(command.targetCommandId);
39036
- return target?.recordSteeringPrompt(command) ?? null;
39076
+ return target?.recordSteeringPrompt(command) ?? false;
39037
39077
  };
39038
39078
  executionSnapshot = async (matches) => {
39039
39079
  const matching = [];
@@ -39064,12 +39104,30 @@ var DaemonTurnRegistry = class {
39064
39104
  }
39065
39105
  return null;
39066
39106
  };
39107
+ recovery = (matches) => {
39108
+ for (const turn of this.#turns.values()) {
39109
+ if (!matches(turn.command)) {
39110
+ continue;
39111
+ }
39112
+ const recovery = turn.recovery();
39113
+ if (recovery !== null) {
39114
+ return recovery;
39115
+ }
39116
+ }
39117
+ for (const completed of this.#completed.values()) {
39118
+ if (matches(completed.command)) {
39119
+ return completed.recovery;
39120
+ }
39121
+ }
39122
+ return null;
39123
+ };
39067
39124
  close = async () => {
39068
39125
  const turns = [...this.#turns.values()];
39069
39126
  for (const turn of turns) {
39070
39127
  turn.abortDaemon();
39071
39128
  }
39072
39129
  await Promise.all(turns.map((turn) => turn.completion));
39130
+ this.#completed.clear();
39073
39131
  };
39074
39132
  admitAndWait = async (turn, waitSignal, onQueued) => {
39075
39133
  const command = turn.command;
@@ -41377,10 +41435,10 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
41377
41435
  }
41378
41436
 
41379
41437
  // src/native-sessions/live-history-page.ts
41380
- function liveHistoryCursor(sessionId, endIndex) {
41381
- return Buffer.from(JSON.stringify({ endIndex, sessionId }), "utf8").toString("base64url");
41438
+ function encodeLiveHistoryCursor(cursor) {
41439
+ return Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
41382
41440
  }
41383
- function liveHistoryEndIndex(cursor, sessionId) {
41441
+ function decodeLiveHistoryCursor(cursor, sessionId) {
41384
41442
  try {
41385
41443
  if (!/^[A-Za-z0-9_-]{1,512}$/u.test(cursor)) {
41386
41444
  throw new Error("Invalid cursor alphabet");
@@ -41390,14 +41448,32 @@ function liveHistoryEndIndex(cursor, sessionId) {
41390
41448
  throw new Error("Invalid cursor shape");
41391
41449
  }
41392
41450
  const record2 = Object.fromEntries(Object.entries(value));
41393
- if (Object.keys(record2).sort().join(",") !== "endIndex,sessionId" || record2["sessionId"] !== sessionId || typeof record2["endIndex"] !== "number" || !Number.isSafeInteger(record2["endIndex"]) || record2["endIndex"] < 0) {
41451
+ const keys = Object.keys(record2).sort().join(",");
41452
+ const legacyNative = keys === "endIndex,sessionId";
41453
+ const kind = legacyNative ? "native" : record2["kind"];
41454
+ 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
41455
  throw new Error("Invalid cursor target");
41395
41456
  }
41396
- return record2["endIndex"];
41457
+ if (kind === "active") {
41458
+ if (keys !== "endIndex,epoch,kind,sessionId" || typeof record2["epoch"] !== "string") {
41459
+ throw new Error("Invalid active cursor target");
41460
+ }
41461
+ return { endIndex: record2["endIndex"], epoch: record2["epoch"], kind, sessionId };
41462
+ }
41463
+ if (keys !== "endIndex,kind,sessionId" && !legacyNative) {
41464
+ throw new Error("Invalid native cursor target");
41465
+ }
41466
+ return { endIndex: record2["endIndex"], kind, sessionId };
41397
41467
  } catch (cause) {
41398
41468
  throw new AcpExecutionError("The native Session history cursor is invalid", { cause }, "invalid_cursor");
41399
41469
  }
41400
41470
  }
41471
+ function activeHistoryCursor(sessionId, epoch, endIndex) {
41472
+ return encodeLiveHistoryCursor({ endIndex, epoch, kind: "active", sessionId });
41473
+ }
41474
+ function nativeHistoryCursor(sessionId, endIndex) {
41475
+ return encodeLiveHistoryCursor({ endIndex, kind: "native", sessionId });
41476
+ }
41401
41477
  function liveHistoryCoveredTurnRanges(history) {
41402
41478
  const ranges = [];
41403
41479
  let historyIndex = history.messages.length;
@@ -41418,139 +41494,180 @@ function liveHistoryCoveredTurnRanges(history) {
41418
41494
  function historyMessageCharacters(message) {
41419
41495
  return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
41420
41496
  }
41421
- function boundedActiveMessages(messages, messageLimit, characterLimit) {
41497
+ function isNativeHistoryImageMimeType(mimeType) {
41498
+ return mimeType === "image/png" || mimeType === "image/jpeg" || mimeType === "image/gif" || mimeType === "image/webp";
41499
+ }
41500
+ function selectMessagesBefore(messages, endIndex, messageLimit, characterLimit) {
41422
41501
  const selected = [];
41423
41502
  let remainingCharacters = characterLimit;
41424
- for (let index = messages.length - 1; index >= 0 && selected.length < messageLimit; index -= 1) {
41503
+ let startIndex = endIndex;
41504
+ for (let index = endIndex - 1; index >= 0 && selected.length < messageLimit; index -= 1) {
41425
41505
  const message = messages[index];
41426
41506
  if (message === void 0) {
41427
41507
  break;
41428
41508
  }
41429
41509
  const characters = historyMessageCharacters(message);
41430
- if (characters <= remainingCharacters) {
41431
- selected.unshift(message);
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;
41510
+ if (characters > remainingCharacters) {
41511
+ break;
41440
41512
  }
41441
- break;
41513
+ selected.unshift(message);
41514
+ remainingCharacters -= characters;
41515
+ startIndex = index;
41442
41516
  }
41443
- return {
41444
- characters: characterLimit - remainingCharacters,
41445
- messages: selected,
41446
- truncated: selected.length !== messages.length
41447
- };
41517
+ if (selected.length === 0 && endIndex > 0) {
41518
+ throw new AcpExecutionError(
41519
+ "A native Session history item exceeds the page budget",
41520
+ {},
41521
+ "history_item_too_large"
41522
+ );
41523
+ }
41524
+ return { characters: characterLimit - remainingCharacters, messages: selected, startIndex };
41448
41525
  }
41449
41526
  function nativeActiveMessage(message) {
41450
- return message.role === "user" ? { role: "user", text: message.text } : {
41451
- activities: message.activities,
41452
- content: message.content,
41453
- role: "assistant",
41454
- text: message.text
41455
- };
41527
+ if (message.role === "assistant") {
41528
+ return {
41529
+ activities: message.activities,
41530
+ content: message.content,
41531
+ role: "assistant",
41532
+ text: message.text
41533
+ };
41534
+ }
41535
+ const images = (message.images ?? []).flatMap((image) => {
41536
+ if (image.data.length < 4 || image.data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/u.test(image.data) || !isNativeHistoryImageMimeType(image.mimeType)) {
41537
+ return [];
41538
+ }
41539
+ return [{ data: image.data, mimeType: image.mimeType, name: image.name }];
41540
+ });
41541
+ return { ...images.length === 0 ? {} : { images }, role: "user", text: message.text };
41542
+ }
41543
+ function nativeHistoryCoversCompletedRecovery(history, recovery) {
41544
+ const root = recovery.messages.find((message) => message.role === "user" && message.id === recovery.commandId);
41545
+ if (root === void 0) {
41546
+ return false;
41547
+ }
41548
+ const rootIndex = history.messages.findLastIndex(
41549
+ (message) => message.role === "user" && message.text === root.text
41550
+ );
41551
+ if (rootIndex < 0) {
41552
+ return false;
41553
+ }
41554
+ const nativeAssistant = history.messages.slice(rootIndex + 1).filter((message) => message.role === "assistant");
41555
+ if (nativeAssistant.length === 0) {
41556
+ return false;
41557
+ }
41558
+ const recoveryAssistant = recovery.messages.filter((message) => message.role === "assistant");
41559
+ const recoveryText = recoveryAssistant.map((message) => message.text).join("");
41560
+ const nativeText = nativeAssistant.map((message) => message.text).join("");
41561
+ if (recoveryText.length > 0 && !nativeText.includes(recoveryText)) {
41562
+ return false;
41563
+ }
41564
+ const nativeContent = new Set(
41565
+ nativeAssistant.flatMap((message) => message.content).map((content) => JSON.stringify(content))
41566
+ );
41567
+ return recoveryAssistant.flatMap((message) => message.content).every((content) => nativeContent.has(JSON.stringify(content)));
41456
41568
  }
41457
- function paginateAcpSessionHistory(history, sessionId, cursor, limit) {
41569
+ function historyBeforeActiveTurn(history, activeTurn) {
41458
41570
  if (history.status === "unavailable") {
41459
- if (cursor !== null) {
41460
- throw new AcpExecutionError("Unavailable native Session history has no cursor", {}, "invalid_cursor");
41461
- }
41462
- return { cause: history.cause, nextCursor: null, status: "unavailable" };
41571
+ return history;
41463
41572
  }
41464
- const endIndex = cursor === null ? history.messages.length : liveHistoryEndIndex(cursor, sessionId);
41573
+ const activeRoot = activeTurn.messages.find(
41574
+ (message) => message.role === "user" && message.id === activeTurn.commandId
41575
+ );
41576
+ 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;
41577
+ const activeUserIndex = matchingActiveUserIndex >= 0 ? matchingActiveUserIndex : liveHistoryCoveredTurnRanges(history).find((range) => range.commandId === activeTurn.commandId)?.userIndex ?? -1;
41578
+ if (activeUserIndex < 0) {
41579
+ return history;
41580
+ }
41581
+ return {
41582
+ ...history,
41583
+ coveredCommandIds: history.coveredCommandIds.filter((id) => id !== activeTurn.commandId),
41584
+ coveredMessageIds: history.coveredMessageIds.filter(
41585
+ (id) => id !== `${activeTurn.commandId}:user` && id !== `${activeTurn.commandId}:agent`
41586
+ ),
41587
+ messages: history.messages.slice(0, activeUserIndex)
41588
+ };
41589
+ }
41590
+ function paginateAvailableNativeHistory(history, sessionId, endIndex, limit, characterLimit) {
41465
41591
  if (endIndex > history.messages.length) {
41466
41592
  throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
41467
41593
  }
41468
- const startIndex = Math.max(0, endIndex - limit);
41594
+ const selected = selectMessagesBefore(history.messages, endIndex, limit, characterLimit);
41469
41595
  const coveredMessageIds = new Set(history.coveredMessageIds);
41470
41596
  const ranges = liveHistoryCoveredTurnRanges(history);
41471
41597
  return {
41472
- coveredCommandIds: ranges.filter((range) => range.userIndex >= startIndex && range.assistantEndIndex <= endIndex).map((range) => range.commandId),
41598
+ coveredCommandIds: ranges.filter((range) => range.userIndex >= selected.startIndex && range.assistantEndIndex <= endIndex).map((range) => range.commandId),
41473
41599
  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`] : []
41600
+ ...range.userIndex >= selected.startIndex && range.userIndex < endIndex && coveredMessageIds.has(`${range.commandId}:user`) ? [`${range.commandId}:user`] : [],
41601
+ ...range.assistantStartIndex >= selected.startIndex && range.assistantEndIndex <= endIndex && coveredMessageIds.has(`${range.commandId}:agent`) ? [`${range.commandId}:agent`] : []
41476
41602
  ]),
41477
- messages: history.messages.slice(startIndex, endIndex),
41478
- nextCursor: startIndex > 0 ? liveHistoryCursor(sessionId, startIndex) : null,
41603
+ messages: selected.messages,
41604
+ nextCursor: selected.startIndex > 0 ? nativeHistoryCursor(sessionId, selected.startIndex) : null,
41479
41605
  status: "available",
41480
41606
  truncated: history.truncated
41481
41607
  };
41482
41608
  }
41483
- function paginateLiveSessionHistory(history, activeTurn, sessionId, cursor, limit) {
41484
- if (activeTurn === null || cursor !== null) {
41485
- return paginateAcpSessionHistory(history, sessionId, cursor, limit);
41609
+ function paginateNativeHistory(history, sessionId, cursor, limit) {
41610
+ if (cursor?.kind === "active") {
41611
+ throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
41486
41612
  }
41487
41613
  if (history.status === "unavailable") {
41488
- const bounded3 = boundedActiveMessages(
41489
- activeTurn.messages.map(nativeActiveMessage),
41490
- limit,
41491
- SESSION_HISTORY_CHARACTER_LIMIT
41492
- );
41493
- return {
41494
- coveredCommandIds: [],
41495
- coveredMessageIds: [],
41496
- messages: bounded3.messages,
41497
- nextCursor: null,
41498
- status: "available",
41499
- truncated: activeTurn.truncated || bounded3.truncated
41500
- };
41614
+ if (cursor !== null) {
41615
+ throw new AcpExecutionError("Unavailable native Session history has no cursor", {}, "invalid_cursor");
41616
+ }
41617
+ return { cause: history.cause, nextCursor: null, status: "unavailable" };
41501
41618
  }
41502
- const activeRoot = activeTurn.messages.find(
41503
- (message) => message.role === "user" && message.id === activeTurn.commandId
41619
+ return paginateAvailableNativeHistory(
41620
+ history,
41621
+ sessionId,
41622
+ cursor?.endIndex ?? history.messages.length,
41623
+ limit,
41624
+ SESSION_HISTORY_CHARACTER_LIMIT
41504
41625
  );
41505
- const coveredActiveRoot = history.coveredCommandIds.includes(activeTurn.commandId);
41506
- const matchingActiveUserIndex = coveredActiveRoot ? history.messages.findLastIndex(
41507
- (message) => message.role === "user" && message.text === (activeRoot?.text ?? activeTurn.prompt)
41508
- ) : -1;
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;
41626
+ }
41627
+ function paginateActiveTurn(history, activeTurn, sessionId, endIndex, limit) {
41628
+ if (endIndex > activeTurn.messages.length) {
41629
+ throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
41539
41630
  }
41540
- const page = historicalMessageCount === 0 ? {
41541
- coveredCommandIds: [],
41542
- coveredMessageIds: [],
41543
- messages: [],
41544
- nextCursor: history.messages.length === 0 ? null : liveHistoryCursor(sessionId, history.messages.length),
41545
- status: "available",
41546
- truncated: history.truncated
41547
- } : paginateAcpSessionHistory(history, sessionId, null, historicalMessageCount);
41631
+ const activeMessages = activeTurn.messages.map(nativeActiveMessage);
41632
+ const active = selectMessagesBefore(activeMessages, endIndex, limit, SESSION_HISTORY_CHARACTER_LIMIT);
41633
+ const historicalLimit = limit - active.messages.length;
41634
+ const historicalCharacterLimit = SESSION_HISTORY_CHARACTER_LIMIT - active.characters;
41635
+ const pendingHistoricalCursor = history.status === "available" && history.messages.length > 0 ? nativeHistoryCursor(sessionId, history.messages.length) : null;
41636
+ const latestHistoricalMessage = history.status === "available" ? history.messages.at(-1) : void 0;
41637
+ const historicalPageFits = latestHistoricalMessage === void 0 || historyMessageCharacters(latestHistoricalMessage) <= historicalCharacterLimit;
41638
+ const historical = active.startIndex === 0 && history.status === "available" && historicalLimit > 0 && historicalPageFits ? paginateAvailableNativeHistory(
41639
+ history,
41640
+ sessionId,
41641
+ history.messages.length,
41642
+ historicalLimit,
41643
+ historicalCharacterLimit
41644
+ ) : null;
41548
41645
  return {
41549
- ...page,
41550
- messages: [...page.messages, ...bounded2.messages],
41551
- truncated: page.truncated || activeTurn.truncated || bounded2.truncated
41646
+ coveredCommandIds: historical?.coveredCommandIds ?? [],
41647
+ coveredMessageIds: [
41648
+ ...historical?.coveredMessageIds ?? [],
41649
+ ...active.startIndex === 0 ? [`${activeTurn.commandId}:user`, `${activeTurn.commandId}:agent`] : []
41650
+ ],
41651
+ messages: [...historical?.messages ?? [], ...active.messages],
41652
+ nextCursor: active.startIndex > 0 ? activeHistoryCursor(sessionId, activeTurn.epoch, active.startIndex) : historical === null ? pendingHistoricalCursor : historical.nextCursor,
41653
+ status: "available",
41654
+ truncated: activeTurn.truncated || (historical?.truncated ?? false)
41552
41655
  };
41553
41656
  }
41657
+ function paginateLiveSessionHistory(history, activeTurn, sessionId, encodedCursor, limit) {
41658
+ const cursor = encodedCursor === null ? null : decodeLiveHistoryCursor(encodedCursor, sessionId);
41659
+ if (activeTurn === null || activeTurn.state === "completed" && history.status === "available" && nativeHistoryCoversCompletedRecovery(history, activeTurn)) {
41660
+ return paginateNativeHistory(history, sessionId, cursor, limit);
41661
+ }
41662
+ const historical = historyBeforeActiveTurn(history, activeTurn);
41663
+ if (cursor?.kind === "native") {
41664
+ return paginateNativeHistory(historical, sessionId, cursor, limit);
41665
+ }
41666
+ if (cursor !== null && cursor.epoch !== activeTurn.epoch) {
41667
+ throw new AcpExecutionError("The active Turn history cursor is stale", {}, "stale_cursor");
41668
+ }
41669
+ return paginateActiveTurn(historical, activeTurn, sessionId, cursor?.endIndex ?? activeTurn.messages.length, limit);
41670
+ }
41554
41671
  function mergeLiveSessionHistory(history, activeTurn, sessionId) {
41555
41672
  const page = paginateLiveSessionHistory(history, activeTurn, sessionId, null, 1e3);
41556
41673
  if (page.status === "unavailable") {
@@ -41561,7 +41678,7 @@ function mergeLiveSessionHistory(history, activeTurn, sessionId) {
41561
41678
  coveredMessageIds: page.coveredMessageIds,
41562
41679
  messages: page.messages,
41563
41680
  status: "available",
41564
- truncated: page.truncated
41681
+ truncated: page.truncated || page.nextCursor !== null
41565
41682
  };
41566
41683
  }
41567
41684
 
@@ -42080,15 +42197,13 @@ async function executePrompt({
42080
42197
  });
42081
42198
  operations.transitionExecution(command.commandId, "running");
42082
42199
  if (availability.disposition === SessionPromptDisposition.Steer) {
42083
- const updated = recordSteeringPrompt();
42084
- if (updated === null) {
42200
+ if (!recordSteeringPrompt()) {
42085
42201
  throw new AcpExecutionError(
42086
42202
  "The steering target is unavailable",
42087
42203
  {},
42088
42204
  "prompt_queue_target_unavailable"
42089
42205
  );
42090
42206
  }
42091
- publisher.publish(command.sessionId, updated);
42092
42207
  }
42093
42208
  const stream = activateAttempt();
42094
42209
  publisher.publish(command.sessionId, {
@@ -42476,7 +42591,7 @@ function createDaemonCommandHandler({
42476
42591
  resolveEnvironment: resolveAgentCatalogEnvironment
42477
42592
  });
42478
42593
  const queueChanged = (sessionId) => publisher.publish(sessionId, { kind: "session.queue.changed", sessionId });
42479
- const activeTurnSnapshot = (sessionId) => activeTurns.snapshot((command) => command.sessionId === sessionId);
42594
+ const activeTurnRecovery = (sessionId) => activeTurns.recovery((command) => command.sessionId === sessionId);
42480
42595
  const nativeRequestHandler = createNativeSessionRequestHandler({
42481
42596
  audit,
42482
42597
  diagnostics,
@@ -42497,7 +42612,7 @@ function createDaemonCommandHandler({
42497
42612
  directories,
42498
42613
  audit,
42499
42614
  sessions,
42500
- activeTurnSnapshot,
42615
+ activeTurnRecovery,
42501
42616
  signal
42502
42617
  );
42503
42618
  return;
@@ -42511,7 +42626,7 @@ function createDaemonCommandHandler({
42511
42626
  directories,
42512
42627
  audit,
42513
42628
  sessions,
42514
- activeTurnSnapshot,
42629
+ activeTurnRecovery,
42515
42630
  signal
42516
42631
  );
42517
42632
  return;