@openagentsy/ledger 0.0.0-stage → 0.2.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/LICENSE +674 -0
- package/README.md +20 -2
- package/data/pricing/litellm.json +8882 -0
- package/data/pricing/models.dev.json +12151 -0
- package/data/pricing/openrouter.json +1017 -0
- package/dist/db.d.ts +44 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +97 -0
- package/dist/db.js.map +1 -0
- package/dist/export.d.ts +71 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +78 -0
- package/dist/export.js.map +1 -0
- package/dist/footprint.d.ts +24 -0
- package/dist/footprint.d.ts.map +1 -0
- package/dist/footprint.js +33 -0
- package/dist/footprint.js.map +1 -0
- package/dist/git.d.ts +44 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +126 -0
- package/dist/git.js.map +1 -0
- package/dist/git.test.d.ts +2 -0
- package/dist/git.test.d.ts.map +1 -0
- package/dist/git.test.js +101 -0
- package/dist/git.test.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest.d.ts +133 -0
- package/dist/ingest.d.ts.map +1 -0
- package/dist/ingest.js +324 -0
- package/dist/ingest.js.map +1 -0
- package/dist/ingest.test.d.ts +2 -0
- package/dist/ingest.test.d.ts.map +1 -0
- package/dist/ingest.test.js +245 -0
- package/dist/ingest.test.js.map +1 -0
- package/dist/outcomes.d.ts +81 -0
- package/dist/outcomes.d.ts.map +1 -0
- package/dist/outcomes.js +85 -0
- package/dist/outcomes.js.map +1 -0
- package/dist/outcomes.test.d.ts +2 -0
- package/dist/outcomes.test.d.ts.map +1 -0
- package/dist/outcomes.test.js +160 -0
- package/dist/outcomes.test.js.map +1 -0
- package/dist/policy.d.ts +48 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +99 -0
- package/dist/policy.js.map +1 -0
- package/dist/policy.test.d.ts +2 -0
- package/dist/policy.test.d.ts.map +1 -0
- package/dist/policy.test.js +126 -0
- package/dist/policy.test.js.map +1 -0
- package/dist/pricing.d.ts +92 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +341 -0
- package/dist/pricing.js.map +1 -0
- package/dist/pricing.test.d.ts +2 -0
- package/dist/pricing.test.d.ts.map +1 -0
- package/dist/pricing.test.js +167 -0
- package/dist/pricing.test.js.map +1 -0
- package/dist/query.d.ts +134 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +247 -0
- package/dist/query.js.map +1 -0
- package/dist/query.test.d.ts +2 -0
- package/dist/query.test.d.ts.map +1 -0
- package/dist/query.test.js +242 -0
- package/dist/query.test.js.map +1 -0
- package/dist/schema.d.ts +33 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +139 -0
- package/dist/schema.js.map +1 -0
- package/dist/schema.test.d.ts +2 -0
- package/dist/schema.test.d.ts.map +1 -0
- package/dist/schema.test.js +129 -0
- package/dist/schema.test.js.map +1 -0
- package/dist/waste.d.ts +116 -0
- package/dist/waste.d.ts.map +1 -0
- package/dist/waste.js +553 -0
- package/dist/waste.js.map +1 -0
- package/dist/waste.test.d.ts +2 -0
- package/dist/waste.test.d.ts.map +1 -0
- package/dist/waste.test.js +278 -0
- package/dist/waste.test.js.map +1 -0
- package/package.json +52 -4
package/dist/waste.js
ADDED
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { gitCommits, gitText, refsTrailers } from './git.js';
|
|
5
|
+
import { listOpencodeDatabases, normalizeOcMessage, parseJson, recordWaste, tableColumns, tableNames, } from './ingest.js';
|
|
6
|
+
/**
|
|
7
|
+
* The waste signals of §6.4 — and who finds them.
|
|
8
|
+
*
|
|
9
|
+
* The seven kinds of §6.4 split in two, and the split is by what the
|
|
10
|
+
* detector needs to see:
|
|
11
|
+
*
|
|
12
|
+
* - `cache_miss`, `no_progress` and `reverted_code` are computable from what
|
|
13
|
+
* is already on disk — OpenCode's own storage, the board's records and the
|
|
14
|
+
* repository — so this module finds them. They need no live event.
|
|
15
|
+
* - `retry`, `tool_error_loop`, `interrupted` and `undo` are properties of a
|
|
16
|
+
* tool call while it happens: they need the event bridge of the plugin, so
|
|
17
|
+
* they are recorded by the bridge through the same `recordWaste` this
|
|
18
|
+
* module writes with. `HOOK_WASTE_KINDS` names them, so the two halves can
|
|
19
|
+
* be counted apart.
|
|
20
|
+
*
|
|
21
|
+
* The full list of the seven is `WASTE_KINDS` in the schema, and the CHECK
|
|
22
|
+
* constraint on the `waste` table holds all of them.
|
|
23
|
+
*/
|
|
24
|
+
/** The kinds this module can find on its own. */
|
|
25
|
+
export const DETECTED_WASTE_KINDS = ['cache_miss', 'no_progress', 'reverted_code'];
|
|
26
|
+
/** The kinds the event bridge finds, because they live in the tool call. */
|
|
27
|
+
export const HOOK_WASTE_KINDS = ['retry', 'tool_error_loop', 'interrupted', 'undo'];
|
|
28
|
+
/** The ratio below which a turn counts as a cache miss (§6.4). */
|
|
29
|
+
export const CACHE_MISS_RATIO = 0.5;
|
|
30
|
+
/** How long a revert may take before it is not a revert any more (§6.4). */
|
|
31
|
+
export const REVERT_WINDOW_DAYS = 14;
|
|
32
|
+
/** A number, or zero. A token count is never a guess. */
|
|
33
|
+
function n(value) {
|
|
34
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : 0;
|
|
35
|
+
}
|
|
36
|
+
function asString(value) {
|
|
37
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Write the waste signals, and skip the ones that are already there.
|
|
41
|
+
*
|
|
42
|
+
* A detector is a command: it runs again and again over the same history,
|
|
43
|
+
* so it must not count the same turn twice. The dedup key is the kind and
|
|
44
|
+
* the message for a message-bound signal, and the kind, the time and the
|
|
45
|
+
* detail for one that has no message.
|
|
46
|
+
*/
|
|
47
|
+
export function recordWasteRows(db, rows) {
|
|
48
|
+
let written = 0;
|
|
49
|
+
for (const row of rows) {
|
|
50
|
+
if (wasteExists(db, row))
|
|
51
|
+
continue;
|
|
52
|
+
recordWaste(db, {
|
|
53
|
+
kind: row.kind,
|
|
54
|
+
tokens: row.tokens,
|
|
55
|
+
ts: row.ts,
|
|
56
|
+
...(row.rootSessionId === undefined ? {} : { rootSessionId: row.rootSessionId }),
|
|
57
|
+
...(row.messageId === undefined ? {} : { messageId: row.messageId }),
|
|
58
|
+
...(row.detail === undefined ? {} : { detail: row.detail }),
|
|
59
|
+
});
|
|
60
|
+
written += 1;
|
|
61
|
+
}
|
|
62
|
+
return written;
|
|
63
|
+
}
|
|
64
|
+
/** Whether the ledger already holds this signal. */
|
|
65
|
+
function wasteExists(db, row) {
|
|
66
|
+
if (row.messageId !== undefined) {
|
|
67
|
+
const found = db
|
|
68
|
+
.query('SELECT 1 FROM waste WHERE kind = ? AND message_id = ? LIMIT 1')
|
|
69
|
+
.get(row.kind, row.messageId);
|
|
70
|
+
return found !== null;
|
|
71
|
+
}
|
|
72
|
+
const found = db
|
|
73
|
+
.query('SELECT 1 FROM waste WHERE kind = ? AND message_id IS NULL AND ts = ? AND detail IS ? LIMIT 1')
|
|
74
|
+
.get(row.kind, row.ts, row.detail ?? null);
|
|
75
|
+
return found !== null;
|
|
76
|
+
}
|
|
77
|
+
/** The sessions the ledger knows, so the storage is only read where it is needed. */
|
|
78
|
+
function ledgerSessions(db) {
|
|
79
|
+
const rows = db.query('SELECT DISTINCT session_id FROM usage').all();
|
|
80
|
+
return rows.map((row) => row.session_id).filter((id) => id.length > 0);
|
|
81
|
+
}
|
|
82
|
+
/** The root session of every message the ledger knows. */
|
|
83
|
+
function rootSessions(db) {
|
|
84
|
+
const rows = db.query('SELECT message_id, root_session_id FROM usage').all();
|
|
85
|
+
const map = new Map();
|
|
86
|
+
for (const row of rows)
|
|
87
|
+
map.set(row.message_id, row.root_session_id);
|
|
88
|
+
return map;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The root session of every session the ledger knows.
|
|
92
|
+
*
|
|
93
|
+
* A turn the ledger has not ingested yet still belongs to a session, and the
|
|
94
|
+
* session knows its root: that is where the turn is counted.
|
|
95
|
+
*/
|
|
96
|
+
function sessionRoots(db) {
|
|
97
|
+
const rows = db.query('SELECT session_id, root_session_id FROM usage').all();
|
|
98
|
+
const map = new Map();
|
|
99
|
+
for (const row of rows) {
|
|
100
|
+
if (!map.has(row.session_id))
|
|
101
|
+
map.set(row.session_id, row.root_session_id);
|
|
102
|
+
}
|
|
103
|
+
return map;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The messages of one session, in the order they were written.
|
|
107
|
+
*
|
|
108
|
+
* The storage is another program's database, so the file is opened read-only
|
|
109
|
+
* and its shape is checked before it is read. A file that does not carry the
|
|
110
|
+
* columns this needs is skipped, not guessed at.
|
|
111
|
+
*/
|
|
112
|
+
function readSessionMessages(source, sessionId) {
|
|
113
|
+
if (!tableNames(source).has('message'))
|
|
114
|
+
return [];
|
|
115
|
+
const columns = tableColumns(source, 'message');
|
|
116
|
+
for (const column of ['id', 'session_id', 'time_created', 'data']) {
|
|
117
|
+
if (!columns.has(column))
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
const rows = source
|
|
121
|
+
.query('SELECT id, session_id, time_created, data FROM message WHERE session_id = ? ORDER BY time_created, id')
|
|
122
|
+
.all(sessionId);
|
|
123
|
+
const messages = [];
|
|
124
|
+
for (const row of rows) {
|
|
125
|
+
const data = parseJson(row.data);
|
|
126
|
+
if (data === null)
|
|
127
|
+
continue;
|
|
128
|
+
const role = asString(data.role);
|
|
129
|
+
if (role !== 'assistant' && role !== 'user')
|
|
130
|
+
continue;
|
|
131
|
+
messages.push({
|
|
132
|
+
id: row.id,
|
|
133
|
+
role,
|
|
134
|
+
session: row.session_id,
|
|
135
|
+
created: Number(row.time_created),
|
|
136
|
+
...(role === 'user' ? { hasText: userHasText(source, row.id) } : {}),
|
|
137
|
+
message: normalizeOcMessage({ ...data, id: row.id, sessionID: row.session_id }),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return messages;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Whether a user message carried anything the user wrote.
|
|
144
|
+
*
|
|
145
|
+
* The plan counts a turn that had "no new user parts" since the previous
|
|
146
|
+
* assistant message, and a user message that carries no text part is not a
|
|
147
|
+
* new user turn: it is the host handing something over. When the storage
|
|
148
|
+
* records no parts at all, the answer is undefined and the message list
|
|
149
|
+
* alone decides — a user message then counts as a turn.
|
|
150
|
+
*/
|
|
151
|
+
function userHasText(source, messageId) {
|
|
152
|
+
if (!tableNames(source).has('part'))
|
|
153
|
+
return undefined;
|
|
154
|
+
const rows = source.query('SELECT data FROM part WHERE message_id = ?').all(messageId);
|
|
155
|
+
for (const row of rows) {
|
|
156
|
+
const data = parseJson(row.data);
|
|
157
|
+
if (data === null)
|
|
158
|
+
continue;
|
|
159
|
+
if (asString(data.type) !== 'text')
|
|
160
|
+
continue;
|
|
161
|
+
const text = asString(data.text);
|
|
162
|
+
if (text !== undefined && text.trim().length > 0)
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
/** Whether a signal happened after the instant the caller asked for. */
|
|
168
|
+
function afterSince(ts, since) {
|
|
169
|
+
return since === undefined || ts >= since;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* The cache misses of §6.4.
|
|
173
|
+
*
|
|
174
|
+
* A turn with no new user parts since the previous assistant message is a
|
|
175
|
+
* retry or a continuation: the prefix was unchanged by definition, so a low
|
|
176
|
+
* cache ratio is the model's problem and not the user's. The detection reads
|
|
177
|
+
* the message list of a session: the pair is the previous assistant message
|
|
178
|
+
* and the one after it, and a user message between them ends the pair. A
|
|
179
|
+
* user message that carried no text part does not end it — nothing new came
|
|
180
|
+
* from the user — but only when the storage records parts at all.
|
|
181
|
+
*
|
|
182
|
+
* The tokens counted are the uncached input of the turn — the part of the
|
|
183
|
+
* prefix the model had to read again.
|
|
184
|
+
*/
|
|
185
|
+
export function detectCacheMiss(db, options = {}) {
|
|
186
|
+
const threshold = options.threshold ?? CACHE_MISS_RATIO;
|
|
187
|
+
const dataDir = options.dataDir ?? join(homedir(), '.local', 'share', 'opencode');
|
|
188
|
+
const sessions = options.sessions ?? ledgerSessions(db);
|
|
189
|
+
if (sessions.length === 0)
|
|
190
|
+
return [];
|
|
191
|
+
const roots = rootSessions(db);
|
|
192
|
+
const rootsBySession = sessionRoots(db);
|
|
193
|
+
const candidates = [];
|
|
194
|
+
for (const file of listOpencodeDatabases(dataDir)) {
|
|
195
|
+
const source = openReadonly(file);
|
|
196
|
+
if (source === null)
|
|
197
|
+
continue;
|
|
198
|
+
try {
|
|
199
|
+
for (const session of sessions) {
|
|
200
|
+
candidates.push(...cacheMissInSession(source, session, threshold, roots, rootsBySession, options.since));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
source.close();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return candidates;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* The cache misses of one session.
|
|
211
|
+
*
|
|
212
|
+
* The pair is the previous assistant message and the one after it, and a
|
|
213
|
+
* user message between them ends the pair. A user message that carried
|
|
214
|
+
* nothing the user wrote does not end it: no new user parts came in, and
|
|
215
|
+
* the turn is still a continuation.
|
|
216
|
+
*/
|
|
217
|
+
function cacheMissInSession(source, session, threshold, roots, rootsBySession, since) {
|
|
218
|
+
const candidates = [];
|
|
219
|
+
let previousAssistant;
|
|
220
|
+
for (const current of readSessionMessages(source, session)) {
|
|
221
|
+
if (current.role === 'user') {
|
|
222
|
+
if (current.hasText !== false)
|
|
223
|
+
previousAssistant = undefined;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
const previous = previousAssistant;
|
|
227
|
+
previousAssistant = current;
|
|
228
|
+
if (previous === undefined)
|
|
229
|
+
continue;
|
|
230
|
+
const candidate = cacheMissOf(current, threshold, roots, rootsBySession);
|
|
231
|
+
if (candidate === undefined)
|
|
232
|
+
continue;
|
|
233
|
+
if (!afterSince(candidate.ts, since))
|
|
234
|
+
continue;
|
|
235
|
+
candidates.push(candidate);
|
|
236
|
+
}
|
|
237
|
+
return candidates;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* The cache miss of one turn, when the turn is one.
|
|
241
|
+
*
|
|
242
|
+
* The ratio is `cache_read / (input + cache_read)`, and the tokens counted
|
|
243
|
+
* are the uncached input: the part of the prefix the model read again.
|
|
244
|
+
*/
|
|
245
|
+
function cacheMissOf(current, threshold, roots, rootsBySession) {
|
|
246
|
+
const tokens = current.message.tokens ?? {};
|
|
247
|
+
const input = n(tokens.input);
|
|
248
|
+
const cacheRead = n(tokens.cache?.read);
|
|
249
|
+
const total = input + cacheRead;
|
|
250
|
+
if (total <= 0)
|
|
251
|
+
return undefined;
|
|
252
|
+
const ratio = cacheRead / total;
|
|
253
|
+
if (ratio >= threshold)
|
|
254
|
+
return undefined;
|
|
255
|
+
const rootSessionId = roots.get(current.id) ?? rootsBySession.get(current.session);
|
|
256
|
+
return {
|
|
257
|
+
kind: 'cache_miss',
|
|
258
|
+
tokens: input,
|
|
259
|
+
ts: Number.isFinite(current.created)
|
|
260
|
+
? new Date(current.created).toISOString()
|
|
261
|
+
: new Date().toISOString(),
|
|
262
|
+
messageId: current.id,
|
|
263
|
+
...(rootSessionId === undefined ? {} : { rootSessionId }),
|
|
264
|
+
detail: `cache read ${cacheRead} of ${total} (${Math.round(ratio * 100)}%) with no new user turn`,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Read the board, and only the parts of it the detector needs.
|
|
269
|
+
*
|
|
270
|
+
* The board's tables are read with plain SQL: the ledger holds no
|
|
271
|
+
* dependency on the board's query layer, and a table that is not there — an
|
|
272
|
+
* older board, a board that was never used — is an empty list and not a
|
|
273
|
+
* failure.
|
|
274
|
+
*/
|
|
275
|
+
function readBoard(boardDb) {
|
|
276
|
+
const snapshot = { records: [], reads: [], leases: [] };
|
|
277
|
+
const names = tableNames(boardDb);
|
|
278
|
+
if (!names.has('records'))
|
|
279
|
+
return snapshot;
|
|
280
|
+
snapshot.records = boardDb
|
|
281
|
+
.query('SELECT id, from_agent, to_agent, created_at FROM records ORDER BY created_at, id')
|
|
282
|
+
.all();
|
|
283
|
+
if (names.has('record_reads')) {
|
|
284
|
+
snapshot.reads = boardDb.query('SELECT agent, read_at FROM record_reads').all();
|
|
285
|
+
}
|
|
286
|
+
if (names.has('leases')) {
|
|
287
|
+
snapshot.leases = boardDb.query('SELECT agent, granted_at FROM leases').all();
|
|
288
|
+
}
|
|
289
|
+
return snapshot;
|
|
290
|
+
}
|
|
291
|
+
/** The beginning of time, as a timestamp the board can be compared against. */
|
|
292
|
+
const ROUND_START = '';
|
|
293
|
+
/** The end of time, as a timestamp the board can be compared against. */
|
|
294
|
+
const ROUND_END = '9999-12-31T23:59:59.999Z';
|
|
295
|
+
/** The Lead messages of the ledger, in the order they were made. */
|
|
296
|
+
function readLeadMessages(db, leadRole) {
|
|
297
|
+
return db
|
|
298
|
+
.query(`SELECT message_id, root_session_id, input, output, reasoning, cache_write, ts
|
|
299
|
+
FROM usage WHERE role = ? ORDER BY ts, message_id`)
|
|
300
|
+
.all(leadRole);
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* The boundaries of the Lead's rounds.
|
|
304
|
+
*
|
|
305
|
+
* The first boundary is the beginning of the window and the last one is the
|
|
306
|
+
* end of it; every record the Lead wrote closes a round.
|
|
307
|
+
*/
|
|
308
|
+
function leadBoundaries(board, leadAgent) {
|
|
309
|
+
const records = board.records.filter((record) => record.from_agent === leadAgent);
|
|
310
|
+
return [ROUND_START, ...records.map((record) => record.created_at), ROUND_END];
|
|
311
|
+
}
|
|
312
|
+
/** The Lead messages that fall inside a round, and what they cost. */
|
|
313
|
+
function roundOf(rows, start, end) {
|
|
314
|
+
const round = { start, end, tokens: 0, messages: 0 };
|
|
315
|
+
for (const row of rows) {
|
|
316
|
+
if (row.ts <= start || row.ts > end)
|
|
317
|
+
continue;
|
|
318
|
+
round.tokens += n(row.input) + n(row.output) + n(row.reasoning) + n(row.cache_write);
|
|
319
|
+
round.messages += 1;
|
|
320
|
+
if (round.messageId === undefined)
|
|
321
|
+
round.messageId = row.message_id;
|
|
322
|
+
if (round.rootSessionId === undefined)
|
|
323
|
+
round.rootSessionId = row.root_session_id;
|
|
324
|
+
}
|
|
325
|
+
return round;
|
|
326
|
+
}
|
|
327
|
+
function leadRounds(db, board, leadAgent, leadRole) {
|
|
328
|
+
const rows = readLeadMessages(db, leadRole);
|
|
329
|
+
const boundaries = leadBoundaries(board, leadAgent);
|
|
330
|
+
return boundaries
|
|
331
|
+
.slice(1)
|
|
332
|
+
.map((end, index) => roundOf(rows, boundaries[index] ?? ROUND_START, end));
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Whether a round made progress.
|
|
336
|
+
*
|
|
337
|
+
* A round made progress when it dispatched something, when it consumed a
|
|
338
|
+
* result or when the board moved under it. A round that did none of the
|
|
339
|
+
* three changed nothing, and it is the waste of §6.4.
|
|
340
|
+
*/
|
|
341
|
+
function roundProgressed(board, round, leadAgent) {
|
|
342
|
+
const inside = board.records.filter((record) => record.created_at > round.start && record.created_at <= round.end);
|
|
343
|
+
if (inside.some((record) => record.to_agent !== null))
|
|
344
|
+
return true;
|
|
345
|
+
if (inside.some((record) => record.to_agent === leadAgent))
|
|
346
|
+
return true;
|
|
347
|
+
if (board.reads.some((read) => read.agent === leadAgent && read.read_at > round.start && read.read_at <= round.end)) {
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
if (inside.some((record) => record.from_agent !== leadAgent))
|
|
351
|
+
return true;
|
|
352
|
+
return board.leases.some((lease) => lease.granted_at > round.start && lease.granted_at <= round.end);
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* The rounds of the Lead that went nowhere (§6.4, §8.7).
|
|
356
|
+
*
|
|
357
|
+
* A round that dispatched nothing, consumed no results and changed nothing
|
|
358
|
+
* on the board cannot claim progress, so it is written down as waste. The
|
|
359
|
+
* tokens counted are the round's tokens — the Lead's own.
|
|
360
|
+
*/
|
|
361
|
+
export function detectNoProgress(db, boardDb, options = {}) {
|
|
362
|
+
const { agent: leadAgent, role: leadRole } = leadIdentity(options);
|
|
363
|
+
const board = readBoard(boardDb);
|
|
364
|
+
const candidates = [];
|
|
365
|
+
for (const round of leadRounds(db, board, leadAgent, leadRole)) {
|
|
366
|
+
if (round.tokens <= 0)
|
|
367
|
+
continue;
|
|
368
|
+
const end = roundEnd(db, leadRole, round);
|
|
369
|
+
if (options.since !== undefined && end < options.since)
|
|
370
|
+
continue;
|
|
371
|
+
if (roundProgressed(board, round, leadAgent))
|
|
372
|
+
continue;
|
|
373
|
+
candidates.push(noProgressCandidate(round, end));
|
|
374
|
+
}
|
|
375
|
+
return candidates;
|
|
376
|
+
}
|
|
377
|
+
/** The agent the Lead writes under, and the role its ledger rows carry. */
|
|
378
|
+
function leadIdentity(options) {
|
|
379
|
+
return { agent: options.leadAgent ?? 'agentsy', role: options.leadRole ?? 'lead' };
|
|
380
|
+
}
|
|
381
|
+
/** The end of a round, when the round never closed. */
|
|
382
|
+
function roundEnd(db, leadRole, round) {
|
|
383
|
+
return round.end === ROUND_END ? lastMessageTs(db, leadRole, round) : round.end;
|
|
384
|
+
}
|
|
385
|
+
/** The waste signal of a round that made no progress. */
|
|
386
|
+
function noProgressCandidate(round, end) {
|
|
387
|
+
return {
|
|
388
|
+
kind: 'no_progress',
|
|
389
|
+
tokens: round.tokens,
|
|
390
|
+
ts: end,
|
|
391
|
+
...(round.rootSessionId === undefined ? {} : { rootSessionId: round.rootSessionId }),
|
|
392
|
+
...(round.messageId === undefined ? {} : { messageId: round.messageId }),
|
|
393
|
+
detail: `lead round with no dispatch, no result and no board change (${round.messages} message(s))`,
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
/** The time of the newest Lead message, for a round that never closed. */
|
|
397
|
+
function lastMessageTs(db, leadRole, round) {
|
|
398
|
+
const row = db
|
|
399
|
+
.query('SELECT MAX(ts) AS ts FROM usage WHERE role = ? AND ts > ? AND ts <= ?')
|
|
400
|
+
.get(leadRole, round.start, round.end);
|
|
401
|
+
return row?.ts ?? new Date().toISOString();
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* The no-progress rounds, read from the board at a path.
|
|
405
|
+
*
|
|
406
|
+
* The board is opened read-only and closed again here, so a caller does not
|
|
407
|
+
* have to know how the board is stored.
|
|
408
|
+
*/
|
|
409
|
+
export function detectNoProgressAtPath(db, boardPath, options = {}) {
|
|
410
|
+
const boardDb = openReadonly(boardPath);
|
|
411
|
+
if (boardDb === null)
|
|
412
|
+
return [];
|
|
413
|
+
try {
|
|
414
|
+
return detectNoProgress(db, boardDb, options);
|
|
415
|
+
}
|
|
416
|
+
finally {
|
|
417
|
+
boardDb.close();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
/** Open a database read-only, or null when it cannot be opened. */
|
|
421
|
+
function openReadonly(path) {
|
|
422
|
+
try {
|
|
423
|
+
return new Database(path, { readonly: true });
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* The reverted code of §6.4.
|
|
431
|
+
*
|
|
432
|
+
* A commit that carries a `Refs:` trailer and whose lines are deleted again
|
|
433
|
+
* within the window is code that was written and then taken back. The tokens
|
|
434
|
+
* counted are the builder tokens of the task, times the share of the added
|
|
435
|
+
* lines that were lost.
|
|
436
|
+
*
|
|
437
|
+
* This is a command and not a daemon: it walks the history of a repository
|
|
438
|
+
* once, when a person or the Lead asks for it.
|
|
439
|
+
*/
|
|
440
|
+
export function scanReverts(gitDir, since, options = {}) {
|
|
441
|
+
const windowDays = options.windowDays ?? REVERT_WINDOW_DAYS;
|
|
442
|
+
const candidates = [];
|
|
443
|
+
for (const commit of gitCommits(gitDir, since)) {
|
|
444
|
+
const refs = refsTrailers(commit.message);
|
|
445
|
+
if (refs.length === 0)
|
|
446
|
+
continue;
|
|
447
|
+
const lines = lostLines(gitDir, commit.sha, commit.at, windowDays);
|
|
448
|
+
if (lines.total === 0 || lines.lost === 0)
|
|
449
|
+
continue;
|
|
450
|
+
const share = lines.lost / lines.total;
|
|
451
|
+
for (const taskId of refs) {
|
|
452
|
+
const taskTokens = options.tokensForTask?.(taskId) ?? 0;
|
|
453
|
+
candidates.push({
|
|
454
|
+
kind: 'reverted_code',
|
|
455
|
+
tokens: Math.round(taskTokens * share),
|
|
456
|
+
ts: new Date(commit.at * 1000).toISOString(),
|
|
457
|
+
detail: `task ${taskId}, commit ${commit.sha.slice(0, 8)}: ${lines.lost} of ${lines.total} added line(s) lost within ${windowDays} day(s)`,
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return candidates;
|
|
462
|
+
}
|
|
463
|
+
/** The added lines of a commit, per file, and how many of them were lost. */
|
|
464
|
+
function lostLines(gitDir, sha, at, windowDays) {
|
|
465
|
+
const numstat = gitText(gitDir, ['show', '--format=', '--numstat', sha]);
|
|
466
|
+
if (numstat === null)
|
|
467
|
+
return { lost: 0, total: 0 };
|
|
468
|
+
let lost = 0;
|
|
469
|
+
let total = 0;
|
|
470
|
+
for (const line of numstat.split('\n')) {
|
|
471
|
+
const parts = line.split('\t');
|
|
472
|
+
const file = parts[2];
|
|
473
|
+
if (file === undefined || file.length === 0)
|
|
474
|
+
continue;
|
|
475
|
+
const added = addedLines(gitDir, sha, file);
|
|
476
|
+
if (added.length === 0)
|
|
477
|
+
continue;
|
|
478
|
+
const later = laterLines(gitDir, file, sha, at, windowDays);
|
|
479
|
+
total += added.length;
|
|
480
|
+
lost += countLost(added, later);
|
|
481
|
+
}
|
|
482
|
+
return { lost, total };
|
|
483
|
+
}
|
|
484
|
+
/** The lines a commit added to a file. */
|
|
485
|
+
function addedLines(gitDir, sha, file) {
|
|
486
|
+
const diff = gitText(gitDir, ['show', '--format=', '--unified=0', '--no-color', sha, '--', file]);
|
|
487
|
+
if (diff === null)
|
|
488
|
+
return [];
|
|
489
|
+
const lines = [];
|
|
490
|
+
for (const line of diff.split('\n')) {
|
|
491
|
+
if (!line.startsWith('+') || line.startsWith('+++'))
|
|
492
|
+
continue;
|
|
493
|
+
const content = line.slice(1).trim();
|
|
494
|
+
if (content.length === 0)
|
|
495
|
+
continue;
|
|
496
|
+
lines.push(content);
|
|
497
|
+
}
|
|
498
|
+
return lines;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* The content of a file after the window, and null when the file was not
|
|
502
|
+
* touched inside it.
|
|
503
|
+
*/
|
|
504
|
+
function laterLines(gitDir, file, sha, at, windowDays) {
|
|
505
|
+
const until = at + windowDays * 24 * 60 * 60;
|
|
506
|
+
const log = gitText(gitDir, [
|
|
507
|
+
'log',
|
|
508
|
+
`--since=@${at}`,
|
|
509
|
+
`--until=@${until}`,
|
|
510
|
+
'--format=%H',
|
|
511
|
+
'--',
|
|
512
|
+
file,
|
|
513
|
+
]);
|
|
514
|
+
if (log === null)
|
|
515
|
+
return null;
|
|
516
|
+
for (const line of log.split('\n')) {
|
|
517
|
+
const commit = line.trim();
|
|
518
|
+
if (commit.length === 0 || commit === sha)
|
|
519
|
+
continue;
|
|
520
|
+
const content = gitText(gitDir, ['show', `${commit}:${file}`]);
|
|
521
|
+
if (content === null)
|
|
522
|
+
return [];
|
|
523
|
+
return content
|
|
524
|
+
.split('\n')
|
|
525
|
+
.map((entry) => entry.trim())
|
|
526
|
+
.filter((entry) => entry.length > 0);
|
|
527
|
+
}
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* How many of the added lines are gone.
|
|
532
|
+
*
|
|
533
|
+
* The lines are matched by their content, not by their position: a line that
|
|
534
|
+
* moved is still there, and a line that was rewritten is gone. The count is
|
|
535
|
+
* a multiset difference, so a line that appears twice is counted twice.
|
|
536
|
+
*/
|
|
537
|
+
function countLost(added, later) {
|
|
538
|
+
if (later === null)
|
|
539
|
+
return 0;
|
|
540
|
+
const counts = new Map();
|
|
541
|
+
for (const line of later)
|
|
542
|
+
counts.set(line, (counts.get(line) ?? 0) + 1);
|
|
543
|
+
let lost = 0;
|
|
544
|
+
for (const line of added) {
|
|
545
|
+
const left = counts.get(line) ?? 0;
|
|
546
|
+
if (left > 0)
|
|
547
|
+
counts.set(line, left - 1);
|
|
548
|
+
else
|
|
549
|
+
lost += 1;
|
|
550
|
+
}
|
|
551
|
+
return lost;
|
|
552
|
+
}
|
|
553
|
+
//# sourceMappingURL=waste.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waste.js","sourceRoot":"","sources":["../src/waste.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waste.test.d.ts","sourceRoot":"","sources":["../src/waste.test.ts"],"names":[],"mappings":""}
|