feat: attach pi turns to an external trace via LANGFUSE_PI_TRACEPARENT - #46
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
LFE-16707
An application that already traces its own run can launch pi as one step, but pi opens an unrelated trace per prompt, so the application's work and pi's turns never meet.
pi was the only one of the four coding-agent plugins where a launcher could not pass a W3C traceparent — it accepted the trace-id/span-id pair only, which exists mainly because pi sets it on itself when it spawns a pi subagent.
The change
LANGFUSE_PI_TRACEPARENT, with the same contract asCC_LANGFUSE_TRACEPARENTin the Claude Code plugin:The traceparent wins over the id pair; a malformed one falls back to the pair rather than disabling nesting, since a typo in a launcher variable must not detach a subagent from its parent turn. All-zero ids are rejected, because that is what
INVALID_SPAN_CONTEXTserialises to when a launcher has no active span. The flags field is read and discarded. A bareTRACEPARENTis deliberately not read: pi runs as a child of whatever launched it, and an OpenTelemetry-instrumented parent exports that variable into its subprocesses.parseTraceparentis not pinned to version00. The spec's versioning rule says a receiver that meets a higher version should read the first three fields and ignore the rest; onlyffis refused, and trailing fields remain an error at version00. This mirrors OTel's ownparseTraceParentand is a deliberate difference from the Claude Code plugin and Codex PR #100, which both hardcode^00-. Worth pulling those two along.Verification
Against a real Anthropic provider (
claude-haiku-4-5) and a real Langfuse project, not a mock:01accepted, versionffrejected, trailing fields at00rejected, bareTRACEPARENTignored, subagent.langfuse.trace.name,session.id,langfuse.trace.tagsoruser.idin attached mode, while the standalone arm still carries all three. Mutation-checked — without the ownership propagation the probe reportsLLM Call trägt session.id, langfuse.trace.tags, user.id auf einem fremden Trace.totalCoststill aggregates on its trace: suppressing the labels costs no cost aggregation, because that rolls up through the observation tree.143/143 tests,
tsc --noUnusedLocals --noUnusedParametersclean.