v0.7.0
Release
- Fix package-scoped Hex publishing pipeline and cut the first published release (no library API changes since v0.6.0)
v0.6.0
Engine hardening
- Node exceptions surface as
{:error, %LangEx.NodeError{node: ..., reason: ...}}instead of raising out ofinvoke/3/stream/3; the original exception and failing node are preserved (breaking: callers matching on raises must match on the error tuple) - Checkpoint format v2:
next_nodesand pending-interrupt entries persist full work items, so%LangEx.Send{}payloads survive crash-continue and interrupt-resume (v1 checkpoints still load) - Completed parallel siblings keep their routing across an interrupt: their resolved next targets (and any deferred fan-in backlog) are recorded in the interrupt checkpoint and scheduled on resume
- A Send target that interrupts pauses with the shared graph state (its payload no longer overwrites the checkpointed state) and resumes with its payload intact
:node_timeoutapplies to single-node super-steps (previously parallel super-steps only); timeouts raiseLangEx.NodeTimeoutErrorper attemptdurability: :exitwrites a final checkpoint on completion and persists the failed super-step on error, soget_state/2stays truthful and an empty re-invoke can retry the failure- Parallel super-steps emit
node_start/node_endstream events (previously single-node super-steps only) - Dynamic resume answers survive static breakpoints:
resume_valuespersist through breakpoint checkpoints, and the resumed super-step bypasses breakpoints that already fired
Validation
add_node/4rejects duplicate and reserved (:__start__/:__end__) names, and validates option values;:cachecannot combine with:on_erroradd_edge/3rejects edges from:__end__;add_conditional_edges/4rejects a second routing function for the same sourcecompile/2validatesinterrupt_before/interrupt_afternode names- Routing to an undefined node (Command goto / Send) raises a descriptive
ArgumentErrornaming the known nodes
Persistence
- New
LangEx.Checkpointer.Memory— built-in ETS backend for development and tests - Postgres checkpointer stores
next_nodes/pending_interruptsas proper jsonb payloads (previously unusable due to an array/jsonb type mismatch) and breakscreated_atordering ties by step and checkpoint id - Subgraphs with their own checkpointer resume interrupts from their
namespaced checkpoint instead of re-running from
:__start__ LangEx.Interrupt.interrupt/1raises a clear error when called outside a graph node process (e.g. from tool functions)
Streaming
- Stream modes:
modes: [:updates, :values, :messages, :custom]onLangEx.stream/3 - Token deltas from streaming LLM adapters surface as
{:message_delta, ...}events (:on_tokencallback on the Anthropic adapter) LangEx.Graph.Stream.emit/1to publish custom events from inside nodesstream/3accepts%Command{resume: ...}and crash-continue (%{}) inputs- Interrupts are emitted as
{:interrupt, payload}stream events
Execution policies
- Per-node options on
Graph.add_node/4:retry:(capped exponential backoff with jitter andretryable?— seeLangEx.Graph.RetryPolicy;backoff_msaccepted as a legacy alias forinitial_interval_ms),cache:(ETS memoization with TTL),defer:(fan-in barrier),timeout:(per-attempt budget, retryable),on_error:(fallback handler after retries are exhausted; its return value becomes the node result) - Node cache verifies the stored input on lookup (hash collisions miss
instead of serving wrong results), deletes expired entries on read, and is
size-bounded via the
:node_cache_max_entriesapplication env ChatModel.node(resilient: ...)routes calls throughLLM.Resilient:durabilityinvoke option::sync|:async|:exitcheckpoint writes
Prebuilts
LangEx.Prebuilt.agent/1— one-call tool-loop agent with system prompt, usage accounting, and context compaction wired in
Long-term memory
LangEx.Storebehaviour with ETS and Postgres backends; attach withGraph.compile(store: ...); reachable in nodes and tools viaLangEx.Store.get/put/delete/search- Migration V2 (
lang_ex_storetable + checkpointversioncolumn)
Checkpointer operations
delete_thread/1on the behaviour, both backends, and the facade (LangEx.delete_thread/2)Checkpointer.Postgres.prune/2retention window (older_than:)- Checkpoint format
versionfield persisted with every checkpoint - Redis backend surfaces errors instead of swallowing them into
[]/:none
Graphs
- Compile-time validation of conditional-edge mapping targets; warning for
unreachable nodes (
warn_unreachable: falseto silence) Graph.to_mermaid/1flowchart export%Command{goto: {:parent, target}}routes the parent graph from inside a subgraph (bubbles one level per graph boundary)- A schema-declared
:remaining_stepskey is no longer overwritten by the managed value
v0.5.0
- Durable execution: crashed runs resume from checkpointed pending nodes
- Lossless checkpoint serialization (
LangEx.Checkpoint.Serializer) - State APIs:
get_state/2,get_state_history/2,update_state/3,parent_idlineage, load bycheckpoint_id - Interrupts v2: stable IDs, multiple interrupts per node, id-addressed
resume maps, static breakpoints (
interrupt_before/interrupt_after), parallel-step interrupt safety - Subgraph propagation: interrupts, errors, context, stream events, and namespaced checkpoint config flow through compiled-graph nodes
- Run-tree telemetry (
run_id/parent_run_id), named graphs, and an optional OpenTelemetry bridge - Token usage accounting in
ChatModel(chat_with_usage,merge_usage/2) - Bounded concurrency:
max_concurrency/node_timeoutinvoke options andTool.Nodemax_concurrency/timeout - Streaming rework: supervised runner, no inactivity halt, crash surfacing
- Send fan-out results merge through reducers and follow target edges
v0.1.0
Initial release.
- StateGraph builder with nodes, edges, conditional routing, and
add_sequence - Pregel super-step execution engine with parallel node execution via
Task.Supervisor - State reducers (per-key merge functions)
- Command routing (combined state update + control flow)
- Checkpointing (Redis via Redix, PostgreSQL via Ecto)
- Oban-style versioned Postgres migrations (
LangEx.Migration) - Interrupts / human-in-the-loop (
LangEx.Interrupt) - Streaming (
LangEx.StreamviaStream.resource) - Runtime context injection (arity-2 node functions)
- Subgraph support (compiled graphs as nodes)
- Send fan-out for dynamic map-reduce patterns
- Managed values (
remaining_steps) - ChatModels registry with model-string auto-resolution
- Built-in LLM adapters: OpenAI, Anthropic
- MessagesState convenience schema
- Message types: Human, AI, System, Tool