Skip to main content

Module usage

Module usage 

Source
Expand description

Provider usage, read as the provider reported it, and the one normalisation every comparison uses.

Providers do not agree on what their fields mean. Anthropic reports three disjoint input quantities (uncached, written to the cache, read from the cache); OpenAI reports one input total with the cached part inside it. Both are kept in their native names in the run record (EconomicsRequest), and totals maps them onto one shape where total_input = uncached + cache write + cache read holds for both.

What a session said is never kept. read_stream reads a Claude Code stream-json transcript and keeps numbers and tool names; text, tool inputs and tool results are dropped as they are read, so a run record cannot leak a prompt, a file or a secret.

use majordomus_cli::economics::usage::read_stream;
let stream = concat!(
    r#"{"type":"assistant","message":{"id":"m1","model":"claude-sonnet-5","content":[{"type":"text","text":"secret"}],"usage":{"input_tokens":3,"cache_creation_input_tokens":100,"cache_read_input_tokens":0,"output_tokens":7}}}"#, "\n",
    r#"{"type":"assistant","message":{"id":"m1","model":"claude-sonnet-5","content":[{"type":"tool_use","name":"Read","input":{"file_path":"/x"}}],"usage":{"input_tokens":3,"cache_creation_input_tokens":100,"cache_read_input_tokens":0,"output_tokens":7}}}"#, "\n",
    r#"{"type":"result","subtype":"success","is_error":false,"num_turns":1,"total_cost_usd":0.25}"#, "\n",
);
let s = read_stream(stream).unwrap();
assert_eq!(s.requests.len(), 1, "one message, two content blocks, one request");
assert_eq!(s.tools.get("Read"), Some(&1));
assert_eq!(s.reported_cost_microusd, Some(250_000));
assert!(!serde_json::to_string(&s.requests).unwrap().contains("secret"));

Structs§

StreamFacts
What read_stream recovers from one session’s transcript: the numeric and structural parts of an EconomicsSession. The caller adds what the transcript does not know (index, prompt digest, wall clock).

Enums§

ShellEffect
What a shell command does to the working tree, as far as its text shows. Agents edit through the shell as often as through edit tools (cat > f, sed -i, a heredoc script that opens a file for writing), so orientation cannot end only at an Edit call.

Functions§

add
The field-wise sum of two totals. Reasoning and cost stay known only when both are: an unknown on either side makes the sum unknown, never a smaller number.
anthropic_request
Read an Anthropic usage object into a request, native field names kept.
first_request_input
The input tokens of a session’s first request: everything the session was given before the model had done anything (system prompt, instruction files, hook output, the prompt). The three disjoint input fields are summed; the request’s output is not input and is left out. None when the session made no request.
openai_request
Read an OpenAI usage object into the same shape. OpenAI’s input_tokens includes the cached part (input_tokens_details.cached_tokens), where Anthropic’s excludes it; the cached part is moved out so that the three input fields are disjoint for both. OpenAI bills no cache writes, so that field is zero, which is what it is.
read_stream
Read a Claude Code --output-format stream-json --verbose transcript. Lines that are not JSON objects are skipped; a transcript with neither a request nor a result event is an error, because a session that reported nothing must be recorded as having reported nothing, not as having used zero tokens.
session_totals
A session’s totals. The harness’s per-model totals are preferred, because they include the calls the harness makes on its own account (titles, summaries) that the transcript does not show as messages; the per-request sum is used only when they are absent. None when the session reported neither: absence stays absence.
shell_effect
Classify one shell command by its text alone; nothing is run. A command that writes a file is an edit whatever else it does, so a write outranks the read or search it starts with; otherwise the leading command decides, and a pipe into grep makes a search. A redirection to /dev/null or to another descriptor (2>&1) writes nothing and is not an edit, and neither is a > inside a quoted argument, which is text, not a redirection.
totals
A run’s totals: the sum of its sessions’. None when any session reported nothing, because a partial sum would understate the run.