Aller au contenu

Comparaison des données par outil

Objectif : Comparer les données disponibles dans les JSON/transcripts de chaque outil supporté par ai-footprint.

Mise à jour : Ce document est mis à jour à chaque nouvel outil ajouté.


Légende

Symbole Signification
Disponible dans cet outil
Non disponible
⚠️ Partiellement disponible (structure différente)

Tableau comparatif

Champ Claude Code (JSONL) Opencode (JSON) Pi (JSONL) Codex CLI (JSONL) Usage dans ai-footprint
Identifiants
sessionId session_id ✅ header type:"session", id session_meta.payload.id Clé de jointure avec sessions table
uuid / id msg_id message.id message.id (entrée type:"message") ❌ (id synthétique session_id:ligne) Clé unique par message
Modèle
model (string) "claude-opus-4-8" ⚠️ {providerID, modelID} message.model turn_context.payload.model (par tour) Normalisé en provider + model dans InferenceEvent
provider ❌ (déduit de model) model.providerID message.provider session_meta.payload.model_provider Permet le lookup EcoLogits
Tokens
input_tokens tokens.input message.usage.input ⚠️ last_token_usage.input_tokens (inclut le cache) Calcul d'impact
output_tokens tokens.output message.usage.output last_token_usage.output_tokens Calcul d'impact
cache_creation_input_tokens ⚠️ tokens.cache.write message.usage.cacheWrite ❌ (non distingué par l'API OpenAI) Calcul d'impact (cache)
cache_read_input_tokens ⚠️ tokens.cache.read message.usage.cacheRead last_token_usage.cached_input_tokens Calcul d'impact (cache)
reasoning_tokens tokens.reasoning ⚠️ last_token_usage.reasoning_output_tokens (non stocké) À valider avec EcoLogits
Temps
timestamp (ISO 8601) ⚠️ Unix timestamp ms ✅ ISO 8601 natif ✅ ISO 8601 natif Converti en ISO 8601 UTC
active_seconds (delta) ✅ Calculé time.completed - time.created ✅ Calculé (delta entre timestamps successifs) ✅ Calculé (delta entre lignes successives) Mesure du temps actif
Coût
cost (USD) ❌ (non lu par le collecteur) cost (BD + exports) ⚠️ message.usage.cost.total (présent mais non stocké) Non stocké — pas de champ cost dans InferenceEvent
latency (ms) ❌ (non lu par le collecteur) Non exploité actuellement
Métadonnées session
title session.title Non stocké (note : à risquer)
directory cwd session.directory session.cwd session_meta.payload.cwd Utilisé pour project (basename)
slug session.slug Non stocké (note : à risquer)
path session.path Non stocké (note : à risquer)
Statut
role (user/assistant) message.role ❌ (filtré via event_msg/token_count) Filtrage (seuls les assistant comptent)
error error.name, error.data Non stocké — pas de champ error dans InferenceEvent
archived time_archived Non exploité actuellement
Collecte
Format de stockage JSONL (ligne par ligne) SQLite (BDD locale) JSONL (ligne par ligne) JSONL (ligne par ligne) Collecteurs spécifiques par outil
Déclencheur hooks.Stop (fin de session) session.idle (plugin) session_shutdown (extension) Aucun (backfill seul — slot notify non câblé) Installation automatique
Backfilling Lecture directe JSONL Lecture directe SQLite Lecture directe JSONL Lecture directe JSONL Scripts de backfilling spécifiques

Détails par outil

Claude Code

Sources disponibles :

  1. Transcripts de session : ~/.claude/projects/**/*.jsonl — seule source effectivement lue par ClaudeCodeCollector (glob + parsing de tous les **/*.jsonl).

Structure d'un event (transcript) :

{
  "type": "assistant",
  "message": {
    "model": "claude-opus-4-8",
    "usage": {
      "input_tokens": 8427,
      "output_tokens": 287,
      "cache_creation_input_tokens": 7052,
      "cache_read_input_tokens": 8020
    }
  },
  "sessionId": "sess-A",
  "uuid": "u1",
  "cwd": "/Users/me/DEV/projA",
  "timestamp": "2026-06-27T10:08:45.619Z"
}

Collecteur : ClaudeCodeCollector (lecture directe JSONL)


Opencode

Sources disponibles :

  1. BDD locale : ~/.local/share/opencode/opencode.db (SQLite)
  2. Exports plugin : ~/.ai-footprint/crush-exports/<sessionId>.json
  3. SDK SSE : event.subscribe() (temps réel)

Structure d'une session (table session) :

{
  "id": "ses_120fa4dc7ffeSg6YofUeAPBX1P",
  "title": "New session - 2026-06-19T08:35:53.016Z",
  "directory": "/Users/renaudheluin/.agents",
  "model": "{\"id\":\"Qwen3.6-35B-A3B-4bit\",\"providerID\":\"myprovider\"}",
  "tokens_input": 145920,
  "tokens_output": 11950,
  "tokens_reasoning": 0,
  "tokens_cache_read": 0,
  "tokens_cache_write": 0,
  "time_created": 1781858206763,
  "time_updated": 1781858206763
}

Structure d'un message (table message) :

{
  "id": "msg_edf05b24e001gD1yQMa8Rqwfpa",
  "session_id": "ses_120fa4dc7ffeSg6YofUeAPBX1P",
  "data": "{\"role\":\"assistant\",\"time\":{\"created\":1781858153054,\"completed\":1781858153428},\"model\":{\"providerID\":\"myprovider\",\"modelID\":\"Qwen3.6-35B-A3B-4bit\"},\"tokens\":{\"input\":0,\"output\":0,\"reasoning\":0,\"cache\":{\"read\":0,\"write\":0}},\"cost\":0}"
}

Structure d'un export (plugin) :

{
  "info": {
    "id": "sess-abc123",
    "slug": "mon-projet",
    "directory": "/home/user/project",
    "model": { "id": "claude-sonnet-4-20250514", "providerID": "anthropic" },
    "tokens": {
      "input": 8427,
      "output": 287,
      "reasoning": 0,
      "cache": { "read": 8020, "write": 7052 }
    },
    "time": { "created": 1719741600000, "updated": 1719742500000 }
  },
  "messages": [
    {
      "info": {
        "id": "msg-1",
        "role": "assistant",
        "time": { "created": 1719741700000, "completed": 1719741800000 },
        "model": {
          "id": "claude-sonnet-4-20250514",
          "providerID": "anthropic"
        },
        "tokens": {
          "input": 8427,
          "output": 287,
          "reasoning": 0,
          "cache": { "read": 8020, "write": 7052 }
        },
        "cost": 0.00123
      }
    }
  ]
}

Collecteur : CrushCollector (backfilling BDD + lecture exports plugin)


Pi

Sources disponibles :

  1. Transcripts de session : ~/.pi/agent/sessions/--<cwd>--/<timestamp>_<uuid>.jsonl

Structure d'un fichier de session (une entrée d'en-tête type:"session" puis des entrées type:"message") :

{"type":"session","id":"sess-A","timestamp":"2026-06-27T10:00:00.000Z","cwd":"/Users/me/DEV/projA"}
{"type":"message","id":"u1","timestamp":"2026-06-27T10:08:45.619Z","message":{"role":"assistant","provider":"anthropic","model":"claude-opus-4-8","usage":{"input":8427,"output":287,"cacheRead":8020,"cacheWrite":7052,"totalTokens":15786,"cost":{"total":0}}}}

Collecteur : PiCollector (lecture directe JSONL, root = répertoire ou fichier unique)


Codex CLI

Sources disponibles :

  1. Transcripts de session (rollout) : $CODEX_HOME/sessions/**/*.jsonl (défaut ~/.codex/sessions si $CODEX_HOME n'est pas positionné).

Structure d'un fichier de session (une entrée session_meta, puis des entrées turn_context — modèle du tour courant — et event_msg de type token_count portant l'usage cumulé et le delta du tour) :

{"type":"session_meta","payload":{"id":"sess-A","cwd":"/Users/me/DEV/projA","model_provider":"openai"}}
{"type":"turn_context","payload":{"turn_id":"t1","model":"gpt-5.5"}}
{"type":"event_msg","payload":{"type":"token_count","info":{"last_token_usage":{"input_tokens":17242,"cached_input_tokens":10496,"output_tokens":117,"reasoning_output_tokens":23,"total_tokens":17359}}}}

Particularité OpenAI : cached_input_tokens et reasoning_output_tokens sont des sous-ensembles de input_tokens/output_tokens (contrairement au schéma Anthropic où le cache est additif) — input_tokens stocké dans InferenceEvent est donc last_token_usage.input_tokens - cached_input_tokens.

Aucun identifiant de message natif n'existe dans ce format : msg_id est synthétique (session_id:numéro_de_ligne). Les lignes token_count dont last_token_usage est null (pas de nouveau tour depuis le dernier calcul) sont ignorées.

Collecteur : CodexCollector (lecture directe JSONL, root = répertoire ou fichier unique). Backfill uniquement — pas de hook temps réel (le slot notify de config.toml peut être pris par un autre outil).


Notes pour les futurs outils

Quand un nouvel outil est ajouté, mettre à jour :

  1. Ce document (tableau comparatif)
  2. Le collecteur correspondant dans ai_footprint/collectors/
  3. Les tests dans tests/test_<outil>_collector.py

Champs obligatoires à mapper dans InferenceEvent :

  • provider (string)
  • model (string)
  • input_tokens (int)
  • output_tokens (int)
  • cache_creation_tokens (int)
  • cache_read_tokens (int)
  • timestamp (ISO 8601 UTC)
  • project (string, basename du directory)
  • session_id (string)
  • msg_id (string)

Champs optionnels déjà mappés dans InferenceEvent :

  • active_seconds (float)
  • client (string, identifie l'outil)

Champs pas encore mappés (présents chez au moins un outil, absents de InferenceEvent — à ajouter si un besoin produit apparaît) :

  • reasoning_tokens (int)
  • cost (float, USD)
  • error (string)

Document créé le 2026-06-30, mis à jour le 2026-07-18. À mettre à jour à chaque nouvel outil ajouté.