Skip to content

fix(antigravity): 3x token/cost triple-counting when ModelUsageStats lacks message/response IDs #2026

Closed

Description

@zhibisora

Describe the bug

When parsing Antigravity SQLite conversation databases (*.db), ccusage antigravity triple-counts (3x) every model turn's tokens (inputTokens, outputTokens, cacheReadTokens) and cost whenever ModelUsageStats does not populate response_id, provider_assigned_message_id, or message_id (which is the case for Gemini models such as gemini-4-argon and gemini-3.8-flash served via Antigravity ACP / localharness).

Root Cause

In rust/adapters/antigravity/src/parser.rs and rust/adapters/antigravity/src/loader.rs:

  1. For a single LLM turn (even when no retry occurred), Antigravity records identical ModelUsageStats in 3 places:

    • gen_metadata -> CortexStepGeneratorMetadata.chat_model.usage (field 4), where chat_model has response_model = "gemini-4-argon" (field 19) and model_display_name = "gemini-4-argon-medium" (field 21).
    • gen_metadata -> CortexStepGeneratorMetadata.chat_model.retry_infos[0].usage (field 17 -> field 4), which always records the initial attempt's usage even when only 1 attempt was made.
    • steps -> CortexStepMetadata.model_usage (field 9), where generator_model_info (field 24) has model_display_name = "gemini-4-argon-medium".
  2. Here is an actual decoded CortexStepGeneratorMetadata row (gen_metadata[0]) and corresponding CortexStepMetadata row (steps[1]) from Antigravity 1.4.1:

    # gen_metadata[0]
    chat_model {
      model: MODEL_GOOGLE_GEMINI_INTERNAL_BYOM
      usage {
        input_tokens: 15027
        output_tokens: 49
        response_output_tokens: 49
      }
      retry_infos {
        usage {
          input_tokens: 15027
          output_tokens: 49
          response_output_tokens: 49
        }
      }
      response_model: "gemini-4-argon"
      custom_metadata {
        key: "request_id"
        value: "5bb041ce-549c-4078-b930-a9381bcd7c96-0"
      }
      model_display_name: "gemini-4-argon-medium"
    }
    step_indices: 1
    
    # steps[1].metadata
    source: CORTEX_STEP_SOURCE_MODEL
    model_usage {
      input_tokens: 15027
      output_tokens: 49
      response_output_tokens: 49
    }
  3. Because ModelUsageStats does not have response_id (field 10), provider_assigned_message_id (field 12), or message_id (field 8) populated in these records, usage.identity_keys() returns an empty Vec<String>.

  4. In loader.rs::deduplicate_events, any AntigravityUsageEvent with empty identities never matches identity_indexes, so all 3 copies are inserted as separate events instead of being merged:

    • gen_metadata usage + retry_infos[0].usage resolve [19, 21] -> field 19 ("gemini-4-argon"), producing 2x tokens under "gemini-4-argon".
    • steps metadata.usage resolves model_info -> "gemini-4-argon-medium", producing 1x tokens under "gemini-4-argon-medium".

Reproduction / Observed Output

For a session whose actual cumulative usage is inputTokens: 70,786, cacheReadTokens: 500,131, outputTokens: 4,996, ccusage antigravity session --json outputs exact 2x + 1x = 3x numbers:

{
  "cacheCreationTokens": 0,
  "cacheReadTokens": 1500393,
  "inputTokens": 212358,
  "modelBreakdowns": [
    {
      "cacheCreationTokens": 0,
      "cacheReadTokens": 1000262,
      "cost": 1.0212204,
      "inputTokens": 141572,
      "modelName": "gemini-4-argon",
      "outputTokens": 9992
    },
    {
      "cacheCreationTokens": 0,
      "cacheReadTokens": 500131,
      "cost": 0.2553051,
      "inputTokens": 70786,
      "modelName": "gemini-4-argon-medium",
      "outputTokens": 4996
    }
  ],
  "outputTokens": 14988,
  "totalTokens": 1731867
}

Notice that "gemini-4-argon" is literally 2 * "gemini-4-argon-medium" across every metric (141572 = 2 * 70786, 1000262 = 2 * 500131, 9992 = 2 * 4996).

Suggested Fix

  1. Deduplicating usage vs retry_infos within a single GeneratorMetadata / StepMetadata:
    • When retry_usages.len() == 1 and its token counts equal usage (or when retry_usages has no distinct identity keys from usage), retry_infos[0] is simply a mirror of the primary attempt in usage and should not be emitted as a second unkeyed event.
  2. Linking gen_metadata and steps when ModelUsage lacks message IDs:
    • CortexStepGeneratorMetadata contains step_indices (repeated int32, field 2) which directly maps a gen_metadata row to the corresponding steps.idx rows, and chat_model.custom_metadata (field 20) includes request_id / last_step_index. Using step_idx (from steps.idx and gen_metadata.step_indices) as a fallback identity key (e.g. step:{session_id}:{step_idx}) allows deduplicate_events to properly merge the steps row and the gen_metadata row even when provider message IDs are absent.

Activity

  1. pullfrog commented on Nov 5, 2026

    @pullfrog
    Contributor
  2. added
    bugSomething isn't working
    priority:highHigh user impact or an important regression.
    triage:maintainableFits the repository's maintainable scope and needs review.
    on Nov 5, 2026
  3. github-actions commented on Nov 5, 2026

    @github-actions
    Contributor

    Pullfrog triage: priority:high
    Kind: bug
    Maintenance fit: maintainable
    Confidence: high

    Antigravity reports 3x tokens and cost when ModelUsageStats lacks message IDs. Issue provides decoded protobuf and exact 3x reproduction numbers, and parser and loader code confirm empty identity keys bypass deduplication. This is a material usage reporting error in supported behavior.

    Decision: kept open; Pullfrog will attempt a focused implementation PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority:highHigh user impact or an important regression.triage:maintainableFits the repository's maintainable scope and needs review.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions