omp-fabric 1.9.0 → 1.10.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/CHANGELOG.md +19 -0
- package/README.md +28 -0
- package/dist/commands/fabric.d.ts.map +1 -1
- package/dist/compaction/lcm-maintenance.d.ts +8 -1
- package/dist/compaction/lcm-maintenance.d.ts.map +1 -1
- package/dist/compaction/lcm-runtime.d.ts +26 -0
- package/dist/compaction/lcm-runtime.d.ts.map +1 -1
- package/dist/compaction/lcm-runtime.js +83 -5
- package/dist/compaction/lcm-runtime.js.map +2 -2
- package/dist/fabric-runtime-state.d.ts +47 -0
- package/dist/fabric-runtime-state.d.ts.map +1 -1
- package/dist/fabric-runtime-state.js.map +2 -2
- package/dist/index.js +2 -51
- package/dist/index.js.map +3 -3
- package/dist/storage/lcm-ledger.d.ts +8 -0
- package/dist/storage/lcm-ledger.d.ts.map +1 -1
- package/dist/storage/lcm-migration.d.ts +2 -0
- package/dist/storage/lcm-migration.d.ts.map +1 -1
- package/dist/ui/controller.d.ts.map +1 -1
- package/dist/ui/dashboard-model.d.ts +1 -1
- package/dist/ui/dashboard-model.d.ts.map +1 -1
- package/dist/ui/dashboard.d.ts +18 -0
- package/dist/ui/dashboard.d.ts.map +1 -1
- package/dist/ui/dashboard.js +498 -64
- package/dist/ui/dashboard.js.map +4 -4
- package/dist/ui/lcm-panel.d.ts +38 -0
- package/dist/ui/lcm-panel.d.ts.map +1 -0
- package/docs/compaction.md +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.10.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- The dashboard carries the LCM ledger on key `3`. It shows the coverage band for the active branch, the node graph paged in bounded requests, the text a compaction would assemble right now beside the session payload it draws from, and a node detail that opens the exact stored raw entry behind any source. A node whose excerpt was later replaced by a model summary shows both, so the upgrade can be judged rather than assumed.
|
|
8
|
+
- Summary nodes keep their replaced text. `summary_node_revisions` records the prior text and model hash whenever maintenance rewrites a node, which is what makes the excerpt-versus-summary comparison possible.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- `/fabric lcm` is gone; the dashboard view replaces it. The single-line summary in `/fabric status` stays.
|
|
13
|
+
- The ledger read paths that feed the view are aggregates rather than row walks. Measured on a live 5,392-entry session: the coverage scan reads identity columns in 15.7 ms against 150.7 ms for the previous full-row walk, and session payload size is one aggregate at 35.2 ms against roughly 620 ms for the per-entry loop it replaces. Preview, coverage, and the coverage map now share a single frontier walk, and node listing pages in SQL rather than slicing an oversized read.
|
|
14
|
+
|
|
15
|
+
## 1.9.1
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Reconciling the session a run is actively writing failed every time, so the live session contributed nothing to the ledger and `/fabric lcm` reported a degraded runtime. The reader compared the file's size and mtime before and after reading and rejected any difference, but session JSONL is append-only and a live session grows during the read: a concurrent writer produced `errors: 1, imported: 0` on five attempts out of five. A longer file is now accepted, and only a shrinking one is refused; the same fixture then imported 4,044 entries and kept up with the writer.
|
|
20
|
+
- Tagging a release stopped publishing the GitHub release. The CI rewrite in 1.8.1 dropped that step while removing duplicated verification, so v1.8.1 through v1.9.0 reached npm with no release entry. The step is restored and the missing releases were created.
|
|
21
|
+
|
|
3
22
|
## 1.9.0
|
|
4
23
|
|
|
5
24
|
### Added
|
package/README.md
CHANGED
|
@@ -127,6 +127,34 @@ Fabric includes a live activity surface in OMP:
|
|
|
127
127
|
|
|
128
128
|
See the [interface & commands reference](docs/interface.md) for every view, keybinding, and slash command.
|
|
129
129
|
|
|
130
|
+
## Measured against OMP without Fabric
|
|
131
|
+
|
|
132
|
+
A resume task, seeded as a paused session, run three times per arm on `claude-opus-5` through the same provider. The baseline arm is OMP with no extension loaded; the Fabric arm loads `dist/index.js` and compacts the session with LCM before resuming. Both arms receive the same fixture, the same prompt, and the same host configuration, and a run counts as a success only when the fixture's own `verify.mjs` exits zero with the forbidden files untouched.
|
|
133
|
+
|
|
134
|
+
| | Baseline | Fabric | Delta |
|
|
135
|
+
|---|---|---|---|
|
|
136
|
+
| Task success | 3/3 | 3/3 | equal |
|
|
137
|
+
| Tokens | 585,197 | 356,542 | **-39%** |
|
|
138
|
+
| Tool calls | 14 | 6 | **-57%** |
|
|
139
|
+
| Wall time | 67.6 s | 59.1 s | -13% |
|
|
140
|
+
| Cost | $0.6987 | $0.2356 | -66% |
|
|
141
|
+
|
|
142
|
+
Per-run tokens were 208,595 / 209,619 / 166,983 for the baseline and 118,751 / 119,387 / 118,404 with Fabric, so the reduction is stable across runs, not an artifact of one lucky sample. Read the cost row with care: the baseline's first run cost $0.4710 against $0.1271 and $0.1007 for its later two, because a cold prompt cache is charged at full rate. The token column is the honest measure of the difference, and cost follows it once caches are warm on both sides.
|
|
143
|
+
|
|
144
|
+
Reproduce it with your own model and provider:
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
OMP_FABRIC_REAL_RESUME=1 \
|
|
148
|
+
OMP_FABRIC_BENCH_MODEL=claude-opus-5 \
|
|
149
|
+
OMP_FABRIC_BENCH_PROVIDER=sub2api-claude \
|
|
150
|
+
OMP_FABRIC_BENCH_KEY_ENV=YOUR_KEY_VARIABLE \
|
|
151
|
+
OMP_FABRIC_BENCH_REPEATS=3 \
|
|
152
|
+
OMP_FABRIC_BENCH_MAX_USD=8 \
|
|
153
|
+
bun run benchmark:real-resume
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The command bills your provider and stops at `OMP_FABRIC_BENCH_MAX_USD`. Without those variables it reports `SKIP` and spends nothing.
|
|
157
|
+
|
|
130
158
|
## Reference
|
|
131
159
|
|
|
132
160
|
- [Configuration](docs/configuration.md): `fabric.json`, code modes, tool capture, approvals, and budgets.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fabric.d.ts","sourceRoot":"","sources":["../../src/commands/fabric.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAErF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AA8C9D,UAAU,iBAAiB;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,aAAa,EAAE,mBAAmB,CAAC;IACnC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,0BAA0B,CAAC,EAAE,MAAM,IAAI,CAAC;IACxC,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;CACjC;AA6HD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"fabric.d.ts","sourceRoot":"","sources":["../../src/commands/fabric.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAErF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AA8C9D,UAAU,iBAAiB;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,aAAa,EAAE,mBAAmB,CAAC;IACnC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,0BAA0B,CAAC,EAAE,MAAM,IAAI,CAAC;IACxC,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;CACjC;AA6HD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAw+BtF"}
|
|
@@ -76,10 +76,17 @@ export declare class LcmMaintenance {
|
|
|
76
76
|
private readonly modelTimeoutMs;
|
|
77
77
|
constructor(ledger: LcmLedger, options?: LcmMaintenanceOptions);
|
|
78
78
|
budgetPolicy(): LcmBudgetPolicy;
|
|
79
|
+
private recordRevision;
|
|
80
|
+
revisionsOf(nodeId: string): Array<{
|
|
81
|
+
revision: number;
|
|
82
|
+
text: string;
|
|
83
|
+
modelHash: string;
|
|
84
|
+
createdAt: number;
|
|
85
|
+
}>;
|
|
79
86
|
selectUpgrades(sessionId?: string, activeSources?: ReadonlySet<string>, branch?: string | null, limit?: number): LcmNode[];
|
|
80
87
|
ancestorsOf(nodeId: string): string[];
|
|
81
88
|
reopen(nodeId: string, force?: boolean): LcmJob;
|
|
82
|
-
listNodes(limit?: number): LcmNode[];
|
|
89
|
+
listNodes(limit?: number, offset?: number): LcmNode[];
|
|
83
90
|
getNode(nodeId: string): LcmNode | undefined;
|
|
84
91
|
getFrontier(sessionId?: string, branch?: string | null, activeSources?: ReadonlySet<string>): LcmNode[];
|
|
85
92
|
listJobs(limit?: number): LcmJob[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lcm-maintenance.d.ts","sourceRoot":"","sources":["../../src/compaction/lcm-maintenance.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"lcm-maintenance.d.ts","sourceRoot":"","sources":["../../src/compaction/lcm-maintenance.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,14 @@ import type { ExtensionContext } from "@oh-my-pi/pi-coding-agent";
|
|
|
2
2
|
import { LcmLedger, type RawEntry } from "../storage/lcm-ledger.js";
|
|
3
3
|
import { LcmMaintenance, type LcmNode } from "./lcm-maintenance.js";
|
|
4
4
|
import type { LcmCompactionInput, LcmCompactionOutput } from "./hook.js";
|
|
5
|
+
export interface LcmPreview {
|
|
6
|
+
text: string;
|
|
7
|
+
nodes: number;
|
|
8
|
+
summaryBytes: number;
|
|
9
|
+
sourceBytes: number;
|
|
10
|
+
coveredSources: number;
|
|
11
|
+
activeSources: number;
|
|
12
|
+
}
|
|
5
13
|
export interface LcmReport {
|
|
6
14
|
projectKey: string;
|
|
7
15
|
sessionId: string | undefined;
|
|
@@ -74,6 +82,24 @@ export declare class LcmRuntime {
|
|
|
74
82
|
private runMaintenance;
|
|
75
83
|
compact(input: LcmCompactionInput): LcmCompactionOutput;
|
|
76
84
|
report(): LcmReport;
|
|
85
|
+
private frontierCache;
|
|
86
|
+
/** One frontier walk shared by preview, coverage, and the coverage map. */
|
|
87
|
+
private frontierSnapshot;
|
|
88
|
+
private sourceKey;
|
|
89
|
+
/** Assembles what a compaction would serve now. Reads only; it never persists a node. */
|
|
90
|
+
preview(): LcmPreview;
|
|
91
|
+
/** Ordered coverage of the active branch: each entry says whether a ready node holds it. */
|
|
92
|
+
coverageMap(limit?: number): Array<{
|
|
93
|
+
key: string;
|
|
94
|
+
covered: boolean;
|
|
95
|
+
}>;
|
|
96
|
+
nodes(limit?: number, offset?: number): LcmNode[];
|
|
97
|
+
node(nodeId: string): {
|
|
98
|
+
node: LcmNode;
|
|
99
|
+
revisions: ReturnType<LcmMaintenance["revisionsOf"]>;
|
|
100
|
+
ancestors: string[];
|
|
101
|
+
} | undefined;
|
|
102
|
+
source(sessionId: string, entryId: string, revision: number): RawEntry | undefined;
|
|
77
103
|
coverage(): {
|
|
78
104
|
active: number;
|
|
79
105
|
covered: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lcm-runtime.d.ts","sourceRoot":"","sources":["../../src/compaction/lcm-runtime.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"lcm-runtime.d.ts","sourceRoot":"","sources":["../../src/compaction/lcm-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,6 +36,7 @@ CREATE TABLE IF NOT EXISTS project_aliases (alias TEXT PRIMARY KEY, project_key
|
|
|
36
36
|
CREATE TABLE IF NOT EXISTS sessions (project_key TEXT NOT NULL, session_id TEXT NOT NULL, created_at INTEGER NOT NULL, PRIMARY KEY(project_key, session_id));
|
|
37
37
|
CREATE TABLE IF NOT EXISTS raw_entries (project_key TEXT NOT NULL, session_id TEXT NOT NULL, entry_id TEXT NOT NULL, revision INTEGER NOT NULL, role TEXT NOT NULL, content TEXT NOT NULL, content_hash TEXT NOT NULL, payload_json TEXT NOT NULL, parent_entry_id TEXT, branch TEXT, created_at INTEGER NOT NULL, PRIMARY KEY(project_key, session_id, entry_id, revision), UNIQUE(project_key, session_id, entry_id, content_hash));
|
|
38
38
|
CREATE TABLE IF NOT EXISTS summary_nodes (node_id TEXT PRIMARY KEY, project_key TEXT NOT NULL, payload TEXT NOT NULL, created_at INTEGER NOT NULL);
|
|
39
|
+
CREATE TABLE IF NOT EXISTS summary_node_revisions (node_id TEXT NOT NULL, revision INTEGER NOT NULL, project_key TEXT NOT NULL, text TEXT NOT NULL, model_hash TEXT NOT NULL, created_at INTEGER NOT NULL, PRIMARY KEY(node_id, revision));
|
|
39
40
|
CREATE TABLE IF NOT EXISTS summary_edges (parent_id TEXT NOT NULL, child_id TEXT NOT NULL, PRIMARY KEY(parent_id, child_id));
|
|
40
41
|
CREATE TABLE IF NOT EXISTS frontiers (project_key TEXT NOT NULL, frontier_id TEXT NOT NULL, node_id TEXT NOT NULL, created_at INTEGER NOT NULL, PRIMARY KEY(project_key, frontier_id, node_id));
|
|
41
42
|
CREATE TABLE IF NOT EXISTS maintenance_jobs (job_id TEXT PRIMARY KEY, project_key TEXT NOT NULL, status TEXT NOT NULL, payload TEXT NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL);
|
|
@@ -198,6 +199,20 @@ var LcmLedger = class {
|
|
|
198
199
|
const row = this.db.prepare("SELECT * FROM raw_entries WHERE project_key=? AND session_id=? AND entry_id=? AND revision=?").get(projectKey, sessionId, entryId, revision);
|
|
199
200
|
return row ? { projectKey: row.project_key, sessionId: row.session_id, entryId: row.entry_id, revision: row.revision, role: row.role, content: row.content, contentHash: row.content_hash, payloadHash: row.content_hash, payloadJson: row.payload_json, parentEntryId: row.parent_entry_id, branch: row.branch, createdAt: row.created_at } : void 0;
|
|
200
201
|
}
|
|
202
|
+
/** Identity columns only, so a coverage scan never loads payloads. */
|
|
203
|
+
readRawKeys(projectKey = this.project.key, sessionId, limit = 1e5) {
|
|
204
|
+
this.guard();
|
|
205
|
+
this.assertProjectKey(projectKey);
|
|
206
|
+
const rows = sessionId ? this.db.prepare("SELECT session_id, entry_id, revision FROM raw_entries WHERE project_key=? AND session_id=? ORDER BY created_at,revision LIMIT ?").all(projectKey, sessionId, limit) : this.db.prepare("SELECT session_id, entry_id, revision FROM raw_entries WHERE project_key=? ORDER BY created_at,session_id,entry_id,revision LIMIT ?").all(projectKey, limit);
|
|
207
|
+
return rows.map((row) => ({ sessionId: row.session_id, entryId: row.entry_id, revision: Number(row.revision) }));
|
|
208
|
+
}
|
|
209
|
+
/** Total stored payload bytes for one session, as a single aggregate. */
|
|
210
|
+
payloadBytes(projectKey = this.project.key, sessionId) {
|
|
211
|
+
this.guard();
|
|
212
|
+
this.assertProjectKey(projectKey);
|
|
213
|
+
const row = sessionId ? this.db.prepare("SELECT coalesce(sum(length(payload_json)),0) n FROM raw_entries WHERE project_key=? AND session_id=?").get(projectKey, sessionId) : this.db.prepare("SELECT coalesce(sum(length(payload_json)),0) n FROM raw_entries WHERE project_key=?").get(projectKey);
|
|
214
|
+
return Number(row.n);
|
|
215
|
+
}
|
|
201
216
|
readOnly(fn) {
|
|
202
217
|
this.guard();
|
|
203
218
|
return fn(this.db);
|
|
@@ -294,6 +309,7 @@ import path2 from "node:path";
|
|
|
294
309
|
var hash2 = (data) => crypto2.createHash("sha256").update(data).digest("hex");
|
|
295
310
|
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
296
311
|
var nonblank = (value) => typeof value === "string" && value.trim().length > 0;
|
|
312
|
+
var sourceStillValid = (before, after) => after >= before;
|
|
297
313
|
var utc = (value) => {
|
|
298
314
|
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|\+00:00)$/.test(value)) throw new Error("timestamps must be explicit UTC ISO-8601 values");
|
|
299
315
|
const at = Date.parse(value);
|
|
@@ -434,7 +450,7 @@ function migrateSessions(options) {
|
|
|
434
450
|
offset += size;
|
|
435
451
|
}
|
|
436
452
|
const after = fs2.fstatSync(fd);
|
|
437
|
-
if (
|
|
453
|
+
if (!sourceStillValid(before.size, after.size)) throw new Error("source shrank during read");
|
|
438
454
|
} catch {
|
|
439
455
|
counts.errors++;
|
|
440
456
|
counts.incompleteDiscovery++;
|
|
@@ -609,6 +625,14 @@ var LcmMaintenance = class {
|
|
|
609
625
|
budgetPolicy() {
|
|
610
626
|
return { ...this.budget };
|
|
611
627
|
}
|
|
628
|
+
recordRevision(db, node) {
|
|
629
|
+
if (!node.text) return;
|
|
630
|
+
const row = db.prepare("SELECT coalesce(max(revision),0) n FROM summary_node_revisions WHERE node_id=?").get(node.nodeId);
|
|
631
|
+
db.prepare("INSERT OR IGNORE INTO summary_node_revisions(node_id,revision,project_key,text,model_hash,created_at) VALUES(?,?,?,?,?,?)").run(node.nodeId, Number(row.n) + 1, this.projectKey, node.text, node.modelHash, this.now());
|
|
632
|
+
}
|
|
633
|
+
revisionsOf(nodeId) {
|
|
634
|
+
return this.ledger.readOnly((db) => db.prepare("SELECT revision, text, model_hash, created_at FROM summary_node_revisions WHERE node_id=? AND project_key=? ORDER BY revision").all(nodeId, this.projectKey).map((row) => ({ revision: Number(row.revision), text: row.text, modelHash: row.model_hash, createdAt: Number(row.created_at) })));
|
|
635
|
+
}
|
|
612
636
|
selectUpgrades(sessionId, activeSources, branch, limit = 1) {
|
|
613
637
|
return this.listNodes(1e5).filter((node) => node.state === "ready" && node.modelHash === "emergency" && node.policyHash === this.policyHash && (!sessionId || node.sessionId === sessionId) && (branch === void 0 || node.branch === branch || node.branch === null) && (!activeSources || node.sources.every((source) => activeSources.has(this.sourceKey(source))))).sort((left, right) => left.depth - right.depth || left.nodeId.localeCompare(right.nodeId)).slice(0, limit);
|
|
614
638
|
}
|
|
@@ -643,8 +667,8 @@ var LcmMaintenance = class {
|
|
|
643
667
|
return job;
|
|
644
668
|
});
|
|
645
669
|
}
|
|
646
|
-
listNodes(limit = 100) {
|
|
647
|
-
return this.ledger.readOnly((db) => db.prepare("SELECT payload FROM summary_nodes WHERE project_key=? ORDER BY created_at,node_id LIMIT ?").all(this.projectKey, limit).map((r) => {
|
|
670
|
+
listNodes(limit = 100, offset = 0) {
|
|
671
|
+
return this.ledger.readOnly((db) => db.prepare("SELECT payload FROM summary_nodes WHERE project_key=? ORDER BY created_at,node_id LIMIT ? OFFSET ?").all(this.projectKey, limit, offset).map((r) => {
|
|
648
672
|
const node = parse(r.payload);
|
|
649
673
|
if (node.projectKey !== this.projectKey) throw new Error("node project does not match ledger project");
|
|
650
674
|
return node;
|
|
@@ -826,6 +850,7 @@ var LcmMaintenance = class {
|
|
|
826
850
|
const projectUsage = this.usage(db, this.day(this.now()));
|
|
827
851
|
const sessionUsage = this.usage(db, this.day(this.now()), node.sessionId);
|
|
828
852
|
if (projectUsage.calls + 1 > this.budget.calls || projectUsage.inputTokens + result.inputTokens > this.budget.inputTokens || projectUsage.outputTokens + result.outputTokens > this.budget.outputTokens || projectUsage.cost + result.cost > this.budget.cost || projectUsage.wallMs + result.wallMs > this.budget.wallMs || sessionUsage.calls + 1 > this.budget.sessionCalls) throw new Error("budget exhausted");
|
|
853
|
+
this.recordRevision(db, node);
|
|
829
854
|
const out = { ...node, state: "ready", text: result.text, modelHash: result.modelHash };
|
|
830
855
|
this.account(db, node.sessionId, result);
|
|
831
856
|
db.prepare("UPDATE summary_nodes SET payload=? WHERE node_id=? AND project_key=?").run(JSON.stringify(out), node.nodeId, this.projectKey);
|
|
@@ -849,6 +874,7 @@ var LcmMaintenance = class {
|
|
|
849
874
|
const raw = db.prepare("SELECT payload_json,session_id FROM raw_entries WHERE project_key=? AND session_id=? AND entry_id=? AND revision=?").get(this.projectKey, source.sessionId, source.entryId, source.revision);
|
|
850
875
|
if (!raw?.payload_json || hash3(parse(raw.payload_json)) !== source.payloadHash || raw.session_id !== source.sessionId) throw new Error("stale source");
|
|
851
876
|
}
|
|
877
|
+
this.recordRevision(db, node);
|
|
852
878
|
const out = { ...node, state: "ready", text, modelHash: "emergency" };
|
|
853
879
|
db.prepare("UPDATE summary_nodes SET payload=? WHERE node_id=? AND project_key=?").run(JSON.stringify(out), node.nodeId, this.projectKey);
|
|
854
880
|
const { ownerId: _ownerId, leaseToken: _leaseToken, leaseUntil: _leaseUntil, ...base } = current;
|
|
@@ -1225,10 +1251,62 @@ var LcmRuntime = class {
|
|
|
1225
1251
|
};
|
|
1226
1252
|
});
|
|
1227
1253
|
}
|
|
1254
|
+
frontierCache;
|
|
1255
|
+
/** One frontier walk shared by preview, coverage, and the coverage map. */
|
|
1256
|
+
frontierSnapshot() {
|
|
1257
|
+
const sessionId = this.activeSessionId ?? "";
|
|
1258
|
+
const branch = this.context.sessionManager.getLeafId();
|
|
1259
|
+
const cached = this.frontierCache;
|
|
1260
|
+
if (cached && cached.sessionId === sessionId && cached.branch === branch && Date.now() - cached.at < 250) {
|
|
1261
|
+
return { nodes: cached.nodes, covered: cached.covered };
|
|
1262
|
+
}
|
|
1263
|
+
const nodes = sessionId ? this.maintenance.getFrontier(sessionId, branch, this.activeSources) : [];
|
|
1264
|
+
const covered = new Set(nodes.flatMap((node) => node.sources.map((source) => this.sourceKey(source))));
|
|
1265
|
+
this.frontierCache = { at: Date.now(), sessionId, branch, nodes, covered };
|
|
1266
|
+
return { nodes, covered };
|
|
1267
|
+
}
|
|
1268
|
+
sourceKey(source) {
|
|
1269
|
+
return `${source.sessionId}:${source.entryId}:${source.revision}`;
|
|
1270
|
+
}
|
|
1271
|
+
/** Assembles what a compaction would serve now. Reads only; it never persists a node. */
|
|
1272
|
+
preview() {
|
|
1273
|
+
const sessionId = this.activeSessionId;
|
|
1274
|
+
if (!sessionId) return { text: "", nodes: 0, summaryBytes: 0, sourceBytes: 0, coveredSources: 0, activeSources: 0 };
|
|
1275
|
+
const { nodes, covered } = this.frontierSnapshot();
|
|
1276
|
+
const text = nodes.map((node) => node.text ?? "").filter(Boolean).join("\n\n");
|
|
1277
|
+
return {
|
|
1278
|
+
text,
|
|
1279
|
+
nodes: nodes.length,
|
|
1280
|
+
summaryBytes: Buffer.byteLength(text, "utf8"),
|
|
1281
|
+
sourceBytes: this.ledger.payloadBytes(this.projectKey, sessionId),
|
|
1282
|
+
coveredSources: covered.size,
|
|
1283
|
+
activeSources: this.activeSources.size
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
/** Ordered coverage of the active branch: each entry says whether a ready node holds it. */
|
|
1287
|
+
coverageMap(limit = 2e3) {
|
|
1288
|
+
const sessionId = this.activeSessionId;
|
|
1289
|
+
if (!sessionId) return [];
|
|
1290
|
+
const { covered } = this.frontierSnapshot();
|
|
1291
|
+
return this.ledger.readRawKeys(this.projectKey, sessionId, limit).map((entry) => {
|
|
1292
|
+
const key = this.sourceKey(entry);
|
|
1293
|
+
return { key, covered: covered.has(key) };
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
nodes(limit = 200, offset = 0) {
|
|
1297
|
+
return this.maintenance.listNodes(limit, offset);
|
|
1298
|
+
}
|
|
1299
|
+
node(nodeId) {
|
|
1300
|
+
const node = this.maintenance.getNode(nodeId);
|
|
1301
|
+
if (!node) return void 0;
|
|
1302
|
+
return { node, revisions: this.maintenance.revisionsOf(nodeId), ancestors: this.maintenance.ancestorsOf(nodeId) };
|
|
1303
|
+
}
|
|
1304
|
+
source(sessionId, entryId, revision) {
|
|
1305
|
+
return this.ledger.readRawEntry(this.projectKey, sessionId, entryId, revision);
|
|
1306
|
+
}
|
|
1228
1307
|
coverage() {
|
|
1229
1308
|
if (!this.activeSessionId) return { active: 0, covered: 0 };
|
|
1230
|
-
const
|
|
1231
|
-
const covered = new Set(frontier.flatMap((node) => node.sources.map((source) => `${source.sessionId}:${source.entryId}:${source.revision}`)));
|
|
1309
|
+
const { covered } = this.frontierSnapshot();
|
|
1232
1310
|
let hits = 0;
|
|
1233
1311
|
for (const key of this.activeSources) if (covered.has(key)) hits += 1;
|
|
1234
1312
|
return { active: this.activeSources.size, covered: hits };
|