Skip to content

scripts: commit the show-spans generator for the telemetry demo - #558

Open
brentrager wants to merge 1 commit into
mainfrom
th-showspans
Open

brentrager wants to merge 1 commit into
mainfrom
th-showspans

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

.github/demo-telemetry.gif is captioned "Not a mockup" and was generated by an ad-hoc show-spans.sh that was never committed. By the time it needed regenerating for a model change, the script was gone — not in the repo, not in git history, not in any session transcript. A reproducible asset nobody can reproduce is just an asset.

This reconstructs and commits it. One real turn, real spans, and gen_ai.request.model is whatever SMOOTH_AGENT_MODEL says — which is how the demo gets re-shot for a new model instead of retouched.

(cd rust && cargo build -p smooai-smooth-operator-server)
SMOOAI_GATEWAY_KEY=sk-… SMOOTH_AGENT_MODEL=gpt-5.6-luna scripts/show-spans.sh

Three ways to get an empty capture

Each looks like broken telemetry rather than a harness mistake. All three are handled by the script and written down in scripts/README-show-spans.md:

  1. RUST_LOG below info for the operator crates. gen_ai.chat and gen_ai.tool are info-level spans — a warn filter doesn't hide them, it stops them being created. This one cost the most time: the turn ran perfectly, the collector was healthy, and the dump was empty.
  2. Server started before the collector. The OTLP exporter connects at boot, so it exports into a closed port and never retries.
  3. Killing the server when the turn resolves. The exporter batches, so the last batch dies with it.

Why a collector is required

The fmt layer prints tracing events; spans only materialise on export. So a span tree can only be read off an OTLP consumer — which is what otelcol:4317 in the demo is. scripts/otel/collector.yaml is a throwaway one whose only job is to print what it receives.

Its service.telemetry.logs.level must stay at info: the debug exporter writes through that logger, so warn silences the very spans it exists to show.

Two protocol details the schemas don't state

Both cost a debugging round and are now recorded in drive-one-turn.mjs:

  • sessionId comes back nested under data, not at the top level.
  • requestId is listed optional on send_message, but the server rejects the frame without one (VALIDATION_ERROR).

Honesty

format-spans.mjs invents nothing — every attribute printed is read from the collector dump, and the "parked for approval" note only appears when the run actually parked (PARKED=1, which the script sets because it sets SMOOTH_AGENT_CONFIRM_TOOLS).

Verification

Clean end-to-end run against llm.smoo.ai: turn parked at knowledge_search, approved, answered with citations, 45 tokens streamed. Collector received gen_ai.chat with gen_ai.request.model: Str(gpt-5.6-luna) and its gen_ai.tool child.

🤖 Generated with Claude Code

`.github/demo-telemetry.gif` is captioned "Not a mockup" and was generated
by an ad-hoc `show-spans.sh` that was never committed. By the time the GIF
needed regenerating for a model change, the script was gone — not in the
repo, not in any session transcript, not in git history. A reproducible
asset that nobody can reproduce is just an asset.

So this reconstructs it and commits it. One real turn, real spans, and
`gen_ai.request.model` is whatever `SMOOTH_AGENT_MODEL` says — which is
how the demo gets re-shot for a new model instead of retouched.

Three things hand you an EMPTY capture, and each looks like broken
telemetry rather than a harness mistake. All three are now handled by the
script and written down in scripts/README-show-spans.md:

  1. RUST_LOG below info. `gen_ai.chat` and `gen_ai.tool` are info-level
     SPANS — a `warn` filter does not hide them, it stops them being
     created. This one cost the most time: the turn ran perfectly, the
     collector was healthy, and the dump was empty.
  2. Server started before the collector. The OTLP exporter connects at
     boot, so it exports into a closed port and never retries.
  3. Killing the server when the turn resolves. The exporter batches, so
     the last batch dies with it.

A collector is required and that is not incidental: the fmt layer prints
tracing EVENTS, and spans only materialise on export — a span tree can
only be read off an OTLP consumer. scripts/otel/collector.yaml is a
throwaway one whose only job is to print what it receives. Note its
`service.telemetry.logs.level` must stay at info; the debug exporter
writes THROUGH that logger, so `warn` silences the very spans it exists
to show.

drive-one-turn.mjs records two protocol details the schemas do not:
`sessionId` comes back nested under `data`, and `requestId` is documented
optional on send_message but the server rejects the frame without one.

format-spans.mjs invents nothing — every attribute printed is read from
the collector dump, and the "parked for approval" note only appears when
the run actually parked (PARKED=1, set by the script because it sets
SMOOTH_AGENT_CONFIRM_TOOLS).
@changeset-bot

changeset-bot Bot commented Aug 29, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 76f1fe3

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

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