Skip to content

Promote finishReason/reasoningTokens to first-class trace + Model Hub fields - #227

Open
anilguleroglu wants to merge 1 commit into
mainfrom
feat/finishreason-reasoning-tokens-firstclass
Open

Promote finishReason/reasoningTokens to first-class trace + Model Hub fields#227
anilguleroglu wants to merge 1 commit into
mainfrom
feat/finishreason-reasoning-tokens-firstclass

Conversation

@anilguleroglu

Copy link
Copy Markdown
Collaborator

Summary

  • finishReason and reasoningTokens were folded into each tracing event's metadata JSON blob — invisible to Mongo projections, unqueryable, and never surfaced in the Model Hub gateway at all. Both are now first-class fields/columns end to end:
    • Schema: agent_tracing_events, agent_tracing_sessions (+totalReasoningTokens/truncatedEvents), model_usage_logs, usage_daily, with ensureTableColumn migrations for existing tenant DBs.
    • Write paths: HTTP batch + stream ingest, OTLP ingest, the internal Console-hosted agent sink, and the Model Hub gateway (previously logged neither value at all).
    • Read paths: session/event APIs (with a ?truncated=true session filter), the tracing detail UI (Reasoning token card, TRUNCATED badges), the Model Hub logs UI (Finish column + reasoning sub-line), i18n (en/tr).
    • Shared src/lib/shared/finishReason.ts normalizes/classifies provider values consistently server + client.
    • scripts/backfill-trace-fields.ts migrates already-stored rows (metadata → column) and recomputes session totals; added the updateAgentTracingEvent DB primitive it needs (events were previously write-once).
  • Hard invariant preserved everywhere: reasoningTokens is a SUBSET of outputTokens — never added into totalTokens or any cost calculation.

Test plan

  • npx tsc --noEmit — clean
  • npx vitest run — 3285 passed, 4 skipped, 0 failed
  • npx eslint on all changed files — 0 errors
  • npm run build — production build succeeds
  • End-to-end manual verification on an isolated SQLite instance: first-class columns round-trip, legacy metadata-only rows fall back correctly, session totalReasoningTokens/truncatedEvents accumulate correctly, totalOutputTokens is unaffected by reasoning tokens (no double count), truncated=true filter and the new updateAgentTracingEvent backfill primitive both work
  • npm run backfill:trace-fields needs a real run against staging/prod data once merged (not run here — local env points at prod)

🤖 Generated with Claude Code

… fields

They used to ride inside each event's `metadata` JSON blob, invisible to
projections, queries and the UI. Both are now real columns/fields across
every write path (external HTTP + OTLP ingest, the internal agent sink,
and the Model Hub gateway), every read path (session/event APIs, the
tracing UI, the Model Hub logs UI), and the usage_daily rollup.

reasoningTokens is always a SUBSET of outputTokens — never billed or
summed on top of it. A shared src/lib/shared/finishReason.ts normalizes
and classifies provider values (stop/length/tool_calls/...) consistently
across server and client code. Old rows fall back to their metadata
location until scripts/backfill-trace-fields.ts is run, which also adds
the updateAgentTracingEvent DB primitive needed to migrate them in place.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant