draken 0.6.0 → 0.8.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 +43 -0
- package/MEMORY.md +64 -13
- package/README.md +25 -19
- package/SETUP.md +26 -3
- package/TRAY.md +3 -3
- package/VOICE.md +8 -6
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +65 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/memory/readiness.d.ts +4 -3
- package/dist/memory/readiness.d.ts.map +1 -1
- package/dist/memory/readiness.js +128 -35
- package/dist/memory/readiness.js.map +1 -1
- package/dist/memory/storage.d.ts.map +1 -1
- package/dist/memory/storage.js +1 -0
- package/dist/memory/storage.js.map +1 -1
- package/dist/routes/sync.d.ts.map +1 -1
- package/dist/routes/sync.js +9 -0
- package/dist/routes/sync.js.map +1 -1
- package/dist/sync/activity.d.ts +11 -1
- package/dist/sync/activity.d.ts.map +1 -1
- package/dist/sync/activity.js +18 -3
- package/dist/sync/activity.js.map +1 -1
- package/dist/sync/background.d.ts +7 -2
- package/dist/sync/background.d.ts.map +1 -1
- package/dist/sync/background.js +66 -19
- package/dist/sync/background.js.map +1 -1
- package/dist/sync/conversation.d.ts +20 -0
- package/dist/sync/conversation.d.ts.map +1 -0
- package/dist/sync/conversation.js +127 -0
- package/dist/sync/conversation.js.map +1 -0
- package/dist/sync/manager.d.ts.map +1 -1
- package/dist/sync/manager.js +56 -16
- package/dist/sync/manager.js.map +1 -1
- package/dist/sync/preparation.d.ts +1 -1
- package/dist/sync/preparation.d.ts.map +1 -1
- package/dist/sync/preparation.js +23 -5
- package/dist/sync/preparation.js.map +1 -1
- package/dist/sync/store.d.ts +4 -1
- package/dist/sync/store.d.ts.map +1 -1
- package/dist/sync/store.js +24 -7
- package/dist/sync/store.js.map +1 -1
- package/dist/sync/summary-preparation.d.ts +14 -0
- package/dist/sync/summary-preparation.d.ts.map +1 -0
- package/dist/sync/summary-preparation.js +205 -0
- package/dist/sync/summary-preparation.js.map +1 -0
- package/dist/sync/tree.d.ts +17 -1
- package/dist/sync/tree.d.ts.map +1 -1
- package/dist/sync/tree.js +94 -29
- package/dist/sync/tree.js.map +1 -1
- package/dist/sync/update-status.d.ts +9 -0
- package/dist/sync/update-status.d.ts.map +1 -0
- package/dist/sync/update-status.js +21 -0
- package/dist/sync/update-status.js.map +1 -0
- package/dist/sync/usage.d.ts +3 -1
- package/dist/sync/usage.d.ts.map +1 -1
- package/dist/sync/usage.js +24 -6
- package/dist/sync/usage.js.map +1 -1
- package/dist/types.d.ts +21 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/voice/live-context.d.ts +1 -1
- package/dist/voice/live-context.d.ts.map +1 -1
- package/dist/voice/live-context.js +1 -1
- package/dist/voice/live.d.ts.map +1 -1
- package/dist/voice/live.js +265 -32
- package/dist/voice/live.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/index-sHcfjDUD.js +131 -0
- package/public/index.html +1 -1
- package/public/assets/index-DXPfCm7z.js +0 -131
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.summaryPreparationEnabled = void 0;
|
|
4
|
+
exports.cancelSummaryPreparation = cancelSummaryPreparation;
|
|
5
|
+
exports.configureAutoSummary = configureAutoSummary;
|
|
6
|
+
exports.summaryPreparationSettings = summaryPreparationSettings;
|
|
7
|
+
exports.warmSummaryCache = warmSummaryCache;
|
|
8
|
+
const schema_1 = require("../db/schema");
|
|
9
|
+
const errors_1 = require("../errors");
|
|
10
|
+
const activity_1 = require("./activity");
|
|
11
|
+
const service_1 = require("../memory/service");
|
|
12
|
+
const store_1 = require("./store");
|
|
13
|
+
const tree_1 = require("./tree");
|
|
14
|
+
const normalize_1 = require("./normalize");
|
|
15
|
+
const BATCH = 64;
|
|
16
|
+
const FAILURE = 'Background summaries could not finish. Check provider settings, invocation limits and original session files, then explicitly enable summaries to retry. Cached work is retained.';
|
|
17
|
+
const setting = (key) => (0, schema_1.getDb)().prepare('SELECT value FROM sync_settings WHERE key=?').get(key)?.value;
|
|
18
|
+
function save(key, value) {
|
|
19
|
+
(0, schema_1.getDb)().prepare('INSERT INTO sync_settings(key,value) VALUES (?,?) ON CONFLICT(key) DO UPDATE SET value=excluded.value').run(key, value);
|
|
20
|
+
}
|
|
21
|
+
const summaryPreparationEnabled = () => setting('auto_summary') === 'true';
|
|
22
|
+
exports.summaryPreparationEnabled = summaryPreparationEnabled;
|
|
23
|
+
const indexingEnabled = () => setting('auto_index') === 'true';
|
|
24
|
+
const idle = () => activity_1.activity.backgroundIdle && !(0, service_1.historyProgress)().active && !(0, service_1.historyProgress)().queued;
|
|
25
|
+
let consentRevision = 0;
|
|
26
|
+
let active;
|
|
27
|
+
/** Cancellation is irrevocable for this job even if consent is immediately re-enabled. */
|
|
28
|
+
function cancelSummaryPreparation() {
|
|
29
|
+
const prior = active;
|
|
30
|
+
prior?.controller.abort();
|
|
31
|
+
// Return the owned promise, not a detached rejecting wrapper. The scheduler
|
|
32
|
+
// retains its rejection handler even when a synchronous setter only aborts.
|
|
33
|
+
return prior?.done || Promise.resolve();
|
|
34
|
+
}
|
|
35
|
+
/** Called by the scheduler's lifecycle owner; reads never start the scheduler. */
|
|
36
|
+
function configureAutoSummary(value) {
|
|
37
|
+
if (typeof value !== 'boolean')
|
|
38
|
+
throw new errors_1.HttpError(400, 'enabled must be a boolean');
|
|
39
|
+
if (value && !indexingEnabled())
|
|
40
|
+
throw new errors_1.HttpError(409, 'Enable automatic indexing before enabling paid background summaries.');
|
|
41
|
+
consentRevision++;
|
|
42
|
+
active?.controller.abort();
|
|
43
|
+
(0, schema_1.getDb)().transaction(() => {
|
|
44
|
+
save('auto_summary', String(value));
|
|
45
|
+
if (value)
|
|
46
|
+
save('auto_summary_error', '');
|
|
47
|
+
})();
|
|
48
|
+
}
|
|
49
|
+
function checkpoint(input) {
|
|
50
|
+
// Canonical recipe/input hashes only; no original text, paths or provider output.
|
|
51
|
+
// SQL sequence IDs can be reassigned by a full rescan; that does not turn
|
|
52
|
+
// unchanged original records into another paid batch. Receipt identity still
|
|
53
|
+
// includes full ordering, while this delta counts canonical source changes.
|
|
54
|
+
return { keys: input.items.map(item => [(0, normalize_1.digest)(JSON.stringify([item.agent || 'pi', item.session_id, item.entry_id])),
|
|
55
|
+
(0, normalize_1.digest)(JSON.stringify([(0, normalize_1.sourceKey)(item), item.agent, item.session_id, item.cwd, item.timestamp, item.role]))]),
|
|
56
|
+
recipe: (0, tree_1.summaryPreparationKey)({ ...input, items: [] }) };
|
|
57
|
+
}
|
|
58
|
+
function completed() {
|
|
59
|
+
return (0, schema_1.getDb)().prepare("SELECT id,input_key,source_keys_json,cache_receipt_json,total_entries,completed_at FROM background_runs WHERE status='completed' ORDER BY id DESC LIMIT 1").get();
|
|
60
|
+
}
|
|
61
|
+
function matching(key) {
|
|
62
|
+
return (0, schema_1.getDb)().prepare("SELECT id,input_key,source_keys_json,cache_receipt_json,total_entries,completed_at FROM background_runs WHERE status='completed' AND input_key=? ORDER BY id DESC LIMIT 1").get(key);
|
|
63
|
+
}
|
|
64
|
+
function cacheIntact(value) {
|
|
65
|
+
let pairs;
|
|
66
|
+
try {
|
|
67
|
+
pairs = typeof value === 'string' ? JSON.parse(value) : value;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
if (!Array.isArray(pairs) || !pairs.length || pairs.some(pair => !Array.isArray(pair) || pair.length !== 2 || pair.some(hash => typeof hash !== 'string' || !/^[a-f0-9]{64}$/.test(hash))))
|
|
73
|
+
return false;
|
|
74
|
+
const lookup = (0, schema_1.getDb)().prepare('SELECT output_json FROM summary_cache WHERE key=?');
|
|
75
|
+
return pairs.every(([key, hash]) => {
|
|
76
|
+
const row = lookup.get(key);
|
|
77
|
+
return row !== undefined && (0, normalize_1.digest)(row.output_json) === hash;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/** Historical progress, not a live readiness claim. Polling must not reopen
|
|
81
|
+
* transcript bodies; the preparing owner and explicit sync validate originals. */
|
|
82
|
+
function summaryPreparationSettings() {
|
|
83
|
+
const enabled = (0, exports.summaryPreparationEnabled)(), error = setting('auto_summary_error') || '';
|
|
84
|
+
const last = (0, schema_1.getDb)().prepare("SELECT total_entries,completed_at FROM background_runs WHERE status='completed' ORDER BY id DESC LIMIT 1").get();
|
|
85
|
+
return { enabled, status: !enabled ? 'off' : error ? 'error' : !indexingEnabled() || !idle() || active?.controller.signal.aborted ? 'paused' : active?.working ? 'running' : 'waiting',
|
|
86
|
+
prepared_entries: last?.total_entries || 0, last_completed_at: last?.completed_at || null, error };
|
|
87
|
+
}
|
|
88
|
+
/** Prepare only reusable summaries. No sync identity, snapshot, briefing or verdict.
|
|
89
|
+
* A successful receipt suppresses repeated work; a failure blocks all automatic
|
|
90
|
+
* paid retries until explicit consent/retry. Cancellation retains its allowance. */
|
|
91
|
+
async function warmSummaryCache(signal, onWork) {
|
|
92
|
+
if (signal.aborted || !(0, exports.summaryPreparationEnabled)() || !indexingEnabled() || !idle() || setting('auto_summary_error'))
|
|
93
|
+
return;
|
|
94
|
+
if (active)
|
|
95
|
+
return active.done;
|
|
96
|
+
const controller = new AbortController();
|
|
97
|
+
const abort = () => controller.abort();
|
|
98
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
99
|
+
const revision = consentRevision;
|
|
100
|
+
const owner = { controller, done: Promise.resolve(), working: false };
|
|
101
|
+
active = owner;
|
|
102
|
+
owner.done = Promise.resolve().then(async () => {
|
|
103
|
+
let run;
|
|
104
|
+
const admitted = () => !controller.signal.aborted && (0, exports.summaryPreparationEnabled)() && indexingEnabled() && idle();
|
|
105
|
+
const check = () => { if (!admitted()) {
|
|
106
|
+
controller.abort();
|
|
107
|
+
throw new errors_1.HttpError(409, 'Background preparation paused');
|
|
108
|
+
} };
|
|
109
|
+
try {
|
|
110
|
+
check();
|
|
111
|
+
const db = (0, schema_1.getDb)();
|
|
112
|
+
// Startup recovery is responsible for interrupted ownership. A running row
|
|
113
|
+
// with no process-local job can also mean failure metadata could not be
|
|
114
|
+
// committed. Never silently replace that run with a fresh allowance.
|
|
115
|
+
const orphan = db.prepare("SELECT id,invocations,max_invocations FROM background_runs WHERE status='running' LIMIT 1").get();
|
|
116
|
+
if (orphan) {
|
|
117
|
+
run = orphan;
|
|
118
|
+
throw new Error('Background ownership was not recovered');
|
|
119
|
+
}
|
|
120
|
+
const input = (0, store_1.previewSummaryInput)();
|
|
121
|
+
(0, store_1.assertEvidenceAvailable)(input);
|
|
122
|
+
const key = (0, tree_1.summaryPreparationKey)(input);
|
|
123
|
+
const receipt = matching(key);
|
|
124
|
+
if (receipt && cacheIntact(receipt.cache_receipt_json))
|
|
125
|
+
return;
|
|
126
|
+
const sources = checkpoint(input), last = completed();
|
|
127
|
+
let prior;
|
|
128
|
+
if (last) {
|
|
129
|
+
prior = JSON.parse(last.source_keys_json);
|
|
130
|
+
if (!Array.isArray(prior.keys) || prior.keys.some(pair => !Array.isArray(pair) || pair.length !== 2 || pair.some(value => typeof value !== 'string')) || typeof prior.recipe !== 'string')
|
|
131
|
+
throw new Error('Invalid receipt metadata');
|
|
132
|
+
}
|
|
133
|
+
const old = new Map(prior?.keys), current = new Map(sources.keys);
|
|
134
|
+
const changed = sources.keys.filter(([id, hash]) => old.get(id) !== hash).length + [...old.keys()].filter(id => !current.has(id)).length;
|
|
135
|
+
// Model/recipe/context changes need a fresh full receipt even when no IDs arrived.
|
|
136
|
+
if (input.items.length < BATCH || (!receipt && changed < BATCH && (!prior || prior.recipe === sources.recipe)))
|
|
137
|
+
return;
|
|
138
|
+
check();
|
|
139
|
+
run = db.prepare(`SELECT id,invocations,max_invocations FROM background_runs WHERE input_key=?
|
|
140
|
+
AND status IN ('cancelled','interrupted') ORDER BY id DESC LIMIT 1`).get(key);
|
|
141
|
+
// Never resurrect an older interrupted allowance after an explicitly retried attempt.
|
|
142
|
+
const latest = db.prepare('SELECT id FROM background_runs WHERE input_key=? ORDER BY id DESC LIMIT 1').get(key);
|
|
143
|
+
if (run && latest?.id !== run.id)
|
|
144
|
+
run = undefined;
|
|
145
|
+
if (run) {
|
|
146
|
+
db.prepare("UPDATE background_runs SET status='running',stage='Planning',processed_entries=0,cache_hits=0,error='',completed_at=NULL WHERE id=?").run(run.id);
|
|
147
|
+
input.models = { ...input.models, max_invocations: run.max_invocations };
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const result = db.prepare(`INSERT INTO background_runs(summary_model,final_model,max_invocations,total_entries,started_at,input_key,source_keys_json)
|
|
151
|
+
VALUES (?,?,?,?,?,?,?)`).run(input.models.summary, input.models.final, input.models.max_invocations, input.items.length, new Date().toISOString(), key, JSON.stringify(sources));
|
|
152
|
+
run = { id: Number(result.lastInsertRowid), invocations: 0, max_invocations: input.models.max_invocations };
|
|
153
|
+
}
|
|
154
|
+
owner.working = true;
|
|
155
|
+
onWork?.();
|
|
156
|
+
const tree = tree_1.SummaryTree.forBackground(input, run.id, controller.signal);
|
|
157
|
+
// Recheck at the last boundary before *each* provider call, including repairs
|
|
158
|
+
// and reconciliation after an await. Route-level yielding also drains this owner.
|
|
159
|
+
const call = tree.call.bind(tree);
|
|
160
|
+
tree.call = async (payload, system, final = false) => {
|
|
161
|
+
check();
|
|
162
|
+
if (final)
|
|
163
|
+
throw new Error('Background preparation cannot request a verdict');
|
|
164
|
+
return call(payload, system, false);
|
|
165
|
+
};
|
|
166
|
+
await tree.build();
|
|
167
|
+
check();
|
|
168
|
+
// Inputs can change while a provider is in flight. Keep useful cache fragments,
|
|
169
|
+
// but never publish a receipt for sources/models no longer admitted or available.
|
|
170
|
+
const latestInput = (0, store_1.previewSummaryInput)();
|
|
171
|
+
(0, store_1.assertEvidenceAvailable)(latestInput);
|
|
172
|
+
if ((0, tree_1.summaryPreparationKey)(latestInput) !== key) {
|
|
173
|
+
controller.abort();
|
|
174
|
+
throw new Error('Input changed');
|
|
175
|
+
}
|
|
176
|
+
const cacheReceipt = tree.cacheReceipt();
|
|
177
|
+
if (!cacheIntact(cacheReceipt))
|
|
178
|
+
throw new Error('Summary cache changed before completion');
|
|
179
|
+
db.prepare("UPDATE background_runs SET status='completed',stage='Cached',error='',completed_at=?,cache_receipt_json=? WHERE id=?")
|
|
180
|
+
.run(new Date().toISOString(), JSON.stringify(cacheReceipt), run.id);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
const db = (0, schema_1.getDb)();
|
|
184
|
+
const counters = run && db.prepare('SELECT invocations,max_invocations FROM background_runs WHERE id=?').get(run.id);
|
|
185
|
+
const cancelled = controller.signal.aborted;
|
|
186
|
+
// Exhausted cancellations are also blocked: do not spin a quota 409 every minute.
|
|
187
|
+
const exhausted = Boolean(counters && counters.invocations >= counters.max_invocations);
|
|
188
|
+
const status = cancelled && !exhausted ? 'cancelled' : 'failed', at = new Date().toISOString();
|
|
189
|
+
db.transaction(() => {
|
|
190
|
+
if (run)
|
|
191
|
+
db.prepare(`UPDATE background_runs SET status=?,error=?,completed_at=?,
|
|
192
|
+
failure_events_json=json_insert(failure_events_json,'$[#]',json(?)) WHERE id=?`)
|
|
193
|
+
.run(status, cancelled && !exhausted ? '' : FAILURE, at, JSON.stringify({ status, at }), run.id);
|
|
194
|
+
if (revision === consentRevision && (!cancelled || exhausted))
|
|
195
|
+
save('auto_summary_error', FAILURE);
|
|
196
|
+
})();
|
|
197
|
+
}
|
|
198
|
+
}).finally(() => {
|
|
199
|
+
signal.removeEventListener('abort', abort);
|
|
200
|
+
if (active === owner)
|
|
201
|
+
active = undefined;
|
|
202
|
+
});
|
|
203
|
+
return owner.done;
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=summary-preparation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary-preparation.js","sourceRoot":"","sources":["../../src/sync/summary-preparation.ts"],"names":[],"mappings":"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"}
|
package/dist/sync/tree.d.ts
CHANGED
|
@@ -18,6 +18,13 @@ export declare function repairSummaryCitations(candidate: NodeSummary, value: un
|
|
|
18
18
|
characters: number;
|
|
19
19
|
}): NodeSummary;
|
|
20
20
|
export declare function validateGroups(value: unknown, allowed: Set<string>): TopicGroups;
|
|
21
|
+
/** Evidence and models only: background preparation does not own a sync. */
|
|
22
|
+
export type SummaryInput = Pick<SyncDetail, 'items' | 'context' | 'models'>;
|
|
23
|
+
declare const BACKGROUND: unique symbol;
|
|
24
|
+
/** A receipt identity, not a persisted copy of the evidence. Keep this recipe
|
|
25
|
+
* version in step with planning/validation/transport changes, even when old
|
|
26
|
+
* validated leaf cache keys intentionally remain compatible. */
|
|
27
|
+
export declare function summaryPreparationKey(input: SummaryInput): string;
|
|
21
28
|
export declare class SummaryTree {
|
|
22
29
|
private sync;
|
|
23
30
|
private runId;
|
|
@@ -26,7 +33,15 @@ export declare class SummaryTree {
|
|
|
26
33
|
private readonly sourceMap;
|
|
27
34
|
private readonly primary;
|
|
28
35
|
private readonly accountAggregation;
|
|
29
|
-
|
|
36
|
+
private readonly runTable;
|
|
37
|
+
private readonly background;
|
|
38
|
+
private readonly cacheHashes;
|
|
39
|
+
static forBackground(input: SummaryInput, runId: number, signal: AbortSignal): SummaryTree;
|
|
40
|
+
constructor(sync: SummaryInput & {
|
|
41
|
+
id?: number;
|
|
42
|
+
}, runId: number, signal: AbortSignal, mode?: typeof BACKGROUND);
|
|
43
|
+
/** Hashes of the validated outputs consumed by this background build. */
|
|
44
|
+
cacheReceipt(): [string, string][];
|
|
30
45
|
private stage;
|
|
31
46
|
call(payload: unknown, system: string, final?: boolean): Promise<string>;
|
|
32
47
|
private register;
|
|
@@ -66,4 +81,5 @@ export declare class SummaryTree {
|
|
|
66
81
|
topic: string;
|
|
67
82
|
}[];
|
|
68
83
|
}
|
|
84
|
+
export {};
|
|
69
85
|
//# sourceMappingURL=tree.d.ts.map
|
package/dist/sync/tree.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../src/sync/tree.ts"],"names":[],"mappings":"AACA,OAAO,EAA6B,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAiDrG,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA4BD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM;;;;CAAgB,GAAG,WAAW,CAmBzG;AAED,iGAAiG;AACjG,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM;;;;CAAgB,GAAG,WAAW,CAiBxI;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,WAAW,CAehF;AAoBD,qBAAa,WAAW;
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../src/sync/tree.ts"],"names":[],"mappings":"AACA,OAAO,EAA6B,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAiDrG,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA4BD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM;;;;CAAgB,GAAG,WAAW,CAmBzG;AAED,iGAAiG;AACjG,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM;;;;CAAgB,GAAG,WAAW,CAiBxI;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,WAAW,CAehF;AAoBD,4EAA4E;AAC5E,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC,CAAC;AAC5E,QAAA,MAAM,UAAU,eAA2C,CAAC;AAE5D;;gEAEgE;AAChE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAajE;AAED,qBAAa,WAAW;IAaV,OAAO,CAAC,IAAI;IAAkC,OAAO,CAAC,KAAK;IAAU,OAAO,CAAC,MAAM;IAZ/F,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAClD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAU;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAC3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IAEzD,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,WAAW;gBAItE,IAAI,EAAE,YAAY,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,EAAU,KAAK,EAAE,MAAM,EAAU,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO,UAAU;IAWtI,yEAAyE;IACzE,YAAY,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;IAElC,OAAO,CAAC,KAAK;IAOP,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAsC5E,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,IAAI;YAYE,IAAI;IA4ElB,OAAO,CAAC,UAAU;IA0BlB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,KAAK;YAYC,UAAU;YAeV,MAAM;IAQpB,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,UAAU;IAoDlB,OAAO,CAAC,YAAY;YAKN,cAAc;YAed,YAAY;IA+BpB,KAAK,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAmErC,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;CACpC"}
|
package/dist/sync/tree.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.SummaryTree = void 0;
|
|
|
4
4
|
exports.validateSummary = validateSummary;
|
|
5
5
|
exports.repairSummaryCitations = repairSummaryCitations;
|
|
6
6
|
exports.validateGroups = validateGroups;
|
|
7
|
+
exports.summaryPreparationKey = summaryPreparationKey;
|
|
7
8
|
const schema_1 = require("../db/schema");
|
|
8
9
|
const normalize_1 = require("./normalize");
|
|
9
10
|
const store_1 = require("./store");
|
|
@@ -164,6 +165,24 @@ function pack(items, cost, maxChars, maxItems) {
|
|
|
164
165
|
function sourceData(item, background = false) {
|
|
165
166
|
return { ...(item.agent && item.agent !== 'pi' ? { agent: item.agent } : {}), id: (0, normalize_1.sourceKey)(item), workspace: item.cwd, timestamp: item.timestamp, sequence: item.sequence, role: item.role, background, text: (0, normalize_1.cleanText)(item.text, Number.MAX_SAFE_INTEGER) };
|
|
166
167
|
}
|
|
168
|
+
const BACKGROUND = Symbol('background summary preparation');
|
|
169
|
+
/** A receipt identity, not a persisted copy of the evidence. Keep this recipe
|
|
170
|
+
* version in step with planning/validation/transport changes, even when old
|
|
171
|
+
* validated leaf cache keys intentionally remain compatible. */
|
|
172
|
+
function summaryPreparationKey(input) {
|
|
173
|
+
const sources = (items, background) => items.map(item => ({
|
|
174
|
+
session: item.session_id, label: item.session_name, ...sourceData(item, background),
|
|
175
|
+
}));
|
|
176
|
+
return (0, normalize_1.digest)(JSON.stringify({
|
|
177
|
+
recipe: 'summary-preparation-v1-stable-prefix',
|
|
178
|
+
prompts: { PROMPT_VERSION, legacySummarySystem, summarySystem, batchSummarySystem, citationRepairSystem, groupingSystem },
|
|
179
|
+
budgets: { CHUNK_CHARS, MERGE_CHARS, OUTPUT_CHARS, BATCH_OUTPUT, LEGACY_OUTPUT, MAX_EVIDENCE, LUNA_BATCH: summary_budget_1.LUNA_BATCH },
|
|
180
|
+
// Versions of the shared normalization, short-label transport and token estimator.
|
|
181
|
+
dependencies: ['normalization-v2', 'references-v2', 'o200k_base-gpt-tokenizer-4.1.0', 'prompt-headroom-1.2-8192'],
|
|
182
|
+
models: { summary: input.models.summary, final: input.models.final, max_invocations: input.models.max_invocations },
|
|
183
|
+
items: sources(input.items, false), context: sources(input.context, true),
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
167
186
|
class SummaryTree {
|
|
168
187
|
sync;
|
|
169
188
|
runId;
|
|
@@ -172,23 +191,39 @@ class SummaryTree {
|
|
|
172
191
|
sourceMap;
|
|
173
192
|
primary;
|
|
174
193
|
accountAggregation;
|
|
175
|
-
|
|
194
|
+
runTable;
|
|
195
|
+
background;
|
|
196
|
+
cacheHashes = new Map();
|
|
197
|
+
static forBackground(input, runId, signal) {
|
|
198
|
+
return new SummaryTree(input, runId, signal, BACKGROUND);
|
|
199
|
+
}
|
|
200
|
+
constructor(sync, runId, signal, mode) {
|
|
176
201
|
this.sync = sync;
|
|
177
202
|
this.runId = runId;
|
|
178
203
|
this.signal = signal;
|
|
204
|
+
this.background = mode === BACKGROUND;
|
|
205
|
+
this.runTable = this.background ? 'background_runs' : 'sync_runs';
|
|
206
|
+
if (!this.background && !Number.isSafeInteger(sync.id))
|
|
207
|
+
throw new Error('Foreground summary preparation requires a sync ID');
|
|
179
208
|
(0, store_1.assertEvidenceAvailable)(sync);
|
|
180
|
-
this.accountAggregation = this.db.prepare('SELECT question FROM sync_runs WHERE id=?').get(runId)?.question === null;
|
|
209
|
+
this.accountAggregation = this.background || this.db.prepare('SELECT question FROM sync_runs WHERE id=?').get(runId)?.question === null;
|
|
181
210
|
this.sourceMap = new Map([...sync.context, ...sync.items].map(item => [(0, normalize_1.sourceKey)(item), item]));
|
|
182
211
|
this.primary = new Set(sync.items.map(normalize_1.sourceKey));
|
|
183
212
|
if (this.primary.size !== sync.items.length)
|
|
184
213
|
throw new Error('Duplicate canonical source IDs in snapshot');
|
|
185
214
|
}
|
|
186
|
-
|
|
215
|
+
/** Hashes of the validated outputs consumed by this background build. */
|
|
216
|
+
cacheReceipt() { return [...this.cacheHashes]; }
|
|
217
|
+
stage(stage, detail) {
|
|
187
218
|
if (this.signal.aborted)
|
|
188
219
|
throw new errors_1.HttpError(409, 'Generation cancelled');
|
|
189
|
-
|
|
220
|
+
// Background accounting must never retain session titles, paths or model prose.
|
|
221
|
+
const label = !this.background && detail ? `${stage}: ${detail}` : stage;
|
|
222
|
+
this.db.prepare(`UPDATE ${this.runTable} SET stage = ? WHERE id = ?`).run(label, this.runId);
|
|
190
223
|
}
|
|
191
224
|
async call(payload, system, final = false) {
|
|
225
|
+
if (this.background && final)
|
|
226
|
+
throw new errors_1.HttpError(409, 'Background preparation cannot call the final provider');
|
|
192
227
|
if (this.signal.aborted)
|
|
193
228
|
throw new errors_1.HttpError(409, 'Generation cancelled');
|
|
194
229
|
const model = final ? this.sync.models.final : this.sync.models.summary;
|
|
@@ -199,14 +234,14 @@ class SummaryTree {
|
|
|
199
234
|
throw new errors_1.HttpError(400, 'Summary request exceeds its token safety budget; cached work is intact.');
|
|
200
235
|
if (final && (0, summary_budget_1.isBatchSummaryModel)(this.sync.models.summary) && estimatedTokens > summary_budget_1.LUNA_BATCH.finalTokens)
|
|
201
236
|
throw new errors_1.HttpError(400, 'The final input exceeds its compact token budget; no larger or more expensive request was substituted. Cached summaries are intact.');
|
|
202
|
-
const limit = this.sync.models.max_invocations - (final ? 0 : 1);
|
|
237
|
+
const limit = this.sync.models.max_invocations - (final || this.background ? 0 : 1);
|
|
203
238
|
const started = Date.now(), request = payload;
|
|
204
239
|
const pending = { started_at: new Date(started).toISOString(), task: request.task || 'unknown', stage: request.stage || null,
|
|
205
240
|
repair: Boolean(request.repair), model, elapsed_ms: 0, input_characters: prompt.length, input_tokens_estimate: estimatedTokens,
|
|
206
241
|
output_characters: null, output_tokens_estimate: null, status: 'running' };
|
|
207
242
|
// Reserve budget and the timestamped metadata slot atomically. An interrupted
|
|
208
243
|
// request remains explicitly unpriced rather than disappearing from usage.
|
|
209
|
-
const claimed = this.db.prepare(`UPDATE
|
|
244
|
+
const claimed = this.db.prepare(`UPDATE ${this.runTable} SET invocations=invocations+1,
|
|
210
245
|
metrics_json=json_insert(metrics_json,'$[#]',json(?)) WHERE id=? AND invocations<?
|
|
211
246
|
RETURNING json_array_length(metrics_json)-1 AS metric_index`).get(JSON.stringify(pending), this.runId, limit);
|
|
212
247
|
if (!claimed)
|
|
@@ -216,6 +251,8 @@ class SummaryTree {
|
|
|
216
251
|
try {
|
|
217
252
|
response = await (0, pi_1.invokePi)(prompt, { model, system, signal: this.signal, thinking: final ? 'medium' : 'off', largeSummary: large,
|
|
218
253
|
onAccounting: this.accountAggregation ? value => { accounting = value; } : undefined });
|
|
254
|
+
if (this.signal.aborted)
|
|
255
|
+
throw new errors_1.HttpError(409, 'Generation cancelled');
|
|
219
256
|
return response;
|
|
220
257
|
}
|
|
221
258
|
finally {
|
|
@@ -223,12 +260,14 @@ class SummaryTree {
|
|
|
223
260
|
elapsed_ms: Date.now() - started, input_characters: prompt.length,
|
|
224
261
|
input_tokens_estimate: estimatedTokens, output_characters: response?.length ?? null,
|
|
225
262
|
output_tokens_estimate: response === undefined ? null : (0, summary_budget_1.summaryTokens)(response),
|
|
226
|
-
status:
|
|
263
|
+
status: this.signal.aborted ? 'cancelled' : response !== undefined ? 'completed' : 'failed' };
|
|
227
264
|
// Metadata only: no prompts, rejected prose, source text, paths or credentials.
|
|
228
|
-
this.db.prepare(
|
|
265
|
+
this.db.prepare(`UPDATE ${this.runTable} SET metrics_json=json_set(metrics_json,?,json(?)) WHERE id=?`).run(`$[${claimed.metric_index}]`, JSON.stringify(metric), this.runId);
|
|
229
266
|
}
|
|
230
267
|
}
|
|
231
268
|
register(spec) {
|
|
269
|
+
if (this.background)
|
|
270
|
+
return;
|
|
232
271
|
this.db.prepare(`INSERT OR IGNORE INTO sync_tree_nodes(sync_id, key, kind, label, children_json, source_count)
|
|
233
272
|
VALUES (?, ?, ?, ?, ?, ?)`).run(this.sync.id, spec.key, spec.kind, spec.label, JSON.stringify(spec.children), spec.sources.length);
|
|
234
273
|
}
|
|
@@ -247,13 +286,22 @@ class SummaryTree {
|
|
|
247
286
|
async node(spec, validate, derived) {
|
|
248
287
|
this.register(spec);
|
|
249
288
|
const limits = spec.batch ? BATCH_OUTPUT : LEGACY_OUTPUT;
|
|
250
|
-
const setStatus = (status, error = '') =>
|
|
289
|
+
const setStatus = (status, error = '') => {
|
|
290
|
+
if (!this.background)
|
|
291
|
+
this.db.prepare('UPDATE sync_tree_nodes SET status = ?, error = ? WHERE sync_id = ? AND key = ?').run(status, error, this.sync.id, spec.key);
|
|
292
|
+
};
|
|
251
293
|
const finish = (cached) => {
|
|
294
|
+
if (this.background) {
|
|
295
|
+
const row = this.db.prepare('SELECT output_json FROM summary_cache WHERE key=?').get(spec.key);
|
|
296
|
+
if (!row)
|
|
297
|
+
throw new Error('A validated summary cache entry disappeared');
|
|
298
|
+
this.cacheHashes.set(spec.key, (0, normalize_1.digest)(row.output_json));
|
|
299
|
+
}
|
|
252
300
|
setStatus(cached ? 'cached' : 'done');
|
|
253
|
-
this.db.prepare(
|
|
301
|
+
this.db.prepare(`UPDATE ${this.runTable} SET cache_hits = cache_hits + ?, processed_entries = processed_entries + ? WHERE id = ?`)
|
|
254
302
|
.run(Number(cached), spec.kind === 'chunk' ? spec.sources.length : 0, this.runId);
|
|
255
303
|
};
|
|
256
|
-
this.stage(
|
|
304
|
+
this.stage(spec.kind, spec.label);
|
|
257
305
|
for (const cacheKey of [spec.key, spec.legacyKey].filter((key) => Boolean(key))) {
|
|
258
306
|
const cache = this.db.prepare('SELECT output_json FROM summary_cache WHERE key = ?').get(cacheKey);
|
|
259
307
|
if (!cache)
|
|
@@ -286,7 +334,7 @@ class SummaryTree {
|
|
|
286
334
|
let parsed;
|
|
287
335
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
288
336
|
if (attempt)
|
|
289
|
-
this.stage(`Repairing ${spec.kind}
|
|
337
|
+
this.stage(`Repairing ${spec.kind}`, `${spec.label} (attempt 2 of 2)`);
|
|
290
338
|
const citationRepair = attempt > 0 && citationCandidate !== undefined;
|
|
291
339
|
const response = await this.call({ task: citationRepair ? 'repair_summary_citations' : spec.kind === 'topics' ? 'group_topics' : 'summarize', stage: spec.kind,
|
|
292
340
|
input: wire.input,
|
|
@@ -440,15 +488,31 @@ class SummaryTree {
|
|
|
440
488
|
: this.sync.context.filter(item => item.session_id === session).slice(-6).map(item => sourceData(item, true));
|
|
441
489
|
const input = { session, workspace: batch[0].cwd, evidence: batch.map(item => sourceData(item)), background };
|
|
442
490
|
const allowed = new Set([...input.evidence, ...background].map(item => item.id));
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
491
|
+
const fits = (length) => {
|
|
492
|
+
const prefix = { ...input, evidence: input.evidence.slice(0, length) };
|
|
493
|
+
const refs = new Set([...prefix.evidence, ...background].map(item => item.id));
|
|
494
|
+
const wire = (0, references_1.prepareModelInput)('chunk', prefix, refs);
|
|
495
|
+
const prompt = JSON.stringify({ task: 'summarize', stage: 'chunk', allowed_source_ids: [...wire.allowed], input: wire.input });
|
|
496
|
+
return (0, summary_budget_1.promptTokens)(prompt, batchSummarySystem) <= summary_budget_1.LUNA_BATCH.plannedRequestTokens &&
|
|
497
|
+
Buffer.byteLength(prompt) + Buffer.byteLength(batchSummarySystem) <= summary_budget_1.LUNA_BATCH.inputBytes;
|
|
498
|
+
};
|
|
499
|
+
if (!fits(batch.length)) {
|
|
500
|
+
if (!fits(1))
|
|
448
501
|
throw new errors_1.HttpError(400, 'One entry and its background exceed the summary budget; no evidence was dropped.');
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
502
|
+
// Never bisect by the current tail length: its midpoint moves when
|
|
503
|
+
// history is appended, invalidating completed large leaves. Fill a
|
|
504
|
+
// deterministic prefix instead, then plan the remainder with its
|
|
505
|
+
// own adjacent evidence. Existing unsplit keys remain unchanged.
|
|
506
|
+
let low = 1, high = batch.length;
|
|
507
|
+
while (low + 1 < high) {
|
|
508
|
+
const middle = Math.floor((low + high) / 2);
|
|
509
|
+
if (fits(middle))
|
|
510
|
+
low = middle;
|
|
511
|
+
else
|
|
512
|
+
high = middle;
|
|
513
|
+
}
|
|
514
|
+
append(batch.slice(0, low));
|
|
515
|
+
append(batch.slice(low));
|
|
452
516
|
return;
|
|
453
517
|
}
|
|
454
518
|
result.push(this.spec('chunk', `${batch[0].session_name || batch[0].cwd} · batch ${first + 1}–${first + batch.length}`, input, allowed, batch.map(normalize_1.sourceKey), [], true));
|
|
@@ -496,14 +560,14 @@ class SummaryTree {
|
|
|
496
560
|
const missing = specs.filter(spec => !this.cached(spec)).length;
|
|
497
561
|
// A lower bound: reconciliation may add calls, or reuse a cached parent.
|
|
498
562
|
// Do not reject an all-cached tree that only needs its reserved final slot.
|
|
499
|
-
const minimum = missing + 1;
|
|
563
|
+
const minimum = missing + (this.background ? 0 : 1);
|
|
500
564
|
if (minimum > this.sync.models.max_invocations)
|
|
501
|
-
throw new errors_1.HttpError(409, `At least ${minimum} invocations are needed for uncached batches and the verdict, before any uncached reconciliation. Raise the invocation limit; no model calls have been made.`);
|
|
565
|
+
throw new errors_1.HttpError(409, `At least ${minimum} invocations are needed for uncached batches${this.background ? '' : ' and the verdict'}, before any uncached reconciliation. Raise the invocation limit; no model calls have been made.`);
|
|
502
566
|
let nodes = [];
|
|
503
567
|
for (const spec of specs)
|
|
504
568
|
nodes.push({ key: spec.key, kind: 'chunk', label: spec.label, sources: spec.sources,
|
|
505
569
|
summary: await this.node(spec, (value, refs) => validateSummary(value, refs, spec.batch ? BATCH_OUTPUT : LEGACY_OUTPUT)) });
|
|
506
|
-
const processed = this.db.prepare(
|
|
570
|
+
const processed = this.db.prepare(`SELECT processed_entries FROM ${this.runTable} WHERE id=?`).get(this.runId).processed_entries;
|
|
507
571
|
if (processed !== this.sync.items.length)
|
|
508
572
|
throw new Error('Incomplete source coverage: refusing to generate a final verdict');
|
|
509
573
|
for (let depth = 0; nodes.length > 1; depth++) {
|
|
@@ -524,7 +588,7 @@ class SummaryTree {
|
|
|
524
588
|
nodes = [await this.reconcileBatch(nodes, 'Compact final input', true)];
|
|
525
589
|
if (!this.compactRoots(nodes))
|
|
526
590
|
throw new errors_1.HttpError(400, 'The reconciled summary cannot fit the compact final budget. Cached results remain inspectable; no evidence was marked reviewed.');
|
|
527
|
-
this.stage('Final verdict');
|
|
591
|
+
this.stage(this.background ? 'Summaries prepared' : 'Final verdict');
|
|
528
592
|
return nodes;
|
|
529
593
|
}
|
|
530
594
|
async build() {
|
|
@@ -532,9 +596,10 @@ class SummaryTree {
|
|
|
532
596
|
return this.buildBatched();
|
|
533
597
|
// Unknown/operator-selected models retain their established conservative limits.
|
|
534
598
|
const specs = this.chunkSpecs();
|
|
535
|
-
const missing = [...specs.values()].flat().filter(spec => !this.
|
|
536
|
-
|
|
537
|
-
|
|
599
|
+
const missing = [...specs.values()].flat().filter(spec => !this.cached(spec)).length;
|
|
600
|
+
const minimum = missing + (this.background ? 0 : 1);
|
|
601
|
+
if (minimum > this.sync.models.max_invocations)
|
|
602
|
+
throw new errors_1.HttpError(409, `At least ${minimum} invocations are needed just for uncached chunks${this.background ? '' : ' and the verdict'}, before merges. Raise the invocation limit; no model calls have been made.`);
|
|
538
603
|
const sessionRoots = [];
|
|
539
604
|
// Deliberately serial for predictable quotas/cancellation. Cached nodes are instant.
|
|
540
605
|
for (const [session, chunks] of specs) {
|
|
@@ -543,7 +608,7 @@ class SummaryTree {
|
|
|
543
608
|
nodes.push({ key: spec.key, kind: 'chunk', label: spec.label, sources: spec.sources, summary: await this.node(spec, validateSummary) });
|
|
544
609
|
sessionRoots.push(await this.reduce(nodes, 'session', `Session ${session.slice(0, 8)}`));
|
|
545
610
|
}
|
|
546
|
-
const processed = this.db.prepare(
|
|
611
|
+
const processed = this.db.prepare(`SELECT processed_entries FROM ${this.runTable} WHERE id = ?`).get(this.runId).processed_entries;
|
|
547
612
|
if (processed !== this.sync.items.length)
|
|
548
613
|
throw new Error('Incomplete source coverage: refusing to generate a final verdict');
|
|
549
614
|
const descriptors = sessionRoots.flatMap(node => node.summary.observations.map((observation, index) => ({
|
|
@@ -589,7 +654,7 @@ class SummaryTree {
|
|
|
589
654
|
throw new Error('Cross-topic tree depth exceeded');
|
|
590
655
|
roots = await this.mergeLevel(roots, 'overview', `Cross-topic reconciliation ${depth + 1}`);
|
|
591
656
|
}
|
|
592
|
-
this.stage('Final verdict');
|
|
657
|
+
this.stage(this.background ? 'Summaries prepared' : 'Final verdict');
|
|
593
658
|
return roots;
|
|
594
659
|
}
|
|
595
660
|
// Final verification records supply roles/session/sequence once per distinct
|