Add Langfuse trace.userId / trace.sessionId population (0064)#171
Merged
chris-colinsky merged 4 commits intoJun 19, 2026
Conversation
Advance the spec submodule pin v0.61.0 -> v0.62.0 to absorb accepted proposal 0064 (Langfuse trace.sessionId / trace.userId population). Updates __spec_version__, the pyproject spec_version, the smoke-test version assertion, and regenerates the bundled AGENTS.md. conformance.toml records 0064 as partial: the trace.userId half ships, while trace.sessionId is dormant until the sessions capability (0020) supplies openarmature.session_id.
Implement proposal 0064's Langfuse Trace-level grouping fields. The observer recognizes a userId key in the caller-supplied invocation metadata and promotes it to the first-class trace.userId, additively (the key also stays in trace.metadata.userId). trace.sessionId sources from openarmature.session_id; python has no source until the sessions capability (0020), so that half is plumbed but dormant (passes None). LangfuseClient.trace() (the Protocol, the in-memory client, and the SDK adapter) gains session_id / user_id; the observer centralizes the promotion through a _client_trace wrapper so all five trace-open sites apply it uniformly. Unit tests cover the client plumbing and the promotion helper; the live integration test plus the extended end-to-end cloud test assert both fields populate real Langfuse.
Activate observability fixture 084 (Langfuse session/user promotion): cases 2/3/4 (not session-bound, userId present additively, userId absent) run now; the session-bound cases 1/5 defer per-case until the sessions capability (0020) supplies a session_id source. Extend the fixture-parsing models for 084's shapes: ObservabilityExpected gains langfuse_trace / langfuse_traces (and the matching discriminator keys), and CaseSpec.invocations widens to int | list to carry case 5's multi-invocation specs alongside the existing run-count usage.
Document the Langfuse trace.userId / trace.sessionId population in the observability concepts page, add the 0.15.0 changelog entry (folding 0064 into the cycle's spec-pin bullet), and demonstrate the userId promotion in the langfuse-observability example (a per-operator userId that surfaces in the captured trace). sessionId is left out of the example since it stays dormant until the sessions capability lands.
There was a problem hiding this comment.
Pull request overview
Implements spec proposal 0064 (spec v0.62.0) for Langfuse observability by populating Langfuse’s cross-trace grouping fields (trace.userId, trace.sessionId) from OpenArmature-carried data, and bumps the pinned spec version to v0.62.0.
Changes:
- Add
session_id/user_idplumbing to the Langfuse client protocol, in-memory client, and Langfuse SDK adapter; centralize trace creation in the observer to apply promotions uniformly. - Promote caller invocation metadata
userIdinto Langfusetrace.userId(additive: remains intrace.metadata.userId); wiretrace.sessionIdend-to-end but leave observer source dormant (unset) pending sessions capability (0020). - Add/extend unit, conformance, and integration coverage for the new trace-level fields; update docs/examples/changelog and bump spec version markers.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_observability_langfuse.py | Adds unit tests for session/user id recording and userId promotion helper. |
| tests/unit/test_observability_langfuse_adapter.py | Updates adapter cloud test invocation to include metadata={"userId": ...} and documents expected dashboard behavior. |
| tests/test_smoke.py | Updates asserted __spec_version__ to 0.62.0. |
| tests/integration/test_langfuse_sdk_adapter.py | Adds live Langfuse integration test asserting session_id / user_id land on the retrieved trace. |
| tests/conformance/test_observability.py | Wires conformance fixture 084 runner and implements assertions for runnable cases (session-bound cases deferred). |
| tests/conformance/harness/fixtures.py | Extends invocations typing to support list-shaped multi-invocation specs for fixture 084. |
| tests/conformance/harness/expectations.py | Adds Langfuse trace-level expectation fields for fixture 084. |
| src/openarmature/observability/langfuse/observer.py | Adds _promoted_user_id and routes all trace opens through _client_trace to set user_id and (currently) unset session_id. |
| src/openarmature/observability/langfuse/client.py | Extends LangfuseTrace and LangfuseClient.trace() with session_id / user_id; stores them in the in-memory client. |
| src/openarmature/observability/langfuse/adapter.py | Caches and propagates session_id / user_id via propagate_attributes for every observation under a trace. |
| src/openarmature/AGENTS.md | Updates embedded spec version reference to v0.62.0. |
| src/openarmature/init.py | Bumps __spec_version__ to 0.62.0. |
| pyproject.toml | Bumps tool.openarmature.spec_version to 0.62.0. |
| examples/langfuse-observability/main.py | Demonstrates passing metadata={"userId": ...} and prints promoted userId in captured trace output. |
| docs/concepts/observability.md | Documents Langfuse trace.sessionId / trace.userId population behavior and current session-id dormancy. |
| conformance.toml | Adds proposal 0064 status as partial with rationale and fixture coverage notes. |
| CHANGELOG.md | Adds release-note entry for proposal 0064 and updates spec pin summary. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
Summary
Implements proposal 0064 (spec v0.62.0): the Langfuse observer populates Langfuse's two cross-trace grouping fields,
trace.userIdandtrace.sessionId, from data OpenArmature already carries. Pins the spec submodule v0.61.0 -> v0.62.0.What changed
trace.userId(live). The observer recognizes auserIdkey in the caller-supplied invocation metadata and promotes it to the first-classtrace.userIdfield, automatically and additively (the key also remains attrace.metadata.userId). An absent key leavestrace.userIdunset.trace.sessionId(dormant). Sourced fromopenarmature.session_id, which the sessions capability (proposal 0020) establishes. python does not implement 0020 yet, so the plumbing is wired end to end but the observer passesNone(unset) until 0020 lands. An unsettrace.sessionIdis the correct "not session-bound" behavior in the interim.LangfuseClient.trace()(the Protocol, the in-memory client, and the SDK adapter) gainssession_id/user_id. The observer centralizes the promotion through a_client_tracewrapper so all five trace-open sites (main, lazy, detached) apply it uniformly.conformance.tomlrecords 0064partial(scoped to the session half); the observability concepts page documents the promotion; thelangfuse-observabilityexample demonstrates theuserIdpromotion.Design notes
The split is principled and matches the proposal:
session_idis a first-class OA concept (it loads and persists session state) and earns its source from the sessions capability, whereas a user id has no runtime semantics in OA, so it is promoted observer-side from caller metadata rather than introduced as an engine surface. Langfuse-only: OpenTelemetry has no trace-level session/user field, and the OTel side already carriesopenarmature.session_idplus theopenarmature.user.*family as span attributes.conformance.tomlispartialbecausetrace.sessionIdcannot be conformance-tested until python producesopenarmature.session_id: fixture 084's session-bound cases (1, 5) defer per-case until 0020, while cases 2/3/4 (not session-bound, plus the userId promotion) run now.Testing
trace.userIdandtrace.sessionIdpopulate the real Trace and the Users dashboard (the integration test asserts both via the REST API; the end-to-end cloud test demonstrates the observer promotion).Notes
0.15.0changelog date is tentative pending the release tag.set_trace_io(the proposal 0043trace.input/trace.outputpath) in favor ofpropagate_attributes; migrating that path is out of scope here (0064 already usespropagate_attributesfor session/user).