Skip to content

feat(tracing): add trace_scope to group a Codex session into one trace#27

Open
TropicalDog17 wants to merge 1 commit into
langfuse:mainfrom
TropicalDog17:feat/trace-scope-session
Open

feat(tracing): add trace_scope to group a Codex session into one trace#27
TropicalDog17 wants to merge 1 commit into
langfuse:mainfrom
TropicalDog17:feat/trace-scope-session

Conversation

@TropicalDog17

Copy link
Copy Markdown

Problem

Every Codex turn becomes its own Langfuse trace, linked to its siblings only through the session id. A working session therefore fills the traces list with a long run of near-identical Codex Turn rows, and the unit people actually reason about — the session — has no single trace to open.

Change

Adds a trace_scope config key (LANGFUSE_CODEX_TRACE_SCOPE):

  • "turn" (default) — today's behaviour, unchanged.
  • "session" — every turn of a thread is pinned to one deterministic trace id derived from the Codex thread id, so the session is a single Codex Session trace whose top-level spans are its turns. Generations, tool calls, and subagents stay nested underneath exactly as before; cost, tokens, and latency aggregate over the session.

The id is hex(sha256("codex-session:<threadId>")).slice(0, 32), so each Stop-hook invocation appends to the same trace. It composes with trace_seed, which becomes hex(sha256("<seed>:<threadId>")).slice(0, 32) — still precomputable by an external harness.

This reuses the existing SEED_PARENT_SPAN_ID placeholder-parent mechanism, so no new tracing concepts are introduced.

Notes / trade-offs (documented in the README)

  • A session trace's latency spans the wall-clock life of the session, including think time between turns.
  • Switching scope mid-session splits it: turns already uploaded keep their old traces, since the sidecar ledger never re-uploads a turn.

Testing

  • Three new tests in trace.test.ts: all turns of a thread share one session-derived trace id and remain top-level sibling spans; distinct threads get distinct traces; trace_scope composes with trace_seed.
  • Full suite green (38 tests), plus pnpm run lint (prettier, tsc --noEmit, and the lint:dist bundle-matches-source check).
  • Also verified end-to-end against a self-hosted Langfuse: a real 29-turn rollout that previously produced 29 traces now produces one Codex Session trace containing 29 turn spans with their generations and tool calls nested underneath.

🤖 Generated with Claude Code

Upstream emits one Langfuse trace per Codex turn, linked only by session id,
so an active session floods the traces list with near-identical "Codex Turn"
rows. trace_scope="session" pins every turn of a thread to one deterministic
trace id derived from the thread id, so the session becomes a single "Codex
Session" trace whose top-level spans are its turns (generations, tool calls
and subagents still nested underneath).

Defaults to "turn", so existing behaviour is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@CLAassistant

CLAassistant commented Jul 14, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

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.

2 participants