// Parse the per-call timing digestApps already logs, so a harness can price a // run without adding instrumentation to the engine. // // WHY SHARED. plans/tools/attribution-pilot.ts and plans/tools/attribution-bakeoff.ts both // decide on a seconds-per-chunk threshold (the pilot's 66.2 against the digest // lane's 11.2; round 2's bar is < 25). Two copies of this regex would let the // two harnesses report different numbers for the same run, which is the same // failure a second copy of the SCORER would be — see attributionScore.ts's // header. The metric and its denominator travel together. // // The line, as digestApps emits it: // ollama qwen2.5:7b: 4102 in / 218 out tokens in 5.0s wall (load 0.4s, // prefill 0.1s, decode 3.0s, engine 3.5s) (num_ctx 8192) const CALL_RE = /^ollama (\S+): (\d+|\?) in \/ (\d+|\?) out tokens in ([\d.]+)s wall(?: \(([^)]*)\))?/; const PHASE_RE = /^(load|prefill|decode|engine) ([\d.]+)s$/; export type CallTiming = { wallSeconds: number; loadSeconds?: number; prefillSeconds?: number; decodeSeconds?: number; engineSeconds?: number; inputTokens?: number; outputTokens?: number; }; // A timing, or null when the line is not an engine call line at all. // // EVERY FIELD IS OPTIONAL ON PURPOSE. nsToMs OMITS a phase rather than zeroing // it, and the whole parenthetical is dropped when the engine reports nothing — // so an absent phase stays absent here too, and a caller averages each // engine-derived figure over ITS OWN denominator rather than over the call // count. Zero-filling would quietly drag every mean toward 0. export function parseEngineCall(line: string): CallTiming | null { const m = CALL_RE.exec(line); if (!m) return null; const out: CallTiming = { wallSeconds: Number(m[4]) }; if (m[2] !== "?") out.inputTokens = Number(m[2]); if (m[3] !== "?") out.outputTokens = Number(m[3]); for (const part of (m[5] ?? "").split(", ")) { const p = PHASE_RE.exec(part.trim()); if (!p) continue; const seconds = Number(p[2]); if (p[1] === "load") out.loadSeconds = seconds; else if (p[1] === "prefill") out.prefillSeconds = seconds; else if (p[1] === "decode") out.decodeSeconds = seconds; else out.engineSeconds = seconds; } return out; } // True for a line that LOOKS like an engine call but did not parse. A harness // counts these and marks every timing number suspect if any appear — a silently // dropped call line would understate cost, which is the direction that gets a // sweep approved on a number that was never true. export function isUnparsedEngineLine(line: string): boolean { return line.startsWith("ollama ") && CALL_RE.exec(line) === null; }