larkin 0.5.2 → 0.5.4

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.
@@ -57,6 +57,7 @@ const host_channel_business_js_1 = require("./host-channel-business.cjs");
57
57
  const interaction_orchestrator_js_1 = require("./interaction-orchestrator.cjs");
58
58
  const message_policy_js_1 = require("./message-policy.cjs");
59
59
  const runtime_readiness_js_1 = require("../runtime/runtime-readiness.cjs");
60
+ const provider_error_classifier_js_1 = require("../runtime/provider-error-classifier.cjs");
60
61
  const callback_capability_js_1 = require("../platform/callback-capability.cjs");
61
62
  const config_js_1 = require("../platform/config.cjs");
62
63
  const internal_command_js_1 = require("../app/internal-command.cjs");
@@ -119,6 +120,9 @@ function memberNamesFromPayloads(payloads) {
119
120
  return names;
120
121
  }
121
122
  function errorMessage(error) { return error instanceof Error ? error.message : String(error); }
123
+ function safeRuntimeStatusDiagnostic(error) {
124
+ return (0, provider_error_classifier_js_1.safeProviderDiagnostic)(error, "Runtime entered an error state", 500);
125
+ }
122
126
  function agentConfigSignature(agent) {
123
127
  return JSON.stringify({
124
128
  agentId: agent.agentId, runtime: agent.runtime, model: agent.model, effort: agent.effort ?? null,
@@ -233,17 +237,40 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
233
237
  }
234
238
  hostState.updateStatus(agent, { runtimeReadiness: { runtime: agent.runtime, state: "ready", observedAt } });
235
239
  };
240
+ const projectFallbackRuntimeReadiness = (agent, observedAt, fallback, preserveCurrentUnavailableDiagnostic = false) => {
241
+ const failure = unresolvedCurrentAuth(agent);
242
+ if (failure) {
243
+ hostState.updateStatus(agent, {
244
+ runtimeReadiness: { ...(0, runtime_readiness_js_1.readinessForPersistedAuthFailure)(failure), observedAt },
245
+ });
246
+ return;
247
+ }
248
+ const currentReadiness = hostState.readStatus(agent).runtimeReadiness;
249
+ const observedMs = Date.parse(String(currentReadiness?.observedAt || ""));
250
+ const daemonStartedMs = Date.parse(daemonStartedAt);
251
+ const currentEpoch = currentReadiness?.runtime === agent.runtime
252
+ && Number.isFinite(observedMs) && Number.isFinite(daemonStartedMs) && observedMs >= daemonStartedMs;
253
+ if (currentEpoch && (currentReadiness?.state === "missing" || currentReadiness?.state === "unauthenticated" || currentReadiness?.state === "incompatible"))
254
+ return;
255
+ if (currentEpoch && preserveCurrentUnavailableDiagnostic && currentReadiness?.state === "unavailable"
256
+ && typeof currentReadiness.reason === "string" && currentReadiness.reason.trim()) {
257
+ hostState.updateStatus(agent, {
258
+ runtimeReadiness: { ...currentReadiness, runtime: agent.runtime, state: "unavailable", observedAt },
259
+ });
260
+ return;
261
+ }
262
+ hostState.updateStatus(agent, {
263
+ runtimeReadiness: { runtime: agent.runtime, ...fallback, observedAt },
264
+ });
265
+ };
236
266
  const recordInboundDeliveryFailure = (agent, code) => {
237
267
  const at = new Date().toISOString();
238
268
  const reason = "Inbound Runtime delivery failed non-retryably; durable Inbox/ledger state is retained for recovery.";
239
269
  const nextAction = "Inspect the delivery/status error, correct the Runtime or canonical Inbox state, then restart to replay safely.";
240
- const currentReadiness = hostState.readStatus(agent).runtimeReadiness;
241
270
  hostState.updateStatus(agent, {
242
271
  inboundDeliveryHealth: { state: "error", code, at, reason, nextAction },
243
- ...(currentReadiness?.state === "unauthenticated" ? {} : {
244
- runtimeReadiness: { runtime: agent.runtime, state: "incompatible", reason, nextAction },
245
- }),
246
272
  });
273
+ projectFallbackRuntimeReadiness(agent, at, { state: "unavailable", reason, nextAction }, true);
247
274
  hostState.recordStatusError(agent, `${reason} ${nextAction} code=${code}`);
248
275
  };
249
276
  const agentStates = new Map();
@@ -397,13 +424,57 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
397
424
  for (const agent of agents)
398
425
  prepareAgentState(agent);
399
426
  const reminder = new host_reminder_orchestrator_js_1.HostReminderOrchestrator({ agents, stateStore, envelopeProjector, deliveryTarget: runtimeHost, log });
427
+ const auditRegistry = (0, missed_outbound_scan_js_1.inboxAuditRegistryFile)(larkinHome);
428
+ const auditRetryJournal = (0, missed_outbound_scan_js_1.inboxAuditRetryFile)(larkinHome);
429
+ let auditRetryTimer = null;
430
+ let auditRetryAttempt = 0;
431
+ const reconcileAuditRetries = () => {
432
+ try {
433
+ return (0, missed_outbound_scan_js_1.reconcileInboxAuditTargetRetries)(auditRegistry, auditRetryJournal).remaining;
434
+ }
435
+ catch (error) {
436
+ log(`inbox audit retry 读取失败: ${(0, inbox_audit_heartbeat_js_1.boundedInboxAuditDiagnostic)(error)}`);
437
+ return 1;
438
+ }
439
+ };
440
+ const scheduleAuditRetry = () => {
441
+ if (auditRetryTimer || auditRetryAttempt >= 5)
442
+ return;
443
+ const delay = [100, 250, 1_000, 3_000, 10_000][auditRetryAttempt++];
444
+ auditRetryTimer = setTimeout(() => {
445
+ auditRetryTimer = null;
446
+ if (reconcileAuditRetries() > 0)
447
+ scheduleAuditRetry();
448
+ else
449
+ auditRetryAttempt = 0;
450
+ }, delay);
451
+ auditRetryTimer.unref?.();
452
+ };
400
453
  const inboxAudit = new inbox_audit_heartbeat_js_1.InboxAuditHeartbeat({
401
454
  agents,
402
455
  stateStore,
403
456
  runtimeHost,
404
457
  log,
458
+ configFile: node_path_1.default.join(larkinHome, "config.json"),
459
+ schedule(agent) {
460
+ try {
461
+ return (0, config_js_1.resolveInboxAuditSchedule)((0, config_js_1.loadConfig)(env).config, agent.agentId);
462
+ }
463
+ catch (error) {
464
+ log(`inbox audit schedule 读取失败 agent=${agent.agentId}: ${errorMessage(error)}`);
465
+ return { enabled: false, intervalMs: inbox_audit_heartbeat_js_1.INBOX_AUDIT_CADENCE_MS };
466
+ }
467
+ },
468
+ shouldDispatch(agent) {
469
+ try {
470
+ return (0, missed_outbound_scan_js_1.hasPendingInboxAuditTargets)(auditRegistry, agent.agentId);
471
+ }
472
+ catch (error) {
473
+ log(`inbox audit pending 读取失败 agent=${agent.agentId}: ${errorMessage(error)}`);
474
+ return false;
475
+ }
476
+ },
405
477
  });
406
- const auditRegistry = (0, missed_outbound_scan_js_1.inboxAuditRegistryFile)(larkinHome);
407
478
  const seenEventIds = new Set();
408
479
  const inFlightEventIds = new Set();
409
480
  const onFeishuMessage = async (agent, event, options) => {
@@ -450,14 +521,23 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
450
521
  // append/dedupe decision is durable. Agent model-seen state is untouched.
451
522
  if (event.event_id)
452
523
  seenEventIds.add(eventKey);
524
+ if (append.status === "duplicate_consumed")
525
+ return null;
526
+ const auditSourceSeq = Number(append.envelope.target_seq);
453
527
  try {
454
- (0, missed_outbound_scan_js_1.observeInboxAuditTarget)(auditRegistry, agent.agentId, event);
528
+ (0, missed_outbound_scan_js_1.observeInboxAuditTarget)(auditRegistry, agent.agentId, { ...event, wake, source_seq: auditSourceSeq });
529
+ (0, missed_outbound_scan_js_1.discardInboxAuditTargetRetry)(auditRetryJournal, agent.agentId, { ...event, source_seq: auditSourceSeq });
455
530
  }
456
531
  catch (error) {
457
- log(`inbox audit target 未持久化: ${error.message}`);
532
+ try {
533
+ (0, missed_outbound_scan_js_1.enqueueInboxAuditTargetRetry)(auditRetryJournal, agent.agentId, { ...event, wake, source_seq: auditSourceSeq });
534
+ scheduleAuditRetry();
535
+ log(`inbox audit target 延后重试: ${(0, inbox_audit_heartbeat_js_1.boundedInboxAuditDiagnostic)(error)}`);
536
+ }
537
+ catch (retryError) {
538
+ log(`inbox audit target 未持久化: ${(0, inbox_audit_heartbeat_js_1.boundedInboxAuditDiagnostic)(retryError)}`);
539
+ }
458
540
  }
459
- if (append.status === "duplicate_consumed")
460
- return null;
461
541
  const inboxEnvelope = append.envelope;
462
542
  if (append.status === "appended")
463
543
  hostState.appendConversation(agent, {
@@ -1312,15 +1392,21 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
1312
1392
  if (message.type === "agent-status") {
1313
1393
  log("agent:status", message.agentId, message.status);
1314
1394
  const observedAt = new Date().toISOString();
1315
- if (message.status === "error" || message.status === "inactive")
1316
- hostState.updateStatus(agent, {
1317
- runtimeReadiness: message.readiness?.state && message.readiness.state !== "ready" ? { ...message.readiness, observedAt } : {
1318
- runtime: agent.runtime,
1319
- state: message.status === "error" ? "incompatible" : "missing",
1320
- reason: message.status === "error" ? message.error || "Runtime entered an error state" : "Runtime is inactive",
1321
- observedAt,
1322
- },
1323
- });
1395
+ if (message.status === "error" || message.status === "inactive") {
1396
+ if (message.readiness?.state && message.readiness.state !== "ready") {
1397
+ hostState.updateStatus(agent, { runtimeReadiness: { ...message.readiness, observedAt } });
1398
+ }
1399
+ else {
1400
+ projectFallbackRuntimeReadiness(agent, observedAt, message.status === "error" ? {
1401
+ state: "unavailable",
1402
+ reason: safeRuntimeStatusDiagnostic(message.error),
1403
+ nextAction: "Inspect the Runtime status error, correct the Runtime availability issue, then retry.",
1404
+ } : {
1405
+ state: "missing",
1406
+ reason: "Runtime is inactive",
1407
+ });
1408
+ }
1409
+ }
1324
1410
  else if (message.readiness) {
1325
1411
  if (message.readiness.state === "ready" && unresolvedCurrentAuth(agent)) {
1326
1412
  projectReadyUnlessUnresolvedAuth(agent, observedAt);
@@ -1338,7 +1424,7 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
1338
1424
  redeliveryTimer.unref?.();
1339
1425
  }
1340
1426
  if (message.status === "error" && message.error)
1341
- hostState.recordStatusError(agent, message.error);
1427
+ hostState.recordStatusError(agent, safeRuntimeStatusDiagnostic(message.error));
1342
1428
  if (message.status === "error" || message.status === "inactive") {
1343
1429
  processingEyes.clear(agent, `agent-status:${message.status}`);
1344
1430
  }
@@ -1419,6 +1505,9 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
1419
1505
  eventSourceStartTimer = null;
1420
1506
  await Promise.resolve(eventSourceStop());
1421
1507
  reminder.stopSync();
1508
+ if (auditRetryTimer)
1509
+ clearTimeout(auditRetryTimer);
1510
+ auditRetryTimer = null;
1422
1511
  inboxAudit.stop();
1423
1512
  interaction.stopSync();
1424
1513
  await runtimeHost.shutdown(reason);
@@ -1637,6 +1726,8 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
1637
1726
  previousSession: agentStates.get(agent.agentId)?.state.previousSessions?.[agent.runtime] ?? null,
1638
1727
  })));
1639
1728
  reminder.startSync();
1729
+ if (reconcileAuditRetries() > 0)
1730
+ scheduleAuditRetry();
1640
1731
  inboxAudit.start();
1641
1732
  interaction.startSync();
1642
1733
  eventSourceStartTimer = setTimeout(() => { eventSourceStartTimer = null; startEventSource(); }, eventSourceStartDelayMs);
@@ -11,14 +11,15 @@ import { HostEnvelopeProjector, HostStateProjection, SenderIdentityCache, projec
11
11
  import { ProcessingEyeOrchestrator } from "./host-processing-eye.mjs";
12
12
  import { projectInboxEnvelope, targetKeyOfInboxEnvelope } from "../agent/inbox-projection.mjs";
13
13
  import { HostReminderOrchestrator } from "../agent/host-reminder-orchestrator.mjs";
14
- import { InboxAuditHeartbeat } from "../agent/inbox-audit-heartbeat.mjs";
15
- import { inboxAuditRegistryFile, observeInboxAuditTarget } from "../agent/missed-outbound-scan.mjs";
14
+ import { boundedInboxAuditDiagnostic, InboxAuditHeartbeat, INBOX_AUDIT_CADENCE_MS } from "../agent/inbox-audit-heartbeat.mjs";
15
+ import { discardInboxAuditTargetRetry, enqueueInboxAuditTargetRetry, hasPendingInboxAuditTargets, inboxAuditRegistryFile, inboxAuditRetryFile, observeInboxAuditTarget, reconcileInboxAuditTargetRetries } from "../agent/missed-outbound-scan.mjs";
16
16
  import { HostChannelBusiness } from "./host-channel-business.mjs";
17
17
  import { HostInteractionOrchestrator } from "./interaction-orchestrator.mjs";
18
18
  import { targetFor } from "./message-policy.mjs";
19
19
  import { authFailureAppliesTo, parsePersistedAuthFailure, providerAuthenticationFailureReadiness, readinessForPersistedAuthFailure, RuntimePrerequisiteError, } from "../runtime/runtime-readiness.mjs";
20
+ import { safeProviderDiagnostic } from "../runtime/provider-error-classifier.mjs";
20
21
  import { readDocumentCommentSubscription, verifyCallbackProbe } from "../platform/callback-capability.mjs";
21
- import { loadConfig, resolveMentionPolicy } from "../platform/config.mjs";
22
+ import { loadConfig, resolveInboxAuditSchedule, resolveMentionPolicy } from "../platform/config.mjs";
22
23
  import { processCommandToken } from "../app/internal-command.mjs";
23
24
  import { managedOfficialLarkCli } from "../app/agent-lark-cli-workspace.mjs";
24
25
  import { isChannelReconnecting, isRuntimeReadinessCurrent } from "../app/agent-readiness.mjs";
@@ -79,6 +80,9 @@ export function memberNamesFromPayloads(payloads) {
79
80
  return names;
80
81
  }
81
82
  function errorMessage(error) { return error instanceof Error ? error.message : String(error); }
83
+ function safeRuntimeStatusDiagnostic(error) {
84
+ return safeProviderDiagnostic(error, "Runtime entered an error state", 500);
85
+ }
82
86
  function agentConfigSignature(agent) {
83
87
  return JSON.stringify({
84
88
  agentId: agent.agentId, runtime: agent.runtime, model: agent.model, effort: agent.effort ?? null,
@@ -193,17 +197,40 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
193
197
  }
194
198
  hostState.updateStatus(agent, { runtimeReadiness: { runtime: agent.runtime, state: "ready", observedAt } });
195
199
  };
200
+ const projectFallbackRuntimeReadiness = (agent, observedAt, fallback, preserveCurrentUnavailableDiagnostic = false) => {
201
+ const failure = unresolvedCurrentAuth(agent);
202
+ if (failure) {
203
+ hostState.updateStatus(agent, {
204
+ runtimeReadiness: { ...readinessForPersistedAuthFailure(failure), observedAt },
205
+ });
206
+ return;
207
+ }
208
+ const currentReadiness = hostState.readStatus(agent).runtimeReadiness;
209
+ const observedMs = Date.parse(String(currentReadiness?.observedAt || ""));
210
+ const daemonStartedMs = Date.parse(daemonStartedAt);
211
+ const currentEpoch = currentReadiness?.runtime === agent.runtime
212
+ && Number.isFinite(observedMs) && Number.isFinite(daemonStartedMs) && observedMs >= daemonStartedMs;
213
+ if (currentEpoch && (currentReadiness?.state === "missing" || currentReadiness?.state === "unauthenticated" || currentReadiness?.state === "incompatible"))
214
+ return;
215
+ if (currentEpoch && preserveCurrentUnavailableDiagnostic && currentReadiness?.state === "unavailable"
216
+ && typeof currentReadiness.reason === "string" && currentReadiness.reason.trim()) {
217
+ hostState.updateStatus(agent, {
218
+ runtimeReadiness: { ...currentReadiness, runtime: agent.runtime, state: "unavailable", observedAt },
219
+ });
220
+ return;
221
+ }
222
+ hostState.updateStatus(agent, {
223
+ runtimeReadiness: { runtime: agent.runtime, ...fallback, observedAt },
224
+ });
225
+ };
196
226
  const recordInboundDeliveryFailure = (agent, code) => {
197
227
  const at = new Date().toISOString();
198
228
  const reason = "Inbound Runtime delivery failed non-retryably; durable Inbox/ledger state is retained for recovery.";
199
229
  const nextAction = "Inspect the delivery/status error, correct the Runtime or canonical Inbox state, then restart to replay safely.";
200
- const currentReadiness = hostState.readStatus(agent).runtimeReadiness;
201
230
  hostState.updateStatus(agent, {
202
231
  inboundDeliveryHealth: { state: "error", code, at, reason, nextAction },
203
- ...(currentReadiness?.state === "unauthenticated" ? {} : {
204
- runtimeReadiness: { runtime: agent.runtime, state: "incompatible", reason, nextAction },
205
- }),
206
232
  });
233
+ projectFallbackRuntimeReadiness(agent, at, { state: "unavailable", reason, nextAction }, true);
207
234
  hostState.recordStatusError(agent, `${reason} ${nextAction} code=${code}`);
208
235
  };
209
236
  const agentStates = new Map();
@@ -357,13 +384,57 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
357
384
  for (const agent of agents)
358
385
  prepareAgentState(agent);
359
386
  const reminder = new HostReminderOrchestrator({ agents, stateStore, envelopeProjector, deliveryTarget: runtimeHost, log });
387
+ const auditRegistry = inboxAuditRegistryFile(larkinHome);
388
+ const auditRetryJournal = inboxAuditRetryFile(larkinHome);
389
+ let auditRetryTimer = null;
390
+ let auditRetryAttempt = 0;
391
+ const reconcileAuditRetries = () => {
392
+ try {
393
+ return reconcileInboxAuditTargetRetries(auditRegistry, auditRetryJournal).remaining;
394
+ }
395
+ catch (error) {
396
+ log(`inbox audit retry 读取失败: ${boundedInboxAuditDiagnostic(error)}`);
397
+ return 1;
398
+ }
399
+ };
400
+ const scheduleAuditRetry = () => {
401
+ if (auditRetryTimer || auditRetryAttempt >= 5)
402
+ return;
403
+ const delay = [100, 250, 1_000, 3_000, 10_000][auditRetryAttempt++];
404
+ auditRetryTimer = setTimeout(() => {
405
+ auditRetryTimer = null;
406
+ if (reconcileAuditRetries() > 0)
407
+ scheduleAuditRetry();
408
+ else
409
+ auditRetryAttempt = 0;
410
+ }, delay);
411
+ auditRetryTimer.unref?.();
412
+ };
360
413
  const inboxAudit = new InboxAuditHeartbeat({
361
414
  agents,
362
415
  stateStore,
363
416
  runtimeHost,
364
417
  log,
418
+ configFile: path.join(larkinHome, "config.json"),
419
+ schedule(agent) {
420
+ try {
421
+ return resolveInboxAuditSchedule(loadConfig(env).config, agent.agentId);
422
+ }
423
+ catch (error) {
424
+ log(`inbox audit schedule 读取失败 agent=${agent.agentId}: ${errorMessage(error)}`);
425
+ return { enabled: false, intervalMs: INBOX_AUDIT_CADENCE_MS };
426
+ }
427
+ },
428
+ shouldDispatch(agent) {
429
+ try {
430
+ return hasPendingInboxAuditTargets(auditRegistry, agent.agentId);
431
+ }
432
+ catch (error) {
433
+ log(`inbox audit pending 读取失败 agent=${agent.agentId}: ${errorMessage(error)}`);
434
+ return false;
435
+ }
436
+ },
365
437
  });
366
- const auditRegistry = inboxAuditRegistryFile(larkinHome);
367
438
  const seenEventIds = new Set();
368
439
  const inFlightEventIds = new Set();
369
440
  const onFeishuMessage = async (agent, event, options) => {
@@ -410,14 +481,23 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
410
481
  // append/dedupe decision is durable. Agent model-seen state is untouched.
411
482
  if (event.event_id)
412
483
  seenEventIds.add(eventKey);
484
+ if (append.status === "duplicate_consumed")
485
+ return null;
486
+ const auditSourceSeq = Number(append.envelope.target_seq);
413
487
  try {
414
- observeInboxAuditTarget(auditRegistry, agent.agentId, event);
488
+ observeInboxAuditTarget(auditRegistry, agent.agentId, { ...event, wake, source_seq: auditSourceSeq });
489
+ discardInboxAuditTargetRetry(auditRetryJournal, agent.agentId, { ...event, source_seq: auditSourceSeq });
415
490
  }
416
491
  catch (error) {
417
- log(`inbox audit target 未持久化: ${error.message}`);
492
+ try {
493
+ enqueueInboxAuditTargetRetry(auditRetryJournal, agent.agentId, { ...event, wake, source_seq: auditSourceSeq });
494
+ scheduleAuditRetry();
495
+ log(`inbox audit target 延后重试: ${boundedInboxAuditDiagnostic(error)}`);
496
+ }
497
+ catch (retryError) {
498
+ log(`inbox audit target 未持久化: ${boundedInboxAuditDiagnostic(retryError)}`);
499
+ }
418
500
  }
419
- if (append.status === "duplicate_consumed")
420
- return null;
421
501
  const inboxEnvelope = append.envelope;
422
502
  if (append.status === "appended")
423
503
  hostState.appendConversation(agent, {
@@ -1272,15 +1352,21 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
1272
1352
  if (message.type === "agent-status") {
1273
1353
  log("agent:status", message.agentId, message.status);
1274
1354
  const observedAt = new Date().toISOString();
1275
- if (message.status === "error" || message.status === "inactive")
1276
- hostState.updateStatus(agent, {
1277
- runtimeReadiness: message.readiness?.state && message.readiness.state !== "ready" ? { ...message.readiness, observedAt } : {
1278
- runtime: agent.runtime,
1279
- state: message.status === "error" ? "incompatible" : "missing",
1280
- reason: message.status === "error" ? message.error || "Runtime entered an error state" : "Runtime is inactive",
1281
- observedAt,
1282
- },
1283
- });
1355
+ if (message.status === "error" || message.status === "inactive") {
1356
+ if (message.readiness?.state && message.readiness.state !== "ready") {
1357
+ hostState.updateStatus(agent, { runtimeReadiness: { ...message.readiness, observedAt } });
1358
+ }
1359
+ else {
1360
+ projectFallbackRuntimeReadiness(agent, observedAt, message.status === "error" ? {
1361
+ state: "unavailable",
1362
+ reason: safeRuntimeStatusDiagnostic(message.error),
1363
+ nextAction: "Inspect the Runtime status error, correct the Runtime availability issue, then retry.",
1364
+ } : {
1365
+ state: "missing",
1366
+ reason: "Runtime is inactive",
1367
+ });
1368
+ }
1369
+ }
1284
1370
  else if (message.readiness) {
1285
1371
  if (message.readiness.state === "ready" && unresolvedCurrentAuth(agent)) {
1286
1372
  projectReadyUnlessUnresolvedAuth(agent, observedAt);
@@ -1298,7 +1384,7 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
1298
1384
  redeliveryTimer.unref?.();
1299
1385
  }
1300
1386
  if (message.status === "error" && message.error)
1301
- hostState.recordStatusError(agent, message.error);
1387
+ hostState.recordStatusError(agent, safeRuntimeStatusDiagnostic(message.error));
1302
1388
  if (message.status === "error" || message.status === "inactive") {
1303
1389
  processingEyes.clear(agent, `agent-status:${message.status}`);
1304
1390
  }
@@ -1379,6 +1465,9 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
1379
1465
  eventSourceStartTimer = null;
1380
1466
  await Promise.resolve(eventSourceStop());
1381
1467
  reminder.stopSync();
1468
+ if (auditRetryTimer)
1469
+ clearTimeout(auditRetryTimer);
1470
+ auditRetryTimer = null;
1382
1471
  inboxAudit.stop();
1383
1472
  interaction.stopSync();
1384
1473
  await runtimeHost.shutdown(reason);
@@ -1597,6 +1686,8 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
1597
1686
  previousSession: agentStates.get(agent.agentId)?.state.previousSessions?.[agent.runtime] ?? null,
1598
1687
  })));
1599
1688
  reminder.startSync();
1689
+ if (reconcileAuditRetries() > 0)
1690
+ scheduleAuditRetry();
1600
1691
  inboxAudit.start();
1601
1692
  interaction.startSync();
1602
1693
  eventSourceStartTimer = setTimeout(() => { eventSourceStartTimer = null; startEventSource(); }, eventSourceStartDelayMs);