lody 0.92.0 → 0.92.1

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.
@@ -80,7 +80,7 @@ let __tla = Promise.all([
80
80
  }
81
81
  })()
82
82
  ]).then(async () => {
83
- const reviewViewerVersion = "0.92.0";
83
+ const reviewViewerVersion = "0.92.1";
84
84
  const reviewViewerSha256 = "dc9c7fc1dde49bb39c5fe86392d69219b469c0cab4fd492d8b562045e7f676e4";
85
85
  const reviewViewerFileName = "standalone.html";
86
86
  const DEFAULT_CDN_BASES = [
package/dist/index.js CHANGED
@@ -4325,7 +4325,7 @@ Upgrade Node, then re-run: npx lody@latest`;
4325
4325
  }
4326
4326
  const name$2 = "lody";
4327
4327
  const name$1 = "@lody/cli-cloud";
4328
- const version$9 = "0.92.0";
4328
+ const version$9 = "0.92.1";
4329
4329
  const type$2 = "module";
4330
4330
  const scripts = {
4331
4331
  "dev": "node dev.mjs",
@@ -14381,9 +14381,16 @@ Requirements:
14381
14381
  progressMessageId: string$1().trim().min(1).optional(),
14382
14382
  completion: unknown(),
14383
14383
  continuation: object$1({
14384
- status: literal$1("not_started"),
14384
+ status: _enum$1([
14385
+ "not_started",
14386
+ "uncertain"
14387
+ ]),
14385
14388
  reason: object$1({
14386
- code: literal$1("CONFIGURATION_UNAVAILABLE"),
14389
+ code: _enum$1([
14390
+ "CONFIGURATION_UNAVAILABLE",
14391
+ "DELIVERY_ATTEMPTS_EXHAUSTED",
14392
+ "DELIVERY_EXECUTION_UNCERTAIN"
14393
+ ]),
14387
14394
  message: string$1()
14388
14395
  }).strict()
14389
14396
  }).strict().optional()
@@ -105122,6 +105129,7 @@ ${value}`;
105122
105129
  this.mirror = new Mirror({
105123
105130
  doc: handle.doc,
105124
105131
  schema: sessionDocSchema,
105132
+ validateUpdates: false,
105125
105133
  ignoreUnknownProperties: true,
105126
105134
  initialState: merged
105127
105135
  });
@@ -135090,12 +135098,22 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
135090
135098
  }
135091
135099
  class SessionTurnHalted extends TaggedError("SessionTurnHalted") {
135092
135100
  }
135101
+ class SessionTurnClaimContended extends TaggedError("SessionTurnClaimContended") {
135102
+ }
135103
+ class SessionTurnStartFenceFailed extends TaggedError("SessionTurnStartFenceFailed") {
135104
+ }
135093
135105
  const isSessionTurnCancelled = (error2) => {
135094
135106
  return typeof error2 === "object" && error2 !== null && "_tag" in error2 && error2._tag === "SessionTurnCancelled";
135095
135107
  };
135096
135108
  const isSessionTurnHalted = (error2) => {
135097
135109
  return typeof error2 === "object" && error2 !== null && "_tag" in error2 && error2._tag === "SessionTurnHalted";
135098
135110
  };
135111
+ const isSessionTurnClaimContended = (error2) => {
135112
+ return typeof error2 === "object" && error2 !== null && "_tag" in error2 && error2._tag === "SessionTurnClaimContended";
135113
+ };
135114
+ const isSessionTurnStartFenceFailed = (error2) => {
135115
+ return typeof error2 === "object" && error2 !== null && "_tag" in error2 && error2._tag === "SessionTurnStartFenceFailed";
135116
+ };
135099
135117
  function truncateAnalyticsString$1(value, maxLength = 1e3) {
135100
135118
  return value.length > maxLength ? `${value.slice(0, maxLength)}...` : value;
135101
135119
  }
@@ -135636,6 +135654,9 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
135636
135654
  requesterUserId: options.userId,
135637
135655
  inputConfig: options.inputConfig
135638
135656
  };
135657
+ await this.settleVisibleTurn(runtime, "handled", {
135658
+ force: true
135659
+ });
135639
135660
  try {
135640
135661
  await this.finalizeYieldedTurnOutput(runtime, options.sessionId, previousTurnId);
135641
135662
  } catch (error2) {
@@ -135827,9 +135848,27 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
135827
135848
  cancelFinalized: false,
135828
135849
  interruptRequested: false,
135829
135850
  terminateSessionOnCancel: false,
135851
+ ...options.onTurnSettled ? {
135852
+ settlement: {
135853
+ callback: options.onTurnSettled,
135854
+ completed: false
135855
+ }
135856
+ } : {},
135830
135857
  yieldedFinalization: Promise.resolve()
135831
135858
  };
135832
135859
  }
135860
+ async settleVisibleTurn(runtime, outcome, options = {}) {
135861
+ const settlement = runtime.settlement;
135862
+ if (!settlement || settlement.completed) return;
135863
+ if (options.force) settlement.forcedOutcome = outcome;
135864
+ const effectiveOutcome = settlement.forcedOutcome ?? outcome;
135865
+ try {
135866
+ await settlement.callback(effectiveOutcome);
135867
+ settlement.completed = true;
135868
+ } catch (error2) {
135869
+ this.deps.logger.error(`[${runtime.sessionId}] Failed to persist ${effectiveOutcome} turn settlement: ${formatErrorMessage(error2)}`);
135870
+ }
135871
+ }
135833
135872
  getTurnRuntime(sessionId, turnId) {
135834
135873
  const runtime = this.turnRuntimeBySession.get(sessionId);
135835
135874
  return runtime?.turnId === turnId ? runtime : void 0;
@@ -136351,6 +136390,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
136351
136390
  }
136352
136391
  async runVisibleSessionTurn(options, body2) {
136353
136392
  const { sessionId, sessionDoc, userTurnId } = options;
136393
+ const assistantEntryParentTurnId = options.assistantEntryParentTurnId ?? userTurnId;
136354
136394
  const span2 = startTraceSpan(this.deps.logger, "execution.visible_turn", {
136355
136395
  sessionId,
136356
136396
  ...userTurnId ? {
@@ -136383,7 +136423,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
136383
136423
  let turnId;
136384
136424
  let runtime;
136385
136425
  try {
136386
- turnId = this.deps.beginConversationTurn(sessionId, userTurnId, {
136426
+ turnId = this.deps.beginConversationTurn(sessionId, assistantEntryParentTurnId, {
136387
136427
  ...options.dispatchSource ? {
136388
136428
  dispatchSource: options.dispatchSource
136389
136429
  } : {},
@@ -136484,7 +136524,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
136484
136524
  userTurnId
136485
136525
  } : {},
136486
136526
  alreadyOpened: wasOpened
136487
- }, async () => await self2.deps.createAssistantEntryForTurn(sessionId, sessionDoc, runtime.turnId, runtime.session?.agentClient?.currentModel, userTurnId)));
136527
+ }, async () => await self2.deps.createAssistantEntryForTurn(sessionId, sessionDoc, runtime.turnId, runtime.session?.agentClient?.currentModel, assistantEntryParentTurnId)));
136488
136528
  if (wasOpened) {
136489
136529
  return void 0;
136490
136530
  }
@@ -136523,6 +136563,20 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
136523
136563
  yield* fail(new Error("Agent session was not ready"));
136524
136564
  return void 0;
136525
136565
  }
136566
+ if (!runtime.promptStarted && options.onTurnStarted) {
136567
+ const started = yield* self2.tryPromise(options.onTurnStarted).pipe(mapError$1((cause) => new SessionTurnStartFenceFailed({
136568
+ sessionId,
136569
+ turnId: runtime.turnId,
136570
+ cause
136571
+ })), tapError(() => self2.ignoreWithWarning(sessionId, "Failed to finalize a rejected Delivery start fence", self2.tryPromise(() => self2.handleTurnError(sessionId, sessionDoc)))));
136572
+ if (!started) {
136573
+ yield* fail(new SessionTurnClaimContended({
136574
+ sessionId,
136575
+ turnId: runtime.turnId
136576
+ }));
136577
+ return void 0;
136578
+ }
136579
+ }
136526
136580
  runtime.terminateSessionOnCancel = false;
136527
136581
  self2.deps.activateConversationTurnForACPUpdates(sessionId, runtime.turnId);
136528
136582
  runtime.promptStarted = true;
@@ -136564,13 +136618,21 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
136564
136618
  }))));
136565
136619
  const fiber = runFork(program2);
136566
136620
  runtime.fiber = fiber;
136621
+ let settlement;
136567
136622
  try {
136568
136623
  await this.awaitTurnFiber(fiber, sessionId, turnId);
136569
136624
  if (outcome === "unknown") {
136570
136625
  outcome = "completed";
136571
136626
  }
136627
+ settlement = "handled";
136572
136628
  } catch (error2) {
136573
- if (isSessionTurnHalted(error2)) {
136629
+ if (isSessionTurnClaimContended(error2)) {
136630
+ outcome = "claim-contended";
136631
+ } else if (isSessionTurnStartFenceFailed(error2)) {
136632
+ outcome = "start-fence-failed";
136633
+ this.deps.logger.warn(`[${sessionId}] Delivery start fence failed before provider execution: ${formatErrorMessage(error2.cause)}`);
136634
+ settlement = "not_started";
136635
+ } else if (isSessionTurnHalted(error2)) {
136574
136636
  outcome = `halted-${error2.reason}`;
136575
136637
  await this.finalizeHaltedTurn({
136576
136638
  sessionId,
@@ -136578,23 +136640,25 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
136578
136640
  turnId: runtime.turnId,
136579
136641
  reason: error2.reason
136580
136642
  });
136581
- return outcome;
136582
- }
136583
- if (isSessionTurnCancelled(error2) || runtime.cancelFinalized || runtime.cancelRequested || this.isTurnCancelled(sessionId, runtime.turnId) || await this.isUserTurnCancelled(sessionDoc, runtime.userTurnId)) {
136643
+ settlement = "handled";
136644
+ } else if (isSessionTurnCancelled(error2) || runtime.cancelFinalized || runtime.cancelRequested || this.isTurnCancelled(sessionId, runtime.turnId) || await this.isUserTurnCancelled(sessionDoc, runtime.userTurnId)) {
136584
136645
  outcome = "cancelled";
136585
- return outcome;
136646
+ const explicitlyCancelled = runtime.cancelRequested || this.isTurnCancelled(sessionId, runtime.turnId) || await this.isUserTurnCancelled(sessionDoc, runtime.userTurnId);
136647
+ settlement = explicitlyCancelled ? "cancelled" : runtime.promptStarted ? "uncertain" : "not_started";
136648
+ } else {
136649
+ await this.handleVisibleTurnUnhandledError({
136650
+ sessionId,
136651
+ sessionDoc,
136652
+ userTurnId: runtime.userTurnId,
136653
+ runtime,
136654
+ error: error2,
136655
+ code: effectiveErrorContext.code,
136656
+ describe: effectiveErrorContext.describe,
136657
+ onUnhandledError: effectiveErrorContext.onUnhandledError
136658
+ });
136659
+ outcome = "unhandled-error-recorded";
136660
+ settlement = "handled";
136586
136661
  }
136587
- await this.handleVisibleTurnUnhandledError({
136588
- sessionId,
136589
- sessionDoc,
136590
- userTurnId: runtime.userTurnId,
136591
- runtime,
136592
- error: error2,
136593
- code: effectiveErrorContext.code,
136594
- describe: effectiveErrorContext.describe,
136595
- onUnhandledError: effectiveErrorContext.onUnhandledError
136596
- });
136597
- outcome = "unhandled-error-recorded";
136598
136662
  } finally {
136599
136663
  if (!runtime.promptStarted) {
136600
136664
  this.deps.clearConversationTurn(sessionId, runtime.turnId);
@@ -136604,6 +136668,9 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
136604
136668
  turnId
136605
136669
  });
136606
136670
  }
136671
+ if (settlement) {
136672
+ await this.settleVisibleTurn(runtime, settlement);
136673
+ }
136607
136674
  return outcome;
136608
136675
  }
136609
136676
  markCurrentTurn(sessionId, turnId) {
@@ -136866,7 +136933,10 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
136866
136933
  })) {
136867
136934
  return;
136868
136935
  }
136869
- const body2 = dispatchOptions?.onTurnClaimed ? (ctx) => promise$1(dispatchOptions.onTurnClaimed).pipe(flatMap$2(() => turn.body(ctx))) : turn.body;
136936
+ const body2 = dispatchOptions?.onTurnClaimed ? (ctx) => promise$1(dispatchOptions.onTurnClaimed).pipe(flatMap$2((claimed) => claimed ? turn.body(ctx) : fail(new SessionTurnClaimContended({
136937
+ sessionId: message.sessionId,
136938
+ turnId: ctx.turnId
136939
+ })))) : turn.body;
136870
136940
  await this.runVisibleSessionTurn(turn.options, body2);
136871
136941
  }
136872
136942
  async prepareContinueSessionTurn(message, dispatchOptions, prepareOptions) {
@@ -137330,6 +137400,15 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
137330
137400
  requesterUserId: userId,
137331
137401
  inputConfig: acpSessionConfig
137332
137402
  },
137403
+ ...dispatchOptions?.dispatchSource === "delivery" ? {
137404
+ assistantEntryParentTurnId: userTurnId
137405
+ } : {},
137406
+ ...dispatchOptions?.onTurnStarted ? {
137407
+ onTurnStarted: dispatchOptions.onTurnStarted
137408
+ } : {},
137409
+ ...dispatchOptions?.onTurnSettled ? {
137410
+ onTurnSettled: dispatchOptions.onTurnSettled
137411
+ } : {},
137333
137412
  ...dispatchOptions?.dispatchSource ? {
137334
137413
  dispatchSource: dispatchOptions.dispatchSource
137335
137414
  } : {},
@@ -141616,6 +141695,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
141616
141695
  const DAY_MS = 24 * 60 * 60 * 1e3;
141617
141696
  const TERMINAL_RETENTION_MS = 7 * DAY_MS;
141618
141697
  const MATERIALIZATION_CLAIM_MS = 6e4;
141698
+ const DELIVERY_MAX_ATTEMPTS = 2;
141619
141699
  const OperationKindSchema = _enum$1([
141620
141700
  "session_create",
141621
141701
  "session_create_many",
@@ -141732,6 +141812,33 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
141732
141812
  completion_json: string$1(),
141733
141813
  consumed_at: string$1().nullable()
141734
141814
  }).strict();
141815
+ const DeliveryReadRowSchema = DeliveryRowSchema.extend({
141816
+ execution_phase: _enum$1([
141817
+ "ready",
141818
+ "claimed",
141819
+ "prepared",
141820
+ "started",
141821
+ "uncertain"
141822
+ ]),
141823
+ attempt_count: number$4().int().nonnegative(),
141824
+ active_claim_id: string$1().nullable(),
141825
+ active_claim_worker_boot_id: string$1().nullable()
141826
+ }).strict();
141827
+ const DELIVERY_READ_COLUMNS = `
141828
+ deliveries.sequence,
141829
+ deliveries.workspace_id,
141830
+ deliveries.requester_session_id,
141831
+ deliveries.operation_id,
141832
+ deliveries.delivery_id,
141833
+ deliveries.system_turn_id,
141834
+ deliveries.state,
141835
+ deliveries.initiator_chain_depth,
141836
+ deliveries.completion_json,
141837
+ deliveries.consumed_at,
141838
+ delivery_execution_state.execution_phase,
141839
+ delivery_execution_state.attempt_count,
141840
+ delivery_execution_state.active_claim_id,
141841
+ delivery_execution_state.active_claim_worker_boot_id`;
141735
141842
  class LodyOperationStoreError extends Error {
141736
141843
  constructor(code2, message, retryable) {
141737
141844
  super(message);
@@ -142134,16 +142241,320 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142134
142241
  return transaction.immediate();
142135
142242
  }
142136
142243
  listPendingDeliveries(workspaceId, requesterSessionId) {
142137
- const rows = requesterSessionId ? this.db.prepare(`SELECT * FROM deliveries
142138
- WHERE workspace_id = ? AND requester_session_id = ? AND state = 'pending'
142139
- ORDER BY sequence ASC`).all(workspaceId, requesterSessionId) : this.db.prepare(`SELECT * FROM deliveries
142140
- WHERE workspace_id = ? AND state = 'pending'
142141
- ORDER BY sequence ASC`).all(workspaceId);
142244
+ const rows = requesterSessionId ? this.db.prepare(`SELECT ${DELIVERY_READ_COLUMNS}
142245
+ FROM deliveries
142246
+ JOIN delivery_execution_state USING (requester_session_id, operation_id)
142247
+ WHERE deliveries.workspace_id = ?
142248
+ AND deliveries.requester_session_id = ?
142249
+ AND deliveries.state = 'pending'
142250
+ ORDER BY deliveries.sequence ASC`).all(workspaceId, requesterSessionId) : this.db.prepare(`SELECT ${DELIVERY_READ_COLUMNS}
142251
+ FROM deliveries
142252
+ JOIN delivery_execution_state USING (requester_session_id, operation_id)
142253
+ WHERE deliveries.workspace_id = ? AND deliveries.state = 'pending'
142254
+ ORDER BY deliveries.sequence ASC`).all(workspaceId);
142142
142255
  return rows.map((row) => this.decodeDelivery(row));
142143
142256
  }
142144
- consumeDelivery(requesterSessionId, operationId, consumedAt = new Date(this.now()).toISOString()) {
142145
- this.db.prepare(`UPDATE deliveries SET state = 'consumed', consumed_at = ?
142146
- WHERE requester_session_id = ? AND operation_id = ? AND state = 'pending'`).run(consumedAt, requesterSessionId, operationId);
142257
+ getDelivery(requesterSessionId, operationId) {
142258
+ const row = this.db.prepare(`SELECT ${DELIVERY_READ_COLUMNS}
142259
+ FROM deliveries
142260
+ JOIN delivery_execution_state USING (requester_session_id, operation_id)
142261
+ WHERE deliveries.requester_session_id = ? AND deliveries.operation_id = ?`).get(requesterSessionId, operationId);
142262
+ if (row === void 0) {
142263
+ throw new LodyOperationStoreError("DELIVERY_NOT_FOUND", `Delivery not found for Operation: ${operationId}`, false);
142264
+ }
142265
+ return this.decodeDelivery(row);
142266
+ }
142267
+ recoverOrphanedDeliveryClaims(workspaceId, workerBootId) {
142268
+ const result = this.db.prepare(`UPDATE delivery_execution_state
142269
+ SET execution_phase = CASE
142270
+ WHEN execution_phase = 'started' THEN 'uncertain'
142271
+ WHEN execution_phase IN ('claimed', 'prepared') THEN 'ready'
142272
+ ELSE execution_phase
142273
+ END,
142274
+ active_claim_id = NULL,
142275
+ active_claim_worker_boot_id = NULL
142276
+ WHERE (active_claim_id IS NOT NULL OR active_claim_worker_boot_id IS NOT NULL)
142277
+ AND (
142278
+ active_claim_id IS NULL
142279
+ OR active_claim_worker_boot_id IS NULL
142280
+ OR active_claim_worker_boot_id <> ?
142281
+ )
142282
+ AND EXISTS (
142283
+ SELECT 1 FROM deliveries
142284
+ WHERE deliveries.requester_session_id = delivery_execution_state.requester_session_id
142285
+ AND deliveries.operation_id = delivery_execution_state.operation_id
142286
+ AND deliveries.workspace_id = ? AND deliveries.state = 'pending'
142287
+ )`).run(workerBootId, workspaceId);
142288
+ return result.changes;
142289
+ }
142290
+ abandonDeliveryClaimsOwnedBy(workspaceId, workerBootId) {
142291
+ const result = this.db.prepare(`UPDATE delivery_execution_state
142292
+ SET execution_phase = CASE
142293
+ WHEN execution_phase = 'started' THEN 'uncertain'
142294
+ WHEN execution_phase IN ('claimed', 'prepared') THEN 'ready'
142295
+ ELSE execution_phase
142296
+ END,
142297
+ active_claim_id = NULL,
142298
+ active_claim_worker_boot_id = NULL
142299
+ WHERE active_claim_worker_boot_id = ?
142300
+ AND EXISTS (
142301
+ SELECT 1 FROM deliveries
142302
+ WHERE deliveries.requester_session_id = delivery_execution_state.requester_session_id
142303
+ AND deliveries.operation_id = delivery_execution_state.operation_id
142304
+ AND deliveries.workspace_id = ? AND deliveries.state = 'pending'
142305
+ )`).run(workerBootId, workspaceId);
142306
+ return result.changes;
142307
+ }
142308
+ claimDeliveryExecution(requesterSessionId, operationId, claim) {
142309
+ const transaction = this.db.transaction(() => {
142310
+ const current2 = this.getDelivery(requesterSessionId, operationId);
142311
+ if (current2.state === "consumed") return {
142312
+ status: "consumed",
142313
+ delivery: current2
142314
+ };
142315
+ if (current2.activeClaimId === claim.claimId && current2.activeClaimWorkerBootId === claim.workerBootId) {
142316
+ return {
142317
+ status: "claimed",
142318
+ delivery: current2
142319
+ };
142320
+ }
142321
+ if (current2.activeClaimId !== void 0 || current2.activeClaimWorkerBootId !== void 0) {
142322
+ return {
142323
+ status: "in_flight",
142324
+ delivery: current2
142325
+ };
142326
+ }
142327
+ if (current2.executionPhase !== "ready") {
142328
+ return {
142329
+ status: "in_flight",
142330
+ delivery: current2
142331
+ };
142332
+ }
142333
+ if (current2.attemptCount >= DELIVERY_MAX_ATTEMPTS) {
142334
+ return {
142335
+ status: "exhausted",
142336
+ delivery: current2
142337
+ };
142338
+ }
142339
+ const result = this.db.prepare(`UPDATE delivery_execution_state
142340
+ SET execution_phase = 'claimed', active_claim_id = ?, active_claim_worker_boot_id = ?
142341
+ WHERE requester_session_id = ? AND operation_id = ?
142342
+ AND attempt_count < ?
142343
+ AND execution_phase = 'ready'
142344
+ AND active_claim_id IS NULL AND active_claim_worker_boot_id IS NULL
142345
+ AND EXISTS (
142346
+ SELECT 1 FROM deliveries
142347
+ WHERE deliveries.requester_session_id = delivery_execution_state.requester_session_id
142348
+ AND deliveries.operation_id = delivery_execution_state.operation_id
142349
+ AND deliveries.state = 'pending'
142350
+ )`).run(claim.claimId, claim.workerBootId, requesterSessionId, operationId, DELIVERY_MAX_ATTEMPTS);
142351
+ if (result.changes !== 1) {
142352
+ const latest2 = this.getDelivery(requesterSessionId, operationId);
142353
+ if (latest2.state === "consumed") return {
142354
+ status: "consumed",
142355
+ delivery: latest2
142356
+ };
142357
+ if (latest2.activeClaimId !== void 0 || latest2.activeClaimWorkerBootId !== void 0) {
142358
+ return {
142359
+ status: "in_flight",
142360
+ delivery: latest2
142361
+ };
142362
+ }
142363
+ return {
142364
+ status: "exhausted",
142365
+ delivery: latest2
142366
+ };
142367
+ }
142368
+ return {
142369
+ status: "claimed",
142370
+ delivery: this.getDelivery(requesterSessionId, operationId)
142371
+ };
142372
+ });
142373
+ return transaction.immediate();
142374
+ }
142375
+ prepareClaimedDeliveryExecution(requesterSessionId, operationId, workerBootId, claimId) {
142376
+ const transaction = this.db.transaction(() => {
142377
+ const current2 = this.getDelivery(requesterSessionId, operationId);
142378
+ if (current2.activeClaimWorkerBootId === workerBootId && current2.activeClaimId === claimId && (current2.executionPhase === "prepared" || current2.executionPhase === "started")) {
142379
+ return {
142380
+ prepared: true,
142381
+ delivery: current2
142382
+ };
142383
+ }
142384
+ const result = this.db.prepare(`UPDATE delivery_execution_state
142385
+ SET execution_phase = 'prepared', attempt_count = attempt_count + 1
142386
+ WHERE requester_session_id = ? AND operation_id = ?
142387
+ AND attempt_count < ?
142388
+ AND execution_phase = 'claimed'
142389
+ AND active_claim_worker_boot_id = ? AND active_claim_id = ?
142390
+ AND EXISTS (
142391
+ SELECT 1 FROM deliveries
142392
+ WHERE deliveries.requester_session_id = delivery_execution_state.requester_session_id
142393
+ AND deliveries.operation_id = delivery_execution_state.operation_id
142394
+ AND deliveries.state = 'pending'
142395
+ )`).run(requesterSessionId, operationId, DELIVERY_MAX_ATTEMPTS, workerBootId, claimId);
142396
+ return {
142397
+ prepared: result.changes === 1,
142398
+ delivery: this.getDelivery(requesterSessionId, operationId)
142399
+ };
142400
+ });
142401
+ return transaction.immediate();
142402
+ }
142403
+ markClaimedDeliveryExecutionStarted(requesterSessionId, operationId, workerBootId, claimId) {
142404
+ const result = this.db.prepare(`UPDATE delivery_execution_state
142405
+ SET execution_phase = 'started'
142406
+ WHERE requester_session_id = ? AND operation_id = ?
142407
+ AND execution_phase = 'prepared'
142408
+ AND active_claim_worker_boot_id = ? AND active_claim_id = ?
142409
+ AND EXISTS (
142410
+ SELECT 1 FROM deliveries
142411
+ WHERE deliveries.requester_session_id = delivery_execution_state.requester_session_id
142412
+ AND deliveries.operation_id = delivery_execution_state.operation_id
142413
+ AND deliveries.state = 'pending'
142414
+ )`).run(requesterSessionId, operationId, workerBootId, claimId);
142415
+ if (result.changes === 1) return true;
142416
+ const current2 = this.getDelivery(requesterSessionId, operationId);
142417
+ return current2.executionPhase === "started" && current2.activeClaimWorkerBootId === workerBootId && current2.activeClaimId === claimId;
142418
+ }
142419
+ markClaimedDeliveryExecutionUncertain(requesterSessionId, operationId, workerBootId, claimId) {
142420
+ const result = this.db.prepare(`UPDATE delivery_execution_state
142421
+ SET execution_phase = 'uncertain',
142422
+ active_claim_id = NULL,
142423
+ active_claim_worker_boot_id = NULL
142424
+ WHERE requester_session_id = ? AND operation_id = ?
142425
+ AND execution_phase = 'started'
142426
+ AND active_claim_worker_boot_id = ? AND active_claim_id = ?
142427
+ AND EXISTS (
142428
+ SELECT 1 FROM deliveries
142429
+ WHERE deliveries.requester_session_id = delivery_execution_state.requester_session_id
142430
+ AND deliveries.operation_id = delivery_execution_state.operation_id
142431
+ AND deliveries.state = 'pending'
142432
+ )`).run(requesterSessionId, operationId, workerBootId, claimId);
142433
+ return result.changes === 1;
142434
+ }
142435
+ claimDeliveryFinalization(requesterSessionId, operationId, claim) {
142436
+ const transaction = this.db.transaction(() => {
142437
+ const current2 = this.getDelivery(requesterSessionId, operationId);
142438
+ if (current2.state === "consumed") return {
142439
+ status: "consumed",
142440
+ delivery: current2
142441
+ };
142442
+ if (current2.activeClaimId === claim.claimId && current2.activeClaimWorkerBootId === claim.workerBootId) {
142443
+ return {
142444
+ status: "claimed",
142445
+ delivery: current2
142446
+ };
142447
+ }
142448
+ if (current2.activeClaimId !== void 0 || current2.activeClaimWorkerBootId !== void 0) {
142449
+ return {
142450
+ status: "in_flight",
142451
+ delivery: current2
142452
+ };
142453
+ }
142454
+ const minimumAttemptCount = claim.requireAttemptsExhausted ? DELIVERY_MAX_ATTEMPTS : 0;
142455
+ const requiredExecutionPhase = claim.requiredExecutionPhase ?? "ready";
142456
+ if (current2.attemptCount < minimumAttemptCount) {
142457
+ return {
142458
+ status: "not_ready",
142459
+ delivery: current2
142460
+ };
142461
+ }
142462
+ if (current2.executionPhase !== requiredExecutionPhase) {
142463
+ return {
142464
+ status: "not_ready",
142465
+ delivery: current2
142466
+ };
142467
+ }
142468
+ const result = this.db.prepare(`UPDATE delivery_execution_state
142469
+ SET active_claim_id = ?, active_claim_worker_boot_id = ?
142470
+ WHERE requester_session_id = ? AND operation_id = ?
142471
+ AND attempt_count >= ?
142472
+ AND execution_phase = ?
142473
+ AND active_claim_id IS NULL AND active_claim_worker_boot_id IS NULL
142474
+ AND EXISTS (
142475
+ SELECT 1 FROM deliveries
142476
+ WHERE deliveries.requester_session_id = delivery_execution_state.requester_session_id
142477
+ AND deliveries.operation_id = delivery_execution_state.operation_id
142478
+ AND deliveries.state = 'pending'
142479
+ )`).run(claim.claimId, claim.workerBootId, requesterSessionId, operationId, minimumAttemptCount, requiredExecutionPhase);
142480
+ if (result.changes !== 1) {
142481
+ const latest2 = this.getDelivery(requesterSessionId, operationId);
142482
+ if (latest2.state === "consumed") return {
142483
+ status: "consumed",
142484
+ delivery: latest2
142485
+ };
142486
+ if (latest2.activeClaimId !== void 0 || latest2.activeClaimWorkerBootId !== void 0) {
142487
+ return {
142488
+ status: "in_flight",
142489
+ delivery: latest2
142490
+ };
142491
+ }
142492
+ return {
142493
+ status: "not_ready",
142494
+ delivery: latest2
142495
+ };
142496
+ }
142497
+ return {
142498
+ status: "claimed",
142499
+ delivery: this.getDelivery(requesterSessionId, operationId)
142500
+ };
142501
+ });
142502
+ return transaction.immediate();
142503
+ }
142504
+ releaseDeliveryClaim(requesterSessionId, operationId, workerBootId, claimId) {
142505
+ const result = this.db.prepare(`UPDATE delivery_execution_state
142506
+ SET execution_phase = CASE
142507
+ WHEN execution_phase IN ('claimed', 'prepared') THEN 'ready'
142508
+ ELSE execution_phase
142509
+ END,
142510
+ active_claim_id = NULL,
142511
+ active_claim_worker_boot_id = NULL
142512
+ WHERE requester_session_id = ? AND operation_id = ?
142513
+ AND active_claim_worker_boot_id = ? AND active_claim_id = ?
142514
+ AND execution_phase <> 'started'
142515
+ AND EXISTS (
142516
+ SELECT 1 FROM deliveries
142517
+ WHERE deliveries.requester_session_id = delivery_execution_state.requester_session_id
142518
+ AND deliveries.operation_id = delivery_execution_state.operation_id
142519
+ AND deliveries.state = 'pending'
142520
+ )`).run(requesterSessionId, operationId, workerBootId, claimId);
142521
+ return result.changes === 1;
142522
+ }
142523
+ consumeClaimedDelivery(requesterSessionId, operationId, workerBootId, claimId, consumedAt = new Date(this.now()).toISOString()) {
142524
+ const transaction = this.db.transaction(() => {
142525
+ const current2 = this.getDelivery(requesterSessionId, operationId);
142526
+ if (current2.state === "consumed" || current2.activeClaimWorkerBootId !== workerBootId || current2.activeClaimId !== claimId) {
142527
+ return {
142528
+ consumed: false,
142529
+ delivery: current2
142530
+ };
142531
+ }
142532
+ const result = this.db.prepare(`UPDATE deliveries
142533
+ SET state = 'consumed', consumed_at = ?
142534
+ WHERE requester_session_id = ? AND operation_id = ? AND state = 'pending'
142535
+ AND EXISTS (
142536
+ SELECT 1 FROM delivery_execution_state
142537
+ WHERE delivery_execution_state.requester_session_id = deliveries.requester_session_id
142538
+ AND delivery_execution_state.operation_id = deliveries.operation_id
142539
+ AND delivery_execution_state.active_claim_worker_boot_id = ?
142540
+ AND delivery_execution_state.active_claim_id = ?
142541
+ )`).run(consumedAt, requesterSessionId, operationId, workerBootId, claimId);
142542
+ if (result.changes === 1) {
142543
+ const released = this.db.prepare(`UPDATE delivery_execution_state
142544
+ SET active_claim_id = NULL, active_claim_worker_boot_id = NULL
142545
+ WHERE requester_session_id = ? AND operation_id = ?
142546
+ AND active_claim_worker_boot_id = ? AND active_claim_id = ?`).run(requesterSessionId, operationId, workerBootId, claimId);
142547
+ if (released.changes !== 1) {
142548
+ throw new Error("Consumed Delivery lost its active claim during transaction.");
142549
+ }
142550
+ }
142551
+ const latest2 = this.getDelivery(requesterSessionId, operationId);
142552
+ return {
142553
+ consumed: result.changes === 1,
142554
+ delivery: latest2
142555
+ };
142556
+ });
142557
+ return transaction.immediate();
142147
142558
  }
142148
142559
  deleteRequesterSession(requesterSessionId) {
142149
142560
  this.db.prepare("DELETE FROM operations WHERE requester_session_id = ?").run(requesterSessionId);
@@ -142220,7 +142631,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142220
142631
  };
142221
142632
  }
142222
142633
  decodeDelivery(row) {
142223
- const parsed = DeliveryRowSchema.parse(row);
142634
+ const parsed = DeliveryReadRowSchema.parse(row);
142224
142635
  return {
142225
142636
  sequence: parsed.sequence,
142226
142637
  workspaceId: parsed.workspace_id,
@@ -142229,6 +142640,14 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142229
142640
  deliveryId: parsed.delivery_id,
142230
142641
  systemTurnId: parsed.system_turn_id,
142231
142642
  state: parsed.state,
142643
+ executionPhase: parsed.execution_phase,
142644
+ attemptCount: parsed.attempt_count,
142645
+ ...parsed.active_claim_id ? {
142646
+ activeClaimId: parsed.active_claim_id
142647
+ } : {},
142648
+ ...parsed.active_claim_worker_boot_id ? {
142649
+ activeClaimWorkerBootId: parsed.active_claim_worker_boot_id
142650
+ } : {},
142232
142651
  initiatorChainDepth: parsed.initiator_chain_depth,
142233
142652
  completion: parseJson$1(parsed.completion_json, OperationCompletionSchema, "Delivery completion"),
142234
142653
  ...parsed.consumed_at ? {
@@ -142287,7 +142706,11 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142287
142706
  }).immediate();
142288
142707
  }
142289
142708
  migrate() {
142290
- this.db.exec(`
142709
+ if (!this.isMigrationRequired()) return;
142710
+ this.db.transaction(() => {
142711
+ const hadDeliveryExecutionState = this.db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'delivery_execution_state'").get() !== void 0;
142712
+ const hadDeliveryExecutionPhase = hadDeliveryExecutionState && this.db.prepare(`PRAGMA table_info(delivery_execution_state)`).all().some((column) => column.name === "execution_phase");
142713
+ this.db.exec(`
142291
142714
  CREATE TABLE IF NOT EXISTS operations (
142292
142715
  workspace_id TEXT NOT NULL,
142293
142716
  owner_machine_id TEXT NOT NULL,
@@ -142330,6 +142753,28 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142330
142753
  CREATE INDEX IF NOT EXISTS deliveries_pending_session
142331
142754
  ON deliveries (workspace_id, requester_session_id, state, sequence);
142332
142755
 
142756
+ CREATE TABLE IF NOT EXISTS delivery_execution_state (
142757
+ requester_session_id TEXT NOT NULL,
142758
+ operation_id TEXT NOT NULL,
142759
+ execution_phase TEXT NOT NULL DEFAULT 'ready'
142760
+ CHECK (execution_phase IN ('ready', 'claimed', 'prepared', 'started', 'uncertain')),
142761
+ attempt_count INTEGER NOT NULL DEFAULT 0,
142762
+ active_claim_id TEXT,
142763
+ active_claim_worker_boot_id TEXT,
142764
+ PRIMARY KEY (requester_session_id, operation_id),
142765
+ FOREIGN KEY (requester_session_id, operation_id)
142766
+ REFERENCES operations (requester_session_id, operation_id)
142767
+ ON DELETE CASCADE
142768
+ );
142769
+
142770
+ CREATE TRIGGER IF NOT EXISTS deliveries_insert_execution_state
142771
+ AFTER INSERT ON deliveries
142772
+ BEGIN
142773
+ INSERT OR IGNORE INTO delivery_execution_state (
142774
+ requester_session_id, operation_id, execution_phase, attempt_count
142775
+ ) VALUES (NEW.requester_session_id, NEW.operation_id, 'ready', 0);
142776
+ END;
142777
+
142333
142778
  CREATE TABLE IF NOT EXISTS operation_item_materializations (
142334
142779
  requester_session_id TEXT NOT NULL,
142335
142780
  operation_id TEXT NOT NULL,
@@ -142355,6 +142800,47 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142355
142800
  value TEXT NOT NULL
142356
142801
  );
142357
142802
  `);
142803
+ if (hadDeliveryExecutionState && !hadDeliveryExecutionPhase) {
142804
+ this.db.exec(`ALTER TABLE delivery_execution_state
142805
+ ADD COLUMN execution_phase TEXT NOT NULL DEFAULT 'ready'`);
142806
+ this.db.exec(`UPDATE delivery_execution_state
142807
+ SET execution_phase = CASE
142808
+ WHEN attempt_count > 0
142809
+ OR active_claim_id IS NOT NULL
142810
+ OR active_claim_worker_boot_id IS NOT NULL
142811
+ THEN 'uncertain'
142812
+ ELSE 'ready'
142813
+ END`);
142814
+ }
142815
+ this.db.prepare(`INSERT OR IGNORE INTO delivery_execution_state (
142816
+ requester_session_id, operation_id, execution_phase, attempt_count
142817
+ )
142818
+ SELECT requester_session_id, operation_id,
142819
+ CASE WHEN state = 'pending' THEN ? ELSE 'ready' END,
142820
+ 0
142821
+ FROM deliveries`).run(hadDeliveryExecutionState ? "ready" : "uncertain");
142822
+ }).immediate();
142823
+ }
142824
+ isMigrationRequired() {
142825
+ const requiredObjects = /* @__PURE__ */ new Set([
142826
+ "table:operations",
142827
+ "index:operations_active_owner",
142828
+ "table:deliveries",
142829
+ "index:deliveries_pending_session",
142830
+ "table:delivery_execution_state",
142831
+ "trigger:deliveries_insert_execution_state",
142832
+ "table:operation_item_materializations",
142833
+ "table:operation_progress_settlements",
142834
+ "table:orchestration_meta"
142835
+ ]);
142836
+ const existingObjects = this.db.prepare(`SELECT type, name FROM sqlite_master
142837
+ WHERE type IN ('table', 'index', 'trigger')`).all();
142838
+ for (const { type: type2, name: name2 } of existingObjects) {
142839
+ requiredObjects.delete(`${type2}:${name2}`);
142840
+ }
142841
+ if (requiredObjects.size > 0) return true;
142842
+ const executionStateColumns = this.db.prepare(`PRAGMA table_info(delivery_execution_state)`).all();
142843
+ return !executionStateColumns.some((column) => column.name === "execution_phase");
142358
142844
  }
142359
142845
  repairTerminalDeliveries() {
142360
142846
  this.db.transaction(() => {
@@ -142463,20 +142949,20 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142463
142949
  }
142464
142950
  const isProgressRow = (entry) => entry.role === "system" && (entry.id === id2 || entry.id.startsWith(duplicatePrefix));
142465
142951
  const timestamp2 = new Date(now2()).toISOString();
142466
- await sessionDoc.updateHistory((history) => {
142467
- const existingIndex = history.findIndex((entry2) => entry2.id === id2 && entry2.role === "system");
142468
- const duplicates = history.filter(isProgressRow);
142952
+ const updateHistory = (history2) => {
142953
+ const existingIndex = history2.findIndex((entry2) => entry2.id === id2 && entry2.role === "system");
142954
+ const duplicates = history2.filter(isProgressRow);
142469
142955
  const existing = duplicates[0];
142470
142956
  const existingProgress = duplicates.flatMap((entry2) => entry2.items ?? []).filter((item) => item.type === "operation_progress").reduce((merged2, item) => mergeOperationProgressContent(merged2, item), void 0);
142471
142957
  const materializedTargets = new Set((existingProgress?.items ?? []).map((item) => getOperationProgressTargetKey(item.target)));
142472
142958
  const content = buildOperationProgressContent(operation, statusByTarget, materializedTargets);
142473
- if (!content) return history;
142959
+ if (!content) return history2;
142474
142960
  const merged = mergeOperationProgressContent(existingProgress, content);
142475
142961
  const nextItems = [
142476
142962
  merged
142477
142963
  ];
142478
142964
  if (duplicates.length === 1 && existing && JSON.stringify(existing.items ?? []) === JSON.stringify(nextItems)) {
142479
- return history;
142965
+ return history2;
142480
142966
  }
142481
142967
  const entry = {
142482
142968
  ...existing ?? {},
@@ -142489,20 +142975,24 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142489
142975
  finished: true
142490
142976
  };
142491
142977
  if (existingIndex < 0) return [
142492
- ...history,
142978
+ ...history2,
142493
142979
  entry
142494
142980
  ];
142495
- return history.flatMap((candidate, index) => index === existingIndex ? [
142981
+ return history2.flatMap((candidate, index) => index === existingIndex ? [
142496
142982
  entry
142497
142983
  ] : isProgressRow(candidate) ? [] : [
142498
142984
  candidate
142499
142985
  ]);
142500
- });
142986
+ };
142987
+ const history = await sessionDoc.getHistory();
142988
+ if (updateHistory(history) === history) return;
142989
+ await sessionDoc.updateHistory(updateHistory);
142501
142990
  };
142502
142991
  const TARGET_OUTPUT_PREVIEW_MAX_BYTES = 8 * 1024;
142503
142992
  const MATERIALIZATION_RETRY_MIN_MS = 1e3;
142504
142993
  const MATERIALIZATION_RETRY_MAX_MS = 3e4;
142505
142994
  const DELIVERY_EXPIRY_GRACE_MS = 8 * 60 * 60 * 1e3;
142995
+ const WORKER_BOOT_ID = randomUUID();
142506
142996
  const truncateTargetOutput = (text) => {
142507
142997
  const originalBytes = Buffer.byteLength(text, "utf8");
142508
142998
  if (originalBytes <= TARGET_OUTPUT_PREVIEW_MAX_BYTES) return {
@@ -142540,7 +143030,8 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142540
143030
  const text = (assistant.items ?? []).filter((item) => item.type === "text").map((item) => item.text).filter((item) => item.length > 0).join("\n\n");
142541
143031
  return text.length > 0 ? truncateTargetOutput(text) : void 0;
142542
143032
  };
142543
- const terminalAssistantFor = (history, userTurnId) => history.find((entry) => entry.role === "assistant" && entry.userTurnId === userTurnId && (entry.finished === true || typeof entry.endedAt === "number"));
143033
+ const isTerminalAssistantEntry = (entry) => entry.role === "assistant" && (entry.finished === true || typeof entry.endedAt === "number");
143034
+ const terminalAssistantFor = (history, userTurnId) => history.find((entry) => entry.userTurnId === userTurnId && isTerminalAssistantEntry(entry));
142544
143035
  const completionText = (operation) => [
142545
143036
  `Lody Operation ${operation.operationId} (${operation.kind}) finished.`,
142546
143037
  "Use the structured completion below to continue the user task. Do not restart completed targets.",
@@ -142552,6 +143043,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142552
143043
  const storePath = options.storePath ?? getLodyOperationStorePath(options.machineId);
142553
143044
  this.storeFactory = options.storeFactory ?? (() => new LodyOperationStore(storePath));
142554
143045
  this.now = options.now ?? getServerNow;
143046
+ this.workerBootId = options.workerBootId ?? WORKER_BOOT_ID;
142555
143047
  }
142556
143048
  storeFactory;
142557
143049
  now;
@@ -142563,7 +143055,8 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142563
143055
  reconcileChains = /* @__PURE__ */ new Map();
142564
143056
  deliveryChains = /* @__PURE__ */ new Map();
142565
143057
  queuedDeliveryIds = /* @__PURE__ */ new Set();
142566
- dirtyDeliveryReasons = /* @__PURE__ */ new Map();
143058
+ dirtyDeliveryIds = /* @__PURE__ */ new Set();
143059
+ observedDeliverySettlements = /* @__PURE__ */ new Map();
142567
143060
  operationAbortControllers = /* @__PURE__ */ new Map();
142568
143061
  metaWatch = null;
142569
143062
  store = null;
@@ -142572,6 +143065,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142572
143065
  storeWakeTimer = null;
142573
143066
  started = false;
142574
143067
  materializationClaimToken = randomUUID();
143068
+ workerBootId;
142575
143069
  start() {
142576
143070
  if (this.started) return;
142577
143071
  this.started = true;
@@ -142584,6 +143078,10 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142584
143078
  ]
142585
143079
  });
142586
143080
  this.store = this.storeFactory();
143081
+ const recoveredClaims = this.store.recoverOrphanedDeliveryClaims(this.options.workspaceId, this.workerBootId);
143082
+ if (recoveredClaims > 0) {
143083
+ this.options.logger.warn(`[orchestration] Recovered ${recoveredClaims} orphaned Delivery claim(s) from an exited Worker`);
143084
+ }
142587
143085
  const storePath = this.options.storePath ?? getLodyOperationStorePath(this.options.machineId);
142588
143086
  const storeBasename = path__default.basename(storePath);
142589
143087
  const watchOperationStore = this.options.operationStoreWatchFactory ?? ((directory, onChange) => watch(directory, (_event, filename) => onChange(filename)));
@@ -142609,6 +143107,16 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142609
143107
  this.storeWakeTimer = null;
142610
143108
  if (this.progressRetryTimer) clearTimeout(this.progressRetryTimer);
142611
143109
  this.progressRetryTimer = null;
143110
+ if (this.store) {
143111
+ try {
143112
+ const abandonedClaims = this.store.abandonDeliveryClaimsOwnedBy(this.options.workspaceId, this.workerBootId);
143113
+ if (abandonedClaims > 0) {
143114
+ this.options.logger.warn(`[orchestration] Abandoned ${abandonedClaims} Delivery claim(s) while stopping the workspace coordinator`);
143115
+ }
143116
+ } catch (error2) {
143117
+ this.options.logger.warn(`[orchestration] Could not abandon Delivery claims during coordinator stop: ${error2 instanceof Error ? error2.message : String(error2)}`);
143118
+ }
143119
+ }
142612
143120
  this.store?.close();
142613
143121
  this.store = null;
142614
143122
  for (const subscription of this.targetSubscriptions.values()) {
@@ -142627,7 +143135,8 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
142627
143135
  this.reconcileChains.clear();
142628
143136
  this.deliveryChains.clear();
142629
143137
  this.queuedDeliveryIds.clear();
142630
- this.dirtyDeliveryReasons.clear();
143138
+ this.dirtyDeliveryIds.clear();
143139
+ this.observedDeliverySettlements.clear();
142631
143140
  for (const controller of this.operationAbortControllers.values()) controller.abort();
142632
143141
  this.operationAbortControllers.clear();
142633
143142
  }
@@ -143074,7 +143583,7 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
143074
143583
  }
143075
143584
  enqueueDelivery(delivery, reason) {
143076
143585
  if (this.queuedDeliveryIds.has(delivery.deliveryId)) {
143077
- this.dirtyDeliveryReasons.set(delivery.deliveryId, reason);
143586
+ this.dirtyDeliveryIds.add(delivery.deliveryId);
143078
143587
  return;
143079
143588
  }
143080
143589
  this.queuedDeliveryIds.add(delivery.deliveryId);
@@ -143083,29 +143592,28 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
143083
143592
  const next2 = previous.catch(() => void 0).then(async () => {
143084
143593
  let attemptReason = reason;
143085
143594
  for (; ; ) {
143086
- this.dirtyDeliveryReasons.delete(delivery.deliveryId);
143595
+ this.dirtyDeliveryIds.delete(delivery.deliveryId);
143087
143596
  try {
143088
143597
  await this.deliverIfRunnable(delivery, attemptReason);
143089
143598
  } catch (error2) {
143090
143599
  this.options.logger.warn(`[orchestration] Delivery ${delivery.deliveryId} failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
143091
143600
  }
143092
- const coalescedReason = this.dirtyDeliveryReasons.get(delivery.deliveryId);
143093
- if (!this.started || !coalescedReason || !this.isDeliveryPending(delivery)) {
143601
+ const retry2 = this.dirtyDeliveryIds.delete(delivery.deliveryId);
143602
+ if (!this.started || !retry2 || !this.isDeliveryPending(delivery)) {
143094
143603
  return;
143095
143604
  }
143096
- attemptReason = coalescedReason;
143605
+ attemptReason = "coalesced";
143097
143606
  }
143098
143607
  }).catch((error2) => {
143099
143608
  this.options.logger.warn(`[orchestration] Delivery ${delivery.deliveryId} coalesced retry failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
143100
143609
  }).finally(() => {
143101
- const lateCoalescedReason = this.dirtyDeliveryReasons.get(delivery.deliveryId);
143610
+ const lateRetry = this.dirtyDeliveryIds.delete(delivery.deliveryId);
143102
143611
  this.queuedDeliveryIds.delete(delivery.deliveryId);
143103
- this.dirtyDeliveryReasons.delete(delivery.deliveryId);
143104
143612
  if (this.deliveryChains.get(sessionId) === next2) {
143105
143613
  this.deliveryChains.delete(sessionId);
143106
143614
  }
143107
- if (this.started && lateCoalescedReason && this.isDeliveryPending(delivery)) {
143108
- this.enqueueDelivery(delivery, lateCoalescedReason);
143615
+ if (this.started && lateRetry && this.isDeliveryPending(delivery)) {
143616
+ this.enqueueDelivery(delivery, "coalesced");
143109
143617
  }
143110
143618
  });
143111
143619
  this.deliveryChains.set(sessionId, next2);
@@ -143113,8 +143621,62 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
143113
143621
  isDeliveryPending(delivery) {
143114
143622
  return this.withStore((store) => store.listPendingDeliveries(this.options.workspaceId, delivery.requesterSessionId).some((candidate) => candidate.deliveryId === delivery.deliveryId));
143115
143623
  }
143624
+ async settleObservedDeliveryClaim(delivery, settlement) {
143625
+ const previous = this.observedDeliverySettlements.get(delivery.deliveryId);
143626
+ if (!previous || previous.claimId === settlement.claimId) {
143627
+ this.observedDeliverySettlements.set(delivery.deliveryId, settlement);
143628
+ }
143629
+ if (settlement.outcome === "finalize" && settlement.pendingHistoryWrite) {
143630
+ const current22 = this.withStore((store) => store.getDelivery(delivery.requesterSessionId, delivery.operationId));
143631
+ if (current22.activeClaimWorkerBootId !== this.workerBootId || current22.activeClaimId !== settlement.claimId) {
143632
+ if (this.observedDeliverySettlements.get(delivery.deliveryId) === settlement) {
143633
+ this.observedDeliverySettlements.delete(delivery.deliveryId);
143634
+ }
143635
+ return current22;
143636
+ }
143637
+ await settlement.pendingHistoryWrite();
143638
+ delete settlement.pendingHistoryWrite;
143639
+ }
143640
+ const current2 = this.withStore((store) => {
143641
+ let latest2 = store.getDelivery(delivery.requesterSessionId, delivery.operationId);
143642
+ if (latest2.activeClaimWorkerBootId !== this.workerBootId || latest2.activeClaimId !== settlement.claimId) {
143643
+ return latest2;
143644
+ }
143645
+ if (settlement.outcome === "handled" || settlement.outcome === "cancelled" || settlement.outcome === "finalize") {
143646
+ return store.consumeClaimedDelivery(delivery.requesterSessionId, delivery.operationId, this.workerBootId, settlement.claimId).delivery;
143647
+ }
143648
+ if (settlement.outcome === "uncertain") {
143649
+ store.markClaimedDeliveryExecutionUncertain(delivery.requesterSessionId, delivery.operationId, this.workerBootId, settlement.claimId);
143650
+ } else {
143651
+ store.releaseDeliveryClaim(delivery.requesterSessionId, delivery.operationId, this.workerBootId, settlement.claimId);
143652
+ }
143653
+ latest2 = store.getDelivery(delivery.requesterSessionId, delivery.operationId);
143654
+ return latest2;
143655
+ });
143656
+ if (current2.activeClaimWorkerBootId !== this.workerBootId || current2.activeClaimId !== settlement.claimId) {
143657
+ if (this.observedDeliverySettlements.get(delivery.deliveryId) === settlement) {
143658
+ this.observedDeliverySettlements.delete(delivery.deliveryId);
143659
+ }
143660
+ }
143661
+ return current2;
143662
+ }
143116
143663
  async deliverIfRunnable(delivery, reason) {
143117
143664
  if (!this.started) return;
143665
+ delivery = this.withStore((store) => store.getDelivery(delivery.requesterSessionId, delivery.operationId));
143666
+ if (delivery.state === "consumed") {
143667
+ this.observedDeliverySettlements.delete(delivery.deliveryId);
143668
+ return;
143669
+ }
143670
+ if (delivery.activeClaimId || delivery.activeClaimWorkerBootId) {
143671
+ const settlement = this.observedDeliverySettlements.get(delivery.deliveryId);
143672
+ if (settlement && delivery.activeClaimWorkerBootId === this.workerBootId && delivery.activeClaimId === settlement.claimId) {
143673
+ await this.settleObservedDeliveryClaim(delivery, settlement);
143674
+ } else if (settlement) {
143675
+ this.observedDeliverySettlements.delete(delivery.deliveryId);
143676
+ }
143677
+ return;
143678
+ }
143679
+ this.observedDeliverySettlements.delete(delivery.deliveryId);
143118
143680
  const metaRecord = await this.options.workspaceDocument.repo.getDocMeta(getSessionRoomId(delivery.requesterSessionId));
143119
143681
  if (!metaRecord?.meta || isLoroRepoDocDeleted(metaRecord)) return;
143120
143682
  const meta = metaRecord.meta;
@@ -143122,32 +143684,54 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
143122
143684
  const sessionDoc = await this.options.workspaceDocument.getOrCreateSessionDoc(delivery.requesterSessionId);
143123
143685
  this.subscribeTarget(delivery.requesterSessionId, sessionDoc);
143124
143686
  const execution = this.options.executionService.getExecutionSnapshot(delivery.requesterSessionId);
143125
- const historyBeforeDispatch = await sessionDoc.getHistory();
143126
- const continuationEvidence = this.getContinuationEvidence(historyBeforeDispatch, delivery.systemTurnId);
143127
- if (continuationEvidence) {
143128
- this.consumeDelivery(delivery, reason, continuationEvidence);
143129
- return;
143130
- }
143131
143687
  const operation = this.withStore((store) => store.get(delivery.requesterSessionId, delivery.operationId));
143132
143688
  if (this.now() >= Date.parse(operation.deadlineAt) + DELIVERY_EXPIRY_GRACE_MS) {
143133
- this.consumeDelivery(delivery, reason, "expired_stale");
143689
+ await this.finalizeDeliveryWithoutExecution(sessionDoc, operation, delivery, reason, "expired_stale", void 0, false, delivery.executionPhase === "uncertain" ? "uncertain" : "ready");
143690
+ return;
143691
+ }
143692
+ if (delivery.executionPhase === "uncertain") {
143693
+ await this.failUncertainDelivery(sessionDoc, operation, delivery, reason);
143134
143694
  return;
143135
143695
  }
143136
143696
  if (execution.hasActiveTurn) return;
143137
143697
  if (this.options.dispatchWatcher.hasPendingDispatch(delivery.requesterSessionId)) return;
143698
+ if (delivery.attemptCount >= DELIVERY_MAX_ATTEMPTS) {
143699
+ await this.failExhaustedDelivery(sessionDoc, operation, delivery, reason);
143700
+ return;
143701
+ }
143138
143702
  const configuration = await this.resolveFrozenConfiguration(operation, delivery, reason);
143139
143703
  if (configuration === "unknown") {
143140
143704
  this.armConfigurationRetry(delivery.requesterSessionId);
143141
143705
  return;
143142
143706
  }
143143
143707
  if (configuration === "unavailable") {
143144
- await this.writeCompletionTurn(sessionDoc, operation, delivery, false);
143145
- this.consumeDelivery(delivery, reason, "configuration_unavailable");
143708
+ await this.finalizeDeliveryWithoutExecution(sessionDoc, operation, delivery, reason, "configuration_unavailable", {
143709
+ code: "CONFIGURATION_UNAVAILABLE",
143710
+ message: "The frozen continuation agent configuration is no longer available."
143711
+ });
143146
143712
  return;
143147
143713
  }
143148
143714
  const frozen = operation.frozenContinuationConfig.inputConfig;
143149
143715
  const requester = await this.resolveRequesterIdentity(operation.requesterUserId);
143150
- await this.options.executionService.continueSession({
143716
+ const attemptId = randomUUID();
143717
+ let observedSettlement;
143718
+ const settleResidualClaim = () => observedSettlement ? this.settleObservedDeliveryClaim(delivery, {
143719
+ claimId: attemptId,
143720
+ outcome: observedSettlement
143721
+ }) : this.withStore((store) => {
143722
+ let current2 = store.getDelivery(delivery.requesterSessionId, delivery.operationId);
143723
+ if (current2.activeClaimWorkerBootId !== this.workerBootId || current2.activeClaimId !== attemptId) {
143724
+ return current2;
143725
+ }
143726
+ if (current2.executionPhase === "started") {
143727
+ store.markClaimedDeliveryExecutionUncertain(delivery.requesterSessionId, delivery.operationId, this.workerBootId, attemptId);
143728
+ } else {
143729
+ store.releaseDeliveryClaim(delivery.requesterSessionId, delivery.operationId, this.workerBootId, attemptId);
143730
+ }
143731
+ current2 = store.getDelivery(delivery.requesterSessionId, delivery.operationId);
143732
+ return current2;
143733
+ });
143734
+ const continuation = this.options.executionService.continueSession({
143151
143735
  type: "session/chat",
143152
143736
  sessionId: delivery.requesterSessionId,
143153
143737
  machineId: this.options.machineId,
@@ -143183,18 +143767,97 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
143183
143767
  }, {
143184
143768
  dispatchSource: "delivery",
143185
143769
  onTurnClaimed: async () => {
143186
- await this.writeCompletionTurn(sessionDoc, operation, delivery, true);
143770
+ if (!this.started) return false;
143771
+ const claim = this.withStore((store) => store.claimDeliveryExecution(delivery.requesterSessionId, delivery.operationId, {
143772
+ claimId: attemptId,
143773
+ workerBootId: this.workerBootId
143774
+ }));
143775
+ if (claim.status !== "claimed") {
143776
+ this.options.logger.debug(`[orchestration] Delivery ${delivery.deliveryId} claim lost status=${claim.status}`);
143777
+ return false;
143778
+ }
143779
+ try {
143780
+ await this.writeCompletionTurn(sessionDoc, operation, delivery);
143781
+ const prepared = this.withStore((store) => store.prepareClaimedDeliveryExecution(delivery.requesterSessionId, delivery.operationId, this.workerBootId, attemptId));
143782
+ if (!prepared.prepared) {
143783
+ this.withStore((store) => store.releaseDeliveryClaim(delivery.requesterSessionId, delivery.operationId, this.workerBootId, attemptId));
143784
+ this.options.logger.debug(`[orchestration] Delivery ${delivery.deliveryId} execution start lost its claim`);
143785
+ return false;
143786
+ }
143787
+ } catch (error2) {
143788
+ this.withStore((store) => store.releaseDeliveryClaim(delivery.requesterSessionId, delivery.operationId, this.workerBootId, attemptId));
143789
+ throw error2;
143790
+ }
143791
+ return true;
143792
+ },
143793
+ onTurnStarted: async () => this.withStore((store) => store.markClaimedDeliveryExecutionStarted(delivery.requesterSessionId, delivery.operationId, this.workerBootId, attemptId)),
143794
+ onTurnSettled: async (outcome) => {
143795
+ observedSettlement = outcome;
143796
+ const settled = await this.settleObservedDeliveryClaim(delivery, {
143797
+ claimId: attemptId,
143798
+ outcome
143799
+ });
143800
+ if (outcome === "handled" || outcome === "cancelled") {
143801
+ this.options.logger.debug(`[orchestration] Delivery ${delivery.deliveryId} consumed=${String(settled.state === "consumed")}`);
143802
+ }
143187
143803
  }
143188
143804
  });
143189
- const historyAfterExecution = await sessionDoc.getHistory();
143190
- const evidenceAfterExecution = this.getContinuationEvidence(historyAfterExecution, delivery.systemTurnId);
143191
- if (evidenceAfterExecution) {
143192
- this.consumeDelivery(delivery, reason, evidenceAfterExecution);
143805
+ try {
143806
+ await continuation;
143807
+ } catch (error2) {
143808
+ const afterInterruption = await settleResidualClaim();
143809
+ if (afterInterruption.executionPhase === "uncertain") {
143810
+ await this.failUncertainDelivery(sessionDoc, operation, afterInterruption, reason);
143811
+ }
143812
+ if (afterInterruption.state === "pending" && !afterInterruption.activeClaimId && afterInterruption.attemptCount >= DELIVERY_MAX_ATTEMPTS) {
143813
+ await this.failExhaustedDelivery(sessionDoc, operation, afterInterruption, reason);
143814
+ }
143815
+ throw error2;
143816
+ }
143817
+ const afterExecution = await settleResidualClaim();
143818
+ if (afterExecution.executionPhase === "uncertain") {
143819
+ await this.failUncertainDelivery(sessionDoc, operation, afterExecution, reason);
143820
+ return;
143193
143821
  }
143822
+ if (afterExecution.state === "pending" && !afterExecution.activeClaimId && afterExecution.attemptCount >= DELIVERY_MAX_ATTEMPTS) {
143823
+ await this.failExhaustedDelivery(sessionDoc, operation, afterExecution, reason);
143824
+ }
143825
+ }
143826
+ async failExhaustedDelivery(sessionDoc, operation, delivery, wakeReason) {
143827
+ await this.finalizeDeliveryWithoutExecution(sessionDoc, operation, delivery, wakeReason, "attempts_exhausted", {
143828
+ code: "DELIVERY_ATTEMPTS_EXHAUSTED",
143829
+ message: "The completion continuation did not settle after two delivery attempts."
143830
+ }, true);
143831
+ }
143832
+ async failUncertainDelivery(sessionDoc, operation, delivery, wakeReason) {
143833
+ await this.finalizeDeliveryWithoutExecution(sessionDoc, operation, delivery, wakeReason, "execution_uncertain", {
143834
+ status: "uncertain",
143835
+ code: "DELIVERY_EXECUTION_UNCERTAIN",
143836
+ message: "The completion continuation may have started before execution was interrupted. It was not replayed; review the session output and continue manually if needed."
143837
+ }, false, "uncertain");
143194
143838
  }
143195
- consumeDelivery(delivery, wakeReason, evidence) {
143839
+ async finalizeDeliveryWithoutExecution(sessionDoc, operation, delivery, wakeReason, evidence, continuationFailure, requireAttemptsExhausted = false, requiredExecutionPhase = "ready") {
143840
+ if (!this.started) return;
143196
143841
  const startedAt = performance$2.now();
143197
- this.withStore((store) => store.consumeDelivery(delivery.requesterSessionId, delivery.operationId));
143842
+ const claimId = randomUUID();
143843
+ const claim = this.withStore((store) => store.claimDeliveryFinalization(delivery.requesterSessionId, delivery.operationId, {
143844
+ claimId,
143845
+ workerBootId: this.workerBootId,
143846
+ requireAttemptsExhausted,
143847
+ requiredExecutionPhase
143848
+ }));
143849
+ if (claim.status !== "claimed") {
143850
+ this.options.logger.debug(`[orchestration] Delivery ${delivery.deliveryId} finalization skipped status=${claim.status} reason=${evidence} wake=${wakeReason}`);
143851
+ return;
143852
+ }
143853
+ const settled = await this.settleObservedDeliveryClaim(delivery, {
143854
+ claimId,
143855
+ outcome: "finalize",
143856
+ ...continuationFailure ? {
143857
+ pendingHistoryWrite: () => this.writeCompletionTurn(sessionDoc, operation, delivery, continuationFailure)
143858
+ } : {}
143859
+ });
143860
+ if (settled.state !== "consumed") return;
143198
143861
  const timer2 = this.configurationTimers.get(delivery.requesterSessionId);
143199
143862
  if (timer2) clearTimeout(timer2);
143200
143863
  this.configurationTimers.delete(delivery.requesterSessionId);
@@ -143248,50 +143911,83 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
143248
143911
  timer2.unref?.();
143249
143912
  this.configurationTimers.set(sessionId, timer2);
143250
143913
  }
143251
- async writeCompletionTurn(sessionDoc, operation, delivery, configAvailable) {
143914
+ async writeCompletionTurn(sessionDoc, operation, delivery, continuationFailure) {
143252
143915
  if (!operation.completion) {
143253
143916
  throw new Error(`Finished Operation ${operation.operationId} has no completion.`);
143254
143917
  }
143255
- const progressMessageId = this.findProgressMessageId(await sessionDoc.getHistory(), operation);
143256
- const item = {
143257
- type: "operation_completion",
143258
- deliveryId: delivery.deliveryId,
143259
- operationId: operation.operationId,
143260
- operationKind: operation.kind,
143261
- ...progressMessageId ? {
143262
- progressMessageId
143263
- } : {},
143264
- completion: operation.completion,
143265
- ...!configAvailable ? {
143266
- continuation: {
143267
- status: "not_started",
143268
- reason: {
143269
- code: "CONFIGURATION_UNAVAILABLE",
143270
- message: "The frozen continuation agent configuration is no longer available."
143918
+ const completion = operation.completion;
143919
+ const buildTurn = (progressMessageId) => {
143920
+ const item = {
143921
+ type: "operation_completion",
143922
+ deliveryId: delivery.deliveryId,
143923
+ operationId: operation.operationId,
143924
+ operationKind: operation.kind,
143925
+ ...progressMessageId ? {
143926
+ progressMessageId
143927
+ } : {},
143928
+ completion,
143929
+ ...continuationFailure ? {
143930
+ continuation: {
143931
+ status: continuationFailure.status ?? "not_started",
143932
+ reason: {
143933
+ code: continuationFailure.code,
143934
+ message: continuationFailure.message
143935
+ }
143271
143936
  }
143937
+ } : {}
143938
+ };
143939
+ return {
143940
+ id: delivery.systemTurnId,
143941
+ role: "system",
143942
+ userId: operation.requesterUserId,
143943
+ timestamp: new Date(this.now()).toISOString(),
143944
+ items: [
143945
+ item
143946
+ ],
143947
+ fileDiff: [],
143948
+ finished: true,
143949
+ inputConfig: {
143950
+ ...operation.frozenContinuationConfig.inputConfig,
143951
+ prompt: completionText(operation),
143952
+ chainDepth: operation.initiatorChainDepth + 1
143272
143953
  }
143273
- } : {}
143274
- };
143275
- const turn = {
143276
- id: delivery.systemTurnId,
143277
- role: "system",
143278
- userId: operation.requesterUserId,
143279
- timestamp: new Date(this.now()).toISOString(),
143280
- items: [
143281
- item
143282
- ],
143283
- fileDiff: [],
143284
- finished: true,
143285
- inputConfig: {
143286
- ...operation.frozenContinuationConfig.inputConfig,
143287
- prompt: completionText(operation),
143288
- chainDepth: operation.initiatorChainDepth + 1
143289
- }
143954
+ };
143290
143955
  };
143291
- await sessionDoc.updateHistory((history) => history.some((entry) => entry.id === delivery.systemTurnId) ? history : [
143292
- ...history,
143293
- turn
143294
- ]);
143956
+ await sessionDoc.updateHistory((history) => {
143957
+ const progressMessageId = this.findProgressMessageId(history, operation);
143958
+ const existing = history.find((entry) => entry.id === delivery.systemTurnId);
143959
+ if (!existing) return [
143960
+ ...history,
143961
+ buildTurn(progressMessageId)
143962
+ ];
143963
+ if (existing.role !== "system") return history;
143964
+ return history.map((entry) => entry.id !== delivery.systemTurnId ? entry : {
143965
+ ...entry,
143966
+ items: entry.items?.map((existingItem) => {
143967
+ if (existingItem.type !== "operation_completion" || existingItem.deliveryId !== delivery.deliveryId) {
143968
+ return existingItem;
143969
+ }
143970
+ const linkedItem = progressMessageId ? {
143971
+ ...existingItem,
143972
+ progressMessageId
143973
+ } : existingItem;
143974
+ if (continuationFailure) {
143975
+ return {
143976
+ ...linkedItem,
143977
+ continuation: {
143978
+ status: continuationFailure.status ?? "not_started",
143979
+ reason: {
143980
+ code: continuationFailure.code,
143981
+ message: continuationFailure.message
143982
+ }
143983
+ }
143984
+ };
143985
+ }
143986
+ const { continuation: _continuation, ...withoutContinuation } = linkedItem;
143987
+ return withoutContinuation;
143988
+ })
143989
+ });
143990
+ });
143295
143991
  }
143296
143992
  findProgressMessageId(history, operation) {
143297
143993
  if (operation.kind !== "session_create" && operation.kind !== "session_create_many") {
@@ -143312,20 +144008,6 @@ The postId is ${normalizedFeedbackPostId}. Use the feedback-progress-reporter sk
143312
144008
  ].every((item) => item.status === "succeeded" ? covered.get(getOperationProgressTargetKey(item.target)) === "succeeded" : item.status === "active" && item.inputDurable ? covered.has(getOperationProgressTargetKey(item.target)) : true);
143313
144009
  return complete2 ? progressMessageId : void 0;
143314
144010
  }
143315
- getContinuationEvidence(history, systemTurnId) {
143316
- const index = history.findIndex((entry) => entry.id === systemTurnId && entry.role === "system");
143317
- if (index < 0) return null;
143318
- const completionWasUnavailable = history[index]?.items?.some((item) => item.type === "operation_completion" && item.continuation?.status === "not_started" && item.continuation.reason.code === "CONFIGURATION_UNAVAILABLE");
143319
- if (completionWasUnavailable) return "configuration_unavailable";
143320
- for (const entry of history.slice(index + 1)) {
143321
- if (entry.role === "assistant") return "assistant_history";
143322
- if (entry.role === "user") return null;
143323
- if (entry.role === "system" && entry.items?.some((item) => item.type === "system_notice" && item.name === "chat_failed")) {
143324
- return "chat_failed";
143325
- }
143326
- }
143327
- return null;
143328
- }
143329
144011
  }
143330
144012
  const version = "1.33.0";
143331
144013
  var lookup = [];
@@ -222954,7 +223636,7 @@ ${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
222954
223636
  data = createReviewBundleSnapshot(bundle);
222955
223637
  }
222956
223638
  const { injectReviewSnapshot } = await import("./chunks/index-VoI6Ds2-.js");
222957
- const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer-CEr3NCEE.js").then(async (m) => {
223639
+ const { resolveReviewViewerTemplate } = await import("./chunks/review-viewer-DqtXyKjy.js").then(async (m) => {
222958
223640
  await m.__tla;
222959
223641
  return m;
222960
223642
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lody",
3
- "version": "0.92.0",
3
+ "version": "0.92.1",
4
4
  "description": "Lody Agent CLI tool for managing remote command execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",