From f015630affc691f40fad6fb78c31c75cc951d5a3 Mon Sep 17 00:00:00 2001 From: chris-colinsky Date: Fri, 17 Jul 2026 19:20:13 -0700 Subject: [PATCH] Prepare v0.16.0: changelog and version bump Add the retrieval-provider Added section and the pin-advance Changed entry to the v0.16.0 changelog, and bump the package version 0.15.0 to 0.16.0 across pyproject, __init__, the smoke-test assertion, uv.lock, and the regenerated bundled AGENTS.md. The spec pin stays at v0.88.0. Docs and a retrieval example still to land before tagging. --- CHANGELOG.md | 12 ++++++++++++ pyproject.toml | 2 +- src/openarmature/AGENTS.md | 2 +- src/openarmature/__init__.py | 2 +- tests/test_smoke.py | 2 +- uv.lock | 2 +- 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07001d05..b3c205a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,18 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The ## [Unreleased] +### Added + +- **Retrieval-provider capability: embeddings** (proposal 0059, retrieval-provider §3 / §4 + observability §5.5.8 / §8.4.5). A new capability alongside llm-provider and prompt-management. The `EmbeddingProvider` protocol (`embed(input, *, config)` over an arbitrary-length input list, returning one vector per input in input order) plus its `EmbeddingResponse` / `EmbeddingUsage` / `EmbeddingRuntimeConfig` types, and `OpenAIEmbeddingProvider` as the reference provider (`POST {base_url}/v1/embeddings`, index-keyed input-order mapping, `dimensions` / `input_type`, base_url override for any OpenAI-compatible backend). Provider calls dispatch typed `EmbeddingEvent` / `EmbeddingFailedEvent` (graph-engine §6), which the bundled observers render: the OTel observer emits an `openarmature.embedding.complete` span, and the Langfuse observer a dedicated Embedding observation. In v0.15.0 proposal 0059 rode as `not-yet` (only its cross-spec `disable_provider_payload` flag rename was adopted); the capability itself lands here. Conformance fixtures for the embed mapping and the embedding observability (074-083, 137) run in `test_observability` and the retrieval-provider suite. +- **Retrieval-provider capability: rerank** (proposal 0060, retrieval-provider §5 / §6 + observability §5.5.13 / §8.4.7, spec v0.70.0). The `RerankProvider` protocol (`rerank(query, documents, *, config)` returning results ranked by relevance) plus its `RerankResponse` / `RerankUsage` / `ScoredDocument` / `RerankRuntimeConfig` types, and `CohereRerankProvider` as the reference reranker (`POST {base_url}/v2/rerank`, response-only echo shape, `top_n`, `search_units` usage). Provider calls dispatch typed `RerankEvent` / `RerankFailedEvent`; the OTel observer emits an `openarmature.rerank.complete` span and the Langfuse observer a dedicated Retriever observation (`asType="retriever"`, via a new `retriever()` client surface, with `LangfuseUsage.search_units`). The rerank result's output surface (`RerankEvent.output_results` / `EmbeddingEvent.output_vectors`) follows proposal 0089's typed-event output-shape rule (scalar lineage; spec v0.84.0). Rode as `not-yet` in v0.15.0; lands here. Conformance fixtures 099-108, 138, 141, 142 run in `test_observability`, plus the rerank retrieval-provider fixtures. +- **Vendor §8 wire mappings for four providers** (proposals 0077 / 0078 / 0079 / 0090 / 0091, retrieval-provider §8). Concrete, live-tested wire mappings realizing the embed and rerank protocols against real vendor APIs: **TEI** (§8.1, spec v0.72.0) `TeiEmbeddingProvider` + `TeiRerankProvider` (bare-array `/embed`, cross-encoder `/rerank` with client-side chunk-and-stitch, `input_type` via `prompt_name` or a client-side prefix); **Jina** (§8.2, spec v0.73.0) `JinaEmbeddingProvider` + `JinaRerankProvider` (`input_type` realized as Jina's native `task` over a closed set, 429 to rate_limit, 422 to invalid_request); **OpenAI** (§8.3, spec v0.74.0) formalized over `OpenAIEmbeddingProvider` (base_url defaults to `https://api.openai.com`, `dimensions` to the wire, `input_type` as a client-side prefix that is a wire no-op on the symmetric OpenAI surface); **Cohere** (§8.4) `CohereRerankProvider` rerank (spec v0.85.0) and a from-scratch `CohereEmbeddingProvider` `/v2/embed` (spec v0.86.0, mandatory `input_type`, `dimensions` to `output_dimension`, base_url defaults to `https://api.cohere.com`). Introduces the shared wire-mapping primitives in `retrieval/_wire.py` (endpoint normalization, the client-side `input_type` prefix, the rerank document echo, batch chunking) and a general wire-capture conformance harness (request method / path / origin / body-key-set / headers assertions). The rerank document echo follows proposal 0097's §6 shape rule (string verbatim including `""`, `TextDoc` unwrap, a non-object scalar raises `provider_invalid_response`), and `RerankResponse.raw` / `EmbeddingResponse.raw` carry the provider body verbatim as a `dict | list` (proposal 0096). Each mapping is live-tested against its real endpoint. +- **Embedding batch chunking** (proposal 0092, retrieval-provider §8, spec v0.87.0). A general rule so `embed()` accepts an arbitrary-length input list against a capped wire: the mapping splits into consecutive `<= cap` slices preserving order, issues one request per slice with every non-input field identical, concatenates the per-chunk vectors in input order, combines usage all-or-nothing (sum when every chunk reports one, else `null`), and takes the response identity from the first chunk. The shared `chunk_and_stitch_embed` helper in `retrieval/_wire.py` realizes it mapping-agnostically; TEI `/embed` (its `max-client-batch-size`), Cohere `/v2/embed` (a fixed 96) and OpenAI `/v1/embeddings` (a fixed 2048) all chunk through it. Fixture 038 (TEI) plus the Cohere and OpenAI unit tests pin the over-cap behavior. +- **Nullable provider usage records** (proposal 0093, retrieval-provider §4 / §6 + observability §5.5.8 / §8.4.5, spec v0.88.0). `EmbeddingResponse.usage` and `RerankResponse.usage` are `record | null` (a usage record when the provider reports one, `null` when it does not), giving one uniform "no usage reported" model across both response types and the typed events. A mapping must not fabricate a record (no empty record, no zero, no client-side estimate); a reported zero is a real record carrying 0, an absent or malformed figure is `null`, and a corrupt-but-present figure logs a warning. The bundled observers emit the embedding usage conditionally (OTel `gen_ai.usage.input_tokens` and Langfuse `usageDetails.input` omitted when no record is reported). Conformance fixtures 139 / 140 (embedding no-usage) join 141 / 142 (rerank no-usage). + +### Changed + +- **Pinned spec advances v0.70.1 → v0.88.0** across the v0.16.0 cycle. The retrieval-provider capability proposals are implemented: v0.72.0 (0077, TEI wire), v0.73.0 (0078, Jina wire), v0.74.0 (0079, OpenAI-compatible embed wire), v0.84.0 (0089, typed-event output surface), v0.85.0 (0090, Cohere rerank wire), v0.86.0 (0091, Cohere embed wire), v0.87.0 (0092, embed batch chunking), and v0.88.0 (0093, nullable usage records), all recorded `implemented` in `conformance.toml`, alongside 0059 / 0060 (embedding + rerank capability, within the prior pin, flipped from `not-yet` to `implemented` this cycle). The cross-cutting engine / observability proposals in the same range mostly ride as `not-yet`, deferred to v0.17.0: v0.71.0 (0062, LLM completion streaming), v0.75.0 (0080), v0.77.0 / v0.78.0 (0082), v0.81.0 (0084), v0.82.0 (0087), and v0.83.0 (0088). Two differ: v0.76.0 (0081) is `textual-only` (a spec-text change with no python-observable behavior), and v0.80.0 (0085) is `partial`: its save-side fan-out-instance checkpoint keying shipped (the nested-fan-out concurrency fix in Fixed below), with the resume round-trip deferred. Interleaved patches carry clarifications or coverage for already-shipped behavior (v0.73.1, v0.74.1, v0.76.1, v0.79.0). Proposals 0096 (raw is `dict | list`) and 0097 (rerank document-echo shape) were adopted in code ahead of their pin; their conformance formalization rides the later pin bump. No further submodule pin bump ships in this release (0094 and 0099 ride v0.17.0). + ### Fixed - **OTel: an orphaned LLM span inside a fan-out instance now parents under the per-instance dispatch span** (observability §5.5). An LLM provider span whose calling node has no open span (for example a provider call originating from middleware or a wrapper) and which fires inside a fan-out instance now parents under the per-instance fan-out dispatch span, matching the Langfuse observer, instead of falling through to the subgraph or invocation span. This resolves a divergence between the two observers. The generalized nearest-open-ancestor fallback (nested instances at any depth, and the instance-vs-deeper-subgraph ordering) is pending a spec clause and fixture; this aligns the top-level instance case now. diff --git a/pyproject.toml b/pyproject.toml index 57538934..40dc7de3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ build-backend = "hatchling.build" [project] name = "openarmature" -version = "0.15.0" +version = "0.16.0" description = "Workflow framework for LLM pipelines and tool-calling agents." readme = "README.md" requires-python = ">=3.12" diff --git a/src/openarmature/AGENTS.md b/src/openarmature/AGENTS.md index fede9a92..05cea805 100644 --- a/src/openarmature/AGENTS.md +++ b/src/openarmature/AGENTS.md @@ -1,6 +1,6 @@ # OpenArmature — Agent documentation -*This is the agent guide bundled with the openarmature Python package, version 0.15.0 (spec v0.88.0). For the full docs site see [openarmature.ai](https://openarmature.ai). For the canonical spec text see [openarmature.org/capabilities](https://openarmature.org/capabilities/). For project-specific conventions for the code you're editing, see the host project's `AGENTS.md` or `CLAUDE.md`.* +*This is the agent guide bundled with the openarmature Python package, version 0.16.0 (spec v0.88.0). For the full docs site see [openarmature.ai](https://openarmature.ai). For the canonical spec text see [openarmature.org/capabilities](https://openarmature.org/capabilities/). For project-specific conventions for the code you're editing, see the host project's `AGENTS.md` or `CLAUDE.md`.* ## TL;DR diff --git a/src/openarmature/__init__.py b/src/openarmature/__init__.py index a0470f86..1dfe7238 100644 --- a/src/openarmature/__init__.py +++ b/src/openarmature/__init__.py @@ -24,7 +24,7 @@ sessions opening the project find the bundled docs automatically. """ -__version__ = "0.15.0" +__version__ = "0.16.0" __spec_version__ = "0.88.0" # Proposal 0052 (spec observability §5.1 / §8.4.1): canonical # package-registry name for this implementation. Surfaces on every diff --git a/tests/test_smoke.py b/tests/test_smoke.py index 0d7a42e3..d0b46a26 100644 --- a/tests/test_smoke.py +++ b/tests/test_smoke.py @@ -8,7 +8,7 @@ def test_package_versions() -> None: - assert openarmature.__version__ == "0.15.0" + assert openarmature.__version__ == "0.16.0" assert openarmature.__spec_version__ == "0.88.0" diff --git a/uv.lock b/uv.lock index 87737881..2caf62ca 100644 --- a/uv.lock +++ b/uv.lock @@ -925,7 +925,7 @@ wheels = [ [[package]] name = "openarmature" -version = "0.15.0" +version = "0.16.0" source = { editable = "." } dependencies = [ { name = "httpx" },