@assuredloop/orca-bot-kit 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -2
- package/package.json +1 -1
- package/rules/mail.md +3 -0
- package/skills/obk-arch/NOTICE.md +45 -0
- package/skills/obk-bot-building/NOTICE.md +5 -0
- package/skills/obk-bot-building/SKILL.md +7 -0
- package/skills/obk-debugging/NOTICE.md +28 -0
- package/skills/obk-decision-memo/NOTICE.md +21 -0
- package/skills/obk-finops/SKILL.md +26 -0
- package/skills/obk-fleet-review/NOTICE.md +8 -0
- package/skills/obk-grilling/NOTICE.md +11 -5
- package/skills/obk-grooming/NOTICE.md +11 -0
- package/skills/obk-grooming/SKILL.md +10 -0
- package/skills/obk-handoff/NOTICE.md +6 -0
- package/skills/obk-personal-facilitation/NOTICE.md +9 -0
- package/skills/obk-personal-facilitation/SKILL.md +30 -0
- package/skills/obk-recall/NOTICE.md +3 -0
- package/skills/obk-researching/NOTICE.md +27 -6
- package/skills/obk-reviewing/NOTICE.md +19 -0
- package/skills/obk-tdd/NOTICE.md +35 -4
- package/skills/obk-tdd/SKILL.md +41 -3
- package/skills/obk-teach/NOTICE.md +3 -0
- package/skills/obk-why/NOTICE.md +3 -0
- package/skills/obk-writing/NOTICE.md +24 -0
- package/src/cli.js +43 -8
- package/src/conversations.js +37 -12
- package/src/groom.js +144 -11
- package/src/health.js +20 -1
- package/src/lines.js +77 -0
- package/src/orca.js +28 -4
- package/src/temp.js +99 -10
- package/src/usage.js +52 -21
package/src/usage.js
CHANGED
|
@@ -39,11 +39,12 @@
|
|
|
39
39
|
// the same call can be in more than one of those files, so a call counts
|
|
40
40
|
// once across all of a conversation's files together (#371).
|
|
41
41
|
|
|
42
|
-
import {
|
|
42
|
+
import { realpathSync } from 'node:fs';
|
|
43
43
|
|
|
44
44
|
import { botDir, botNames, readBot } from './bot.js';
|
|
45
45
|
import { readBook, sessionIdsIn } from './book.js';
|
|
46
|
-
import { claudeSubagentTranscripts, codexRollout, transcriptsIn } from './conversations.js';
|
|
46
|
+
import { claudeSubagentTranscripts, claudeTranscriptAnywhere, codexRollout, transcriptsIn } from './conversations.js';
|
|
47
|
+
import { eachLine } from './lines.js';
|
|
47
48
|
import { HARNESSES, harnessOf } from './launch.js';
|
|
48
49
|
|
|
49
50
|
/** The kinds a call's tokens are reported in, the same on either harness. */
|
|
@@ -123,6 +124,20 @@ function forBot(bots, name, onlySession, window) {
|
|
|
123
124
|
|
|
124
125
|
const claimed = sessionIdsIn(book);
|
|
125
126
|
|
|
127
|
+
// A conversation the book names is its session's wherever the harness filed
|
|
128
|
+
// it: the book says whose it is (ADR 0012). One filed under another
|
|
129
|
+
// folder, or whose record cannot be opened to say which folder it ran in, is
|
|
130
|
+
// found by its id instead, and counted or said to be unreadable (#396).
|
|
131
|
+
for (const id of claimed) {
|
|
132
|
+
if (onRecord.has(id)) continue;
|
|
133
|
+
for (const harness of harnesses) {
|
|
134
|
+
const file = harness === 'codex' ? codexRollout(id) : harness === 'claude' ? claudeTranscriptAnywhere(id) : undefined;
|
|
135
|
+
if (file === undefined) continue;
|
|
136
|
+
onRecord.set(id, { id, file, harness, subagent: false });
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
126
141
|
// Two entries can name the same conversation, one resumed after its session
|
|
127
142
|
// was retired, and one entry can name it twice, now and in its history: it is
|
|
128
143
|
// counted once, in the first block asked for that names it.
|
|
@@ -190,7 +205,7 @@ function counted(one, window) {
|
|
|
190
205
|
tally.gaps.unreadable_transcripts += subagents.unreadable;
|
|
191
206
|
const sources = [one.file, ...subagents.files]
|
|
192
207
|
.map((file, index) => {
|
|
193
|
-
const { entries, unreadable, broken } = transcript(file);
|
|
208
|
+
const { entries, unreadable, broken } = transcript(file, countable);
|
|
194
209
|
tally.gaps.unreadable_transcripts += unreadable;
|
|
195
210
|
tally.gaps.broken_lines += broken;
|
|
196
211
|
return { entries, subagent: index > 0 };
|
|
@@ -463,7 +478,7 @@ function originOf(entries, tally) {
|
|
|
463
478
|
if (typeof id !== 'string' || id === '') return undefined;
|
|
464
479
|
|
|
465
480
|
const file = codexRollout(id);
|
|
466
|
-
const origin = file === undefined ? { unreadable: 1 } : transcript(file);
|
|
481
|
+
const origin = file === undefined ? { unreadable: 1 } : transcript(file, countable);
|
|
467
482
|
// No `info` is a note about rate limits, not a record of usage.
|
|
468
483
|
const records = origin.unreadable > 0 ? [] : origin.entries
|
|
469
484
|
.filter((entry) => entry.type === 'event_msg' && entry.payload?.type === 'token_count')
|
|
@@ -552,28 +567,44 @@ function count(tally, used, model, effort, when, calls = 1, subagent = false) {
|
|
|
552
567
|
export const lines = (file) => transcript(file).entries;
|
|
553
568
|
|
|
554
569
|
/**
|
|
555
|
-
* The
|
|
556
|
-
*
|
|
570
|
+
* The records the counting here reads: Claude Code's `assistant` and `system`
|
|
571
|
+
* lines, Codex's `session_meta`, `turn_context`, `compacted` and `event_msg`.
|
|
572
|
+
* The rest (what was said, tool calls and their output) is most of a long
|
|
573
|
+
* conversation's record and none of what it cost, so it is not held (#396).
|
|
574
|
+
*/
|
|
575
|
+
const COUNTED = new Set(['assistant', 'system', 'session_meta', 'turn_context', 'compacted', 'event_msg']);
|
|
576
|
+
const countable = (entry) => COUNTED.has(entry.type);
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* The lines of a transcript that are JSON records, and how many were not; with
|
|
580
|
+
* `keep`, only the records it takes. A transcript that cannot be read is said
|
|
581
|
+
* to be, rather than a run that stops. It is read a line at a time, whatever
|
|
582
|
+
* its size, and a line too long to hold counts as one that is not a record
|
|
583
|
+
* (#396).
|
|
557
584
|
*/
|
|
558
|
-
function transcript(file) {
|
|
559
|
-
|
|
585
|
+
function transcript(file, keep = () => true) {
|
|
586
|
+
const entries = [];
|
|
587
|
+
let broken = 0;
|
|
560
588
|
try {
|
|
561
|
-
|
|
589
|
+
eachLine(file, (line) => {
|
|
590
|
+
if (line === undefined) {
|
|
591
|
+
broken += 1;
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
if (line.trim() === '') return;
|
|
595
|
+
let entry;
|
|
596
|
+
try {
|
|
597
|
+
entry = JSON.parse(line);
|
|
598
|
+
} catch {
|
|
599
|
+
broken += 1;
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
if (entry === null || typeof entry !== 'object' || Array.isArray(entry)) broken += 1;
|
|
603
|
+
else if (keep(entry)) entries.push(entry);
|
|
604
|
+
});
|
|
562
605
|
} catch {
|
|
563
606
|
return { entries: [], unreadable: 1, broken: 0 };
|
|
564
607
|
}
|
|
565
|
-
let broken = 0;
|
|
566
|
-
const entries = text.split('\n').flatMap((line) => {
|
|
567
|
-
if (line.trim() === '') return [];
|
|
568
|
-
try {
|
|
569
|
-
const entry = JSON.parse(line);
|
|
570
|
-
if (entry !== null && typeof entry === 'object' && !Array.isArray(entry)) return [entry];
|
|
571
|
-
} catch {
|
|
572
|
-
// Counted below with any other line that is not a record.
|
|
573
|
-
}
|
|
574
|
-
broken += 1;
|
|
575
|
-
return [];
|
|
576
|
-
});
|
|
577
608
|
return { entries, unreadable: 0, broken };
|
|
578
609
|
}
|
|
579
610
|
|