Releases: LunarCommand/openarmature-python
v0.3.0
Spec v0.2 / proposal 0002: explicit subgraph input/output mapping.
ExplicitMapping(inputs=..., outputs=...)projection strategy as a built-in alternative to writing a customProjectionStrategy.- New
mapping_references_undeclared_fieldcompile error category forinputs/outputsthat name fields absent from the relevant schema. ProjectionStrategy.validateis an optional duck-typed compile hook — declarative strategies (ExplicitMapping) expose it; imperative custom projections aren't forced to write a no-op.- Spec submodule pinned at v0.2.0.
See the proposal for design rationale.
v0.2.0
API ergonomics release. Two improvements landed:
- Method renames — the two "non-default" builder methods now name themselves explicitly at the call site.
- Generics —
GraphBuilderandCompiledGraphcarry the concreteStatesubclass through at type-check time, socast(MyState, ...)is no longer needed oninvoke()returns or projection arguments.
No spec-behavior changes; conformance fixtures continue to pass. Targets openarmature-spec v0.1.1.
Breaking changes
```diff
-builder.add_subgraph("research", research_subgraph, projection=MyProjection())
+builder.add_subgraph_node("research", research_subgraph, projection=MyProjection())
-builder.add_conditional("classify", route_fn)
+builder.add_conditional_edge("classify", route_fn)
```
Rationale: align names with what they add. `add_subgraph_node` pairs with `add_node` as the non-default node variant; `add_conditional_edge` pairs with `add_edge` as the non-default edge variant.
What's new: generic state typing (PEP 695)
`GraphBuilder`, `CompiledGraph`, `Node`, `FunctionNode`, `ConditionalEdge`, `SubgraphNode`, and `ProjectionStrategy` are all parameterized on a `StateT`-bound TypeVar.
```python
graph: CompiledGraph[MyState] = (
GraphBuilder(MyState)
.add_node("step", my_node)
.add_edge("step", END)
.set_entry("step")
.compile()
)
final = await graph.invoke(MyState(topic="..."))
final is typed MyState — field access works without cast()
print(final.topic)
```
Custom projections type their signatures directly:
```python
class MyProjection:
def project_in(
self,
parent_state: MyParentState,
subgraph_state_cls: type[MyChildState],
) -> MyChildState:
return subgraph_state_cls(topic=parent_state.topic)
```
Protocol is structural — no inheritance required.
See also
- Demo projects: openarmature-examples — `01-linear-pipeline` (minimal graph) and `02-routing-and-subgraphs` (conditional routing + subgraph + custom projection)
- Merged: #2 (renames), #3 (generics)
v0.1.0
Initial graph engine implementation. Targets openarmature-spec v0.1.1.
Included
- Typed `State` schema (frozen, strict) with per-field reducers (`last_write_wins`, `append`, `merge`)
- Static and conditional edges; `END` sentinel
- Subgraphs via `add_subgraph` with pluggable `ProjectionStrategy` (default: `FieldNameMatching`)
- Compile-time structural validation: `NoDeclaredEntry`, `UnreachableNode`, `DanglingEdge`, `MultipleOutgoingEdges`, `ConflictingReducers`
- Runtime error categories: `NodeException`, `EdgeException`, `ReducerError`, `RoutingError`, `StateValidationError` (all but the last carry `recoverable_state`)
- Spec conformance fixtures 001–010 passing
Note
Tag backfilled after v0.2.0 for version-history symmetry with openarmature-spec. No one was consuming v0.1.0 at the time; see v0.2.0 for the first release intended for external pinning.