feat(otel): enrich root span with gen_ai attributes and improve output format - #10816
Conversation
…t format Add gen_ai.* semantic convention attributes to root spans (reply/reply_stream) so MLflow can display Request, Response, and Token columns. Fix span hierarchy by explicitly parenting reply_stream under reply to prevent duplicate traces. Consolidate consecutive streaming text/reasoning tokens into single entries in OTEL output instead of per-token JSON objects. Use OpenAI-compatible message format on root spans for MLflow overview compatibility. Closes aaif-goose#10815 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ec5cdd6df5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| gen_ai.usage.input_tokens = tracing::field::Empty, | ||
| gen_ai.usage.output_tokens = tracing::field::Empty, |
There was a problem hiding this comment.
Declare cache-token fields on the aggregate spans
When a turn includes cache read/write tokens, the new aggregate reply/reply_stream usage recording drops them: record_usage records gen_ai.usage.cache_read.input_tokens and gen_ai.usage.cache_creation.input_tokens, but tracing only accepts fields declared at the span callsite. This span (and the reply span above) declares only input/output tokens, so cache-token records are ignored and the root telemetry remains incomplete for providers that report cache usage.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good feature for a future PR
|
This is excellent - thank you @thesteve0 |
|
Thanks this has been really fun. I think from here on out I am going to try using Goose and Qwen 3.6 35B 8bit to see how well it goes. I have has some good preliminary results so far on smaller side projects Let me know if there is something in particular you think would be good to add to the OTEL output |
* main: (103 commits) fix: parse PyPI requirements for OSV checks (#10510) fix(telegram): contain voice file extensions (#10456) Revert "feat(security): chunk command-classifier input with overlapping windows" (#10416) (#10870) docs: update Discord invite (#10863) fix(security): preserve denied tool request precedence (#10612) fix(hints): contain subdirectory hint discovery (#10545) chore(deps): bump pem from 3.0.6 to 4.0.0 (#10853) chore(deps): bump base64 from 0.22.1 to 0.23.0 (#10851) chore(deps): bump jsonwebtoken from 10.4.0 to 11.0.0 (#10850) chore(deps): bump astral-sh/setup-uv from 8.3.2 to 9.0.0 (#10847) chore(deps): bump docker/login-action from 4.5.1 to 4.5.2 (#10846) chore(deps): bump github/codeql-action from 4 to 4.37.3 (#10845) chore(deps): bump actions/stale from 10.4.0 to 11.0.0 (#10844) feat(dictation): add LOCAL_WHISPER_LANGUAGE for multilingual local transcription (#10634) fix(desktop): clear stale validation error when reopening the schedule modal (#10627) fix(docs): resolve CVE-2026-13149 in both brace-expansion copies (#10842) feat(provider): add Friendli as declarative provider (#10762) fix: sanitize shell/subprocess call in linux.rs (#10748) fix(desktop): unlink destination before copying binaries (#10705) feat(otel): enrich root span with gen_ai attributes and improve output format (#10816) ...





Summary
gen_ai.*semantic convention attributes (operation.name,input.messages,output.messages,usage.*) to root spans (reply/reply_stream) so MLflow can populate Request, Response, and Token columnsreply_streamunderreplywithparent:— prevents duplicate traces caused by async stream lazy evaluation breaking span context propagation{"type":"text","content":"..."}JSON objects that made traces unreadable{"role":"user","content":"..."}) on root spans so MLflow's_try_extract_messagescan parse them for the overview preview columnsreply_streamandreplyspansCloses #10815
Test change rationale
Updated the
provider_stream_records_gen_ai_span_attributestest assertion to expect consolidated text ("hello world") instead of two separate streaming tokens ("hello ","world"). This reflects the intentional behavior improvement — the previous per-token output produced dozens of tiny JSON objects that were unreadable in trace dashboards.Test plan
cargo test -p goose gen_ai— all 5 tests passcargo clippy -p goose --all-targets -- -D warnings— clean🤖 Generated with Claude Code