You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add per-attempt LLM spans under call-level retry (0050) (#170)
* Add LlmRetryAttemptEvent for per-attempt LLM spans (0050)
* Emit per-attempt LlmRetryAttemptEvent from complete() (0050)
* Render per-attempt LLM spans from LlmRetryAttemptEvent (0050)
* Activate obs-057 (single-attempt llm.attempt_index) (0050)
* Add N-span call-level-retry integration test (0050)
* Activate call-level-retry per-attempt span fixtures (0050)
* Document per-attempt LLM spans and flip 0050
Flip conformance.toml [proposals."0050"] partial -> implemented
(since 0.15.0): the call-level-retry per-attempt span surface now
ships.
Document the openarmature.llm.attempt_index attribute and the
per-attempt span behavior in the observability concepts page, plus
notes that span enrichers receive LlmRetryAttemptEvent on the LLM
span and that the bundled provider dispatches that internal event
alongside the unchanged terminal events.
Add the 0.15.0 changelog section covering this work and backfilling
the 0061 detached-trace invocation span (which landed without an
entry), plus the v0.60.0 -> v0.61.0 spec-pin bullet.
* Deduplicate per-attempt LLM event builder
_build_llm_retry_attempt_event constructed a full LlmRetryAttemptEvent
twice, repeating ~18 shared identity, scoping, and request-side fields
across the success and failure branches. Hoist them into one base dict
and splat it, leaving each branch to add only its outcome fields. No
behavior change.
* Test OTel observer ignores terminal LLM events
The OTel observer now renders the LLM span solely from the per-attempt
LlmRetryAttemptEvent; terminal LlmCompletionEvent / LlmFailedEvent are
ignored. Add a regression test feeding both terminal events and
asserting zero openarmature.llm.complete spans, guarding against
reintroducing the terminal-event span path.
Also fix a stale docstring in _drive_llm_span_with_cached_tokens that
still referenced "typed LlmCompletionEvent".
* Re-export LlmRetryAttemptEvent; isinstance filter
PR #170 CoPilot review:
- Re-export LlmRetryAttemptEvent from the openarmature.graph package
(import block + __all__), matching the sibling LlmCompletionEvent /
LlmFailedEvent so the documented observer import path works.
- Replace the brittle type(event).__name__ name match with an
isinstance check in the conformance _TypedEventCollector; the
filter_event_type string comparison stays as-is.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+11Lines changed: 11 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,17 @@ All notable changes to `openarmature-python` are documented in this file.
4
4
5
5
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The package follows [Semantic Versioning](https://semver.org/); pre-1.0 minor bumps may carry behavioral changes per [spec governance](https://github.com/LunarCommand/openarmature-spec/blob/main/GOVERNANCE.md).
6
6
7
+
## [0.15.0] — 2026-06-18
8
+
9
+
### Added
10
+
11
+
-**Detached-trace invocation span** (proposal 0061, observability §4.4, spec v0.61.0). The OTel observer now synthesizes an `openarmature.invocation` span at the root of each detached trace (a detached subgraph and each detached fan-out instance), carrying the parent's shared `invocation_id` (detached mode is observer-side trace rendering, not a new run) and the detached unit's own `entry_node`; the detached subgraph / instance span nests under it. A raising detached subgraph surfaces ERROR plus the error category and an OTel exception event on both the parent dispatch span and the detached invocation span. This is observer-side only, with no graph-engine change; the Langfuse observer is unchanged (its Trace entity already plays the invocation-level-container role). Conformance fixtures 008 (rewritten) and 058 (newly wired) run in `test_observability`.
12
+
- **Per-attempt LLM spans under call-level retry** (proposal 0050, observability §5.5 / llm-provider §7.1). Completes proposal 0050, which shipped `partial` in v0.14.0 (failure-isolation middleware and the `complete(retry=...)` loop landed then; the per-attempt span surface was deferred). Under call-level retry the OTel observer now emits one `openarmature.llm.complete` span per attempt, each carrying `openarmature.llm.attempt_index` (0-based, 0..N-1, and 0 for a no-retry call). An intermediate failed attempt's span carries ERROR status plus its error category and the request-side attributes; the final attempt's span carries the terminal outcome and, on success, the full response surface. A python-internal `LlmRetryAttemptEvent`, dispatched once per attempt, is the sole source of the OTel span; the terminal `LlmCompletionEvent` / `LlmFailedEvent` stay one per call (payload, latency, Langfuse Generation) and no longer drive the OTel span. Langfuse renders one terminal Generation per call, with the per-attempt detail on the OTel span surface only (a spec-side §8 clarification to pin this is tracked, non-blocking). `conformance.toml` flips proposal 0050 to `implemented`; the call-level fixtures 056-058 are driven through the provider plus OTel observer and the single-attempt observability fixture 057 is wired.
13
+
14
+
### Changed
15
+
16
+
-**Pinned spec advances v0.60.0 → v0.61.0** (proposal 0061, the detached-trace invocation span above). A single step this cycle; `conformance.toml` records proposal 0061 as `implemented`. Proposal 0050 needed no pin bump of its own (it was already within the pin from its v0.42.0 acceptance); its v0.14.0 `partial` entry flips to `implemented` with the per-attempt span surface above.
0 commit comments