chatroom-cli 1.112.0 → 1.115.0

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.
package/dist/index.js CHANGED
@@ -28823,7 +28823,7 @@ function normalizeAgentLifecycleFact(raw) {
28823
28823
  emittedAt: Number(rest.emittedAt)
28824
28824
  };
28825
28825
  }
28826
- if (kind === "spawned" || kind === "exited" || kind === "activity") {
28826
+ if (kind === "spawned" || kind === "exited" || kind === "activity" || kind === "turn_failed") {
28827
28827
  return rest;
28828
28828
  }
28829
28829
  throw new Error(`Unknown agent lifecycle fact kind: ${String(kind)}`);
@@ -30154,11 +30154,10 @@ class AgentProcessManager {
30154
30154
  wantResume: slot?.wantResume
30155
30155
  });
30156
30156
  const completionStatus = opts.completion?.status ?? "completed";
30157
- console.log(`[AgentProcessManager] lifecycle.turn.${completionStatus === "completed" ? "completed" : "terminal"}: role=${opts.role} pid=${opts.pid} harness=${opts.harness} status=${completionStatus}${opts.completion ? ` source=${opts.completion.source}` : ""}`);
30157
+ console.log(`[AgentProcessManager] lifecycle.turn.${completionStatus === "completed" ? "completed" : "failed"}: role=${opts.role} pid=${opts.pid} harness=${opts.harness} status=${completionStatus} completion=${JSON.stringify(opts.completion ?? { status: "completed" })}`);
30158
30158
  if (capabilities.supportsNativeIntegration) {
30159
- if (completionStatus !== "completed") {
30159
+ if (completionStatus === "process_exited") {
30160
30160
  setNativeTurnPhase(slot, defaultNativeTurnPhase());
30161
- console.warn(`[AgentProcessManager] Native turn did not complete successfully for ${opts.role}: ${completionStatus}`);
30162
30161
  return;
30163
30162
  }
30164
30163
  this.maybeEmitProviderUnavailable(opts.chatroomId, opts.role, slot);
@@ -30168,11 +30167,25 @@ class AgentProcessManager {
30168
30167
  pid: opts.pid,
30169
30168
  harness: opts.harness,
30170
30169
  slot,
30171
- eventId: `${opts.pid}:${++this.agentTurnEndedSequence}`
30170
+ eventId: `${opts.pid}:${++this.agentTurnEndedSequence}`,
30171
+ completion: opts.completion ?? {
30172
+ turnId: `${opts.pid}:${this.agentTurnEndedSequence}`,
30173
+ status: "completed",
30174
+ source: "agent-process-manager.agent-end"
30175
+ }
30172
30176
  };
30173
- await Promise.all([...this.agentTurnEndedHandlers].map((handler) => handler(event)));
30177
+ const dispositions = await Promise.all([...this.agentTurnEndedHandlers].map((handler) => handler(event)));
30178
+ const held = dispositions.find((disposition) => disposition?.kind === "hold-slot");
30179
+ if (held?.kind === "hold-slot") {
30180
+ console.warn(`[AgentProcessManager] Native turn slot held after ${completionStatus}: role=${opts.role} pid=${opts.pid} reason=${held.reason}`);
30181
+ return;
30182
+ }
30183
+ if (completionStatus !== "completed" && !dispositions.some((disposition) => disposition?.kind === "release-slot")) {
30184
+ console.warn(`[AgentProcessManager] Native turn slot held: no task-service disposition returned role=${opts.role} pid=${opts.pid} status=${completionStatus}`);
30185
+ return;
30186
+ }
30174
30187
  setNativeTurnPhase(slot, defaultNativeTurnPhase());
30175
- console.log(`[AgentProcessManager] ✅ Native agent_end completed for ${opts.role}`);
30188
+ console.log(`[AgentProcessManager] Native agent_end disposition accepted: role=${opts.role} status=${completionStatus} disposition=release-slot`);
30176
30189
  return;
30177
30190
  }
30178
30191
  const result = await handleTurnCompleted({
@@ -30208,17 +30221,7 @@ class AgentProcessManager {
30208
30221
  }
30209
30222
  this.maybeEmitProviderUnavailable(opts.chatroomId, opts.role, slot);
30210
30223
  if (slot.harness && getHarnessCapabilities(slot.harness).supportsNativeIntegration) {
30211
- for (const handler of this.agentSessionLostHandlers) {
30212
- try {
30213
- handler({
30214
- chatroomId: opts.chatroomId,
30215
- role: opts.role,
30216
- harnessSessionId: ctx.harnessSessionId
30217
- });
30218
- } catch (error) {
30219
- console.warn(`[AgentProcessManager] native session-loss cleanup failed for ${opts.role}@${opts.chatroomId}: ${error instanceof Error ? error.message : String(error)}`);
30220
- }
30221
- }
30224
+ this.notifyAgentSessionLost(opts.chatroomId, opts.role, ctx.harnessSessionId);
30222
30225
  }
30223
30226
  const lifecyclePromise = this.lifecycle.runPromise(exports_Effect.gen(function* () {
30224
30227
  const svc = yield* AgentLifecycleService;
@@ -30509,12 +30512,22 @@ class AgentProcessManager {
30509
30512
  async syncSlotsAfterScopedStop(result) {
30510
30513
  for (const { target } of result.targets) {
30511
30514
  const slot = this.slots.get(agentKey2(target.chatroomId, target.role));
30515
+ this.notifyAgentSessionLost(target.chatroomId, target.role, slot?.pid === target.pid ? slot.harnessSessionId : undefined);
30512
30516
  if (!slot || slot.pid !== target.pid)
30513
30517
  continue;
30514
30518
  this.resetSlotAfterStop(slot);
30515
30519
  await this.clearAgentPidQuietly(target.chatroomId, target.role);
30516
30520
  }
30517
30521
  }
30522
+ notifyAgentSessionLost(chatroomId, role, harnessSessionId) {
30523
+ for (const handler of this.agentSessionLostHandlers) {
30524
+ try {
30525
+ handler({ chatroomId, role, ...harnessSessionId ? { harnessSessionId } : {} });
30526
+ } catch (error) {
30527
+ console.warn(`[AgentProcessManager] native session-loss cleanup failed for ${role}@${chatroomId}: ${error instanceof Error ? error.message : String(error)}`);
30528
+ }
30529
+ }
30530
+ }
30518
30531
  queueExitRetry(item) {
30519
30532
  this.exitRetryQueue.push(item);
30520
30533
  if (this.exitRetryTimer === null) {
@@ -31807,6 +31820,55 @@ function logNativeDeliveryInjecting(role, chatroomId, taskId) {
31807
31820
  console.log(`[NativeDelivery:inject] ${role}@${chatroomId} task ${taskId} — starting injection`);
31808
31821
  }
31809
31822
 
31823
+ // src/daemon/services/task-service/service/native-delivery/role-delivery-state.ts
31824
+ function roleKey(chatroomId, role) {
31825
+ return `${chatroomId}:${role.toLowerCase()}`;
31826
+ }
31827
+
31828
+ class RoleDeliveryState {
31829
+ generation = new Map;
31830
+ inFlight = new Set;
31831
+ nativeNudgeFailures = new Map;
31832
+ getGeneration(chatroomId, role) {
31833
+ return this.generation.get(roleKey(chatroomId, role)) ?? 0;
31834
+ }
31835
+ resetDeliveryState(chatroomId, role) {
31836
+ const key = roleKey(chatroomId, role);
31837
+ const next4 = (this.generation.get(key) ?? 0) + 1;
31838
+ this.generation.set(key, next4);
31839
+ this.inFlight.delete(key);
31840
+ this.nativeNudgeFailures.delete(key);
31841
+ return next4;
31842
+ }
31843
+ tryAcquireDelivery(chatroomId, role) {
31844
+ const key = roleKey(chatroomId, role);
31845
+ if (this.inFlight.has(key))
31846
+ return false;
31847
+ this.inFlight.add(key);
31848
+ return true;
31849
+ }
31850
+ releaseDelivery(chatroomId, role) {
31851
+ this.inFlight.delete(roleKey(chatroomId, role));
31852
+ }
31853
+ recordNativeNudgeFailure(chatroomId, role) {
31854
+ const key = roleKey(chatroomId, role);
31855
+ const count3 = (this.nativeNudgeFailures.get(key) ?? 0) + 1;
31856
+ this.nativeNudgeFailures.set(key, count3);
31857
+ return count3;
31858
+ }
31859
+ clearNativeNudgeFailures(chatroomId, role) {
31860
+ this.nativeNudgeFailures.delete(roleKey(chatroomId, role));
31861
+ }
31862
+ getNativeNudgeFailures(chatroomId, role) {
31863
+ return this.nativeNudgeFailures.get(roleKey(chatroomId, role)) ?? 0;
31864
+ }
31865
+ }
31866
+ function getRoleDeliveryState() {
31867
+ shared ??= new RoleDeliveryState;
31868
+ return shared;
31869
+ }
31870
+ var shared;
31871
+
31810
31872
  // src/daemon/services/task-service/service/native-delivery/delivery-decision.ts
31811
31873
  function taskSort(a, b) {
31812
31874
  const pendingOrder = Number(b.status === "pending") - Number(a.status === "pending");
@@ -31889,112 +31951,27 @@ var init_delivery_decision = __esm(() => {
31889
31951
  init_check_agent_slot();
31890
31952
  });
31891
31953
 
31892
- // src/infrastructure/mappers/map-assigned-task.ts
31893
- function mapAssignedTaskSnapshot(row) {
31894
- return {
31895
- taskId: row.taskId,
31896
- chatroomId: row.chatroomId,
31897
- status: row.status,
31898
- assignedTo: row.assignedTo,
31899
- updatedAt: row.updatedAt,
31900
- createdAt: row.createdAt,
31901
- agentConfig: {
31902
- role: row.agentConfig.role,
31903
- machineId: row.agentConfig.machineId,
31904
- agentHarness: row.agentConfig.agentHarness,
31905
- model: row.agentConfig.model,
31906
- workingDir: row.agentConfig.workingDir,
31907
- spawnedAgentPid: row.agentConfig.spawnedAgentPid,
31908
- desiredState: row.agentConfig.desiredState,
31909
- circuitState: row.agentConfig.circuitState,
31910
- configLifecycleRevision: row.agentConfig.configLifecycleRevision
31911
- },
31912
- participant: row.participant,
31913
- requestsNativeColdSession: row.requestsNativeColdSession
31914
- };
31915
- }
31916
- function mapAssignedTaskView(row) {
31917
- return {
31918
- ...mapAssignedTaskSnapshot(row),
31919
- taskContent: row.taskContent,
31920
- taskEnvelope: row.taskEnvelope,
31921
- startInNewSession: row.startInNewSession
31922
- };
31923
- }
31924
- function mapAssignedTaskSnapshotList(rows) {
31925
- return rows.map(mapAssignedTaskSnapshot);
31926
- }
31927
-
31928
31954
  // src/daemon/entry/restart-orchestrator-in-flight.ts
31929
- function roleKey(chatroomId, role) {
31955
+ function roleKey2(chatroomId, role) {
31930
31956
  return `${chatroomId}:${role.toLowerCase()}`;
31931
31957
  }
31932
31958
  function markRestartOrchestratorInFlight(chatroomId, role, correlationId) {
31933
- inFlight.set(roleKey(chatroomId, role), correlationId);
31959
+ inFlight.set(roleKey2(chatroomId, role), correlationId);
31934
31960
  }
31935
31961
  function clearRestartOrchestratorInFlight(chatroomId, role, correlationId) {
31936
- const key = roleKey(chatroomId, role);
31962
+ const key = roleKey2(chatroomId, role);
31937
31963
  if (correlationId !== undefined && inFlight.get(key) !== correlationId)
31938
31964
  return;
31939
31965
  inFlight.delete(key);
31940
31966
  }
31941
31967
  function isRestartOrchestratorInFlight(chatroomId, role) {
31942
- return inFlight.has(roleKey(chatroomId, role));
31968
+ return inFlight.has(roleKey2(chatroomId, role));
31943
31969
  }
31944
31970
  var inFlight;
31945
31971
  var init_restart_orchestrator_in_flight = __esm(() => {
31946
31972
  inFlight = new Map;
31947
31973
  });
31948
31974
 
31949
- // src/daemon/entry/role-delivery-state.ts
31950
- function roleKey2(chatroomId, role) {
31951
- return `${chatroomId}:${role.toLowerCase()}`;
31952
- }
31953
-
31954
- class RoleDeliveryState {
31955
- generation = new Map;
31956
- inFlight = new Set;
31957
- nativeNudgeFailures = new Map;
31958
- getGeneration(chatroomId, role) {
31959
- return this.generation.get(roleKey2(chatroomId, role)) ?? 0;
31960
- }
31961
- resetDeliveryState(chatroomId, role) {
31962
- const key = roleKey2(chatroomId, role);
31963
- const next4 = (this.generation.get(key) ?? 0) + 1;
31964
- this.generation.set(key, next4);
31965
- this.inFlight.delete(key);
31966
- this.nativeNudgeFailures.delete(key);
31967
- return next4;
31968
- }
31969
- tryAcquireDelivery(chatroomId, role) {
31970
- const key = roleKey2(chatroomId, role);
31971
- if (this.inFlight.has(key))
31972
- return false;
31973
- this.inFlight.add(key);
31974
- return true;
31975
- }
31976
- releaseDelivery(chatroomId, role) {
31977
- this.inFlight.delete(roleKey2(chatroomId, role));
31978
- }
31979
- recordNativeNudgeFailure(chatroomId, role) {
31980
- const key = roleKey2(chatroomId, role);
31981
- const count3 = (this.nativeNudgeFailures.get(key) ?? 0) + 1;
31982
- this.nativeNudgeFailures.set(key, count3);
31983
- return count3;
31984
- }
31985
- clearNativeNudgeFailures(chatroomId, role) {
31986
- this.nativeNudgeFailures.delete(roleKey2(chatroomId, role));
31987
- }
31988
- getNativeNudgeFailures(chatroomId, role) {
31989
- return this.nativeNudgeFailures.get(roleKey2(chatroomId, role)) ?? 0;
31990
- }
31991
- }
31992
- function getRoleDeliveryState() {
31993
- shared ??= new RoleDeliveryState;
31994
- return shared;
31995
- }
31996
- var shared;
31997
-
31998
31975
  // src/daemon/services/task-service/service/native-delivery/native-task-delivery-coordinator.ts
31999
31976
  class NativeTaskDeliveryCoordinator {
32000
31977
  resetRoleDeliveryState(chatroomId, role) {
@@ -32008,10 +31985,8 @@ class NativeTaskDeliveryCoordinator {
32008
31985
  runtime: runtime4,
32009
31986
  effectContext: effectContext2,
32010
31987
  agentMgr,
32011
- sessionDeps,
32012
31988
  operationalModel,
32013
31989
  isTaskActive,
32014
- machineId,
32015
31990
  onTaskDelivered,
32016
31991
  executors
32017
31992
  } = params;
@@ -32121,17 +32096,15 @@ class NativeTaskDeliveryCoordinator {
32121
32096
  continue;
32122
32097
  }
32123
32098
  await exports_Runtime.runPromise(runtime4)(exports_Effect.gen(function* () {
32124
- const backend2 = yield* exports_Effect.tryPromise(() => sessionDeps.backend.query(api.machines.getAssignedTaskForAction, {
32125
- sessionId: sessionDeps.sessionId,
32126
- machineId,
32127
- taskId: row.taskId,
32128
- role: row.agentConfig.role
32099
+ const full = yield* exports_Effect.tryPromise(() => taskService.loadAssignedTaskForAction({
32100
+ chatroomId: row.chatroomId,
32101
+ role: row.agentConfig.role,
32102
+ taskId: row.taskId
32129
32103
  }));
32130
- if (!backend2) {
32104
+ if (!full) {
32131
32105
  console.warn(`[NativeDelivery:execution] attempt=${attemptId} role=${role} chatroom=${row.chatroomId} task=${row.taskId} operation=inject result=task_hydration_missing`);
32132
32106
  return;
32133
32107
  }
32134
- const full = mapAssignedTaskView(backend2);
32135
32108
  yield* exports_Effect.tryPromise(() => taskService.deliverNativeTask(full, harnessSessionId, (delivered) => {
32136
32109
  onTaskDelivered?.(delivered);
32137
32110
  deliveryState.clearNativeNudgeFailures(delivered.chatroomId, delivered.role);
@@ -32155,7 +32128,6 @@ var init_native_task_delivery_coordinator = __esm(() => {
32155
32128
  init_agent();
32156
32129
  init_esm();
32157
32130
  init_delivery_decision();
32158
- init_api3();
32159
32131
  init_convex_error();
32160
32132
  init_check_agent_slot();
32161
32133
  init_restart_orchestrator_in_flight();
@@ -32180,15 +32152,13 @@ async function processTasksUpdate(runtime4, effectContext2, agentMgr, runSeriali
32180
32152
  taskId: task.taskId
32181
32153
  }, context5.signal)),
32182
32154
  injectTask: async (task, harnessSessionId) => {
32183
- const backend2 = await sessionDeps.backend.query(api.machines.getAssignedTaskForAction, {
32184
- sessionId: sessionDeps.sessionId,
32185
- machineId,
32186
- taskId: task.taskId,
32187
- role: task.agentConfig.role
32155
+ const full = await taskService.loadAssignedTaskForAction({
32156
+ chatroomId: task.chatroomId,
32157
+ role: task.agentConfig.role,
32158
+ taskId: task.taskId
32188
32159
  });
32189
- if (!backend2)
32160
+ if (!full)
32190
32161
  return { kind: "task-unavailable" };
32191
- const full = mapAssignedTaskView(backend2);
32192
32162
  let delivered;
32193
32163
  await taskService.deliverNativeTask(full, harnessSessionId, (result) => {
32194
32164
  delivered = result;
@@ -32216,7 +32186,6 @@ async function processTasksUpdate(runtime4, effectContext2, agentMgr, runSeriali
32216
32186
  var init_task_delivery_processor = __esm(() => {
32217
32187
  init_agent();
32218
32188
  init_native_task_delivery_coordinator();
32219
- init_api3();
32220
32189
  });
32221
32190
 
32222
32191
  // src/daemon/services/task-service/service/native-delivery/native-delivery-service.ts
@@ -32237,6 +32206,7 @@ class NativeDeliveryService {
32237
32206
  this.unsubscribeTaskService = deps.taskService.subscribe?.((notification) => this.handleTaskServiceNotification(notification));
32238
32207
  }
32239
32208
  async handleAgentStarted(event) {
32209
+ this.deps.agentTaskState.clear({ chatroomId: event.chatroomId, role: event.role });
32240
32210
  await this.requestReconcile({
32241
32211
  chatroomId: event.chatroomId,
32242
32212
  role: event.role,
@@ -32255,7 +32225,57 @@ class NativeDeliveryService {
32255
32225
  });
32256
32226
  }
32257
32227
  async handleAgentTurnEnded(event) {
32228
+ const completion = event.completion;
32229
+ if (completion && completion.status !== "completed") {
32230
+ const activeTask = this.deps.agentTaskState.get({
32231
+ chatroomId: event.chatroomId,
32232
+ role: event.role
32233
+ });
32234
+ const errorDetail = completion.error;
32235
+ console.error(`[NativeDelivery:turn-failed] chatroom=${event.chatroomId} role=${event.role} task=${activeTask?.taskId ?? "none"} turn=${completion.turnId} status=${completion.status} source=${completion.source} error=${errorDetail ?? "none"}`);
32236
+ if (activeTask) {
32237
+ try {
32238
+ await this.deps.taskService.releaseTaskAfterTurnFailure({
32239
+ chatroomId: event.chatroomId,
32240
+ role: event.role,
32241
+ taskId: activeTask.taskId
32242
+ });
32243
+ } catch (error) {
32244
+ console.error(`[NativeDelivery:turn-failed-recovery-error] chatroom=${event.chatroomId} role=${event.role} task=${activeTask.taskId} turn=${completion.turnId} error=${error instanceof Error ? error.stack ?? error.message : String(error)}`);
32245
+ return { kind: "hold-slot", reason: "task-recovery-failed" };
32246
+ }
32247
+ this.deps.agentTaskState.clear({ chatroomId: event.chatroomId, role: event.role });
32248
+ }
32249
+ const fact = {
32250
+ kind: "turn_failed",
32251
+ chatroomId: event.chatroomId,
32252
+ role: event.role,
32253
+ ...activeTask?.taskId ? { taskId: activeTask.taskId } : {},
32254
+ ...event.slot.harnessSessionId ? { harnessSessionId: event.slot.harnessSessionId } : {},
32255
+ turnId: completion.turnId,
32256
+ status: completion.status,
32257
+ source: completion.source,
32258
+ ...errorDetail ? { error: errorDetail } : {},
32259
+ revisionKey: buildAgentLifecycleRevisionKey("turn_failed", {
32260
+ chatroomId: event.chatroomId,
32261
+ role: event.role,
32262
+ turnId: completion.turnId
32263
+ }),
32264
+ emittedAt: Date.now()
32265
+ };
32266
+ try {
32267
+ await this.deps.lifecycleOutbox.enqueue(fact);
32268
+ } catch (error) {
32269
+ console.error(`[NativeDelivery:turn-failed-outbox-error] chatroom=${event.chatroomId} role=${event.role} turn=${completion.turnId} error=${error instanceof Error ? error.stack ?? error.message : String(error)}`);
32270
+ if (activeTask)
32271
+ return { kind: "release-slot" };
32272
+ return { kind: "hold-slot", reason: "turn-failed-outbox-enqueue-failed" };
32273
+ }
32274
+ return { kind: "release-slot" };
32275
+ }
32276
+ this.deps.agentTaskState.clear({ chatroomId: event.chatroomId, role: event.role });
32258
32277
  this.scheduleRoleDelivery(event.chatroomId, event.role);
32278
+ return { kind: "release-slot" };
32259
32279
  }
32260
32280
  scheduleRoleDelivery(chatroomId, role) {
32261
32281
  setTimeout(() => {
@@ -32345,6 +32365,19 @@ class NativeDeliveryService {
32345
32365
  this.reconcileStates.set(key, state);
32346
32366
  await state.promise;
32347
32367
  }
32368
+ async reconcileAfterAgentRestart(args2) {
32369
+ const delivered = [];
32370
+ await this.deps.taskService.syncAssignedTaskSnapshots();
32371
+ await this.requestReconcile({
32372
+ chatroomId: args2.chatroomId,
32373
+ role: args2.role,
32374
+ source: "restart-completed",
32375
+ onTaskDelivered: ({ taskId }) => {
32376
+ delivered.push(taskId);
32377
+ }
32378
+ });
32379
+ return delivered;
32380
+ }
32348
32381
  async requestReconcileForSnapshots(snapshots, source) {
32349
32382
  const roles = new Set(snapshots.map((snapshot) => `${snapshot.chatroomId}:${snapshot.agentConfig.role.toLowerCase()}`));
32350
32383
  await Promise.all([...roles].map((key) => {
@@ -32376,8 +32409,8 @@ var init_native_delivery_service = __esm(() => {
32376
32409
  init_task_delivery_processor();
32377
32410
  });
32378
32411
 
32379
- // src/daemon/services/task-service/service/task-outbox.ts
32380
- class TaskOutbox {
32412
+ // src/daemon/services/task-service/service/native-task-delivery-queue.ts
32413
+ class NativeTaskDeliveryQueue {
32381
32414
  sender;
32382
32415
  tails = new Map;
32383
32416
  constructor(sender) {
@@ -47125,6 +47158,42 @@ var init_assigned_task_snapshot_contract = __esm(() => {
47125
47158
  }));
47126
47159
  });
47127
47160
 
47161
+ // src/infrastructure/mappers/map-assigned-task.ts
47162
+ function mapAssignedTaskSnapshot(row) {
47163
+ return {
47164
+ taskId: row.taskId,
47165
+ chatroomId: row.chatroomId,
47166
+ status: row.status,
47167
+ assignedTo: row.assignedTo,
47168
+ updatedAt: row.updatedAt,
47169
+ createdAt: row.createdAt,
47170
+ agentConfig: {
47171
+ role: row.agentConfig.role,
47172
+ machineId: row.agentConfig.machineId,
47173
+ agentHarness: row.agentConfig.agentHarness,
47174
+ model: row.agentConfig.model,
47175
+ workingDir: row.agentConfig.workingDir,
47176
+ spawnedAgentPid: row.agentConfig.spawnedAgentPid,
47177
+ desiredState: row.agentConfig.desiredState,
47178
+ circuitState: row.agentConfig.circuitState,
47179
+ configLifecycleRevision: row.agentConfig.configLifecycleRevision
47180
+ },
47181
+ participant: row.participant,
47182
+ requestsNativeColdSession: row.requestsNativeColdSession
47183
+ };
47184
+ }
47185
+ function mapAssignedTaskView(row) {
47186
+ return {
47187
+ ...mapAssignedTaskSnapshot(row),
47188
+ taskContent: row.taskContent,
47189
+ taskEnvelope: row.taskEnvelope,
47190
+ startInNewSession: row.startInNewSession
47191
+ };
47192
+ }
47193
+ function mapAssignedTaskSnapshotList(rows) {
47194
+ return rows.map(mapAssignedTaskSnapshot);
47195
+ }
47196
+
47128
47197
  // src/daemon/infrastructure/inbox/fetch-machine-assigned-task-snapshots.ts
47129
47198
  async function fetchMachineAssignedTaskSnapshots(sessionDeps, machineId) {
47130
47199
  const result = await sessionDeps.backend.query(api.machines.listMachineAssignedTaskSnapshots, {
@@ -47292,6 +47361,11 @@ var init_inbox = __esm(() => {
47292
47361
  function snapshotKey(taskId, role) {
47293
47362
  return `${taskId}:${role.toLowerCase()}`;
47294
47363
  }
47364
+ function isStaleStatusPatch(snapshot, status3, updatedAt) {
47365
+ if (snapshot.updatedAt > updatedAt)
47366
+ return true;
47367
+ return snapshot.updatedAt === updatedAt && snapshot.status === "completed" && status3 !== "completed";
47368
+ }
47295
47369
 
47296
47370
  class MachineTaskSnapshotState {
47297
47371
  snapshots = new Map;
@@ -47335,13 +47409,23 @@ class MachineTaskSnapshotState {
47335
47409
  this.snapshots.set(snapshotKey(snapshot.taskId, snapshot.agentConfig.role), snapshot);
47336
47410
  }
47337
47411
  }
47412
+ markStatus(chatroomId, role, taskId, status3, updatedAt) {
47413
+ const key = snapshotKey(taskId, role);
47414
+ const snapshot = this.snapshots.get(key);
47415
+ if (!snapshot || snapshot.chatroomId !== chatroomId)
47416
+ return false;
47417
+ if (isStaleStatusPatch(snapshot, status3, updatedAt))
47418
+ return false;
47419
+ this.snapshots.set(key, { ...snapshot, status: status3, updatedAt });
47420
+ return true;
47421
+ }
47338
47422
  }
47339
47423
 
47340
47424
  // src/daemon/infrastructure/inbox/task-signal-contract.ts
47341
47425
  function asChatroomId(chatroomId) {
47342
47426
  return chatroomId;
47343
47427
  }
47344
- function buildSubscribeTaskStatusSignalsSinceArgs(input) {
47428
+ function buildSubscribeTaskDeliverySignalsSinceArgs(input) {
47345
47429
  return {
47346
47430
  sessionId: input.sessionId,
47347
47431
  machineId: input.machineId,
@@ -47350,7 +47434,7 @@ function buildSubscribeTaskStatusSignalsSinceArgs(input) {
47350
47434
  ...input.limit === undefined ? {} : { limit: input.limit }
47351
47435
  };
47352
47436
  }
47353
- function buildListTasksForMachineSignalRangeArgs(input) {
47437
+ function buildListTasksForMachineTaskDeliverySignalRangeArgs(input) {
47354
47438
  return {
47355
47439
  sessionId: input.sessionId,
47356
47440
  machineId: input.machineId,
@@ -47400,7 +47484,7 @@ function waitForTaskSignalPage(options, afterSignalKey) {
47400
47484
  settle(() => reject(error51));
47401
47485
  return;
47402
47486
  }
47403
- unsubscribe = options.client.onUpdate(api.messageList.subscribeTaskStatusSignalsSince, buildSubscribeTaskStatusSignalsSinceArgs({
47487
+ unsubscribe = options.client.onUpdate(api.taskDelivery.subscribeTaskDeliverySignalsSince, buildSubscribeTaskDeliverySignalsSinceArgs({
47404
47488
  sessionId: options.sessionId,
47405
47489
  machineId: options.machineId,
47406
47490
  chatroomId: options.chatroomId,
@@ -47437,7 +47521,7 @@ async function fetchSnapshotsForSignalPage(options, page) {
47437
47521
  let afterSignalKey = page.afterSignalKey;
47438
47522
  while (true) {
47439
47523
  throwIfAborted(options.signal);
47440
- const result = await options.client.query(api.tasks.listTasksForMachineSignalRange, buildListTasksForMachineSignalRangeArgs({
47524
+ const result = await options.client.query(api.taskDelivery.listTasksForMachineTaskDeliverySignalRange, buildListTasksForMachineTaskDeliverySignalRangeArgs({
47441
47525
  sessionId: options.sessionId,
47442
47526
  machineId: options.machineId,
47443
47527
  chatroomId: options.chatroomId,
@@ -47474,6 +47558,7 @@ function createConvexNativeTaskDeliveryGateway(backend2) {
47474
47558
  claimPendingTask: async (args2) => {
47475
47559
  await backend2.mutation(api.tasks.claimTask, args2);
47476
47560
  },
47561
+ releaseTaskAfterTurnFailure: (args2) => backend2.mutation(api.tasks.releaseTaskAfterTurnFailure, args2),
47477
47562
  loadDeliveryPrompt: (args2) => backend2.query(api.messages.getTaskDeliveryPrompt, args2),
47478
47563
  recordReceipt: async (args2) => {
47479
47564
  await backend2.mutation(api.taskDeliveryReceipts.record, {
@@ -47489,6 +47574,23 @@ function createConvexNativeTaskDeliveryGateway(backend2) {
47489
47574
  },
47490
47575
  recordSessionAugmentation: async (args2) => {
47491
47576
  await backend2.mutation(api.daemon.agentEvents.sessionAugmented, args2);
47577
+ },
47578
+ loadAssignedTaskForAction: async (args2) => {
47579
+ const row = await backend2.query(api.machines.getAssignedTaskForAction, {
47580
+ sessionId: args2.sessionId,
47581
+ machineId: args2.machineId,
47582
+ taskId: args2.taskId,
47583
+ role: args2.role
47584
+ });
47585
+ if (!row)
47586
+ return null;
47587
+ return mapAssignedTaskView(row);
47588
+ },
47589
+ syncAssignedTaskSnapshots: async ({ sessionId, machineId }) => {
47590
+ await backend2.mutation(api.machines.syncMachineAssignedTaskSnapshotsMutation, {
47591
+ sessionId,
47592
+ machineId
47593
+ });
47492
47594
  }
47493
47595
  };
47494
47596
  }
@@ -47519,7 +47621,7 @@ function createTaskService(deps) {
47519
47621
  let inboxClient;
47520
47622
  let serviceStartedAt = 0;
47521
47623
  let stopped = false;
47522
- const taskOutbox = new TaskOutbox(async (entry) => {
47624
+ const nativeTaskDeliveryQueue = new NativeTaskDeliveryQueue(async (entry) => {
47523
47625
  await exports_Effect.runPromise(runNativeInjectionEffect(entry.task, entry.harnessSessionId, {
47524
47626
  ...deps,
47525
47627
  agentMgr,
@@ -47590,10 +47692,7 @@ function createTaskService(deps) {
47590
47692
  sessionId: deps.sessionId,
47591
47693
  machineId: deps.machineId
47592
47694
  });
47593
- await deps.backend.mutation(api.machines.syncMachineAssignedTaskSnapshotsMutation, {
47594
- sessionId: deps.sessionId,
47595
- machineId: deps.machineId
47596
- });
47695
+ await service4.syncAssignedTaskSnapshots();
47597
47696
  const snapshots = await fetchMachineAssignedTaskSnapshots({ ...deps, convexUrl: deps.convexUrl }, deps.machineId);
47598
47697
  taskSnapshotState.replace(snapshots);
47599
47698
  inboxClient = client2;
@@ -47619,16 +47718,43 @@ function createTaskService(deps) {
47619
47718
  for (const controller of roomControllers.values())
47620
47719
  controller.abort();
47621
47720
  roomControllers.clear();
47622
- taskOutbox.stop();
47721
+ nativeTaskDeliveryQueue.stop();
47623
47722
  inboxStore?.close();
47624
47723
  inboxStore = undefined;
47625
47724
  },
47626
47725
  listTasksForRole: (chatroomId, role) => taskSnapshotState.listForRole(chatroomId, role),
47627
47726
  listAllTasks: () => taskSnapshotState.listAll(),
47628
47727
  taskSnapshotState,
47629
- deliverNativeTask: (task, harnessSessionId, onTaskDelivered) => taskOutbox.enqueue({ task, harnessSessionId, onTaskDelivered }),
47728
+ deliverNativeTask: (task, harnessSessionId, onTaskDelivered) => nativeTaskDeliveryQueue.enqueue({ task, harnessSessionId, onTaskDelivered }),
47630
47729
  isNativeHarness,
47730
+ releaseTaskAfterTurnFailure: async (args2) => {
47731
+ const result = await gateway.releaseTaskAfterTurnFailure({
47732
+ sessionId: deps.sessionId,
47733
+ chatroomId: args2.chatroomId,
47734
+ role: args2.role,
47735
+ taskId: args2.taskId
47736
+ });
47737
+ taskSnapshotState.markStatus(args2.chatroomId, args2.role, args2.taskId, result.status, result.updatedAt);
47738
+ return result;
47739
+ },
47631
47740
  snapshotRequestsNativeColdSession,
47741
+ loadAssignedTaskForAction: async ({ chatroomId, role, taskId }) => {
47742
+ const task = await gateway.loadAssignedTaskForAction({
47743
+ sessionId: deps.sessionId,
47744
+ machineId: deps.machineId,
47745
+ taskId,
47746
+ role
47747
+ });
47748
+ return task?.chatroomId === chatroomId ? task : null;
47749
+ },
47750
+ syncAssignedTaskSnapshots: async () => {
47751
+ await gateway.syncAssignedTaskSnapshots({
47752
+ sessionId: deps.sessionId,
47753
+ machineId: deps.machineId
47754
+ });
47755
+ const snapshots = await fetchMachineAssignedTaskSnapshots({ ...deps, convexUrl: deps.convexUrl }, deps.machineId);
47756
+ taskSnapshotState.replace(snapshots);
47757
+ },
47632
47758
  explainNativeDeliveryBlock: (task, options) => explainNativeDeliveryBlock(task, options),
47633
47759
  createNativeDeliveryService: (deliveryDeps) => {
47634
47760
  const nativeDelivery = new NativeDeliveryService({
@@ -104587,7 +104713,7 @@ function toConvexLifecycleFact(fact) {
104587
104713
  return {
104588
104714
  ...normalized,
104589
104715
  chatroomId: normalized.chatroomId,
104590
- ...normalized.kind === "activity" && normalized.taskId ? { taskId: normalized.taskId } : {}
104716
+ ...(normalized.kind === "activity" || normalized.kind === "turn_failed") && normalized.taskId ? { taskId: normalized.taskId } : {}
104591
104717
  };
104592
104718
  }
104593
104719
  function createAgentLifecycleSend(session2) {
@@ -111121,25 +111247,6 @@ async function forceNativeWaiting(deps, event) {
111121
111247
  action: NATIVE_WAITING_ACTION
111122
111248
  });
111123
111249
  }
111124
- async function syncAssignedTaskSnapshots(deps) {
111125
- await deps.session.backend.mutation(api.machines.syncMachineAssignedTaskSnapshotsMutation, {
111126
- sessionId: deps.session.sessionId,
111127
- machineId: deps.session.machineId
111128
- });
111129
- }
111130
- async function deliverPendingTasks(deps, event) {
111131
- const delivered = [];
111132
- await syncAssignedTaskSnapshots(deps);
111133
- await deps.nativeDelivery.requestReconcile({
111134
- chatroomId: event.chatroomId,
111135
- role: event.role,
111136
- source: "restart-completed",
111137
- onTaskDelivered: ({ taskId }) => {
111138
- delivered.push(taskId);
111139
- }
111140
- });
111141
- return delivered;
111142
- }
111143
111250
  async function runRestartOrchestrator(deps, event) {
111144
111251
  const { chatroomId, role } = event;
111145
111252
  markRestartOrchestratorInFlight(chatroomId, role, event.correlationId);
@@ -111173,7 +111280,10 @@ async function runRestartOrchestrator(deps, event) {
111173
111280
  await forceNativeWaiting(deps, event);
111174
111281
  await emitPhase(deps, event, "ready");
111175
111282
  await emitPhase(deps, event, "deliver");
111176
- const deliveredTaskIds = await deliverPendingTasks(deps, event);
111283
+ const deliveredTaskIds = await deps.nativeDelivery.reconcileAfterAgentRestart({
111284
+ chatroomId,
111285
+ role
111286
+ });
111177
111287
  await emitPhase(deps, event, "completed");
111178
111288
  await logDaemonAuditEvent(deps.session.logEvent, buildAgentRestartCompletedEvent({
111179
111289
  chatroomId: event.chatroomId,
@@ -117993,14 +118103,14 @@ var init_command_run_subscription = __esm(() => {
117993
118103
  dispatchedStop = new Set;
117994
118104
  });
117995
118105
 
117996
- // src/daemon/entry/task-inbox-membership-registry.ts
117997
- function registerTaskInboxRoomMembershipRefresh(refresh) {
118106
+ // src/daemon/entry/workspace-membership-refresh-registry.ts
118107
+ function registerWorkspaceMembershipRefresh(refresh) {
117998
118108
  refreshRoomMembership = refresh;
117999
118109
  }
118000
- function unregisterTaskInboxRoomMembershipRefresh() {
118110
+ function unregisterWorkspaceMembershipRefresh() {
118001
118111
  refreshRoomMembership = null;
118002
118112
  }
118003
- async function refreshTaskInboxRoomMembership() {
118113
+ async function refreshWorkspaceMembership() {
118004
118114
  await refreshRoomMembership?.();
118005
118115
  }
118006
118116
  var refreshRoomMembership = null;
@@ -118277,7 +118387,7 @@ var init_operational_inbox = __esm(() => {
118277
118387
  init_operational_signal_feeds();
118278
118388
  });
118279
118389
 
118280
- // src/daemon/entry/task-inbox-runtime.ts
118390
+ // src/daemon/entry/operational-inbox-runtime.ts
118281
118391
  function isAbortError2(error51) {
118282
118392
  return error51 instanceof Error && error51.name === "AbortError";
118283
118393
  }
@@ -118299,7 +118409,7 @@ async function runOperationalInboxLoopWithRestart(options, onUpdate, isStopped)
118299
118409
  }
118300
118410
  }
118301
118411
  }
118302
- var INBOX_RESTART_INITIAL_MS = 1000, INBOX_RESTART_MAX_MS = 30000, startTaskInboxEffect = (wsClient2) => exports_Effect.gen(function* () {
118412
+ var INBOX_RESTART_INITIAL_MS = 1000, INBOX_RESTART_MAX_MS = 30000, startOperationalInboxEffect = (wsClient2) => exports_Effect.gen(function* () {
118303
118413
  const session2 = yield* DaemonSessionService;
118304
118414
  const agentMgr = yield* DaemonAgentProcessManagerService;
118305
118415
  const commandService = yield* DaemonAgentProcessManagerCommandService;
@@ -118319,7 +118429,7 @@ var INBOX_RESTART_INITIAL_MS = 1000, INBOX_RESTART_MAX_MS = 30000, startTaskInbo
118319
118429
  query: (fn2, args2) => session2.backend.query(fn2, args2)
118320
118430
  }
118321
118431
  };
118322
- console.log(`[${formatTimestamp()}] \uD83D\uDCEC Starting task-inbox (chatroom-scoped operational signals)`);
118432
+ console.log(`[${formatTimestamp()}] \uD83D\uDCEC Starting operational-inbox (chatroom-scoped operational signals)`);
118323
118433
  const inboxStore = createInboxStateStore(resolveInboxDbPath(session2.machineId));
118324
118434
  const serviceStartedAt = Date.now();
118325
118435
  const abort = new AbortController;
@@ -118338,7 +118448,7 @@ var INBOX_RESTART_INITIAL_MS = 1000, INBOX_RESTART_MAX_MS = 30000, startTaskInbo
118338
118448
  lifecycleOutbox
118339
118449
  });
118340
118450
  yield* exports_Effect.tryPromise(() => session2.taskService.startTaskInbox(wsClient2)).pipe(exports_Effect.catchAll((error51) => {
118341
- console.warn("[TaskInbox] service bootstrap failed:", error51);
118451
+ console.warn("[TaskService] task inbox bootstrap failed:", error51);
118342
118452
  return exports_Effect.void;
118343
118453
  }));
118344
118454
  const knownRoomIds = new Set;
@@ -118447,10 +118557,10 @@ var INBOX_RESTART_INITIAL_MS = 1000, INBOX_RESTART_MAX_MS = 30000, startTaskInbo
118447
118557
  }
118448
118558
  await Promise.all(chatroomIds.map((chatroomId2) => ensureRoomInboxes(chatroomId2)));
118449
118559
  } catch (error51) {
118450
- console.warn("[TaskInbox] room membership refresh failed:", error51);
118560
+ console.warn("[WorkspaceMembership] room membership refresh failed:", error51);
118451
118561
  }
118452
118562
  };
118453
- registerTaskInboxRoomMembershipRefresh(refreshRoomMembership2);
118563
+ registerWorkspaceMembershipRefresh(refreshRoomMembership2);
118454
118564
  yield* exports_Effect.promise(refreshRoomMembership2);
118455
118565
  yield* exports_Effect.tryPromise(() => Promise.all([...knownRoomIds].map((chatroomId2) => ensureRoomInboxes(chatroomId2)))).pipe(exports_Effect.catchAll((error51) => {
118456
118566
  console.warn("[OperationalInbox] initial watcher start failed:", error51);
@@ -118464,7 +118574,7 @@ var INBOX_RESTART_INITIAL_MS = 1000, INBOX_RESTART_MAX_MS = 30000, startTaskInbo
118464
118574
  for (const watcher of roomWatchers.values()) {
118465
118575
  watcher.controller.abort();
118466
118576
  }
118467
- unregisterTaskInboxRoomMembershipRefresh();
118577
+ unregisterWorkspaceMembershipRefresh();
118468
118578
  session2.taskService.stopTaskInbox();
118469
118579
  nativeDelivery.dispose();
118470
118580
  nativeDelivery.agentTaskState.clearAll();
@@ -118472,7 +118582,7 @@ var INBOX_RESTART_INITIAL_MS = 1000, INBOX_RESTART_MAX_MS = 30000, startTaskInbo
118472
118582
  }
118473
118583
  };
118474
118584
  });
118475
- var init_task_inbox_runtime = __esm(() => {
118585
+ var init_operational_inbox_runtime = __esm(() => {
118476
118586
  init_esm();
118477
118587
  init_daemon_services();
118478
118588
  init_api3();
@@ -118993,7 +119103,7 @@ function createDaemonRuntime(deps) {
118993
119103
  break;
118994
119104
  }
118995
119105
  });
118996
- taskInboxHandle = yield* startTaskInboxEffect(deps.wsClient);
119106
+ taskInboxHandle = yield* startOperationalInboxEffect(deps.wsClient);
118997
119107
  logObserverSubscriptionHandle = startLogObserverSubscription({ sessionId: session2.sessionId, machineId: session2.machineId }, deps.wsClient);
118998
119108
  const commandRunRuntime = yield* exports_Effect.runtime();
118999
119109
  agenticQueryWorkerHandle = startAgenticQuerySubscriptions({
@@ -119048,7 +119158,7 @@ var init_daemon_runtime = __esm(() => {
119048
119158
  init_command_run_subscription();
119049
119159
  init_log_observer_sync();
119050
119160
  init_init_daemon();
119051
- init_task_inbox_runtime();
119161
+ init_operational_inbox_runtime();
119052
119162
  init_git_subscription();
119053
119163
  init_api3();
119054
119164
  init_workspace_list_subscription();
@@ -119979,7 +120089,7 @@ function startAllSubscribers(deps) {
119979
120089
  if (claimed.type === "daemon.workspaceListChanged") {
119980
120090
  enhancerJob.refreshChatrooms();
119981
120091
  gitRequest.refreshWorkspaces();
119982
- refreshTaskInboxRoomMembership();
120092
+ refreshWorkspaceMembership();
119983
120093
  }
119984
120094
  await dispatchCommandInboundEvent({
119985
120095
  type: "command.received",
@@ -135820,4 +135930,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
135820
135930
  });
135821
135931
  program2.parse();
135822
135932
 
135823
- //# debugId=B512277D42B2480364756E2164756E21
135933
+ //# debugId=A4A4E9F28A3DEB2964756E2164756E21