Commit 052b839
authored
Observability LLM payload + GenAI semconv (v0.17.0) (#61)
* chore: bump spec submodule + spec_version to v0.17.0
Pin to v0.17.0 (proposal 0024 accepted — LLM span payload + GenAI
semconv). Submodule, pyproject.toml [tool.openarmature].spec_version,
and the runtime __spec_version__ move in lockstep per the three-pin
drift guard in tests/test_smoke.py.
* feat(observability): LLM payload + GenAI semconv
Realize spec v0.17.0 §5.5 expansion and the five python-only items
from the observability friction roundup.
§5.5.1 input/output payload: openarmature.llm.input.messages,
openarmature.llm.output.content, openarmature.llm.request.extras —
JSON-encoded with sorted keys, default-off via disable_llm_payload,
truncated per §5.5.5 at payload_max_bytes (default 64 KiB, minimum
256). Inline image bytes are redacted at the provider before
reaching the event payload, not gated by any observer flag.
§5.5.2 / §5.5.3 GenAI semconv: gen_ai.system (caller-overridable
per OpenAIProvider for non-OpenAI endpoints), gen_ai.request.model,
gen_ai.response.{model,id,finish_reasons}, gen_ai.usage.{input,
output}_tokens, plus gen_ai.request.{temperature,max_tokens,top_p,
seed} when set. Opt-out via disable_genai_semconv.
OTelObserver knobs: resource= for service.name, span_processor
accepts SpanProcessor | Sequence[SpanProcessor], attribute_enrichers
hook fires before every span.end() the observer issues.
LlmEventPayload (renamed from _LlmEventState, moved to
openarmature.observability.llm_event) and LLM_NAMESPACE are now
public — third-party Provider impls and custom observers can
interoperate against a stable shape. _LlmEventState retained as a
deprecated alias for one release.
Response gains response_id and response_model typed fields sourcing
the new gen_ai.response.* attributes from the wire payload.
Fix the prompt-context cross-task propagation bug: the worker task
running deliver_loop snapshots its Context at invoke()-entry, so
with_active_prompt(...) blocks opened later inside node bodies were
invisible to the observer. Capture current_prompt_result() /
current_prompt_group() at dispatch time in _make_llm_event (running
in the node task where the ContextVars are set) and put the snapshot
on LlmEventPayload; observer reads from the payload.
Tests: 10 new conformance fixture drivers (012-021), assertion-helper
module, RuntimeConfigSpec directive shape, end-to-end #3 regression
test exercising the real cross-task boundary. Reset OTel global
tracer provider state in test finally blocks via the SDK's private
Once primitive so cross-suite runs no longer leak the global
provider into subsequent tests.
* docs: LLM payload + GenAI semconv release notes
CHANGELOG [Unreleased] entry describing the eight friction-roundup
items shipped against spec v0.17.0. README adds a sibling pitch
bullet under the existing "doesn't double-export" framing covering
the dual openarmature.llm.* + gen_ai.* attribute story and the
default-off / privacy posture on payload emission.
Concepts/observability page gains seven new subsections under the
existing OpenTelemetry coverage: the LLM provider span, the
default-off payload attributes with truncation + image-redaction
subsections, the Resource constructor knob, multi-processor fan-out,
attribute_enrichers, the public LlmEventPayload / LLM_NAMESPACE
contract, and BatchSpanProcessor flush behaviour under fast
teardown.
Model-providers/authoring page expands the "Observability spans"
bullet from one-line claim to a runnable dispatch sketch that
third-party Provider authors can copy directly.
* examples: surface prompt context + service.name on OTel spans
Example 03 (observer-hooks) gains a Resource carrying service.name
so its OTel spans match the shape every production backend expects.
Comment expanded to mention the auto-emitted gen_ai.* attributes now
surfacing on openarmature.llm.complete spans.
Example 07 (multimodal-prompt) gets the OTelObserver wiring its
docstring has been claiming all along — the example's headline
teach was that with_active_prompt_group plus with_active_prompt
stamps openarmature.prompt.* attributes on LLM-call spans, but
without an attached observer the propagation was unobservable. The
console exporter now prints those spans so the prompt-context story
is end-to-end visible. The cross-task ContextVar fix makes this
work for real (previously the worker task's stale Context snapshot
silently dropped both attribute families).
Per-example docs page and the examples index updated for the new
--all-extras requirement on demo 07.
* fix: address PR #61 review threads
- Drop the speculative _LlmEventState backwards-compat alias and
the two test-side imports + constructor sites that referenced it
(no real downstream consumer to protect). CodeQL's unused-global
warnings clear as a side-effect.
- Move LLM_NAMESPACE from otel/observer.py to llm_event.py so the
core openarmature.observability package no longer pulls the OTel
backend (and opentelemetry-sdk) into its import chain. Users
without the [otel] extra can now import LLM_NAMESPACE /
LlmEventPayload cleanly.
- Reconcile the stale "subclasses State" header comment on
llm_event.py with the actual BaseModel-based implementation.
- Widen attribute_enrichers' type to
Sequence[Callable[[Span, NodeEvent | None], None]] to match how
_run_enrichers calls it; drop the cast("Any", event) workaround.
- Add try/finally + await provider.aclose() to the new #3
regression test so its httpx.AsyncClient doesn't leak.
- Collapse the vestigial if/isinstance/else branch in the payload-
fixture driver to one append.
729 passed, pyright + ruff clean.1 parent 9ab4be6 commit 052b839
22 files changed
Lines changed: 1862 additions & 165 deletions
File tree
- docs
- concepts
- examples
- model-providers
- examples
- 03-observer-hooks
- 07-multimodal-prompt
- src/openarmature
- llm
- providers
- observability
- otel
- tests
- conformance
- harness
- unit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
7 | 40 | | |
8 | 41 | | |
9 | 42 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
56 | 59 | | |
57 | 60 | | |
58 | 61 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
333 | 333 | | |
334 | 334 | | |
335 | 335 | | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
0 commit comments