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
* Bump spec conformance pin to v0.107.0
Advance the openarmature-spec submodule pin from v0.88.0 to v0.107.0,
absorbing proposals 0094-0113 into the v0.17.0 release. This is a
mechanical bump: the four sync points (pyproject spec_version, package
__spec_version__, conformance.toml spec_pin, the submodule CHANGELOG)
plus the test_smoke assertion move together, and AGENTS.md regenerates.
No src behavior changes.
Moving the pin surfaces the band's conformance fixtures, whose behavior
shipped and is unit-tested ahead of the pin but whose harness wiring is
not yet in place. All 67 are deferred with categorized reasons, keeping
the suite green; the fixture wiring lands in a follow-up PR before the
release tag.
Manifest notes: 0096, 0097, and 0100 are since 0.16.0 (shipped with the
v0.16.0 retrieval work); 0098, 0102, and 0107 are textual-only
(conformance-adapter directives with no shipped-module component); 0113
is partial (the general merge-arm malformed handling is not yet built).
* Clarify retrieval fixture-deferral comments
Two review-driven comment refinements in test_retrieval_provider.py, no
behavior change:
- Reconcile the header comment above _DEFERRED_FIXTURES: it claimed no
retrieval fixtures remain deferred, which the v0.107.0 bump contradicts
by re-deferring 042 / 043 / 052.
- Refine 042's deferral reason to name the actual gap. The chunk-stitch
behavior shipped in v0.16.0 (first-chunk-only response_id nulling, all-
or-nothing usage); 042 fails only on the contains_event matcher, which
compares a record-valued field (usage) against a dict expectation.
From review of PR #259.
Copy file name to clipboardExpand all lines: src/openarmature/AGENTS.md
+69-8Lines changed: 69 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# OpenArmature — Agent documentation
2
2
3
-
*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`.*
3
+
*This is the agent guide bundled with the openarmature Python package, version 0.16.0 (spec v0.107.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`.*
4
4
5
5
## TL;DR
6
6
@@ -10,7 +10,7 @@ OpenArmature is a workflow framework for LLM pipelines and tool-calling agents:
10
10
11
11
## Capability contracts
12
12
13
-
_Sourced from openarmature-spec v0.88.0. Each entry below reproduces §1 (Purpose) and §2 (Concepts) of the capability's `spec.md` verbatim — including additions from accepted proposals that this Python implementation may not yet ship. For per-proposal implementation status (implemented / partial / textual-only / not-yet), see the `conformance.toml` manifest at the repo root. For the full spec text (execution model, error semantics, determinism, observer hooks, etc.) see the linked docs site._
13
+
_Sourced from openarmature-spec v0.107.0. Each entry below reproduces §1 (Purpose) and §2 (Concepts) of the capability's `spec.md` verbatim — including additions from accepted proposals that this Python implementation may not yet ship. For per-proposal implementation status (implemented / partial / textual-only / not-yet), see the `conformance.toml` manifest at the repo root. For the full spec text (execution model, error semantics, determinism, observer hooks, etc.) see the linked docs site._
14
14
15
15
### Capability: `graph-engine`
16
16
@@ -168,13 +168,72 @@ the defaults themselves: projection-in is off by default (so `inputs` turns it o
168
168
projection-out is on by default via field-name matching (so `outputs` replaces it to avoid ambiguous mixed
169
169
rules).
170
170
171
+
**Declared same-name projection boundary.** As a checked alternative between the implicit
172
+
field-name-matching default and the explicit rename maps, a subgraph-as-node MAY declare its boundary as two
173
+
field-name *sets* — an **in-set** and an **out-set** — naming the fields that cross by the *same name* on
174
+
both sides. The *per-entry* semantics of each set match the explicit maps restricted to same-name pairs: an in-set entry
175
+
behaves as an `inputs` entry whose subgraph and parent field names coincide (the parent field's value is
176
+
copied into the same-named subgraph field at entry); an out-set entry behaves as an `outputs` entry whose
177
+
parent and subgraph field names coincide (the subgraph field's final value is merged into the same-named
178
+
parent field via the parent's reducer at exit).
179
+
180
+
Unlike the maps, the declared form is a **complete boundary declaration with no field-name-matching
181
+
fallback** — using it states exactly what crosses:
182
+
183
+
- The in-set fully determines projection-in: subgraph fields not named receive their schema-declared
184
+
defaults; an empty in-set projects nothing in (identical to the no-projection-in default).
185
+
- The out-set fully determines projection-out, replacing field-name matching: subgraph fields not named are
186
+
discarded; an empty out-set projects nothing out. There is no "absent out-set falls back to field-name
187
+
matching" state — a subgraph-as-node that wants field-name matching uses the default (declares no
188
+
boundary). An empty set means "nothing," symmetrically for both directions.
189
+
190
+
Using the declared form governs **both** directions: declaring either set opts the node into the declared
191
+
form, and a set that is *omitted entirely* is treated as empty — nothing crosses in that direction, with no
192
+
fall-back to field-name matching or to the maps' defaults. Declaring `projects_in` alone, for example,
193
+
projects the named fields in and projects **nothing** out (to keep field-name matching on the way out, use
194
+
the default form). This is what distinguishes the declared form from the explicit maps, whose `inputs`-only
195
+
case *does* leave projection-out at the field-name-matching default (below).
196
+
197
+
The declared same-name sets and the explicit `inputs`/`outputs` maps are **mutually exclusive** on a single
198
+
subgraph-as-node: a node declares its projection with at most one of the default (nothing declared), the
199
+
declared same-name sets, or the explicit maps.
200
+
171
201
Compilation MUST fail with category `mapping_references_undeclared_field` if an `inputs` mapping names a
172
202
parent field that is not declared in the parent's state schema, or a subgraph field that is not declared in
173
203
the subgraph's state schema. The same rule applies symmetrically to `outputs`. Implementations SHOULD
174
204
validate at compile time that the types of mapped parent/subgraph field pairs are compatible (per the
175
205
language's type system's notion of compatibility); this is SHOULD rather than MUST because type-system
176
206
expressiveness varies across languages.
177
207
208
+
The same `mapping_references_undeclared_field` rule applies to the declared same-name sets: compilation MUST
209
+
fail if an in-set or out-set names a field not declared on the relevant schema (a same-name field is checked
210
+
on both the parent and the subgraph schema). Declaring both the same-name sets and an explicit
211
+
`inputs`/`outputs` mapping on one subgraph-as-node MUST fail compilation with category
212
+
`conflicting_projection_forms`.
213
+
214
+
**Reducer round-trip warning.** Because projection-out merges through the parent's reducer, a field projected
215
+
*in* and then *back out* into the same parent field re-merges: for a reducer that is not
216
+
*round-trip-idempotent* — one for which re-applying an already-merged value changes the field — the unchanged
217
+
value is merged a second time (e.g. an `append` reducer doubles the list). Of the canonical reducers above,
218
+
`last_write_wins`, `merge`, `merge_by_key`, and `dedupe_append` are round-trip-idempotent (a replace, or a
219
+
keyed / deduplicated / shallow merge re-applied with the same value, is a no-op); `append`, `concat_flatten`,
220
+
`bounded_append`, and `merge_all` are not — `append` / `concat_flatten` / `bounded_append` grow the field on
221
+
re-application, and `merge_all` requires a *list-of-mappings* update (see its definition above), so re-merging
222
+
a single mapping value is ill-typed and raises `reducer_error` rather than a no-op. A projection
223
+
**round-trips** a field when the same parent field is copied into the subgraph and a subgraph field carrying
224
+
it is merged back into that same parent field. This occurs when: (a) in the declared same-name form, a field
225
+
is named in **both** the in-set and the out-set; (b) in the explicit maps, a parent field is both an `inputs`
226
+
value and an `outputs` key mapped to the **same** subgraph field; or (c) with `outputs` absent (projection-out
227
+
left at the field-name-matching default), an `inputs` entry copies a parent field into a **same-named**
228
+
subgraph field, so field-name matching merges it straight back out. Implementations **MUST** emit a compile-time warning
229
+
`projection_reducer_round_trip` (a warning, distinct from the MUST-fail compile-error categories below) when a
230
+
projection round-trips a field into a non-round-trip-idempotent **canonical** reducer, and **SHOULD** emit it
231
+
when the target is a custom reducer the implementation classifies as non-idempotent. The warning is a
232
+
structural heuristic — an implementation cannot statically prove the subgraph left the value unchanged, so it
233
+
MAY fire on a round-trip that legitimately replaces the value — and it changes no runtime behavior
234
+
(projection-out still merges through the parent's reducer). Authors SHOULD route a round-tripped field through
235
+
a replace/idempotent reducer or avoid round-tripping it.
236
+
178
237
**Compiled graph.** The result of compiling a graph definition. A compiled graph is immutable and executable.
179
238
The entry node MUST be declared explicitly by the graph author — there is no implicit "first node added"
180
239
default. Compilation MUST fail with a diagnostic error if the graph has: no declared entry node, unreachable
@@ -189,8 +248,10 @@ identifiers (as an error class, error code, or tagged discriminant, per the lang
189
248
-`dangling_edge` — an edge references a node name that is not declared.
190
249
-`multiple_outgoing_edges` — a node has more than one outgoing edge.
191
250
-`conflicting_reducers` — a state field has more than one declared reducer.
192
-
-`mapping_references_undeclared_field` — a subgraph-as-node `inputs` or `outputs` mapping names a field
193
-
not declared in the relevant state schema.
251
+
-`mapping_references_undeclared_field` — a subgraph-as-node `inputs` or `outputs` mapping, or a declared
252
+
same-name in-set / out-set, names a field not declared in the relevant state schema.
253
+
-`conflicting_projection_forms` — a subgraph-as-node declares both the same-name projection sets and an
254
+
explicit `inputs`/`outputs` mapping (the two are mutually exclusive).
194
255
-`reducer_configuration_invalid` — a reducer factory was supplied invalid construction parameters
195
256
(e.g., `bounded_append(max_len=0)`, `merge_by_key(key=None)`). Raised at field registration / graph
196
257
compilation time, before any node body runs. Distinct from `conflicting_reducers`, which is about
@@ -496,8 +557,8 @@ The substrate is intentionally narrow, matching llm-provider's posture:
496
557
497
558
**Transparency.** Per charter §3.1 principle 8 ("Transparency over abstraction"), the embedding
498
559
abstraction surfaces a normalized shape — `EmbeddingResponse`, `EmbeddingUsage` — without hiding
499
-
what the underlying provider returned. The `EmbeddingResponse.raw` field carries the parsed provider
500
-
response verbatim alongside the normalized fields, and the error categories preserve the underlying
560
+
what the underlying provider returned. The `EmbeddingResponse.raw` field carries the provider
561
+
response verbatim — an objector an array (§4) — alongside the normalized fields, and the error categories preserve the underlying
501
562
provider exception as cause.
502
563
503
564
#### 2. Concepts
@@ -511,7 +572,7 @@ vectors wrapped in an `EmbeddingResponse`. Bound to a specific embedding model i
511
572
instance.
512
573
513
574
**EmbeddingResponse.** The result of an `embed()` call: the vectors, the model identifier, the
514
-
parsed raw response, and — when present — usage information and the provider-returned request
575
+
verbatim provider response (`raw`), and — when present — usage information and the provider-returned request
515
576
identifier.
516
577
517
578
**EmbeddingUsage.** A usage record carrying `input_tokens` only — embedding has no output tokens
@@ -534,7 +595,7 @@ the documents sorted by query-relevance with provider-specific scores. Bound to
534
595
model identifier per instance.
535
596
536
597
**RerankResponse.** The result of a `rerank()` call: the sorted scored documents, the model
537
-
identifier, the parsed raw response, and — when present — usage information and the
598
+
identifier, the verbatim provider response (`raw`), and — when present — usage information and the
538
599
provider-returned response identifier.
539
600
540
601
**RerankUsage.** A usage record with optional `search_units`and optional `input_tokens`, reflecting
0 commit comments