@slock-ai/daemon 0.57.2 → 0.57.3
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/{chunk-EKSATDT3.js → chunk-H2QU4LAU.js} +177 -18
- package/dist/core.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
|
@@ -1438,9 +1438,9 @@ Error code prefixes tell you the layer:
|
|
|
1438
1438
|
function buildCredentialHygieneSection() {
|
|
1439
1439
|
return `### Credential hygiene
|
|
1440
1440
|
|
|
1441
|
-
**Never paste credentials into Slock
|
|
1441
|
+
**Never paste credentials into public Slock channels, public-channel threads, or public-channel task/attachment fields.** Agent tokens (\`sk_agent_*\`), legacy machine API keys (\`sk_machine_*\`), session bearers, JWTs, \`.env\` files, or \`credential.json\` contents must not appear in public channel chat. DMs and private channels are allowed for authorized secret handoff, but verify the audience first. If you accidentally paste one into a public channel, immediately tell the credential owner so they can rotate it.
|
|
1442
1442
|
|
|
1443
|
-
If a tool or error output contains credential-shaped strings, redact them to \`sk_agent_<redacted>\` / \`sk_machine_<redacted>\` shape before
|
|
1443
|
+
If a tool or error output contains credential-shaped strings, redact them to \`sk_agent_<redacted>\` / \`sk_machine_<redacted>\` shape before posting to a public channel.
|
|
1444
1444
|
|
|
1445
1445
|
**Profile credential resolution is strict.** When invoked as \`slock --profile <slug>\` or with \`SLOCK_PROFILE=<slug>\`, the CLI resolves credentials from \`$SLOCK_PROFILE_DIR\` \u2192 \`$SLOCK_HOME/profiles/<slug>\` \u2192 \`$HOME/.slock/profiles/<slug>\` in that order. It does **not** fall back to a different profile's credential, to an ambient user-level token, or to environment-leaked secrets \u2014 if your designated profile credential is missing or unreadable, the CLI fails closed rather than authenticating as someone else.`;
|
|
1446
1446
|
}
|
|
@@ -1808,9 +1808,9 @@ You have MCP tools from the "chat" server. Use ONLY these for communication:
|
|
|
1808
1808
|
17. **${cancelReminderCmd}** \u2014 Cancel one of your reminders by ID.`;
|
|
1809
1809
|
const credentialHygieneSection = isCli ? cliGuideSections.credentialHygiene : `### Credential hygiene
|
|
1810
1810
|
|
|
1811
|
-
**Never paste credentials into Slock
|
|
1811
|
+
**Never paste credentials into public Slock channels, public-channel threads, or public-channel task/attachment fields.** Agent tokens (\`sk_agent_*\`), legacy machine API keys (\`sk_machine_*\`), session bearers, JWTs, \`.env\` files, or \`credential.json\` contents must not appear in public channel chat. DMs and private channels are allowed for authorized secret handoff, but verify the audience first. If you accidentally paste one into a public channel, immediately tell the credential owner so they can rotate it.
|
|
1812
1812
|
|
|
1813
|
-
If a tool or error output contains credential-shaped strings, redact them to \`sk_agent_<redacted>\` / \`sk_machine_<redacted>\` shape before
|
|
1813
|
+
If a tool or error output contains credential-shaped strings, redact them to \`sk_agent_<redacted>\` / \`sk_machine_<redacted>\` shape before posting to a public channel.`;
|
|
1814
1814
|
const reminderSection = isCli ? cliGuideSections.reminders : `### Reminders
|
|
1815
1815
|
|
|
1816
1816
|
Use reminders for follow-up that depends on future state you cannot resolve now, whether user-requested or self-driven. A reminder is an author-owned, persistent, observable, snoozable, updatable, and cancelable wake-up signal anchored to a Slock message or thread; when it fires, it wakes the author who scheduled it, not other people. If anchored to a message or thread, the receipt/fire system message is visible in that surface, but wake ownership does not transfer. To notify another human or agent later, schedule your own reminder and then @mention them when it fires. Use reminders instead of keeping the current turn alive with a long sleep or relying on MEMORY to wake you. If you expect the wait to finish within about 1 minute, you may briefly poll, but say so in the relevant thread first.
|
|
@@ -7985,6 +7985,9 @@ var STDIN_NOTIFICATION_INITIAL_DELAY_MS = 3e3;
|
|
|
7985
7985
|
var STDIN_NOTIFICATION_RETRY_DELAY_MS = 15e3;
|
|
7986
7986
|
var RUNTIME_ERROR_DELIVERY_BACKOFF_BASE_MS = 1e4;
|
|
7987
7987
|
var RUNTIME_ERROR_DELIVERY_BACKOFF_MAX_MS = 5 * 6e4;
|
|
7988
|
+
var SPAWN_FAIL_BACKOFF_BASE_MS = 1e3;
|
|
7989
|
+
var SPAWN_FAIL_BACKOFF_MAX_MS = 3e4;
|
|
7990
|
+
var SPAWN_FAIL_BACKOFF_THRESHOLD = 3;
|
|
7988
7991
|
var COMPACTION_STALE_MS = 5 * 6e4;
|
|
7989
7992
|
var RUNTIME_PROGRESS_STALE_MS = 15 * 6e4;
|
|
7990
7993
|
var DEFAULT_RUNTIME_START_TIMEOUT_MS = 2 * 6e4;
|
|
@@ -8492,6 +8495,12 @@ function summarizeCrash(code, signal) {
|
|
|
8492
8495
|
if (typeof code === "number") return `exit code ${code}`;
|
|
8493
8496
|
return "unknown exit";
|
|
8494
8497
|
}
|
|
8498
|
+
function currentErrorCandidates(ap) {
|
|
8499
|
+
return [
|
|
8500
|
+
ap.runtimeErrorSinceProgress ? ap.lastRuntimeError : null,
|
|
8501
|
+
...ap.recentDecisionStderr
|
|
8502
|
+
].filter((value) => !!value);
|
|
8503
|
+
}
|
|
8495
8504
|
function classifyTerminalFailure(ap) {
|
|
8496
8505
|
const candidates = [
|
|
8497
8506
|
ap.lastRuntimeError,
|
|
@@ -8535,21 +8544,16 @@ function isCodexProviderReconnectLog(text) {
|
|
|
8535
8544
|
function isCodexBenignTransportLog(text) {
|
|
8536
8545
|
return /Falling back from WebSockets/i.test(text);
|
|
8537
8546
|
}
|
|
8547
|
+
function isStdinClassRecoveryLine(text) {
|
|
8548
|
+
return /write_stdin failed|stdin is closed|closed for this session|session.*closed/i.test(text);
|
|
8549
|
+
}
|
|
8538
8550
|
function hasDirectStdinRecoveryEvidence(ap) {
|
|
8539
|
-
const candidates =
|
|
8540
|
-
|
|
8541
|
-
...ap.recentStderr
|
|
8542
|
-
].filter((value) => !!value);
|
|
8543
|
-
return candidates.some(
|
|
8544
|
-
(text) => /write_stdin failed|stdin is closed|closed for this session|session.*closed/i.test(text)
|
|
8545
|
-
);
|
|
8551
|
+
const candidates = currentErrorCandidates(ap);
|
|
8552
|
+
return candidates.some((text) => isStdinClassRecoveryLine(text));
|
|
8546
8553
|
}
|
|
8547
8554
|
function resumeSessionRecoveryReason(ap) {
|
|
8548
8555
|
if (!ap.sessionId) return null;
|
|
8549
|
-
const candidates =
|
|
8550
|
-
ap.lastRuntimeError,
|
|
8551
|
-
...ap.recentStderr
|
|
8552
|
-
].filter((value) => !!value);
|
|
8556
|
+
const candidates = currentErrorCandidates(ap);
|
|
8553
8557
|
if (ap.driver.id === "claude") {
|
|
8554
8558
|
return candidates.some((text) => /No conversation found with session ID/i.test(text)) ? "missing" : null;
|
|
8555
8559
|
}
|
|
@@ -8860,6 +8864,11 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8860
8864
|
runtimeExitTraceAttrs = /* @__PURE__ */ new WeakMap();
|
|
8861
8865
|
agentVisibleBoundaries = /* @__PURE__ */ new Map();
|
|
8862
8866
|
agentVisibleMessageIds = /* @__PURE__ */ new Map();
|
|
8867
|
+
// Spawn-fail backoff state per-agent (lifted outside AgentProcess because spawn fails
|
|
8868
|
+
// BEFORE ap exists; rate-state must persist across stop/respawn so churn can't bypass).
|
|
8869
|
+
// Explicit stop clears (fresh launch resets dedup clock — CC1 lifecycle pattern); silent
|
|
8870
|
+
// stop preserves (same-launch respawn must keep counter or churn bypasses the cap).
|
|
8871
|
+
agentSpawnFailBackoff = /* @__PURE__ */ new Map();
|
|
8863
8872
|
daemonVersion;
|
|
8864
8873
|
computerVersion;
|
|
8865
8874
|
constructor(sendToServer, daemonApiKey, opts) {
|
|
@@ -8939,6 +8948,57 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
8939
8948
|
const id = typeof message.message_id === "string" ? message.message_id : typeof message.id === "string" ? message.id : "";
|
|
8940
8949
|
return id.length > 0 && this.getVisibleMessageIdSet(agentId, target)?.has(id) === true;
|
|
8941
8950
|
}
|
|
8951
|
+
// ----- SPAWN-FAIL BACKOFF (per-agent) ----------------------------------
|
|
8952
|
+
// Anchored at auto_restart_from_idle (apm:3596) + runtime_profile_auto_restart (apm:4137).
|
|
8953
|
+
// Threshold > 1 → first SPAWN_FAIL_BACKOFF_THRESHOLD failures behave as today (preserves
|
|
8954
|
+
// single-transient-hiccup); subsequent failure schedules a per-agent cooldown gating new
|
|
8955
|
+
// spawn attempts. Successful spawn resets state. State lives outside AgentProcess because
|
|
8956
|
+
// spawn fails BEFORE ap exists and the rate-window must persist across stop/respawn
|
|
8957
|
+
// (else stop/start churn bypasses the cap — CC1 lifecycle pattern). Never advances any
|
|
8958
|
+
// consume cursor or model-seen state (3-cursor orthogonality with CC1/CC2).
|
|
8959
|
+
getOrCreateSpawnFailBackoff(agentId) {
|
|
8960
|
+
let state = this.agentSpawnFailBackoff.get(agentId);
|
|
8961
|
+
if (!state) {
|
|
8962
|
+
state = createRuntimeErrorDeliveryBackoffState();
|
|
8963
|
+
this.agentSpawnFailBackoff.set(agentId, state);
|
|
8964
|
+
}
|
|
8965
|
+
return state;
|
|
8966
|
+
}
|
|
8967
|
+
isSpawnFailBackoffActive(agentId) {
|
|
8968
|
+
const state = this.agentSpawnFailBackoff.get(agentId);
|
|
8969
|
+
if (!state) return false;
|
|
8970
|
+
return state.untilMs > 0 && this.clockNow() < state.untilMs;
|
|
8971
|
+
}
|
|
8972
|
+
clockNow() {
|
|
8973
|
+
return Date.now();
|
|
8974
|
+
}
|
|
8975
|
+
recordSpawnFailure(agentId, reason) {
|
|
8976
|
+
const state = this.getOrCreateSpawnFailBackoff(agentId);
|
|
8977
|
+
state.attempts += 1;
|
|
8978
|
+
state.reason = reason;
|
|
8979
|
+
if (state.attempts <= SPAWN_FAIL_BACKOFF_THRESHOLD) {
|
|
8980
|
+
state.untilMs = 0;
|
|
8981
|
+
return { backoffActive: false, attempts: state.attempts, untilMs: 0 };
|
|
8982
|
+
}
|
|
8983
|
+
const exponent = Math.min(state.attempts - SPAWN_FAIL_BACKOFF_THRESHOLD, 10);
|
|
8984
|
+
const baseDelay = Math.min(SPAWN_FAIL_BACKOFF_MAX_MS, SPAWN_FAIL_BACKOFF_BASE_MS * Math.pow(2, exponent));
|
|
8985
|
+
state.untilMs = this.clockNow() + Math.floor(baseDelay);
|
|
8986
|
+
if (state.timer) clearTimeout(state.timer);
|
|
8987
|
+
state.timer = setTimeout(() => {
|
|
8988
|
+
const s = this.agentSpawnFailBackoff.get(agentId);
|
|
8989
|
+
if (s) {
|
|
8990
|
+
s.timer = null;
|
|
8991
|
+
s.untilMs = 0;
|
|
8992
|
+
}
|
|
8993
|
+
}, Math.max(1, state.untilMs - this.clockNow()));
|
|
8994
|
+
return { backoffActive: true, attempts: state.attempts, untilMs: state.untilMs };
|
|
8995
|
+
}
|
|
8996
|
+
resetSpawnFailBackoff(agentId) {
|
|
8997
|
+
const state = this.agentSpawnFailBackoff.get(agentId);
|
|
8998
|
+
if (!state) return;
|
|
8999
|
+
if (state.timer) clearTimeout(state.timer);
|
|
9000
|
+
this.agentSpawnFailBackoff.delete(agentId);
|
|
9001
|
+
}
|
|
8942
9002
|
scheduleStdinNotification(agentId, ap, delayMs) {
|
|
8943
9003
|
return ap.notifications.schedule(() => {
|
|
8944
9004
|
this.sendStdinNotification(agentId);
|
|
@@ -9793,6 +9853,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9793
9853
|
recentStdout: [],
|
|
9794
9854
|
recentStderr: [],
|
|
9795
9855
|
lastRuntimeError: null,
|
|
9856
|
+
recentDecisionStderr: [],
|
|
9857
|
+
runtimeErrorSinceProgress: false,
|
|
9796
9858
|
runtimeErrorDeliveryBackoff: createRuntimeErrorDeliveryBackoffState(),
|
|
9797
9859
|
spawnError: null,
|
|
9798
9860
|
exitCode: null,
|
|
@@ -9836,6 +9898,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9836
9898
|
if (driver.id === "codex" && isCodexProviderReconnectLog(text)) {
|
|
9837
9899
|
if (current) {
|
|
9838
9900
|
current.recentStderr = pushRecentStderr(current.recentStderr, text);
|
|
9901
|
+
current.recentDecisionStderr = pushRecentStderr(current.recentDecisionStderr, text);
|
|
9839
9902
|
}
|
|
9840
9903
|
this.recordDaemonTrace("daemon.agent.provider_reconnect", {
|
|
9841
9904
|
agentId,
|
|
@@ -9852,6 +9915,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
9852
9915
|
if (driver.id === "codex" && isCodexBenignTransportLog(text)) return;
|
|
9853
9916
|
if (current) {
|
|
9854
9917
|
current.recentStderr = pushRecentStderr(current.recentStderr, text);
|
|
9918
|
+
current.recentDecisionStderr = pushRecentStderr(current.recentDecisionStderr, text);
|
|
9855
9919
|
}
|
|
9856
9920
|
logger.error(`[Agent ${agentId} stderr]: ${text}`);
|
|
9857
9921
|
});
|
|
@@ -10342,6 +10406,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10342
10406
|
this.activityClientSeqByAgent.delete(agentId);
|
|
10343
10407
|
this.agentVisibleBoundaries.delete(agentId);
|
|
10344
10408
|
this.agentVisibleMessageIds.delete(agentId);
|
|
10409
|
+
this.resetSpawnFailBackoff(agentId);
|
|
10345
10410
|
}
|
|
10346
10411
|
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
10347
10412
|
stop_source: silent ? "daemon_internal" : "explicit_request",
|
|
@@ -10438,6 +10503,25 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10438
10503
|
return true;
|
|
10439
10504
|
}
|
|
10440
10505
|
logger.info(`[Agent ${agentId}] Starting from idle state for new message`);
|
|
10506
|
+
if (this.isSpawnFailBackoffActive(agentId)) {
|
|
10507
|
+
const state = this.agentSpawnFailBackoff.get(agentId);
|
|
10508
|
+
const pending = this.startingInboxes.get(agentId) || [];
|
|
10509
|
+
pending.push(message);
|
|
10510
|
+
this.startingInboxes.set(agentId, pending);
|
|
10511
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
10512
|
+
outcome: "spawn_fail_cooldown_active",
|
|
10513
|
+
accepted: true,
|
|
10514
|
+
process_present: false,
|
|
10515
|
+
cached_idle_config_present: true,
|
|
10516
|
+
runtime: cached.config.runtime,
|
|
10517
|
+
session_id_present: Boolean(cached.sessionId),
|
|
10518
|
+
launchId: cached.launchId || void 0,
|
|
10519
|
+
spawn_fail_attempts: state.attempts,
|
|
10520
|
+
spawn_fail_until_ms: state.untilMs,
|
|
10521
|
+
starting_inbox_count: pending.length
|
|
10522
|
+
}));
|
|
10523
|
+
return true;
|
|
10524
|
+
}
|
|
10441
10525
|
this.idleAgentConfigs.delete(agentId);
|
|
10442
10526
|
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
10443
10527
|
outcome: "auto_restart_from_idle",
|
|
@@ -10448,12 +10532,33 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10448
10532
|
session_id_present: Boolean(cached.sessionId),
|
|
10449
10533
|
launchId: cached.launchId || void 0
|
|
10450
10534
|
}));
|
|
10451
|
-
return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0, transientDelivery).then(() =>
|
|
10535
|
+
return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0, transientDelivery).then(() => {
|
|
10536
|
+
this.resetSpawnFailBackoff(agentId);
|
|
10537
|
+
return true;
|
|
10538
|
+
}, (err) => {
|
|
10452
10539
|
logger.error(`[Agent ${agentId}] Failed to auto-restart`, err);
|
|
10453
10540
|
if (this.reportRunnerCredentialMintFailure(agentId, err, cached.launchId, "idle_auto_restart")) {
|
|
10541
|
+
const report2 = this.recordSpawnFailure(agentId, "runner_credential_mint");
|
|
10542
|
+
this.recordDaemonTrace("daemon.agent.spawn.fail_backoff", {
|
|
10543
|
+
agentId,
|
|
10544
|
+
source: "idle_auto_restart",
|
|
10545
|
+
reason: "runner_credential_mint",
|
|
10546
|
+
attempts: report2.attempts,
|
|
10547
|
+
cooldown_active: report2.backoffActive,
|
|
10548
|
+
until_ms: report2.untilMs
|
|
10549
|
+
});
|
|
10454
10550
|
return false;
|
|
10455
10551
|
}
|
|
10456
10552
|
this.idleAgentConfigs.set(agentId, cached);
|
|
10553
|
+
const report = this.recordSpawnFailure(agentId, "spawn_error");
|
|
10554
|
+
this.recordDaemonTrace("daemon.agent.spawn.fail_backoff", {
|
|
10555
|
+
agentId,
|
|
10556
|
+
source: "idle_auto_restart",
|
|
10557
|
+
reason: "spawn_error",
|
|
10558
|
+
attempts: report.attempts,
|
|
10559
|
+
cooldown_active: report.backoffActive,
|
|
10560
|
+
until_ms: report.untilMs
|
|
10561
|
+
});
|
|
10457
10562
|
return false;
|
|
10458
10563
|
});
|
|
10459
10564
|
}
|
|
@@ -10928,10 +11033,35 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10928
11033
|
const cached = this.idleAgentConfigs.get(agentId);
|
|
10929
11034
|
if (cached) {
|
|
10930
11035
|
logger.info(`[Agent ${agentId}] Starting from idle state for runtime profile ${kind} ${key}`);
|
|
11036
|
+
if (this.isSpawnFailBackoffActive(agentId)) {
|
|
11037
|
+
const state = this.agentSpawnFailBackoff.get(agentId);
|
|
11038
|
+
span.end("ok", {
|
|
11039
|
+
attrs: {
|
|
11040
|
+
outcome: "spawn_fail_cooldown_active",
|
|
11041
|
+
runtime: cached.config.runtime,
|
|
11042
|
+
launchId: cached.launchId || void 0,
|
|
11043
|
+
spawn_fail_attempts: state.attempts,
|
|
11044
|
+
spawn_fail_until_ms: state.untilMs
|
|
11045
|
+
}
|
|
11046
|
+
});
|
|
11047
|
+
return true;
|
|
11048
|
+
}
|
|
10931
11049
|
this.idleAgentConfigs.delete(agentId);
|
|
10932
|
-
return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0).then(() =>
|
|
11050
|
+
return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0).then(() => {
|
|
11051
|
+
this.resetSpawnFailBackoff(agentId);
|
|
11052
|
+
return true;
|
|
11053
|
+
}, (err) => {
|
|
10933
11054
|
logger.error(`[Agent ${agentId}] Failed to auto-restart for runtime profile notification`, err);
|
|
10934
11055
|
if (this.reportRunnerCredentialMintFailure(agentId, err, cached.launchId, "runtime_profile_auto_restart")) {
|
|
11056
|
+
const report2 = this.recordSpawnFailure(agentId, "runner_credential_mint");
|
|
11057
|
+
this.recordDaemonTrace("daemon.agent.spawn.fail_backoff", {
|
|
11058
|
+
agentId,
|
|
11059
|
+
source: "runtime_profile_auto_restart",
|
|
11060
|
+
reason: "runner_credential_mint",
|
|
11061
|
+
attempts: report2.attempts,
|
|
11062
|
+
cooldown_active: report2.backoffActive,
|
|
11063
|
+
until_ms: report2.untilMs
|
|
11064
|
+
});
|
|
10935
11065
|
span.end("error", {
|
|
10936
11066
|
attrs: {
|
|
10937
11067
|
outcome: "runner_credential_mint_failed",
|
|
@@ -10942,6 +11072,15 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
10942
11072
|
return false;
|
|
10943
11073
|
}
|
|
10944
11074
|
this.idleAgentConfigs.set(agentId, cached);
|
|
11075
|
+
const report = this.recordSpawnFailure(agentId, "spawn_error");
|
|
11076
|
+
this.recordDaemonTrace("daemon.agent.spawn.fail_backoff", {
|
|
11077
|
+
agentId,
|
|
11078
|
+
source: "runtime_profile_auto_restart",
|
|
11079
|
+
reason: "spawn_error",
|
|
11080
|
+
attempts: report.attempts,
|
|
11081
|
+
cooldown_active: report.backoffActive,
|
|
11082
|
+
until_ms: report.untilMs
|
|
11083
|
+
});
|
|
10945
11084
|
span.end("error", {
|
|
10946
11085
|
attrs: {
|
|
10947
11086
|
outcome: "restart_failed",
|
|
@@ -11535,6 +11674,21 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11535
11674
|
}
|
|
11536
11675
|
noteRuntimeProgress(ap, eventKind) {
|
|
11537
11676
|
ap.runtimeProgress.noteRuntimeEvent(eventKind);
|
|
11677
|
+
this.invalidateRecoveryErrorView(ap);
|
|
11678
|
+
}
|
|
11679
|
+
/**
|
|
11680
|
+
* Invalidate the decision-only error view on a liveness signal. The process is
|
|
11681
|
+
* alive and has moved past any error it logged earlier in the turn, so a stale
|
|
11682
|
+
* error must not keep restarting/re-routing a recovered agent. Error-class
|
|
11683
|
+
* agnostic; a genuinely current failure re-populates the view after this point.
|
|
11684
|
+
* Called on BOTH progress paths — ordinary runtime events and
|
|
11685
|
+
* `internal_progress` (raw runtime activity that stale-recovery already treats
|
|
11686
|
+
* as liveness). `recentStderr`/`lastRuntimeError` are untouched and stay full
|
|
11687
|
+
* for diagnostics, user-facing reporting, and sticky terminal-failure gating.
|
|
11688
|
+
*/
|
|
11689
|
+
invalidateRecoveryErrorView(ap) {
|
|
11690
|
+
ap.recentDecisionStderr = [];
|
|
11691
|
+
ap.runtimeErrorSinceProgress = false;
|
|
11538
11692
|
}
|
|
11539
11693
|
recordGatedSteeringEvent(agentId, ap, event, attrs = {}) {
|
|
11540
11694
|
if (ap.runtime.descriptor.busyDelivery !== "gated") return;
|
|
@@ -11725,6 +11879,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11725
11879
|
const terminalFailureDetail = classifyTerminalFailure(ap);
|
|
11726
11880
|
const detail = terminalFailureDetail?.detail ?? formatRuntimeStartTimeoutMessage(ap.driver.id);
|
|
11727
11881
|
ap.lastRuntimeError = detail;
|
|
11882
|
+
ap.runtimeErrorSinceProgress = true;
|
|
11728
11883
|
ap.runtimeProgress.markStale();
|
|
11729
11884
|
const staleForMs = Math.max(timeoutMs, ap.runtimeProgress.ageMs());
|
|
11730
11885
|
const diagnostic = buildRuntimeStallDiagnostic(ap, staleForMs, Math.max(1, Math.floor(staleForMs / 6e4)));
|
|
@@ -11879,6 +12034,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
11879
12034
|
}
|
|
11880
12035
|
if (event.kind === "internal_progress") {
|
|
11881
12036
|
ap.runtimeProgress.noteInternalProgress();
|
|
12037
|
+
this.invalidateRecoveryErrorView(ap);
|
|
11882
12038
|
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
11883
12039
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.progress.internal_observed", {
|
|
11884
12040
|
turn_outcome: "held",
|
|
@@ -12053,7 +12209,10 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
12053
12209
|
case "error": {
|
|
12054
12210
|
this.interruptCompactionIfActive(agentId);
|
|
12055
12211
|
this.flushPendingTrajectory(agentId);
|
|
12056
|
-
if (ap)
|
|
12212
|
+
if (ap) {
|
|
12213
|
+
ap.lastRuntimeError = event.message;
|
|
12214
|
+
ap.runtimeErrorSinceProgress = true;
|
|
12215
|
+
}
|
|
12057
12216
|
let visibleErrorMessage = event.message;
|
|
12058
12217
|
if (ap) {
|
|
12059
12218
|
const runtimeErrorDiagnostics = buildRuntimeErrorDiagnosticEnvelope(event.message);
|
package/dist/core.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slock-ai/daemon",
|
|
3
|
-
"version": "0.57.
|
|
3
|
+
"version": "0.57.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"slock-daemon": "dist/index.js"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"prepublishOnly": "pnpm run build",
|
|
32
32
|
"typecheck": "tsc --noEmit",
|
|
33
33
|
"generate:slock-cli-guide": "tsx scripts/generate-slock-cli-guide.ts",
|
|
34
|
-
"check:slock-cli-guide-fresh": "pnpm generate:slock-cli-guide && git diff --exit-code ../../
|
|
34
|
+
"check:slock-cli-guide-fresh": "pnpm generate:slock-cli-guide && git diff --exit-code ../../manual/agent-knowledge/slock-cli-overview.md",
|
|
35
35
|
"release:patch": "npm version patch --no-git-tag-version && cd ../.. && pnpm install --lockfile-only && git add packages/daemon/package.json pnpm-lock.yaml && git commit -m \"chore: bump @slock-ai/daemon to v$(node -p \"require('./packages/daemon/package.json').version\")\" && git tag daemon-v$(node -p \"require('./packages/daemon/package.json').version\") && git push && git push --tags",
|
|
36
36
|
"release:minor": "npm version minor --no-git-tag-version && cd ../.. && pnpm install --lockfile-only && git add packages/daemon/package.json pnpm-lock.yaml && git commit -m \"chore: bump @slock-ai/daemon to v$(node -p \"require('./packages/daemon/package.json').version\")\" && git tag daemon-v$(node -p \"require('./packages/daemon/package.json').version\") && git push && git push --tags",
|
|
37
37
|
"release:major": "npm version major --no-git-tag-version && cd ../.. && pnpm install --lockfile-only && git add packages/daemon/package.json pnpm-lock.yaml && git commit -m \"chore: bump @slock-ai/daemon to v$(node -p \"require('./packages/daemon/package.json').version\")\" && git tag daemon-v$(node -p \"require('./packages/daemon/package.json').version\") && git push && git push --tags",
|