@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/index.js CHANGED
@@ -21520,10 +21520,7 @@ var lifecycleMetadataV2Schema = external_exports.discriminatedUnion("kind", [
21520
21520
  external_exports.object({ kind: external_exports.literal("session.queue.changed") }).readonly(),
21521
21521
  external_exports.object({ event: sessionPermissionRequestedEventSchema, kind: external_exports.literal("session.permission.requested") }).readonly(),
21522
21522
  external_exports.object({ event: sessionPermissionResolvedEventSchema, kind: external_exports.literal("session.permission.resolved") }).readonly(),
21523
- external_exports.object({
21524
- event: sessionElicitationRequestedEventSchema,
21525
- kind: external_exports.literal("session.elicitation.requested")
21526
- }).readonly(),
21523
+ external_exports.object({ event: sessionElicitationRequestedEventSchema, kind: external_exports.literal("session.elicitation.requested") }).readonly(),
21527
21524
  external_exports.object({ event: sessionElicitationResolvedEventSchema, kind: external_exports.literal("session.elicitation.resolved") }).readonly(),
21528
21525
  external_exports.object({
21529
21526
  ...lifecycleBase,
@@ -21625,6 +21622,7 @@ var mobiusSessionExportV2Schema = external_exports.object({
21625
21622
  }).readonly();
21626
21623
  var sessionEventEnvelopeV2Schema = external_exports.object({ event: sessionEventV2Schema, kind: external_exports.literal(SESSION_EVENT_V2_KIND) }).readonly();
21627
21624
  var sessionEventLogPageV2Schema = external_exports.object({
21625
+ daemonGenerationId: identifierStringSchema,
21628
21626
  events: external_exports.array(sessionEventV2Schema).max(MAX_EVENT_COUNT).readonly(),
21629
21627
  nextCursor: external_exports.string().min(1).max(512).nullable(),
21630
21628
  tailCursor: external_exports.string().max(512),
@@ -21632,17 +21630,13 @@ var sessionEventLogPageV2Schema = external_exports.object({
21632
21630
  version: external_exports.literal(2)
21633
21631
  }).readonly();
21634
21632
  var nativeEventPageRequestV2Schema = external_exports.object({ cursor: external_exports.string().min(1).max(512).nullable(), eventLimit: external_exports.number().int().min(1).max(1e4) }).readonly();
21635
- var executingPromptRequestEventLogV2Schema = external_exports.object({
21636
- attemptId: identifierStringSchema,
21633
+ var queuedPromptRequestEventLogV2Schema = external_exports.object({
21637
21634
  commandId: identifierStringSchema,
21638
- epoch: identifierStringSchema,
21639
- events: external_exports.array(sessionEventV2Schema).max(MAX_EVENT_COUNT).readonly(),
21640
- tailCursor: external_exports.string().max(512),
21641
- truncated: external_exports.boolean()
21635
+ content: external_exports.array(contentBlockV2Schema).min(1).max(100).readonly()
21642
21636
  }).readonly();
21643
21637
  var nativeSessionEventsV2Schema = external_exports.object({
21644
- executingPromptRequest: executingPromptRequestEventLogV2Schema.nullable(),
21645
- history: sessionEventLogPageV2Schema
21638
+ events: sessionEventLogPageV2Schema,
21639
+ queuedPromptRequests: external_exports.array(queuedPromptRequestEventLogV2Schema).max(MAX_COLLECTION_SIZE).readonly()
21646
21640
  }).readonly();
21647
21641
  function inputValue(value) {
21648
21642
  if (typeof value !== "string") {
@@ -21666,7 +21660,6 @@ function decode5(value, schema) {
21666
21660
  function encode4(value, schema) {
21667
21661
  return JSON.stringify(decode5(value, schema));
21668
21662
  }
21669
- var decodeSessionEventV2 = (value) => decode5(value, sessionEventV2Schema);
21670
21663
  var decodeSessionEventEnvelopeV2 = (value) => decode5(value, sessionEventEnvelopeV2Schema);
21671
21664
  var encodeSessionEventEnvelopeV2 = (value) => encode4(value, sessionEventEnvelopeV2Schema);
21672
21665
  var decodeAcpSessionUpdateV2 = (value) => decode5(value, acpSessionUpdateV2Schema);
@@ -24481,7 +24474,7 @@ function sessionConfigProtocolForAgent(_agentId) {
24481
24474
 
24482
24475
  // src/acp/session-contracts.ts
24483
24476
  var NullAcpSessionObserver = class {
24484
- onAcpUpdate = (_sessionId, _update) => Promise.resolve();
24477
+ onSessionEventV2 = (_sessionId, _event, _position) => Promise.resolve();
24485
24478
  onCommands = () => Promise.resolve();
24486
24479
  onConfig = () => Promise.resolve();
24487
24480
  onContent = () => Promise.resolve();
@@ -24606,7 +24599,8 @@ function historyContentCharacters(messages) {
24606
24599
  var AcpHistoryReplay = class {
24607
24600
  #activities = /* @__PURE__ */ new Map();
24608
24601
  #messages = [];
24609
- #updates = [];
24602
+ #events = [];
24603
+ #records = [];
24610
24604
  #turnActivityIds = /* @__PURE__ */ new Set();
24611
24605
  #activityTracker = new AcpActivityTracker(
24612
24606
  async (activity2) => {
@@ -24628,8 +24622,10 @@ var AcpHistoryReplay = class {
24628
24622
  #firstMessageIndex = 0;
24629
24623
  #characters = 0;
24630
24624
  #truncated = false;
24631
- record = async (update, rawUpdate) => {
24632
- this.#updates.push(rawUpdate);
24625
+ record = async (update, rawUpdate, onRecorded = () => Promise.resolve()) => {
24626
+ this.#records.push({ kind: "acp", rawUpdate, update });
24627
+ this.#events.push({ payload: rawUpdate, type: "acp" });
24628
+ await onRecorded(this.#events.length);
24633
24629
  if (update.sessionUpdate === "agent_thought_chunk") {
24634
24630
  if (update.content.type === "text") {
24635
24631
  await this.#activityTracker.recordNarrative(
@@ -24638,30 +24634,30 @@ var AcpHistoryReplay = class {
24638
24634
  update.content.text
24639
24635
  );
24640
24636
  }
24641
- return;
24637
+ return this.#events.length;
24642
24638
  }
24643
24639
  if (update.sessionUpdate === "tool_call") {
24644
24640
  await this.#activityTracker.recordToolCall(update);
24645
- return;
24641
+ return this.#events.length;
24646
24642
  }
24647
24643
  if (update.sessionUpdate === "tool_call_update") {
24648
24644
  await this.#activityTracker.recordToolCallUpdate(update);
24649
- return;
24645
+ return this.#events.length;
24650
24646
  }
24651
24647
  if (update.sessionUpdate === "plan") {
24652
24648
  await this.#activityTracker.recordPlan(update);
24653
- return;
24649
+ return this.#events.length;
24654
24650
  }
24655
24651
  if (update.sessionUpdate === "plan_update") {
24656
24652
  await this.#activityTracker.recordPlanUpdate(update);
24657
- return;
24653
+ return this.#events.length;
24658
24654
  }
24659
24655
  if (update.sessionUpdate === "plan_removed") {
24660
24656
  await this.#activityTracker.removePlan(update);
24661
- return;
24657
+ return this.#events.length;
24662
24658
  }
24663
24659
  if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk") {
24664
- return;
24660
+ return this.#events.length;
24665
24661
  }
24666
24662
  if (update.sessionUpdate === "agent_message_chunk" && isProgressMessage(update)) {
24667
24663
  if (update.content.type === "text") {
@@ -24671,18 +24667,18 @@ var AcpHistoryReplay = class {
24671
24667
  update.content.text
24672
24668
  );
24673
24669
  }
24674
- return;
24670
+ return this.#events.length;
24675
24671
  }
24676
24672
  const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
24677
24673
  const content = update.content;
24678
24674
  if (role === "assistant" && content.type !== "text") {
24679
24675
  await this.#activityTracker.finishNarrative();
24680
24676
  this.recordAssistantContent(update.messageId ?? null, normalizeContentBlock(content));
24681
- return;
24677
+ return this.#events.length;
24682
24678
  }
24683
24679
  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]`;
24684
24680
  if (text2.length === 0) {
24685
- return;
24681
+ return this.#events.length;
24686
24682
  }
24687
24683
  const previous = this.#messages.at(-1);
24688
24684
  const id = update.messageId ?? null;
@@ -24709,10 +24705,30 @@ var AcpHistoryReplay = class {
24709
24705
  this.#characters += bounded2.length;
24710
24706
  this.#lastMessageId = id;
24711
24707
  this.trimMessages();
24708
+ return this.#events.length;
24709
+ };
24710
+ recordLifecycle = (event) => {
24711
+ if (event.type !== "lifecycle-metadata") {
24712
+ throw new Error("Lifecycle history only accepts lifecycle metadata");
24713
+ }
24714
+ this.#records.push({ event, kind: "lifecycle" });
24715
+ this.#events.push(event);
24716
+ return this.#events.length;
24717
+ };
24718
+ eventCount = () => this.#events.length;
24719
+ append = async (replay) => {
24720
+ for (const record2 of replay.#records) {
24721
+ if (record2.kind === "acp") {
24722
+ await this.record(record2.update, record2.rawUpdate);
24723
+ } else {
24724
+ this.recordLifecycle(record2.event);
24725
+ }
24726
+ }
24712
24727
  };
24713
- eventPage = (eventLimit, cursor) => {
24714
- const parsedCursor = cursor === null ? this.#updates.length : Number(cursor);
24715
- if (!Number.isSafeInteger(parsedCursor) || parsedCursor < 0 || parsedCursor > this.#updates.length) {
24728
+ eventPage = (eventLimit, cursor, appended = null) => {
24729
+ const events = appended === null ? this.#events : [...this.#events, ...appended.#events];
24730
+ const parsedCursor = cursor === null ? events.length : Number(cursor);
24731
+ if (!Number.isSafeInteger(parsedCursor) || parsedCursor < 0 || parsedCursor > events.length) {
24716
24732
  throw new Error("The native event cursor is invalid");
24717
24733
  }
24718
24734
  const endUpdate = parsedCursor;
@@ -24721,7 +24737,7 @@ var AcpHistoryReplay = class {
24721
24737
  nextCursor: startUpdate === 0 ? null : startUpdate.toString(),
24722
24738
  startPosition: startUpdate + 1,
24723
24739
  truncated: startUpdate > 0,
24724
- updates: this.#updates.slice(startUpdate, endUpdate)
24740
+ events: events.slice(startUpdate, endUpdate)
24725
24741
  };
24726
24742
  };
24727
24743
  snapshot = async () => {
@@ -25108,6 +25124,34 @@ var AcpSessionInteractions = class {
25108
25124
  constructor(context) {
25109
25125
  this.#context = context;
25110
25126
  }
25127
+ #notifyPermissionRequested = async (event) => {
25128
+ await this.#context.recordSessionEventV2({
25129
+ payload: { event, kind: "session.permission.requested" },
25130
+ type: "lifecycle-metadata"
25131
+ });
25132
+ await this.#context.observer().onPermission(event);
25133
+ };
25134
+ #notifyPermissionResolved = async (event) => {
25135
+ await this.#context.recordSessionEventV2({
25136
+ payload: { event, kind: "session.permission.resolved" },
25137
+ type: "lifecycle-metadata"
25138
+ });
25139
+ await this.#context.observer().onPermissionResolved(event);
25140
+ };
25141
+ #notifyElicitationRequested = async (event) => {
25142
+ await this.#context.recordSessionEventV2({
25143
+ payload: { event, kind: "session.elicitation.requested" },
25144
+ type: "lifecycle-metadata"
25145
+ });
25146
+ await this.#context.observer().onElicitation(event);
25147
+ };
25148
+ #notifyElicitationResolved = async (event) => {
25149
+ await this.#context.recordSessionEventV2({
25150
+ payload: { event, kind: "session.elicitation.resolved" },
25151
+ type: "lifecycle-metadata"
25152
+ });
25153
+ await this.#context.observer().onElicitationResolved(event);
25154
+ };
25111
25155
  respondPermission = async (options) => {
25112
25156
  const pending = this.#pendingPermissions.get(options.interactionId);
25113
25157
  if (pending === void 0) {
@@ -25133,7 +25177,7 @@ var AcpSessionInteractions = class {
25133
25177
  );
25134
25178
  }
25135
25179
  this.#pendingPermissions.delete(options.interactionId);
25136
- await this.#context.observer().onPermissionResolved({
25180
+ await this.#notifyPermissionResolved({
25137
25181
  interactionId: options.interactionId,
25138
25182
  kind: SESSION_PERMISSION_RESOLVED_KIND,
25139
25183
  optionId: options.outcome === "selected" ? options.optionId : "",
@@ -25173,7 +25217,7 @@ var AcpSessionInteractions = class {
25173
25217
  );
25174
25218
  }
25175
25219
  this.#pendingElicitations.delete(options.interactionId);
25176
- await this.#context.observer().onElicitationResolved({
25220
+ await this.#notifyElicitationResolved({
25177
25221
  action: options.action,
25178
25222
  interactionId: options.interactionId,
25179
25223
  kind: SESSION_ELICITATION_RESOLVED_KIND,
@@ -25202,7 +25246,7 @@ var AcpSessionInteractions = class {
25202
25246
  };
25203
25247
  signal.addEventListener("abort", abort, { once: true });
25204
25248
  try {
25205
- await this.#context.observer().onPermission({
25249
+ await this.#notifyPermissionRequested({
25206
25250
  commandId: this.#context.commandId(),
25207
25251
  interactionId,
25208
25252
  kind: SESSION_PERMISSION_REQUESTED_KIND,
@@ -25247,7 +25291,7 @@ var AcpSessionInteractions = class {
25247
25291
  };
25248
25292
  signal.addEventListener("abort", abort, { once: true });
25249
25293
  try {
25250
- await this.#context.observer().onElicitation({
25294
+ await this.#notifyElicitationRequested({
25251
25295
  accepted: false,
25252
25296
  commandId: this.#context.commandId(),
25253
25297
  elicitationId,
@@ -25271,7 +25315,7 @@ var AcpSessionInteractions = class {
25271
25315
  return;
25272
25316
  }
25273
25317
  this.#acceptedUrlElicitations.delete(notification.elicitationId);
25274
- await this.#context.observer().onElicitationResolved({
25318
+ await this.#notifyElicitationResolved({
25275
25319
  action: "complete",
25276
25320
  interactionId,
25277
25321
  kind: SESSION_ELICITATION_RESOLVED_KIND,
@@ -25284,7 +25328,7 @@ var AcpSessionInteractions = class {
25284
25328
  return;
25285
25329
  }
25286
25330
  this.#pendingPermissions.delete(interactionId);
25287
- await this.#context.observer().onPermissionResolved({
25331
+ await this.#notifyPermissionResolved({
25288
25332
  interactionId,
25289
25333
  kind: SESSION_PERMISSION_RESOLVED_KIND,
25290
25334
  optionId: "",
@@ -25298,7 +25342,7 @@ var AcpSessionInteractions = class {
25298
25342
  return;
25299
25343
  }
25300
25344
  this.#pendingElicitations.delete(interactionId);
25301
- await this.#context.observer().onElicitationResolved({
25345
+ await this.#notifyElicitationResolved({
25302
25346
  action: "cancel",
25303
25347
  interactionId,
25304
25348
  kind: SESSION_ELICITATION_RESOLVED_KIND,
@@ -25317,7 +25361,7 @@ var AcpSessionInteractions = class {
25317
25361
  await this.cancelElicitation(interactionId);
25318
25362
  }
25319
25363
  for (const interactionId of acceptedElicitationIds) {
25320
- await this.#context.observer().onElicitationResolved({
25364
+ await this.#notifyElicitationResolved({
25321
25365
  action: "cancel",
25322
25366
  interactionId,
25323
25367
  kind: SESSION_ELICITATION_RESOLVED_KIND,
@@ -30252,21 +30296,9 @@ var DeletedAcpStoredSession = class extends AcpStoredSessionLookup {
30252
30296
  var MemoryAcpSessionStore = class {
30253
30297
  #sessions = /* @__PURE__ */ new Map();
30254
30298
  #deleted = /* @__PURE__ */ new Set();
30255
- #eventsV2 = /* @__PURE__ */ new Map();
30256
- appendExecutingPromptEventV2 = (event) => {
30257
- const events = this.#eventsV2.get(event.sessionId);
30258
- if (events === void 0) {
30259
- throw new Error("The executing prompt event log has not started");
30260
- }
30261
- events.push(event);
30262
- };
30263
- clearExecutingPromptEventsV2 = (sessionId) => {
30264
- this.#eventsV2.delete(sessionId);
30265
- };
30266
30299
  close = () => {
30267
30300
  this.#sessions.clear();
30268
30301
  this.#deleted.clear();
30269
- this.#eventsV2.clear();
30270
30302
  };
30271
30303
  findNative = (agentId, nativeSessionId) => [...this.#sessions.values()].filter(
30272
30304
  (session) => session.agentId === agentId && session.nativeSessionId === nativeSessionId
@@ -30277,7 +30309,6 @@ var MemoryAcpSessionStore = class {
30277
30309
  for (const id of ids) {
30278
30310
  this.#sessions.delete(id);
30279
30311
  this.#deleted.add(id);
30280
- this.#eventsV2.delete(id);
30281
30312
  }
30282
30313
  return ids;
30283
30314
  };
@@ -30290,13 +30321,6 @@ var MemoryAcpSessionStore = class {
30290
30321
  };
30291
30322
  remove = (sessionId) => {
30292
30323
  this.#sessions.delete(sessionId);
30293
- this.#eventsV2.delete(sessionId);
30294
- };
30295
- readExecutingPromptEventsV2 = (sessionId) => [
30296
- ...this.#eventsV2.get(sessionId) ?? []
30297
- ];
30298
- startExecutingPromptEventsV2 = (sessionId, events) => {
30299
- this.#eventsV2.set(sessionId, [...events]);
30300
30324
  };
30301
30325
  write = (session) => {
30302
30326
  this.#sessions.set(session.sessionId, session);
@@ -30375,30 +30399,6 @@ var SqliteAcpSessionStore = class {
30375
30399
  close = () => {
30376
30400
  this.#sqliteDatabase.close();
30377
30401
  };
30378
- appendExecutingPromptEventV2 = (event) => {
30379
- this.#database.insert(sessionEventV2).values({
30380
- eventId: event.eventId,
30381
- eventJson: JSON.stringify(event),
30382
- position: Number(event.position),
30383
- sessionId: event.sessionId
30384
- }).run();
30385
- };
30386
- clearExecutingPromptEventsV2 = (sessionId) => {
30387
- this.#database.delete(sessionEventV2).where(eq(sessionEventV2.sessionId, sessionId)).run();
30388
- };
30389
- startExecutingPromptEventsV2 = (sessionId, events) => {
30390
- this.#transaction(() => {
30391
- this.#database.delete(sessionEventV2).where(eq(sessionEventV2.sessionId, sessionId)).run();
30392
- for (const event of events) {
30393
- this.#database.insert(sessionEventV2).values({
30394
- eventId: event.eventId,
30395
- eventJson: JSON.stringify(event),
30396
- position: Number(event.position),
30397
- sessionId: event.sessionId
30398
- }).run();
30399
- }
30400
- });
30401
- };
30402
30402
  findNative = (agentId, nativeSessionId) => this.#database.select().from(acpSession).where(and(eq(acpSession.agentId, agentId), eq(acpSession.nativeSessionId, nativeSessionId))).all().map(decodeStoredSession);
30403
30403
  list = () => this.#database.select().from(acpSession).orderBy(desc(acpSession.updatedAt)).all().map(decodeStoredSession);
30404
30404
  markDeleted = (agentId, nativeSessionId) => {
@@ -30407,7 +30407,6 @@ var SqliteAcpSessionStore = class {
30407
30407
  this.#database.delete(acpSession).where(and(eq(acpSession.agentId, agentId), eq(acpSession.nativeSessionId, nativeSessionId))).run();
30408
30408
  for (const id of ids) {
30409
30409
  this.#database.insert(deletedAcpSession).values({ sessionId: id }).onConflictDoNothing().run();
30410
- this.#database.delete(sessionEventV2).where(eq(sessionEventV2.sessionId, id)).run();
30411
30410
  }
30412
30411
  });
30413
30412
  return ids;
@@ -30421,12 +30420,8 @@ var SqliteAcpSessionStore = class {
30421
30420
  const row = this.#database.select().from(acpSession).where(eq(acpSession.sessionId, sessionId)).get();
30422
30421
  return row === void 0 ? new MissingAcpStoredSession() : new FoundAcpStoredSession(decodeStoredSession(row));
30423
30422
  };
30424
- 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));
30425
30423
  remove = (sessionId) => {
30426
- this.#transaction(() => {
30427
- this.#database.delete(acpSession).where(eq(acpSession.sessionId, sessionId)).run();
30428
- this.#database.delete(sessionEventV2).where(eq(sessionEventV2.sessionId, sessionId)).run();
30429
- });
30424
+ this.#database.delete(acpSession).where(eq(acpSession.sessionId, sessionId)).run();
30430
30425
  };
30431
30426
  write = (session) => {
30432
30427
  const value = {
@@ -30496,6 +30491,7 @@ var AgentSession = class _AgentSession {
30496
30491
  #sessionTitle = null;
30497
30492
  #sessionUpdatedAt = "";
30498
30493
  #turn = new IdleAcpTurn();
30494
+ #turnHistory = null;
30499
30495
  constructor(agent, cwd, additionalDirectories, mobiusSessionId, getObserver, store, metrics, contentExternalizer) {
30500
30496
  this.#updates = new AgentUpdateStream((notification) => this.#processUpdate(notification));
30501
30497
  this.#additionalDirectories = [...additionalDirectories];
@@ -30513,7 +30509,8 @@ var AgentSession = class _AgentSession {
30513
30509
  sessionId: () => this.#mobiusSessionId,
30514
30510
  commandId: () => this.#turn.commandId,
30515
30511
  assertNativeSession: (sessionId) => this.assertNativeSession(sessionId),
30516
- observer: getObserver
30512
+ observer: getObserver,
30513
+ recordSessionEventV2: this.#recordLifecycleEventV2
30517
30514
  });
30518
30515
  this.#connection = new AgentConnection(agent, cwd, this);
30519
30516
  this.#contentExternalizer = contentExternalizer;
@@ -30609,13 +30606,10 @@ var AgentSession = class _AgentSession {
30609
30606
  }
30610
30607
  };
30611
30608
  }
30612
- const loaded = await this.#loadSession(signal, "ACP agent exited while loading history");
30613
- return await embedLocalHistoryImages(await loaded.history.snapshot(), signal);
30609
+ const history = await this.#completedHistory(signal, "ACP agent exited while loading history");
30610
+ return await embedLocalHistoryImages(await history.snapshot(), signal);
30614
30611
  };
30615
30612
  loadHistoryEventsV2 = async (eventLimit, cursor, signal) => {
30616
- if (!this.#prompted && this.#nativeHistoryOwnership.kind === "fresh-session") {
30617
- return new AcpHistoryReplay().eventPage(eventLimit, cursor);
30618
- }
30619
30613
  if (!this.#capabilities.loadSession) {
30620
30614
  throw new AcpExecutionError(
30621
30615
  "This Agent restores context but does not provide message history.",
@@ -30623,9 +30617,20 @@ var AgentSession = class _AgentSession {
30623
30617
  "native_history_unsupported"
30624
30618
  );
30625
30619
  }
30626
- const loaded = await this.#loadSession(signal, "ACP agent exited while loading history");
30627
- return loaded.history.eventPage(eventLimit, cursor);
30620
+ const history = await this.#completedHistory(signal, "ACP agent exited while loading history");
30621
+ return history.eventPage(eventLimit, cursor, this.#turnHistory);
30628
30622
  };
30623
+ async #completedHistory(signal, exitMessage) {
30624
+ if (!this.#prompted && this.#nativeHistoryOwnership.kind === "fresh-session") {
30625
+ if (this.#sessionLoad.kind === "not-requested") {
30626
+ this.#sessionLoad = { history: new AcpHistoryReplay(), kind: "loaded", response: {} };
30627
+ }
30628
+ if (this.#sessionLoad.kind === "loaded") {
30629
+ return this.#sessionLoad.history;
30630
+ }
30631
+ }
30632
+ return (await this.#loadSession(signal, exitMessage)).history;
30633
+ }
30629
30634
  async #loadSession(signal, exitMessage) {
30630
30635
  if (this.#sessionLoad.kind === "loaded") {
30631
30636
  return this.#sessionLoad;
@@ -31109,19 +31114,7 @@ var AgentSession = class _AgentSession {
31109
31114
  if (this.#turn.running) {
31110
31115
  throw new AcpExecutionError("Another prompt is already running in this conversation", {}, "session_busy");
31111
31116
  }
31112
- switch (this.#sessionLoad.kind) {
31113
- case "not-requested":
31114
- break;
31115
- case "loaded":
31116
- this.#sessionLoad = { kind: "not-requested" };
31117
- break;
31118
- case "capturing":
31119
- throw new AcpExecutionError("Session history is still loading", {}, "session_busy");
31120
- default: {
31121
- const unexpected = this.#sessionLoad;
31122
- throw new Error(`Unexpected Session load state: ${JSON.stringify(unexpected)}`);
31123
- }
31124
- }
31117
+ const completedHistory = this.#capabilities.loadSession ? await this.#completedHistory(options.signal, "ACP agent exited while loading history before a prompt") : null;
31125
31118
  const prompt = this.buildPrompt(options);
31126
31119
  if (this.#sessionTitle === null || this.#sessionTitle.length === 0) {
31127
31120
  this.#sessionTitle = truncate2(options.prompt, 500);
@@ -31148,6 +31141,23 @@ var AgentSession = class _AgentSession {
31148
31141
  this.prepareAgentContent
31149
31142
  );
31150
31143
  this.#turn = running;
31144
+ this.#turnHistory = completedHistory === null ? null : new AcpHistoryReplay();
31145
+ const lifecycleV2 = options.lifecycleV2;
31146
+ if (lifecycleV2 !== void 0) {
31147
+ await this.#recordLifecycleEventV2({
31148
+ payload: { commandId: options.commandId, content: lifecycleV2.content, kind: "prompt.requested" },
31149
+ type: "lifecycle-metadata"
31150
+ });
31151
+ await this.#recordLifecycleEventV2({
31152
+ payload: {
31153
+ attemptId: lifecycleV2.attemptId,
31154
+ commandId: options.commandId,
31155
+ epoch: lifecycleV2.epoch,
31156
+ kind: "prompt.started"
31157
+ },
31158
+ type: "lifecycle-metadata"
31159
+ });
31160
+ }
31151
31161
  this.#nativePrompt = {
31152
31162
  commandId: options.commandId,
31153
31163
  previousTurnId: this.#connection.inProcessAgent?.nativeTurnId?.() ?? null
@@ -31202,16 +31212,37 @@ var AgentSession = class _AgentSession {
31202
31212
  this.#lastTerminalCommandId
31203
31213
  )
31204
31214
  );
31215
+ if (lifecycleV2 !== void 0) {
31216
+ await this.#recordLifecycleEventV2({
31217
+ payload: { commandId: options.commandId, kind: "prompt.completed", stopReason: result.stopReason },
31218
+ type: "lifecycle-metadata"
31219
+ });
31220
+ }
31205
31221
  return result;
31206
31222
  } catch (error62) {
31207
31223
  await running.activities.finish();
31224
+ const failure2 = error62 instanceof AcpExecutionError ? error62 : new AcpExecutionError("ACP agent execution failed", { cause: error62 });
31225
+ if (lifecycleV2 !== void 0) {
31226
+ await this.#recordLifecycleEventV2({
31227
+ payload: {
31228
+ attemptId: lifecycleV2.attemptId,
31229
+ code: failure2.code,
31230
+ commandId: options.commandId,
31231
+ kind: "prompt.failed",
31232
+ message: truncate2(failure2.message, 500)
31233
+ },
31234
+ type: "lifecycle-metadata"
31235
+ });
31236
+ }
31208
31237
  if (error62 instanceof AcpExecutionError) {
31209
31238
  throw error62;
31210
31239
  }
31211
- throw new AcpExecutionError("ACP agent execution failed", {
31212
- cause: error62
31213
- });
31240
+ throw failure2;
31214
31241
  } finally {
31242
+ if (completedHistory !== null && this.#turnHistory !== null) {
31243
+ await completedHistory.append(this.#turnHistory);
31244
+ }
31245
+ this.#turnHistory = null;
31215
31246
  this.#turn = new IdleAcpTurn();
31216
31247
  }
31217
31248
  };
@@ -31227,41 +31258,80 @@ var AgentSession = class _AgentSession {
31227
31258
  throw new AcpExecutionError("The target turn is no longer active", {}, "steering_target_unavailable");
31228
31259
  }
31229
31260
  const prompt = this.buildPrompt(options);
31230
- const response = await this.race(
31231
- this.#connection.connection.agent.request("_session/steering", {
31232
- _meta: { steering: { idleBehavior: "promptRequired" } },
31233
- prompt,
31234
- sessionId: this.#updates.sessionId()
31235
- }),
31236
- "ACP agent exited during steering",
31237
- options.signal
31238
- );
31239
- if (!isRecord4(response)) {
31261
+ const lifecycleV2 = options.lifecycleV2;
31262
+ if (lifecycleV2 !== void 0) {
31263
+ await this.#recordLifecycleEventV2({
31264
+ payload: { commandId: options.commandId, content: lifecycleV2.content, kind: "prompt.requested" },
31265
+ type: "lifecycle-metadata"
31266
+ });
31267
+ await this.#recordLifecycleEventV2({
31268
+ payload: {
31269
+ attemptId: lifecycleV2.attemptId,
31270
+ commandId: options.commandId,
31271
+ epoch: lifecycleV2.epoch,
31272
+ kind: "prompt.started"
31273
+ },
31274
+ type: "lifecycle-metadata"
31275
+ });
31276
+ }
31277
+ try {
31278
+ const response = await this.race(
31279
+ this.#connection.connection.agent.request("_session/steering", {
31280
+ _meta: { steering: { idleBehavior: "promptRequired" } },
31281
+ prompt,
31282
+ sessionId: this.#updates.sessionId()
31283
+ }),
31284
+ "ACP agent exited during steering",
31285
+ options.signal
31286
+ );
31287
+ if (!isRecord4(response)) {
31288
+ throw new AcpExecutionError(
31289
+ "ACP agent returned an invalid steering response",
31290
+ {},
31291
+ "acp_invalid_steering_response"
31292
+ );
31293
+ }
31294
+ const outcome = response["outcome"];
31295
+ if (outcome === "injected" || outcome === "startedNewTurn") {
31296
+ if (lifecycleV2 !== void 0) {
31297
+ await this.#recordLifecycleEventV2({
31298
+ payload: { commandId: options.commandId, kind: "prompt.completed", stopReason: "steered" },
31299
+ type: "lifecycle-metadata"
31300
+ });
31301
+ }
31302
+ return outcome;
31303
+ }
31304
+ if (outcome === "promptRequired") {
31305
+ throw new AcpExecutionError(
31306
+ "The target turn finished before steering could be injected",
31307
+ {},
31308
+ "steering_target_unavailable"
31309
+ );
31310
+ }
31311
+ if (outcome === "failed") {
31312
+ throw new AcpExecutionError("The Agent could not inject steering", {}, "steering_failed");
31313
+ }
31240
31314
  throw new AcpExecutionError(
31241
31315
  "ACP agent returned an invalid steering response",
31242
31316
  {},
31243
31317
  "acp_invalid_steering_response"
31244
31318
  );
31319
+ } catch (error62) {
31320
+ const failure2 = error62 instanceof AcpExecutionError ? error62 : new AcpExecutionError("ACP agent execution failed", { cause: error62 });
31321
+ if (lifecycleV2 !== void 0) {
31322
+ await this.#recordLifecycleEventV2({
31323
+ payload: {
31324
+ attemptId: lifecycleV2.attemptId,
31325
+ code: failure2.code,
31326
+ commandId: options.commandId,
31327
+ kind: "prompt.failed",
31328
+ message: truncate2(failure2.message, 500)
31329
+ },
31330
+ type: "lifecycle-metadata"
31331
+ });
31332
+ }
31333
+ throw failure2;
31245
31334
  }
31246
- const outcome = response["outcome"];
31247
- if (outcome === "injected" || outcome === "startedNewTurn") {
31248
- return outcome;
31249
- }
31250
- if (outcome === "promptRequired") {
31251
- throw new AcpExecutionError(
31252
- "The target turn finished before steering could be injected",
31253
- {},
31254
- "steering_target_unavailable"
31255
- );
31256
- }
31257
- if (outcome === "failed") {
31258
- throw new AcpExecutionError("The Agent could not inject steering", {}, "steering_failed");
31259
- }
31260
- throw new AcpExecutionError(
31261
- "ACP agent returned an invalid steering response",
31262
- {},
31263
- "acp_invalid_steering_response"
31264
- );
31265
31335
  };
31266
31336
  cancel = async () => {
31267
31337
  const capturedProcesses = await this.#connection.captureProcessTree();
@@ -31282,6 +31352,13 @@ var AgentSession = class _AgentSession {
31282
31352
  onElicitation = (request, signal) => this.#interactions.onElicitation(request, signal);
31283
31353
  onElicitationComplete = (notification) => this.#interactions.onElicitationComplete(notification);
31284
31354
  onUpdate = (notification) => this.#updates.receive(notification);
31355
+ #recordLifecycleEventV2 = async (event) => {
31356
+ if (event.type !== "lifecycle-metadata" || this.#sessionLoad.kind !== "loaded") {
31357
+ return;
31358
+ }
31359
+ const position = this.#turnHistory === null ? this.#sessionLoad.history.recordLifecycle(event) : this.#sessionLoad.history.eventCount() + this.#turnHistory.recordLifecycle(event);
31360
+ await this.#getObserver().onSessionEventV2?.(this.#mobiusSessionId, event, position);
31361
+ };
31285
31362
  selectNativeSession = (sessionId) => {
31286
31363
  this.#updates.select(sessionId);
31287
31364
  this.#nativeHistoryOwnership = { kind: "agent-owned" };
@@ -31298,9 +31375,20 @@ var AgentSession = class _AgentSession {
31298
31375
  if (this.#sessionLoad.kind === "capturing") {
31299
31376
  await this.#sessionLoad.history.record(update, rawUpdate);
31300
31377
  } else {
31301
- const onAcpUpdate = this.#getObserver().onAcpUpdate;
31302
- if (onAcpUpdate !== void 0) {
31303
- await onAcpUpdate(this.#mobiusSessionId, rawUpdate);
31378
+ const onSessionEventV2 = this.#getObserver().onSessionEventV2;
31379
+ if (this.#turnHistory !== null) {
31380
+ const completedEventCount = this.#sessionLoad.kind === "loaded" ? this.#sessionLoad.history.eventCount() : 0;
31381
+ await this.#turnHistory.record(update, rawUpdate, async (turnPosition) => {
31382
+ await onSessionEventV2?.(
31383
+ this.#mobiusSessionId,
31384
+ { payload: rawUpdate, type: "acp" },
31385
+ completedEventCount + turnPosition
31386
+ );
31387
+ });
31388
+ } else if (this.#sessionLoad.kind === "loaded") {
31389
+ await this.#sessionLoad.history.record(update, rawUpdate, async (position) => {
31390
+ await onSessionEventV2?.(this.#mobiusSessionId, { payload: rawUpdate, type: "acp" }, position);
31391
+ });
31304
31392
  }
31305
31393
  }
31306
31394
  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")) {
@@ -32994,13 +33082,19 @@ var AgentRuntimeManager = class {
32994
33082
  // src/acp/run-prompt.ts
32995
33083
  async function runAcpPrompt(options) {
32996
33084
  const agentRuntime = new AgentRuntimeManager();
33085
+ const commandId = crypto.randomUUID();
32997
33086
  try {
32998
33087
  return await agentRuntime.runPrompt({
32999
33088
  additionalDirectories: [],
33000
33089
  agent: new LocalAgentDefinition("test-agent", "Test agent", options.agentCommand, options.agentArguments),
33001
33090
  cwd: options.cwd,
33002
- commandId: crypto.randomUUID(),
33091
+ commandId,
33003
33092
  images: [],
33093
+ lifecycleV2: {
33094
+ attemptId: crypto.randomUUID(),
33095
+ content: [{ text: options.prompt, type: "text" }],
33096
+ epoch: crypto.randomUUID()
33097
+ },
33004
33098
  onActivity: options.onActivity,
33005
33099
  ...options.onNarration === void 0 ? {} : { onNarration: options.onNarration },
33006
33100
  onText: options.onText,
@@ -34691,8 +34785,8 @@ function promptInput(prompt) {
34691
34785
  function isCompactPrompt(prompt) {
34692
34786
  return prompt.length === 1 && prompt[0]?.type === "text" && prompt[0].text.trim() === "/compact";
34693
34787
  }
34694
- function steeringPromptInput(prompt) {
34695
- const input2 = [];
34788
+ function steeringPrompt(prompt) {
34789
+ const blocks = [];
34696
34790
  for (const block of prompt) {
34697
34791
  if (typeof block !== "object" || block === null) {
34698
34792
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
@@ -34703,7 +34797,7 @@ function steeringPromptInput(prompt) {
34703
34797
  if (typeof text2 !== "string") {
34704
34798
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
34705
34799
  }
34706
- input2.push({ text: text2, text_elements: [], type: "text" });
34800
+ blocks.push({ content: { text: text2, type: "text" }, input: { text: text2, text_elements: [], type: "text" } });
34707
34801
  continue;
34708
34802
  }
34709
34803
  if (type === "image") {
@@ -34712,7 +34806,10 @@ function steeringPromptInput(prompt) {
34712
34806
  if (typeof data !== "string" || typeof mimeType !== "string") {
34713
34807
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
34714
34808
  }
34715
- input2.push({ type: "image", url: `data:${mimeType};base64,${data}` });
34809
+ blocks.push({
34810
+ content: { data, mimeType, type: "image" },
34811
+ input: { type: "image", url: `data:${mimeType};base64,${data}` }
34812
+ });
34716
34813
  continue;
34717
34814
  }
34718
34815
  if (type === "resource") {
@@ -34720,24 +34817,33 @@ function steeringPromptInput(prompt) {
34720
34817
  if (typeof resource !== "object" || resource === null) {
34721
34818
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
34722
34819
  }
34820
+ const uri = Reflect.get(resource, "uri");
34723
34821
  const text2 = Reflect.get(resource, "text");
34724
- if (text2 !== void 0 && typeof text2 !== "string") {
34822
+ const blob2 = Reflect.get(resource, "blob");
34823
+ if (typeof uri !== "string" || typeof text2 !== "string" && typeof blob2 !== "string" || text2 !== void 0 && typeof text2 !== "string" || blob2 !== void 0 && typeof blob2 !== "string") {
34725
34824
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
34726
34825
  }
34727
- input2.push({ text: text2 ?? "", text_elements: [], type: "text" });
34826
+ blocks.push({
34827
+ content: typeof text2 === "string" ? { resource: { text: text2, uri }, type: "resource" } : { resource: { blob: blob2, uri }, type: "resource" },
34828
+ input: { text: text2 ?? "", text_elements: [], type: "text" }
34829
+ });
34728
34830
  continue;
34729
34831
  }
34730
34832
  if (type === "resource_link") {
34833
+ const name2 = Reflect.get(block, "name");
34731
34834
  const uri = Reflect.get(block, "uri");
34732
- if (typeof uri !== "string") {
34835
+ if (typeof name2 !== "string" || typeof uri !== "string") {
34733
34836
  throw new AcpExecutionError("Codex received an invalid steering prompt", {}, "invalid_request");
34734
34837
  }
34735
- input2.push({ text: `Resource: ${uri}`, text_elements: [], type: "text" });
34838
+ blocks.push({
34839
+ content: { name: name2, type: "resource_link", uri },
34840
+ input: { text: `Resource: ${uri}`, text_elements: [], type: "text" }
34841
+ });
34736
34842
  continue;
34737
34843
  }
34738
34844
  throw new AcpExecutionError("Codex received an unsupported steering prompt", {}, "invalid_request");
34739
34845
  }
34740
- return input2;
34846
+ return blocks;
34741
34847
  }
34742
34848
  function agentMessageUpdate(messageId, text2, phase) {
34743
34849
  return {
@@ -34884,6 +34990,14 @@ var CodexAcpAgent = class {
34884
34990
  if (isCompactPrompt(context.params.prompt)) {
34885
34991
  return await this.#compact(context.signal);
34886
34992
  }
34993
+ const messageId = crypto.randomUUID();
34994
+ for (const content of context.params.prompt) {
34995
+ await this.#emit({
34996
+ content,
34997
+ messageId,
34998
+ sessionUpdate: "user_message_chunk"
34999
+ });
35000
+ }
34887
35001
  return await this.#runTurn(promptInput(context.params.prompt), context.signal);
34888
35002
  }).onRequest(
34889
35003
  "_session/steering",
@@ -35365,14 +35479,22 @@ var CodexAcpAgent = class {
35365
35479
  if (sessionId !== this.#nativeSessionId || active === null || active.turn.id.length === 0) {
35366
35480
  return { outcome: "promptRequired", reason: "noRunningTurn" };
35367
35481
  }
35368
- const input2 = steeringPromptInput(prompt);
35369
- if (input2.length === 0) {
35482
+ const steering = steeringPrompt(prompt);
35483
+ if (steering.length === 0) {
35370
35484
  throw new AcpExecutionError("Codex received an empty steering request", {}, "invalid_request");
35371
35485
  }
35486
+ const messageId = crypto.randomUUID();
35487
+ for (const block of steering) {
35488
+ await this.#emit({ content: block.content, messageId, sessionUpdate: "user_message_chunk" });
35489
+ }
35372
35490
  const response = turnSteerResponseSchema.parse(
35373
35491
  await this.#appServer.request(
35374
35492
  "turn/steer",
35375
- { expectedTurnId: active.turn.id, input: input2, threadId: this.#nativeSessionId },
35493
+ {
35494
+ expectedTurnId: active.turn.id,
35495
+ input: steering.map((block) => block.input),
35496
+ threadId: this.#nativeSessionId
35497
+ },
35376
35498
  AbortSignal.any([signal, AbortSignal.timeout(APPROVAL_TIMEOUT_MILLISECONDS2)])
35377
35499
  )
35378
35500
  );
@@ -38052,7 +38174,7 @@ function isRuntimeRelayRevocation(closeCode, closeReason) {
38052
38174
  }
38053
38175
 
38054
38176
  // src/run-daemon.ts
38055
- import { createHash as createHash8, randomUUID as randomUUID8 } from "node:crypto";
38177
+ import { createHash as createHash8, randomUUID as randomUUID9 } from "node:crypto";
38056
38178
  import { join as join19 } from "node:path";
38057
38179
  import { styleText } from "node:util";
38058
38180
 
@@ -39133,8 +39255,8 @@ var DaemonAcpObserver = class {
39133
39255
  this.#record = record2;
39134
39256
  this.#recordV2 = recordV2;
39135
39257
  }
39136
- onAcpUpdate = (sessionId, update) => {
39137
- this.#recordV2(sessionId, { payload: update, type: "acp" });
39258
+ onSessionEventV2 = (sessionId, event, position) => {
39259
+ this.#recordV2(sessionId, event, position);
39138
39260
  return Promise.resolve();
39139
39261
  };
39140
39262
  onCommands = (event) => {
@@ -39151,18 +39273,10 @@ var DaemonAcpObserver = class {
39151
39273
  };
39152
39274
  onElicitation = (event) => {
39153
39275
  this.#record(event.sessionId, event);
39154
- this.#recordV2(event.sessionId, {
39155
- payload: { event, kind: "session.elicitation.requested" },
39156
- type: "lifecycle-metadata"
39157
- });
39158
39276
  return Promise.resolve();
39159
39277
  };
39160
39278
  onElicitationResolved = (event) => {
39161
39279
  this.#record(event.sessionId, event);
39162
- this.#recordV2(event.sessionId, {
39163
- payload: { event, kind: "session.elicitation.resolved" },
39164
- type: "lifecycle-metadata"
39165
- });
39166
39280
  return Promise.resolve();
39167
39281
  };
39168
39282
  onInfo = (event) => {
@@ -39171,18 +39285,10 @@ var DaemonAcpObserver = class {
39171
39285
  };
39172
39286
  onPermission = (event) => {
39173
39287
  this.#record(event.sessionId, event);
39174
- this.#recordV2(event.sessionId, {
39175
- payload: { event, kind: "session.permission.requested" },
39176
- type: "lifecycle-metadata"
39177
- });
39178
39288
  return Promise.resolve();
39179
39289
  };
39180
39290
  onPermissionResolved = (event) => {
39181
39291
  this.#record(event.sessionId, event);
39182
- this.#recordV2(event.sessionId, {
39183
- payload: { event, kind: "session.permission.resolved" },
39184
- type: "lifecycle-metadata"
39185
- });
39186
39292
  return Promise.resolve();
39187
39293
  };
39188
39294
  onUsage = (event) => {
@@ -42042,9 +42148,6 @@ async function streamLocalFile(command, send2, signal, workingDirectory, externa
42042
42148
  });
42043
42149
  }
42044
42150
 
42045
- // src/daemon-history-commands.ts
42046
- import { createHash as createHash7 } from "node:crypto";
42047
-
42048
42151
  // src/authorization/resolve-session-directories.ts
42049
42152
  import { basename as basename7 } from "node:path";
42050
42153
  var ResolvedSessionDirectories = class {
@@ -42371,20 +42474,7 @@ async function executeSessionLiveHistoryPageLoad(socket, command, config2, direc
42371
42474
  });
42372
42475
  }
42373
42476
  }
42374
- function replayEvent(sessionId, position, update) {
42375
- const encoded = JSON.stringify(update);
42376
- const eventId = `native-${createHash7("sha256").update(sessionId).update(":").update(position.toString()).update(":").update(encoded).digest("hex")}`;
42377
- return {
42378
- eventId,
42379
- payload: update,
42380
- position: position.toString(),
42381
- provenance: { kind: "original" },
42382
- recordedAt: "1970-01-01T00:00:00.000Z",
42383
- sessionId,
42384
- type: "acp"
42385
- };
42386
- }
42387
- async function executeSessionLiveHistoryV2PageLoad(socket, command, config2, directories, audit, diagnostics, sessions, executingPromptRequest, signal) {
42477
+ async function executeSessionLiveHistoryV2PageLoad(socket, command, config2, directories, audit, diagnostics, sessions, eventLogV2, signal) {
42388
42478
  try {
42389
42479
  const resolved = await resolveSessionDirectories(
42390
42480
  directories,
@@ -42393,20 +42483,18 @@ async function executeSessionLiveHistoryV2PageLoad(socket, command, config2, dir
42393
42483
  command.additionalDirectoryIds,
42394
42484
  signal
42395
42485
  );
42396
- const replay = await sessions.loadSessionEventsV2(
42397
- {
42398
- additionalDirectories: resolved.additionalDirectories,
42399
- agent: config2.catalog.find(command.agentId),
42400
- cwd: resolved.cwd,
42401
- sessionId: command.sessionId,
42402
- signal
42403
- },
42404
- command.eventLimit,
42405
- command.cursor
42406
- );
42486
+ const loadOptions = {
42487
+ additionalDirectories: resolved.additionalDirectories,
42488
+ agent: config2.catalog.find(command.agentId),
42489
+ cwd: resolved.cwd,
42490
+ sessionId: command.sessionId,
42491
+ signal
42492
+ };
42493
+ const recovery = eventLogV2.promptRequestRecovery(command.sessionId);
42494
+ const replay = await sessions.loadSessionEventsV2(loadOptions, command.eventLimit, command.cursor);
42407
42495
  signal.throwIfAborted();
42408
- const events = replay.updates.map(
42409
- (update, index2) => replayEvent(command.sessionId, replay.startPosition + index2, update)
42496
+ const events = replay.events.map(
42497
+ (event, index2) => eventLogV2.event(command.sessionId, replay.startPosition + index2, event, "1970-01-01T00:00:00.000Z")
42410
42498
  );
42411
42499
  const tailCursor = events.at(-1)?.eventId ?? "";
42412
42500
  audit.record({
@@ -42416,14 +42504,15 @@ async function executeSessionLiveHistoryV2PageLoad(socket, command, config2, dir
42416
42504
  });
42417
42505
  send(socket, {
42418
42506
  events: {
42419
- executingPromptRequest: executingPromptRequest(command.sessionId),
42420
- history: {
42507
+ events: {
42508
+ daemonGenerationId: eventLogV2.daemonGenerationId,
42421
42509
  events,
42422
42510
  nextCursor: replay.nextCursor,
42423
42511
  tailCursor,
42424
42512
  truncated: replay.truncated,
42425
42513
  version: 2
42426
- }
42514
+ },
42515
+ queuedPromptRequests: recovery.queuedPromptRequests
42427
42516
  },
42428
42517
  kind: "session.live-history.v2.page.loaded",
42429
42518
  requestId: command.requestId,
@@ -42873,7 +42962,7 @@ async function executePrompt({
42873
42962
  }
42874
42963
  }
42875
42964
  const stream = activateAttempt();
42876
- eventLogV2.started(command.sessionId, command.commandId, attemptId, stream.epoch);
42965
+ const lifecycleV2 = eventLogV2.started(command.sessionId, command.commandId, attemptId, stream.epoch);
42877
42966
  if (!prepared.prompted) {
42878
42967
  const listing = await directories.list(config2.bindingId, command.directoryId, signal);
42879
42968
  publisher.publish(command.sessionId, {
@@ -42910,6 +42999,7 @@ async function executePrompt({
42910
42999
  commandId: command.commandId,
42911
43000
  cwd: resolved.cwd,
42912
43001
  images: attachments.images,
43002
+ lifecycleV2,
42913
43003
  prompt: command.prompt,
42914
43004
  resources: attachments.resources,
42915
43005
  sessionId: command.sessionId,
@@ -42925,6 +43015,7 @@ async function executePrompt({
42925
43015
  cwd: resolved.cwd,
42926
43016
  disposition: availability.disposition,
42927
43017
  images: attachments.images,
43018
+ lifecycleV2,
42928
43019
  onActivity: events.recordActivity,
42929
43020
  onNarration: events.recordNarration,
42930
43021
  onText: events.recordText,
@@ -43339,7 +43430,7 @@ function createDaemonCommandHandler({
43339
43430
  audit,
43340
43431
  diagnostics,
43341
43432
  sessions,
43342
- eventLogV2.executingPromptRequest,
43433
+ eventLogV2,
43343
43434
  signal
43344
43435
  );
43345
43436
  return;
@@ -43992,10 +44083,6 @@ import { WebSocket as WebSocket9 } from "undici";
43992
44083
  var MAX_BUFFERED_BYTES = 32 * 1024 * 1024;
43993
44084
  var DaemonSessionEventPublisher = class {
43994
44085
  #socket = null;
43995
- #store;
43996
- constructor(store) {
43997
- this.#store = store;
43998
- }
43999
44086
  connect = (socket) => {
44000
44087
  this.#socket = socket;
44001
44088
  };
@@ -44047,7 +44134,6 @@ var DaemonSessionEventPublisher = class {
44047
44134
  }
44048
44135
  };
44049
44136
  publishV2 = (event) => {
44050
- this.#store.appendExecutingPromptEventV2(event);
44051
44137
  const socket = this.#socket;
44052
44138
  if (socket === null || socket.readyState !== WebSocket9.OPEN) {
44053
44139
  return;
@@ -44074,7 +44160,7 @@ var SystemDaemonTimer = class {
44074
44160
  var systemDaemonTimer = new SystemDaemonTimer();
44075
44161
 
44076
44162
  // src/session-event-log-v2.ts
44077
- var EXECUTING_PROMPT_EVENT_LIMIT = 1e4;
44163
+ import { createHash as createHash7, randomUUID as randomUUID8 } from "node:crypto";
44078
44164
  function promptContent(command) {
44079
44165
  const content = [];
44080
44166
  if (command.prompt.length > 0) {
@@ -44098,176 +44184,59 @@ function promptContent(command) {
44098
44184
  }
44099
44185
  return content;
44100
44186
  }
44187
+ function sessionEventV22(daemonGenerationId, sessionId, position, event, recordedAt) {
44188
+ const sessionPrefix = createHash7("sha256").update(sessionId).digest("hex").slice(0, 16);
44189
+ return {
44190
+ eventId: `event-${daemonGenerationId}-${sessionPrefix}-${position.toString().padStart(16, "0")}`,
44191
+ ...event,
44192
+ position: position.toString(),
44193
+ provenance: { kind: "original" },
44194
+ recordedAt,
44195
+ sessionId
44196
+ };
44197
+ }
44101
44198
  var DaemonSessionEventLogV2 = class {
44102
- #positions = /* @__PURE__ */ new Map();
44103
- #requests = /* @__PURE__ */ new Map();
44104
- #loadedRequestSessions = /* @__PURE__ */ new Set();
44199
+ daemonGenerationId = randomUUID8();
44105
44200
  #publisher;
44106
- #store;
44107
- constructor(publisher, store) {
44201
+ #queued = /* @__PURE__ */ new Map();
44202
+ constructor(publisher) {
44108
44203
  this.#publisher = publisher;
44109
- this.#store = store;
44110
44204
  }
44111
- #loadStoredEvents = (sessionId) => {
44112
- const stored = this.#store.readExecutingPromptEventsV2(sessionId);
44113
- const lastPosition = stored.at(-1)?.position;
44114
- if (lastPosition !== void 0) {
44115
- this.#positions.set(sessionId, Number(lastPosition));
44116
- }
44117
- return stored;
44118
- };
44119
- #loadRequests = (sessionId) => {
44120
- if (this.#loadedRequestSessions.has(sessionId)) {
44121
- return;
44122
- }
44123
- for (const event of this.#loadStoredEvents(sessionId)) {
44124
- if (event.type === "acp") {
44125
- continue;
44126
- }
44127
- const payload = event.payload;
44128
- if (payload.kind === "prompt.requested") {
44129
- this.#requests.set(payload.commandId, {
44130
- commandId: payload.commandId,
44131
- kind: "requested",
44132
- sessionId
44133
- });
44134
- continue;
44135
- }
44136
- if ("event" in payload) {
44137
- continue;
44138
- }
44139
- if (!("commandId" in payload)) {
44140
- continue;
44141
- }
44142
- const state = this.#requests.get(payload.commandId);
44143
- if (state === void 0) {
44144
- continue;
44145
- }
44146
- if (payload.kind === "prompt.started") {
44147
- this.#requests.set(payload.commandId, {
44148
- attemptId: payload.attemptId,
44149
- commandId: payload.commandId,
44150
- epoch: payload.epoch,
44151
- kind: "executing",
44152
- sessionId
44153
- });
44154
- } else if (payload.kind === "prompt.completed" || payload.kind === "prompt.failed" || payload.kind === "prompt.failed-before-start") {
44155
- this.#requests.delete(payload.commandId);
44156
- }
44157
- }
44158
- this.#loadedRequestSessions.add(sessionId);
44159
- };
44160
- #append = (sessionId, payload) => {
44161
- this.#loadRequests(sessionId);
44162
- const position = (this.#positions.get(sessionId) ?? 0) + 1;
44163
- const event = {
44164
- eventId: `event-${crypto.randomUUID()}`,
44165
- ...payload,
44166
- position: position.toString(),
44167
- provenance: { kind: "original" },
44168
- recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
44169
- sessionId
44170
- };
44171
- this.#publisher.publishV2(event);
44172
- this.#positions.set(sessionId, position);
44173
- return event;
44174
- };
44175
44205
  requested = (command) => {
44176
- const content = promptContent(command);
44177
- this.#append(command.sessionId, {
44178
- payload: { commandId: command.commandId, content, kind: "prompt.requested" },
44179
- type: "lifecycle-metadata"
44180
- });
44181
- this.#requests.set(command.commandId, {
44206
+ this.#queued.set(command.commandId, {
44182
44207
  commandId: command.commandId,
44183
- kind: "requested",
44208
+ content: promptContent(command),
44184
44209
  sessionId: command.sessionId
44185
44210
  });
44186
44211
  };
44187
44212
  started = (sessionId, commandId, attemptId, epoch) => {
44188
- this.#loadRequests(sessionId);
44189
- const request = this.#requests.get(commandId);
44190
- if (request?.sessionId !== sessionId) {
44191
- return;
44213
+ const request = this.#queued.get(commandId);
44214
+ if (request?.sessionId === sessionId) {
44215
+ this.#queued.delete(commandId);
44216
+ return { attemptId, content: request.content, epoch };
44192
44217
  }
44193
- this.#append(sessionId, {
44194
- payload: { attemptId, commandId, epoch, kind: "prompt.started" },
44195
- type: "lifecycle-metadata"
44196
- });
44197
- this.#requests.set(commandId, {
44198
- attemptId,
44199
- commandId,
44200
- epoch,
44201
- kind: "executing",
44202
- sessionId
44203
- });
44218
+ throw new Error("The executing prompt was not registered in the V2 queue");
44204
44219
  };
44205
- record = (sessionId, payload) => {
44206
- this.#loadRequests(sessionId);
44207
- this.#append(sessionId, payload);
44208
- };
44209
- #clearCompletedSession = (sessionId) => {
44210
- if (![...this.#requests.values()].some((request) => request.sessionId === sessionId)) {
44211
- this.#store.clearExecutingPromptEventsV2(sessionId);
44212
- }
44213
- };
44214
- queueChanged = (sessionId) => {
44215
- this.#append(sessionId, {
44216
- payload: { kind: "session.queue.changed" },
44217
- type: "lifecycle-metadata"
44218
- });
44220
+ record = (sessionId, event, position) => {
44221
+ this.#publisher.publishV2(this.event(sessionId, position, event, (/* @__PURE__ */ new Date()).toISOString()));
44219
44222
  };
44220
- completed = (sessionId, commandId, stopReason) => {
44221
- this.#loadRequests(sessionId);
44222
- this.#append(sessionId, {
44223
- payload: { commandId, kind: "prompt.completed", stopReason },
44224
- type: "lifecycle-metadata"
44225
- });
44226
- this.#requests.delete(commandId);
44227
- this.#clearCompletedSession(sessionId);
44228
- };
44229
- failed = (sessionId, commandId, code, message) => {
44230
- this.#loadRequests(sessionId);
44231
- const request = this.#requests.get(commandId);
44232
- if (request?.kind === "executing" && request.commandId === commandId) {
44233
- this.#append(sessionId, {
44234
- payload: {
44235
- attemptId: request.attemptId,
44236
- code,
44237
- commandId,
44238
- kind: "prompt.failed",
44239
- message
44240
- },
44241
- type: "lifecycle-metadata"
44242
- });
44243
- } else {
44244
- this.#append(sessionId, {
44245
- payload: { code, commandId, kind: "prompt.failed-before-start", message },
44246
- type: "lifecycle-metadata"
44247
- });
44223
+ event = (sessionId, position, event, recordedAt) => sessionEventV22(this.daemonGenerationId, sessionId, position, event, recordedAt);
44224
+ queueChanged = (_sessionId) => void 0;
44225
+ completed = (sessionId, commandId, _stopReason) => {
44226
+ const request = this.#queued.get(commandId);
44227
+ if (request?.sessionId === sessionId) {
44228
+ this.#queued.delete(commandId);
44248
44229
  }
44249
- this.#requests.delete(commandId);
44250
- this.#clearCompletedSession(sessionId);
44251
44230
  };
44252
- executingPromptRequest = (sessionId) => {
44253
- this.#loadRequests(sessionId);
44254
- const request = [...this.#requests.values()].find(
44255
- (candidate) => candidate.sessionId === sessionId && candidate.kind === "executing"
44256
- );
44257
- if (request?.kind !== "executing") {
44258
- return null;
44231
+ failed = (sessionId, commandId, _code, _message) => {
44232
+ const request = this.#queued.get(commandId);
44233
+ if (request?.sessionId === sessionId) {
44234
+ this.#queued.delete(commandId);
44259
44235
  }
44260
- const requestEvents = this.#store.readExecutingPromptEventsV2(sessionId);
44261
- const events = requestEvents.slice(-EXECUTING_PROMPT_EVENT_LIMIT);
44262
- return {
44263
- attemptId: request.attemptId,
44264
- commandId: request.commandId,
44265
- epoch: request.epoch,
44266
- events,
44267
- tailCursor: events.at(-1)?.eventId ?? "",
44268
- truncated: events.length < requestEvents.length
44269
- };
44270
44236
  };
44237
+ promptRequestRecovery = (sessionId) => ({
44238
+ queuedPromptRequests: [...this.#queued.values()].filter((request) => request.sessionId === sessionId).map(({ commandId, content }) => ({ commandId, content }))
44239
+ });
44271
44240
  };
44272
44241
 
44273
44242
  // src/run-daemon.ts
@@ -44318,7 +44287,7 @@ async function installDetectedAgentIntegrations(config2, installations, signal)
44318
44287
  {
44319
44288
  agentId: agent.id,
44320
44289
  kind: AGENT_INSTALL_REQUEST_KIND,
44321
- requestId: `automatic-integration-${randomUUID8()}`
44290
+ requestId: `automatic-integration-${randomUUID9()}`
44322
44291
  },
44323
44292
  signal
44324
44293
  );
@@ -44341,8 +44310,8 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer, opti
44341
44310
  );
44342
44311
  await using externalContent = new LocalExternalContentStore(stateDirectory);
44343
44312
  const operations = new DaemonOperationState();
44344
- const publisher = new DaemonSessionEventPublisher(sessionStore);
44345
- const eventLogV2 = new DaemonSessionEventLogV2(publisher, sessionStore);
44313
+ const publisher = new DaemonSessionEventPublisher();
44314
+ const eventLogV2 = new DaemonSessionEventLogV2(publisher);
44346
44315
  const activeTurns = new DaemonTurnRegistry(operations);
44347
44316
  const recordSessionEvent = (sessionId, event) => {
44348
44317
  publisher.publish(sessionId, activeTurns.recordEvent(event));