@moxt-ai/mobius 0.0.146 → 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.
Files changed (42) hide show
  1. package/dist/agent-catalog/agent-diagnostics.d.ts +1 -1
  2. package/dist/agent-catalog/agent-diagnostics.d.ts.map +1 -1
  3. package/dist/agent-catalog/agent-diagnostics.js +31 -8
  4. package/dist/agent-catalog/agent-diagnostics.js.map +1 -1
  5. package/dist/agent-catalog/agent-discovery.d.ts +15 -1
  6. package/dist/agent-catalog/agent-discovery.d.ts.map +1 -1
  7. package/dist/agent-catalog/agent-discovery.js +34 -1
  8. package/dist/agent-catalog/agent-discovery.js.map +1 -1
  9. package/dist/agent-catalog/discover-agent.d.ts.map +1 -1
  10. package/dist/agent-catalog/discover-agent.js +3 -2
  11. package/dist/agent-catalog/discover-agent.js.map +1 -1
  12. package/dist/agent-catalog/discover-local-agents.d.ts +1 -0
  13. package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
  14. package/dist/agent-catalog/discover-local-agents.js +8 -3
  15. package/dist/agent-catalog/discover-local-agents.js.map +1 -1
  16. package/dist/cli.js +370 -177
  17. package/dist/cli.js.map +3 -3
  18. package/dist/daemon-active-turn.d.ts +15 -2
  19. package/dist/daemon-active-turn.d.ts.map +1 -1
  20. package/dist/daemon-active-turn.js +63 -25
  21. package/dist/daemon-active-turn.js.map +1 -1
  22. package/dist/daemon-command-handler.js +3 -3
  23. package/dist/daemon-history-commands.d.ts +4 -7
  24. package/dist/daemon-history-commands.d.ts.map +1 -1
  25. package/dist/daemon-history-commands.js.map +1 -1
  26. package/dist/daemon-prompt-executor.d.ts +1 -1
  27. package/dist/daemon-prompt-executor.d.ts.map +1 -1
  28. package/dist/daemon-prompt-executor.js +1 -3
  29. package/dist/daemon-prompt-executor.js.map +1 -1
  30. package/dist/daemon-turn-registry.d.ts +5 -43
  31. package/dist/daemon-turn-registry.d.ts.map +1 -1
  32. package/dist/daemon-turn-registry.js +40 -1
  33. package/dist/daemon-turn-registry.js.map +1 -1
  34. package/dist/index.js +325 -167
  35. package/dist/index.js.map +3 -3
  36. package/dist/native-sessions/live-history-page.d.ts +4 -7
  37. package/dist/native-sessions/live-history-page.d.ts.map +1 -1
  38. package/dist/native-sessions/live-history-page.js +163 -107
  39. package/dist/native-sessions/live-history-page.js.map +1 -1
  40. package/dist/runtime.js +325 -167
  41. package/dist/runtime.js.map +3 -3
  42. package/package.json +1 -1
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:
@@ -32569,6 +32557,17 @@ var AgentProbeFailed = class extends UnavailableAgent {
32569
32557
  this.message = message;
32570
32558
  }
32571
32559
  };
32560
+ var UnsupportedAgentVersion = class extends UnavailableInstalledAgent {
32561
+ code = "agent_version_unsupported";
32562
+ message;
32563
+ minimumSupportedVersion;
32564
+ status = "unsupported_version";
32565
+ constructor(specification, agent, minimumSupportedVersion) {
32566
+ super(specification, agent);
32567
+ this.minimumSupportedVersion = minimumSupportedVersion;
32568
+ this.message = `Agent version ${agent.agentVersion} is below the minimum supported version ${minimumSupportedVersion}`;
32569
+ }
32570
+ };
32572
32571
  var IntegrationProbeFailed = class extends UnavailableInstalledAgent {
32573
32572
  code;
32574
32573
  message;
@@ -32596,12 +32595,25 @@ var AuthenticationRequiredAgent = class extends UnavailableInstalledAgent {
32596
32595
  super(specification, agent);
32597
32596
  }
32598
32597
  };
32598
+ var AgentDiscoveryResult = class {
32599
+ detectionMilliseconds;
32600
+ discovery;
32601
+ constructor(discovery, detectionMilliseconds) {
32602
+ if (!Number.isFinite(detectionMilliseconds) || detectionMilliseconds < 0) {
32603
+ throw new Error("The Agent detection duration is invalid");
32604
+ }
32605
+ this.detectionMilliseconds = Math.round(detectionMilliseconds * 1e3) / 1e3;
32606
+ this.discovery = discovery;
32607
+ }
32608
+ };
32599
32609
  var LocalAgentInventory = class {
32600
32610
  available;
32601
32611
  discoveries;
32602
32612
  installable;
32613
+ results;
32603
32614
  unavailable;
32604
- constructor(discoveries) {
32615
+ constructor(results) {
32616
+ const discoveries = results.map((result) => result.discovery);
32605
32617
  const available = [];
32606
32618
  const unavailable = [];
32607
32619
  for (const discovery of discoveries) {
@@ -32620,8 +32632,17 @@ var LocalAgentInventory = class {
32620
32632
  (discovery) => discovery instanceof UnavailableInstalledAgent ? discovery.agent : new MissingAgentDefinition(discovery.specification.id, discovery.specification.label)
32621
32633
  )
32622
32634
  );
32635
+ this.results = Object.freeze([...results]);
32623
32636
  this.unavailable = Object.freeze(unavailable);
32624
32637
  }
32638
+ detectionMillisecondsFor = (discovery) => {
32639
+ for (const result of this.results) {
32640
+ if (result.discovery === discovery) {
32641
+ return result.detectionMilliseconds;
32642
+ }
32643
+ }
32644
+ throw new Error("The Agent discovery result is unavailable");
32645
+ };
32625
32646
  readyAgents = () => this.available.map((discovery) => discovery.agent);
32626
32647
  };
32627
32648
 
@@ -36540,15 +36561,20 @@ async function discoverAgent(specification, context) {
36540
36561
  );
36541
36562
  continue;
36542
36563
  }
36543
- if (!supportedVersion) {
36544
- continue;
36545
- }
36546
36564
  const installedAgent = new AgentIntegrationDefinition(
36547
36565
  specification.id,
36548
36566
  specification.label,
36549
36567
  agent.identity.requestedPath,
36550
36568
  agentVersion
36551
36569
  );
36570
+ if (!supportedVersion) {
36571
+ lastFailure = new UnsupportedAgentVersion(
36572
+ specification,
36573
+ installedAgent,
36574
+ specification.minimumSupportedAgentVersion
36575
+ );
36576
+ continue;
36577
+ }
36552
36578
  if (adapters.length === 0 && !(specification instanceof InProcessAcpAgentDefinition2)) {
36553
36579
  return new MissingAdapter(specification, installedAgent);
36554
36580
  }
@@ -36642,10 +36668,15 @@ async function discoverAgent(specification, context) {
36642
36668
  // src/agent-catalog/discover-local-agents.ts
36643
36669
  async function discoverLocalAgentInventory(options) {
36644
36670
  const specifications = options.specifications ?? supportedLocalAgentSpecifications();
36645
- const discoveries = await Promise.all(
36646
- specifications.map(async (specification) => await discoverAgent(specification, options))
36671
+ const monotonicTimeMilliseconds = options.monotonicTimeMilliseconds ?? (() => performance.now());
36672
+ const results = await Promise.all(
36673
+ specifications.map(async (specification) => {
36674
+ const startedAt = monotonicTimeMilliseconds();
36675
+ const discovery = await discoverAgent(specification, options);
36676
+ return new AgentDiscoveryResult(discovery, monotonicTimeMilliseconds() - startedAt);
36677
+ })
36647
36678
  );
36648
- return new LocalAgentInventory(discoveries);
36679
+ return new LocalAgentInventory(results);
36649
36680
  }
36650
36681
 
36651
36682
  // src/storage/runtime-installation-store.ts
@@ -38688,6 +38719,28 @@ var DaemonInstallationObserver = class {
38688
38719
 
38689
38720
  // src/daemon-active-turn.ts
38690
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
+ }
38691
38744
  var ActiveDaemonTurn = class {
38692
38745
  attemptId;
38693
38746
  command;
@@ -38695,9 +38748,7 @@ var ActiveDaemonTurn = class {
38695
38748
  #finished = Promise.withResolvers();
38696
38749
  #cancellationRequested = false;
38697
38750
  #dispatch;
38698
- #text = "";
38699
38751
  #activities = /* @__PURE__ */ new Map();
38700
- #content = /* @__PURE__ */ new Map();
38701
38752
  #timeline;
38702
38753
  #sequence = 0;
38703
38754
  #interaction = null;
@@ -38744,9 +38795,17 @@ var ActiveDaemonTurn = class {
38744
38795
  effectiveDisposition = () => this.#dispatch.kind === "promoted" ? SessionPromptDisposition.Steer : this.command.disposition;
38745
38796
  recordEvent = (event) => {
38746
38797
  if (event.kind === AGENT_MESSAGE_DELTA_KIND) {
38747
- this.#text += event.text;
38798
+ const sequence = this.advance();
38748
38799
  this.appendMessageText(event.messageId, event.text);
38749
- 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
+ };
38750
38809
  }
38751
38810
  if (event.sessionId !== this.command.sessionId || "commandId" in event && event.commandId !== this.command.commandId) {
38752
38811
  return event;
@@ -38793,7 +38852,6 @@ var ActiveDaemonTurn = class {
38793
38852
  toolKind: previous?.toolKind ?? ""
38794
38853
  });
38795
38854
  } else if (event.kind === AGENT_CONTENT_KIND) {
38796
- this.#content.set(event.contentId, event.content);
38797
38855
  const target = this.#timeline.findLastIndex(
38798
38856
  (entry) => entry.kind === "message" && entry.sourceMessageId === event.messageId
38799
38857
  );
@@ -38819,7 +38877,7 @@ var ActiveDaemonTurn = class {
38819
38877
  this.#interaction = null;
38820
38878
  }
38821
38879
  if (event.kind === AGENT_ACTIVITY_KIND || event.kind === AGENT_ACTIVITY_NARRATION_KIND || event.kind === AGENT_CONTENT_KIND) {
38822
- return this.updated();
38880
+ this.advance();
38823
38881
  }
38824
38882
  return event;
38825
38883
  };
@@ -38828,7 +38886,7 @@ var ActiveDaemonTurn = class {
38828
38886
  while (remaining.length > 0) {
38829
38887
  const latest = this.#timeline.at(-1);
38830
38888
  if (latest?.kind === "message" && latest.sourceMessageId === messageId) {
38831
- const available = SESSION_HISTORY_CHARACTER_LIMIT - latest.text.length;
38889
+ const available = ACTIVE_TURN_TEXT_CHUNK_LIMIT - latest.text.length;
38832
38890
  if (available > 0) {
38833
38891
  this.#timeline = [
38834
38892
  ...this.#timeline.slice(0, -1),
@@ -38845,21 +38903,22 @@ var ActiveDaemonTurn = class {
38845
38903
  id: decodeIdentifier(randomUUID2()),
38846
38904
  kind: "message",
38847
38905
  sourceMessageId: messageId,
38848
- text: remaining.slice(0, SESSION_HISTORY_CHARACTER_LIMIT)
38906
+ text: remaining.slice(0, ACTIVE_TURN_TEXT_CHUNK_LIMIT)
38849
38907
  }
38850
38908
  ];
38851
- remaining = remaining.slice(SESSION_HISTORY_CHARACTER_LIMIT);
38909
+ remaining = remaining.slice(ACTIVE_TURN_TEXT_CHUNK_LIMIT);
38852
38910
  }
38853
38911
  }
38854
38912
  recordSteeringPrompt = (command) => {
38855
38913
  if (this.#dispatch.kind !== "running" || command.sessionId !== this.command.sessionId || command.targetCommandId !== this.command.commandId) {
38856
- return null;
38914
+ return false;
38857
38915
  }
38858
38916
  this.#timeline = [
38859
38917
  ...this.#timeline,
38860
38918
  { id: decodeIdentifier(command.commandId), images: command.images, kind: "user", text: command.prompt }
38861
38919
  ];
38862
- return this.updated();
38920
+ this.advance();
38921
+ return true;
38863
38922
  };
38864
38923
  timelineMessages() {
38865
38924
  return this.#timeline.flatMap((entry) => {
@@ -38881,32 +38940,39 @@ var ActiveDaemonTurn = class {
38881
38940
  return activity2 === void 0 ? [] : [{ activities: [activity2], content: [], id: entry.id, role: "assistant", text: "" }];
38882
38941
  });
38883
38942
  }
38884
- updated = () => {
38885
- this.#sequence += 1;
38886
- const turn = this.snapshot();
38887
- if (turn === null) {
38888
- 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");
38889
38946
  }
38890
- return { kind: "session.turn.updated", sessionId: this.command.sessionId, turn };
38947
+ this.#sequence += 1;
38948
+ return this.#sequence;
38891
38949
  };
38892
38950
  snapshot = () => {
38893
38951
  if (this.#dispatch.kind !== "running") {
38894
38952
  return null;
38895
38953
  }
38896
- const completeMessages = this.timelineMessages();
38897
- const messages = completeMessages.slice(-SESSION_HISTORY_MESSAGE_LIMIT);
38954
+ const bounded2 = boundedRecoveryMessages(this.timelineMessages());
38898
38955
  return {
38899
- activities: [...this.#activities.values()].sort((left, right) => left.sequence - right.sequence),
38900
38956
  commandId: decodeIdentifier(this.command.commandId),
38901
- content: [...this.#content.values()],
38902
- prompt: this.command.prompt,
38903
- text: this.#text,
38904
- truncated: messages.length !== completeMessages.length,
38905
38957
  epoch: this.#epoch,
38958
+ hasOlder: bounded2.hasOlder,
38906
38959
  interaction: this.#interaction,
38907
- messages,
38960
+ messages: bounded2.messages,
38908
38961
  sequence: this.#sequence,
38909
- 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
38910
38976
  };
38911
38977
  };
38912
38978
  matches = (cancellation) => cancellation.commandId === this.command.commandId && cancellation.sessionId === this.command.sessionId;
@@ -38932,6 +38998,7 @@ var ActiveDaemonTurn = class {
38932
38998
  };
38933
38999
 
38934
39000
  // src/daemon-turn-registry.ts
39001
+ var COMPLETED_TURN_RECOVERY_LIMIT = 32;
38935
39002
  var waitForTurnCompletion = (turn, waitSignal) => {
38936
39003
  waitSignal.throwIfAborted();
38937
39004
  return new Promise((resolve9, reject) => {
@@ -38958,6 +39025,7 @@ var waitForTurnCompletion = (turn, waitSignal) => {
38958
39025
  };
38959
39026
  var DaemonTurnRegistry = class {
38960
39027
  #turns = /* @__PURE__ */ new Map();
39028
+ #completed = /* @__PURE__ */ new Map();
38961
39029
  #operations;
38962
39030
  constructor(operations) {
38963
39031
  this.#operations = operations;
@@ -38969,7 +39037,22 @@ var DaemonTurnRegistry = class {
38969
39037
  };
38970
39038
  get = (commandId) => this.#turns.get(commandId);
38971
39039
  finish = (turn) => {
39040
+ const recovery = turn.recovery();
38972
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
+ }
38973
39056
  turn.finish();
38974
39057
  };
38975
39058
  recordEvent = (event) => {
@@ -38990,7 +39073,7 @@ var DaemonTurnRegistry = class {
38990
39073
  };
38991
39074
  recordSteeringPrompt = (command) => {
38992
39075
  const target = this.#turns.get(command.targetCommandId);
38993
- return target?.recordSteeringPrompt(command) ?? null;
39076
+ return target?.recordSteeringPrompt(command) ?? false;
38994
39077
  };
38995
39078
  executionSnapshot = async (matches) => {
38996
39079
  const matching = [];
@@ -39021,12 +39104,30 @@ var DaemonTurnRegistry = class {
39021
39104
  }
39022
39105
  return null;
39023
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
+ };
39024
39124
  close = async () => {
39025
39125
  const turns = [...this.#turns.values()];
39026
39126
  for (const turn of turns) {
39027
39127
  turn.abortDaemon();
39028
39128
  }
39029
39129
  await Promise.all(turns.map((turn) => turn.completion));
39130
+ this.#completed.clear();
39030
39131
  };
39031
39132
  admitAndWait = async (turn, waitSignal, onQueued) => {
39032
39133
  const command = turn.command;
@@ -41334,10 +41435,10 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
41334
41435
  }
41335
41436
 
41336
41437
  // src/native-sessions/live-history-page.ts
41337
- function liveHistoryCursor(sessionId, endIndex) {
41338
- return Buffer.from(JSON.stringify({ endIndex, sessionId }), "utf8").toString("base64url");
41438
+ function encodeLiveHistoryCursor(cursor) {
41439
+ return Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
41339
41440
  }
41340
- function liveHistoryEndIndex(cursor, sessionId) {
41441
+ function decodeLiveHistoryCursor(cursor, sessionId) {
41341
41442
  try {
41342
41443
  if (!/^[A-Za-z0-9_-]{1,512}$/u.test(cursor)) {
41343
41444
  throw new Error("Invalid cursor alphabet");
@@ -41347,14 +41448,32 @@ function liveHistoryEndIndex(cursor, sessionId) {
41347
41448
  throw new Error("Invalid cursor shape");
41348
41449
  }
41349
41450
  const record2 = Object.fromEntries(Object.entries(value));
41350
- 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) {
41351
41455
  throw new Error("Invalid cursor target");
41352
41456
  }
41353
- 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 };
41354
41467
  } catch (cause) {
41355
41468
  throw new AcpExecutionError("The native Session history cursor is invalid", { cause }, "invalid_cursor");
41356
41469
  }
41357
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
+ }
41358
41477
  function liveHistoryCoveredTurnRanges(history) {
41359
41478
  const ranges = [];
41360
41479
  let historyIndex = history.messages.length;
@@ -41375,139 +41494,180 @@ function liveHistoryCoveredTurnRanges(history) {
41375
41494
  function historyMessageCharacters(message) {
41376
41495
  return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
41377
41496
  }
41378
- 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) {
41379
41501
  const selected = [];
41380
41502
  let remainingCharacters = characterLimit;
41381
- 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) {
41382
41505
  const message = messages[index];
41383
41506
  if (message === void 0) {
41384
41507
  break;
41385
41508
  }
41386
41509
  const characters = historyMessageCharacters(message);
41387
- if (characters <= remainingCharacters) {
41388
- selected.unshift(message);
41389
- remainingCharacters -= characters;
41390
- continue;
41391
- }
41392
- const structuredCharacters = characters - message.text.length;
41393
- if (selected.length === 0 && structuredCharacters <= remainingCharacters) {
41394
- const textCharacters = remainingCharacters - structuredCharacters;
41395
- selected.unshift({ ...message, text: textCharacters === 0 ? "" : message.text.slice(-textCharacters) });
41396
- remainingCharacters = 0;
41510
+ if (characters > remainingCharacters) {
41511
+ break;
41397
41512
  }
41398
- break;
41513
+ selected.unshift(message);
41514
+ remainingCharacters -= characters;
41515
+ startIndex = index;
41399
41516
  }
41400
- return {
41401
- characters: characterLimit - remainingCharacters,
41402
- messages: selected,
41403
- truncated: selected.length !== messages.length
41404
- };
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 };
41405
41525
  }
41406
41526
  function nativeActiveMessage(message) {
41407
- return message.role === "user" ? { role: "user", text: message.text } : {
41408
- activities: message.activities,
41409
- content: message.content,
41410
- role: "assistant",
41411
- text: message.text
41412
- };
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)));
41413
41568
  }
41414
- function paginateAcpSessionHistory(history, sessionId, cursor, limit) {
41569
+ function historyBeforeActiveTurn(history, activeTurn) {
41415
41570
  if (history.status === "unavailable") {
41416
- if (cursor !== null) {
41417
- throw new AcpExecutionError("Unavailable native Session history has no cursor", {}, "invalid_cursor");
41418
- }
41419
- return { cause: history.cause, nextCursor: null, status: "unavailable" };
41571
+ return history;
41572
+ }
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;
41420
41580
  }
41421
- const endIndex = cursor === null ? history.messages.length : liveHistoryEndIndex(cursor, sessionId);
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) {
41422
41591
  if (endIndex > history.messages.length) {
41423
41592
  throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
41424
41593
  }
41425
- const startIndex = Math.max(0, endIndex - limit);
41594
+ const selected = selectMessagesBefore(history.messages, endIndex, limit, characterLimit);
41426
41595
  const coveredMessageIds = new Set(history.coveredMessageIds);
41427
41596
  const ranges = liveHistoryCoveredTurnRanges(history);
41428
41597
  return {
41429
- 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),
41430
41599
  coveredMessageIds: ranges.flatMap((range) => [
41431
- ...range.userIndex >= startIndex && range.userIndex < endIndex && coveredMessageIds.has(`${range.commandId}:user`) ? [`${range.commandId}:user`] : [],
41432
- ...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`] : []
41433
41602
  ]),
41434
- messages: history.messages.slice(startIndex, endIndex),
41435
- nextCursor: startIndex > 0 ? liveHistoryCursor(sessionId, startIndex) : null,
41603
+ messages: selected.messages,
41604
+ nextCursor: selected.startIndex > 0 ? nativeHistoryCursor(sessionId, selected.startIndex) : null,
41436
41605
  status: "available",
41437
41606
  truncated: history.truncated
41438
41607
  };
41439
41608
  }
41440
- function paginateLiveSessionHistory(history, activeTurn, sessionId, cursor, limit) {
41441
- if (activeTurn === null || cursor !== null) {
41442
- 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");
41443
41612
  }
41444
41613
  if (history.status === "unavailable") {
41445
- const bounded3 = boundedActiveMessages(
41446
- activeTurn.messages.map(nativeActiveMessage),
41447
- limit,
41448
- SESSION_HISTORY_CHARACTER_LIMIT
41449
- );
41450
- return {
41451
- coveredCommandIds: [],
41452
- coveredMessageIds: [],
41453
- messages: bounded3.messages,
41454
- nextCursor: null,
41455
- status: "available",
41456
- truncated: activeTurn.truncated || bounded3.truncated
41457
- };
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" };
41458
41618
  }
41459
- const activeRoot = activeTurn.messages.find(
41460
- (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
41461
41625
  );
41462
- const coveredActiveRoot = history.coveredCommandIds.includes(activeTurn.commandId);
41463
- const matchingActiveUserIndex = coveredActiveRoot ? history.messages.findLastIndex(
41464
- (message) => message.role === "user" && message.text === (activeRoot?.text ?? activeTurn.prompt)
41465
- ) : -1;
41466
- const activeUserIndex = matchingActiveUserIndex >= 0 ? matchingActiveUserIndex : liveHistoryCoveredTurnRanges(history).find((range) => range.commandId === activeTurn.commandId)?.userIndex ?? -1;
41467
- if (activeUserIndex >= 0) {
41468
- history = {
41469
- ...history,
41470
- coveredCommandIds: history.coveredCommandIds.filter((id) => id !== activeTurn.commandId),
41471
- coveredMessageIds: history.coveredMessageIds.filter(
41472
- (id) => id !== `${activeTurn.commandId}:user` && id !== `${activeTurn.commandId}:agent`
41473
- ),
41474
- messages: history.messages.slice(0, activeUserIndex + 1)
41475
- };
41476
- }
41477
- const latestNativeMessage = history.messages.at(-1);
41478
- const firstActiveMessage = activeTurn.messages[0];
41479
- const preserveNativeRoot = activeUserIndex >= 0 || firstActiveMessage?.role === "user" && latestNativeMessage?.role === "user" && latestNativeMessage.text === firstActiveMessage.text;
41480
- const activeMessages = activeTurn.messages.slice(preserveNativeRoot ? 1 : 0).map(nativeActiveMessage);
41481
- const bounded2 = boundedActiveMessages(activeMessages, limit, SESSION_HISTORY_CHARACTER_LIMIT);
41482
- let historicalMessageCount = 0;
41483
- let remainingCharacters = SESSION_HISTORY_CHARACTER_LIMIT - bounded2.characters;
41484
- const historicalMessageLimit = Math.max(0, limit - bounded2.messages.length);
41485
- for (let index = history.messages.length - 1; index >= 0 && historicalMessageCount < historicalMessageLimit; index -= 1) {
41486
- const message = history.messages[index];
41487
- if (message === void 0) {
41488
- break;
41489
- }
41490
- const characters = historyMessageCharacters(message);
41491
- if (characters > remainingCharacters) {
41492
- break;
41493
- }
41494
- historicalMessageCount += 1;
41495
- 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");
41496
41630
  }
41497
- const page = historicalMessageCount === 0 ? {
41498
- coveredCommandIds: [],
41499
- coveredMessageIds: [],
41500
- messages: [],
41501
- nextCursor: history.messages.length === 0 ? null : liveHistoryCursor(sessionId, history.messages.length),
41502
- status: "available",
41503
- truncated: history.truncated
41504
- } : 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;
41505
41645
  return {
41506
- ...page,
41507
- messages: [...page.messages, ...bounded2.messages],
41508
- 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)
41509
41655
  };
41510
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
+ }
41511
41671
  function mergeLiveSessionHistory(history, activeTurn, sessionId) {
41512
41672
  const page = paginateLiveSessionHistory(history, activeTurn, sessionId, null, 1e3);
41513
41673
  if (page.status === "unavailable") {
@@ -41518,7 +41678,7 @@ function mergeLiveSessionHistory(history, activeTurn, sessionId) {
41518
41678
  coveredMessageIds: page.coveredMessageIds,
41519
41679
  messages: page.messages,
41520
41680
  status: "available",
41521
- truncated: page.truncated
41681
+ truncated: page.truncated || page.nextCursor !== null
41522
41682
  };
41523
41683
  }
41524
41684
 
@@ -42037,15 +42197,13 @@ async function executePrompt({
42037
42197
  });
42038
42198
  operations.transitionExecution(command.commandId, "running");
42039
42199
  if (availability.disposition === SessionPromptDisposition.Steer) {
42040
- const updated = recordSteeringPrompt();
42041
- if (updated === null) {
42200
+ if (!recordSteeringPrompt()) {
42042
42201
  throw new AcpExecutionError(
42043
42202
  "The steering target is unavailable",
42044
42203
  {},
42045
42204
  "prompt_queue_target_unavailable"
42046
42205
  );
42047
42206
  }
42048
- publisher.publish(command.sessionId, updated);
42049
42207
  }
42050
42208
  const stream = activateAttempt();
42051
42209
  publisher.publish(command.sessionId, {
@@ -42433,7 +42591,7 @@ function createDaemonCommandHandler({
42433
42591
  resolveEnvironment: resolveAgentCatalogEnvironment
42434
42592
  });
42435
42593
  const queueChanged = (sessionId) => publisher.publish(sessionId, { kind: "session.queue.changed", sessionId });
42436
- const activeTurnSnapshot = (sessionId) => activeTurns.snapshot((command) => command.sessionId === sessionId);
42594
+ const activeTurnRecovery = (sessionId) => activeTurns.recovery((command) => command.sessionId === sessionId);
42437
42595
  const nativeRequestHandler = createNativeSessionRequestHandler({
42438
42596
  audit,
42439
42597
  diagnostics,
@@ -42454,7 +42612,7 @@ function createDaemonCommandHandler({
42454
42612
  directories,
42455
42613
  audit,
42456
42614
  sessions,
42457
- activeTurnSnapshot,
42615
+ activeTurnRecovery,
42458
42616
  signal
42459
42617
  );
42460
42618
  return;
@@ -42468,7 +42626,7 @@ function createDaemonCommandHandler({
42468
42626
  directories,
42469
42627
  audit,
42470
42628
  sessions,
42471
- activeTurnSnapshot,
42629
+ activeTurnRecovery,
42472
42630
  signal
42473
42631
  );
42474
42632
  return;