Skip to content

telemetry: MLflow trace columns (Name/Session/User/Source) blank; token & cost omit cache tokens #5361

Description

@dhshah13

What happens

Now that L2 OTLP export is live to the pilot MLflow (post-#3749, fullsend-ai dogfood runs landing in experiment 1), the experiment Traces view populates only a few columns. Across the 50 most recent real traces:

Column Populated Note
Name 0/50 blank on every trace
Session 0/50 can't group runs by issue/PR
User 0/50 triggering actor unknown
Source 0/50 repo / workflow / commit unknown
Request / Response 0/50 content — L3, expected empty
Tokens 50/50 derived from input_tokens/output_tokens only
Cost 50/50 undercounts — see below

Sample (tr-6d451616…, 218s run): tokenUsage {input: 30, output: 13536}, cost {input_cost: 0.00015, output_cost: 0.338}. The run consumed ~100k+ cached input tokens, but input_tokens: 30 (and thus input_cost: ~$0.0002) reflects only non-cached input — MLflow derives token/cost from gen_ai.usage.input_tokens/output_tokens and ignores the cache_read_input_tokens / cache_creation_input_tokens we emit.

Why it matters

Name / Session / User / Source are the columns that make the trace list navigable and groupable (per issue/PR, per actor, per repo). Cost is the pilot's headline metric; undercounting cached input by orders of magnitude undermines it.

Root cause

The exporter emits generic OTel attributes only — fullsend.*, gen_ai.usage.*, fullsend.cost_usd — and no mlflow.* trace-level attributes. MLflow auto-derives tokenUsage/cost from gen_ai.usage.input/output, but has no source for Name/Session/User/Source and does not fold cache tokens into the input figure.

Raw material we already emit (root span)

fullsend.agent, fullsend.work_item_id, gen_ai.request.model, gen_ai.usage.{input,output,cache_read,cache_creation}_input_tokens, fullsend.cost_usd (cache-aware, accurate), fullsend.tool_calls, fullsend.num_turns, fullsend.iterations. Not captured today: triggering actor and source repo/commit/run-url as span attributes.

Candidate mappings (illustrative, not prescriptive)

  • Namefullsend.agent (optionally + work_item_id)
  • Sessionfullsend.work_item_id (groups all runs for one issue/PR)
  • User ← triggering actor (needs capture from CI context, e.g. GITHUB_ACTOR / issue author)
  • Source ← repo + commit + run URL (needs capture from CI env)
  • Tokens/Cost ← include cache tokens in the input figure, and/or surface fullsend.cost_usd directly

Open design question

Populating MLflow's Name/Session/User/Source requires emitting mlflow.*-prefixed trace attributes, which couples the backend-agnostic exporter to MLflow. Options to decide: emit mlflow.* attributes per ADR 0050; keep the exporter generic and accept blank MLflow columns; or map at a Collector/backend layer. The token/cost fidelity gap is partly upstream (MLflow's extractor ignores cache fields) and partly ours (we could emit a combined input count or the cost directly).

Out of scope

Request/Response = prompt/completion content = L3 (governance-gated). Not part of this issue.

Relates to #2862.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugcomponent/runnerAgent runner behavior and lifecyclepr-openAn open PR already addresses this issuepriority/highSignificant impact, address soonready-to-codeTriaged and ready for the code agenttype/bugConfirmed defect in existing behavior

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions