sigrank 0.0.194 → 0.0.196
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/adapters/index.mjs +108 -29
- package/package.json +1 -1
package/adapters/index.mjs
CHANGED
|
@@ -747,8 +747,16 @@ export const hermesAdapter = {
|
|
|
747
747
|
// Native 4-pillar: metrics.input_tokens is FRESH input (does NOT include cache
|
|
748
748
|
// read or cache creation — verified against live data where input=3 alongside
|
|
749
749
|
// cache_creation_tokens=23500). cache_read_tokens and cache_creation_tokens are
|
|
750
|
-
// separate fields
|
|
751
|
-
//
|
|
750
|
+
// separate fields. output_tokens includes any reasoning tokens.
|
|
751
|
+
//
|
|
752
|
+
// CACHE_CREATION FALLBACK: the Devin CLI records cache_creation_tokens natively
|
|
753
|
+
// for Claude models (claude-sonnet-4-6, claude-opus-4-6) but writes NULL for
|
|
754
|
+
// GLM-5-2 and other non-Claude models. When the field is NULL, estimate
|
|
755
|
+
// cacheCreate from cache_read using the construction ratio (cw/cr = 0.0635)
|
|
756
|
+
// calibrated from the 8K Claude-era rows (50.3M cw / 792M cr). This preserves
|
|
757
|
+
// the compounding signal — without it, cacheCreate=0 makes every window look
|
|
758
|
+
// like a "stateless pipe" (no cache commits), which is a data gap, not reality.
|
|
759
|
+
const DEVIN_CONSTRUCTION_RATIO = 0.0635;
|
|
752
760
|
export const devinAdapter = {
|
|
753
761
|
platform: "devin",
|
|
754
762
|
defaultRoot: () => join(homedir(), ".local", "share", "devin", "cli"),
|
|
@@ -773,7 +781,12 @@ export const devinAdapter = {
|
|
|
773
781
|
const input = Number(row.input_tokens || 0);
|
|
774
782
|
const output = Number(row.output_tokens || 0);
|
|
775
783
|
const cacheRead = Number(row.cache_read_tokens || 0);
|
|
776
|
-
|
|
784
|
+
// Use native cache_creation_tokens when present; estimate from cache_read
|
|
785
|
+
// when NULL (GLM-5-2 era doesn't record the field).
|
|
786
|
+
const cacheCreate =
|
|
787
|
+
row.cache_creation_tokens != null
|
|
788
|
+
? Number(row.cache_creation_tokens || 0)
|
|
789
|
+
: Math.round(cacheRead * DEVIN_CONSTRUCTION_RATIO);
|
|
777
790
|
if (input + output + cacheRead + cacheCreate === 0) continue;
|
|
778
791
|
yield {
|
|
779
792
|
id: `devin:${row.row_id}`,
|
|
@@ -904,38 +917,104 @@ export const otherAdapter = {
|
|
|
904
917
|
// File cap: a real omp tree runs to 20k+ transcripts, past walkFiles' 10_000 default,
|
|
905
918
|
// which would silently drop half the operator's tokens — pass an explicit cap.
|
|
906
919
|
const OMP_MAX_FILES = 500_000;
|
|
920
|
+
|
|
921
|
+
// ── Stage 1: bounded-concurrency + line-guard optimization ───────────────────
|
|
922
|
+
// Based on George-RD's measured findings (PR #32 review comment):
|
|
923
|
+
// - CPU-bound, not disk-bound: 90.5% of one thread, tree fully page-cached
|
|
924
|
+
// - c=8 is optimal: 45.06s → 34.92s (1.29x), regresses at c12/c16
|
|
925
|
+
// - Line guard MUST pass both "message" AND "session" lines, or it breaks
|
|
926
|
+
// the (session_id, entry_id) dedup key — session header lines carry the id
|
|
927
|
+
// - Two-term guard: 0 false negatives across 2.18M lines
|
|
928
|
+
// - All 504 duplicate keys carry byte-identical pillar tuples → order-safe
|
|
929
|
+
// - Only ~1-3% end-to-end win from the guard alone (omp's skippable lines are
|
|
930
|
+
// 19.8% of lines but 15.3% of bytes); the guard costs 1.2s but saves parse
|
|
931
|
+
// on lines that can't contain usage. Folded into concurrency, not standalone.
|
|
932
|
+
const OMP_CONCURRENCY = 8;
|
|
933
|
+
|
|
934
|
+
/** Check if a line could contain an omp usage record or session header.
|
|
935
|
+
* Conservative: false positives are fine, false negatives are not.
|
|
936
|
+
* Must match both "message" (usage) and "session" (dedup key) lines. */
|
|
937
|
+
function ompLineCouldMatter(line) {
|
|
938
|
+
// Fast substring check before JSON.parse — rejects ~20% of lines that are
|
|
939
|
+
// neither message nor session entries (tool calls, reasoning, etc.)
|
|
940
|
+
return line.includes('"message"') || line.includes('"session"');
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/** Parse a single omp transcript file and yield usage records.
|
|
944
|
+
* Isolated so it can be called concurrently from the bounded pool. */
|
|
945
|
+
function* parseOmpFile(text, path) {
|
|
946
|
+
if (!text) return;
|
|
947
|
+
let sid = null;
|
|
948
|
+
for (const line of text.split("\n")) {
|
|
949
|
+
const s = line.trim();
|
|
950
|
+
if (!s) continue;
|
|
951
|
+
// Line guard: skip lines that can't be message or session entries.
|
|
952
|
+
// George-RD verified 0 false negatives across 2.18M lines with this guard.
|
|
953
|
+
if (!ompLineCouldMatter(s)) continue;
|
|
954
|
+
let ev;
|
|
955
|
+
try {
|
|
956
|
+
ev = JSON.parse(s);
|
|
957
|
+
} catch {
|
|
958
|
+
continue;
|
|
959
|
+
}
|
|
960
|
+
if (!ev) continue;
|
|
961
|
+
if (ev.type === "session") {
|
|
962
|
+
sid = ev.id || null;
|
|
963
|
+
continue;
|
|
964
|
+
}
|
|
965
|
+
if (ev.type !== "message") continue;
|
|
966
|
+
const u = ev.message && ev.message.usage;
|
|
967
|
+
if (!u) continue;
|
|
968
|
+
const input = Number(u.input || 0);
|
|
969
|
+
const output = Number(u.output || 0); // reasoningTokens ALREADY inside — TRAP 1
|
|
970
|
+
const cacheCreate = Number(u.cacheWrite || 0);
|
|
971
|
+
const cacheRead = Number(u.cacheRead || 0);
|
|
972
|
+
if (input + output + cacheCreate + cacheRead === 0) continue;
|
|
973
|
+
yield {
|
|
974
|
+
id: ev.id || null,
|
|
975
|
+
sid,
|
|
976
|
+
ts: ev.timestamp || null,
|
|
977
|
+
input,
|
|
978
|
+
output,
|
|
979
|
+
cacheCreate,
|
|
980
|
+
cacheRead,
|
|
981
|
+
file: path,
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
|
|
907
986
|
export const ompAdapter = {
|
|
908
987
|
platform: "omp",
|
|
909
988
|
defaultRoot: () => join(homedir(), ".omp", "agent", "sessions"),
|
|
910
989
|
async *messages(root) {
|
|
911
990
|
for (const r of roots("OMP_DATA_DIR", root)) {
|
|
991
|
+
// Collect all file paths first (readdir is 0.8% of scan time — negligible)
|
|
992
|
+
const paths = [];
|
|
912
993
|
for await (const path of walkFiles(r, isJsonl, { n: 0 }, OMP_MAX_FILES)) {
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
const
|
|
926
|
-
const
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
file: path,
|
|
938
|
-
};
|
|
994
|
+
paths.push(path);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// Bounded-concurrency read+parse: George-RD measured c=8 as optimal
|
|
998
|
+
// (1.29x speedup, 45s → 35s). Order-safe: all 504 duplicate keys carry
|
|
999
|
+
// byte-identical pillar tuples, so completion order can't change totals.
|
|
1000
|
+
const concurrency = OMP_CONCURRENCY;
|
|
1001
|
+
const inflight = new Set();
|
|
1002
|
+
const queue = [...paths];
|
|
1003
|
+
|
|
1004
|
+
while (queue.length > 0 || inflight.size > 0) {
|
|
1005
|
+
while (inflight.size < concurrency && queue.length > 0) {
|
|
1006
|
+
const path = queue.shift();
|
|
1007
|
+
const p = (async () => {
|
|
1008
|
+
const text = await readUtf8(path);
|
|
1009
|
+
return { path, records: [...parseOmpFile(text, path)] };
|
|
1010
|
+
})();
|
|
1011
|
+
inflight.add(p);
|
|
1012
|
+
p.finally(() => inflight.delete(p));
|
|
1013
|
+
}
|
|
1014
|
+
const done = await Promise.race(inflight);
|
|
1015
|
+
inflight.delete(done);
|
|
1016
|
+
for (const record of done.records) {
|
|
1017
|
+
yield record;
|
|
939
1018
|
}
|
|
940
1019
|
}
|
|
941
1020
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigrank",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.196",
|
|
4
4
|
"author": "SunrisesIllNeverSee (https://github.com/SunrisesIllNeverSee)",
|
|
5
5
|
"description": "SigRank MCP server — the yield cascade + live leaderboard as MCP tools any agent can call",
|
|
6
6
|
"mcpName": "io.github.SunrisesIllNeverSee/sigrank-mcp",
|