@moxt-ai/mobius 0.0.141 → 0.0.143

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 (48) hide show
  1. package/dist/acp/agent-query-processes.js +2 -2
  2. package/dist/acp/agent-query-processes.js.map +1 -1
  3. package/dist/acp/agent-runtime-manager.js +4 -4
  4. package/dist/acp/agent-runtime-manager.js.map +1 -1
  5. package/dist/acp/agent-session.d.ts.map +1 -1
  6. package/dist/acp/agent-session.js +37 -34
  7. package/dist/acp/agent-session.js.map +1 -1
  8. package/dist/acp/runtime-operations.d.ts +2 -2
  9. package/dist/acp/runtime-operations.d.ts.map +1 -1
  10. package/dist/acp/runtime-operations.js +2 -2
  11. package/dist/acp/runtime-operations.js.map +1 -1
  12. package/dist/cli.js +347 -315
  13. package/dist/cli.js.map +4 -4
  14. package/dist/daemon-active-turn.d.ts +3 -0
  15. package/dist/daemon-active-turn.d.ts.map +1 -1
  16. package/dist/daemon-active-turn.js +81 -6
  17. package/dist/daemon-active-turn.js.map +1 -1
  18. package/dist/daemon-prompt-executor.d.ts.map +1 -1
  19. package/dist/daemon-prompt-executor.js +25 -41
  20. package/dist/daemon-prompt-executor.js.map +1 -1
  21. package/dist/daemon-turn-registry.d.ts +48 -0
  22. package/dist/daemon-turn-registry.d.ts.map +1 -1
  23. package/dist/daemon-turn-registry.js +8 -1
  24. package/dist/daemon-turn-registry.js.map +1 -1
  25. package/dist/index.js +346 -314
  26. package/dist/index.js.map +4 -4
  27. package/dist/native-sessions/live-history-page.d.ts.map +1 -1
  28. package/dist/native-sessions/live-history-page.js +40 -24
  29. package/dist/native-sessions/live-history-page.js.map +1 -1
  30. package/dist/relay-connection/coalescing-agent-event-publisher.d.ts +32 -0
  31. package/dist/relay-connection/coalescing-agent-event-publisher.d.ts.map +1 -0
  32. package/dist/relay-connection/coalescing-agent-event-publisher.js +116 -0
  33. package/dist/relay-connection/coalescing-agent-event-publisher.js.map +1 -0
  34. package/dist/runtime.js +346 -314
  35. package/dist/runtime.js.map +4 -4
  36. package/package.json +1 -1
  37. package/dist/relay-connection/coalescing-activity-publisher.d.ts +0 -10
  38. package/dist/relay-connection/coalescing-activity-publisher.d.ts.map +0 -1
  39. package/dist/relay-connection/coalescing-activity-publisher.js +0 -54
  40. package/dist/relay-connection/coalescing-activity-publisher.js.map +0 -1
  41. package/dist/relay-connection/coalescing-narration-publisher.d.ts +0 -31
  42. package/dist/relay-connection/coalescing-narration-publisher.d.ts.map +0 -1
  43. package/dist/relay-connection/coalescing-narration-publisher.js +0 -61
  44. package/dist/relay-connection/coalescing-narration-publisher.js.map +0 -1
  45. package/dist/relay-connection/coalescing-text-publisher.d.ts +0 -26
  46. package/dist/relay-connection/coalescing-text-publisher.d.ts.map +0 -1
  47. package/dist/relay-connection/coalescing-text-publisher.js +0 -57
  48. package/dist/relay-connection/coalescing-text-publisher.js.map +0 -1
package/dist/index.js CHANGED
@@ -20955,7 +20955,7 @@ var userHistoryMessage = external_exports.strictObject({
20955
20955
  text: external_exports.string().max(SESSION_HISTORY_CHARACTER_LIMIT),
20956
20956
  images: external_exports.array(historyImage).max(8).readonly().optional()
20957
20957
  }).readonly();
20958
- var assistantHistoryMessage = external_exports.strictObject({
20958
+ var assistantHistoryMessageSchema = external_exports.strictObject({
20959
20959
  activities: external_exports.array(nativeMessageActivitySchema).max(100).readonly().default([]),
20960
20960
  content: external_exports.array(displayContentSchema).max(100).readonly().default([]),
20961
20961
  role: external_exports.literal("assistant"),
@@ -20964,7 +20964,7 @@ var assistantHistoryMessage = external_exports.strictObject({
20964
20964
  text: external_exports.string().max(SESSION_HISTORY_CHARACTER_LIMIT),
20965
20965
  images: external_exports.array(historyImage).max(8).readonly().optional()
20966
20966
  }).readonly();
20967
- var historyMessage = external_exports.discriminatedUnion("role", [userHistoryMessage, assistantHistoryMessage]);
20967
+ var historyMessage = external_exports.discriminatedUnion("role", [userHistoryMessage, assistantHistoryMessageSchema]);
20968
20968
  var availableSessionHistoryObjectSchema = external_exports.strictObject({
20969
20969
  status: external_exports.literal("available"),
20970
20970
  messages: external_exports.array(historyMessage).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
@@ -21035,6 +21035,7 @@ var activeTurnSnapshotSchema = external_exports.strictObject({
21035
21035
  truncated: external_exports.boolean(),
21036
21036
  epoch: identifierStringSchema,
21037
21037
  interaction: external_exports.discriminatedUnion("kind", [sessionPermissionRequestedEventSchema, sessionElicitationRequestedEventSchema]).nullable(),
21038
+ messages: external_exports.array(assistantHistoryMessageSchema).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
21038
21039
  sequence: external_exports.number().int().nonnegative(),
21039
21040
  state: external_exports.literal("running")
21040
21041
  }).readonly();
@@ -23729,6 +23730,48 @@ var AgentUpdateStream = class {
23729
23730
  };
23730
23731
  };
23731
23732
 
23733
+ // src/acp/runtime-operations.ts
23734
+ var RuntimeOperations = class {
23735
+ #shutdown = new AbortController();
23736
+ #pending = /* @__PURE__ */ new Set();
23737
+ #closing = null;
23738
+ run = async (options, operation) => {
23739
+ const signal = AbortSignal.any([options.signal, this.#shutdown.signal]);
23740
+ signal.throwIfAborted();
23741
+ const pending = Promise.resolve().then(() => operation({ ...options, signal }));
23742
+ this.#pending.add(pending);
23743
+ try {
23744
+ const result = await pending;
23745
+ signal.throwIfAborted();
23746
+ return result;
23747
+ } finally {
23748
+ this.#pending.delete(pending);
23749
+ }
23750
+ };
23751
+ close = (release) => {
23752
+ if (this.#closing !== null) {
23753
+ return this.#closing;
23754
+ }
23755
+ this.#shutdown.abort();
23756
+ this.#closing = (async () => {
23757
+ await Promise.allSettled([...this.#pending]);
23758
+ await release();
23759
+ })();
23760
+ return this.#closing;
23761
+ };
23762
+ };
23763
+ async function waitForSharedOperation(pending, signal) {
23764
+ signal.throwIfAborted();
23765
+ const cancelled = Promise.withResolvers();
23766
+ const abort = () => cancelled.reject(signal.reason);
23767
+ signal.addEventListener("abort", abort, { once: true });
23768
+ try {
23769
+ return await Promise.race([pending, cancelled.promise]);
23770
+ } finally {
23771
+ signal.removeEventListener("abort", abort);
23772
+ }
23773
+ }
23774
+
23732
23775
  // src/acp/session-config/session-config-protocol.ts
23733
23776
  import { methods as methods2 } from "@agentclientprotocol/sdk";
23734
23777
  var MAXIMUM_CONFIG_OPTIONS = 100;
@@ -30425,9 +30468,7 @@ var AgentSession = class _AgentSession {
30425
30468
  #configOptions = [];
30426
30469
  #prompted = false;
30427
30470
  #nativePrompt = null;
30428
- #replay = {
30429
- kind: "idle"
30430
- };
30471
+ #sessionLoad = { kind: "not-requested" };
30431
30472
  #restored = false;
30432
30473
  #sessionTitle = null;
30433
30474
  #sessionUpdatedAt = "";
@@ -30540,30 +30581,46 @@ var AgentSession = class _AgentSession {
30540
30581
  }
30541
30582
  };
30542
30583
  }
30543
- const history = new AcpHistoryReplay();
30544
- this.#replay = { kind: "capture", history };
30545
- try {
30546
- await this.race(
30547
- this.#connection.connection.agent.request(
30548
- methods3.agent.session.load,
30549
- {
30550
- additionalDirectories: [...this.#additionalDirectories],
30551
- cwd: this.#cwd,
30552
- mcpServers: [],
30553
- sessionId: this.#updates.sessionId()
30554
- },
30555
- { cancellationSignal: signal }
30556
- ),
30557
- "ACP agent exited while loading history",
30558
- signal
30559
- );
30560
- await this.#updates.drained();
30561
- signal.throwIfAborted();
30562
- return await embedLocalHistoryImages(await history.snapshot(), signal);
30563
- } finally {
30564
- this.#replay = { kind: "idle" };
30565
- }
30584
+ const loaded = await this.#loadSession(signal, "ACP agent exited while loading history");
30585
+ return await embedLocalHistoryImages(await loaded.history.snapshot(), signal);
30566
30586
  };
30587
+ async #loadSession(signal, exitMessage) {
30588
+ if (this.#sessionLoad.kind === "loaded") {
30589
+ return this.#sessionLoad;
30590
+ }
30591
+ if (this.#sessionLoad.kind === "capturing") {
30592
+ return await waitForSharedOperation(this.#sessionLoad.completion, signal);
30593
+ }
30594
+ const history = new AcpHistoryReplay();
30595
+ const completion = Promise.resolve().then(async () => {
30596
+ try {
30597
+ const response = await this.race(
30598
+ this.#connection.connection.agent.request(
30599
+ methods3.agent.session.load,
30600
+ {
30601
+ additionalDirectories: [...this.#additionalDirectories],
30602
+ cwd: this.#cwd,
30603
+ mcpServers: [],
30604
+ sessionId: this.#updates.sessionId()
30605
+ },
30606
+ { cancellationSignal: signal }
30607
+ ),
30608
+ exitMessage,
30609
+ signal
30610
+ );
30611
+ await this.#updates.drained();
30612
+ signal.throwIfAborted();
30613
+ const loaded = { history, kind: "loaded", response };
30614
+ this.#sessionLoad = loaded;
30615
+ return loaded;
30616
+ } catch (cause) {
30617
+ this.#sessionLoad = { kind: "not-requested" };
30618
+ throw cause;
30619
+ }
30620
+ });
30621
+ this.#sessionLoad = { completion, history, kind: "capturing" };
30622
+ return await completion;
30623
+ }
30567
30624
  prepareAgentContent = async (content) => {
30568
30625
  if (content.type === "image" && content.uri.length > 0) {
30569
30626
  const signal = AbortSignal.timeout(2e4);
@@ -30766,29 +30823,10 @@ var AgentSession = class _AgentSession {
30766
30823
  )
30767
30824
  );
30768
30825
  } else if (this.#capabilities.loadSession) {
30769
- this.#replay = { kind: "discard" };
30770
- try {
30771
- lifecycleResponse = await this.#metrics.measure(
30772
- "session-load",
30773
- async () => await this.race(
30774
- this.#connection.connection.agent.request(
30775
- methods3.agent.session.load,
30776
- {
30777
- additionalDirectories: [...this.#additionalDirectories],
30778
- cwd: this.#cwd,
30779
- mcpServers: [],
30780
- sessionId: this.#updates.sessionId()
30781
- },
30782
- { cancellationSignal: signal }
30783
- ),
30784
- "ACP agent exited while loading a session",
30785
- signal
30786
- )
30787
- );
30788
- } finally {
30789
- await this.#updates.drained();
30790
- this.#replay = { kind: "idle" };
30791
- }
30826
+ lifecycleResponse = await this.#metrics.measure(
30827
+ "session-load",
30828
+ async () => (await this.#loadSession(signal, "ACP agent exited while loading a session")).response
30829
+ );
30792
30830
  } else {
30793
30831
  throw new AcpExecutionError(
30794
30832
  "The ACP agent cannot restore its persisted session",
@@ -31173,10 +31211,10 @@ var AgentSession = class _AgentSession {
31173
31211
  #processUpdate = async (notification) => {
31174
31212
  this.assertNativeSession(notification.sessionId);
31175
31213
  const update = notification.update;
31176
- if (this.#replay.kind === "capture") {
31177
- await this.#replay.history.record(update);
31214
+ if (this.#sessionLoad.kind !== "not-requested") {
31215
+ await this.#sessionLoad.history.record(update);
31178
31216
  }
31179
- if (this.#replay.kind !== "idle" && (update.sessionUpdate === "user_message_chunk" || update.sessionUpdate === "agent_message_chunk" || update.sessionUpdate === "agent_thought_chunk" || update.sessionUpdate === "tool_call" || update.sessionUpdate === "tool_call_update" || update.sessionUpdate === "plan" || update.sessionUpdate === "plan_update" || update.sessionUpdate === "plan_removed")) {
31217
+ if (this.#sessionLoad.kind === "capturing" && (update.sessionUpdate === "user_message_chunk" || update.sessionUpdate === "agent_message_chunk" || update.sessionUpdate === "agent_thought_chunk" || update.sessionUpdate === "tool_call" || update.sessionUpdate === "tool_call_update" || update.sessionUpdate === "plan" || update.sessionUpdate === "plan_update" || update.sessionUpdate === "plan_removed")) {
31180
31218
  return;
31181
31219
  }
31182
31220
  if (update.sessionUpdate === "agent_message_chunk") {
@@ -31446,48 +31484,6 @@ var RetainedAgentProcesses = class {
31446
31484
  };
31447
31485
  };
31448
31486
 
31449
- // src/acp/runtime-operations.ts
31450
- var RuntimeOperations = class {
31451
- #shutdown = new AbortController();
31452
- #pending = /* @__PURE__ */ new Set();
31453
- #closing = null;
31454
- run = async (options, operation) => {
31455
- const signal = AbortSignal.any([options.signal, this.#shutdown.signal]);
31456
- signal.throwIfAborted();
31457
- const pending = Promise.resolve().then(() => operation({ ...options, signal }));
31458
- this.#pending.add(pending);
31459
- try {
31460
- const result = await pending;
31461
- signal.throwIfAborted();
31462
- return result;
31463
- } finally {
31464
- this.#pending.delete(pending);
31465
- }
31466
- };
31467
- close = (release) => {
31468
- if (this.#closing !== null) {
31469
- return this.#closing;
31470
- }
31471
- this.#shutdown.abort();
31472
- this.#closing = (async () => {
31473
- await Promise.allSettled([...this.#pending]);
31474
- await release();
31475
- })();
31476
- return this.#closing;
31477
- };
31478
- };
31479
- async function waitForPreparation(pending, signal) {
31480
- signal.throwIfAborted();
31481
- const cancelled = Promise.withResolvers();
31482
- const abort = () => cancelled.reject(signal.reason);
31483
- signal.addEventListener("abort", abort, { once: true });
31484
- try {
31485
- return await Promise.race([pending, cancelled.promise]);
31486
- } finally {
31487
- signal.removeEventListener("abort", abort);
31488
- }
31489
- }
31490
-
31491
31487
  // src/acp/agent-query-processes.ts
31492
31488
  var AgentQueryProcesses = class {
31493
31489
  #processesByQuery;
@@ -31534,7 +31530,7 @@ var AgentQueryProcesses = class {
31534
31530
  prepare = async (options) => {
31535
31531
  const pending = this.#processesByQuery.pending(options.sessionId);
31536
31532
  if (pending !== void 0) {
31537
- const runtime2 = await waitForPreparation(pending, options.signal);
31533
+ const runtime2 = await waitForSharedOperation(pending, options.signal);
31538
31534
  if (runtime2.belongsTo(options.agent.id, options.cwd, options.additionalDirectories)) {
31539
31535
  this.#processesByQuery.touch(options.sessionId, runtime2);
31540
31536
  return runtime2.prepared();
@@ -31952,7 +31948,7 @@ var AgentRuntimeManager = class {
31952
31948
  if (pending !== void 0) {
31953
31949
  const runtime2 = await metrics.measure(
31954
31950
  "session-preparation-wait",
31955
- async () => await waitForPreparation(pending, options2.signal)
31951
+ async () => await waitForSharedOperation(pending, options2.signal)
31956
31952
  );
31957
31953
  if (runtime2.belongsTo(options2.agent.id, options2.cwd, options2.additionalDirectories)) {
31958
31954
  this.#executionProcesses.touch(options2.sessionId, runtime2);
@@ -32042,7 +32038,7 @@ var AgentRuntimeManager = class {
32042
32038
  prepareExecutionSession = async (options) => this.#operations.run(options, async (options2) => {
32043
32039
  const pending = this.#executionProcesses.pending(options2.sessionId);
32044
32040
  if (pending !== void 0) {
32045
- await waitForPreparation(pending, options2.signal);
32041
+ await waitForSharedOperation(pending, options2.signal);
32046
32042
  return await this.prepareExecutionSession(options2);
32047
32043
  }
32048
32044
  const existing = this.#executionProcesses.get(options2.sessionId);
@@ -32096,7 +32092,7 @@ var AgentRuntimeManager = class {
32096
32092
  }
32097
32093
  const pending = this.#executionProcesses.pending(options2.sessionId);
32098
32094
  if (pending !== void 0) {
32099
- await waitForPreparation(pending, options2.signal);
32095
+ await waitForSharedOperation(pending, options2.signal);
32100
32096
  }
32101
32097
  if (this.#executions.command(options2.sessionId) !== options2.targetCommandId) {
32102
32098
  throw new AcpExecutionError("The target turn is no longer active", {}, "steering_target_unavailable");
@@ -38662,6 +38658,7 @@ var ActiveDaemonTurn = class {
38662
38658
  #text = "";
38663
38659
  #activities = /* @__PURE__ */ new Map();
38664
38660
  #content = /* @__PURE__ */ new Map();
38661
+ #timeline = [];
38665
38662
  #sequence = 0;
38666
38663
  #interaction = null;
38667
38664
  #epoch = decodeIdentifier(randomUUID2());
@@ -38705,12 +38702,16 @@ var ActiveDaemonTurn = class {
38705
38702
  recordEvent = (event) => {
38706
38703
  if (event.kind === AGENT_MESSAGE_DELTA_KIND) {
38707
38704
  this.#text += event.text;
38705
+ this.appendMessageText(event.messageId, event.text);
38708
38706
  return this.updated();
38709
38707
  }
38710
38708
  if (event.sessionId !== this.command.sessionId || "commandId" in event && event.commandId !== this.command.commandId) {
38711
38709
  return event;
38712
38710
  }
38713
38711
  if (event.kind === AGENT_ACTIVITY_KIND) {
38712
+ if (!this.#activities.has(event.activityId)) {
38713
+ this.#timeline = [...this.#timeline, { activityId: event.activityId, kind: "activity" }];
38714
+ }
38714
38715
  this.#activities.set(event.activityId, {
38715
38716
  activityId: event.activityId,
38716
38717
  activityType: event.activityType,
@@ -38726,6 +38727,9 @@ var ActiveDaemonTurn = class {
38726
38727
  });
38727
38728
  } else if (event.kind === AGENT_ACTIVITY_NARRATION_KIND) {
38728
38729
  const previous = this.#activities.get(event.activityId);
38730
+ if (previous === void 0) {
38731
+ this.#timeline = [...this.#timeline, { activityId: event.activityId, kind: "activity" }];
38732
+ }
38729
38733
  this.#activities.set(event.activityId, {
38730
38734
  activityId: event.activityId,
38731
38735
  activityType: event.activityType,
@@ -38741,6 +38745,24 @@ var ActiveDaemonTurn = class {
38741
38745
  });
38742
38746
  } else if (event.kind === AGENT_CONTENT_KIND) {
38743
38747
  this.#content.set(event.contentId, event.content);
38748
+ const target = this.#timeline.findLastIndex(
38749
+ (entry) => entry.kind === "message" && entry.messageId === event.messageId
38750
+ );
38751
+ if (target < 0) {
38752
+ this.#timeline = [
38753
+ ...this.#timeline,
38754
+ {
38755
+ content: /* @__PURE__ */ new Map([[event.contentId, event.content]]),
38756
+ kind: "message",
38757
+ messageId: event.messageId,
38758
+ text: ""
38759
+ }
38760
+ ];
38761
+ } else {
38762
+ this.#timeline = this.#timeline.map(
38763
+ (entry, index) => index === target && entry.kind === "message" ? { ...entry, content: new Map([...entry.content, [event.contentId, event.content]]) } : entry
38764
+ );
38765
+ }
38744
38766
  } else if (event.kind === SESSION_PERMISSION_REQUESTED_KIND || event.kind === SESSION_ELICITATION_REQUESTED_KIND) {
38745
38767
  this.#interaction = event;
38746
38768
  } else if ((event.kind === SESSION_PERMISSION_RESOLVED_KIND || event.kind === SESSION_ELICITATION_RESOLVED_KIND) && this.#interaction?.interactionId === event.interactionId) {
@@ -38751,6 +38773,49 @@ var ActiveDaemonTurn = class {
38751
38773
  }
38752
38774
  return event;
38753
38775
  };
38776
+ appendMessageText(messageId, text2) {
38777
+ let remaining = text2;
38778
+ while (remaining.length > 0) {
38779
+ const latest = this.#timeline.at(-1);
38780
+ if (latest?.kind === "message" && latest.messageId === messageId) {
38781
+ const available = SESSION_HISTORY_CHARACTER_LIMIT - latest.text.length;
38782
+ if (available > 0) {
38783
+ this.#timeline = [
38784
+ ...this.#timeline.slice(0, -1),
38785
+ { ...latest, text: `${latest.text}${remaining.slice(0, available)}` }
38786
+ ];
38787
+ remaining = remaining.slice(available);
38788
+ continue;
38789
+ }
38790
+ }
38791
+ this.#timeline = [
38792
+ ...this.#timeline,
38793
+ {
38794
+ content: /* @__PURE__ */ new Map(),
38795
+ kind: "message",
38796
+ messageId,
38797
+ text: remaining.slice(0, SESSION_HISTORY_CHARACTER_LIMIT)
38798
+ }
38799
+ ];
38800
+ remaining = remaining.slice(SESSION_HISTORY_CHARACTER_LIMIT);
38801
+ }
38802
+ }
38803
+ timelineMessages() {
38804
+ return this.#timeline.flatMap((entry) => {
38805
+ if (entry.kind === "message") {
38806
+ return [
38807
+ {
38808
+ activities: [],
38809
+ content: [...entry.content.values()],
38810
+ role: "assistant",
38811
+ text: entry.text
38812
+ }
38813
+ ];
38814
+ }
38815
+ const activity2 = this.#activities.get(entry.activityId);
38816
+ return activity2 === void 0 ? [] : [{ activities: [activity2], content: [], role: "assistant", text: "" }];
38817
+ });
38818
+ }
38754
38819
  updated = () => {
38755
38820
  this.#sequence += 1;
38756
38821
  const turn = this.snapshot();
@@ -38759,19 +38824,28 @@ var ActiveDaemonTurn = class {
38759
38824
  }
38760
38825
  return { kind: "session.turn.updated", sessionId: this.command.sessionId, turn };
38761
38826
  };
38762
- snapshot = () => this.#dispatch.kind === "running" ? {
38763
- activities: [...this.#activities.values()].sort((left, right) => left.sequence - right.sequence),
38764
- commandId: decodeIdentifier(this.command.commandId),
38765
- content: [...this.#content.values()],
38766
- prompt: this.command.prompt,
38767
- text: this.#text,
38768
- truncated: false,
38769
- epoch: this.#epoch,
38770
- interaction: this.#interaction,
38771
- sequence: this.#sequence,
38772
- state: "running"
38773
- } : null;
38827
+ snapshot = () => {
38828
+ if (this.#dispatch.kind !== "running") {
38829
+ return null;
38830
+ }
38831
+ const completeMessages = this.timelineMessages();
38832
+ const messages = completeMessages.slice(-SESSION_HISTORY_MESSAGE_LIMIT);
38833
+ return {
38834
+ activities: [...this.#activities.values()].sort((left, right) => left.sequence - right.sequence),
38835
+ commandId: decodeIdentifier(this.command.commandId),
38836
+ content: [...this.#content.values()],
38837
+ prompt: this.command.prompt,
38838
+ text: this.#text,
38839
+ truncated: messages.length !== completeMessages.length,
38840
+ epoch: this.#epoch,
38841
+ interaction: this.#interaction,
38842
+ messages,
38843
+ sequence: this.#sequence,
38844
+ state: "running"
38845
+ };
38846
+ };
38774
38847
  matches = (cancellation) => cancellation.commandId === this.command.commandId && cancellation.sessionId === this.command.sessionId;
38848
+ matchesInteraction = (interactionId, sessionId) => this.command.sessionId === sessionId && this.#interaction?.interactionId === interactionId;
38775
38849
  requestCancellation = () => {
38776
38850
  if (this.#cancellationRequested) {
38777
38851
  return "already-requested";
@@ -38840,6 +38914,13 @@ var DaemonTurnRegistry = class {
38840
38914
  return turn.recordEvent(event);
38841
38915
  }
38842
38916
  }
38917
+ if (event.kind === SESSION_PERMISSION_RESOLVED_KIND || event.kind === SESSION_ELICITATION_RESOLVED_KIND) {
38918
+ for (const turn of this.#turns.values()) {
38919
+ if (turn.matchesInteraction(event.interactionId, event.sessionId)) {
38920
+ return turn.recordEvent(event);
38921
+ }
38922
+ }
38923
+ }
38843
38924
  return event;
38844
38925
  };
38845
38926
  executionSnapshot = async (matches) => {
@@ -41072,6 +41153,34 @@ function liveHistoryCoveredTurnRanges(history) {
41072
41153
  function historyMessageCharacters(message) {
41073
41154
  return message.text.length + (message.role === "assistant" ? JSON.stringify(message.activities).length + JSON.stringify(message.content).length : 0);
41074
41155
  }
41156
+ function boundedActiveMessages(messages, messageLimit, characterLimit) {
41157
+ const selected = [];
41158
+ let remainingCharacters = characterLimit;
41159
+ for (let index = messages.length - 1; index >= 0 && selected.length < messageLimit; index -= 1) {
41160
+ const message = messages[index];
41161
+ if (message === void 0) {
41162
+ break;
41163
+ }
41164
+ const characters = historyMessageCharacters(message);
41165
+ if (characters <= remainingCharacters) {
41166
+ selected.unshift(message);
41167
+ remainingCharacters -= characters;
41168
+ continue;
41169
+ }
41170
+ const structuredCharacters = characters - message.text.length;
41171
+ if (selected.length === 0 && structuredCharacters <= remainingCharacters) {
41172
+ const textCharacters = remainingCharacters - structuredCharacters;
41173
+ selected.unshift({ ...message, text: textCharacters === 0 ? "" : message.text.slice(-textCharacters) });
41174
+ remainingCharacters = 0;
41175
+ }
41176
+ break;
41177
+ }
41178
+ return {
41179
+ characters: characterLimit - remainingCharacters,
41180
+ messages: selected,
41181
+ truncated: selected.length !== messages.length
41182
+ };
41183
+ }
41075
41184
  function paginateAcpSessionHistory(history, sessionId, cursor, limit) {
41076
41185
  if (history.status === "unavailable") {
41077
41186
  if (cursor !== null) {
@@ -41102,30 +41211,19 @@ function paginateLiveSessionHistory(history, activeTurn, sessionId, cursor, limi
41102
41211
  if (activeTurn === null || cursor !== null) {
41103
41212
  return paginateAcpSessionHistory(history, sessionId, cursor, limit);
41104
41213
  }
41105
- const activeMessageOverhead = 4;
41106
- const activeStructuredCharacters = JSON.stringify(activeTurn.activities).length + JSON.stringify(activeTurn.content).length;
41107
- const maximumActiveTextLength = Math.max(
41108
- 0,
41109
- SESSION_HISTORY_CHARACTER_LIMIT - activeTurn.prompt.length - activeStructuredCharacters - activeMessageOverhead
41110
- );
41111
- const activeText = activeTurn.text.slice(-maximumActiveTextLength);
41112
- const completeActiveMessages = [
41113
- { role: "user", text: activeTurn.prompt },
41114
- {
41115
- activities: activeTurn.activities,
41116
- content: activeTurn.content,
41117
- role: "assistant",
41118
- text: activeText
41119
- }
41120
- ];
41121
41214
  if (history.status === "unavailable") {
41215
+ const bounded3 = boundedActiveMessages(
41216
+ activeTurn.messages,
41217
+ Math.max(0, limit - 1),
41218
+ Math.max(0, SESSION_HISTORY_CHARACTER_LIMIT - activeTurn.prompt.length)
41219
+ );
41122
41220
  return {
41123
41221
  coveredCommandIds: [],
41124
41222
  coveredMessageIds: [],
41125
- messages: completeActiveMessages,
41223
+ messages: [{ role: "user", text: activeTurn.prompt }, ...bounded3.messages],
41126
41224
  nextCursor: null,
41127
41225
  status: "available",
41128
- truncated: activeTurn.truncated || activeText.length !== activeTurn.text.length
41226
+ truncated: activeTurn.truncated || bounded3.truncated
41129
41227
  };
41130
41228
  }
41131
41229
  const activeUserIndex = history.coveredCommandIds.includes(activeTurn.commandId) ? history.messages.findLastIndex((message) => message.role === "user") : -1;
@@ -41140,9 +41238,18 @@ function paginateLiveSessionHistory(history, activeTurn, sessionId, cursor, limi
41140
41238
  };
41141
41239
  }
41142
41240
  const latestNativeMessage = history.messages.at(-1);
41143
- const activeMessages = activeUserIndex >= 0 || latestNativeMessage?.role === "user" && latestNativeMessage.text === activeTurn.prompt ? completeActiveMessages.slice(1) : completeActiveMessages;
41241
+ const includeActivePrompt = activeUserIndex < 0 && !(latestNativeMessage?.role === "user" && latestNativeMessage.text === activeTurn.prompt);
41242
+ const bounded2 = boundedActiveMessages(
41243
+ activeTurn.messages,
41244
+ Math.max(0, limit - (includeActivePrompt ? 1 : 0)),
41245
+ Math.max(0, SESSION_HISTORY_CHARACTER_LIMIT - (includeActivePrompt ? activeTurn.prompt.length : 0))
41246
+ );
41247
+ const activeMessages = [
41248
+ ...includeActivePrompt ? [{ role: "user", text: activeTurn.prompt }] : [],
41249
+ ...bounded2.messages
41250
+ ];
41144
41251
  let historicalMessageCount = 0;
41145
- let remainingCharacters = SESSION_HISTORY_CHARACTER_LIMIT - activeText.length - activeMessageOverhead - activeStructuredCharacters - (activeMessages.length === completeActiveMessages.length ? activeTurn.prompt.length : 0);
41252
+ let remainingCharacters = SESSION_HISTORY_CHARACTER_LIMIT - bounded2.characters - (includeActivePrompt ? activeTurn.prompt.length : 0);
41146
41253
  const historicalMessageLimit = Math.max(0, limit - activeMessages.length);
41147
41254
  for (let index = history.messages.length - 1; index >= 0 && historicalMessageCount < historicalMessageLimit; index -= 1) {
41148
41255
  const message = history.messages[index];
@@ -41167,7 +41274,7 @@ function paginateLiveSessionHistory(history, activeTurn, sessionId, cursor, limi
41167
41274
  return {
41168
41275
  ...page,
41169
41276
  messages: [...page.messages, ...activeMessages],
41170
- truncated: page.truncated || activeTurn.truncated || activeText.length !== activeTurn.text.length
41277
+ truncated: page.truncated || activeTurn.truncated || bounded2.truncated
41171
41278
  };
41172
41279
  }
41173
41280
  function mergeLiveSessionHistory(history, activeTurn, sessionId) {
@@ -41477,167 +41584,113 @@ function warnIgnoredSetting(audit, event, commandId, sessionId, agentId, selecti
41477
41584
  `);
41478
41585
  }
41479
41586
 
41480
- // src/relay-connection/coalescing-activity-publisher.ts
41481
- var AGENT_ACTIVITY_COALESCING_MILLISECONDS = 100;
41482
- var CoalescingDaemonActivityPublisher = class {
41483
- #pending = /* @__PURE__ */ new Map();
41587
+ // src/relay-connection/coalescing-agent-event-publisher.ts
41588
+ var AGENT_EVENT_COALESCING_MILLISECONDS = 100;
41589
+ var AGENT_EVENT_TEXT_MAXIMUM_LENGTH = 1e5;
41590
+ var CoalescingAgentEventPublisher = class {
41591
+ #entries = [];
41484
41592
  #publish;
41485
41593
  #publishedActivityIds = /* @__PURE__ */ new Set();
41486
- #scheduled = /* @__PURE__ */ new Map();
41594
+ #scheduled = null;
41487
41595
  #timer;
41488
41596
  constructor(timer, publish) {
41489
41597
  this.#publish = publish;
41490
41598
  this.#timer = timer;
41491
41599
  }
41492
- flush = () => {
41493
- const activities = [...this.#pending.values()].sort((left, right) => left.sequence - right.sequence);
41494
- for (const task of this.#scheduled.values()) {
41495
- task.cancel();
41496
- }
41497
- this.#pending.clear();
41498
- this.#scheduled.clear();
41499
- for (const activity2 of activities) {
41500
- this.#publish(activity2);
41501
- }
41502
- };
41503
- record = (activity2) => {
41504
- if (activity2.status !== "pending" && activity2.status !== "running") {
41505
- this.#discardPending(activity2.activityId);
41506
- this.#publishedActivityIds.add(activity2.activityId);
41507
- this.#publish(activity2);
41508
- return Promise.resolve();
41509
- }
41510
- if (!this.#publishedActivityIds.has(activity2.activityId)) {
41511
- this.#publishedActivityIds.add(activity2.activityId);
41512
- this.#publish(activity2);
41513
- return Promise.resolve();
41514
- }
41515
- this.#pending.set(activity2.activityId, activity2);
41516
- if (!this.#scheduled.has(activity2.activityId)) {
41517
- this.#scheduled.set(
41518
- activity2.activityId,
41519
- this.#timer.schedule(
41520
- () => this.#flushActivity(activity2.activityId),
41521
- AGENT_ACTIVITY_COALESCING_MILLISECONDS
41522
- )
41523
- );
41524
- }
41525
- return Promise.resolve();
41526
- };
41527
- #discardPending = (activityId) => {
41528
- this.#scheduled.get(activityId)?.cancel();
41529
- this.#scheduled.delete(activityId);
41530
- this.#pending.delete(activityId);
41531
- };
41532
- #flushActivity = (activityId) => {
41533
- const activity2 = this.#pending.get(activityId);
41534
- this.#discardPending(activityId);
41535
- if (activity2 !== void 0) {
41536
- this.#publish(activity2);
41537
- }
41538
- };
41539
- };
41540
-
41541
- // src/relay-connection/coalescing-narration-publisher.ts
41542
- var CoalescingNarrationPublisher = class {
41543
- #coalescingMilliseconds;
41544
- #maximumTextLength;
41545
- #publish;
41546
- #timer;
41547
- #pending = /* @__PURE__ */ new Map();
41548
- #scheduled = null;
41549
- constructor(timer, publish, coalescingMilliseconds, maximumTextLength) {
41550
- this.#publish = publish;
41551
- this.#timer = timer;
41552
- this.#coalescingMilliseconds = coalescingMilliseconds;
41553
- this.#maximumTextLength = maximumTextLength;
41554
- }
41555
- /** Emit every buffered increment now, cancelling the pending flush. */
41556
41600
  flush = () => {
41557
41601
  this.#scheduled?.cancel();
41558
41602
  this.#scheduled = null;
41559
- const increments = [...this.#pending.entries()].map(
41560
- ([activityId, pending]) => ({
41561
- activityId,
41562
- activityType: pending.activityType,
41563
- sequence: pending.sequence,
41564
- text: pending.text
41565
- })
41566
- );
41567
- this.#pending.clear();
41568
- for (const increment of increments) {
41569
- this.#publish(increment);
41603
+ const entries = this.#entries;
41604
+ this.#entries = [];
41605
+ for (const entry of entries) {
41606
+ this.#publish(entry);
41570
41607
  }
41571
41608
  };
41572
- /**
41573
- * Buffer an increment, emitting the buffered text when it would exceed the
41574
- * protocol's per-event text limit so no event is rejected by the codec.
41575
- */
41576
- record = (increment) => {
41577
- if (increment.text.length === 0) {
41578
- return;
41579
- }
41580
- const previous = this.#pending.get(increment.activityId);
41581
- if (previous !== void 0 && previous.text.length + increment.text.length > this.#maximumTextLength) {
41609
+ recordActivity = (activity2) => {
41610
+ const latest = this.#entries.at(-1);
41611
+ this.#entries = latest?.kind === "activity" && latest.activity.activityId === activity2.activityId ? [...this.#entries.slice(0, -1), { activity: activity2, kind: "activity" }] : [...this.#entries, { activity: activity2, kind: "activity" }];
41612
+ const first = !this.#publishedActivityIds.has(activity2.activityId);
41613
+ this.#publishedActivityIds.add(activity2.activityId);
41614
+ if (first || activity2.status !== "pending" && activity2.status !== "running") {
41582
41615
  this.flush();
41616
+ } else {
41617
+ this.schedule();
41583
41618
  }
41584
- const current = this.#pending.get(increment.activityId);
41585
- this.#pending.set(increment.activityId, {
41586
- activityType: increment.activityType,
41587
- sequence: increment.sequence,
41588
- text: `${current?.text ?? ""}${increment.text}`
41589
- });
41590
- this.#scheduled ??= this.#timer.schedule(this.flush, this.#coalescingMilliseconds);
41619
+ return Promise.resolve();
41591
41620
  };
41592
- };
41593
-
41594
- // src/relay-connection/coalescing-text-publisher.ts
41595
- var CoalescingTextPublisher = class {
41596
- #coalescingMilliseconds;
41597
- #maximumTextLength;
41598
- #publish;
41599
- #timer;
41600
- #messageId = "";
41601
- #scheduled = null;
41602
- #text = "";
41603
- constructor(timer, publish, coalescingMilliseconds, maximumTextLength) {
41604
- this.#publish = publish;
41605
- this.#timer = timer;
41606
- this.#coalescingMilliseconds = coalescingMilliseconds;
41607
- this.#maximumTextLength = maximumTextLength;
41608
- }
41609
- /** Emit any buffered text now, cancelling the pending flush. */
41610
- flush = () => {
41611
- this.#scheduled?.cancel();
41612
- this.#scheduled = null;
41613
- const messageId = this.#messageId;
41614
- const text2 = this.#text;
41615
- this.#messageId = "";
41616
- this.#text = "";
41617
- if (text2.length > 0) {
41618
- this.#publish(messageId, text2);
41621
+ recordNarration = (increment) => {
41622
+ if (increment.text.length === 0) {
41623
+ return Promise.resolve();
41624
+ }
41625
+ let remaining = increment.text;
41626
+ while (remaining.length > 0) {
41627
+ const latest = this.#entries.at(-1);
41628
+ if (latest?.kind === "narration" && latest.increment.activityId === increment.activityId) {
41629
+ const available = AGENT_EVENT_TEXT_MAXIMUM_LENGTH - latest.increment.text.length;
41630
+ if (available > 0) {
41631
+ this.#entries = [
41632
+ ...this.#entries.slice(0, -1),
41633
+ {
41634
+ increment: {
41635
+ ...increment,
41636
+ text: `${latest.increment.text}${remaining.slice(0, available)}`
41637
+ },
41638
+ kind: "narration"
41639
+ }
41640
+ ];
41641
+ remaining = remaining.slice(available);
41642
+ continue;
41643
+ }
41644
+ }
41645
+ this.#entries = [
41646
+ ...this.#entries,
41647
+ {
41648
+ increment: { ...increment, text: remaining.slice(0, AGENT_EVENT_TEXT_MAXIMUM_LENGTH) },
41649
+ kind: "narration"
41650
+ }
41651
+ ];
41652
+ remaining = remaining.slice(AGENT_EVENT_TEXT_MAXIMUM_LENGTH);
41619
41653
  }
41654
+ this.schedule();
41655
+ return Promise.resolve();
41620
41656
  };
41621
- /**
41622
- * Buffer a chunk, emitting the buffered text when the message changes or the
41623
- * buffer would exceed the protocol's per-event text limit.
41624
- */
41625
- record = (messageId, text2) => {
41657
+ recordText = (text2, messageId) => {
41626
41658
  if (text2.length === 0) {
41627
- return;
41659
+ return Promise.resolve();
41628
41660
  }
41629
- if (this.#text.length > 0 && (this.#messageId !== messageId || this.#text.length + text2.length > this.#maximumTextLength)) {
41630
- this.flush();
41661
+ let remaining = text2;
41662
+ while (remaining.length > 0) {
41663
+ const latest = this.#entries.at(-1);
41664
+ if (latest?.kind === "text" && latest.messageId === messageId) {
41665
+ const available = AGENT_EVENT_TEXT_MAXIMUM_LENGTH - latest.text.length;
41666
+ if (available > 0) {
41667
+ this.#entries = [
41668
+ ...this.#entries.slice(0, -1),
41669
+ { ...latest, text: `${latest.text}${remaining.slice(0, available)}` }
41670
+ ];
41671
+ remaining = remaining.slice(available);
41672
+ continue;
41673
+ }
41674
+ }
41675
+ this.#entries = [
41676
+ ...this.#entries,
41677
+ {
41678
+ kind: "text",
41679
+ messageId,
41680
+ text: remaining.slice(0, AGENT_EVENT_TEXT_MAXIMUM_LENGTH)
41681
+ }
41682
+ ];
41683
+ remaining = remaining.slice(AGENT_EVENT_TEXT_MAXIMUM_LENGTH);
41631
41684
  }
41632
- this.#messageId = messageId;
41633
- this.#text = `${this.#text}${text2}`;
41634
- this.#scheduled ??= this.#timer.schedule(this.flush, this.#coalescingMilliseconds);
41685
+ this.schedule();
41686
+ return Promise.resolve();
41635
41687
  };
41688
+ schedule() {
41689
+ this.#scheduled ??= this.#timer.schedule(this.flush, AGENT_EVENT_COALESCING_MILLISECONDS);
41690
+ }
41636
41691
  };
41637
41692
 
41638
41693
  // src/daemon-prompt-executor.ts
41639
- var AGENT_TEXT_COALESCING_MILLISECONDS = 100;
41640
- var AGENT_TEXT_MAXIMUM_LENGTH = 1e5;
41641
41694
  function daemonActivity(command, activity2) {
41642
41695
  return {
41643
41696
  activityId: activity2.activityId,
@@ -41673,41 +41726,30 @@ async function executePrompt({
41673
41726
  recordLiveEvent,
41674
41727
  cancellationRequested
41675
41728
  }) {
41676
- const narration = new CoalescingNarrationPublisher(
41677
- timer,
41678
- (increment) => {
41679
- const event = {
41680
- activityId: increment.activityId,
41681
- activityType: increment.activityType,
41729
+ const events = new CoalescingAgentEventPublisher(timer, (event) => {
41730
+ if (event.kind === "text") {
41731
+ publisher.publish(
41732
+ command.sessionId,
41733
+ recordLiveEvent({ kind: AGENT_MESSAGE_DELTA_KIND, messageId: event.messageId, text: event.text })
41734
+ );
41735
+ return;
41736
+ }
41737
+ if (event.kind === "narration") {
41738
+ const recorded = {
41739
+ activityId: event.increment.activityId,
41740
+ activityType: event.increment.activityType,
41682
41741
  commandId: command.commandId,
41683
41742
  kind: AGENT_ACTIVITY_NARRATION_KIND,
41684
- sequence: increment.sequence,
41743
+ sequence: event.increment.sequence,
41685
41744
  sessionId: command.sessionId,
41686
- text: increment.text
41745
+ text: event.increment.text
41687
41746
  };
41688
- publisher.publish(command.sessionId, recordLiveEvent(event));
41689
- },
41690
- AGENT_ACTIVITY_COALESCING_MILLISECONDS,
41691
- AGENT_TEXT_MAXIMUM_LENGTH
41692
- );
41693
- const activities = new CoalescingDaemonActivityPublisher(timer, (activity2) => {
41694
- if (activity2.status !== "pending" && activity2.status !== "running") {
41695
- narration.flush();
41747
+ publisher.publish(command.sessionId, recordLiveEvent(recorded));
41748
+ return;
41696
41749
  }
41697
- const event = daemonActivity(command, activity2);
41698
- publisher.publish(command.sessionId, recordLiveEvent(event));
41750
+ const activity2 = daemonActivity(command, event.activity);
41751
+ publisher.publish(command.sessionId, recordLiveEvent(activity2));
41699
41752
  });
41700
- const text2 = new CoalescingTextPublisher(
41701
- timer,
41702
- (messageId, delta) => {
41703
- publisher.publish(
41704
- command.sessionId,
41705
- recordLiveEvent({ kind: AGENT_MESSAGE_DELTA_KIND, messageId, text: delta })
41706
- );
41707
- },
41708
- AGENT_TEXT_COALESCING_MILLISECONDS,
41709
- AGENT_TEXT_MAXIMUM_LENGTH
41710
- );
41711
41753
  try {
41712
41754
  const resolved = await resolveSessionDirectories(
41713
41755
  directories,
@@ -41796,15 +41838,9 @@ async function executePrompt({
41796
41838
  cwd: resolved.cwd,
41797
41839
  disposition: availability.disposition,
41798
41840
  images: attachments.images,
41799
- onActivity: activities.record,
41800
- onNarration: (increment) => {
41801
- narration.record(increment);
41802
- return Promise.resolve();
41803
- },
41804
- onText: (delta, messageId) => {
41805
- text2.record(messageId, delta);
41806
- return Promise.resolve();
41807
- },
41841
+ onActivity: events.recordActivity,
41842
+ onNarration: events.recordNarration,
41843
+ onText: events.recordText,
41808
41844
  prompt: command.prompt,
41809
41845
  resources: attachments.resources,
41810
41846
  sessionId: command.sessionId,
@@ -41813,9 +41849,7 @@ async function executePrompt({
41813
41849
  });
41814
41850
  stopReason = result.stopReason;
41815
41851
  }
41816
- text2.flush();
41817
- narration.flush();
41818
- activities.flush();
41852
+ events.flush();
41819
41853
  publisher.publish(command.sessionId, {
41820
41854
  commandId: command.commandId,
41821
41855
  kind: SESSION_COMPLETED_KIND,
@@ -41829,9 +41863,7 @@ async function executePrompt({
41829
41863
  sessionId: command.sessionId
41830
41864
  });
41831
41865
  } catch (error62) {
41832
- text2.flush();
41833
- narration.flush();
41834
- activities.flush();
41866
+ events.flush();
41835
41867
  if (signal.aborted && cancellationRequested()) {
41836
41868
  publisher.publish(command.sessionId, {
41837
41869
  commandId: command.commandId,