@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/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:
@@ -22368,6 +22356,17 @@ var AgentProbeFailed = class extends UnavailableAgent {
22368
22356
  this.message = message;
22369
22357
  }
22370
22358
  };
22359
+ var UnsupportedAgentVersion = class extends UnavailableInstalledAgent {
22360
+ code = "agent_version_unsupported";
22361
+ message;
22362
+ minimumSupportedVersion;
22363
+ status = "unsupported_version";
22364
+ constructor(specification, agent, minimumSupportedVersion) {
22365
+ super(specification, agent);
22366
+ this.minimumSupportedVersion = minimumSupportedVersion;
22367
+ this.message = `Agent version ${agent.agentVersion} is below the minimum supported version ${minimumSupportedVersion}`;
22368
+ }
22369
+ };
22371
22370
  var IntegrationProbeFailed = class extends UnavailableInstalledAgent {
22372
22371
  code;
22373
22372
  message;
@@ -22395,12 +22394,25 @@ var AuthenticationRequiredAgent = class extends UnavailableInstalledAgent {
22395
22394
  super(specification, agent);
22396
22395
  }
22397
22396
  };
22397
+ var AgentDiscoveryResult = class {
22398
+ detectionMilliseconds;
22399
+ discovery;
22400
+ constructor(discovery, detectionMilliseconds) {
22401
+ if (!Number.isFinite(detectionMilliseconds) || detectionMilliseconds < 0) {
22402
+ throw new Error("The Agent detection duration is invalid");
22403
+ }
22404
+ this.detectionMilliseconds = Math.round(detectionMilliseconds * 1e3) / 1e3;
22405
+ this.discovery = discovery;
22406
+ }
22407
+ };
22398
22408
  var LocalAgentInventory = class {
22399
22409
  available;
22400
22410
  discoveries;
22401
22411
  installable;
22412
+ results;
22402
22413
  unavailable;
22403
- constructor(discoveries) {
22414
+ constructor(results) {
22415
+ const discoveries = results.map((result) => result.discovery);
22404
22416
  const available = [];
22405
22417
  const unavailable = [];
22406
22418
  for (const discovery of discoveries) {
@@ -22419,8 +22431,17 @@ var LocalAgentInventory = class {
22419
22431
  (discovery) => discovery instanceof UnavailableInstalledAgent ? discovery.agent : new MissingAgentDefinition(discovery.specification.id, discovery.specification.label)
22420
22432
  )
22421
22433
  );
22434
+ this.results = Object.freeze([...results]);
22422
22435
  this.unavailable = Object.freeze(unavailable);
22423
22436
  }
22437
+ detectionMillisecondsFor = (discovery) => {
22438
+ for (const result of this.results) {
22439
+ if (result.discovery === discovery) {
22440
+ return result.detectionMilliseconds;
22441
+ }
22442
+ }
22443
+ throw new Error("The Agent discovery result is unavailable");
22444
+ };
22424
22445
  readyAgents = () => this.available.map((discovery) => discovery.agent);
22425
22446
  };
22426
22447
 
@@ -26485,15 +26506,20 @@ async function discoverAgent(specification, context) {
26485
26506
  );
26486
26507
  continue;
26487
26508
  }
26488
- if (!supportedVersion) {
26489
- continue;
26490
- }
26491
26509
  const installedAgent = new AgentIntegrationDefinition(
26492
26510
  specification.id,
26493
26511
  specification.label,
26494
26512
  agent.identity.requestedPath,
26495
26513
  agentVersion
26496
26514
  );
26515
+ if (!supportedVersion) {
26516
+ lastFailure = new UnsupportedAgentVersion(
26517
+ specification,
26518
+ installedAgent,
26519
+ specification.minimumSupportedAgentVersion
26520
+ );
26521
+ continue;
26522
+ }
26497
26523
  if (adapters.length === 0 && !(specification instanceof InProcessAcpAgentDefinition2)) {
26498
26524
  return new MissingAdapter(specification, installedAgent);
26499
26525
  }
@@ -26587,10 +26613,15 @@ async function discoverAgent(specification, context) {
26587
26613
  // src/agent-catalog/discover-local-agents.ts
26588
26614
  async function discoverLocalAgentInventory(options) {
26589
26615
  const specifications = options.specifications ?? supportedLocalAgentSpecifications();
26590
- const discoveries = await Promise.all(
26591
- specifications.map(async (specification) => await discoverAgent(specification, options))
26616
+ const monotonicTimeMilliseconds = options.monotonicTimeMilliseconds ?? (() => performance.now());
26617
+ const results = await Promise.all(
26618
+ specifications.map(async (specification) => {
26619
+ const startedAt = monotonicTimeMilliseconds();
26620
+ const discovery = await discoverAgent(specification, options);
26621
+ return new AgentDiscoveryResult(discovery, monotonicTimeMilliseconds() - startedAt);
26622
+ })
26592
26623
  );
26593
- return new LocalAgentInventory(discoveries);
26624
+ return new LocalAgentInventory(results);
26594
26625
  }
26595
26626
 
26596
26627
  // src/audit/audit-store.ts
@@ -37810,6 +37841,28 @@ var DaemonInstallationObserver = class {
37810
37841
 
37811
37842
  // src/daemon-active-turn.ts
37812
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
+ }
37813
37866
  var ActiveDaemonTurn = class {
37814
37867
  attemptId;
37815
37868
  command;
@@ -37817,9 +37870,7 @@ var ActiveDaemonTurn = class {
37817
37870
  #finished = Promise.withResolvers();
37818
37871
  #cancellationRequested = false;
37819
37872
  #dispatch;
37820
- #text = "";
37821
37873
  #activities = /* @__PURE__ */ new Map();
37822
- #content = /* @__PURE__ */ new Map();
37823
37874
  #timeline;
37824
37875
  #sequence = 0;
37825
37876
  #interaction = null;
@@ -37866,9 +37917,17 @@ var ActiveDaemonTurn = class {
37866
37917
  effectiveDisposition = () => this.#dispatch.kind === "promoted" ? SessionPromptDisposition.Steer : this.command.disposition;
37867
37918
  recordEvent = (event) => {
37868
37919
  if (event.kind === AGENT_MESSAGE_DELTA_KIND) {
37869
- this.#text += event.text;
37920
+ const sequence = this.advance();
37870
37921
  this.appendMessageText(event.messageId, event.text);
37871
- 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
+ };
37872
37931
  }
37873
37932
  if (event.sessionId !== this.command.sessionId || "commandId" in event && event.commandId !== this.command.commandId) {
37874
37933
  return event;
@@ -37915,7 +37974,6 @@ var ActiveDaemonTurn = class {
37915
37974
  toolKind: previous?.toolKind ?? ""
37916
37975
  });
37917
37976
  } else if (event.kind === AGENT_CONTENT_KIND) {
37918
- this.#content.set(event.contentId, event.content);
37919
37977
  const target = this.#timeline.findLastIndex(
37920
37978
  (entry) => entry.kind === "message" && entry.sourceMessageId === event.messageId
37921
37979
  );
@@ -37941,7 +37999,7 @@ var ActiveDaemonTurn = class {
37941
37999
  this.#interaction = null;
37942
38000
  }
37943
38001
  if (event.kind === AGENT_ACTIVITY_KIND || event.kind === AGENT_ACTIVITY_NARRATION_KIND || event.kind === AGENT_CONTENT_KIND) {
37944
- return this.updated();
38002
+ this.advance();
37945
38003
  }
37946
38004
  return event;
37947
38005
  };
@@ -37950,7 +38008,7 @@ var ActiveDaemonTurn = class {
37950
38008
  while (remaining.length > 0) {
37951
38009
  const latest = this.#timeline.at(-1);
37952
38010
  if (latest?.kind === "message" && latest.sourceMessageId === messageId) {
37953
- const available = SESSION_HISTORY_CHARACTER_LIMIT - latest.text.length;
38011
+ const available = ACTIVE_TURN_TEXT_CHUNK_LIMIT - latest.text.length;
37954
38012
  if (available > 0) {
37955
38013
  this.#timeline = [
37956
38014
  ...this.#timeline.slice(0, -1),
@@ -37967,21 +38025,22 @@ var ActiveDaemonTurn = class {
37967
38025
  id: decodeIdentifier(randomUUID()),
37968
38026
  kind: "message",
37969
38027
  sourceMessageId: messageId,
37970
- text: remaining.slice(0, SESSION_HISTORY_CHARACTER_LIMIT)
38028
+ text: remaining.slice(0, ACTIVE_TURN_TEXT_CHUNK_LIMIT)
37971
38029
  }
37972
38030
  ];
37973
- remaining = remaining.slice(SESSION_HISTORY_CHARACTER_LIMIT);
38031
+ remaining = remaining.slice(ACTIVE_TURN_TEXT_CHUNK_LIMIT);
37974
38032
  }
37975
38033
  }
37976
38034
  recordSteeringPrompt = (command) => {
37977
38035
  if (this.#dispatch.kind !== "running" || command.sessionId !== this.command.sessionId || command.targetCommandId !== this.command.commandId) {
37978
- return null;
38036
+ return false;
37979
38037
  }
37980
38038
  this.#timeline = [
37981
38039
  ...this.#timeline,
37982
38040
  { id: decodeIdentifier(command.commandId), images: command.images, kind: "user", text: command.prompt }
37983
38041
  ];
37984
- return this.updated();
38042
+ this.advance();
38043
+ return true;
37985
38044
  };
37986
38045
  timelineMessages() {
37987
38046
  return this.#timeline.flatMap((entry) => {
@@ -38003,32 +38062,39 @@ var ActiveDaemonTurn = class {
38003
38062
  return activity2 === void 0 ? [] : [{ activities: [activity2], content: [], id: entry.id, role: "assistant", text: "" }];
38004
38063
  });
38005
38064
  }
38006
- updated = () => {
38007
- this.#sequence += 1;
38008
- const turn = this.snapshot();
38009
- if (turn === null) {
38010
- 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");
38011
38068
  }
38012
- return { kind: "session.turn.updated", sessionId: this.command.sessionId, turn };
38069
+ this.#sequence += 1;
38070
+ return this.#sequence;
38013
38071
  };
38014
38072
  snapshot = () => {
38015
38073
  if (this.#dispatch.kind !== "running") {
38016
38074
  return null;
38017
38075
  }
38018
- const completeMessages = this.timelineMessages();
38019
- const messages = completeMessages.slice(-SESSION_HISTORY_MESSAGE_LIMIT);
38076
+ const bounded2 = boundedRecoveryMessages(this.timelineMessages());
38020
38077
  return {
38021
- activities: [...this.#activities.values()].sort((left, right) => left.sequence - right.sequence),
38022
38078
  commandId: decodeIdentifier(this.command.commandId),
38023
- content: [...this.#content.values()],
38024
- prompt: this.command.prompt,
38025
- text: this.#text,
38026
- truncated: messages.length !== completeMessages.length,
38027
38079
  epoch: this.#epoch,
38080
+ hasOlder: bounded2.hasOlder,
38028
38081
  interaction: this.#interaction,
38029
- messages,
38082
+ messages: bounded2.messages,
38030
38083
  sequence: this.#sequence,
38031
- 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
38032
38098
  };
38033
38099
  };
38034
38100
  matches = (cancellation) => cancellation.commandId === this.command.commandId && cancellation.sessionId === this.command.sessionId;
@@ -38054,6 +38120,7 @@ var ActiveDaemonTurn = class {
38054
38120
  };
38055
38121
 
38056
38122
  // src/daemon-turn-registry.ts
38123
+ var COMPLETED_TURN_RECOVERY_LIMIT = 32;
38057
38124
  var waitForTurnCompletion = (turn, waitSignal) => {
38058
38125
  waitSignal.throwIfAborted();
38059
38126
  return new Promise((resolve9, reject) => {
@@ -38080,6 +38147,7 @@ var waitForTurnCompletion = (turn, waitSignal) => {
38080
38147
  };
38081
38148
  var DaemonTurnRegistry = class {
38082
38149
  #turns = /* @__PURE__ */ new Map();
38150
+ #completed = /* @__PURE__ */ new Map();
38083
38151
  #operations;
38084
38152
  constructor(operations) {
38085
38153
  this.#operations = operations;
@@ -38091,7 +38159,22 @@ var DaemonTurnRegistry = class {
38091
38159
  };
38092
38160
  get = (commandId) => this.#turns.get(commandId);
38093
38161
  finish = (turn) => {
38162
+ const recovery = turn.recovery();
38094
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
+ }
38095
38178
  turn.finish();
38096
38179
  };
38097
38180
  recordEvent = (event) => {
@@ -38112,7 +38195,7 @@ var DaemonTurnRegistry = class {
38112
38195
  };
38113
38196
  recordSteeringPrompt = (command) => {
38114
38197
  const target = this.#turns.get(command.targetCommandId);
38115
- return target?.recordSteeringPrompt(command) ?? null;
38198
+ return target?.recordSteeringPrompt(command) ?? false;
38116
38199
  };
38117
38200
  executionSnapshot = async (matches) => {
38118
38201
  const matching = [];
@@ -38143,12 +38226,30 @@ var DaemonTurnRegistry = class {
38143
38226
  }
38144
38227
  return null;
38145
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
+ };
38146
38246
  close = async () => {
38147
38247
  const turns = [...this.#turns.values()];
38148
38248
  for (const turn of turns) {
38149
38249
  turn.abortDaemon();
38150
38250
  }
38151
38251
  await Promise.all(turns.map((turn) => turn.completion));
38252
+ this.#completed.clear();
38152
38253
  };
38153
38254
  admitAndWait = async (turn, waitSignal, onQueued) => {
38154
38255
  const command = turn.command;
@@ -40456,10 +40557,10 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
40456
40557
  }
40457
40558
 
40458
40559
  // src/native-sessions/live-history-page.ts
40459
- function liveHistoryCursor(sessionId, endIndex) {
40460
- return Buffer.from(JSON.stringify({ endIndex, sessionId }), "utf8").toString("base64url");
40560
+ function encodeLiveHistoryCursor(cursor) {
40561
+ return Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
40461
40562
  }
40462
- function liveHistoryEndIndex(cursor, sessionId) {
40563
+ function decodeLiveHistoryCursor(cursor, sessionId) {
40463
40564
  try {
40464
40565
  if (!/^[A-Za-z0-9_-]{1,512}$/u.test(cursor)) {
40465
40566
  throw new Error("Invalid cursor alphabet");
@@ -40469,14 +40570,32 @@ function liveHistoryEndIndex(cursor, sessionId) {
40469
40570
  throw new Error("Invalid cursor shape");
40470
40571
  }
40471
40572
  const record2 = Object.fromEntries(Object.entries(value));
40472
- 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) {
40473
40577
  throw new Error("Invalid cursor target");
40474
40578
  }
40475
- 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 };
40476
40589
  } catch (cause) {
40477
40590
  throw new AcpExecutionError("The native Session history cursor is invalid", { cause }, "invalid_cursor");
40478
40591
  }
40479
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
+ }
40480
40599
  function liveHistoryCoveredTurnRanges(history) {
40481
40600
  const ranges = [];
40482
40601
  let historyIndex = history.messages.length;
@@ -40497,139 +40616,180 @@ function liveHistoryCoveredTurnRanges(history) {
40497
40616
  function historyMessageCharacters(message) {
40498
40617
  return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
40499
40618
  }
40500
- 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) {
40501
40623
  const selected = [];
40502
40624
  let remainingCharacters = characterLimit;
40503
- 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) {
40504
40627
  const message = messages[index];
40505
40628
  if (message === void 0) {
40506
40629
  break;
40507
40630
  }
40508
40631
  const characters = historyMessageCharacters(message);
40509
- if (characters <= remainingCharacters) {
40510
- selected.unshift(message);
40511
- remainingCharacters -= characters;
40512
- continue;
40513
- }
40514
- const structuredCharacters = characters - message.text.length;
40515
- if (selected.length === 0 && structuredCharacters <= remainingCharacters) {
40516
- const textCharacters = remainingCharacters - structuredCharacters;
40517
- selected.unshift({ ...message, text: textCharacters === 0 ? "" : message.text.slice(-textCharacters) });
40518
- remainingCharacters = 0;
40632
+ if (characters > remainingCharacters) {
40633
+ break;
40519
40634
  }
40520
- break;
40635
+ selected.unshift(message);
40636
+ remainingCharacters -= characters;
40637
+ startIndex = index;
40521
40638
  }
40522
- return {
40523
- characters: characterLimit - remainingCharacters,
40524
- messages: selected,
40525
- truncated: selected.length !== messages.length
40526
- };
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 };
40527
40647
  }
40528
40648
  function nativeActiveMessage(message) {
40529
- return message.role === "user" ? { role: "user", text: message.text } : {
40530
- activities: message.activities,
40531
- content: message.content,
40532
- role: "assistant",
40533
- text: message.text
40534
- };
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)));
40535
40690
  }
40536
- function paginateAcpSessionHistory(history, sessionId, cursor, limit) {
40691
+ function historyBeforeActiveTurn(history, activeTurn) {
40537
40692
  if (history.status === "unavailable") {
40538
- if (cursor !== null) {
40539
- throw new AcpExecutionError("Unavailable native Session history has no cursor", {}, "invalid_cursor");
40540
- }
40541
- return { cause: history.cause, nextCursor: null, status: "unavailable" };
40693
+ return history;
40694
+ }
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;
40542
40702
  }
40543
- const endIndex = cursor === null ? history.messages.length : liveHistoryEndIndex(cursor, sessionId);
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) {
40544
40713
  if (endIndex > history.messages.length) {
40545
40714
  throw new AcpExecutionError("The native Session history cursor is invalid", {}, "invalid_cursor");
40546
40715
  }
40547
- const startIndex = Math.max(0, endIndex - limit);
40716
+ const selected = selectMessagesBefore(history.messages, endIndex, limit, characterLimit);
40548
40717
  const coveredMessageIds = new Set(history.coveredMessageIds);
40549
40718
  const ranges = liveHistoryCoveredTurnRanges(history);
40550
40719
  return {
40551
- 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),
40552
40721
  coveredMessageIds: ranges.flatMap((range) => [
40553
- ...range.userIndex >= startIndex && range.userIndex < endIndex && coveredMessageIds.has(`${range.commandId}:user`) ? [`${range.commandId}:user`] : [],
40554
- ...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`] : []
40555
40724
  ]),
40556
- messages: history.messages.slice(startIndex, endIndex),
40557
- nextCursor: startIndex > 0 ? liveHistoryCursor(sessionId, startIndex) : null,
40725
+ messages: selected.messages,
40726
+ nextCursor: selected.startIndex > 0 ? nativeHistoryCursor(sessionId, selected.startIndex) : null,
40558
40727
  status: "available",
40559
40728
  truncated: history.truncated
40560
40729
  };
40561
40730
  }
40562
- function paginateLiveSessionHistory(history, activeTurn, sessionId, cursor, limit) {
40563
- if (activeTurn === null || cursor !== null) {
40564
- 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");
40565
40734
  }
40566
40735
  if (history.status === "unavailable") {
40567
- const bounded3 = boundedActiveMessages(
40568
- activeTurn.messages.map(nativeActiveMessage),
40569
- limit,
40570
- SESSION_HISTORY_CHARACTER_LIMIT
40571
- );
40572
- return {
40573
- coveredCommandIds: [],
40574
- coveredMessageIds: [],
40575
- messages: bounded3.messages,
40576
- nextCursor: null,
40577
- status: "available",
40578
- truncated: activeTurn.truncated || bounded3.truncated
40579
- };
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" };
40580
40740
  }
40581
- const activeRoot = activeTurn.messages.find(
40582
- (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
40583
40747
  );
40584
- const coveredActiveRoot = history.coveredCommandIds.includes(activeTurn.commandId);
40585
- const matchingActiveUserIndex = coveredActiveRoot ? history.messages.findLastIndex(
40586
- (message) => message.role === "user" && message.text === (activeRoot?.text ?? activeTurn.prompt)
40587
- ) : -1;
40588
- const activeUserIndex = matchingActiveUserIndex >= 0 ? matchingActiveUserIndex : liveHistoryCoveredTurnRanges(history).find((range) => range.commandId === activeTurn.commandId)?.userIndex ?? -1;
40589
- if (activeUserIndex >= 0) {
40590
- history = {
40591
- ...history,
40592
- coveredCommandIds: history.coveredCommandIds.filter((id) => id !== activeTurn.commandId),
40593
- coveredMessageIds: history.coveredMessageIds.filter(
40594
- (id) => id !== `${activeTurn.commandId}:user` && id !== `${activeTurn.commandId}:agent`
40595
- ),
40596
- messages: history.messages.slice(0, activeUserIndex + 1)
40597
- };
40598
- }
40599
- const latestNativeMessage = history.messages.at(-1);
40600
- const firstActiveMessage = activeTurn.messages[0];
40601
- const preserveNativeRoot = activeUserIndex >= 0 || firstActiveMessage?.role === "user" && latestNativeMessage?.role === "user" && latestNativeMessage.text === firstActiveMessage.text;
40602
- const activeMessages = activeTurn.messages.slice(preserveNativeRoot ? 1 : 0).map(nativeActiveMessage);
40603
- const bounded2 = boundedActiveMessages(activeMessages, limit, SESSION_HISTORY_CHARACTER_LIMIT);
40604
- let historicalMessageCount = 0;
40605
- let remainingCharacters = SESSION_HISTORY_CHARACTER_LIMIT - bounded2.characters;
40606
- const historicalMessageLimit = Math.max(0, limit - bounded2.messages.length);
40607
- for (let index = history.messages.length - 1; index >= 0 && historicalMessageCount < historicalMessageLimit; index -= 1) {
40608
- const message = history.messages[index];
40609
- if (message === void 0) {
40610
- break;
40611
- }
40612
- const characters = historyMessageCharacters(message);
40613
- if (characters > remainingCharacters) {
40614
- break;
40615
- }
40616
- historicalMessageCount += 1;
40617
- 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");
40618
40752
  }
40619
- const page = historicalMessageCount === 0 ? {
40620
- coveredCommandIds: [],
40621
- coveredMessageIds: [],
40622
- messages: [],
40623
- nextCursor: history.messages.length === 0 ? null : liveHistoryCursor(sessionId, history.messages.length),
40624
- status: "available",
40625
- truncated: history.truncated
40626
- } : 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;
40627
40767
  return {
40628
- ...page,
40629
- messages: [...page.messages, ...bounded2.messages],
40630
- 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)
40631
40777
  };
40632
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
+ }
40633
40793
  function mergeLiveSessionHistory(history, activeTurn, sessionId) {
40634
40794
  const page = paginateLiveSessionHistory(history, activeTurn, sessionId, null, 1e3);
40635
40795
  if (page.status === "unavailable") {
@@ -40640,7 +40800,7 @@ function mergeLiveSessionHistory(history, activeTurn, sessionId) {
40640
40800
  coveredMessageIds: page.coveredMessageIds,
40641
40801
  messages: page.messages,
40642
40802
  status: "available",
40643
- truncated: page.truncated
40803
+ truncated: page.truncated || page.nextCursor !== null
40644
40804
  };
40645
40805
  }
40646
40806
 
@@ -41159,15 +41319,13 @@ async function executePrompt({
41159
41319
  });
41160
41320
  operations.transitionExecution(command.commandId, "running");
41161
41321
  if (availability.disposition === SessionPromptDisposition.Steer) {
41162
- const updated = recordSteeringPrompt();
41163
- if (updated === null) {
41322
+ if (!recordSteeringPrompt()) {
41164
41323
  throw new AcpExecutionError(
41165
41324
  "The steering target is unavailable",
41166
41325
  {},
41167
41326
  "prompt_queue_target_unavailable"
41168
41327
  );
41169
41328
  }
41170
- publisher.publish(command.sessionId, updated);
41171
41329
  }
41172
41330
  const stream = activateAttempt();
41173
41331
  publisher.publish(command.sessionId, {
@@ -41555,7 +41713,7 @@ function createDaemonCommandHandler({
41555
41713
  resolveEnvironment: resolveAgentCatalogEnvironment
41556
41714
  });
41557
41715
  const queueChanged = (sessionId) => publisher.publish(sessionId, { kind: "session.queue.changed", sessionId });
41558
- const activeTurnSnapshot = (sessionId) => activeTurns.snapshot((command) => command.sessionId === sessionId);
41716
+ const activeTurnRecovery = (sessionId) => activeTurns.recovery((command) => command.sessionId === sessionId);
41559
41717
  const nativeRequestHandler = createNativeSessionRequestHandler({
41560
41718
  audit,
41561
41719
  diagnostics,
@@ -41576,7 +41734,7 @@ function createDaemonCommandHandler({
41576
41734
  directories,
41577
41735
  audit,
41578
41736
  sessions,
41579
- activeTurnSnapshot,
41737
+ activeTurnRecovery,
41580
41738
  signal
41581
41739
  );
41582
41740
  return;
@@ -41590,7 +41748,7 @@ function createDaemonCommandHandler({
41590
41748
  directories,
41591
41749
  audit,
41592
41750
  sessions,
41593
- activeTurnSnapshot,
41751
+ activeTurnRecovery,
41594
41752
  signal
41595
41753
  );
41596
41754
  return;