@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/runtime.js CHANGED
@@ -21034,18 +21034,21 @@ var activeTurnMessageSchema = external_exports.discriminatedUnion("role", [
21034
21034
  activeTurnAssistantMessageSchema
21035
21035
  ]);
21036
21036
  var activeTurnSnapshotSchema = external_exports.strictObject({
21037
- activities: external_exports.array(activeTurnActivitySchema).readonly(),
21038
21037
  commandId: identifierStringSchema,
21039
- content: external_exports.array(displayContentSchema).readonly(),
21040
- prompt: external_exports.string().max(1e5),
21041
- text: external_exports.string(),
21042
- truncated: external_exports.boolean(),
21043
21038
  epoch: identifierStringSchema,
21039
+ hasOlder: external_exports.boolean(),
21044
21040
  interaction: external_exports.discriminatedUnion("kind", [sessionPermissionRequestedEventSchema, sessionElicitationRequestedEventSchema]).nullable(),
21045
21041
  messages: external_exports.array(activeTurnMessageSchema).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
21046
21042
  sequence: external_exports.number().int().nonnegative(),
21047
- state: external_exports.literal("running")
21048
- }).readonly();
21043
+ state: external_exports.literal("running"),
21044
+ truncated: external_exports.boolean()
21045
+ }).readonly().refine(
21046
+ (snapshot) => snapshot.messages.reduce(
21047
+ (total, message) => total + message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0),
21048
+ 0
21049
+ ) <= SESSION_HISTORY_CHARACTER_LIMIT,
21050
+ "Active Turn snapshot content is too large"
21051
+ );
21049
21052
  var identity = {
21050
21053
  ...envelope,
21051
21054
  kind: external_exports.literal(NATIVE_SESSION_REQUEST_KIND),
@@ -21189,27 +21192,14 @@ var encodeNativeSessionCancel = (value) => JSON.stringify(nativeSessionCancelSch
21189
21192
 
21190
21193
  // ../protocol/src/session-events.ts
21191
21194
  var SESSION_EVENT_KIND = "session.event";
21192
- var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
21193
21195
  var MAX_RECORDED_EVENT_LENGTH = 8 * 1024 * 1024;
21194
21196
  var eventEnvelopeSchema = external_exports.strictObject({
21195
21197
  kind: external_exports.literal(SESSION_EVENT_KIND),
21196
21198
  payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
21197
21199
  sessionId: identifierStringSchema
21198
21200
  }).readonly();
21199
- var committedEventSchema = external_exports.strictObject({
21200
- kind: external_exports.literal(SESSION_EVENT_COMMITTED_KIND),
21201
- payload: external_exports.string().min(2).max(MAX_RECORDED_EVENT_LENGTH),
21202
- sessionId: identifierStringSchema
21203
- }).readonly();
21204
21201
  var SESSION_QUEUE_CHANGED_KIND = "session.queue.changed";
21205
21202
  var sessionQueueChangedSchema = external_exports.strictObject({ kind: external_exports.literal(SESSION_QUEUE_CHANGED_KIND), sessionId: identifierStringSchema }).readonly();
21206
- var SESSION_TURN_UPDATED_KIND = "session.turn.updated";
21207
- var sessionTurnUpdatedSchema = external_exports.strictObject({
21208
- kind: external_exports.literal(SESSION_TURN_UPDATED_KIND),
21209
- sessionId: identifierStringSchema,
21210
- turn: activeTurnSnapshotSchema
21211
- }).readonly();
21212
- var decodeSessionTurnUpdatedEvent = (encoded) => decode5(encoded, sessionTurnUpdatedSchema);
21213
21203
  function decode5(encoded, schema) {
21214
21204
  let value;
21215
21205
  try {
@@ -21239,8 +21229,6 @@ var encodeSessionEventEnvelope = (message) => encode4(message, eventEnvelopeSche
21239
21229
  function decodeRecordedSessionEvent(encoded) {
21240
21230
  const kind = decodeMessageKind(encoded);
21241
21231
  switch (kind) {
21242
- case SESSION_TURN_UPDATED_KIND:
21243
- return decodeSessionTurnUpdatedEvent(encoded);
21244
21232
  case SESSION_QUEUE_CHANGED_KIND:
21245
21233
  return decode5(encoded, sessionQueueChangedSchema);
21246
21234
  case AGENT_ACTIVITY_KIND:
@@ -37853,6 +37841,28 @@ var DaemonInstallationObserver = class {
37853
37841
 
37854
37842
  // src/daemon-active-turn.ts
37855
37843
  import { randomUUID } from "node:crypto";
37844
+ function activeMessageCharacters(message) {
37845
+ return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
37846
+ }
37847
+ var ACTIVE_TURN_TEXT_CHUNK_LIMIT = Math.floor(SESSION_HISTORY_CHARACTER_LIMIT / 2);
37848
+ function boundedRecoveryMessages(messages) {
37849
+ const selected = [];
37850
+ let remainingCharacters = SESSION_HISTORY_CHARACTER_LIMIT;
37851
+ for (let index = messages.length - 1; index >= 0 && selected.length < SESSION_HISTORY_MESSAGE_LIMIT; index -= 1) {
37852
+ const message = messages[index];
37853
+ if (message === void 0) {
37854
+ break;
37855
+ }
37856
+ const characters = activeMessageCharacters(message);
37857
+ if (characters <= remainingCharacters) {
37858
+ selected.unshift(message);
37859
+ remainingCharacters -= characters;
37860
+ continue;
37861
+ }
37862
+ break;
37863
+ }
37864
+ return { hasOlder: selected.length !== messages.length, messages: selected };
37865
+ }
37856
37866
  var ActiveDaemonTurn = class {
37857
37867
  attemptId;
37858
37868
  command;
@@ -37860,9 +37870,7 @@ var ActiveDaemonTurn = class {
37860
37870
  #finished = Promise.withResolvers();
37861
37871
  #cancellationRequested = false;
37862
37872
  #dispatch;
37863
- #text = "";
37864
37873
  #activities = /* @__PURE__ */ new Map();
37865
- #content = /* @__PURE__ */ new Map();
37866
37874
  #timeline;
37867
37875
  #sequence = 0;
37868
37876
  #interaction = null;
@@ -37909,9 +37917,17 @@ var ActiveDaemonTurn = class {
37909
37917
  effectiveDisposition = () => this.#dispatch.kind === "promoted" ? SessionPromptDisposition.Steer : this.command.disposition;
37910
37918
  recordEvent = (event) => {
37911
37919
  if (event.kind === AGENT_MESSAGE_DELTA_KIND) {
37912
- this.#text += event.text;
37920
+ const sequence = this.advance();
37913
37921
  this.appendMessageText(event.messageId, event.text);
37914
- return this.updated();
37922
+ return {
37923
+ commandId: this.command.commandId,
37924
+ epoch: this.#epoch,
37925
+ kind: AGENT_MESSAGE_DELTA_KIND,
37926
+ messageId: event.messageId,
37927
+ sequence,
37928
+ sessionId: this.command.sessionId,
37929
+ text: event.text
37930
+ };
37915
37931
  }
37916
37932
  if (event.sessionId !== this.command.sessionId || "commandId" in event && event.commandId !== this.command.commandId) {
37917
37933
  return event;
@@ -37958,7 +37974,6 @@ var ActiveDaemonTurn = class {
37958
37974
  toolKind: previous?.toolKind ?? ""
37959
37975
  });
37960
37976
  } else if (event.kind === AGENT_CONTENT_KIND) {
37961
- this.#content.set(event.contentId, event.content);
37962
37977
  const target = this.#timeline.findLastIndex(
37963
37978
  (entry) => entry.kind === "message" && entry.sourceMessageId === event.messageId
37964
37979
  );
@@ -37984,7 +37999,7 @@ var ActiveDaemonTurn = class {
37984
37999
  this.#interaction = null;
37985
38000
  }
37986
38001
  if (event.kind === AGENT_ACTIVITY_KIND || event.kind === AGENT_ACTIVITY_NARRATION_KIND || event.kind === AGENT_CONTENT_KIND) {
37987
- return this.updated();
38002
+ this.advance();
37988
38003
  }
37989
38004
  return event;
37990
38005
  };
@@ -37993,7 +38008,7 @@ var ActiveDaemonTurn = class {
37993
38008
  while (remaining.length > 0) {
37994
38009
  const latest = this.#timeline.at(-1);
37995
38010
  if (latest?.kind === "message" && latest.sourceMessageId === messageId) {
37996
- const available = SESSION_HISTORY_CHARACTER_LIMIT - latest.text.length;
38011
+ const available = ACTIVE_TURN_TEXT_CHUNK_LIMIT - latest.text.length;
37997
38012
  if (available > 0) {
37998
38013
  this.#timeline = [
37999
38014
  ...this.#timeline.slice(0, -1),
@@ -38010,21 +38025,22 @@ var ActiveDaemonTurn = class {
38010
38025
  id: decodeIdentifier(randomUUID()),
38011
38026
  kind: "message",
38012
38027
  sourceMessageId: messageId,
38013
- text: remaining.slice(0, SESSION_HISTORY_CHARACTER_LIMIT)
38028
+ text: remaining.slice(0, ACTIVE_TURN_TEXT_CHUNK_LIMIT)
38014
38029
  }
38015
38030
  ];
38016
- remaining = remaining.slice(SESSION_HISTORY_CHARACTER_LIMIT);
38031
+ remaining = remaining.slice(ACTIVE_TURN_TEXT_CHUNK_LIMIT);
38017
38032
  }
38018
38033
  }
38019
38034
  recordSteeringPrompt = (command) => {
38020
38035
  if (this.#dispatch.kind !== "running" || command.sessionId !== this.command.sessionId || command.targetCommandId !== this.command.commandId) {
38021
- return null;
38036
+ return false;
38022
38037
  }
38023
38038
  this.#timeline = [
38024
38039
  ...this.#timeline,
38025
38040
  { id: decodeIdentifier(command.commandId), images: command.images, kind: "user", text: command.prompt }
38026
38041
  ];
38027
- return this.updated();
38042
+ this.advance();
38043
+ return true;
38028
38044
  };
38029
38045
  timelineMessages() {
38030
38046
  return this.#timeline.flatMap((entry) => {
@@ -38046,32 +38062,39 @@ var ActiveDaemonTurn = class {
38046
38062
  return activity2 === void 0 ? [] : [{ activities: [activity2], content: [], id: entry.id, role: "assistant", text: "" }];
38047
38063
  });
38048
38064
  }
38049
- updated = () => {
38050
- this.#sequence += 1;
38051
- const turn = this.snapshot();
38052
- if (turn === null) {
38053
- throw new Error("Only a running turn can publish a snapshot");
38065
+ advance = () => {
38066
+ if (this.#dispatch.kind !== "running") {
38067
+ throw new Error("Only a running turn can advance its snapshot");
38054
38068
  }
38055
- return { kind: "session.turn.updated", sessionId: this.command.sessionId, turn };
38069
+ this.#sequence += 1;
38070
+ return this.#sequence;
38056
38071
  };
38057
38072
  snapshot = () => {
38058
38073
  if (this.#dispatch.kind !== "running") {
38059
38074
  return null;
38060
38075
  }
38061
- const completeMessages = this.timelineMessages();
38062
- const messages = completeMessages.slice(-SESSION_HISTORY_MESSAGE_LIMIT);
38076
+ const bounded2 = boundedRecoveryMessages(this.timelineMessages());
38063
38077
  return {
38064
- activities: [...this.#activities.values()].sort((left, right) => left.sequence - right.sequence),
38065
38078
  commandId: decodeIdentifier(this.command.commandId),
38066
- content: [...this.#content.values()],
38067
- prompt: this.command.prompt,
38068
- text: this.#text,
38069
- truncated: messages.length !== completeMessages.length,
38070
38079
  epoch: this.#epoch,
38080
+ hasOlder: bounded2.hasOlder,
38071
38081
  interaction: this.#interaction,
38072
- messages,
38082
+ messages: bounded2.messages,
38073
38083
  sequence: this.#sequence,
38074
- state: "running"
38084
+ state: "running",
38085
+ truncated: false
38086
+ };
38087
+ };
38088
+ recovery = () => {
38089
+ if (this.#dispatch.kind !== "running") {
38090
+ return null;
38091
+ }
38092
+ return {
38093
+ commandId: decodeIdentifier(this.command.commandId),
38094
+ epoch: this.#epoch,
38095
+ messages: this.timelineMessages(),
38096
+ state: "running",
38097
+ truncated: false
38075
38098
  };
38076
38099
  };
38077
38100
  matches = (cancellation) => cancellation.commandId === this.command.commandId && cancellation.sessionId === this.command.sessionId;
@@ -38097,6 +38120,7 @@ var ActiveDaemonTurn = class {
38097
38120
  };
38098
38121
 
38099
38122
  // src/daemon-turn-registry.ts
38123
+ var COMPLETED_TURN_RECOVERY_LIMIT = 32;
38100
38124
  var waitForTurnCompletion = (turn, waitSignal) => {
38101
38125
  waitSignal.throwIfAborted();
38102
38126
  return new Promise((resolve9, reject) => {
@@ -38123,6 +38147,7 @@ var waitForTurnCompletion = (turn, waitSignal) => {
38123
38147
  };
38124
38148
  var DaemonTurnRegistry = class {
38125
38149
  #turns = /* @__PURE__ */ new Map();
38150
+ #completed = /* @__PURE__ */ new Map();
38126
38151
  #operations;
38127
38152
  constructor(operations) {
38128
38153
  this.#operations = operations;
@@ -38134,7 +38159,22 @@ var DaemonTurnRegistry = class {
38134
38159
  };
38135
38160
  get = (commandId) => this.#turns.get(commandId);
38136
38161
  finish = (turn) => {
38162
+ const recovery = turn.recovery();
38137
38163
  this.#turns.delete(turn.command.commandId);
38164
+ if (recovery !== null) {
38165
+ this.#completed.delete(turn.command.sessionId);
38166
+ this.#completed.set(turn.command.sessionId, {
38167
+ command: turn.command,
38168
+ recovery: { ...recovery, state: "completed" }
38169
+ });
38170
+ while (this.#completed.size > COMPLETED_TURN_RECOVERY_LIMIT) {
38171
+ const oldestSessionId = this.#completed.keys().next().value;
38172
+ if (oldestSessionId === void 0) {
38173
+ break;
38174
+ }
38175
+ this.#completed.delete(oldestSessionId);
38176
+ }
38177
+ }
38138
38178
  turn.finish();
38139
38179
  };
38140
38180
  recordEvent = (event) => {
@@ -38155,7 +38195,7 @@ var DaemonTurnRegistry = class {
38155
38195
  };
38156
38196
  recordSteeringPrompt = (command) => {
38157
38197
  const target = this.#turns.get(command.targetCommandId);
38158
- return target?.recordSteeringPrompt(command) ?? null;
38198
+ return target?.recordSteeringPrompt(command) ?? false;
38159
38199
  };
38160
38200
  executionSnapshot = async (matches) => {
38161
38201
  const matching = [];
@@ -38186,12 +38226,30 @@ var DaemonTurnRegistry = class {
38186
38226
  }
38187
38227
  return null;
38188
38228
  };
38229
+ recovery = (matches) => {
38230
+ for (const turn of this.#turns.values()) {
38231
+ if (!matches(turn.command)) {
38232
+ continue;
38233
+ }
38234
+ const recovery = turn.recovery();
38235
+ if (recovery !== null) {
38236
+ return recovery;
38237
+ }
38238
+ }
38239
+ for (const completed of this.#completed.values()) {
38240
+ if (matches(completed.command)) {
38241
+ return completed.recovery;
38242
+ }
38243
+ }
38244
+ return null;
38245
+ };
38189
38246
  close = async () => {
38190
38247
  const turns = [...this.#turns.values()];
38191
38248
  for (const turn of turns) {
38192
38249
  turn.abortDaemon();
38193
38250
  }
38194
38251
  await Promise.all(turns.map((turn) => turn.completion));
38252
+ this.#completed.clear();
38195
38253
  };
38196
38254
  admitAndWait = async (turn, waitSignal, onQueued) => {
38197
38255
  const command = turn.command;
@@ -40499,10 +40557,10 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
40499
40557
  }
40500
40558
 
40501
40559
  // src/native-sessions/live-history-page.ts
40502
- function liveHistoryCursor(sessionId, endIndex) {
40503
- return Buffer.from(JSON.stringify({ endIndex, sessionId }), "utf8").toString("base64url");
40560
+ function encodeLiveHistoryCursor(cursor) {
40561
+ return Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
40504
40562
  }
40505
- function liveHistoryEndIndex(cursor, sessionId) {
40563
+ function decodeLiveHistoryCursor(cursor, sessionId) {
40506
40564
  try {
40507
40565
  if (!/^[A-Za-z0-9_-]{1,512}$/u.test(cursor)) {
40508
40566
  throw new Error("Invalid cursor alphabet");
@@ -40512,14 +40570,32 @@ function liveHistoryEndIndex(cursor, sessionId) {
40512
40570
  throw new Error("Invalid cursor shape");
40513
40571
  }
40514
40572
  const record2 = Object.fromEntries(Object.entries(value));
40515
- if (Object.keys(record2).sort().join(",") !== "endIndex,sessionId" || record2["sessionId"] !== sessionId || typeof record2["endIndex"] !== "number" || !Number.isSafeInteger(record2["endIndex"]) || record2["endIndex"] < 0) {
40573
+ const keys = Object.keys(record2).sort().join(",");
40574
+ const legacyNative = keys === "endIndex,sessionId";
40575
+ const kind = legacyNative ? "native" : record2["kind"];
40576
+ if (keys !== "endIndex,kind,sessionId" && keys !== "endIndex,epoch,kind,sessionId" && !legacyNative || record2["sessionId"] !== sessionId || kind !== "active" && kind !== "native" || typeof record2["endIndex"] !== "number" || !Number.isSafeInteger(record2["endIndex"]) || record2["endIndex"] < 0) {
40516
40577
  throw new Error("Invalid cursor target");
40517
40578
  }
40518
- return record2["endIndex"];
40579
+ if (kind === "active") {
40580
+ if (keys !== "endIndex,epoch,kind,sessionId" || typeof record2["epoch"] !== "string") {
40581
+ throw new Error("Invalid active cursor target");
40582
+ }
40583
+ return { endIndex: record2["endIndex"], epoch: record2["epoch"], kind, sessionId };
40584
+ }
40585
+ if (keys !== "endIndex,kind,sessionId" && !legacyNative) {
40586
+ throw new Error("Invalid native cursor target");
40587
+ }
40588
+ return { endIndex: record2["endIndex"], kind, sessionId };
40519
40589
  } catch (cause) {
40520
40590
  throw new AcpExecutionError("The native Session history cursor is invalid", { cause }, "invalid_cursor");
40521
40591
  }
40522
40592
  }
40593
+ function activeHistoryCursor(sessionId, epoch, endIndex) {
40594
+ return encodeLiveHistoryCursor({ endIndex, epoch, kind: "active", sessionId });
40595
+ }
40596
+ function nativeHistoryCursor(sessionId, endIndex) {
40597
+ return encodeLiveHistoryCursor({ endIndex, kind: "native", sessionId });
40598
+ }
40523
40599
  function liveHistoryCoveredTurnRanges(history) {
40524
40600
  const ranges = [];
40525
40601
  let historyIndex = history.messages.length;
@@ -40540,139 +40616,180 @@ function liveHistoryCoveredTurnRanges(history) {
40540
40616
  function historyMessageCharacters(message) {
40541
40617
  return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
40542
40618
  }
40543
- function boundedActiveMessages(messages, messageLimit, characterLimit) {
40619
+ function isNativeHistoryImageMimeType(mimeType) {
40620
+ return mimeType === "image/png" || mimeType === "image/jpeg" || mimeType === "image/gif" || mimeType === "image/webp";
40621
+ }
40622
+ function selectMessagesBefore(messages, endIndex, messageLimit, characterLimit) {
40544
40623
  const selected = [];
40545
40624
  let remainingCharacters = characterLimit;
40546
- for (let index = messages.length - 1; index >= 0 && selected.length < messageLimit; index -= 1) {
40625
+ let startIndex = endIndex;
40626
+ for (let index = endIndex - 1; index >= 0 && selected.length < messageLimit; index -= 1) {
40547
40627
  const message = messages[index];
40548
40628
  if (message === void 0) {
40549
40629
  break;
40550
40630
  }
40551
40631
  const characters = historyMessageCharacters(message);
40552
- if (characters <= remainingCharacters) {
40553
- selected.unshift(message);
40554
- remainingCharacters -= characters;
40555
- continue;
40556
- }
40557
- const structuredCharacters = characters - message.text.length;
40558
- if (selected.length === 0 && structuredCharacters <= remainingCharacters) {
40559
- const textCharacters = remainingCharacters - structuredCharacters;
40560
- selected.unshift({ ...message, text: textCharacters === 0 ? "" : message.text.slice(-textCharacters) });
40561
- remainingCharacters = 0;
40632
+ if (characters > remainingCharacters) {
40633
+ break;
40562
40634
  }
40563
- break;
40635
+ selected.unshift(message);
40636
+ remainingCharacters -= characters;
40637
+ startIndex = index;
40564
40638
  }
40565
- return {
40566
- characters: characterLimit - remainingCharacters,
40567
- messages: selected,
40568
- truncated: selected.length !== messages.length
40569
- };
40639
+ if (selected.length === 0 && endIndex > 0) {
40640
+ throw new AcpExecutionError(
40641
+ "A native Session history item exceeds the page budget",
40642
+ {},
40643
+ "history_item_too_large"
40644
+ );
40645
+ }
40646
+ return { characters: characterLimit - remainingCharacters, messages: selected, startIndex };
40570
40647
  }
40571
40648
  function nativeActiveMessage(message) {
40572
- return message.role === "user" ? { role: "user", text: message.text } : {
40573
- activities: message.activities,
40574
- content: message.content,
40575
- role: "assistant",
40576
- text: message.text
40577
- };
40649
+ if (message.role === "assistant") {
40650
+ return {
40651
+ activities: message.activities,
40652
+ content: message.content,
40653
+ role: "assistant",
40654
+ text: message.text
40655
+ };
40656
+ }
40657
+ const images = (message.images ?? []).flatMap((image) => {
40658
+ if (image.data.length < 4 || image.data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/u.test(image.data) || !isNativeHistoryImageMimeType(image.mimeType)) {
40659
+ return [];
40660
+ }
40661
+ return [{ data: image.data, mimeType: image.mimeType, name: image.name }];
40662
+ });
40663
+ return { ...images.length === 0 ? {} : { images }, role: "user", text: message.text };
40664
+ }
40665
+ function nativeHistoryCoversCompletedRecovery(history, recovery) {
40666
+ const root = recovery.messages.find((message) => message.role === "user" && message.id === recovery.commandId);
40667
+ if (root === void 0) {
40668
+ return false;
40669
+ }
40670
+ const rootIndex = history.messages.findLastIndex(
40671
+ (message) => message.role === "user" && message.text === root.text
40672
+ );
40673
+ if (rootIndex < 0) {
40674
+ return false;
40675
+ }
40676
+ const nativeAssistant = history.messages.slice(rootIndex + 1).filter((message) => message.role === "assistant");
40677
+ if (nativeAssistant.length === 0) {
40678
+ return false;
40679
+ }
40680
+ const recoveryAssistant = recovery.messages.filter((message) => message.role === "assistant");
40681
+ const recoveryText = recoveryAssistant.map((message) => message.text).join("");
40682
+ const nativeText = nativeAssistant.map((message) => message.text).join("");
40683
+ if (recoveryText.length > 0 && !nativeText.includes(recoveryText)) {
40684
+ return false;
40685
+ }
40686
+ const nativeContent = new Set(
40687
+ nativeAssistant.flatMap((message) => message.content).map((content) => JSON.stringify(content))
40688
+ );
40689
+ return recoveryAssistant.flatMap((message) => message.content).every((content) => nativeContent.has(JSON.stringify(content)));
40578
40690
  }
40579
- function paginateAcpSessionHistory(history, sessionId, cursor, limit) {
40691
+ function historyBeforeActiveTurn(history, activeTurn) {
40580
40692
  if (history.status === "unavailable") {
40581
- if (cursor !== null) {
40582
- throw new AcpExecutionError("Unavailable native Session history has no cursor", {}, "invalid_cursor");
40583
- }
40584
- return { cause: history.cause, nextCursor: null, status: "unavailable" };
40693
+ return history;
40585
40694
  }
40586
- const endIndex = cursor === null ? history.messages.length : liveHistoryEndIndex(cursor, sessionId);
40695
+ const activeRoot = activeTurn.messages.find(
40696
+ (message) => message.role === "user" && message.id === activeTurn.commandId
40697
+ );
40698
+ 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;
40699
+ const activeUserIndex = matchingActiveUserIndex >= 0 ? matchingActiveUserIndex : liveHistoryCoveredTurnRanges(history).find((range) => range.commandId === activeTurn.commandId)?.userIndex ?? -1;
40700
+ if (activeUserIndex < 0) {
40701
+ return history;
40702
+ }
40703
+ return {
40704
+ ...history,
40705
+ coveredCommandIds: history.coveredCommandIds.filter((id) => id !== activeTurn.commandId),
40706
+ coveredMessageIds: history.coveredMessageIds.filter(
40707
+ (id) => id !== `${activeTurn.commandId}:user` && id !== `${activeTurn.commandId}:agent`
40708
+ ),
40709
+ messages: history.messages.slice(0, activeUserIndex)
40710
+ };
40711
+ }
40712
+ function paginateAvailableNativeHistory(history, sessionId, endIndex, limit, characterLimit) {
40587
40713
  if (endIndex > history.messages.length) {
40588
40714
  throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
40589
40715
  }
40590
- const startIndex = Math.max(0, endIndex - limit);
40716
+ const selected = selectMessagesBefore(history.messages, endIndex, limit, characterLimit);
40591
40717
  const coveredMessageIds = new Set(history.coveredMessageIds);
40592
40718
  const ranges = liveHistoryCoveredTurnRanges(history);
40593
40719
  return {
40594
- coveredCommandIds: ranges.filter((range) => range.userIndex >= startIndex && range.assistantEndIndex <= endIndex).map((range) => range.commandId),
40720
+ coveredCommandIds: ranges.filter((range) => range.userIndex >= selected.startIndex && range.assistantEndIndex <= endIndex).map((range) => range.commandId),
40595
40721
  coveredMessageIds: ranges.flatMap((range) => [
40596
- ...range.userIndex >= startIndex && range.userIndex < endIndex && coveredMessageIds.has(`${range.commandId}:user`) ? [`${range.commandId}:user`] : [],
40597
- ...range.assistantStartIndex >= startIndex && range.assistantEndIndex <= endIndex && coveredMessageIds.has(`${range.commandId}:agent`) ? [`${range.commandId}:agent`] : []
40722
+ ...range.userIndex >= selected.startIndex && range.userIndex < endIndex && coveredMessageIds.has(`${range.commandId}:user`) ? [`${range.commandId}:user`] : [],
40723
+ ...range.assistantStartIndex >= selected.startIndex && range.assistantEndIndex <= endIndex && coveredMessageIds.has(`${range.commandId}:agent`) ? [`${range.commandId}:agent`] : []
40598
40724
  ]),
40599
- messages: history.messages.slice(startIndex, endIndex),
40600
- nextCursor: startIndex > 0 ? liveHistoryCursor(sessionId, startIndex) : null,
40725
+ messages: selected.messages,
40726
+ nextCursor: selected.startIndex > 0 ? nativeHistoryCursor(sessionId, selected.startIndex) : null,
40601
40727
  status: "available",
40602
40728
  truncated: history.truncated
40603
40729
  };
40604
40730
  }
40605
- function paginateLiveSessionHistory(history, activeTurn, sessionId, cursor, limit) {
40606
- if (activeTurn === null || cursor !== null) {
40607
- return paginateAcpSessionHistory(history, sessionId, cursor, limit);
40731
+ function paginateNativeHistory(history, sessionId, cursor, limit) {
40732
+ if (cursor?.kind === "active") {
40733
+ throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
40608
40734
  }
40609
40735
  if (history.status === "unavailable") {
40610
- const bounded3 = boundedActiveMessages(
40611
- activeTurn.messages.map(nativeActiveMessage),
40612
- limit,
40613
- SESSION_HISTORY_CHARACTER_LIMIT
40614
- );
40615
- return {
40616
- coveredCommandIds: [],
40617
- coveredMessageIds: [],
40618
- messages: bounded3.messages,
40619
- nextCursor: null,
40620
- status: "available",
40621
- truncated: activeTurn.truncated || bounded3.truncated
40622
- };
40736
+ if (cursor !== null) {
40737
+ throw new AcpExecutionError("Unavailable native Session history has no cursor", {}, "invalid_cursor");
40738
+ }
40739
+ return { cause: history.cause, nextCursor: null, status: "unavailable" };
40623
40740
  }
40624
- const activeRoot = activeTurn.messages.find(
40625
- (message) => message.role === "user" && message.id === activeTurn.commandId
40741
+ return paginateAvailableNativeHistory(
40742
+ history,
40743
+ sessionId,
40744
+ cursor?.endIndex ?? history.messages.length,
40745
+ limit,
40746
+ SESSION_HISTORY_CHARACTER_LIMIT
40626
40747
  );
40627
- const coveredActiveRoot = history.coveredCommandIds.includes(activeTurn.commandId);
40628
- const matchingActiveUserIndex = coveredActiveRoot ? history.messages.findLastIndex(
40629
- (message) => message.role === "user" && message.text === (activeRoot?.text ?? activeTurn.prompt)
40630
- ) : -1;
40631
- const activeUserIndex = matchingActiveUserIndex >= 0 ? matchingActiveUserIndex : liveHistoryCoveredTurnRanges(history).find((range) => range.commandId === activeTurn.commandId)?.userIndex ?? -1;
40632
- if (activeUserIndex >= 0) {
40633
- history = {
40634
- ...history,
40635
- coveredCommandIds: history.coveredCommandIds.filter((id) => id !== activeTurn.commandId),
40636
- coveredMessageIds: history.coveredMessageIds.filter(
40637
- (id) => id !== `${activeTurn.commandId}:user` && id !== `${activeTurn.commandId}:agent`
40638
- ),
40639
- messages: history.messages.slice(0, activeUserIndex + 1)
40640
- };
40641
- }
40642
- const latestNativeMessage = history.messages.at(-1);
40643
- const firstActiveMessage = activeTurn.messages[0];
40644
- const preserveNativeRoot = activeUserIndex >= 0 || firstActiveMessage?.role === "user" && latestNativeMessage?.role === "user" && latestNativeMessage.text === firstActiveMessage.text;
40645
- const activeMessages = activeTurn.messages.slice(preserveNativeRoot ? 1 : 0).map(nativeActiveMessage);
40646
- const bounded2 = boundedActiveMessages(activeMessages, limit, SESSION_HISTORY_CHARACTER_LIMIT);
40647
- let historicalMessageCount = 0;
40648
- let remainingCharacters = SESSION_HISTORY_CHARACTER_LIMIT - bounded2.characters;
40649
- const historicalMessageLimit = Math.max(0, limit - bounded2.messages.length);
40650
- for (let index = history.messages.length - 1; index >= 0 && historicalMessageCount < historicalMessageLimit; index -= 1) {
40651
- const message = history.messages[index];
40652
- if (message === void 0) {
40653
- break;
40654
- }
40655
- const characters = historyMessageCharacters(message);
40656
- if (characters > remainingCharacters) {
40657
- break;
40658
- }
40659
- historicalMessageCount += 1;
40660
- remainingCharacters -= characters;
40748
+ }
40749
+ function paginateActiveTurn(history, activeTurn, sessionId, endIndex, limit) {
40750
+ if (endIndex > activeTurn.messages.length) {
40751
+ throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
40661
40752
  }
40662
- const page = historicalMessageCount === 0 ? {
40663
- coveredCommandIds: [],
40664
- coveredMessageIds: [],
40665
- messages: [],
40666
- nextCursor: history.messages.length === 0 ? null : liveHistoryCursor(sessionId, history.messages.length),
40667
- status: "available",
40668
- truncated: history.truncated
40669
- } : paginateAcpSessionHistory(history, sessionId, null, historicalMessageCount);
40753
+ const activeMessages = activeTurn.messages.map(nativeActiveMessage);
40754
+ const active = selectMessagesBefore(activeMessages, endIndex, limit, SESSION_HISTORY_CHARACTER_LIMIT);
40755
+ const historicalLimit = limit - active.messages.length;
40756
+ const historicalCharacterLimit = SESSION_HISTORY_CHARACTER_LIMIT - active.characters;
40757
+ const pendingHistoricalCursor = history.status === "available" && history.messages.length > 0 ? nativeHistoryCursor(sessionId, history.messages.length) : null;
40758
+ const latestHistoricalMessage = history.status === "available" ? history.messages.at(-1) : void 0;
40759
+ const historicalPageFits = latestHistoricalMessage === void 0 || historyMessageCharacters(latestHistoricalMessage) <= historicalCharacterLimit;
40760
+ const historical = active.startIndex === 0 && history.status === "available" && historicalLimit > 0 && historicalPageFits ? paginateAvailableNativeHistory(
40761
+ history,
40762
+ sessionId,
40763
+ history.messages.length,
40764
+ historicalLimit,
40765
+ historicalCharacterLimit
40766
+ ) : null;
40670
40767
  return {
40671
- ...page,
40672
- messages: [...page.messages, ...bounded2.messages],
40673
- truncated: page.truncated || activeTurn.truncated || bounded2.truncated
40768
+ coveredCommandIds: historical?.coveredCommandIds ?? [],
40769
+ coveredMessageIds: [
40770
+ ...historical?.coveredMessageIds ?? [],
40771
+ ...active.startIndex === 0 ? [`${activeTurn.commandId}:user`, `${activeTurn.commandId}:agent`] : []
40772
+ ],
40773
+ messages: [...historical?.messages ?? [], ...active.messages],
40774
+ nextCursor: active.startIndex > 0 ? activeHistoryCursor(sessionId, activeTurn.epoch, active.startIndex) : historical === null ? pendingHistoricalCursor : historical.nextCursor,
40775
+ status: "available",
40776
+ truncated: activeTurn.truncated || (historical?.truncated ?? false)
40674
40777
  };
40675
40778
  }
40779
+ function paginateLiveSessionHistory(history, activeTurn, sessionId, encodedCursor, limit) {
40780
+ const cursor = encodedCursor === null ? null : decodeLiveHistoryCursor(encodedCursor, sessionId);
40781
+ if (activeTurn === null || activeTurn.state === "completed" && history.status === "available" && nativeHistoryCoversCompletedRecovery(history, activeTurn)) {
40782
+ return paginateNativeHistory(history, sessionId, cursor, limit);
40783
+ }
40784
+ const historical = historyBeforeActiveTurn(history, activeTurn);
40785
+ if (cursor?.kind === "native") {
40786
+ return paginateNativeHistory(historical, sessionId, cursor, limit);
40787
+ }
40788
+ if (cursor !== null && cursor.epoch !== activeTurn.epoch) {
40789
+ throw new AcpExecutionError("The active Turn history cursor is stale", {}, "stale_cursor");
40790
+ }
40791
+ return paginateActiveTurn(historical, activeTurn, sessionId, cursor?.endIndex ?? activeTurn.messages.length, limit);
40792
+ }
40676
40793
  function mergeLiveSessionHistory(history, activeTurn, sessionId) {
40677
40794
  const page = paginateLiveSessionHistory(history, activeTurn, sessionId, null, 1e3);
40678
40795
  if (page.status === "unavailable") {
@@ -40683,7 +40800,7 @@ function mergeLiveSessionHistory(history, activeTurn, sessionId) {
40683
40800
  coveredMessageIds: page.coveredMessageIds,
40684
40801
  messages: page.messages,
40685
40802
  status: "available",
40686
- truncated: page.truncated
40803
+ truncated: page.truncated || page.nextCursor !== null
40687
40804
  };
40688
40805
  }
40689
40806
 
@@ -41202,15 +41319,13 @@ async function executePrompt({
41202
41319
  });
41203
41320
  operations.transitionExecution(command.commandId, "running");
41204
41321
  if (availability.disposition === SessionPromptDisposition.Steer) {
41205
- const updated = recordSteeringPrompt();
41206
- if (updated === null) {
41322
+ if (!recordSteeringPrompt()) {
41207
41323
  throw new AcpExecutionError(
41208
41324
  "The steering target is unavailable",
41209
41325
  {},
41210
41326
  "prompt_queue_target_unavailable"
41211
41327
  );
41212
41328
  }
41213
- publisher.publish(command.sessionId, updated);
41214
41329
  }
41215
41330
  const stream = activateAttempt();
41216
41331
  publisher.publish(command.sessionId, {
@@ -41598,7 +41713,7 @@ function createDaemonCommandHandler({
41598
41713
  resolveEnvironment: resolveAgentCatalogEnvironment
41599
41714
  });
41600
41715
  const queueChanged = (sessionId) => publisher.publish(sessionId, { kind: "session.queue.changed", sessionId });
41601
- const activeTurnSnapshot = (sessionId) => activeTurns.snapshot((command) => command.sessionId === sessionId);
41716
+ const activeTurnRecovery = (sessionId) => activeTurns.recovery((command) => command.sessionId === sessionId);
41602
41717
  const nativeRequestHandler = createNativeSessionRequestHandler({
41603
41718
  audit,
41604
41719
  diagnostics,
@@ -41619,7 +41734,7 @@ function createDaemonCommandHandler({
41619
41734
  directories,
41620
41735
  audit,
41621
41736
  sessions,
41622
- activeTurnSnapshot,
41737
+ activeTurnRecovery,
41623
41738
  signal
41624
41739
  );
41625
41740
  return;
@@ -41633,7 +41748,7 @@ function createDaemonCommandHandler({
41633
41748
  directories,
41634
41749
  audit,
41635
41750
  sessions,
41636
- activeTurnSnapshot,
41751
+ activeTurnRecovery,
41637
41752
  signal
41638
41753
  );
41639
41754
  return;