@schlessera/brain-ui-server 0.34.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/activity/notify.d.ts.map +1 -1
- package/dist/activity/notify.js +18 -8
- package/dist/activity/notify.js.map +1 -1
- package/dist/activity/push-sender.d.ts +7 -3
- package/dist/activity/push-sender.d.ts.map +1 -1
- package/dist/activity/push-sender.js +45 -11
- package/dist/activity/push-sender.js.map +1 -1
- package/dist/activity/query.d.ts.map +1 -1
- package/dist/activity/query.js +8 -0
- package/dist/activity/query.js.map +1 -1
- package/dist/activity/recorder.d.ts +11 -1
- package/dist/activity/recorder.d.ts.map +1 -1
- package/dist/activity/recorder.js +52 -2
- package/dist/activity/recorder.js.map +1 -1
- package/dist/activity/runtime.d.ts.map +1 -1
- package/dist/activity/runtime.js +2 -5
- package/dist/activity/runtime.js.map +1 -1
- package/dist/activity/sql.d.ts +34 -0
- package/dist/activity/sql.d.ts.map +1 -0
- package/dist/activity/sql.js +114 -0
- package/dist/activity/sql.js.map +1 -0
- package/dist/activity/store.d.ts +7 -0
- package/dist/activity/store.d.ts.map +1 -1
- package/dist/activity/store.js +48 -113
- package/dist/activity/store.js.map +1 -1
- package/dist/activity/stream.d.ts +3 -1
- package/dist/activity/stream.d.ts.map +1 -1
- package/dist/activity/stream.js +32 -17
- package/dist/activity/stream.js.map +1 -1
- package/dist/app-env.d.ts +8 -0
- package/dist/app-env.d.ts.map +1 -0
- package/dist/app-env.js +2 -0
- package/dist/app-env.js.map +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +28 -3
- package/dist/app.js.map +1 -1
- package/dist/brain/client.d.ts +4 -2
- package/dist/brain/client.d.ts.map +1 -1
- package/dist/brain/client.js +60 -20
- package/dist/brain/client.js.map +1 -1
- package/dist/brain/types.d.ts +9 -0
- package/dist/brain/types.d.ts.map +1 -1
- package/dist/cron/run-job.d.ts.map +1 -1
- package/dist/cron/run-job.js +60 -10
- package/dist/cron/run-job.js.map +1 -1
- package/dist/db/principals.d.ts +72 -0
- package/dist/db/principals.d.ts.map +1 -0
- package/dist/db/principals.js +294 -0
- package/dist/db/principals.js.map +1 -0
- package/dist/files/walker.d.ts.map +1 -1
- package/dist/files/walker.js +6 -1
- package/dist/files/walker.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/auth.d.ts +37 -9
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +148 -74
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/passkeys.d.ts +9 -7
- package/dist/middleware/passkeys.d.ts.map +1 -1
- package/dist/middleware/passkeys.js +25 -7
- package/dist/middleware/passkeys.js.map +1 -1
- package/dist/middleware/principals.d.ts +18 -0
- package/dist/middleware/principals.d.ts.map +1 -0
- package/dist/middleware/principals.js +138 -0
- package/dist/middleware/principals.js.map +1 -0
- package/dist/middleware/require-owner.d.ts +5 -0
- package/dist/middleware/require-owner.d.ts.map +1 -0
- package/dist/middleware/require-owner.js +10 -0
- package/dist/middleware/require-owner.js.map +1 -0
- package/dist/observability/loggers.js +1 -1
- package/dist/observability/loggers.js.map +1 -1
- package/dist/routes/activity.d.ts.map +1 -1
- package/dist/routes/activity.js +3 -0
- package/dist/routes/activity.js.map +1 -1
- package/dist/routes/brain.d.ts.map +1 -1
- package/dist/routes/brain.js +102 -63
- package/dist/routes/brain.js.map +1 -1
- package/dist/routes/files.d.ts.map +1 -1
- package/dist/routes/files.js +7 -2
- package/dist/routes/files.js.map +1 -1
- package/dist/routes/push.d.ts +61 -2
- package/dist/routes/push.d.ts.map +1 -1
- package/dist/routes/push.js +8 -3
- package/dist/routes/push.js.map +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +30 -4
- package/dist/routes/sessions.js.map +1 -1
- package/dist/share/staging.d.ts.map +1 -1
- package/dist/share/staging.js +11 -4
- package/dist/share/staging.js.map +1 -1
- package/dist/ws/bridge.d.ts.map +1 -1
- package/dist/ws/bridge.js +6 -2
- package/dist/ws/bridge.js.map +1 -1
- package/dist/ws/clients.d.ts +9 -2
- package/dist/ws/clients.d.ts.map +1 -1
- package/dist/ws/clients.js +44 -6
- package/dist/ws/clients.js.map +1 -1
- package/dist/ws/connection.d.ts +7 -4
- package/dist/ws/connection.d.ts.map +1 -1
- package/dist/ws/connection.js +83 -12
- package/dist/ws/connection.js.map +1 -1
- package/dist/ws/dispatch.d.ts +12 -1
- package/dist/ws/dispatch.d.ts.map +1 -1
- package/dist/ws/dispatch.js +46 -6
- package/dist/ws/dispatch.js.map +1 -1
- package/dist/ws/history.d.ts.map +1 -1
- package/dist/ws/history.js +7 -5
- package/dist/ws/history.js.map +1 -1
- package/dist/ws/host.d.ts +22 -0
- package/dist/ws/host.d.ts.map +1 -1
- package/dist/ws/host.js +39 -1
- package/dist/ws/host.js.map +1 -1
- package/dist/ws/run-session.d.ts +7 -7
- package/dist/ws/run-session.d.ts.map +1 -1
- package/dist/ws/run-session.js +208 -52
- package/dist/ws/run-session.js.map +1 -1
- package/dist/ws/shrink.d.ts +3 -1
- package/dist/ws/shrink.d.ts.map +1 -1
- package/dist/ws/shrink.js +46 -16
- package/dist/ws/shrink.js.map +1 -1
- package/dist/ws/turns.d.ts +58 -3
- package/dist/ws/turns.d.ts.map +1 -1
- package/dist/ws/turns.js +101 -2
- package/dist/ws/turns.js.map +1 -1
- package/migrations/011_principals.sql +13 -0
- package/migrations/012_activity_principals.sql +12 -0
- package/migrations/013_push_subscription_principals.sql +7 -0
- package/migrations/014_invalidate_legacy_sessions.sql +14 -0
- package/package.json +3 -3
- package/src/activity/notify.ts +16 -7
- package/src/activity/push-sender.ts +79 -16
- package/src/activity/query.ts +8 -0
- package/src/activity/recorder.ts +68 -3
- package/src/activity/runtime.ts +2 -5
- package/src/activity/sql.ts +122 -0
- package/src/activity/store.ts +73 -155
- package/src/activity/stream.ts +37 -17
- package/src/app-env.ts +8 -0
- package/src/app.ts +33 -4
- package/src/brain/client.ts +61 -20
- package/src/brain/types.ts +10 -0
- package/src/cron/run-job.ts +41 -17
- package/src/db/principals.ts +452 -0
- package/src/files/walker.ts +5 -1
- package/src/index.ts +6 -1
- package/src/middleware/auth.ts +241 -81
- package/src/middleware/passkeys.ts +35 -14
- package/src/middleware/principals.ts +189 -0
- package/src/middleware/require-owner.ts +13 -0
- package/src/observability/loggers.ts +1 -1
- package/src/routes/activity.ts +3 -0
- package/src/routes/brain.ts +107 -70
- package/src/routes/files.ts +10 -5
- package/src/routes/push.ts +11 -5
- package/src/routes/sessions.ts +45 -20
- package/src/share/staging.ts +11 -4
- package/src/ws/bridge.ts +14 -2
- package/src/ws/clients.ts +52 -7
- package/src/ws/connection.ts +98 -20
- package/src/ws/dispatch.ts +66 -6
- package/src/ws/history.ts +7 -5
- package/src/ws/host.ts +59 -1
- package/src/ws/run-session.ts +247 -74
- package/src/ws/shrink.ts +48 -14
- package/src/ws/turns.ts +136 -5
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/** SQL owned by the activity store, kept together so the store reads as operations. */
|
|
2
|
+
export const ACTIVITY_SQL = {
|
|
3
|
+
nextSeq: "SELECT COALESCE(MAX(seq), 0) AS hi FROM activity_changes WHERE run_id = ?",
|
|
4
|
+
insertChange: "INSERT INTO activity_changes (run_id, seq, span_id, event_index) VALUES (?, ?, ?, ?)",
|
|
5
|
+
spanById: "SELECT * FROM activity_spans WHERE span_id = ?",
|
|
6
|
+
spanStateById: "SELECT run_id, outcome, attrs FROM activity_spans WHERE span_id = ?",
|
|
7
|
+
endSpan: `UPDATE activity_spans SET outcome = ?, outcome_reason = ?, ended_at = ?, attrs = ?,
|
|
8
|
+
input_tokens = COALESCE(?, input_tokens),
|
|
9
|
+
output_tokens = COALESCE(?, output_tokens),
|
|
10
|
+
cache_read_tokens = COALESCE(?, cache_read_tokens),
|
|
11
|
+
cache_creation_tokens = COALESCE(?, cache_creation_tokens),
|
|
12
|
+
cost_usd = COALESCE(?, cost_usd),
|
|
13
|
+
model = COALESCE(?, model)
|
|
14
|
+
WHERE span_id = ?`,
|
|
15
|
+
openSpansByRun: "SELECT span_id FROM activity_spans WHERE run_id = ? AND outcome IS NULL ORDER BY started_at DESC",
|
|
16
|
+
spansByRun: "SELECT * FROM activity_spans WHERE run_id = ? ORDER BY started_at",
|
|
17
|
+
upsertRollup: `INSERT INTO activity_run_rollups
|
|
18
|
+
(run_id, origin, name, session_id, job_name, principal_id, principal_label,
|
|
19
|
+
principal_kind, started_at, ended_at, outcome,
|
|
20
|
+
duration_ms, span_count, input_tokens, output_tokens, cache_read_tokens,
|
|
21
|
+
cache_creation_tokens, cost_usd, effective_cost_usd, billing_mode,
|
|
22
|
+
pricing_estimate, failure_reason, detail_pruned)
|
|
23
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)
|
|
24
|
+
ON CONFLICT(run_id) DO UPDATE SET
|
|
25
|
+
ended_at = excluded.ended_at, outcome = excluded.outcome,
|
|
26
|
+
duration_ms = excluded.duration_ms, span_count = excluded.span_count,
|
|
27
|
+
input_tokens = excluded.input_tokens, output_tokens = excluded.output_tokens,
|
|
28
|
+
cache_read_tokens = excluded.cache_read_tokens,
|
|
29
|
+
cache_creation_tokens = excluded.cache_creation_tokens,
|
|
30
|
+
cost_usd = COALESCE(activity_run_rollups.cost_usd, excluded.cost_usd),
|
|
31
|
+
effective_cost_usd = CASE
|
|
32
|
+
WHEN activity_run_rollups.effective_cost_usd IS NOT NULL
|
|
33
|
+
THEN activity_run_rollups.effective_cost_usd
|
|
34
|
+
WHEN activity_run_rollups.billing_mode IS NULL
|
|
35
|
+
OR activity_run_rollups.billing_mode = excluded.billing_mode
|
|
36
|
+
THEN excluded.effective_cost_usd
|
|
37
|
+
ELSE NULL
|
|
38
|
+
END,
|
|
39
|
+
billing_mode = COALESCE(activity_run_rollups.billing_mode, excluded.billing_mode),
|
|
40
|
+
pricing_estimate = CASE
|
|
41
|
+
WHEN activity_run_rollups.pricing_estimate IS NOT NULL
|
|
42
|
+
THEN activity_run_rollups.pricing_estimate
|
|
43
|
+
WHEN activity_run_rollups.billing_mode IS NULL
|
|
44
|
+
OR activity_run_rollups.billing_mode = excluded.billing_mode
|
|
45
|
+
THEN excluded.pricing_estimate
|
|
46
|
+
ELSE NULL
|
|
47
|
+
END,
|
|
48
|
+
failure_reason = excluded.failure_reason`,
|
|
49
|
+
insertSpan: `INSERT INTO activity_spans
|
|
50
|
+
(span_id, run_id, parent_span_id, name, kind, origin, session_id, job_name, principal_id,
|
|
51
|
+
attrs, started_at, writer, last_heartbeat_at)
|
|
52
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
53
|
+
patchSpan: `UPDATE activity_spans SET principal_id = COALESCE(?, principal_id),
|
|
54
|
+
attrs = ?, wait_until = COALESCE(?, wait_until),
|
|
55
|
+
input_tokens = COALESCE(?, input_tokens),
|
|
56
|
+
output_tokens = COALESCE(?, output_tokens),
|
|
57
|
+
cache_read_tokens = COALESCE(?, cache_read_tokens),
|
|
58
|
+
cache_creation_tokens = COALESCE(?, cache_creation_tokens),
|
|
59
|
+
cost_usd = COALESCE(?, cost_usd),
|
|
60
|
+
model = COALESCE(?, model)
|
|
61
|
+
WHERE span_id = ?`,
|
|
62
|
+
spanRunById: "SELECT run_id FROM activity_spans WHERE span_id = ?",
|
|
63
|
+
nextEventIndex: "SELECT COALESCE(MAX(event_index), -1) + 1 AS idx FROM activity_events WHERE span_id = ?",
|
|
64
|
+
insertEvent: "INSERT INTO activity_events (span_id, event_index, ts, event_type, payload) VALUES (?, ?, ?, ?, ?)",
|
|
65
|
+
heartbeat: "UPDATE activity_spans SET last_heartbeat_at = ? WHERE span_id = ? AND outcome IS NULL",
|
|
66
|
+
openSessionRuns: "SELECT DISTINCT run_id FROM activity_spans WHERE outcome IS NULL AND origin = 'session'",
|
|
67
|
+
staleRoots: `SELECT span_id, run_id FROM activity_spans
|
|
68
|
+
WHERE outcome IS NULL AND parent_span_id IS NULL
|
|
69
|
+
AND writer != ? AND COALESCE(last_heartbeat_at, started_at) < ?`,
|
|
70
|
+
stuckRoots: "SELECT * FROM activity_spans WHERE outcome IS NULL AND parent_span_id IS NULL AND started_at < ?",
|
|
71
|
+
spanChanges: `SELECT c.change_id, c.run_id, c.seq, s.*
|
|
72
|
+
FROM activity_changes c
|
|
73
|
+
JOIN activity_spans s ON s.span_id = c.span_id
|
|
74
|
+
WHERE c.change_id > ? AND c.event_index IS NULL
|
|
75
|
+
ORDER BY c.change_id LIMIT ?`,
|
|
76
|
+
eventChanges: `SELECT c.change_id, c.run_id, c.seq, e.*
|
|
77
|
+
FROM activity_changes c
|
|
78
|
+
JOIN activity_events e
|
|
79
|
+
ON e.span_id = c.span_id AND e.event_index = c.event_index
|
|
80
|
+
WHERE c.change_id > ? AND c.event_index IS NOT NULL
|
|
81
|
+
ORDER BY c.change_id LIMIT ?`,
|
|
82
|
+
terminalRootChanges: `SELECT MAX(c.change_id) AS change_id, s.*
|
|
83
|
+
FROM activity_changes c
|
|
84
|
+
JOIN activity_spans s ON s.span_id = c.span_id
|
|
85
|
+
WHERE c.change_id > ? AND c.event_index IS NULL
|
|
86
|
+
AND s.parent_span_id IS NULL AND s.outcome IS NOT NULL
|
|
87
|
+
GROUP BY s.span_id
|
|
88
|
+
ORDER BY change_id LIMIT ?`,
|
|
89
|
+
latestChangeCursor: "SELECT COALESCE(MAX(change_id), 0) AS hi FROM activity_changes",
|
|
90
|
+
eventsByRun: `SELECT e.* FROM activity_events e
|
|
91
|
+
JOIN activity_spans s ON s.span_id = e.span_id
|
|
92
|
+
WHERE s.run_id = ? ORDER BY e.ts, e.event_index`,
|
|
93
|
+
openRootSpans: "SELECT * FROM activity_spans WHERE outcome IS NULL AND parent_span_id IS NULL ORDER BY started_at DESC",
|
|
94
|
+
pruneCandidates: `SELECT run_id, ended_at AS ended FROM activity_run_rollups r
|
|
95
|
+
WHERE detail_pruned = 0 AND ended_at IS NOT NULL
|
|
96
|
+
AND ((ended_at < ? AND ended_at < ?) OR ended_at < ?)
|
|
97
|
+
AND NOT EXISTS (
|
|
98
|
+
SELECT 1 FROM activity_spans s
|
|
99
|
+
WHERE s.run_id = r.run_id AND s.outcome IS NULL
|
|
100
|
+
)
|
|
101
|
+
LIMIT ?`,
|
|
102
|
+
markDetailPruned: "UPDATE activity_run_rollups SET detail_pruned = 1 WHERE run_id = ?",
|
|
103
|
+
markDigestCoverageGap: "UPDATE activity_run_rollups SET failure_reason = COALESCE(failure_reason, 'digest coverage gap') WHERE run_id = ?",
|
|
104
|
+
deleteEventsByRun: `DELETE FROM activity_events WHERE span_id IN
|
|
105
|
+
(SELECT span_id FROM activity_spans WHERE run_id = ?)`,
|
|
106
|
+
deleteSpansByRun: "DELETE FROM activity_spans WHERE run_id = ?",
|
|
107
|
+
deleteChangesByRun: "DELETE FROM activity_changes WHERE run_id = ?",
|
|
108
|
+
compactChanges: `DELETE FROM activity_changes WHERE change_id < (
|
|
109
|
+
SELECT COALESCE(MAX(change_id), 0) FROM activity_changes
|
|
110
|
+
) - 100000 AND run_id NOT IN (
|
|
111
|
+
SELECT DISTINCT run_id FROM activity_spans WHERE outcome IS NULL
|
|
112
|
+
)`,
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=sql.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql.js","sourceRoot":"","sources":["../../src/activity/sql.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,OAAO,EAAE,2EAA2E;IACpF,YAAY,EACV,sFAAsF;IACxF,QAAQ,EAAE,gDAAgD;IAC1D,aAAa,EAAE,qEAAqE;IACpF,OAAO,EAAE;;;;;;;yBAOc;IACvB,cAAc,EACZ,kGAAkG;IACpG,UAAU,EAAE,mEAAmE;IAC/E,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kDA+BkC;IAChD,UAAU,EAAE;;;0DAG4C;IACxD,SAAS,EAAE;;;;;;;;6BAQgB;IAC3B,WAAW,EAAE,qDAAqD;IAClE,cAAc,EACZ,yFAAyF;IAC3F,WAAW,EACT,oGAAoG;IACtG,SAAS,EACP,uFAAuF;IACzF,eAAe,EACb,yFAAyF;IAC3F,UAAU,EAAE;;6EAE+D;IAC3E,UAAU,EACR,kGAAkG;IACpG,WAAW,EAAE;;;;wCAIyB;IACtC,YAAY,EAAE;;;;;wCAKwB;IACtC,mBAAmB,EAAE;;;;;;sCAMe;IACpC,kBAAkB,EAAE,gEAAgE;IACpF,WAAW,EAAE;;+DAEgD;IAC7D,aAAa,EACX,wGAAwG;IAC1G,eAAe,EAAE;;;;;;;qBAOE;IACnB,gBAAgB,EAAE,oEAAoE;IACtF,qBAAqB,EACnB,mHAAmH;IACrH,iBAAiB,EAAE;qEACgD;IACnE,gBAAgB,EAAE,6CAA6C;IAC/D,kBAAkB,EAAE,+CAA+C;IACnE,cAAc,EAAE;;;;aAIL;CACH,CAAC"}
|
package/dist/activity/store.d.ts
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
import type { Database } from "bun:sqlite";
|
|
34
34
|
import { type BillingMode } from "@schlessera/brain-ui-sdk/protocol";
|
|
35
35
|
import { type PricingRates } from "../pricing/model-pricing.js";
|
|
36
|
+
import type { PrincipalKind } from "../db/principals.js";
|
|
36
37
|
export declare const SPAN_OUTCOMES: readonly ["success", "error", "timeout", "cancelled", "denied", "interrupted"];
|
|
37
38
|
export type SpanOutcome = (typeof SPAN_OUTCOMES)[number];
|
|
38
39
|
export type SpanKind = "turn" | "tool" | "subagent" | "cron";
|
|
@@ -55,6 +56,7 @@ export interface SpanRow {
|
|
|
55
56
|
origin: SpanOrigin;
|
|
56
57
|
sessionId: string | null;
|
|
57
58
|
jobName: string | null;
|
|
59
|
+
principalId: string | null;
|
|
58
60
|
attrs: Record<string, unknown>;
|
|
59
61
|
startedAt: number;
|
|
60
62
|
waitUntil: number | null;
|
|
@@ -80,6 +82,9 @@ export interface RunRollupRow {
|
|
|
80
82
|
name: string;
|
|
81
83
|
sessionId: string | null;
|
|
82
84
|
jobName: string | null;
|
|
85
|
+
principalId: string | null;
|
|
86
|
+
principalLabel: string | null;
|
|
87
|
+
principalKind: PrincipalKind | null;
|
|
83
88
|
startedAt: number;
|
|
84
89
|
endedAt: number | null;
|
|
85
90
|
outcome: SpanOutcome | null;
|
|
@@ -139,6 +144,7 @@ export interface StartSpanInput {
|
|
|
139
144
|
origin: SpanOrigin;
|
|
140
145
|
sessionId?: string;
|
|
141
146
|
jobName?: string;
|
|
147
|
+
principalId?: string;
|
|
142
148
|
attrs?: Record<string, unknown>;
|
|
143
149
|
startedAt?: number;
|
|
144
150
|
}
|
|
@@ -187,6 +193,7 @@ export interface ActivityStore {
|
|
|
187
193
|
endSpan(spanId: string, input: EndSpanInput): boolean;
|
|
188
194
|
/** Non-terminal field updates (usage enrichment, wait boundary, attrs). */
|
|
189
195
|
patchSpan(spanId: string, patch: {
|
|
196
|
+
principalId?: string;
|
|
190
197
|
attrs?: Record<string, unknown>;
|
|
191
198
|
usage?: SpanUsage;
|
|
192
199
|
waitUntil?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/activity/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAMpF,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/activity/store.ts"],"names":[],"mappings":"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"}
|
package/dist/activity/store.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isBillingMode } from "@schlessera/brain-ui-sdk/protocol";
|
|
2
2
|
import { resolveAmbientBillingMode, resolveStandalonePricingConfig, } from "../config/env.js";
|
|
3
3
|
import { createModelPricing } from "../pricing/model-pricing.js";
|
|
4
|
+
import { ACTIVITY_SQL } from "./sql.js";
|
|
4
5
|
export const SPAN_OUTCOMES = [
|
|
5
6
|
"success",
|
|
6
7
|
"error",
|
|
@@ -9,6 +10,9 @@ export const SPAN_OUTCOMES = [
|
|
|
9
10
|
"denied",
|
|
10
11
|
"interrupted",
|
|
11
12
|
];
|
|
13
|
+
function isPrincipalKind(value) {
|
|
14
|
+
return (value === "owner" || value === "agent" || value === "ambient" || value === "system");
|
|
15
|
+
}
|
|
12
16
|
/** The one snake→camel mapper for rollup rows — every reader shares it. */
|
|
13
17
|
export function rowToRunRollup(r) {
|
|
14
18
|
return {
|
|
@@ -17,6 +21,9 @@ export function rowToRunRollup(r) {
|
|
|
17
21
|
name: r.name,
|
|
18
22
|
sessionId: r.session_id,
|
|
19
23
|
jobName: r.job_name,
|
|
24
|
+
principalId: r.principal_id ?? null,
|
|
25
|
+
principalLabel: r.principal_label ?? null,
|
|
26
|
+
principalKind: isPrincipalKind(r.principal_kind) ? r.principal_kind : null,
|
|
20
27
|
startedAt: r.started_at,
|
|
21
28
|
endedAt: r.ended_at,
|
|
22
29
|
outcome: r.outcome,
|
|
@@ -69,12 +76,12 @@ export function createActivityStore(db, options = {}) {
|
|
|
69
76
|
const inWrite = (fn) => db.transaction(fn).immediate();
|
|
70
77
|
function nextSeq(runId) {
|
|
71
78
|
const row = db
|
|
72
|
-
.query(
|
|
79
|
+
.query(ACTIVITY_SQL.nextSeq)
|
|
73
80
|
.get(runId);
|
|
74
81
|
return row.hi + 1;
|
|
75
82
|
}
|
|
76
83
|
function logChange(runId, seq, spanId, eventIndex) {
|
|
77
|
-
db.query(
|
|
84
|
+
db.query(ACTIVITY_SQL.insertChange).run(runId, seq, spanId, eventIndex ?? null);
|
|
78
85
|
}
|
|
79
86
|
function rowToSpan(r) {
|
|
80
87
|
return {
|
|
@@ -86,6 +93,7 @@ export function createActivityStore(db, options = {}) {
|
|
|
86
93
|
origin: r.origin,
|
|
87
94
|
sessionId: r.session_id,
|
|
88
95
|
jobName: r.job_name,
|
|
96
|
+
principalId: r.principal_id ?? null,
|
|
89
97
|
attrs: safeParse(r.attrs) ?? {},
|
|
90
98
|
startedAt: r.started_at,
|
|
91
99
|
waitUntil: r.wait_until,
|
|
@@ -116,18 +124,18 @@ export function createActivityStore(db, options = {}) {
|
|
|
116
124
|
};
|
|
117
125
|
}
|
|
118
126
|
function getSpanRaw(spanId) {
|
|
119
|
-
const r = db.query(
|
|
127
|
+
const r = db.query(ACTIVITY_SQL.spanById).get(spanId);
|
|
120
128
|
return r ? rowToSpan(r) : null;
|
|
121
129
|
}
|
|
122
130
|
function runHighWaterSeqRaw(runId) {
|
|
123
131
|
const row = db
|
|
124
|
-
.query(
|
|
132
|
+
.query(ACTIVITY_SQL.nextSeq)
|
|
125
133
|
.get(runId);
|
|
126
134
|
return row.hi;
|
|
127
135
|
}
|
|
128
136
|
function endSpanInTx(spanId, input) {
|
|
129
137
|
const existing = db
|
|
130
|
-
.query(
|
|
138
|
+
.query(ACTIVITY_SQL.spanStateById)
|
|
131
139
|
.get(spanId);
|
|
132
140
|
if (!existing || existing.outcome !== null)
|
|
133
141
|
return false;
|
|
@@ -136,21 +144,14 @@ export function createActivityStore(db, options = {}) {
|
|
|
136
144
|
? JSON.stringify({ ...(safeParse(existing.attrs) ?? {}), ...input.attrs })
|
|
137
145
|
: existing.attrs;
|
|
138
146
|
const u = input.usage ?? {};
|
|
139
|
-
db.query(
|
|
140
|
-
input_tokens = COALESCE(?, input_tokens),
|
|
141
|
-
output_tokens = COALESCE(?, output_tokens),
|
|
142
|
-
cache_read_tokens = COALESCE(?, cache_read_tokens),
|
|
143
|
-
cache_creation_tokens = COALESCE(?, cache_creation_tokens),
|
|
144
|
-
cost_usd = COALESCE(?, cost_usd),
|
|
145
|
-
model = COALESCE(?, model)
|
|
146
|
-
WHERE span_id = ?`).run(input.outcome, input.reason ?? null, endedAt, attrs, u.inputTokens ?? null, u.outputTokens ?? null, u.cacheReadTokens ?? null, u.cacheCreationTokens ?? null, u.costUsd ?? null, u.model ?? null, spanId);
|
|
147
|
+
db.query(ACTIVITY_SQL.endSpan).run(input.outcome, input.reason ?? null, endedAt, attrs, u.inputTokens ?? null, u.outputTokens ?? null, u.cacheReadTokens ?? null, u.cacheCreationTokens ?? null, u.costUsd ?? null, u.model ?? null, spanId);
|
|
147
148
|
logChange(existing.run_id, nextSeq(existing.run_id), spanId);
|
|
148
149
|
return true;
|
|
149
150
|
}
|
|
150
151
|
/** Close every open span of the run (children first) and roll it up. */
|
|
151
152
|
function closeRunInTx(runId, outcome, reason) {
|
|
152
153
|
const open = db
|
|
153
|
-
.query(
|
|
154
|
+
.query(ACTIVITY_SQL.openSpansByRun)
|
|
154
155
|
.all(runId);
|
|
155
156
|
let closed = 0;
|
|
156
157
|
for (const { span_id } of open) {
|
|
@@ -163,7 +164,7 @@ export function createActivityStore(db, options = {}) {
|
|
|
163
164
|
}
|
|
164
165
|
function rollupRunInTx(runId) {
|
|
165
166
|
const spans = db
|
|
166
|
-
.query(
|
|
167
|
+
.query(ACTIVITY_SQL.spansByRun)
|
|
167
168
|
.all(runId)
|
|
168
169
|
.map(rowToSpan);
|
|
169
170
|
if (spans.length === 0)
|
|
@@ -214,37 +215,12 @@ export function createActivityStore(db, options = {}) {
|
|
|
214
215
|
? (priced.estimate ? 1 : 0)
|
|
215
216
|
: null;
|
|
216
217
|
const costUsd = root.usage.costUsd ?? priced?.costUsd ?? null;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
ON CONFLICT(run_id) DO UPDATE SET
|
|
224
|
-
ended_at = excluded.ended_at, outcome = excluded.outcome,
|
|
225
|
-
duration_ms = excluded.duration_ms, span_count = excluded.span_count,
|
|
226
|
-
input_tokens = excluded.input_tokens, output_tokens = excluded.output_tokens,
|
|
227
|
-
cache_read_tokens = excluded.cache_read_tokens,
|
|
228
|
-
cache_creation_tokens = excluded.cache_creation_tokens,
|
|
229
|
-
cost_usd = COALESCE(activity_run_rollups.cost_usd, excluded.cost_usd),
|
|
230
|
-
effective_cost_usd = CASE
|
|
231
|
-
WHEN activity_run_rollups.effective_cost_usd IS NOT NULL
|
|
232
|
-
THEN activity_run_rollups.effective_cost_usd
|
|
233
|
-
WHEN activity_run_rollups.billing_mode IS NULL
|
|
234
|
-
OR activity_run_rollups.billing_mode = excluded.billing_mode
|
|
235
|
-
THEN excluded.effective_cost_usd
|
|
236
|
-
ELSE NULL
|
|
237
|
-
END,
|
|
238
|
-
billing_mode = COALESCE(activity_run_rollups.billing_mode, excluded.billing_mode),
|
|
239
|
-
pricing_estimate = CASE
|
|
240
|
-
WHEN activity_run_rollups.pricing_estimate IS NOT NULL
|
|
241
|
-
THEN activity_run_rollups.pricing_estimate
|
|
242
|
-
WHEN activity_run_rollups.billing_mode IS NULL
|
|
243
|
-
OR activity_run_rollups.billing_mode = excluded.billing_mode
|
|
244
|
-
THEN excluded.pricing_estimate
|
|
245
|
-
ELSE NULL
|
|
246
|
-
END,
|
|
247
|
-
failure_reason = excluded.failure_reason`
|
|
218
|
+
const principal = root.principalId
|
|
219
|
+
? db
|
|
220
|
+
.query("SELECT label, kind FROM principals WHERE id = ?")
|
|
221
|
+
.get(root.principalId)
|
|
222
|
+
: null;
|
|
223
|
+
db.query(ACTIVITY_SQL.upsertRollup
|
|
248
224
|
// Every cost column is FROZEN at first non-NULL write (AE5): a re-rollup
|
|
249
225
|
// after a pricing refresh must not silently reprice history — only a
|
|
250
226
|
// still-NULL slot may be filled by a later computation. cost_usd gets
|
|
@@ -255,17 +231,14 @@ export function createActivityStore(db, options = {}) {
|
|
|
255
231
|
// and a slot left NULL under one classification must never be filled by
|
|
256
232
|
// a number computed under a different one (a subscription $0 landing on
|
|
257
233
|
// an api-classified row would fabricate a cross-classified price).
|
|
258
|
-
).run(runId, root.origin, root.name, root.sessionId, root.jobName, root.startedAt, root.endedAt, root.outcome, root.endedAt !== null ? root.endedAt - root.startedAt : null, spans.length, root.usage.inputTokens ?? null, root.usage.outputTokens ?? null, root.usage.cacheReadTokens ?? null, root.usage.cacheCreationTokens ?? null, costUsd, effectiveCostUsd, billingMode, pricingEstimate, failure);
|
|
234
|
+
).run(runId, root.origin, root.name, root.sessionId, root.jobName, root.principalId, principal?.label ?? null, principal?.kind ?? null, root.startedAt, root.endedAt, root.outcome, root.endedAt !== null ? root.endedAt - root.startedAt : null, spans.length, root.usage.inputTokens ?? null, root.usage.outputTokens ?? null, root.usage.cacheReadTokens ?? null, root.usage.cacheCreationTokens ?? null, costUsd, effectiveCostUsd, billingMode, pricingEstimate, failure);
|
|
259
235
|
}
|
|
260
236
|
return {
|
|
261
237
|
writer,
|
|
262
238
|
startSpan(input) {
|
|
263
239
|
return inWrite(() => {
|
|
264
240
|
const startedAt = input.startedAt ?? Date.now();
|
|
265
|
-
db.query(
|
|
266
|
-
(span_id, run_id, parent_span_id, name, kind, origin, session_id, job_name,
|
|
267
|
-
attrs, started_at, writer, last_heartbeat_at)
|
|
268
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(input.spanId, input.runId, input.parentSpanId ?? null, input.name, input.kind, input.origin, input.sessionId ?? null, input.jobName ?? null, input.attrs ? JSON.stringify(input.attrs) : null, startedAt, writer, input.parentSpanId ? null : startedAt);
|
|
241
|
+
db.query(ACTIVITY_SQL.insertSpan).run(input.spanId, input.runId, input.parentSpanId ?? null, input.name, input.kind, input.origin, input.sessionId ?? null, input.jobName ?? null, input.principalId ?? null, input.attrs ? JSON.stringify(input.attrs) : null, startedAt, writer, input.parentSpanId ? null : startedAt);
|
|
269
242
|
logChange(input.runId, nextSeq(input.runId), input.spanId);
|
|
270
243
|
return getSpanRaw(input.spanId);
|
|
271
244
|
});
|
|
@@ -276,7 +249,7 @@ export function createActivityStore(db, options = {}) {
|
|
|
276
249
|
patchSpan(spanId, patch) {
|
|
277
250
|
return inWrite(() => {
|
|
278
251
|
const existing = db
|
|
279
|
-
.query(
|
|
252
|
+
.query(ACTIVITY_SQL.spanStateById)
|
|
280
253
|
.get(spanId);
|
|
281
254
|
if (!existing || existing.outcome !== null)
|
|
282
255
|
return false;
|
|
@@ -284,14 +257,7 @@ export function createActivityStore(db, options = {}) {
|
|
|
284
257
|
? JSON.stringify({ ...(safeParse(existing.attrs) ?? {}), ...patch.attrs })
|
|
285
258
|
: existing.attrs;
|
|
286
259
|
const u = patch.usage ?? {};
|
|
287
|
-
db.query(
|
|
288
|
-
input_tokens = COALESCE(?, input_tokens),
|
|
289
|
-
output_tokens = COALESCE(?, output_tokens),
|
|
290
|
-
cache_read_tokens = COALESCE(?, cache_read_tokens),
|
|
291
|
-
cache_creation_tokens = COALESCE(?, cache_creation_tokens),
|
|
292
|
-
cost_usd = COALESCE(?, cost_usd),
|
|
293
|
-
model = COALESCE(?, model)
|
|
294
|
-
WHERE span_id = ?`).run(attrs, patch.waitUntil ?? null, u.inputTokens ?? null, u.outputTokens ?? null, u.cacheReadTokens ?? null, u.cacheCreationTokens ?? null, u.costUsd ?? null, u.model ?? null, spanId);
|
|
260
|
+
db.query(ACTIVITY_SQL.patchSpan).run(patch.principalId ?? null, attrs, patch.waitUntil ?? null, u.inputTokens ?? null, u.outputTokens ?? null, u.cacheReadTokens ?? null, u.cacheCreationTokens ?? null, u.costUsd ?? null, u.model ?? null, spanId);
|
|
295
261
|
logChange(existing.run_id, nextSeq(existing.run_id), spanId);
|
|
296
262
|
return true;
|
|
297
263
|
});
|
|
@@ -299,16 +265,16 @@ export function createActivityStore(db, options = {}) {
|
|
|
299
265
|
appendEvent(spanId, eventType, payload, ts, cap) {
|
|
300
266
|
return inWrite(() => {
|
|
301
267
|
const span = db
|
|
302
|
-
.query(
|
|
268
|
+
.query(ACTIVITY_SQL.spanRunById)
|
|
303
269
|
.get(spanId);
|
|
304
270
|
if (!span)
|
|
305
271
|
return null;
|
|
306
272
|
const next = db
|
|
307
|
-
.query(
|
|
273
|
+
.query(ACTIVITY_SQL.nextEventIndex)
|
|
308
274
|
.get(spanId);
|
|
309
275
|
const stored = capPayload(payload, cap);
|
|
310
276
|
const at = ts ?? Date.now();
|
|
311
|
-
db.query(
|
|
277
|
+
db.query(ACTIVITY_SQL.insertEvent).run(spanId, next.idx, at, eventType, JSON.stringify(stored));
|
|
312
278
|
logChange(span.run_id, nextSeq(span.run_id), spanId, next.idx);
|
|
313
279
|
// Built from the values just written — no read-back needed.
|
|
314
280
|
return {
|
|
@@ -325,7 +291,7 @@ export function createActivityStore(db, options = {}) {
|
|
|
325
291
|
inWrite(() => {
|
|
326
292
|
// Deliberately NOT change-logged: a heartbeat is liveness metadata,
|
|
327
293
|
// not activity the client needs a delta for.
|
|
328
|
-
db.query(
|
|
294
|
+
db.query(ACTIVITY_SQL.heartbeat).run(at ?? Date.now(), spanId);
|
|
329
295
|
});
|
|
330
296
|
},
|
|
331
297
|
cascadeClose(runId, outcome, reason) {
|
|
@@ -346,7 +312,7 @@ export function createActivityStore(db, options = {}) {
|
|
|
346
312
|
// loop re-checks open-ness inside the transaction (endSpanInTx is
|
|
347
313
|
// write-once), so a race just skips.
|
|
348
314
|
const open = db
|
|
349
|
-
.query(
|
|
315
|
+
.query(ACTIVITY_SQL.openSessionRuns)
|
|
350
316
|
.all();
|
|
351
317
|
if (open.length === 0)
|
|
352
318
|
return 0;
|
|
@@ -365,9 +331,7 @@ export function createActivityStore(db, options = {}) {
|
|
|
365
331
|
// legitimately long, quiet run with a live writer is never killed.
|
|
366
332
|
// Candidate read outside the write transaction, same as sweepOwnOrphans.
|
|
367
333
|
const staleRoots = db
|
|
368
|
-
.query(
|
|
369
|
-
WHERE outcome IS NULL AND parent_span_id IS NULL
|
|
370
|
-
AND writer != ? AND COALESCE(last_heartbeat_at, started_at) < ?`)
|
|
334
|
+
.query(ACTIVITY_SQL.staleRoots)
|
|
371
335
|
.all(writer, cutoff);
|
|
372
336
|
if (staleRoots.length === 0)
|
|
373
337
|
return 0;
|
|
@@ -383,7 +347,7 @@ export function createActivityStore(db, options = {}) {
|
|
|
383
347
|
findStuck(thresholdMs, now) {
|
|
384
348
|
const cutoff = (now ?? Date.now()) - thresholdMs;
|
|
385
349
|
return db
|
|
386
|
-
.query(
|
|
350
|
+
.query(ACTIVITY_SQL.stuckRoots)
|
|
387
351
|
.all(cutoff).map(rowToSpan);
|
|
388
352
|
},
|
|
389
353
|
changesSince(changeCursor, limit = 500) {
|
|
@@ -391,19 +355,10 @@ export function createActivityStore(db, options = {}) {
|
|
|
391
355
|
// change whose span/event row was pruned drops out via the join, same
|
|
392
356
|
// as the old per-row miss.
|
|
393
357
|
const spanRows = db
|
|
394
|
-
.query(
|
|
395
|
-
FROM activity_changes c
|
|
396
|
-
JOIN activity_spans s ON s.span_id = c.span_id
|
|
397
|
-
WHERE c.change_id > ? AND c.event_index IS NULL
|
|
398
|
-
ORDER BY c.change_id LIMIT ?`)
|
|
358
|
+
.query(ACTIVITY_SQL.spanChanges)
|
|
399
359
|
.all(changeCursor, limit);
|
|
400
360
|
const eventRows = db
|
|
401
|
-
.query(
|
|
402
|
-
FROM activity_changes c
|
|
403
|
-
JOIN activity_events e
|
|
404
|
-
ON e.span_id = c.span_id AND e.event_index = c.event_index
|
|
405
|
-
WHERE c.change_id > ? AND c.event_index IS NOT NULL
|
|
406
|
-
ORDER BY c.change_id LIMIT ?`)
|
|
361
|
+
.query(ACTIVITY_SQL.eventChanges)
|
|
407
362
|
.all(changeCursor, limit);
|
|
408
363
|
const changes = [
|
|
409
364
|
...spanRows.map((r) => ({
|
|
@@ -426,19 +381,13 @@ export function createActivityStore(db, options = {}) {
|
|
|
426
381
|
},
|
|
427
382
|
terminalRootChangesSince(changeCursor, limit = 500) {
|
|
428
383
|
const rows = db
|
|
429
|
-
.query(
|
|
430
|
-
FROM activity_changes c
|
|
431
|
-
JOIN activity_spans s ON s.span_id = c.span_id
|
|
432
|
-
WHERE c.change_id > ? AND c.event_index IS NULL
|
|
433
|
-
AND s.parent_span_id IS NULL AND s.outcome IS NOT NULL
|
|
434
|
-
GROUP BY s.span_id
|
|
435
|
-
ORDER BY change_id LIMIT ?`)
|
|
384
|
+
.query(ACTIVITY_SQL.terminalRootChanges)
|
|
436
385
|
.all(changeCursor, limit);
|
|
437
386
|
return rows.map((r) => ({ changeId: r.change_id, span: rowToSpan(r) }));
|
|
438
387
|
},
|
|
439
388
|
latestChangeCursor() {
|
|
440
389
|
const row = db
|
|
441
|
-
.query(
|
|
390
|
+
.query(ACTIVITY_SQL.latestChangeCursor)
|
|
442
391
|
.get();
|
|
443
392
|
return row.hi;
|
|
444
393
|
},
|
|
@@ -448,17 +397,15 @@ export function createActivityStore(db, options = {}) {
|
|
|
448
397
|
// exactly this moment (no gap between snapshot and first delta).
|
|
449
398
|
return db.transaction(() => {
|
|
450
399
|
const spans = db
|
|
451
|
-
.query(
|
|
400
|
+
.query(ACTIVITY_SQL.spansByRun)
|
|
452
401
|
.all(runId).map(rowToSpan);
|
|
453
402
|
if (spans.length === 0)
|
|
454
403
|
return null;
|
|
455
404
|
const events = db
|
|
456
|
-
.query(
|
|
457
|
-
JOIN activity_spans s ON s.span_id = e.span_id
|
|
458
|
-
WHERE s.run_id = ? ORDER BY e.ts, e.event_index`)
|
|
405
|
+
.query(ACTIVITY_SQL.eventsByRun)
|
|
459
406
|
.all(runId).map(rowToEvent);
|
|
460
407
|
const cursor = db
|
|
461
|
-
.query(
|
|
408
|
+
.query(ACTIVITY_SQL.latestChangeCursor)
|
|
462
409
|
.get();
|
|
463
410
|
return {
|
|
464
411
|
runId,
|
|
@@ -473,7 +420,7 @@ export function createActivityStore(db, options = {}) {
|
|
|
473
420
|
getSpan: getSpanRaw,
|
|
474
421
|
openRootSpans() {
|
|
475
422
|
return db
|
|
476
|
-
.query(
|
|
423
|
+
.query(ACTIVITY_SQL.openRootSpans)
|
|
477
424
|
.all().map(rowToSpan);
|
|
478
425
|
},
|
|
479
426
|
rollupRun(runId) {
|
|
@@ -500,36 +447,24 @@ export function createActivityStore(db, options = {}) {
|
|
|
500
447
|
// run — that terminal write is what made the run prunable), guarded
|
|
501
448
|
// against any run that still has an open span.
|
|
502
449
|
const candidates = db
|
|
503
|
-
.query(
|
|
504
|
-
WHERE detail_pruned = 0 AND ended_at IS NOT NULL
|
|
505
|
-
AND ((ended_at < ? AND ended_at < ?) OR ended_at < ?)
|
|
506
|
-
AND NOT EXISTS (
|
|
507
|
-
SELECT 1 FROM activity_spans s
|
|
508
|
-
WHERE s.run_id = r.run_id AND s.outcome IS NULL
|
|
509
|
-
)
|
|
510
|
-
LIMIT ?`)
|
|
450
|
+
.query(ACTIVITY_SQL.pruneCandidates)
|
|
511
451
|
.all(floor, retentionCutoff, ceiling, batch);
|
|
512
452
|
let spansDeleted = 0;
|
|
513
453
|
for (const { run_id, ended } of candidates) {
|
|
514
|
-
db.query(
|
|
454
|
+
db.query(ACTIVITY_SQL.markDetailPruned).run(run_id);
|
|
515
455
|
if (ended >= floor) {
|
|
516
456
|
// Pruned by the hard ceiling alone — the digest never covered
|
|
517
457
|
// this run; make the coverage gap visible on the rollup.
|
|
518
|
-
db.query(
|
|
458
|
+
db.query(ACTIVITY_SQL.markDigestCoverageGap).run(run_id);
|
|
519
459
|
}
|
|
520
|
-
db.query(
|
|
521
|
-
|
|
522
|
-
const res = db.query("DELETE FROM activity_spans WHERE run_id = ?").run(run_id);
|
|
460
|
+
db.query(ACTIVITY_SQL.deleteEventsByRun).run(run_id);
|
|
461
|
+
const res = db.query(ACTIVITY_SQL.deleteSpansByRun).run(run_id);
|
|
523
462
|
spansDeleted += res.changes;
|
|
524
|
-
db.query(
|
|
463
|
+
db.query(ACTIVITY_SQL.deleteChangesByRun).run(run_id);
|
|
525
464
|
}
|
|
526
465
|
// The change log only serves live polling; rows this deep in the past
|
|
527
466
|
// are unreachable by any live cursor. Keep runs with open spans.
|
|
528
|
-
db.query(
|
|
529
|
-
SELECT COALESCE(MAX(change_id), 0) FROM activity_changes
|
|
530
|
-
) - 100000 AND run_id NOT IN (
|
|
531
|
-
SELECT DISTINCT run_id FROM activity_spans WHERE outcome IS NULL
|
|
532
|
-
)`).run();
|
|
467
|
+
db.query(ACTIVITY_SQL.compactChanges).run();
|
|
533
468
|
return { runsPruned: candidates.length, spansDeleted };
|
|
534
469
|
});
|
|
535
470
|
},
|