chatroom-cli 1.127.0 → 1.128.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.
package/dist/index.js CHANGED
@@ -20251,6 +20251,16 @@ var init_agent_process_manager_service = __esm(() => {
20251
20251
  init_check_agent_slot();
20252
20252
  });
20253
20253
 
20254
+ // ../../services/backend/config/reliability.ts
20255
+ var HARNESS_SESSION_READY_TIMEOUT_MS = 5000, NATIVE_DELIVERY_RECONCILE_MS = 1e4, DAEMON_HEARTBEAT_INTERVAL_MS, DAEMON_HEARTBEAT_TTL_MS, AGENT_REQUEST_DEADLINE_MS = 120000, MACHINE_COMMAND_LEASE_RENEWAL_INTERVAL_MS = 20000, MACHINE_COMMAND_DAEMON_ROUTINE_TTL_MS, SCOPE_TARGET_STOP_TIMEOUT_MS = 1e4, AGENT_LIFECYCLE_OPERATION_TIMEOUT_MS = 120000, CONNECTION_CLOSE_REQUEST_TTL_MS, ENHANCER_TERMINAL_JOB_RETENTION_MS;
20256
+ var init_reliability = __esm(() => {
20257
+ DAEMON_HEARTBEAT_INTERVAL_MS = 5 * 60000;
20258
+ DAEMON_HEARTBEAT_TTL_MS = 6 * DAEMON_HEARTBEAT_INTERVAL_MS;
20259
+ MACHINE_COMMAND_DAEMON_ROUTINE_TTL_MS = 5 * 60000;
20260
+ CONNECTION_CLOSE_REQUEST_TTL_MS = 10 * 60000;
20261
+ ENHANCER_TERMINAL_JOB_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;
20262
+ });
20263
+
20254
20264
  // ../shared/src/domain/team-kind.ts
20255
20265
  var TEAM_PRESET_IDS;
20256
20266
  var init_team_kind = __esm(() => {
@@ -35229,8 +35239,10 @@ var init_agent_lifecycle_fact = __esm(() => {
35229
35239
  function isDeliverableTaskStatus(status) {
35230
35240
  return status === "pending" || status === "acknowledged";
35231
35241
  }
35242
+ var ACTIVE_TASK_STATUSES;
35232
35243
  var init_assigned_task = __esm(() => {
35233
35244
  init_agent_role();
35245
+ ACTIVE_TASK_STATUSES = ["pending", "acknowledged", "in_progress"];
35234
35246
  });
35235
35247
 
35236
35248
  // src/daemon/infrastructure/local/harness/services/spawn-prompt.ts
@@ -35292,6 +35304,17 @@ var init_native_task_injector_logic = __esm(() => {
35292
35304
  };
35293
35305
  });
35294
35306
 
35307
+ // src/daemon/services/task-service/domain/usecase/uncovered-turn-nudge.ts
35308
+ function buildUncoveredTurnNudgePrompt(args2) {
35309
+ return [
35310
+ `Your previous turn ended, but task ${args2.taskId} has no handoff recorded.`,
35311
+ "If the work is complete, run `chatroom handoff` for this task now, as instructed in the task.",
35312
+ "If you are waiting on something (for example a background command or CI), do not end your turn: wait for it in the foreground, then run `chatroom handoff`.",
35313
+ "If you cannot do either, reply with one line saying what you are waiting on."
35314
+ ].join(`
35315
+ `);
35316
+ }
35317
+
35295
35318
  // ../../services/backend/src/domain/entities/participant.ts
35296
35319
  var NATIVE_WAITING_ACTION = "native:waiting", NATIVE_TASK_INJECTED_ACTION = "native:task-injected", GET_NEXT_TASK_STARTED_ACTION = "get-next-task:started";
35297
35320
 
@@ -36324,16 +36347,6 @@ var init_parse_session_augmentation = __esm(() => {
36324
36347
  init_team_agent_settings();
36325
36348
  });
36326
36349
 
36327
- // ../../services/backend/config/reliability.ts
36328
- var HARNESS_SESSION_READY_TIMEOUT_MS = 5000, NATIVE_DELIVERY_RECONCILE_MS = 1e4, DAEMON_HEARTBEAT_INTERVAL_MS, DAEMON_HEARTBEAT_TTL_MS, AGENT_REQUEST_DEADLINE_MS = 120000, MACHINE_COMMAND_LEASE_RENEWAL_INTERVAL_MS = 20000, MACHINE_COMMAND_DAEMON_ROUTINE_TTL_MS, SCOPE_TARGET_STOP_TIMEOUT_MS = 1e4, AGENT_LIFECYCLE_OPERATION_TIMEOUT_MS = 120000, CONNECTION_CLOSE_REQUEST_TTL_MS, ENHANCER_TERMINAL_JOB_RETENTION_MS;
36329
- var init_reliability = __esm(() => {
36330
- DAEMON_HEARTBEAT_INTERVAL_MS = 5 * 60000;
36331
- DAEMON_HEARTBEAT_TTL_MS = 6 * DAEMON_HEARTBEAT_INTERVAL_MS;
36332
- MACHINE_COMMAND_DAEMON_ROUTINE_TTL_MS = 5 * 60000;
36333
- CONNECTION_CLOSE_REQUEST_TTL_MS = 10 * 60000;
36334
- ENHANCER_TERMINAL_JOB_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;
36335
- });
36336
-
36337
36350
  // src/daemon/services/task-service/service/native-cold-session-before-inject.ts
36338
36351
  function sleep3(ms) {
36339
36352
  return new Promise((resolve2) => setTimeout(resolve2, ms));
@@ -36603,7 +36616,7 @@ function resumeHarnessWithPrompt(task, deps, prompt, harnessSessionId) {
36603
36616
  taskId,
36604
36617
  error: error51
36605
36618
  });
36606
- return;
36619
+ return yield* exports_Effect.fail(resumeResult.failure);
36607
36620
  }
36608
36621
  yield* exports_Effect.tryPromise({
36609
36622
  try: () => deps.audit.emit({
@@ -36732,6 +36745,8 @@ class AgentWorkManager {
36732
36745
  nativeTaskDeliveryQueue;
36733
36746
  deliveryTaskService;
36734
36747
  recoveryGates = new Map;
36748
+ respawnStartRetries = new Map;
36749
+ respawnRestartSeq = 0;
36735
36750
  disposed = false;
36736
36751
  constructor(deps) {
36737
36752
  this.deps = deps;
@@ -36763,7 +36778,10 @@ class AgentWorkManager {
36763
36778
  releaseTaskAfterTurnFailure: deps.taskService.releaseTaskAfterTurnFailure,
36764
36779
  recordDeliveryFailure: deps.taskService.recordDeliveryFailure,
36765
36780
  clearDeliveryFailure: deps.taskService.clearDeliveryFailure,
36766
- recordUncoveredTurnEnd: deps.taskService.recordUncoveredTurnEnd,
36781
+ recordTurnFailure: deps.taskService.recordTurnFailure,
36782
+ decideUncoveredTurnEnd: deps.taskService.decideUncoveredTurnEnd,
36783
+ confirmNudgeSent: deps.taskService.confirmNudgeSent,
36784
+ resetTurnTracking: deps.taskService.resetTurnTracking,
36767
36785
  isRedeliveryExhausted: deps.taskService.isRedeliveryExhausted,
36768
36786
  clearRedeliveryTracking: deps.taskService.clearRedeliveryTracking,
36769
36787
  forgetStaleTask: deps.taskService.forgetStaleTask,
@@ -36789,6 +36807,7 @@ class AgentWorkManager {
36789
36807
  this.unsubscribeTaskService = deps.taskService.subscribe((notification) => this.handleTaskServiceNotification(notification));
36790
36808
  }
36791
36809
  async handleAgentStarted(event) {
36810
+ this.cancelRespawnStart(recoveryKey(event.chatroomId, event.role), `agent_started:${event.reason ?? "unknown"}`);
36792
36811
  await this.waitForRoleRecovery(event.chatroomId, event.role);
36793
36812
  this.deps.agentTaskState.clear({ chatroomId: event.chatroomId, role: event.role });
36794
36813
  if (event.reason === "user.start") {
@@ -36906,9 +36925,9 @@ class AgentWorkManager {
36906
36925
  });
36907
36926
  }, delay3);
36908
36927
  }
36909
- async recoverTaskAfterUncoveredTurnEnd(event, activeTask, phase) {
36928
+ async recoverTaskAfterTurnFailure(event, activeTask, phase) {
36910
36929
  const { chatroomId, role } = event;
36911
- const { exceeded } = await this.deps.taskService.recordUncoveredTurnEnd({
36930
+ const { exceeded } = await this.deps.taskService.recordTurnFailure({
36912
36931
  chatroomId,
36913
36932
  role,
36914
36933
  taskId: activeTask.taskId
@@ -36937,7 +36956,7 @@ class AgentWorkManager {
36937
36956
  const errorDetail = completion.error;
36938
36957
  console.error(`[NativeDelivery:turn-failed] chatroom=${event.chatroomId} role=${event.role} task=${activeTask2?.taskId ?? "none"} turn=${completion.turnId} status=${completion.status} source=${completion.source} error=${errorDetail ?? "none"}`);
36939
36958
  if (activeTask2) {
36940
- const recovery = await this.recoverTaskAfterUncoveredTurnEnd(event, activeTask2, "turn-failed");
36959
+ const recovery = await this.recoverTaskAfterTurnFailure(event, activeTask2, "turn-failed");
36941
36960
  if (recovery === "exceeded") {
36942
36961
  this.deps.agentTaskState.clear({ chatroomId: event.chatroomId, role: event.role });
36943
36962
  return { kind: "release-slot" };
@@ -36977,14 +36996,41 @@ class AgentWorkManager {
36977
36996
  });
36978
36997
  if (activeTask) {
36979
36998
  const handoff = await this.deps.taskService.getLatestHandoff(event.chatroomId, event.role);
36980
- if (!handoff?.taskIds.includes(activeTask.taskId)) {
36981
- const recovery = await this.recoverTaskAfterUncoveredTurnEnd(event, activeTask, "turn-ended");
36982
- if (recovery === "recovery-failed") {
36983
- return { kind: "hold-slot", reason: "task-recovery-failed" };
36999
+ const covered = handoff?.taskIds.includes(activeTask.taskId) ?? false;
37000
+ if (covered) {
37001
+ this.deps.taskService.resetTurnTracking({
37002
+ chatroomId: event.chatroomId,
37003
+ role: event.role,
37004
+ taskId: activeTask.taskId
37005
+ });
37006
+ } else {
37007
+ const decision = await this.deps.taskService.decideUncoveredTurnEnd({
37008
+ chatroomId: event.chatroomId,
37009
+ role: event.role,
37010
+ taskId: activeTask.taskId,
37011
+ sessionKey: sessionKeyFor(event.pid, event.slot.harnessSessionId)
37012
+ });
37013
+ if (decision.action === "nudge") {
37014
+ await this.enqueueTurnEndedWaitingFact(event);
37015
+ this.scheduleUncoveredAction(event, activeTask, "nudge");
37016
+ return { kind: "release-slot" };
36984
37017
  }
37018
+ if (decision.action === "restart-session") {
37019
+ await this.enqueueTurnEndedWaitingFact(event);
37020
+ this.scheduleUncoveredAction(event, activeTask, "restart-session");
37021
+ return { kind: "release-slot" };
37022
+ }
37023
+ await this.enqueueTurnEndedWaitingFact(event);
37024
+ this.applyParkAction(event);
37025
+ return { kind: "release-slot" };
36985
37026
  }
36986
37027
  }
36987
37028
  this.deps.agentTaskState.clear({ chatroomId: event.chatroomId, role: event.role });
37029
+ await this.enqueueTurnEndedWaitingFact(event);
37030
+ this.scheduleRoleDelivery(event.chatroomId, event.role);
37031
+ return { kind: "release-slot" };
37032
+ }
37033
+ async enqueueTurnEndedWaitingFact(event) {
36988
37034
  try {
36989
37035
  await this.deps.lifecycleOutbox.enqueue(buildAgentStatusFact({
36990
37036
  chatroomId: event.chatroomId,
@@ -36994,8 +37040,244 @@ class AgentWorkManager {
36994
37040
  } catch (error51) {
36995
37041
  console.error(`[NativeDelivery:turn-ended-outbox-error] chatroom=${event.chatroomId} role=${event.role} error=${error51 instanceof Error ? error51.stack ?? error51.message : String(error51)}`);
36996
37042
  }
37043
+ }
37044
+ scheduleUncoveredAction(event, task, action, attempt = 0, delayMs = 0) {
37045
+ setTimeout(() => {
37046
+ if (this.disposed)
37047
+ return;
37048
+ const run = action === "nudge" ? this.sendUncoveredNudge(event, task, attempt) : this.restartSessionForUncoveredTask(event, task);
37049
+ run.catch((error51) => {
37050
+ console.error(`[NativeDelivery:uncovered-action-error] action=${action} chatroom=${event.chatroomId} role=${event.role} task=${task.taskId} error=${error51 instanceof Error ? error51.stack ?? error51.message : String(error51)}`);
37051
+ });
37052
+ }, delayMs);
37053
+ }
37054
+ async sendUncoveredNudge(event, task, attempt = 0) {
37055
+ const { chatroomId, role } = event;
37056
+ const sessionKey = sessionKeyFor(event.pid, event.slot.harnessSessionId);
37057
+ const deliveryState = getRoleDeliveryState();
37058
+ if (!deliveryState.tryAcquireDelivery(chatroomId, role)) {
37059
+ console.log(`[NativeDelivery:uncovered-nudge-skipped] chatroom=${chatroomId} role=${role} task=${task.taskId} reason=delivery_busy`);
37060
+ if (attempt + 1 < MAX_UNCOVERED_NUDGE_SEND_ATTEMPTS) {
37061
+ this.scheduleUncoveredAction(event, task, "nudge", attempt + 1, UNCOVERED_NUDGE_RETRY_MS);
37062
+ return;
37063
+ }
37064
+ await this.escalateUndeliverableNudge(event, task, sessionKey);
37065
+ return;
37066
+ }
37067
+ const generation = deliveryState.getGeneration(chatroomId, role);
37068
+ try {
37069
+ const skipReason = this.uncoveredNudgeSkipReason(event, task);
37070
+ if (skipReason) {
37071
+ console.log(`[NativeDelivery:uncovered-nudge-skipped] chatroom=${chatroomId} role=${role} task=${task.taskId} reason=${skipReason}`);
37072
+ return;
37073
+ }
37074
+ try {
37075
+ await exports_Effect.runPromise(this.deps.agentMgr.resumeTurnForSlot({
37076
+ chatroomId,
37077
+ role,
37078
+ prompt: buildUncoveredTurnNudgePrompt({ taskId: task.taskId })
37079
+ }));
37080
+ } catch (error51) {
37081
+ console.error(`[NativeDelivery:uncovered-nudge] chatroom=${chatroomId} role=${role} task=${task.taskId} error=${error51 instanceof Error ? error51.stack ?? error51.message : String(error51)}`);
37082
+ await this.escalateUndeliverableNudge(event, task, sessionKey);
37083
+ return;
37084
+ }
37085
+ this.deps.taskService.confirmNudgeSent({ chatroomId, role, taskId: task.taskId, sessionKey });
37086
+ } finally {
37087
+ deliveryState.releaseDelivery(chatroomId, role, generation);
37088
+ }
37089
+ }
37090
+ async escalateUndeliverableNudge(event, task, sessionKey) {
37091
+ const decision = await this.deps.taskService.decideUncoveredTurnEnd({
37092
+ chatroomId: event.chatroomId,
37093
+ role: event.role,
37094
+ taskId: task.taskId,
37095
+ sessionKey,
37096
+ nudgeUnavailable: true
37097
+ });
37098
+ if (decision.action === "restart-session") {
37099
+ this.scheduleUncoveredAction(event, task, "restart-session");
37100
+ } else {
37101
+ this.applyParkAction(event);
37102
+ }
37103
+ }
37104
+ async restartSessionForUncoveredTask(event, task) {
37105
+ const { chatroomId, role, pid } = event;
37106
+ const config3 = this.deps.configurationService.get(chatroomId, role);
37107
+ const slot = this.deps.agentMgr.getSlot(chatroomId, role);
37108
+ const harness = config3?.agentHarness ?? slot?.harness;
37109
+ const model = config3?.model ?? slot?.model;
37110
+ const workingDir = config3?.workingDir ?? slot?.workingDir;
37111
+ if (!harness || !model || !workingDir) {
37112
+ console.error(`[NativeDelivery:uncovered-restart-failed] chatroom=${chatroomId} role=${role} task=${task.taskId} error=missing_agent_config`);
37113
+ const sessionKey = sessionKeyFor(event.pid, event.slot.harnessSessionId);
37114
+ await this.deps.taskService.decideUncoveredTurnEnd({
37115
+ chatroomId,
37116
+ role,
37117
+ taskId: task.taskId,
37118
+ sessionKey,
37119
+ nudgeUnavailable: true
37120
+ });
37121
+ this.applyParkAction(event);
37122
+ return;
37123
+ }
37124
+ const startInput = {
37125
+ chatroomId,
37126
+ role,
37127
+ agentHarness: harness,
37128
+ model,
37129
+ workingDir,
37130
+ reason: DaemonStartReasonCode.RESPAWN,
37131
+ wantResume: false
37132
+ };
37133
+ let outcome;
37134
+ try {
37135
+ outcome = await this.deps.runSerializedForAgent({ chatroomId, role, workingDir }, { timeoutMs: AGENT_LIFECYCLE_OPERATION_TIMEOUT_MS }, async (ops, context3) => {
37136
+ const current = this.deps.agentMgr.getSlot(chatroomId, role);
37137
+ if (this.deps.agentMgr.isStopRequested(chatroomId, role) || current?.pid !== pid || current?.harnessSessionId !== event.slot.harnessSessionId) {
37138
+ console.log(`[NativeDelivery:uncovered-restart-stale] chatroom=${chatroomId} role=${role} task=${task.taskId}`);
37139
+ return { kind: "skipped", reason: "stale_slot" };
37140
+ }
37141
+ await this.prepareRoleRecovery({ chatroomId, role });
37142
+ await ops.stopAgent({ chatroomId, role, reason: AgentStopReasonEnum["daemon.respawn"], pid, workingDir }, context3.signal);
37143
+ await this.recoverStoppedRole({ chatroomId, role, mode: "automatic" });
37144
+ return this.attemptRespawnStart(ops, startInput, context3.signal);
37145
+ });
37146
+ } catch (error51) {
37147
+ const message = error51 instanceof Error ? error51.message : String(error51);
37148
+ console.error(`[NativeDelivery:uncovered-restart-failed] chatroom=${chatroomId} role=${role} task=${task.taskId} error=${message}`);
37149
+ if (this.recoveryGates.has(recoveryKey(chatroomId, role))) {
37150
+ this.scheduleRecoveryRetry(chatroomId, role);
37151
+ }
37152
+ return;
37153
+ }
37154
+ if (outcome.kind === "start-failed") {
37155
+ console.error(`[NativeDelivery:uncovered-restart-failed] chatroom=${chatroomId} role=${role} task=${task.taskId} attempt=1 of ${MAX_RESPAWN_START_ATTEMPTS} error=${outcome.error}`);
37156
+ this.beginRespawnStartRetries({ chatroomId, role, workingDir, startInput });
37157
+ }
37158
+ }
37159
+ async attemptRespawnStart(ops, startInput, signal) {
37160
+ try {
37161
+ const started = await ops.startAgent(startInput, signal);
37162
+ return started.success ? { kind: "started" } : { kind: "start-failed", error: started.error ?? "start_rejected" };
37163
+ } catch (error51) {
37164
+ return {
37165
+ kind: "start-failed",
37166
+ error: error51 instanceof Error ? error51.message : String(error51)
37167
+ };
37168
+ }
37169
+ }
37170
+ beginRespawnStartRetries(request3) {
37171
+ if (this.disposed)
37172
+ return;
37173
+ const key = recoveryKey(request3.chatroomId, request3.role);
37174
+ this.cancelRespawnStart(key, "superseded_by_new_restart");
37175
+ this.respawnRestartSeq += 1;
37176
+ const pending = {
37177
+ restartId: this.respawnRestartSeq,
37178
+ request: request3,
37179
+ attempts: 1
37180
+ };
37181
+ this.respawnStartRetries.set(key, pending);
37182
+ this.armRespawnStartRetry(key, pending);
37183
+ }
37184
+ armRespawnStartRetry(key, pending) {
37185
+ if (this.disposed)
37186
+ return;
37187
+ const delay3 = Math.min(30000, 1000 * 2 ** (pending.attempts - 1));
37188
+ pending.timer = setTimeout(() => {
37189
+ pending.timer = undefined;
37190
+ this.retryRespawnStart(key, pending.restartId).catch((error51) => {
37191
+ console.error(`[NativeDelivery:uncovered-restart-error] chatroom=${pending.request.chatroomId} role=${pending.request.role} error=${error51 instanceof Error ? error51.stack ?? error51.message : String(error51)}`);
37192
+ });
37193
+ }, delay3);
37194
+ }
37195
+ async retryRespawnStart(key, restartId) {
37196
+ const pending = this.respawnStartRetries.get(key);
37197
+ if (!pending || pending.restartId !== restartId || this.disposed)
37198
+ return;
37199
+ const { chatroomId, role, workingDir, startInput } = pending.request;
37200
+ if (this.deps.agentMgr.isStopRequested(chatroomId, role)) {
37201
+ this.cancelRespawnStart(key, "stop_requested");
37202
+ return;
37203
+ }
37204
+ const slot = this.deps.agentMgr.getSlot(chatroomId, role);
37205
+ if (slot && isSlotRunning(slot.state)) {
37206
+ this.cancelRespawnStart(key, "agent_already_running");
37207
+ return;
37208
+ }
37209
+ const outcome = await this.deps.runSerializedForAgent({ chatroomId, role, workingDir }, { timeoutMs: AGENT_LIFECYCLE_OPERATION_TIMEOUT_MS }, async (ops, context3) => {
37210
+ if (this.respawnStartRetries.get(key)?.restartId !== restartId) {
37211
+ return { kind: "skipped", reason: "superseded" };
37212
+ }
37213
+ if (this.deps.agentMgr.isStopRequested(chatroomId, role)) {
37214
+ return { kind: "skipped", reason: "stop_requested" };
37215
+ }
37216
+ const current2 = this.deps.agentMgr.getSlot(chatroomId, role);
37217
+ if (current2 && isSlotRunning(current2.state)) {
37218
+ return { kind: "skipped", reason: "agent_already_running" };
37219
+ }
37220
+ return this.attemptRespawnStart(ops, startInput, context3.signal);
37221
+ });
37222
+ if (outcome.kind === "skipped") {
37223
+ this.cancelRespawnStart(key, outcome.reason);
37224
+ return;
37225
+ }
37226
+ const current = this.respawnStartRetries.get(key);
37227
+ if (current?.restartId !== restartId)
37228
+ return;
37229
+ if (outcome.kind === "started") {
37230
+ this.cancelRespawnStart(key, "started");
37231
+ return;
37232
+ }
37233
+ current.attempts += 1;
37234
+ if (current.attempts >= MAX_RESPAWN_START_ATTEMPTS) {
37235
+ this.respawnStartRetries.delete(key);
37236
+ console.error(`[NativeDelivery:uncovered-restart-failed] attempts exhausted chatroom=${chatroomId} role=${role} attempts=${current.attempts} error=${outcome.error}`);
37237
+ return;
37238
+ }
37239
+ console.error(`[NativeDelivery:uncovered-restart-failed] chatroom=${chatroomId} role=${role} attempt=${current.attempts} of ${MAX_RESPAWN_START_ATTEMPTS} error=${outcome.error}`);
37240
+ this.armRespawnStartRetry(key, current);
37241
+ }
37242
+ cancelRespawnStart(key, reason) {
37243
+ const pending = this.respawnStartRetries.get(key);
37244
+ if (!pending)
37245
+ return;
37246
+ if (pending.timer)
37247
+ clearTimeout(pending.timer);
37248
+ pending.timer = undefined;
37249
+ this.respawnStartRetries.delete(key);
37250
+ if (reason === "started")
37251
+ return;
37252
+ console.log(`[NativeDelivery:uncovered-restart-cancelled] chatroom=${pending.request.chatroomId} role=${pending.request.role} attempts=${pending.attempts} reason=${reason}`);
37253
+ }
37254
+ uncoveredNudgeSkipReason(event, task) {
37255
+ const { chatroomId, role } = event;
37256
+ const slot = this.deps.agentMgr.getSlot(chatroomId, role);
37257
+ if (!slot || !isSlotRunning(slot.state))
37258
+ return "slot_not_running";
37259
+ if (slot.pid !== event.pid)
37260
+ return "pid_changed";
37261
+ if (slot.harnessSessionId !== event.slot.harnessSessionId)
37262
+ return "session_changed";
37263
+ if (!isTurnPhaseIdle(slot.nativeTurnPhase ?? "idle"))
37264
+ return "turn_not_idle";
37265
+ if (this.deps.agentMgr.isStopRequested(chatroomId, role))
37266
+ return "stop_requested";
37267
+ if (this.recoveryGates.has(recoveryKey(chatroomId, role)))
37268
+ return "recovery_in_progress";
37269
+ if (this.deps.agentTaskState.get({ chatroomId, role })?.taskId !== task.taskId) {
37270
+ return "task_not_active";
37271
+ }
37272
+ const current = this.deps.taskInboxState.getForRole(chatroomId, role, task.taskId);
37273
+ if (!current || !ACTIVE_TASK_STATUSES.includes(current.status)) {
37274
+ return "task_not_in_inbox";
37275
+ }
37276
+ return;
37277
+ }
37278
+ applyParkAction(event) {
37279
+ this.deps.agentTaskState.clear({ chatroomId: event.chatroomId, role: event.role });
36997
37280
  this.scheduleRoleDelivery(event.chatroomId, event.role);
36998
- return { kind: "release-slot" };
36999
37281
  }
37000
37282
  scheduleRoleDelivery(chatroomId, role) {
37001
37283
  setTimeout(() => {
@@ -37006,6 +37288,12 @@ class AgentWorkManager {
37006
37288
  }
37007
37289
  dispose() {
37008
37290
  this.disposed = true;
37291
+ for (const pending of this.respawnStartRetries.values()) {
37292
+ if (pending.timer)
37293
+ clearTimeout(pending.timer);
37294
+ pending.timer = undefined;
37295
+ }
37296
+ this.respawnStartRetries.clear();
37009
37297
  for (const gate of this.recoveryGates.values()) {
37010
37298
  if (gate.retryTimer)
37011
37299
  clearTimeout(gate.retryTimer);
@@ -37217,13 +37505,16 @@ class AgentWorkManager {
37217
37505
  this.deps.agentTaskState.start(args2);
37218
37506
  }
37219
37507
  }
37220
- var recoveryKey = (chatroomId, role) => `${chatroomId}:${role.toLowerCase()}`;
37508
+ var MAX_RESPAWN_START_ATTEMPTS = 3, MAX_UNCOVERED_NUDGE_SEND_ATTEMPTS = 3, UNCOVERED_NUDGE_RETRY_MS = 250, recoveryKey = (chatroomId, role) => `${chatroomId}:${role.toLowerCase()}`, sessionKeyFor = (pid, harnessSessionId) => `${pid}:${harnessSessionId ?? "none"}`;
37221
37509
  var init_agent_work_manager = __esm(() => {
37510
+ init_reliability();
37222
37511
  init_agent();
37223
37512
  init_chatroom_workspace_task_inbox();
37224
37513
  init_dist();
37225
37514
  init_agent_lifecycle_fact();
37226
37515
  init_agent_slot();
37516
+ init_assigned_task();
37517
+ init_check_agent_slot();
37227
37518
  init_native_task_injector_logic();
37228
37519
  init_convex_native_task_delivery_gateway();
37229
37520
  init_daemon_audit_port();
@@ -40322,6 +40613,27 @@ class TaskInboxState {
40322
40613
  }
40323
40614
  }
40324
40615
 
40616
+ // src/daemon/services/task-service/domain/usecase/uncovered-turn-ladder.ts
40617
+ function decideUncoveredTurnEnd(entry, sessionKey, opts = {}) {
40618
+ const current = entry ?? FRESH_ENTRY;
40619
+ if (isNudgeDue(current, sessionKey, opts))
40620
+ return { action: "nudge" };
40621
+ return current.sessionRestarts < MAX_SESSION_RESTARTS_PER_TASK ? { action: "restart-session" } : { action: "park" };
40622
+ }
40623
+ function isNudgeDue(entry, sessionKey, opts) {
40624
+ return !opts.nudgeUnavailable && entry.nudgedSessionKey !== sessionKey;
40625
+ }
40626
+ function withNudgeSent(entry, sessionKey) {
40627
+ return { nudgedSessionKey: sessionKey, sessionRestarts: entry?.sessionRestarts ?? 0 };
40628
+ }
40629
+ function withSessionRestart(entry) {
40630
+ return { nudgedSessionKey: undefined, sessionRestarts: (entry?.sessionRestarts ?? 0) + 1 };
40631
+ }
40632
+ var MAX_SESSION_RESTARTS_PER_TASK = 1, FRESH_ENTRY;
40633
+ var init_uncovered_turn_ladder = __esm(() => {
40634
+ FRESH_ENTRY = { sessionRestarts: 0 };
40635
+ });
40636
+
40325
40637
  // src/daemon/services/task-service/service/task-service.ts
40326
40638
  function createTaskService(deps) {
40327
40639
  const gateway = createConvexNativeTaskDeliveryGateway(deps.backend);
@@ -40339,18 +40651,13 @@ function createTaskService(deps) {
40339
40651
  let bootstrapRecoveryAttempts = 0;
40340
40652
  let bootstrapRecoveryTimer;
40341
40653
  let bootstrapRecoveryPromise;
40342
- const REDIVERY_ATTEMPT_CAP = 3;
40343
- const turnEndAttemptCounts = new Map;
40654
+ const TURN_FAILURE_RETRY_CAP = 3;
40655
+ const turnFailureCounts = new Map;
40656
+ const uncoveredLadder = new Map;
40344
40657
  const redeliveryExhaustedKeys = new Set;
40345
40658
  const redeliveryKey = (chatroomId, role, taskId) => `${chatroomId}:${role.toLowerCase()}:${taskId}`;
40346
- const recordUncoveredTurnEnd = async (args2) => {
40659
+ const parkTask = async (args2, attempts) => {
40347
40660
  const key = redeliveryKey(args2.chatroomId, args2.role, args2.taskId);
40348
- if (redeliveryExhaustedKeys.has(key))
40349
- return { exceeded: true };
40350
- const attempts = (turnEndAttemptCounts.get(key) ?? 0) + 1;
40351
- turnEndAttemptCounts.set(key, attempts);
40352
- if (attempts < REDIVERY_ATTEMPT_CAP)
40353
- return { exceeded: false };
40354
40661
  redeliveryExhaustedKeys.add(key);
40355
40662
  try {
40356
40663
  await gateway.recordDeliveryFailure({
@@ -40362,13 +40669,50 @@ function createTaskService(deps) {
40362
40669
  } catch (error51) {
40363
40670
  console.warn(`[TaskService] redelivery-exhausted failure record failed chatroom=${args2.chatroomId} role=${args2.role} task=${args2.taskId}: ${error51 instanceof Error ? error51.message : String(error51)}`);
40364
40671
  }
40365
- console.log(`[NativeDelivery:redelivery-exhausted] chatroom=${args2.chatroomId} role=${args2.role} task=${args2.taskId} attempts=${attempts} — release/redelivery stopped; agent restart (user.start) resets`);
40672
+ const attemptsSuffix = attempts === undefined ? "" : ` attempts=${attempts}`;
40673
+ console.log(`[NativeDelivery:redelivery-exhausted] chatroom=${args2.chatroomId} role=${args2.role} task=${args2.taskId}${attemptsSuffix} — release/redelivery stopped; agent restart (user.start) resets`);
40674
+ };
40675
+ const recordTurnFailure = async (args2) => {
40676
+ const key = redeliveryKey(args2.chatroomId, args2.role, args2.taskId);
40677
+ if (redeliveryExhaustedKeys.has(key))
40678
+ return { exceeded: true };
40679
+ const attempts = (turnFailureCounts.get(key) ?? 0) + 1;
40680
+ turnFailureCounts.set(key, attempts);
40681
+ if (attempts < TURN_FAILURE_RETRY_CAP)
40682
+ return { exceeded: false };
40683
+ await parkTask(args2, attempts);
40366
40684
  return { exceeded: true };
40367
40685
  };
40686
+ const decideUncoveredTurnEnd2 = async (args2) => {
40687
+ const key = redeliveryKey(args2.chatroomId, args2.role, args2.taskId);
40688
+ if (redeliveryExhaustedKeys.has(key))
40689
+ return { action: "park" };
40690
+ turnFailureCounts.delete(key);
40691
+ const entry = uncoveredLadder.get(key);
40692
+ const decision = decideUncoveredTurnEnd(entry, args2.sessionKey, {
40693
+ nudgeUnavailable: args2.nudgeUnavailable ?? false
40694
+ });
40695
+ if (decision.action === "restart-session") {
40696
+ uncoveredLadder.set(key, withSessionRestart(entry));
40697
+ } else if (decision.action === "park") {
40698
+ await parkTask(args2);
40699
+ }
40700
+ return decision;
40701
+ };
40702
+ const confirmNudgeSent = (args2) => {
40703
+ const key = redeliveryKey(args2.chatroomId, args2.role, args2.taskId);
40704
+ uncoveredLadder.set(key, withNudgeSent(uncoveredLadder.get(key), args2.sessionKey));
40705
+ };
40706
+ const resetTurnTracking = (args2) => {
40707
+ const key = redeliveryKey(args2.chatroomId, args2.role, args2.taskId);
40708
+ turnFailureCounts.delete(key);
40709
+ uncoveredLadder.delete(key);
40710
+ };
40368
40711
  const isRedeliveryExhausted = (args2) => redeliveryExhaustedKeys.has(redeliveryKey(args2.chatroomId, args2.role, args2.taskId));
40369
40712
  const clearRedeliveryTrackingForTask = (chatroomId, role, taskId) => {
40370
40713
  const key = redeliveryKey(chatroomId, role, taskId);
40371
- turnEndAttemptCounts.delete(key);
40714
+ turnFailureCounts.delete(key);
40715
+ uncoveredLadder.delete(key);
40372
40716
  redeliveryExhaustedKeys.delete(key);
40373
40717
  };
40374
40718
  const forgetStaleTask = ({
@@ -40398,9 +40742,13 @@ function createTaskService(deps) {
40398
40742
  };
40399
40743
  const clearRoleRedeliveryTracking = (chatroomId, role) => {
40400
40744
  const prefix = `${chatroomId}:${role.toLowerCase()}:`;
40401
- for (const key of [...turnEndAttemptCounts.keys()]) {
40745
+ for (const key of [...turnFailureCounts.keys()]) {
40402
40746
  if (key.startsWith(prefix))
40403
- turnEndAttemptCounts.delete(key);
40747
+ turnFailureCounts.delete(key);
40748
+ }
40749
+ for (const key of [...uncoveredLadder.keys()]) {
40750
+ if (key.startsWith(prefix))
40751
+ uncoveredLadder.delete(key);
40404
40752
  }
40405
40753
  for (const key of [...redeliveryExhaustedKeys]) {
40406
40754
  if (key.startsWith(prefix))
@@ -40802,7 +41150,10 @@ function createTaskService(deps) {
40802
41150
  taskId,
40803
41151
  ...expectedReason ? { expectedReason } : {}
40804
41152
  }),
40805
- recordUncoveredTurnEnd,
41153
+ recordTurnFailure,
41154
+ decideUncoveredTurnEnd: decideUncoveredTurnEnd2,
41155
+ confirmNudgeSent,
41156
+ resetTurnTracking,
40806
41157
  isRedeliveryExhausted,
40807
41158
  clearRedeliveryTracking: ({ chatroomId, role }) => {
40808
41159
  clearRoleRedeliveryTracking(chatroomId, role);
@@ -40817,6 +41168,7 @@ var init_task_service = __esm(() => {
40817
41168
  init_task_inbox_acknowledgement_retry_watcher();
40818
41169
  init_task_inbox_delivery_retry_watcher();
40819
41170
  init_api3();
41171
+ init_uncovered_turn_ladder();
40820
41172
  init_convex_native_task_delivery_gateway();
40821
41173
  });
40822
41174
 
@@ -48728,6 +49080,14 @@ var init_pi_sdk_package = __esm(() => {
48728
49080
  };
48729
49081
  });
48730
49082
 
49083
+ // src/daemon/infrastructure/local/harness/services/pi-sdk/assistant-error.ts
49084
+ function assistantErrorOf(event) {
49085
+ if (event.message.role !== "assistant" || event.message.stopReason !== "error")
49086
+ return;
49087
+ return event.message.errorMessage ?? UNKNOWN_PROVIDER_ERROR;
49088
+ }
49089
+ var UNKNOWN_PROVIDER_ERROR = "unknown provider error";
49090
+
48731
49091
  // src/daemon/infrastructure/local/harness/services/pi-sdk/pi-sdk-stream-adapter.ts
48732
49092
  var PiSdkStreamAdapter;
48733
49093
  var init_pi_sdk_stream_adapter = __esm(() => {
@@ -48735,6 +49095,7 @@ var init_pi_sdk_stream_adapter = __esm(() => {
48735
49095
  PiSdkStreamAdapter = class PiSdkStreamAdapter extends NativeStreamAdapterBase {
48736
49096
  textBuffer = "";
48737
49097
  thinkingBuffer = "";
49098
+ lastAssistantError;
48738
49099
  constructor(logPrefix, emitLogLine, activityEmitter) {
48739
49100
  super(logPrefix, emitLogLine, activityEmitter);
48740
49101
  }
@@ -48774,17 +49135,43 @@ var init_pi_sdk_stream_adapter = __esm(() => {
48774
49135
  this.writeLine(formatAgentLogLine(this.logPrefix, "tool_result", `${event.toolName} result: ${resultStr}`));
48775
49136
  break;
48776
49137
  }
49138
+ case "message_end":
49139
+ this.recordAssistantOutcome(event);
49140
+ break;
48777
49141
  case "agent_end":
48778
- this.completeTurn({ status: "completed", source: "pi-sdk.agent_end" });
49142
+ if (event.willRetry)
49143
+ break;
49144
+ this.settleRun("pi-sdk.agent_end");
48779
49145
  break;
48780
49146
  default:
48781
49147
  break;
48782
49148
  }
48783
49149
  }
49150
+ recordAssistantOutcome(event) {
49151
+ const message = event.message;
49152
+ if (message.role !== "assistant")
49153
+ return;
49154
+ this.lastAssistantError = assistantErrorOf(event);
49155
+ if (this.lastAssistantError === undefined)
49156
+ return;
49157
+ this.writeLine(formatAgentLogLine(this.logPrefix, "run-error", `assistant error: ${this.lastAssistantError}`));
49158
+ }
49159
+ settleResolvedPrompt() {
49160
+ this.settleRun("pi-sdk.prompt.resolved");
49161
+ }
48784
49162
  finish() {
48785
49163
  this.flushText();
48786
49164
  this.flushThinking();
48787
49165
  }
49166
+ settleRun(source) {
49167
+ if (this.lastAssistantError !== undefined) {
49168
+ const error51 = this.lastAssistantError;
49169
+ if (this.completeTurn({ status: "failed", source, error: error51 }))
49170
+ this.notifyFailure(source);
49171
+ } else {
49172
+ this.completeTurn({ status: "completed", source });
49173
+ }
49174
+ }
48788
49175
  appendText(delta) {
48789
49176
  this.flushThinking();
48790
49177
  this.textBuffer += delta;
@@ -48876,9 +49263,13 @@ function waitForResumeOrAbort4(session2) {
48876
49263
  })
48877
49264
  ]);
48878
49265
  }
48879
- function resolveRequiredModel(modelRegistry, model) {
49266
+ async function createModelRuntime() {
49267
+ const sdk = await loadSdk4();
49268
+ return sdk.ModelRuntime.create();
49269
+ }
49270
+ function resolveRequiredModel(modelRuntime, model) {
48880
49271
  const slash = model.indexOf("/");
48881
- const resolved = slash === -1 ? modelRegistry.getAll().find((entry) => entry.id === model) : modelRegistry.find(model.slice(0, slash), model.slice(slash + 1));
49272
+ const resolved = slash === -1 ? modelRuntime.getModels().find((entry) => entry.id === model) : modelRuntime.getModel(model.slice(0, slash), model.slice(slash + 1));
48882
49273
  if (!resolved) {
48883
49274
  throw new Error(`Pi model not found: ${model}`);
48884
49275
  }
@@ -48912,10 +49303,8 @@ var init_pi_sdk_agent_service = __esm(() => {
48912
49303
  }
48913
49304
  async isInstalled() {
48914
49305
  try {
48915
- const { ModelRegistry, AuthStorage } = await loadSdk4();
48916
- const authStorage = AuthStorage.create();
48917
- const modelRegistry = ModelRegistry.create(authStorage);
48918
- return modelRegistry.getAvailable().length > 0;
49306
+ const modelRuntime = await createModelRuntime();
49307
+ return (await modelRuntime.getAvailable()).length > 0;
48919
49308
  } catch (err) {
48920
49309
  console.warn(`[pi-sdk] unavailable: ${formatPiSdkLoadError(err)}`);
48921
49310
  return false;
@@ -48938,26 +49327,16 @@ var init_pi_sdk_agent_service = __esm(() => {
48938
49327
  }
48939
49328
  async listModels() {
48940
49329
  try {
48941
- const { ModelRegistry, AuthStorage } = await loadSdk4();
48942
- const authStorage = AuthStorage.create();
48943
- const modelRegistry = ModelRegistry.create(authStorage);
48944
- return modelRegistry.getAvailable().map((entry) => `${entry.provider}/${entry.id}`);
49330
+ const modelRuntime = await createModelRuntime();
49331
+ return (await modelRuntime.getAvailable()).map((entry) => `${entry.provider}/${entry.id}`);
48945
49332
  } catch (err) {
48946
49333
  console.warn(`[pi-sdk] listModels failed:`, err instanceof Error ? err.message : err);
48947
49334
  return [];
48948
49335
  }
48949
49336
  }
48950
49337
  async openResumedSession(args2) {
48951
- const {
48952
- AuthStorage,
48953
- createAgentSession,
48954
- DefaultResourceLoader,
48955
- getAgentDir,
48956
- ModelRegistry,
48957
- SessionManager
48958
- } = await loadSdk4();
48959
- const authStorage = AuthStorage.create();
48960
- const modelRegistry = ModelRegistry.create(authStorage);
49338
+ const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await loadSdk4();
49339
+ const modelRuntime = await createModelRuntime();
48961
49340
  const sessions = await SessionManager.list(args2.workingDir, getPiSessionDir(args2.workingDir));
48962
49341
  const match5 = sessions.find((s) => s.id === args2.harnessSessionId);
48963
49342
  if (!match5) {
@@ -48972,8 +49351,7 @@ var init_pi_sdk_agent_service = __esm(() => {
48972
49351
  const { session: session2 } = await withTimeout(createAgentSession({
48973
49352
  cwd: args2.workingDir,
48974
49353
  sessionManager: SessionManager.open(match5.path, getPiSessionDir(args2.workingDir)),
48975
- authStorage,
48976
- modelRegistry,
49354
+ modelRuntime,
48977
49355
  resourceLoader
48978
49356
  }), SESSION_CREATE_TIMEOUT_MS2, "createAgentSession");
48979
49357
  return session2;
@@ -49027,19 +49405,11 @@ var init_pi_sdk_agent_service = __esm(() => {
49027
49405
  return keeper;
49028
49406
  }
49029
49407
  async createSession(args2) {
49030
- const {
49031
- AuthStorage,
49032
- createAgentSession,
49033
- DefaultResourceLoader,
49034
- getAgentDir,
49035
- ModelRegistry,
49036
- SessionManager
49037
- } = await loadSdk4();
49038
- const authStorage = AuthStorage.create();
49039
- const modelRegistry = ModelRegistry.create(authStorage);
49408
+ const { createAgentSession, DefaultResourceLoader, getAgentDir, SessionManager } = await loadSdk4();
49409
+ const modelRuntime = await createModelRuntime();
49040
49410
  const model = requireHarnessModel(args2.model, "pi-sdk spawn");
49041
49411
  const parsed = parsePiSpawnModel(model);
49042
- const resolvedModel = resolveRequiredModel(modelRegistry, parsed.model ?? model);
49412
+ const resolvedModel = resolveRequiredModel(modelRuntime, parsed.model ?? model);
49043
49413
  const thinkingLevel = resolvePiThinkingLevel(parsed?.thinking);
49044
49414
  const agentDir = getAgentDir();
49045
49415
  const resourceLoader = new DefaultResourceLoader({
@@ -49053,8 +49423,7 @@ var init_pi_sdk_agent_service = __esm(() => {
49053
49423
  model: resolvedModel,
49054
49424
  ...thinkingLevel ? { thinkingLevel } : {},
49055
49425
  sessionManager: SessionManager.create(getPiSessionDir(args2.workingDir)),
49056
- authStorage,
49057
- modelRegistry,
49426
+ modelRuntime,
49058
49427
  resourceLoader
49059
49428
  }), SESSION_CREATE_TIMEOUT_MS2, "createAgentSession");
49060
49429
  return session2;
@@ -49201,9 +49570,7 @@ ${deferredResume}` : deferredResume;
49201
49570
  exitSignal = "SIGTERM";
49202
49571
  break;
49203
49572
  }
49204
- if (!adapter.turnCompletion.isComplete) {
49205
- adapter.completeTurn({ status: "completed", source: "pi-sdk.prompt.resolved" });
49206
- }
49573
+ adapter.settleResolvedPrompt();
49207
49574
  adapter.finish();
49208
49575
  nextPrompt = null;
49209
49576
  } catch (turnErr) {
@@ -122973,6 +123340,7 @@ class PiSdkSession {
122973
123340
  listeners = new Set;
122974
123341
  closed = false;
122975
123342
  unsubscribe;
123343
+ lastAssistantError;
122976
123344
  constructor(options) {
122977
123345
  this.session = options.session;
122978
123346
  this.opencodeSessionId = options.opencodeSessionId;
@@ -122988,14 +123356,21 @@ class PiSdkSession {
122988
123356
  const text = input.parts.map((p) => p.text).join(`
122989
123357
  `);
122990
123358
  const messageId = randomUUID14();
123359
+ this.lastAssistantError = undefined;
122991
123360
  const onSessionEvent = (event) => {
122992
123361
  if (this.closed)
122993
123362
  return;
123363
+ if (event.type === "message_end" && event.message.role === "assistant") {
123364
+ this.lastAssistantError = assistantErrorOf(event);
123365
+ }
122994
123366
  this.emitFromPiEvent(event, messageId);
122995
123367
  };
122996
123368
  this.unsubscribe?.();
122997
123369
  this.unsubscribe = this.session.subscribe(onSessionEvent);
122998
123370
  await withTimeout(this.session.prompt(text), PROMPT_TIMEOUT_MS3, "session.prompt");
123371
+ if (this.lastAssistantError !== undefined) {
123372
+ throw new Error(this.lastAssistantError);
123373
+ }
122999
123374
  this.emit({ type: "session.idle", payload: {}, timestamp: Date.now() });
123000
123375
  }
123001
123376
  onEvent(listener) {
@@ -123060,9 +123435,9 @@ async function loadSdk7() {
123060
123435
  throw err;
123061
123436
  }
123062
123437
  }
123063
- function resolveRequiredModel2(modelRegistry, model) {
123438
+ function resolveRequiredModel2(modelRuntime, model) {
123064
123439
  const slash = model.indexOf("/");
123065
- const resolved = slash === -1 ? modelRegistry.getAll().find((entry) => entry.id === model) : modelRegistry.find(model.slice(0, slash), model.slice(slash + 1));
123440
+ const resolved = slash === -1 ? modelRuntime.getModels().find((entry) => entry.id === model) : modelRuntime.getModel(model.slice(0, slash), model.slice(slash + 1));
123066
123441
  if (!resolved) {
123067
123442
  throw new Error(`Pi model not found: ${model}`);
123068
123443
  }
@@ -123075,15 +123450,13 @@ class PiSdkHarness {
123075
123450
  cwd;
123076
123451
  closed = false;
123077
123452
  sessions = new Map;
123078
- modelRegistry;
123079
- authStorage;
123080
- constructor(cwd, modelRegistry, authStorage) {
123453
+ modelRuntime;
123454
+ constructor(cwd, modelRuntime) {
123081
123455
  this.cwd = cwd;
123082
- this.modelRegistry = modelRegistry;
123083
- this.authStorage = authStorage;
123456
+ this.modelRuntime = modelRuntime;
123084
123457
  }
123085
123458
  async models() {
123086
- return this.modelRegistry.getAvailable().map((entry) => ({
123459
+ return (await this.modelRuntime.getAvailable()).map((entry) => ({
123087
123460
  id: `${entry.provider}/${entry.id}`,
123088
123461
  name: entry.id,
123089
123462
  provider: entry.provider
@@ -123094,7 +123467,7 @@ class PiSdkHarness {
123094
123467
  }
123095
123468
  async listProviders() {
123096
123469
  const byProvider = new Map;
123097
- for (const entry of this.modelRegistry.getAvailable()) {
123470
+ for (const entry of await this.modelRuntime.getAvailable()) {
123098
123471
  const models = byProvider.get(entry.provider) ?? [];
123099
123472
  models.push({ modelID: entry.id, name: entry.id });
123100
123473
  byProvider.set(entry.provider, models);
@@ -123170,7 +123543,7 @@ class PiSdkHarness {
123170
123543
  const { createAgentSession, DefaultResourceLoader, getAgentDir } = await loadSdk7();
123171
123544
  const parsed = args2.model ? parsePiSpawnModel(args2.model) : undefined;
123172
123545
  const modelSlug = parsed?.model ?? args2.model;
123173
- const resolvedModel = args2.requireModel ? resolveRequiredModel2(this.modelRegistry, requireHarnessModel(modelSlug, "pi-sdk openAgentSession")) : modelSlug ? resolveRequiredModel2(this.modelRegistry, modelSlug) : undefined;
123546
+ const resolvedModel = args2.requireModel ? resolveRequiredModel2(this.modelRuntime, requireHarnessModel(modelSlug, "pi-sdk openAgentSession")) : modelSlug ? resolveRequiredModel2(this.modelRuntime, modelSlug) : undefined;
123174
123547
  const thinkingLevel = resolvePiThinkingLevel(parsed?.thinking);
123175
123548
  if (args2.requireModel && !resolvedModel) {
123176
123549
  throw new Error("No Pi model available — configure provider credentials in ~/.pi/agent/auth.json");
@@ -123184,8 +123557,7 @@ class PiSdkHarness {
123184
123557
  const { session: session2 } = await withTimeout(createAgentSession({
123185
123558
  cwd: this.cwd,
123186
123559
  sessionManager: args2.sessionManager,
123187
- authStorage: this.authStorage,
123188
- modelRegistry: this.modelRegistry,
123560
+ modelRuntime: this.modelRuntime,
123189
123561
  resourceLoader,
123190
123562
  ...resolvedModel ? { model: resolvedModel } : {},
123191
123563
  ...thinkingLevel ? { thinkingLevel } : {}
@@ -123195,13 +123567,12 @@ class PiSdkHarness {
123195
123567
  }
123196
123568
  var SESSION_CREATE_TIMEOUT_MS3 = 60000, _sdkCache7, _sdkLoadError7, startPiSdkHarness = async (config4) => {
123197
123569
  try {
123198
- const { AuthStorage, ModelRegistry } = await loadSdk7();
123199
- const authStorage = AuthStorage.create();
123200
- const modelRegistry = ModelRegistry.create(authStorage);
123201
- if (modelRegistry.getAvailable().length === 0) {
123570
+ const sdk = await loadSdk7();
123571
+ const modelRuntime = await sdk.ModelRuntime.create();
123572
+ if ((await modelRuntime.getAvailable()).length === 0) {
123202
123573
  throw new Error("No Pi models available");
123203
123574
  }
123204
- return new PiSdkHarness(config4.workingDir, modelRegistry, authStorage);
123575
+ return new PiSdkHarness(config4.workingDir, modelRuntime);
123205
123576
  } catch (err) {
123206
123577
  throw new Error(`pi-sdk unavailable: ${formatPiSdkLoadError(err)}`);
123207
123578
  }
@@ -137899,4 +138270,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
137899
138270
  });
137900
138271
  program2.parse();
137901
138272
 
137902
- //# debugId=E3A1D1E6D6D8AB0C64756E2164756E21
138273
+ //# debugId=7C84BEF97B16C1D064756E2164756E21