@moxt-ai/mobius 0.0.170 → 0.0.172

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 (55) hide show
  1. package/dist/acp/agent-session.d.ts.map +1 -1
  2. package/dist/acp/agent-session.js +141 -42
  3. package/dist/acp/agent-session.js.map +1 -1
  4. package/dist/acp/codex/agent.d.ts.map +1 -1
  5. package/dist/acp/codex/agent.js +45 -12
  6. package/dist/acp/codex/agent.js.map +1 -1
  7. package/dist/acp/run-prompt.d.ts.map +1 -1
  8. package/dist/acp/run-prompt.js +7 -1
  9. package/dist/acp/run-prompt.js.map +1 -1
  10. package/dist/acp/session-contracts.d.ts +9 -4
  11. package/dist/acp/session-contracts.d.ts.map +1 -1
  12. package/dist/acp/session-contracts.js +1 -1
  13. package/dist/acp/session-contracts.js.map +1 -1
  14. package/dist/acp/session-history.d.ts +6 -3
  15. package/dist/acp/session-history.d.ts.map +1 -1
  16. package/dist/acp/session-history.js +41 -17
  17. package/dist/acp/session-history.js.map +1 -1
  18. package/dist/acp/session-interactions.d.ts +2 -0
  19. package/dist/acp/session-interactions.d.ts.map +1 -1
  20. package/dist/acp/session-interactions.js +36 -8
  21. package/dist/acp/session-interactions.js.map +1 -1
  22. package/dist/acp/session-store.d.ts +0 -13
  23. package/dist/acp/session-store.d.ts.map +1 -1
  24. package/dist/acp/session-store.js +3 -65
  25. package/dist/acp/session-store.js.map +1 -1
  26. package/dist/cli.js +337 -374
  27. package/dist/cli.js.map +4 -4
  28. package/dist/daemon-command-handler.js +1 -1
  29. package/dist/daemon-command-handler.js.map +1 -1
  30. package/dist/daemon-history-commands.d.ts +2 -1
  31. package/dist/daemon-history-commands.d.ts.map +1 -1
  32. package/dist/daemon-history-commands.js +9 -20
  33. package/dist/daemon-history-commands.js.map +1 -1
  34. package/dist/daemon-observers.d.ts +3 -3
  35. package/dist/daemon-observers.d.ts.map +1 -1
  36. package/dist/daemon-observers.js +2 -18
  37. package/dist/daemon-observers.js.map +1 -1
  38. package/dist/daemon-prompt-executor.d.ts.map +1 -1
  39. package/dist/daemon-prompt-executor.js +3 -1
  40. package/dist/daemon-prompt-executor.js.map +1 -1
  41. package/dist/index.js +343 -374
  42. package/dist/index.js.map +4 -4
  43. package/dist/relay-connection/session-event-publisher.d.ts +1 -6
  44. package/dist/relay-connection/session-event-publisher.d.ts.map +1 -1
  45. package/dist/relay-connection/session-event-publisher.js +2 -7
  46. package/dist/relay-connection/session-event-publisher.js.map +1 -1
  47. package/dist/run-daemon.js +2 -2
  48. package/dist/run-daemon.js.map +1 -1
  49. package/dist/runtime.js +340 -377
  50. package/dist/runtime.js.map +4 -4
  51. package/dist/session-event-log-v2.d.ts +18 -9
  52. package/dist/session-event-log-v2.d.ts.map +1 -1
  53. package/dist/session-event-log-v2.js +39 -156
  54. package/dist/session-event-log-v2.js.map +1 -1
  55. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -3381,7 +3381,7 @@ var program = new Command();
3381
3381
  // package.json
3382
3382
  var package_default = {
3383
3383
  name: "@moxt-ai/mobius",
3384
- version: "0.0.170",
3384
+ version: "0.0.172",
3385
3385
  description: "Mobius CLI for pairing and running local AI agent services.",
3386
3386
  type: "module",
3387
3387
  bin: {
@@ -25707,8 +25707,8 @@ function promptInput(prompt) {
25707
25707
  function isCompactPrompt(prompt) {
25708
25708
  return prompt.length === 1 && prompt[0]?.type === "text" && prompt[0].text.trim() === "/compact";
25709
25709
  }
25710
- function steeringPromptInput(prompt) {
25711
- const input2 = [];
25710
+ function steeringPrompt(prompt) {
25711
+ const blocks = [];
25712
25712
  for (const block of prompt) {
25713
25713
  if (typeof block !== "object" || block === null) {
25714
25714
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
@@ -25719,7 +25719,7 @@ function steeringPromptInput(prompt) {
25719
25719
  if (typeof text2 !== "string") {
25720
25720
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
25721
25721
  }
25722
- input2.push({ text: text2, text_elements: [], type: "text" });
25722
+ blocks.push({ content: { text: text2, type: "text" }, input: { text: text2, text_elements: [], type: "text" } });
25723
25723
  continue;
25724
25724
  }
25725
25725
  if (type === "image") {
@@ -25728,7 +25728,10 @@ function steeringPromptInput(prompt) {
25728
25728
  if (typeof data !== "string" || typeof mimeType !== "string") {
25729
25729
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
25730
25730
  }
25731
- input2.push({ type: "image", url: `data:${mimeType};base64,${data}` });
25731
+ blocks.push({
25732
+ content: { data, mimeType, type: "image" },
25733
+ input: { type: "image", url: `data:${mimeType};base64,${data}` }
25734
+ });
25732
25735
  continue;
25733
25736
  }
25734
25737
  if (type === "resource") {
@@ -25736,24 +25739,33 @@ function steeringPromptInput(prompt) {
25736
25739
  if (typeof resource !== "object" || resource === null) {
25737
25740
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
25738
25741
  }
25742
+ const uri = Reflect.get(resource, "uri");
25739
25743
  const text2 = Reflect.get(resource, "text");
25740
- if (text2 !== void 0 && typeof text2 !== "string") {
25744
+ const blob2 = Reflect.get(resource, "blob");
25745
+ if (typeof uri !== "string" || typeof text2 !== "string" && typeof blob2 !== "string" || text2 !== void 0 && typeof text2 !== "string" || blob2 !== void 0 && typeof blob2 !== "string") {
25741
25746
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
25742
25747
  }
25743
- input2.push({ text: text2 ?? "", text_elements: [], type: "text" });
25748
+ blocks.push({
25749
+ content: typeof text2 === "string" ? { resource: { text: text2, uri }, type: "resource" } : { resource: { blob: blob2, uri }, type: "resource" },
25750
+ input: { text: text2 ?? "", text_elements: [], type: "text" }
25751
+ });
25744
25752
  continue;
25745
25753
  }
25746
25754
  if (type === "resource_link") {
25755
+ const name2 = Reflect.get(block, "name");
25747
25756
  const uri = Reflect.get(block, "uri");
25748
- if (typeof uri !== "string") {
25757
+ if (typeof name2 !== "string" || typeof uri !== "string") {
25749
25758
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
25750
25759
  }
25751
- input2.push({ text: `Resource: ${uri}`, text_elements: [], type: "text" });
25760
+ blocks.push({
25761
+ content: { name: name2, type: "resource_link", uri },
25762
+ input: { text: `Resource: ${uri}`, text_elements: [], type: "text" }
25763
+ });
25752
25764
  continue;
25753
25765
  }
25754
25766
  throw new AcpExecutionError("Codex received an unsupported steering prompt", {}, "invalid_request");
25755
25767
  }
25756
- return input2;
25768
+ return blocks;
25757
25769
  }
25758
25770
  function agentMessageUpdate(messageId, text2, phase) {
25759
25771
  return {
@@ -25900,6 +25912,14 @@ var CodexAcpAgent = class {
25900
25912
  if (isCompactPrompt(context.params.prompt)) {
25901
25913
  return await this.#compact(context.signal);
25902
25914
  }
25915
+ const messageId = crypto.randomUUID();
25916
+ for (const content of context.params.prompt) {
25917
+ await this.#emit({
25918
+ content,
25919
+ messageId,
25920
+ sessionUpdate: "user_message_chunk"
25921
+ });
25922
+ }
25903
25923
  return await this.#runTurn(promptInput(context.params.prompt), context.signal);
25904
25924
  }).onRequest(
25905
25925
  "_session/steering",
@@ -26381,14 +26401,22 @@ var CodexAcpAgent = class {
26381
26401
  if (sessionId !== this.#nativeSessionId || active === null || active.turn.id.length === 0) {
26382
26402
  return { outcome: "promptRequired", reason: "noRunningTurn" };
26383
26403
  }
26384
- const input2 = steeringPromptInput(prompt);
26385
- if (input2.length === 0) {
26404
+ const steering = steeringPrompt(prompt);
26405
+ if (steering.length === 0) {
26386
26406
  throw new AcpExecutionError("Codex received an empty steering request", {}, "invalid_request");
26387
26407
  }
26408
+ const messageId = crypto.randomUUID();
26409
+ for (const block of steering) {
26410
+ await this.#emit({ content: block.content, messageId, sessionUpdate: "user_message_chunk" });
26411
+ }
26388
26412
  const response = turnSteerResponseSchema.parse(
26389
26413
  await this.#appServer.request(
26390
26414
  "turn/steer",
26391
- { expectedTurnId: active.turn.id, input: input2, threadId: this.#nativeSessionId },
26415
+ {
26416
+ expectedTurnId: active.turn.id,
26417
+ input: steering.map((block) => block.input),
26418
+ threadId: this.#nativeSessionId
26419
+ },
26392
26420
  AbortSignal.any([signal, AbortSignal.timeout(APPROVAL_TIMEOUT_MILLISECONDS2)])
26393
26421
  )
26394
26422
  );
@@ -30093,10 +30121,7 @@ var lifecycleMetadataV2Schema = external_exports.discriminatedUnion("kind", [
30093
30121
  external_exports.object({ kind: external_exports.literal("session.queue.changed") }).readonly(),
30094
30122
  external_exports.object({ event: sessionPermissionRequestedEventSchema, kind: external_exports.literal("session.permission.requested") }).readonly(),
30095
30123
  external_exports.object({ event: sessionPermissionResolvedEventSchema, kind: external_exports.literal("session.permission.resolved") }).readonly(),
30096
- external_exports.object({
30097
- event: sessionElicitationRequestedEventSchema,
30098
- kind: external_exports.literal("session.elicitation.requested")
30099
- }).readonly(),
30124
+ external_exports.object({ event: sessionElicitationRequestedEventSchema, kind: external_exports.literal("session.elicitation.requested") }).readonly(),
30100
30125
  external_exports.object({ event: sessionElicitationResolvedEventSchema, kind: external_exports.literal("session.elicitation.resolved") }).readonly(),
30101
30126
  external_exports.object({
30102
30127
  ...lifecycleBase,
@@ -30198,6 +30223,7 @@ var mobiusSessionExportV2Schema = external_exports.object({
30198
30223
  }).readonly();
30199
30224
  var sessionEventEnvelopeV2Schema = external_exports.object({ event: sessionEventV2Schema, kind: external_exports.literal(SESSION_EVENT_V2_KIND) }).readonly();
30200
30225
  var sessionEventLogPageV2Schema = external_exports.object({
30226
+ daemonGenerationId: identifierStringSchema,
30201
30227
  events: external_exports.array(sessionEventV2Schema).max(MAX_EVENT_COUNT).readonly(),
30202
30228
  nextCursor: external_exports.string().min(1).max(512).nullable(),
30203
30229
  tailCursor: external_exports.string().max(512),
@@ -30205,17 +30231,13 @@ var sessionEventLogPageV2Schema = external_exports.object({
30205
30231
  version: external_exports.literal(2)
30206
30232
  }).readonly();
30207
30233
  var nativeEventPageRequestV2Schema = external_exports.object({ cursor: external_exports.string().min(1).max(512).nullable(), eventLimit: external_exports.number().int().min(1).max(1e4) }).readonly();
30208
- var executingPromptRequestEventLogV2Schema = external_exports.object({
30209
- attemptId: identifierStringSchema,
30234
+ var queuedPromptRequestEventLogV2Schema = external_exports.object({
30210
30235
  commandId: identifierStringSchema,
30211
- epoch: identifierStringSchema,
30212
- events: external_exports.array(sessionEventV2Schema).max(MAX_EVENT_COUNT).readonly(),
30213
- tailCursor: external_exports.string().max(512),
30214
- truncated: external_exports.boolean()
30236
+ content: external_exports.array(contentBlockV2Schema).min(1).max(100).readonly()
30215
30237
  }).readonly();
30216
30238
  var nativeSessionEventsV2Schema = external_exports.object({
30217
- executingPromptRequest: executingPromptRequestEventLogV2Schema.nullable(),
30218
- history: sessionEventLogPageV2Schema
30239
+ events: sessionEventLogPageV2Schema,
30240
+ queuedPromptRequests: external_exports.array(queuedPromptRequestEventLogV2Schema).max(MAX_COLLECTION_SIZE).readonly()
30219
30241
  }).readonly();
30220
30242
  function inputValue(value) {
30221
30243
  if (typeof value !== "string") {
@@ -30239,7 +30261,6 @@ function decode5(value, schema) {
30239
30261
  function encode4(value, schema) {
30240
30262
  return JSON.stringify(decode5(value, schema));
30241
30263
  }
30242
- var decodeSessionEventV2 = (value) => decode5(value, sessionEventV2Schema);
30243
30264
  var decodeSessionEventEnvelopeV2 = (value) => decode5(value, sessionEventEnvelopeV2Schema);
30244
30265
  var encodeSessionEventEnvelopeV2 = (value) => encode4(value, sessionEventEnvelopeV2Schema);
30245
30266
  var decodeAcpSessionUpdateV2 = (value) => decode5(value, acpSessionUpdateV2Schema);
@@ -31530,7 +31551,7 @@ var AuditStore = class {
31530
31551
  };
31531
31552
 
31532
31553
  // src/run-daemon.ts
31533
- import { createHash as createHash8, randomUUID as randomUUID8 } from "node:crypto";
31554
+ import { createHash as createHash8, randomUUID as randomUUID9 } from "node:crypto";
31534
31555
  import { join as join19 } from "node:path";
31535
31556
  import { styleText } from "node:util";
31536
31557
 
@@ -33079,7 +33100,7 @@ function sessionConfigProtocolForAgent(_agentId) {
33079
33100
 
33080
33101
  // src/acp/session-contracts.ts
33081
33102
  var NullAcpSessionObserver = class {
33082
- onAcpUpdate = (_sessionId, _update) => Promise.resolve();
33103
+ onSessionEventV2 = (_sessionId, _event, _position) => Promise.resolve();
33083
33104
  onCommands = () => Promise.resolve();
33084
33105
  onConfig = () => Promise.resolve();
33085
33106
  onContent = () => Promise.resolve();
@@ -33147,7 +33168,8 @@ function historyContentCharacters(messages) {
33147
33168
  var AcpHistoryReplay = class {
33148
33169
  #activities = /* @__PURE__ */ new Map();
33149
33170
  #messages = [];
33150
- #updates = [];
33171
+ #events = [];
33172
+ #records = [];
33151
33173
  #turnActivityIds = /* @__PURE__ */ new Set();
33152
33174
  #activityTracker = new AcpActivityTracker(
33153
33175
  async (activity2) => {
@@ -33169,8 +33191,10 @@ var AcpHistoryReplay = class {
33169
33191
  #firstMessageIndex = 0;
33170
33192
  #characters = 0;
33171
33193
  #truncated = false;
33172
- record = async (update, rawUpdate) => {
33173
- this.#updates.push(rawUpdate);
33194
+ record = async (update, rawUpdate, onRecorded = () => Promise.resolve()) => {
33195
+ this.#records.push({ kind: "acp", rawUpdate, update });
33196
+ this.#events.push({ payload: rawUpdate, type: "acp" });
33197
+ await onRecorded(this.#events.length);
33174
33198
  if (update.sessionUpdate === "agent_thought_chunk") {
33175
33199
  if (update.content.type === "text") {
33176
33200
  await this.#activityTracker.recordNarrative(
@@ -33179,30 +33203,30 @@ var AcpHistoryReplay = class {
33179
33203
  update.content.text
33180
33204
  );
33181
33205
  }
33182
- return;
33206
+ return this.#events.length;
33183
33207
  }
33184
33208
  if (update.sessionUpdate === "tool_call") {
33185
33209
  await this.#activityTracker.recordToolCall(update);
33186
- return;
33210
+ return this.#events.length;
33187
33211
  }
33188
33212
  if (update.sessionUpdate === "tool_call_update") {
33189
33213
  await this.#activityTracker.recordToolCallUpdate(update);
33190
- return;
33214
+ return this.#events.length;
33191
33215
  }
33192
33216
  if (update.sessionUpdate === "plan") {
33193
33217
  await this.#activityTracker.recordPlan(update);
33194
- return;
33218
+ return this.#events.length;
33195
33219
  }
33196
33220
  if (update.sessionUpdate === "plan_update") {
33197
33221
  await this.#activityTracker.recordPlanUpdate(update);
33198
- return;
33222
+ return this.#events.length;
33199
33223
  }
33200
33224
  if (update.sessionUpdate === "plan_removed") {
33201
33225
  await this.#activityTracker.removePlan(update);
33202
- return;
33226
+ return this.#events.length;
33203
33227
  }
33204
33228
  if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk") {
33205
- return;
33229
+ return this.#events.length;
33206
33230
  }
33207
33231
  if (update.sessionUpdate === "agent_message_chunk" && isProgressMessage(update)) {
33208
33232
  if (update.content.type === "text") {
@@ -33212,18 +33236,18 @@ var AcpHistoryReplay = class {
33212
33236
  update.content.text
33213
33237
  );
33214
33238
  }
33215
- return;
33239
+ return this.#events.length;
33216
33240
  }
33217
33241
  const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
33218
33242
  const content = update.content;
33219
33243
  if (role === "assistant" && content.type !== "text") {
33220
33244
  await this.#activityTracker.finishNarrative();
33221
33245
  this.recordAssistantContent(update.messageId ?? null, normalizeContentBlock(content));
33222
- return;
33246
+ return this.#events.length;
33223
33247
  }
33224
33248
  const text2 = content.type === "text" ? content.text : content.type === "image" ? content.data.length > 0 ? `[@image](data:${content.mimeType};base64,${content.data})` : content.uri != null && content.uri.length > 0 ? `[@image](${content.uri})` : "[image attachment]" : `[${content.type} attachment]`;
33225
33249
  if (text2.length === 0) {
33226
- return;
33250
+ return this.#events.length;
33227
33251
  }
33228
33252
  const previous = this.#messages.at(-1);
33229
33253
  const id = update.messageId ?? null;
@@ -33250,10 +33274,30 @@ var AcpHistoryReplay = class {
33250
33274
  this.#characters += bounded2.length;
33251
33275
  this.#lastMessageId = id;
33252
33276
  this.trimMessages();
33277
+ return this.#events.length;
33278
+ };
33279
+ recordLifecycle = (event) => {
33280
+ if (event.type !== "lifecycle-metadata") {
33281
+ throw new Error("Lifecycle history only accepts lifecycle metadata");
33282
+ }
33283
+ this.#records.push({ event, kind: "lifecycle" });
33284
+ this.#events.push(event);
33285
+ return this.#events.length;
33253
33286
  };
33254
- eventPage = (eventLimit, cursor) => {
33255
- const parsedCursor = cursor === null ? this.#updates.length : Number(cursor);
33256
- if (!Number.isSafeInteger(parsedCursor) || parsedCursor < 0 || parsedCursor > this.#updates.length) {
33287
+ eventCount = () => this.#events.length;
33288
+ append = async (replay) => {
33289
+ for (const record2 of replay.#records) {
33290
+ if (record2.kind === "acp") {
33291
+ await this.record(record2.update, record2.rawUpdate);
33292
+ } else {
33293
+ this.recordLifecycle(record2.event);
33294
+ }
33295
+ }
33296
+ };
33297
+ eventPage = (eventLimit, cursor, appended = null) => {
33298
+ const events = appended === null ? this.#events : [...this.#events, ...appended.#events];
33299
+ const parsedCursor = cursor === null ? events.length : Number(cursor);
33300
+ if (!Number.isSafeInteger(parsedCursor) || parsedCursor < 0 || parsedCursor > events.length) {
33257
33301
  throw new Error("The native event cursor is invalid");
33258
33302
  }
33259
33303
  const endUpdate = parsedCursor;
@@ -33262,7 +33306,7 @@ var AcpHistoryReplay = class {
33262
33306
  nextCursor: startUpdate === 0 ? null : startUpdate.toString(),
33263
33307
  startPosition: startUpdate + 1,
33264
33308
  truncated: startUpdate > 0,
33265
- updates: this.#updates.slice(startUpdate, endUpdate)
33309
+ events: events.slice(startUpdate, endUpdate)
33266
33310
  };
33267
33311
  };
33268
33312
  snapshot = async () => {
@@ -33649,6 +33693,34 @@ var AcpSessionInteractions = class {
33649
33693
  constructor(context) {
33650
33694
  this.#context = context;
33651
33695
  }
33696
+ #notifyPermissionRequested = async (event) => {
33697
+ await this.#context.recordSessionEventV2({
33698
+ payload: { event, kind: "session.permission.requested" },
33699
+ type: "lifecycle-metadata"
33700
+ });
33701
+ await this.#context.observer().onPermission(event);
33702
+ };
33703
+ #notifyPermissionResolved = async (event) => {
33704
+ await this.#context.recordSessionEventV2({
33705
+ payload: { event, kind: "session.permission.resolved" },
33706
+ type: "lifecycle-metadata"
33707
+ });
33708
+ await this.#context.observer().onPermissionResolved(event);
33709
+ };
33710
+ #notifyElicitationRequested = async (event) => {
33711
+ await this.#context.recordSessionEventV2({
33712
+ payload: { event, kind: "session.elicitation.requested" },
33713
+ type: "lifecycle-metadata"
33714
+ });
33715
+ await this.#context.observer().onElicitation(event);
33716
+ };
33717
+ #notifyElicitationResolved = async (event) => {
33718
+ await this.#context.recordSessionEventV2({
33719
+ payload: { event, kind: "session.elicitation.resolved" },
33720
+ type: "lifecycle-metadata"
33721
+ });
33722
+ await this.#context.observer().onElicitationResolved(event);
33723
+ };
33652
33724
  respondPermission = async (options) => {
33653
33725
  const pending = this.#pendingPermissions.get(options.interactionId);
33654
33726
  if (pending === void 0) {
@@ -33674,7 +33746,7 @@ var AcpSessionInteractions = class {
33674
33746
  );
33675
33747
  }
33676
33748
  this.#pendingPermissions.delete(options.interactionId);
33677
- await this.#context.observer().onPermissionResolved({
33749
+ await this.#notifyPermissionResolved({
33678
33750
  interactionId: options.interactionId,
33679
33751
  kind: SESSION_PERMISSION_RESOLVED_KIND,
33680
33752
  optionId: options.outcome === "selected" ? options.optionId : "",
@@ -33714,7 +33786,7 @@ var AcpSessionInteractions = class {
33714
33786
  );
33715
33787
  }
33716
33788
  this.#pendingElicitations.delete(options.interactionId);
33717
- await this.#context.observer().onElicitationResolved({
33789
+ await this.#notifyElicitationResolved({
33718
33790
  action: options.action,
33719
33791
  interactionId: options.interactionId,
33720
33792
  kind: SESSION_ELICITATION_RESOLVED_KIND,
@@ -33743,7 +33815,7 @@ var AcpSessionInteractions = class {
33743
33815
  };
33744
33816
  signal.addEventListener("abort", abort, { once: true });
33745
33817
  try {
33746
- await this.#context.observer().onPermission({
33818
+ await this.#notifyPermissionRequested({
33747
33819
  commandId: this.#context.commandId(),
33748
33820
  interactionId,
33749
33821
  kind: SESSION_PERMISSION_REQUESTED_KIND,
@@ -33788,7 +33860,7 @@ var AcpSessionInteractions = class {
33788
33860
  };
33789
33861
  signal.addEventListener("abort", abort, { once: true });
33790
33862
  try {
33791
- await this.#context.observer().onElicitation({
33863
+ await this.#notifyElicitationRequested({
33792
33864
  accepted: false,
33793
33865
  commandId: this.#context.commandId(),
33794
33866
  elicitationId,
@@ -33812,7 +33884,7 @@ var AcpSessionInteractions = class {
33812
33884
  return;
33813
33885
  }
33814
33886
  this.#acceptedUrlElicitations.delete(notification.elicitationId);
33815
- await this.#context.observer().onElicitationResolved({
33887
+ await this.#notifyElicitationResolved({
33816
33888
  action: "complete",
33817
33889
  interactionId,
33818
33890
  kind: SESSION_ELICITATION_RESOLVED_KIND,
@@ -33825,7 +33897,7 @@ var AcpSessionInteractions = class {
33825
33897
  return;
33826
33898
  }
33827
33899
  this.#pendingPermissions.delete(interactionId);
33828
- await this.#context.observer().onPermissionResolved({
33900
+ await this.#notifyPermissionResolved({
33829
33901
  interactionId,
33830
33902
  kind: SESSION_PERMISSION_RESOLVED_KIND,
33831
33903
  optionId: "",
@@ -33839,7 +33911,7 @@ var AcpSessionInteractions = class {
33839
33911
  return;
33840
33912
  }
33841
33913
  this.#pendingElicitations.delete(interactionId);
33842
- await this.#context.observer().onElicitationResolved({
33914
+ await this.#notifyElicitationResolved({
33843
33915
  action: "cancel",
33844
33916
  interactionId,
33845
33917
  kind: SESSION_ELICITATION_RESOLVED_KIND,
@@ -33858,7 +33930,7 @@ var AcpSessionInteractions = class {
33858
33930
  await this.cancelElicitation(interactionId);
33859
33931
  }
33860
33932
  for (const interactionId of acceptedElicitationIds) {
33861
- await this.#context.observer().onElicitationResolved({
33933
+ await this.#notifyElicitationResolved({
33862
33934
  action: "cancel",
33863
33935
  interactionId,
33864
33936
  kind: SESSION_ELICITATION_RESOLVED_KIND,
@@ -38793,21 +38865,9 @@ var DeletedAcpStoredSession = class extends AcpStoredSessionLookup {
38793
38865
  var MemoryAcpSessionStore = class {
38794
38866
  #sessions = /* @__PURE__ */ new Map();
38795
38867
  #deleted = /* @__PURE__ */ new Set();
38796
- #eventsV2 = /* @__PURE__ */ new Map();
38797
- appendExecutingPromptEventV2 = (event) => {
38798
- const events = this.#eventsV2.get(event.sessionId);
38799
- if (events === void 0) {
38800
- throw new Error("The executing prompt event log has not started");
38801
- }
38802
- events.push(event);
38803
- };
38804
- clearExecutingPromptEventsV2 = (sessionId) => {
38805
- this.#eventsV2.delete(sessionId);
38806
- };
38807
38868
  close = () => {
38808
38869
  this.#sessions.clear();
38809
38870
  this.#deleted.clear();
38810
- this.#eventsV2.clear();
38811
38871
  };
38812
38872
  findNative = (agentId, nativeSessionId) => [...this.#sessions.values()].filter(
38813
38873
  (session) => session.agentId === agentId && session.nativeSessionId === nativeSessionId
@@ -38818,7 +38878,6 @@ var MemoryAcpSessionStore = class {
38818
38878
  for (const id of ids) {
38819
38879
  this.#sessions.delete(id);
38820
38880
  this.#deleted.add(id);
38821
- this.#eventsV2.delete(id);
38822
38881
  }
38823
38882
  return ids;
38824
38883
  };
@@ -38831,13 +38890,6 @@ var MemoryAcpSessionStore = class {
38831
38890
  };
38832
38891
  remove = (sessionId) => {
38833
38892
  this.#sessions.delete(sessionId);
38834
- this.#eventsV2.delete(sessionId);
38835
- };
38836
- readExecutingPromptEventsV2 = (sessionId) => [
38837
- ...this.#eventsV2.get(sessionId) ?? []
38838
- ];
38839
- startExecutingPromptEventsV2 = (sessionId, events) => {
38840
- this.#eventsV2.set(sessionId, [...events]);
38841
38893
  };
38842
38894
  write = (session) => {
38843
38895
  this.#sessions.set(session.sessionId, session);
@@ -38916,30 +38968,6 @@ var SqliteAcpSessionStore = class {
38916
38968
  close = () => {
38917
38969
  this.#sqliteDatabase.close();
38918
38970
  };
38919
- appendExecutingPromptEventV2 = (event) => {
38920
- this.#database.insert(sessionEventV2).values({
38921
- eventId: event.eventId,
38922
- eventJson: JSON.stringify(event),
38923
- position: Number(event.position),
38924
- sessionId: event.sessionId
38925
- }).run();
38926
- };
38927
- clearExecutingPromptEventsV2 = (sessionId) => {
38928
- this.#database.delete(sessionEventV2).where(eq(sessionEventV2.sessionId, sessionId)).run();
38929
- };
38930
- startExecutingPromptEventsV2 = (sessionId, events) => {
38931
- this.#transaction(() => {
38932
- this.#database.delete(sessionEventV2).where(eq(sessionEventV2.sessionId, sessionId)).run();
38933
- for (const event of events) {
38934
- this.#database.insert(sessionEventV2).values({
38935
- eventId: event.eventId,
38936
- eventJson: JSON.stringify(event),
38937
- position: Number(event.position),
38938
- sessionId: event.sessionId
38939
- }).run();
38940
- }
38941
- });
38942
- };
38943
38971
  findNative = (agentId, nativeSessionId) => this.#database.select().from(acpSession).where(and(eq(acpSession.agentId, agentId), eq(acpSession.nativeSessionId, nativeSessionId))).all().map(decodeStoredSession);
38944
38972
  list = () => this.#database.select().from(acpSession).orderBy(desc(acpSession.updatedAt)).all().map(decodeStoredSession);
38945
38973
  markDeleted = (agentId, nativeSessionId) => {
@@ -38948,7 +38976,6 @@ var SqliteAcpSessionStore = class {
38948
38976
  this.#database.delete(acpSession).where(and(eq(acpSession.agentId, agentId), eq(acpSession.nativeSessionId, nativeSessionId))).run();
38949
38977
  for (const id of ids) {
38950
38978
  this.#database.insert(deletedAcpSession).values({ sessionId: id }).onConflictDoNothing().run();
38951
- this.#database.delete(sessionEventV2).where(eq(sessionEventV2.sessionId, id)).run();
38952
38979
  }
38953
38980
  });
38954
38981
  return ids;
@@ -38962,12 +38989,8 @@ var SqliteAcpSessionStore = class {
38962
38989
  const row = this.#database.select().from(acpSession).where(eq(acpSession.sessionId, sessionId)).get();
38963
38990
  return row === void 0 ? new MissingAcpStoredSession() : new FoundAcpStoredSession(decodeStoredSession(row));
38964
38991
  };
38965
- readExecutingPromptEventsV2 = (sessionId) => this.#database.select({ eventJson: sessionEventV2.eventJson }).from(sessionEventV2).where(eq(sessionEventV2.sessionId, sessionId)).orderBy(asc(sessionEventV2.position)).all().map((row) => decodeSessionEventV2(row.eventJson));
38966
38992
  remove = (sessionId) => {
38967
- this.#transaction(() => {
38968
- this.#database.delete(acpSession).where(eq(acpSession.sessionId, sessionId)).run();
38969
- this.#database.delete(sessionEventV2).where(eq(sessionEventV2.sessionId, sessionId)).run();
38970
- });
38993
+ this.#database.delete(acpSession).where(eq(acpSession.sessionId, sessionId)).run();
38971
38994
  };
38972
38995
  write = (session) => {
38973
38996
  const value = {
@@ -39037,6 +39060,7 @@ var AgentSession = class _AgentSession {
39037
39060
  #sessionTitle = null;
39038
39061
  #sessionUpdatedAt = "";
39039
39062
  #turn = new IdleAcpTurn();
39063
+ #turnHistory = null;
39040
39064
  constructor(agent, cwd, additionalDirectories, mobiusSessionId, getObserver, store, metrics, contentExternalizer) {
39041
39065
  this.#updates = new AgentUpdateStream((notification) => this.#processUpdate(notification));
39042
39066
  this.#additionalDirectories = [...additionalDirectories];
@@ -39054,7 +39078,8 @@ var AgentSession = class _AgentSession {
39054
39078
  sessionId: () => this.#mobiusSessionId,
39055
39079
  commandId: () => this.#turn.commandId,
39056
39080
  assertNativeSession: (sessionId) => this.assertNativeSession(sessionId),
39057
- observer: getObserver
39081
+ observer: getObserver,
39082
+ recordSessionEventV2: this.#recordLifecycleEventV2
39058
39083
  });
39059
39084
  this.#connection = new AgentConnection(agent, cwd, this);
39060
39085
  this.#contentExternalizer = contentExternalizer;
@@ -39150,13 +39175,10 @@ var AgentSession = class _AgentSession {
39150
39175
  }
39151
39176
  };
39152
39177
  }
39153
- const loaded = await this.#loadSession(signal, "ACP agent exited while loading history");
39154
- return await embedLocalHistoryImages(await loaded.history.snapshot(), signal);
39178
+ const history = await this.#completedHistory(signal, "ACP agent exited while loading history");
39179
+ return await embedLocalHistoryImages(await history.snapshot(), signal);
39155
39180
  };
39156
39181
  loadHistoryEventsV2 = async (eventLimit, cursor, signal) => {
39157
- if (!this.#prompted && this.#nativeHistoryOwnership.kind === "fresh-session") {
39158
- return new AcpHistoryReplay().eventPage(eventLimit, cursor);
39159
- }
39160
39182
  if (!this.#capabilities.loadSession) {
39161
39183
  throw new AcpExecutionError(
39162
39184
  "This Agent restores context but does not provide message history.",
@@ -39164,9 +39186,20 @@ var AgentSession = class _AgentSession {
39164
39186
  "native_history_unsupported"
39165
39187
  );
39166
39188
  }
39167
- const loaded = await this.#loadSession(signal, "ACP agent exited while loading history");
39168
- return loaded.history.eventPage(eventLimit, cursor);
39189
+ const history = await this.#completedHistory(signal, "ACP agent exited while loading history");
39190
+ return history.eventPage(eventLimit, cursor, this.#turnHistory);
39169
39191
  };
39192
+ async #completedHistory(signal, exitMessage) {
39193
+ if (!this.#prompted && this.#nativeHistoryOwnership.kind === "fresh-session") {
39194
+ if (this.#sessionLoad.kind === "not-requested") {
39195
+ this.#sessionLoad = { history: new AcpHistoryReplay(), kind: "loaded", response: {} };
39196
+ }
39197
+ if (this.#sessionLoad.kind === "loaded") {
39198
+ return this.#sessionLoad.history;
39199
+ }
39200
+ }
39201
+ return (await this.#loadSession(signal, exitMessage)).history;
39202
+ }
39170
39203
  async #loadSession(signal, exitMessage) {
39171
39204
  if (this.#sessionLoad.kind === "loaded") {
39172
39205
  return this.#sessionLoad;
@@ -39650,19 +39683,7 @@ var AgentSession = class _AgentSession {
39650
39683
  if (this.#turn.running) {
39651
39684
  throw new AcpExecutionError("Another prompt is already running in this conversation", {}, "session_busy");
39652
39685
  }
39653
- switch (this.#sessionLoad.kind) {
39654
- case "not-requested":
39655
- break;
39656
- case "loaded":
39657
- this.#sessionLoad = { kind: "not-requested" };
39658
- break;
39659
- case "capturing":
39660
- throw new AcpExecutionError("Session history is still loading", {}, "session_busy");
39661
- default: {
39662
- const unexpected = this.#sessionLoad;
39663
- throw new Error(`Unexpected Session load state: ${JSON.stringify(unexpected)}`);
39664
- }
39665
- }
39686
+ const completedHistory = this.#capabilities.loadSession ? await this.#completedHistory(options.signal, "ACP agent exited while loading history before a prompt") : null;
39666
39687
  const prompt = this.buildPrompt(options);
39667
39688
  if (this.#sessionTitle === null || this.#sessionTitle.length === 0) {
39668
39689
  this.#sessionTitle = truncate(options.prompt, 500);
@@ -39689,6 +39710,23 @@ var AgentSession = class _AgentSession {
39689
39710
  this.prepareAgentContent
39690
39711
  );
39691
39712
  this.#turn = running;
39713
+ this.#turnHistory = completedHistory === null ? null : new AcpHistoryReplay();
39714
+ const lifecycleV2 = options.lifecycleV2;
39715
+ if (lifecycleV2 !== void 0) {
39716
+ await this.#recordLifecycleEventV2({
39717
+ payload: { commandId: options.commandId, content: lifecycleV2.content, kind: "prompt.requested" },
39718
+ type: "lifecycle-metadata"
39719
+ });
39720
+ await this.#recordLifecycleEventV2({
39721
+ payload: {
39722
+ attemptId: lifecycleV2.attemptId,
39723
+ commandId: options.commandId,
39724
+ epoch: lifecycleV2.epoch,
39725
+ kind: "prompt.started"
39726
+ },
39727
+ type: "lifecycle-metadata"
39728
+ });
39729
+ }
39692
39730
  this.#nativePrompt = {
39693
39731
  commandId: options.commandId,
39694
39732
  previousTurnId: this.#connection.inProcessAgent?.nativeTurnId?.() ?? null
@@ -39743,16 +39781,37 @@ var AgentSession = class _AgentSession {
39743
39781
  this.#lastTerminalCommandId
39744
39782
  )
39745
39783
  );
39784
+ if (lifecycleV2 !== void 0) {
39785
+ await this.#recordLifecycleEventV2({
39786
+ payload: { commandId: options.commandId, kind: "prompt.completed", stopReason: result.stopReason },
39787
+ type: "lifecycle-metadata"
39788
+ });
39789
+ }
39746
39790
  return result;
39747
39791
  } catch (error62) {
39748
39792
  await running.activities.finish();
39793
+ const failure2 = error62 instanceof AcpExecutionError ? error62 : new AcpExecutionError("ACP agent execution failed", { cause: error62 });
39794
+ if (lifecycleV2 !== void 0) {
39795
+ await this.#recordLifecycleEventV2({
39796
+ payload: {
39797
+ attemptId: lifecycleV2.attemptId,
39798
+ code: failure2.code,
39799
+ commandId: options.commandId,
39800
+ kind: "prompt.failed",
39801
+ message: truncate(failure2.message, 500)
39802
+ },
39803
+ type: "lifecycle-metadata"
39804
+ });
39805
+ }
39749
39806
  if (error62 instanceof AcpExecutionError) {
39750
39807
  throw error62;
39751
39808
  }
39752
- throw new AcpExecutionError("ACP agent execution failed", {
39753
- cause: error62
39754
- });
39809
+ throw failure2;
39755
39810
  } finally {
39811
+ if (completedHistory !== null && this.#turnHistory !== null) {
39812
+ await completedHistory.append(this.#turnHistory);
39813
+ }
39814
+ this.#turnHistory = null;
39756
39815
  this.#turn = new IdleAcpTurn();
39757
39816
  }
39758
39817
  };
@@ -39768,41 +39827,80 @@ var AgentSession = class _AgentSession {
39768
39827
  throw new AcpExecutionError("The target turn is no longer active", {}, "steering_target_unavailable");
39769
39828
  }
39770
39829
  const prompt = this.buildPrompt(options);
39771
- const response = await this.race(
39772
- this.#connection.connection.agent.request("_session/steering", {
39773
- _meta: { steering: { idleBehavior: "promptRequired" } },
39774
- prompt,
39775
- sessionId: this.#updates.sessionId()
39776
- }),
39777
- "ACP agent exited during steering",
39778
- options.signal
39779
- );
39780
- if (!isRecord3(response)) {
39830
+ const lifecycleV2 = options.lifecycleV2;
39831
+ if (lifecycleV2 !== void 0) {
39832
+ await this.#recordLifecycleEventV2({
39833
+ payload: { commandId: options.commandId, content: lifecycleV2.content, kind: "prompt.requested" },
39834
+ type: "lifecycle-metadata"
39835
+ });
39836
+ await this.#recordLifecycleEventV2({
39837
+ payload: {
39838
+ attemptId: lifecycleV2.attemptId,
39839
+ commandId: options.commandId,
39840
+ epoch: lifecycleV2.epoch,
39841
+ kind: "prompt.started"
39842
+ },
39843
+ type: "lifecycle-metadata"
39844
+ });
39845
+ }
39846
+ try {
39847
+ const response = await this.race(
39848
+ this.#connection.connection.agent.request("_session/steering", {
39849
+ _meta: { steering: { idleBehavior: "promptRequired" } },
39850
+ prompt,
39851
+ sessionId: this.#updates.sessionId()
39852
+ }),
39853
+ "ACP agent exited during steering",
39854
+ options.signal
39855
+ );
39856
+ if (!isRecord3(response)) {
39857
+ throw new AcpExecutionError(
39858
+ "ACP agent returned an invalid steering response",
39859
+ {},
39860
+ "acp_invalid_steering_response"
39861
+ );
39862
+ }
39863
+ const outcome = response["outcome"];
39864
+ if (outcome === "injected" || outcome === "startedNewTurn") {
39865
+ if (lifecycleV2 !== void 0) {
39866
+ await this.#recordLifecycleEventV2({
39867
+ payload: { commandId: options.commandId, kind: "prompt.completed", stopReason: "steered" },
39868
+ type: "lifecycle-metadata"
39869
+ });
39870
+ }
39871
+ return outcome;
39872
+ }
39873
+ if (outcome === "promptRequired") {
39874
+ throw new AcpExecutionError(
39875
+ "The target turn finished before steering could be injected",
39876
+ {},
39877
+ "steering_target_unavailable"
39878
+ );
39879
+ }
39880
+ if (outcome === "failed") {
39881
+ throw new AcpExecutionError("The Agent could not inject steering", {}, "steering_failed");
39882
+ }
39781
39883
  throw new AcpExecutionError(
39782
39884
  "ACP agent returned an invalid steering response",
39783
39885
  {},
39784
39886
  "acp_invalid_steering_response"
39785
39887
  );
39888
+ } catch (error62) {
39889
+ const failure2 = error62 instanceof AcpExecutionError ? error62 : new AcpExecutionError("ACP agent execution failed", { cause: error62 });
39890
+ if (lifecycleV2 !== void 0) {
39891
+ await this.#recordLifecycleEventV2({
39892
+ payload: {
39893
+ attemptId: lifecycleV2.attemptId,
39894
+ code: failure2.code,
39895
+ commandId: options.commandId,
39896
+ kind: "prompt.failed",
39897
+ message: truncate(failure2.message, 500)
39898
+ },
39899
+ type: "lifecycle-metadata"
39900
+ });
39901
+ }
39902
+ throw failure2;
39786
39903
  }
39787
- const outcome = response["outcome"];
39788
- if (outcome === "injected" || outcome === "startedNewTurn") {
39789
- return outcome;
39790
- }
39791
- if (outcome === "promptRequired") {
39792
- throw new AcpExecutionError(
39793
- "The target turn finished before steering could be injected",
39794
- {},
39795
- "steering_target_unavailable"
39796
- );
39797
- }
39798
- if (outcome === "failed") {
39799
- throw new AcpExecutionError("The Agent could not inject steering", {}, "steering_failed");
39800
- }
39801
- throw new AcpExecutionError(
39802
- "ACP agent returned an invalid steering response",
39803
- {},
39804
- "acp_invalid_steering_response"
39805
- );
39806
39904
  };
39807
39905
  cancel = async () => {
39808
39906
  const capturedProcesses = await this.#connection.captureProcessTree();
@@ -39823,6 +39921,13 @@ var AgentSession = class _AgentSession {
39823
39921
  onElicitation = (request, signal) => this.#interactions.onElicitation(request, signal);
39824
39922
  onElicitationComplete = (notification) => this.#interactions.onElicitationComplete(notification);
39825
39923
  onUpdate = (notification) => this.#updates.receive(notification);
39924
+ #recordLifecycleEventV2 = async (event) => {
39925
+ if (event.type !== "lifecycle-metadata" || this.#sessionLoad.kind !== "loaded") {
39926
+ return;
39927
+ }
39928
+ const position = this.#turnHistory === null ? this.#sessionLoad.history.recordLifecycle(event) : this.#sessionLoad.history.eventCount() + this.#turnHistory.recordLifecycle(event);
39929
+ await this.#getObserver().onSessionEventV2?.(this.#mobiusSessionId, event, position);
39930
+ };
39826
39931
  selectNativeSession = (sessionId) => {
39827
39932
  this.#updates.select(sessionId);
39828
39933
  this.#nativeHistoryOwnership = { kind: "agent-owned" };
@@ -39839,9 +39944,20 @@ var AgentSession = class _AgentSession {
39839
39944
  if (this.#sessionLoad.kind === "capturing") {
39840
39945
  await this.#sessionLoad.history.record(update, rawUpdate);
39841
39946
  } else {
39842
- const onAcpUpdate = this.#getObserver().onAcpUpdate;
39843
- if (onAcpUpdate !== void 0) {
39844
- await onAcpUpdate(this.#mobiusSessionId, rawUpdate);
39947
+ const onSessionEventV2 = this.#getObserver().onSessionEventV2;
39948
+ if (this.#turnHistory !== null) {
39949
+ const completedEventCount = this.#sessionLoad.kind === "loaded" ? this.#sessionLoad.history.eventCount() : 0;
39950
+ await this.#turnHistory.record(update, rawUpdate, async (turnPosition) => {
39951
+ await onSessionEventV2?.(
39952
+ this.#mobiusSessionId,
39953
+ { payload: rawUpdate, type: "acp" },
39954
+ completedEventCount + turnPosition
39955
+ );
39956
+ });
39957
+ } else if (this.#sessionLoad.kind === "loaded") {
39958
+ await this.#sessionLoad.history.record(update, rawUpdate, async (position) => {
39959
+ await onSessionEventV2?.(this.#mobiusSessionId, { payload: rawUpdate, type: "acp" }, position);
39960
+ });
39845
39961
  }
39846
39962
  }
39847
39963
  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")) {
@@ -42620,8 +42736,8 @@ var DaemonAcpObserver = class {
42620
42736
  this.#record = record2;
42621
42737
  this.#recordV2 = recordV2;
42622
42738
  }
42623
- onAcpUpdate = (sessionId, update) => {
42624
- this.#recordV2(sessionId, { payload: update, type: "acp" });
42739
+ onSessionEventV2 = (sessionId, event, position) => {
42740
+ this.#recordV2(sessionId, event, position);
42625
42741
  return Promise.resolve();
42626
42742
  };
42627
42743
  onCommands = (event) => {
@@ -42638,18 +42754,10 @@ var DaemonAcpObserver = class {
42638
42754
  };
42639
42755
  onElicitation = (event) => {
42640
42756
  this.#record(event.sessionId, event);
42641
- this.#recordV2(event.sessionId, {
42642
- payload: { event, kind: "session.elicitation.requested" },
42643
- type: "lifecycle-metadata"
42644
- });
42645
42757
  return Promise.resolve();
42646
42758
  };
42647
42759
  onElicitationResolved = (event) => {
42648
42760
  this.#record(event.sessionId, event);
42649
- this.#recordV2(event.sessionId, {
42650
- payload: { event, kind: "session.elicitation.resolved" },
42651
- type: "lifecycle-metadata"
42652
- });
42653
42761
  return Promise.resolve();
42654
42762
  };
42655
42763
  onInfo = (event) => {
@@ -42658,18 +42766,10 @@ var DaemonAcpObserver = class {
42658
42766
  };
42659
42767
  onPermission = (event) => {
42660
42768
  this.#record(event.sessionId, event);
42661
- this.#recordV2(event.sessionId, {
42662
- payload: { event, kind: "session.permission.requested" },
42663
- type: "lifecycle-metadata"
42664
- });
42665
42769
  return Promise.resolve();
42666
42770
  };
42667
42771
  onPermissionResolved = (event) => {
42668
42772
  this.#record(event.sessionId, event);
42669
- this.#recordV2(event.sessionId, {
42670
- payload: { event, kind: "session.permission.resolved" },
42671
- type: "lifecycle-metadata"
42672
- });
42673
42773
  return Promise.resolve();
42674
42774
  };
42675
42775
  onUsage = (event) => {
@@ -45529,9 +45629,6 @@ async function streamLocalFile(command, send2, signal, workingDirectory, externa
45529
45629
  });
45530
45630
  }
45531
45631
 
45532
- // src/daemon-history-commands.ts
45533
- import { createHash as createHash7 } from "node:crypto";
45534
-
45535
45632
  // src/authorization/resolve-session-directories.ts
45536
45633
  import { basename as basename7 } from "node:path";
45537
45634
  var ResolvedSessionDirectories = class {
@@ -45858,20 +45955,7 @@ async function executeSessionLiveHistoryPageLoad(socket, command, config2, direc
45858
45955
  });
45859
45956
  }
45860
45957
  }
45861
- function replayEvent(sessionId, position, update) {
45862
- const encoded = JSON.stringify(update);
45863
- const eventId = `native-${createHash7("sha256").update(sessionId).update(":").update(position.toString()).update(":").update(encoded).digest("hex")}`;
45864
- return {
45865
- eventId,
45866
- payload: update,
45867
- position: position.toString(),
45868
- provenance: { kind: "original" },
45869
- recordedAt: "1970-01-01T00:00:00.000Z",
45870
- sessionId,
45871
- type: "acp"
45872
- };
45873
- }
45874
- async function executeSessionLiveHistoryV2PageLoad(socket, command, config2, directories, audit, diagnostics, sessions, executingPromptRequest, signal) {
45958
+ async function executeSessionLiveHistoryV2PageLoad(socket, command, config2, directories, audit, diagnostics, sessions, eventLogV2, signal) {
45875
45959
  try {
45876
45960
  const resolved = await resolveSessionDirectories(
45877
45961
  directories,
@@ -45880,20 +45964,18 @@ async function executeSessionLiveHistoryV2PageLoad(socket, command, config2, dir
45880
45964
  command.additionalDirectoryIds,
45881
45965
  signal
45882
45966
  );
45883
- const replay = await sessions.loadSessionEventsV2(
45884
- {
45885
- additionalDirectories: resolved.additionalDirectories,
45886
- agent: config2.catalog.find(command.agentId),
45887
- cwd: resolved.cwd,
45888
- sessionId: command.sessionId,
45889
- signal
45890
- },
45891
- command.eventLimit,
45892
- command.cursor
45893
- );
45967
+ const loadOptions = {
45968
+ additionalDirectories: resolved.additionalDirectories,
45969
+ agent: config2.catalog.find(command.agentId),
45970
+ cwd: resolved.cwd,
45971
+ sessionId: command.sessionId,
45972
+ signal
45973
+ };
45974
+ const recovery = eventLogV2.promptRequestRecovery(command.sessionId);
45975
+ const replay = await sessions.loadSessionEventsV2(loadOptions, command.eventLimit, command.cursor);
45894
45976
  signal.throwIfAborted();
45895
- const events = replay.updates.map(
45896
- (update, index2) => replayEvent(command.sessionId, replay.startPosition + index2, update)
45977
+ const events = replay.events.map(
45978
+ (event, index2) => eventLogV2.event(command.sessionId, replay.startPosition + index2, event, "1970-01-01T00:00:00.000Z")
45897
45979
  );
45898
45980
  const tailCursor = events.at(-1)?.eventId ?? "";
45899
45981
  audit.record({
@@ -45903,14 +45985,15 @@ async function executeSessionLiveHistoryV2PageLoad(socket, command, config2, dir
45903
45985
  });
45904
45986
  send(socket, {
45905
45987
  events: {
45906
- executingPromptRequest: executingPromptRequest(command.sessionId),
45907
- history: {
45988
+ events: {
45989
+ daemonGenerationId: eventLogV2.daemonGenerationId,
45908
45990
  events,
45909
45991
  nextCursor: replay.nextCursor,
45910
45992
  tailCursor,
45911
45993
  truncated: replay.truncated,
45912
45994
  version: 2
45913
- }
45995
+ },
45996
+ queuedPromptRequests: recovery.queuedPromptRequests
45914
45997
  },
45915
45998
  kind: "session.live-history.v2.page.loaded",
45916
45999
  requestId: command.requestId,
@@ -46360,7 +46443,7 @@ async function executePrompt({
46360
46443
  }
46361
46444
  }
46362
46445
  const stream = activateAttempt();
46363
- eventLogV2.started(command.sessionId, command.commandId, attemptId, stream.epoch);
46446
+ const lifecycleV2 = eventLogV2.started(command.sessionId, command.commandId, attemptId, stream.epoch);
46364
46447
  if (!prepared.prompted) {
46365
46448
  const listing = await directories.list(config2.bindingId, command.directoryId, signal);
46366
46449
  publisher.publish(command.sessionId, {
@@ -46397,6 +46480,7 @@ async function executePrompt({
46397
46480
  commandId: command.commandId,
46398
46481
  cwd: resolved.cwd,
46399
46482
  images: attachments.images,
46483
+ lifecycleV2,
46400
46484
  prompt: command.prompt,
46401
46485
  resources: attachments.resources,
46402
46486
  sessionId: command.sessionId,
@@ -46412,6 +46496,7 @@ async function executePrompt({
46412
46496
  cwd: resolved.cwd,
46413
46497
  disposition: availability.disposition,
46414
46498
  images: attachments.images,
46499
+ lifecycleV2,
46415
46500
  onActivity: events.recordActivity,
46416
46501
  onNarration: events.recordNarration,
46417
46502
  onText: events.recordText,
@@ -46826,7 +46911,7 @@ function createDaemonCommandHandler({
46826
46911
  audit,
46827
46912
  diagnostics,
46828
46913
  sessions,
46829
- eventLogV2.executingPromptRequest,
46914
+ eventLogV2,
46830
46915
  signal
46831
46916
  );
46832
46917
  return;
@@ -47499,10 +47584,6 @@ import { WebSocket as WebSocket9 } from "undici";
47499
47584
  var MAX_BUFFERED_BYTES = 32 * 1024 * 1024;
47500
47585
  var DaemonSessionEventPublisher = class {
47501
47586
  #socket = null;
47502
- #store;
47503
- constructor(store) {
47504
- this.#store = store;
47505
- }
47506
47587
  connect = (socket) => {
47507
47588
  this.#socket = socket;
47508
47589
  };
@@ -47554,7 +47635,6 @@ var DaemonSessionEventPublisher = class {
47554
47635
  }
47555
47636
  };
47556
47637
  publishV2 = (event) => {
47557
- this.#store.appendExecutingPromptEventV2(event);
47558
47638
  const socket = this.#socket;
47559
47639
  if (socket === null || socket.readyState !== WebSocket9.OPEN) {
47560
47640
  return;
@@ -47581,7 +47661,7 @@ var SystemDaemonTimer = class {
47581
47661
  var systemDaemonTimer = new SystemDaemonTimer();
47582
47662
 
47583
47663
  // src/session-event-log-v2.ts
47584
- var EXECUTING_PROMPT_EVENT_LIMIT = 1e4;
47664
+ import { createHash as createHash7, randomUUID as randomUUID8 } from "node:crypto";
47585
47665
  function promptContent(command) {
47586
47666
  const content = [];
47587
47667
  if (command.prompt.length > 0) {
@@ -47605,176 +47685,59 @@ function promptContent(command) {
47605
47685
  }
47606
47686
  return content;
47607
47687
  }
47688
+ function sessionEventV22(daemonGenerationId, sessionId, position, event, recordedAt) {
47689
+ const sessionPrefix = createHash7("sha256").update(sessionId).digest("hex").slice(0, 16);
47690
+ return {
47691
+ eventId: `event-${daemonGenerationId}-${sessionPrefix}-${position.toString().padStart(16, "0")}`,
47692
+ ...event,
47693
+ position: position.toString(),
47694
+ provenance: { kind: "original" },
47695
+ recordedAt,
47696
+ sessionId
47697
+ };
47698
+ }
47608
47699
  var DaemonSessionEventLogV2 = class {
47609
- #positions = /* @__PURE__ */ new Map();
47610
- #requests = /* @__PURE__ */ new Map();
47611
- #loadedRequestSessions = /* @__PURE__ */ new Set();
47700
+ daemonGenerationId = randomUUID8();
47612
47701
  #publisher;
47613
- #store;
47614
- constructor(publisher, store) {
47702
+ #queued = /* @__PURE__ */ new Map();
47703
+ constructor(publisher) {
47615
47704
  this.#publisher = publisher;
47616
- this.#store = store;
47617
47705
  }
47618
- #loadStoredEvents = (sessionId) => {
47619
- const stored = this.#store.readExecutingPromptEventsV2(sessionId);
47620
- const lastPosition = stored.at(-1)?.position;
47621
- if (lastPosition !== void 0) {
47622
- this.#positions.set(sessionId, Number(lastPosition));
47623
- }
47624
- return stored;
47625
- };
47626
- #loadRequests = (sessionId) => {
47627
- if (this.#loadedRequestSessions.has(sessionId)) {
47628
- return;
47629
- }
47630
- for (const event of this.#loadStoredEvents(sessionId)) {
47631
- if (event.type === "acp") {
47632
- continue;
47633
- }
47634
- const payload = event.payload;
47635
- if (payload.kind === "prompt.requested") {
47636
- this.#requests.set(payload.commandId, {
47637
- commandId: payload.commandId,
47638
- kind: "requested",
47639
- sessionId
47640
- });
47641
- continue;
47642
- }
47643
- if ("event" in payload) {
47644
- continue;
47645
- }
47646
- if (!("commandId" in payload)) {
47647
- continue;
47648
- }
47649
- const state = this.#requests.get(payload.commandId);
47650
- if (state === void 0) {
47651
- continue;
47652
- }
47653
- if (payload.kind === "prompt.started") {
47654
- this.#requests.set(payload.commandId, {
47655
- attemptId: payload.attemptId,
47656
- commandId: payload.commandId,
47657
- epoch: payload.epoch,
47658
- kind: "executing",
47659
- sessionId
47660
- });
47661
- } else if (payload.kind === "prompt.completed" || payload.kind === "prompt.failed" || payload.kind === "prompt.failed-before-start") {
47662
- this.#requests.delete(payload.commandId);
47663
- }
47664
- }
47665
- this.#loadedRequestSessions.add(sessionId);
47666
- };
47667
- #append = (sessionId, payload) => {
47668
- this.#loadRequests(sessionId);
47669
- const position = (this.#positions.get(sessionId) ?? 0) + 1;
47670
- const event = {
47671
- eventId: `event-${crypto.randomUUID()}`,
47672
- ...payload,
47673
- position: position.toString(),
47674
- provenance: { kind: "original" },
47675
- recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
47676
- sessionId
47677
- };
47678
- this.#publisher.publishV2(event);
47679
- this.#positions.set(sessionId, position);
47680
- return event;
47681
- };
47682
47706
  requested = (command) => {
47683
- const content = promptContent(command);
47684
- this.#append(command.sessionId, {
47685
- payload: { commandId: command.commandId, content, kind: "prompt.requested" },
47686
- type: "lifecycle-metadata"
47687
- });
47688
- this.#requests.set(command.commandId, {
47707
+ this.#queued.set(command.commandId, {
47689
47708
  commandId: command.commandId,
47690
- kind: "requested",
47709
+ content: promptContent(command),
47691
47710
  sessionId: command.sessionId
47692
47711
  });
47693
47712
  };
47694
47713
  started = (sessionId, commandId, attemptId, epoch) => {
47695
- this.#loadRequests(sessionId);
47696
- const request = this.#requests.get(commandId);
47697
- if (request?.sessionId !== sessionId) {
47698
- return;
47714
+ const request = this.#queued.get(commandId);
47715
+ if (request?.sessionId === sessionId) {
47716
+ this.#queued.delete(commandId);
47717
+ return { attemptId, content: request.content, epoch };
47699
47718
  }
47700
- this.#append(sessionId, {
47701
- payload: { attemptId, commandId, epoch, kind: "prompt.started" },
47702
- type: "lifecycle-metadata"
47703
- });
47704
- this.#requests.set(commandId, {
47705
- attemptId,
47706
- commandId,
47707
- epoch,
47708
- kind: "executing",
47709
- sessionId
47710
- });
47711
- };
47712
- record = (sessionId, payload) => {
47713
- this.#loadRequests(sessionId);
47714
- this.#append(sessionId, payload);
47715
- };
47716
- #clearCompletedSession = (sessionId) => {
47717
- if (![...this.#requests.values()].some((request) => request.sessionId === sessionId)) {
47718
- this.#store.clearExecutingPromptEventsV2(sessionId);
47719
- }
47720
- };
47721
- queueChanged = (sessionId) => {
47722
- this.#append(sessionId, {
47723
- payload: { kind: "session.queue.changed" },
47724
- type: "lifecycle-metadata"
47725
- });
47719
+ throw new Error("The executing prompt was not registered in the V2 queue");
47726
47720
  };
47727
- completed = (sessionId, commandId, stopReason) => {
47728
- this.#loadRequests(sessionId);
47729
- this.#append(sessionId, {
47730
- payload: { commandId, kind: "prompt.completed", stopReason },
47731
- type: "lifecycle-metadata"
47732
- });
47733
- this.#requests.delete(commandId);
47734
- this.#clearCompletedSession(sessionId);
47721
+ record = (sessionId, event, position) => {
47722
+ this.#publisher.publishV2(this.event(sessionId, position, event, (/* @__PURE__ */ new Date()).toISOString()));
47735
47723
  };
47736
- failed = (sessionId, commandId, code, message) => {
47737
- this.#loadRequests(sessionId);
47738
- const request = this.#requests.get(commandId);
47739
- if (request?.kind === "executing" && request.commandId === commandId) {
47740
- this.#append(sessionId, {
47741
- payload: {
47742
- attemptId: request.attemptId,
47743
- code,
47744
- commandId,
47745
- kind: "prompt.failed",
47746
- message
47747
- },
47748
- type: "lifecycle-metadata"
47749
- });
47750
- } else {
47751
- this.#append(sessionId, {
47752
- payload: { code, commandId, kind: "prompt.failed-before-start", message },
47753
- type: "lifecycle-metadata"
47754
- });
47724
+ event = (sessionId, position, event, recordedAt) => sessionEventV22(this.daemonGenerationId, sessionId, position, event, recordedAt);
47725
+ queueChanged = (_sessionId) => void 0;
47726
+ completed = (sessionId, commandId, _stopReason) => {
47727
+ const request = this.#queued.get(commandId);
47728
+ if (request?.sessionId === sessionId) {
47729
+ this.#queued.delete(commandId);
47755
47730
  }
47756
- this.#requests.delete(commandId);
47757
- this.#clearCompletedSession(sessionId);
47758
47731
  };
47759
- executingPromptRequest = (sessionId) => {
47760
- this.#loadRequests(sessionId);
47761
- const request = [...this.#requests.values()].find(
47762
- (candidate) => candidate.sessionId === sessionId && candidate.kind === "executing"
47763
- );
47764
- if (request?.kind !== "executing") {
47765
- return null;
47732
+ failed = (sessionId, commandId, _code, _message) => {
47733
+ const request = this.#queued.get(commandId);
47734
+ if (request?.sessionId === sessionId) {
47735
+ this.#queued.delete(commandId);
47766
47736
  }
47767
- const requestEvents = this.#store.readExecutingPromptEventsV2(sessionId);
47768
- const events = requestEvents.slice(-EXECUTING_PROMPT_EVENT_LIMIT);
47769
- return {
47770
- attemptId: request.attemptId,
47771
- commandId: request.commandId,
47772
- epoch: request.epoch,
47773
- events,
47774
- tailCursor: events.at(-1)?.eventId ?? "",
47775
- truncated: events.length < requestEvents.length
47776
- };
47777
47737
  };
47738
+ promptRequestRecovery = (sessionId) => ({
47739
+ queuedPromptRequests: [...this.#queued.values()].filter((request) => request.sessionId === sessionId).map(({ commandId, content }) => ({ commandId, content }))
47740
+ });
47778
47741
  };
47779
47742
 
47780
47743
  // src/run-daemon.ts
@@ -47825,7 +47788,7 @@ async function installDetectedAgentIntegrations(config2, installations, signal)
47825
47788
  {
47826
47789
  agentId: agent.id,
47827
47790
  kind: AGENT_INSTALL_REQUEST_KIND,
47828
- requestId: `automatic-integration-${randomUUID8()}`
47791
+ requestId: `automatic-integration-${randomUUID9()}`
47829
47792
  },
47830
47793
  signal
47831
47794
  );
@@ -47848,8 +47811,8 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer, opti
47848
47811
  );
47849
47812
  await using externalContent = new LocalExternalContentStore(stateDirectory);
47850
47813
  const operations = new DaemonOperationState();
47851
- const publisher = new DaemonSessionEventPublisher(sessionStore);
47852
- const eventLogV2 = new DaemonSessionEventLogV2(publisher, sessionStore);
47814
+ const publisher = new DaemonSessionEventPublisher();
47815
+ const eventLogV2 = new DaemonSessionEventLogV2(publisher);
47853
47816
  const activeTurns = new DaemonTurnRegistry(operations);
47854
47817
  const recordSessionEvent = (sessionId, event) => {
47855
47818
  publisher.publish(sessionId, activeTurns.recordEvent(event));