* Restore usage from Mistral Vibe Unified Harness sessions * fix(mistral-vibe): read unpinned Vibe 2.26 unified sessions exactly An unpinned session has session_metadata.active_model null, so the parser dropped it entirely. Fall back to config.toml's active_model, then Vibe's default mistral-medium-3.5. Split the rotated journal prefix into as many calls as runtime state lists completions, so call counts match. Drop the tool group prefix from history names (file_system.bash) and attach a turn's tools to its first call only. Re-derive settled days (DAILY_CACHE_VERSION 58). Adds a redacted fixture from a real 2.26.0 session. --------- Co-authored-by: Resham Joshi <65915470+iamtoruk@users.noreply.github.com>
5.5 KiB
Mistral Vibe
Mistral Vibe CLI.
- Source:
src/providers/mistral-vibe.ts - Loading: eager (
src/providers/index.ts) - Test:
tests/providers/mistral-vibe.test.ts
Where it reads from
$VIBE_HOME/logs/session/ when VIBE_HOME is set, otherwise ~/.vibe/logs/session/.
Storage format
Legacy Vibe 2.x stores each session as a directory:
meta.jsoncontains session metadata, cumulative token totals, active model config, model prices, timestamps, working directory, and available tools.messages.jsonlcontains non-system messages and assistanttool_calls.
Subagent traces are stored under a parent session's agents/ folder with the same meta.json / messages.jsonl shape, so CodeBurn scans those one level down as separate sessions.
Vibe 2.25's Unified Harness (still the layout in 2.26) stores every session
under unified/<session_id>/. A subagent is its own sibling session there,
linked by parent_session_id; its usage is not included in the parent's. Its meta.json has no stats, and there is no
messages.jsonl. CURRENT selects a committed generation containing
projection-state.json, runtime-state.json, and a manifest. The projection's
history can be stored in content-addressed chunks/ files.
CodeBurn reads snapshot.session.tokenUsage and the cumulative usage envelopes
in journal/*.jsonl. It supports both projection_advanced and
projection_delta records. These are recovery journals: Vibe retains only two
segments after checkpointing. Summing action_result records alone loses older
usage, while summing every nested usage object double-counts copies of a call.
CodeBurn takes deltas between cumulative envelopes and recovers the older prefix
from the snapshot. Each later envelope step is one call with its exact usage
(the same numbers as that call's action_result.result.usage). The rotated
prefix is split evenly into as many calls as runtime-state.json lists
succeeded completion actions, across its recorded turns. Call counts and
session totals stay exact; per-call values inside that prefix are an even split.
Caching
Legacy Vibe local logs do not expose cache-read/cache-write token fields, so
CodeBurn reports cache token counts as 0. When meta.json.stats.session_cost
is present, CodeBurn uses that session total instead of re-estimating from
prompt/completion token prices because it is the best cache-aware cost signal
available in the local log shape.
Unified inputTokens includes cachedInputTokens. CodeBurn subtracts cached
input from ordinary input and records it as cache-read usage, then estimates
cost using the pricing catalog. Unified sessions persist no cost of their own
(Vibe's session_cost is computed in memory only), so these costs are marked
estimated. It does not treat contextUsage (the latest context window) as
cumulative spend.
The model is not recorded per call. runtime-state.json
session_metadata.active_model is only a pin and is null for an unpinned
session, which runs the configured default. CodeBurn then reads the top-level
active_model from $VIBE_HOME/config.toml at parse time, falling back to
mistral-medium-3.5 (Vibe's built-in default, priced at Vibe's own rates of
$1.5/M input, $0.15/M cached, $7.5/M output). Changing config.toml later does
not reprice sessions already cached, and mid-session model switches are not
recoverable.
The source cache fingerprints CURRENT, metadata, and the bounded journal
segments. Appending usage invalidates the cache even before Vibe publishes a new
generation. Generation contents and chunks are immutable once published.
Deduplication
Legacy message IDs, or the session ID for an aggregate fallback. Unified usage uses the session ID, projection sequence, turn ID, and call index. Repeated journal sequences and cumulative totals are not counted again.
Quirks
- Usage is cumulative per session. Vibe does not write per-assistant-message token usage into
messages.jsonl; token counts come frommeta.json.stats.session_prompt_tokensandsession_completion_tokens. CodeBurn splits assistant-message tools into their user turns for classification and distributes the cumulative token/cost totals across those assistant calls so session totals remain unchanged. - Cost prefers Vibe's own session total.
meta.json.stats.session_costis used first. If it is missing,meta.json.stats.input_price_per_millionandoutput_price_per_millionare used with the active model config as a fallback. LiteLLM pricing is only used when Vibe provides no price data. - Project names come from metadata. Discovery uses
meta.json.environment.working_directoryand falls back to the session directory name if that field is missing. - Unified tool names carry their group (
file_system.bash,ui.ask_user_question). CodeBurn drops the group before mapping, and a turn's tools are attached to its first call only. - Tool calls come from messages. Assistant
tool_calls[*].function.nameis normalized to the standard CodeBurn names (bashtoBash,search_replacetoEdit, etc.). Bash commands are extracted fromfunction.arguments.command.
When fixing a bug here
- Identify the harness first. Legacy sessions require
meta.jsonandmessages.jsonl; Unified sessions useCURRENT, generations, chunks, and journals. - Check legacy
meta.json.statsor Unified projectionsession.tokenUsage, nevercontextUsage. - Test journal rotation and appends against a warm CodeBurn cache, as well as legacy compatibility. See
tests/fixtures/mistral-vibe-unified.mdfor fixture provenance.