@dorokuma/herdsman 0.9.0 → 0.11.5
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/README.ja.md +4 -2
- package/README.md +5 -3
- package/dist/src/agent-history/antigravity-proto.js +1 -1
- package/dist/src/agent-history/antigravity-proto.js.map +1 -1
- package/dist/src/agent-history/antigravity-reader.d.ts +13 -1
- package/dist/src/agent-history/antigravity-reader.d.ts.map +1 -1
- package/dist/src/agent-history/antigravity-reader.js +22 -1
- package/dist/src/agent-history/antigravity-reader.js.map +1 -1
- package/dist/src/agent-history/discovery.d.ts +8 -2
- package/dist/src/agent-history/discovery.d.ts.map +1 -1
- package/dist/src/agent-history/discovery.js +89 -9
- package/dist/src/agent-history/discovery.js.map +1 -1
- package/dist/src/agent-history/readers.d.ts +15 -1
- package/dist/src/agent-history/readers.d.ts.map +1 -1
- package/dist/src/agent-history/readers.js +77 -31
- package/dist/src/agent-history/readers.js.map +1 -1
- package/dist/src/agent-history/service.d.ts +4 -2
- package/dist/src/agent-history/service.d.ts.map +1 -1
- package/dist/src/agent-history/service.js +22 -22
- package/dist/src/agent-history/service.js.map +1 -1
- package/dist/src/agent-history/source-fingerprint.d.ts +7 -0
- package/dist/src/agent-history/source-fingerprint.d.ts.map +1 -0
- package/dist/src/agent-history/source-fingerprint.js +26 -0
- package/dist/src/agent-history/source-fingerprint.js.map +1 -0
- package/dist/src/agent-history/text.d.ts.map +1 -1
- package/dist/src/agent-history/text.js +5 -0
- package/dist/src/agent-history/text.js.map +1 -1
- package/dist/src/cli/herdsman.d.ts.map +1 -1
- package/dist/src/cli/herdsman.js +31 -9
- package/dist/src/cli/herdsman.js.map +1 -1
- package/dist/src/daemon/agent-event-reconciler.d.ts +25 -4
- package/dist/src/daemon/agent-event-reconciler.d.ts.map +1 -1
- package/dist/src/daemon/agent-event-reconciler.js +84 -6
- package/dist/src/daemon/agent-event-reconciler.js.map +1 -1
- package/dist/src/daemon/herdr-session-watch-manager.d.ts +1 -0
- package/dist/src/daemon/herdr-session-watch-manager.d.ts.map +1 -1
- package/dist/src/daemon/herdr-session-watch-manager.js +176 -55
- package/dist/src/daemon/herdr-session-watch-manager.js.map +1 -1
- package/dist/src/daemon/observability-server.d.ts +3 -0
- package/dist/src/daemon/observability-server.d.ts.map +1 -1
- package/dist/src/daemon/observability-server.js +73 -24
- package/dist/src/daemon/observability-server.js.map +1 -1
- package/dist/src/daemon/process-manager.d.ts +41 -2
- package/dist/src/daemon/process-manager.d.ts.map +1 -1
- package/dist/src/daemon/process-manager.js +340 -19
- package/dist/src/daemon/process-manager.js.map +1 -1
- package/dist/src/daemon/service.d.ts +46 -0
- package/dist/src/daemon/service.d.ts.map +1 -1
- package/dist/src/daemon/service.js +172 -12
- package/dist/src/daemon/service.js.map +1 -1
- package/dist/src/db/agent-events.d.ts +34 -1
- package/dist/src/db/agent-events.d.ts.map +1 -1
- package/dist/src/db/agent-events.js +168 -28
- package/dist/src/db/agent-events.js.map +1 -1
- package/dist/src/db/agent-history-cache.d.ts +4 -0
- package/dist/src/db/agent-history-cache.d.ts.map +1 -1
- package/dist/src/db/agent-history-cache.js +27 -0
- package/dist/src/db/agent-history-cache.js.map +1 -1
- package/dist/src/db/agent-orchestrator-scopes.d.ts +8 -0
- package/dist/src/db/agent-orchestrator-scopes.d.ts.map +1 -1
- package/dist/src/db/agent-orchestrator-scopes.js +13 -0
- package/dist/src/db/agent-orchestrator-scopes.js.map +1 -1
- package/dist/src/db/agents.d.ts +44 -0
- package/dist/src/db/agents.d.ts.map +1 -1
- package/dist/src/db/agents.js +91 -5
- package/dist/src/db/agents.js.map +1 -1
- package/dist/src/db/client.d.ts +1 -0
- package/dist/src/db/client.d.ts.map +1 -1
- package/dist/src/db/client.js +12 -0
- package/dist/src/db/client.js.map +1 -1
- package/dist/src/db/schema.d.ts +391 -0
- package/dist/src/db/schema.d.ts.map +1 -1
- package/dist/src/db/schema.js +34 -0
- package/dist/src/db/schema.js.map +1 -1
- package/dist/src/db/status-event-plans.d.ts +62 -0
- package/dist/src/db/status-event-plans.d.ts.map +1 -0
- package/dist/src/db/status-event-plans.js +147 -0
- package/dist/src/db/status-event-plans.js.map +1 -0
- package/dist/src/herdr/pane-identity-resolver.d.ts +4 -0
- package/dist/src/herdr/pane-identity-resolver.d.ts.map +1 -1
- package/dist/src/herdr/pane-identity-resolver.js +13 -1
- package/dist/src/herdr/pane-identity-resolver.js.map +1 -1
- package/dist/src/herdr/socket-client.d.ts +2 -0
- package/dist/src/herdr/socket-client.d.ts.map +1 -1
- package/dist/src/herdr/socket-client.js +64 -20
- package/dist/src/herdr/socket-client.js.map +1 -1
- package/dist/src/observability/agent-context-service.d.ts +17 -1
- package/dist/src/observability/agent-context-service.d.ts.map +1 -1
- package/dist/src/observability/agent-context-service.js +85 -21
- package/dist/src/observability/agent-context-service.js.map +1 -1
- package/dist/src/observability/agent-index-service.d.ts +47 -2
- package/dist/src/observability/agent-index-service.d.ts.map +1 -1
- package/dist/src/observability/agent-index-service.js +1125 -115
- package/dist/src/observability/agent-index-service.js.map +1 -1
- package/dist/src/observability/agent-orchestrator-service.d.ts.map +1 -1
- package/dist/src/observability/agent-orchestrator-service.js +34 -12
- package/dist/src/observability/agent-orchestrator-service.js.map +1 -1
- package/dist/src/observability/contracts.d.ts +2 -1
- package/dist/src/observability/contracts.d.ts.map +1 -1
- package/dist/src/observability/contracts.js.map +1 -1
- package/dist/src/observability/interactive-pi.d.ts +1 -1
- package/dist/src/observability/interactive-pi.d.ts.map +1 -1
- package/dist/src/observability/interactive-pi.js +1 -1
- package/dist/src/observability/interactive-pi.js.map +1 -1
- package/dist/src/observability/schemas.d.ts +1 -0
- package/dist/src/observability/schemas.d.ts.map +1 -1
- package/dist/src/observability/schemas.js +1 -0
- package/dist/src/observability/schemas.js.map +1 -1
- package/dist/src/observability/turn-completion.d.ts +2 -1
- package/dist/src/observability/turn-completion.d.ts.map +1 -1
- package/dist/src/observability/turn-completion.js +10 -1
- package/dist/src/observability/turn-completion.js.map +1 -1
- package/dist/src/shared/unix-peercred.d.ts +14 -0
- package/dist/src/shared/unix-peercred.d.ts.map +1 -0
- package/dist/src/shared/unix-peercred.js +144 -0
- package/dist/src/shared/unix-peercred.js.map +1 -0
- package/drizzle/0008_pane_tombstones.sql +9 -0
- package/drizzle/0009_high_lake.sql +24 -0
- package/drizzle/meta/0008_snapshot.json +823 -0
- package/drizzle/meta/0009_snapshot.json +975 -0
- package/drizzle/meta/_journal.json +14 -0
- package/package.json +24 -22
|
@@ -4,6 +4,7 @@ import { env, exit } from "node:process";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { createAgentHistoryService } from "../agent-history/service.js";
|
|
6
6
|
import { resolveRuntime } from "../config/runtime.js";
|
|
7
|
+
import { acquireDaemonLock, daemonInstanceLockPath, removeDaemonPidFile, writeDaemonPidFile, } from "../daemon/process-manager.js";
|
|
7
8
|
import { AgentContextSnapshotStore } from "../db/agent-context-snapshots.js";
|
|
8
9
|
import { AgentEventStore } from "../db/agent-events.js";
|
|
9
10
|
import { AgentHistoryCacheStore } from "../db/agent-history-cache.js";
|
|
@@ -13,6 +14,7 @@ import { applyMigrations } from "../db/apply-migrations.js";
|
|
|
13
14
|
import { openSqlite } from "../db/client.js";
|
|
14
15
|
import { HerdrSessionStore } from "../db/herdr-sessions.js";
|
|
15
16
|
import { HerdrWorkspaceStore } from "../db/herdr-workspaces.js";
|
|
17
|
+
import { StatusEventPlanStore } from "../db/status-event-plans.js";
|
|
16
18
|
import { createHerdrSessionListRunner } from "../herdr/session-list.js";
|
|
17
19
|
import { AgentContextService } from "../observability/agent-context-service.js";
|
|
18
20
|
import { AgentIndexService } from "../observability/agent-index-service.js";
|
|
@@ -21,6 +23,63 @@ import { TurnCompletionRegistry } from "../observability/turn-completion.js";
|
|
|
21
23
|
import { AgentEventReconciler } from "./agent-event-reconciler.js";
|
|
22
24
|
import { HerdrSessionWatchManager } from "./herdr-session-watch-manager.js";
|
|
23
25
|
import { ObservabilityRpcServer } from "./observability-server.js";
|
|
26
|
+
/**
|
|
27
|
+
* Periodic reconcile cadence. The 7-day (settled events) and 30-day (released
|
|
28
|
+
* scopes) TTLs only converge when AgentEventReconciler.reconcile runs, so the
|
|
29
|
+
* daemon drives it on a fixed 15-minute cycle instead of only at startup.
|
|
30
|
+
* 15 minutes is deliberately coarser than the watch manager's 10s/60s refresh
|
|
31
|
+
* ticks: reconcile opens sockets to every running Herdr session, while the TTLs
|
|
32
|
+
* it enforces are days long, so a 15-minute cycle converges promptly without
|
|
33
|
+
* per-tick socket traffic.
|
|
34
|
+
*/
|
|
35
|
+
export const RECONCILE_INTERVAL_MS = 15 * 60 * 1000;
|
|
36
|
+
/**
|
|
37
|
+
* Runs the reconcile cycle on a fixed cadence while guaranteeing at most one
|
|
38
|
+
* in-flight run: a tick that fires while the previous run is still executing is
|
|
39
|
+
* skipped. This mirrors HerdrSessionWatchManager's in-flight tick guard. SQLite
|
|
40
|
+
* writes on the daemon's single shared connection are synchronous, so the only
|
|
41
|
+
* concurrency hazard between periodic reconcile and live event writes would be
|
|
42
|
+
* two reconcile loops interleaving at their await points; the in-flight guard
|
|
43
|
+
* prevents that, keeping event writes and reconcile serialized exactly like the
|
|
44
|
+
* rest of the daemon.
|
|
45
|
+
*/
|
|
46
|
+
export class PeriodicReconcileScheduler {
|
|
47
|
+
#clearInterval;
|
|
48
|
+
#intervalMs;
|
|
49
|
+
#run;
|
|
50
|
+
#setInterval;
|
|
51
|
+
#handle;
|
|
52
|
+
#inFlight;
|
|
53
|
+
constructor(options) {
|
|
54
|
+
this.#clearInterval = options.clearInterval ?? clearInterval;
|
|
55
|
+
this.#intervalMs = options.intervalMs;
|
|
56
|
+
this.#run = options.run;
|
|
57
|
+
this.#setInterval = options.setInterval ?? setInterval;
|
|
58
|
+
}
|
|
59
|
+
start() {
|
|
60
|
+
if (this.#handle !== undefined)
|
|
61
|
+
return;
|
|
62
|
+
this.#handle = this.#setInterval(() => {
|
|
63
|
+
if (this.#inFlight)
|
|
64
|
+
return;
|
|
65
|
+
this.#inFlight = Promise.resolve()
|
|
66
|
+
.then(this.#run)
|
|
67
|
+
.catch((error) => {
|
|
68
|
+
console.warn("Herdsman periodic reconcile failed", error);
|
|
69
|
+
})
|
|
70
|
+
.finally(() => {
|
|
71
|
+
this.#inFlight = undefined;
|
|
72
|
+
});
|
|
73
|
+
}, this.#intervalMs);
|
|
74
|
+
}
|
|
75
|
+
async stop() {
|
|
76
|
+
if (this.#handle !== undefined) {
|
|
77
|
+
this.#clearInterval(this.#handle);
|
|
78
|
+
this.#handle = undefined;
|
|
79
|
+
}
|
|
80
|
+
await this.#inFlight?.catch(() => undefined);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
24
83
|
export async function runObservabilityDaemonService(input = {}) {
|
|
25
84
|
const runtime = resolveRuntime({ environment: input.environment });
|
|
26
85
|
applyEnvironment(runtime.environment);
|
|
@@ -49,6 +108,7 @@ export async function runObservabilityDaemonService(input = {}) {
|
|
|
49
108
|
const agentHistoryCache = new AgentHistoryCacheStore(sqlite);
|
|
50
109
|
const agentContextSnapshots = new AgentContextSnapshotStore(sqlite);
|
|
51
110
|
const agentOrchestratorScopes = new AgentOrchestratorScopeStore(sqlite);
|
|
111
|
+
const statusEventPlans = new StatusEventPlanStore(sqlite);
|
|
52
112
|
const history = createAgentHistoryService({ cache: agentHistoryCache });
|
|
53
113
|
const context = new AgentContextService({
|
|
54
114
|
history,
|
|
@@ -70,17 +130,23 @@ export async function runObservabilityDaemonService(input = {}) {
|
|
|
70
130
|
agents,
|
|
71
131
|
herdrSessions,
|
|
72
132
|
herdrWorkspaces,
|
|
133
|
+
sqlite,
|
|
134
|
+
statusEventPlans,
|
|
73
135
|
},
|
|
74
136
|
turnCompletions,
|
|
75
137
|
});
|
|
138
|
+
const sessionList = input.sessionList ?? createHerdrSessionListRunner({ env: runtime.environment });
|
|
76
139
|
let connectedTerminal = (_input) => false;
|
|
77
140
|
const reconciler = new AgentEventReconciler({
|
|
141
|
+
agentHistoryCache,
|
|
78
142
|
connectedTerminal: (input) => connectedTerminal(input),
|
|
79
143
|
events: agentEvents,
|
|
80
144
|
scopes: agentOrchestratorScopes,
|
|
81
|
-
sessionList
|
|
145
|
+
sessionList,
|
|
146
|
+
statusEventPlans,
|
|
82
147
|
});
|
|
83
148
|
const server = new ObservabilityRpcServer({
|
|
149
|
+
...(input.connectSocket !== undefined ? { connectSocket: input.connectSocket } : {}),
|
|
84
150
|
context: daemonServices.context,
|
|
85
151
|
history: daemonServices.history,
|
|
86
152
|
orchestrator,
|
|
@@ -97,20 +163,114 @@ export async function runObservabilityDaemonService(input = {}) {
|
|
|
97
163
|
onAgentContextChanged: (scope) => server.publishAgentContext(scope),
|
|
98
164
|
onAgentEvent: (event) => server.publishAgentEvent(event),
|
|
99
165
|
onAgentIndexRefreshed: (refreshed) => server.reconcileAgentLocations(refreshed),
|
|
100
|
-
sessionList
|
|
166
|
+
sessionList,
|
|
101
167
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
168
|
+
const onUnhandledRejection = (reason) => {
|
|
169
|
+
console.error("Herdsman daemon unhandled rejection", reason);
|
|
170
|
+
};
|
|
171
|
+
const onUncaughtException = (error) => {
|
|
172
|
+
console.error("Herdsman daemon uncaught exception", error);
|
|
173
|
+
};
|
|
174
|
+
process.on("unhandledRejection", onUnhandledRejection);
|
|
175
|
+
process.on("uncaughtException", onUncaughtException);
|
|
176
|
+
const currentPid = input.pid ?? process.pid;
|
|
177
|
+
const signalTarget = input.signalTarget ?? process;
|
|
178
|
+
const doExit = input.exit ?? exit;
|
|
179
|
+
// Register signal handlers before the first await that can block (server
|
|
180
|
+
// start, reconcile): once the pid file is written the daemon must always
|
|
181
|
+
// clean it up on a graceful shutdown, even if startup is still in progress.
|
|
182
|
+
let reconcileScheduler;
|
|
183
|
+
let releaseInstanceLock;
|
|
184
|
+
const releaseInstanceLockIfHeld = () => {
|
|
185
|
+
if (releaseInstanceLock) {
|
|
186
|
+
releaseInstanceLock();
|
|
187
|
+
releaseInstanceLock = undefined;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
106
190
|
const stop = async () => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
191
|
+
let exitCode = 0;
|
|
192
|
+
try {
|
|
193
|
+
process.off("unhandledRejection", onUnhandledRejection);
|
|
194
|
+
process.off("uncaughtException", onUncaughtException);
|
|
195
|
+
index.stopWaitingHistoryRetries();
|
|
196
|
+
await index.drainInFlightPlans();
|
|
197
|
+
await reconcileScheduler?.stop();
|
|
198
|
+
await watchManager.stop();
|
|
199
|
+
await server.stop();
|
|
200
|
+
sqlite.close();
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
console.error("Herdsman daemon shutdown failed", error);
|
|
204
|
+
exitCode = 1;
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
removeDaemonPidFile(runtime.paths.pidPath, currentPid);
|
|
208
|
+
releaseInstanceLockIfHeld();
|
|
209
|
+
doExit(exitCode);
|
|
210
|
+
}
|
|
111
211
|
};
|
|
112
|
-
|
|
113
|
-
|
|
212
|
+
signalTarget.once("SIGINT", stop);
|
|
213
|
+
signalTarget.once("SIGTERM", stop);
|
|
214
|
+
try {
|
|
215
|
+
// The bare daemon entrypoint (herdsman-daemon.js) takes an instance lock
|
|
216
|
+
// distinct from the CLI operation lock so two daemon processes cannot
|
|
217
|
+
// share one HERDSMAN_HOME even when neither goes through the CLI. The lock
|
|
218
|
+
// is released on graceful stop and on every startup failure path.
|
|
219
|
+
releaseInstanceLock = acquireDaemonLock(daemonInstanceLockPath(runtime.paths.pidPath), {
|
|
220
|
+
pid: currentPid,
|
|
221
|
+
});
|
|
222
|
+
await server.start();
|
|
223
|
+
writeDaemonPidFile(runtime.paths.pidPath, currentPid);
|
|
224
|
+
await reconciler.reconcile({ releaseStaleOwners: false });
|
|
225
|
+
await index.drainPendingPlans();
|
|
226
|
+
// Periodic reconcile keeps the 7-day/30-day TTLs converging on long-running
|
|
227
|
+
// daemons; the in-flight guard inside the scheduler prevents overlapping runs.
|
|
228
|
+
reconcileScheduler = new PeriodicReconcileScheduler({
|
|
229
|
+
...(input.reconcileClearInterval === undefined
|
|
230
|
+
? {}
|
|
231
|
+
: { clearInterval: input.reconcileClearInterval }),
|
|
232
|
+
intervalMs: input.reconcileIntervalMs ?? RECONCILE_INTERVAL_MS,
|
|
233
|
+
// Long-lived daemons must also keep retrying runtime-failed status event
|
|
234
|
+
// plans: drainPendingPlans is idempotent (pending/running rows only,
|
|
235
|
+
// per-agent serial, attempts capped) and the periodic cadence prevents a
|
|
236
|
+
// hot loop, so piggybacking it on the reconcile cycle completes the retry
|
|
237
|
+
// path that the startup-only drain leaves open.
|
|
238
|
+
run: async () => {
|
|
239
|
+
await reconciler.reconcile({ releaseStaleOwners: false });
|
|
240
|
+
await index.drainPendingPlans();
|
|
241
|
+
},
|
|
242
|
+
...(input.reconcileSetInterval === undefined
|
|
243
|
+
? {}
|
|
244
|
+
: { setInterval: input.reconcileSetInterval }),
|
|
245
|
+
});
|
|
246
|
+
reconcileScheduler.start();
|
|
247
|
+
await watchManager.start();
|
|
248
|
+
console.log(`Herdsman daemon listening on ${runtime.paths.socketPath}`);
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
process.off("unhandledRejection", onUnhandledRejection);
|
|
252
|
+
process.off("uncaughtException", onUncaughtException);
|
|
253
|
+
if (typeof signalTarget.off === "function") {
|
|
254
|
+
signalTarget.off("SIGINT", stop);
|
|
255
|
+
signalTarget.off("SIGTERM", stop);
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
await reconcileScheduler?.stop();
|
|
259
|
+
}
|
|
260
|
+
catch { }
|
|
261
|
+
try {
|
|
262
|
+
await watchManager.stop();
|
|
263
|
+
}
|
|
264
|
+
catch { }
|
|
265
|
+
try {
|
|
266
|
+
await server.stop();
|
|
267
|
+
}
|
|
268
|
+
catch { }
|
|
269
|
+
removeDaemonPidFile(runtime.paths.pidPath, currentPid);
|
|
270
|
+
releaseInstanceLockIfHeld();
|
|
271
|
+
sqlite.close();
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
114
274
|
}
|
|
115
275
|
export function resolveMigrationsFolder(startDir) {
|
|
116
276
|
let current = resolve(startDir);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/daemon/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/daemon/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import type { DatabaseSync } from "node:sqlite";
|
|
2
2
|
import type { AgentEventRecord, AgentEventType, AgentIndexRecord, AgentQueryScope, CompactAgentHistory } from "../observability/contracts.js";
|
|
3
|
+
/**
|
|
4
|
+
* A delivered event is re-listed for the same owner terminal only within this
|
|
5
|
+
* freshness window after its last delivery attempt. The window covers the
|
|
6
|
+
* crash/redelivery path (an extension that missed the first delivery re-fetches
|
|
7
|
+
* it right after reconnecting) while preventing an unacked delivered event from
|
|
8
|
+
* being re-returned indefinitely on every orchestrator.get, which would feed
|
|
9
|
+
* duplicate presentations whenever the extension's local dedup state is lost.
|
|
10
|
+
*/
|
|
11
|
+
export declare const REDELIVERY_FRESHNESS_MS = 300000;
|
|
12
|
+
/**
|
|
13
|
+
* Persist interval for the monotonic logical clock. The clock is written to
|
|
14
|
+
* daemon_meta only when it advances by at least this much since the last
|
|
15
|
+
* persist, so read-only queries do not trigger a write+fsync on every call.
|
|
16
|
+
* The freshness window is 300s, so a 60s persist granularity does not weaken
|
|
17
|
+
* the anti-rollback semantics.
|
|
18
|
+
*/
|
|
19
|
+
export declare const LOGICAL_CLOCK_PERSIST_INTERVAL_MS = 60000;
|
|
20
|
+
export declare const LOGICAL_CLOCK_META_KEY = "logical_now_ms";
|
|
21
|
+
export declare function hasNonEmptyAssistantMessage(compactHistory: CompactAgentHistory | null | undefined): boolean;
|
|
3
22
|
/** The single delivery predicate shared by pending discovery and acknowledgement. */
|
|
4
23
|
export declare function isDeliverableAgentEvent(event: AgentEventRecord, agent: AgentIndexRecord | undefined, scope: {
|
|
5
24
|
herdrSessionName: string;
|
|
@@ -50,7 +69,19 @@ export declare class AgentEventStore {
|
|
|
50
69
|
}): void;
|
|
51
70
|
listReconcileCandidates(limit?: number, afterId?: number): AgentEventRecord[];
|
|
52
71
|
deleteReconcileCandidate(id: number): boolean;
|
|
53
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Physically removes invalidated events older than the given age, measured from
|
|
74
|
+
* coalesce(last_attempt_at, created_at) so a delivered-then-invalidated event is
|
|
75
|
+
* aged from its last delivery. A short grace window lets the owner that already
|
|
76
|
+
* received the event ack it and advance the cursor.
|
|
77
|
+
*/
|
|
78
|
+
deleteInvalidatedOlderThan(ageMs: number): number;
|
|
79
|
+
/**
|
|
80
|
+
* Physically removes terminal events (acked/failed) older than the given age.
|
|
81
|
+
* These statuses are never redelivered or reconciled, so a periodic TTL bounds
|
|
82
|
+
* the table's growth without touching pending/delivered/invalidated rows.
|
|
83
|
+
*/
|
|
84
|
+
deleteSettledOlderThan(ageMs: number): number;
|
|
54
85
|
ackSelfOwned(input: {
|
|
55
86
|
herdrSessionName: string;
|
|
56
87
|
workspaceId: string;
|
|
@@ -58,6 +89,8 @@ export declare class AgentEventStore {
|
|
|
58
89
|
}): number;
|
|
59
90
|
invalidateById(id: number, reason: string): boolean;
|
|
60
91
|
latestStatusTransition(agentId: string, herdrSessionName: string): AgentEventRecord | undefined;
|
|
92
|
+
hasTerminalEventAfter(agentId: string, herdrSessionName: string, afterId: number): boolean;
|
|
93
|
+
latestTerminalEvent(agentId: string, herdrSessionName: string): AgentEventRecord | undefined;
|
|
61
94
|
listAfter(input: AgentQueryScope & {
|
|
62
95
|
afterEventId?: number;
|
|
63
96
|
limit?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-events.d.ts","sourceRoot":"","sources":["../../../src/db/agent-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAGtC,qFAAqF;AACrF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,gBAAgB,GAAG,SAAS,EACnC,KAAK,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EACxD,eAAe,EAAE,MAAM,GACtB,OAAO,
|
|
1
|
+
{"version":3,"file":"agent-events.d.ts","sourceRoot":"","sources":["../../../src/db/agent-events.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,24 +1,51 @@
|
|
|
1
1
|
import { isInteractivePiAgent } from "../observability/interactive-pi.js";
|
|
2
|
+
/**
|
|
3
|
+
* A delivered event is re-listed for the same owner terminal only within this
|
|
4
|
+
* freshness window after its last delivery attempt. The window covers the
|
|
5
|
+
* crash/redelivery path (an extension that missed the first delivery re-fetches
|
|
6
|
+
* it right after reconnecting) while preventing an unacked delivered event from
|
|
7
|
+
* being re-returned indefinitely on every orchestrator.get, which would feed
|
|
8
|
+
* duplicate presentations whenever the extension's local dedup state is lost.
|
|
9
|
+
*/
|
|
10
|
+
export const REDELIVERY_FRESHNESS_MS = 300_000;
|
|
11
|
+
/**
|
|
12
|
+
* Persist interval for the monotonic logical clock. The clock is written to
|
|
13
|
+
* daemon_meta only when it advances by at least this much since the last
|
|
14
|
+
* persist, so read-only queries do not trigger a write+fsync on every call.
|
|
15
|
+
* The freshness window is 300s, so a 60s persist granularity does not weaken
|
|
16
|
+
* the anti-rollback semantics.
|
|
17
|
+
*/
|
|
18
|
+
export const LOGICAL_CLOCK_PERSIST_INTERVAL_MS = 60_000;
|
|
19
|
+
export const LOGICAL_CLOCK_META_KEY = "logical_now_ms";
|
|
20
|
+
export function hasNonEmptyAssistantMessage(compactHistory) {
|
|
21
|
+
const text = compactHistory?.lastAssistantMessage?.text;
|
|
22
|
+
return typeof text === "string" && text.trim().length > 0;
|
|
23
|
+
}
|
|
2
24
|
/** The single delivery predicate shared by pending discovery and acknowledgement. */
|
|
3
25
|
export function isDeliverableAgentEvent(event, agent, scope, ownerTerminalId) {
|
|
26
|
+
const failed = event.type === "agent.failed";
|
|
4
27
|
return ((event.status === "pending" || event.status === "delivered") &&
|
|
5
28
|
(event.status === "delivered" ||
|
|
6
29
|
event.nextAttemptAt === null ||
|
|
7
30
|
event.nextAttemptAt === undefined ||
|
|
8
31
|
event.nextAttemptAt <= new Date()) &&
|
|
9
32
|
(event.status === "pending" || event.deliveredToTerminalId === ownerTerminalId) &&
|
|
10
|
-
event.agentId !== null &&
|
|
11
|
-
agent !== undefined &&
|
|
33
|
+
(failed || event.agentId !== null) &&
|
|
12
34
|
event.type !== "agent.status.changed" &&
|
|
13
35
|
!(event.type === "agent.idle" && asRecord(event.payload).from !== "working") &&
|
|
14
|
-
!(isInteractivePiAgent(agent) && event.type === "agent.idle") &&
|
|
15
|
-
agent.paneId === event.paneId &&
|
|
16
|
-
(event.paneGeneration === null || agent.paneGeneration === event.paneGeneration) &&
|
|
17
|
-
agent.workspaceId === scope.workspaceId &&
|
|
18
36
|
event.workspaceId === scope.workspaceId &&
|
|
19
37
|
event.herdrSessionName === scope.herdrSessionName &&
|
|
20
38
|
event.terminalId !== null &&
|
|
21
|
-
event.terminalId !== ownerTerminalId
|
|
39
|
+
event.terminalId !== ownerTerminalId &&
|
|
40
|
+
(failed ||
|
|
41
|
+
(agent !== undefined &&
|
|
42
|
+
!(isInteractivePiAgent(agent) && event.type === "agent.idle") &&
|
|
43
|
+
!(agent.agent !== "pi" &&
|
|
44
|
+
(event.type === "agent.idle" || event.type === "agent.done") &&
|
|
45
|
+
!hasNonEmptyAssistantMessage(event.compactHistory)) &&
|
|
46
|
+
agent.paneId === event.paneId &&
|
|
47
|
+
(event.paneGeneration === null || agent.paneGeneration === event.paneGeneration) &&
|
|
48
|
+
agent.workspaceId === scope.workspaceId)));
|
|
22
49
|
}
|
|
23
50
|
function asRecord(value) {
|
|
24
51
|
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
@@ -27,8 +54,39 @@ function asRecord(value) {
|
|
|
27
54
|
}
|
|
28
55
|
export class AgentEventStore {
|
|
29
56
|
#sqlite;
|
|
57
|
+
#lastPersistedLogicalNowMs;
|
|
58
|
+
#logicalNowMs;
|
|
30
59
|
constructor(sqlite) {
|
|
31
60
|
this.#sqlite = sqlite;
|
|
61
|
+
const row = this.#sqlite
|
|
62
|
+
.prepare("select value from daemon_meta where key = ?")
|
|
63
|
+
.get(LOGICAL_CLOCK_META_KEY);
|
|
64
|
+
const persisted = row ? Number(row.value) : 0;
|
|
65
|
+
this.#logicalNowMs = Number.isFinite(persisted) && persisted > 0 ? persisted : 0;
|
|
66
|
+
this.#lastPersistedLogicalNowMs = this.#logicalNowMs;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Monotonic logical clock: never goes backwards, even when the wall clock
|
|
70
|
+
* is rolled back. The in-memory value is seeded from daemon_meta on
|
|
71
|
+
* construction and advanced to the wall clock when the wall clock is ahead.
|
|
72
|
+
* Persistence is throttled so read-only queries do not write+fsync every
|
|
73
|
+
* call; on crash the persisted value is only ever stale (never ahead of the
|
|
74
|
+
* last persisted value), so the anti-rollback invariant holds across
|
|
75
|
+
* restarts.
|
|
76
|
+
*/
|
|
77
|
+
#now() {
|
|
78
|
+
const wallClock = Date.now();
|
|
79
|
+
if (wallClock <= this.#logicalNowMs)
|
|
80
|
+
return this.#logicalNowMs;
|
|
81
|
+
this.#logicalNowMs = wallClock;
|
|
82
|
+
if (this.#logicalNowMs - this.#lastPersistedLogicalNowMs >= LOGICAL_CLOCK_PERSIST_INTERVAL_MS) {
|
|
83
|
+
this.#lastPersistedLogicalNowMs = this.#logicalNowMs;
|
|
84
|
+
this.#sqlite
|
|
85
|
+
.prepare(`insert into daemon_meta (key, value) values (?, ?)
|
|
86
|
+
on conflict(key) do update set value = excluded.value`)
|
|
87
|
+
.run(LOGICAL_CLOCK_META_KEY, String(this.#logicalNowMs));
|
|
88
|
+
}
|
|
89
|
+
return this.#logicalNowMs;
|
|
32
90
|
}
|
|
33
91
|
append(input) {
|
|
34
92
|
const existing = input.idempotencyKey
|
|
@@ -42,7 +100,7 @@ export class AgentEventStore {
|
|
|
42
100
|
.prepare(`insert into agent_events
|
|
43
101
|
(herdr_session_name, agent_id, pane_id, pane_generation, workspace_id, terminal_id, type, payload_json, compact_history_json, idempotency_key, deliverable, status, delivery_attempts, created_at)
|
|
44
102
|
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 'pending', 0, ?)`)
|
|
45
|
-
.run(input.herdrSessionName, input.agentId ?? null, input.paneId ?? null, input.paneGeneration ?? null, input.workspaceId ?? null, input.terminalId ?? null, input.type, JSON.stringify(input.payload), input.compactHistory ? JSON.stringify(input.compactHistory) : null, input.idempotencyKey ?? null,
|
|
103
|
+
.run(input.herdrSessionName, input.agentId ?? null, input.paneId ?? null, input.paneGeneration ?? null, input.workspaceId ?? null, input.terminalId ?? null, input.type, JSON.stringify(input.payload), input.compactHistory ? JSON.stringify(input.compactHistory) : null, input.idempotencyKey ?? null, this.#now());
|
|
46
104
|
return this.get(Number(result.lastInsertRowid));
|
|
47
105
|
}
|
|
48
106
|
invalidatePane(input) {
|
|
@@ -65,8 +123,27 @@ export class AgentEventStore {
|
|
|
65
123
|
.prepare("delete from agent_events where id = ? and status in ('pending', 'delivered')")
|
|
66
124
|
.run(id).changes) > 0);
|
|
67
125
|
}
|
|
68
|
-
|
|
69
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Physically removes invalidated events older than the given age, measured from
|
|
128
|
+
* coalesce(last_attempt_at, created_at) so a delivered-then-invalidated event is
|
|
129
|
+
* aged from its last delivery. A short grace window lets the owner that already
|
|
130
|
+
* received the event ack it and advance the cursor.
|
|
131
|
+
*/
|
|
132
|
+
deleteInvalidatedOlderThan(ageMs) {
|
|
133
|
+
return Number(this.#sqlite
|
|
134
|
+
.prepare(`delete from agent_events
|
|
135
|
+
where status = 'invalidated' and coalesce(last_attempt_at, created_at) < ?`)
|
|
136
|
+
.run(Date.now() - ageMs).changes);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Physically removes terminal events (acked/failed) older than the given age.
|
|
140
|
+
* These statuses are never redelivered or reconciled, so a periodic TTL bounds
|
|
141
|
+
* the table's growth without touching pending/delivered/invalidated rows.
|
|
142
|
+
*/
|
|
143
|
+
deleteSettledOlderThan(ageMs) {
|
|
144
|
+
return Number(this.#sqlite
|
|
145
|
+
.prepare(`delete from agent_events where status in ('acked', 'failed') and created_at < ?`)
|
|
146
|
+
.run(Date.now() - ageMs).changes);
|
|
70
147
|
}
|
|
71
148
|
ackSelfOwned(input) {
|
|
72
149
|
return Number(this.#sqlite
|
|
@@ -88,16 +165,35 @@ export class AgentEventStore {
|
|
|
88
165
|
.get(agentId, herdrSessionName);
|
|
89
166
|
return row ? mapAgentEvent(row) : undefined;
|
|
90
167
|
}
|
|
168
|
+
hasTerminalEventAfter(agentId, herdrSessionName, afterId) {
|
|
169
|
+
const row = this.#sqlite
|
|
170
|
+
.prepare(`select 1 from agent_events
|
|
171
|
+
where agent_id = ? and herdr_session_name = ? and id > ?
|
|
172
|
+
and type in ('agent.idle', 'agent.done', 'agent.blocked')
|
|
173
|
+
limit 1`)
|
|
174
|
+
.get(agentId, herdrSessionName, afterId);
|
|
175
|
+
return Boolean(row);
|
|
176
|
+
}
|
|
177
|
+
latestTerminalEvent(agentId, herdrSessionName) {
|
|
178
|
+
const row = this.#sqlite
|
|
179
|
+
.prepare(`select * from agent_events
|
|
180
|
+
where agent_id = ? and herdr_session_name = ?
|
|
181
|
+
and type in ('agent.idle', 'agent.done', 'agent.blocked')
|
|
182
|
+
order by id desc limit 1`)
|
|
183
|
+
.get(agentId, herdrSessionName);
|
|
184
|
+
return row ? mapAgentEvent(row) : undefined;
|
|
185
|
+
}
|
|
91
186
|
listAfter(input) {
|
|
92
187
|
const clauses = [
|
|
93
188
|
"id > ?",
|
|
94
|
-
"((status = 'pending' and (next_attempt_at is null or next_attempt_at <= ?)) or (status = 'delivered' and delivered_to_terminal_id = ? and id > ?))",
|
|
189
|
+
"((status = 'pending' and (next_attempt_at is null or next_attempt_at <= ?)) or (status = 'delivered' and delivered_to_terminal_id = ? and id > ? and last_attempt_at >= ?))",
|
|
95
190
|
];
|
|
96
191
|
const params = [
|
|
97
192
|
input.afterEventId ?? 0,
|
|
98
|
-
|
|
193
|
+
this.#now(),
|
|
99
194
|
input.ownerTerminalId ?? null,
|
|
100
195
|
input.afterEventId ?? 0,
|
|
196
|
+
this.#now() - REDELIVERY_FRESHNESS_MS,
|
|
101
197
|
];
|
|
102
198
|
if (input.herdrSessionName) {
|
|
103
199
|
clauses.push("herdr_session_name = ?");
|
|
@@ -128,15 +224,16 @@ export class AgentEventStore {
|
|
|
128
224
|
for (let page = 0; page < 50; page += 1) {
|
|
129
225
|
const params = [
|
|
130
226
|
afterEventId,
|
|
131
|
-
|
|
227
|
+
this.#now(),
|
|
132
228
|
input.ownerTerminalId,
|
|
229
|
+
this.#now() - REDELIVERY_FRESHNESS_MS,
|
|
133
230
|
input.herdrSessionName,
|
|
134
231
|
input.workspaceId,
|
|
135
232
|
input.ownerTerminalId,
|
|
136
233
|
];
|
|
137
234
|
const rows = this.#sqlite
|
|
138
235
|
.prepare(`select * from agent_events
|
|
139
|
-
where id > ? and ((status = 'pending' and (next_attempt_at is null or next_attempt_at <= ?)) or (status = 'delivered' and delivered_to_terminal_id = ?)) and herdr_session_name = ? and workspace_id = ?
|
|
236
|
+
where id > ? and ((status = 'pending' and (next_attempt_at is null or next_attempt_at <= ?)) or (status = 'delivered' and delivered_to_terminal_id = ? and last_attempt_at >= ?)) and herdr_session_name = ? and workspace_id = ?
|
|
140
237
|
and terminal_id is not null and terminal_id != ? and agent_id is not null
|
|
141
238
|
${agentFilter}
|
|
142
239
|
order by id asc limit 1000`)
|
|
@@ -158,14 +255,14 @@ export class AgentEventStore {
|
|
|
158
255
|
}
|
|
159
256
|
reservePending(terminalId, limit = 100, ids) {
|
|
160
257
|
return this.#transaction(() => {
|
|
161
|
-
const now =
|
|
258
|
+
const now = this.#now();
|
|
162
259
|
const idClause = ids && ids.length > 0 ? `and id in (${ids.map(() => "?").join(",")})` : "";
|
|
163
|
-
const params = [now, terminalId];
|
|
260
|
+
const params = [now, terminalId, now - REDELIVERY_FRESHNESS_MS];
|
|
164
261
|
if (ids && ids.length > 0)
|
|
165
262
|
params.push(...ids);
|
|
166
263
|
params.push(limit);
|
|
167
264
|
const rows = this.#sqlite
|
|
168
|
-
.prepare(`select * from agent_events where ((status = 'pending' and (next_attempt_at is null or next_attempt_at <= ?)) or (status = 'delivered' and delivered_to_terminal_id = ?)) ${idClause} order by id asc limit ?`)
|
|
265
|
+
.prepare(`select * from agent_events where ((status = 'pending' and (next_attempt_at is null or next_attempt_at <= ?)) or (status = 'delivered' and delivered_to_terminal_id = ? and last_attempt_at >= ?)) ${idClause} order by id asc limit ?`)
|
|
169
266
|
.all(...params);
|
|
170
267
|
for (const row of rows) {
|
|
171
268
|
this.#sqlite
|
|
@@ -185,18 +282,61 @@ export class AgentEventStore {
|
|
|
185
282
|
}
|
|
186
283
|
reclaimDelivered(timeoutMs) {
|
|
187
284
|
return this.#transaction(() => {
|
|
188
|
-
const
|
|
189
|
-
|
|
285
|
+
const cutoff = this.#now() - timeoutMs;
|
|
286
|
+
// The delivered event's own agent row (matched by pane) is the pane-open
|
|
287
|
+
// guard: it decides whether branch (a) and branch (b) apply.
|
|
288
|
+
const agentPaneOpen = `exists (
|
|
289
|
+
select 1 from agents
|
|
290
|
+
where agents.id = agent_events.agent_id
|
|
291
|
+
and agents.herdr_session_name = agent_events.herdr_session_name
|
|
292
|
+
and agents.workspace_id = agent_events.workspace_id
|
|
293
|
+
and agents.pane_id = agent_events.pane_id
|
|
294
|
+
)`;
|
|
295
|
+
// Branch (b): the agent pane is closed/retired, so the delivered event is
|
|
296
|
+
// invalidated instead of being reclaimed and redelivered.
|
|
297
|
+
const invalidated = this.#sqlite
|
|
298
|
+
.prepare(`update agent_events
|
|
299
|
+
set deliverable = 0, status = 'invalidated', invalidated_reason = 'PANE_CLOSED_RECLAIM'
|
|
300
|
+
where status = 'delivered' and last_attempt_at < ? and not ${agentPaneOpen}`)
|
|
301
|
+
.run(cutoff).changes;
|
|
302
|
+
// Branch (c): the pane is still open but the delivery terminal no longer
|
|
303
|
+
// holds the orchestrator scope (owner_terminal_id != delivered_to_terminal_id
|
|
304
|
+
// or no owner), so reclaim immediately without waiting for last_attempt_at
|
|
305
|
+
// timeout. If the scope is still owned by the delivery terminal (branch a),
|
|
306
|
+
// the event remains in-flight with the owner.
|
|
307
|
+
const reclaimWhere = `status = 'delivered'
|
|
308
|
+
and ${agentPaneOpen}
|
|
190
309
|
and not exists (
|
|
191
|
-
select 1 from
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
and
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
310
|
+
select 1 from agent_orchestrator_scopes
|
|
311
|
+
where agent_orchestrator_scopes.herdr_session_name = agent_events.herdr_session_name
|
|
312
|
+
and agent_orchestrator_scopes.workspace_id = agent_events.workspace_id
|
|
313
|
+
and agent_orchestrator_scopes.owner_terminal_id = agent_events.delivered_to_terminal_id
|
|
314
|
+
)`;
|
|
315
|
+
const exceeded = this.#sqlite
|
|
316
|
+
.prepare(`select id, agent_id, herdr_session_name, workspace_id, delivery_attempts
|
|
317
|
+
from agent_events
|
|
318
|
+
where ${reclaimWhere} and delivery_attempts >= 10`)
|
|
319
|
+
.all();
|
|
320
|
+
const reclaimed = this.#sqlite
|
|
321
|
+
.prepare(`update agent_events
|
|
322
|
+
set status = case when delivery_attempts >= 10 then 'failed' else 'pending' end,
|
|
323
|
+
deliverable = case when delivery_attempts >= 10 then 0 else 1 end,
|
|
324
|
+
last_failure_code = case when delivery_attempts >= 10 then 'DELIVERY_ATTEMPTS_EXCEEDED' else last_failure_code end,
|
|
325
|
+
delivered_to_terminal_id = null,
|
|
326
|
+
next_attempt_at = null
|
|
327
|
+
where ${reclaimWhere}`)
|
|
328
|
+
.run().changes;
|
|
329
|
+
for (const row of exceeded) {
|
|
330
|
+
console.error("Herdsman agent event delivery attempts exceeded", {
|
|
331
|
+
eventId: row.id,
|
|
332
|
+
agentId: row.agent_id,
|
|
333
|
+
herdrSessionName: row.herdr_session_name,
|
|
334
|
+
workspaceId: row.workspace_id,
|
|
335
|
+
deliveryAttempts: row.delivery_attempts,
|
|
336
|
+
lastFailureCode: "DELIVERY_ATTEMPTS_EXCEEDED",
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
return Number(invalidated) + Number(reclaimed);
|
|
200
340
|
});
|
|
201
341
|
}
|
|
202
342
|
markAcked(id, scope) {
|