Documentation
¶
Overview ¶
Package minigraph is a minimal LangGraph for Go: a state machine of nodes that transform a shared, typed state, wired with static or conditional edges. Build a Graph, Compile it, then Invoke or Stream.
Index ¶
- Constants
- Variables
- type App
- func (r *App[S]) Invoke(ctx context.Context, state S) (S, error)
- func (r *App[S]) InvokeFrom(ctx context.Context, from Step[S]) (S, error)
- func (r *App[S]) InvokeThread(ctx context.Context, saver Checkpointer[S], thread string, initial S) (S, error)
- func (r *App[S]) Stream(ctx context.Context, state S) iter.Seq2[Step[S], error]
- func (r *App[S]) StreamFrom(ctx context.Context, from Step[S]) iter.Seq2[Step[S], error]
- func (r *App[S]) StreamThread(ctx context.Context, saver Checkpointer[S], thread string, initial S) iter.Seq2[Step[S], error]
- type Checkpointer
- type Graph
- type Interrupt
- type MemorySaver
- type Node
- type Router
- type Step
Constants ¶
const ( Start = "__start__" End = "__end__" )
Start and End are the reserved endpoints of every run: wire Start to your entry node, and route to End to finish.
Variables ¶
var ErrMaxSteps = errors.New("minigraph: max steps exceeded")
ErrMaxSteps is returned when a run exceeds App.MaxSteps node executions — usually a cycle that never routes to End.
Functions ¶
This section is empty.
Types ¶
type App ¶
type App[S any] struct { // MaxSteps caps node executions per run, catching endless cycles. // Compile sets it to 25; override freely. MaxSteps int // contains filtered or unexported fields }
App is a compiled, immutable graph. Safe for concurrent use.
func (*App[S]) Invoke ¶
Invoke runs the graph to completion and returns the final state. On error it returns the last state a node produced successfully.
func (*App[S]) InvokeFrom ¶
InvokeFrom runs the graph to completion from a previously yielded Step.
func (*App[S]) InvokeThread ¶
func (r *App[S]) InvokeThread(ctx context.Context, saver Checkpointer[S], thread string, initial S) (S, error)
InvokeThread runs a thread to completion (or its next Interrupt) and returns the final state. Calling it again on a finished thread is a no-op that returns the same final state. To answer an Interrupt, edit the returned state, Save it under the interrupted node, and call InvokeThread again:
saver.Save(ctx, thread, Step[S]{Node: intr.Node, State: edited})
func (*App[S]) Stream ¶
Stream runs the graph from Start, yielding after every node. An error arrives as the final pair, with the Step beside it carrying the last completed node and last good state — so resuming an error Step retries the step that failed. Breaking out of the loop stops the run.
func (*App[S]) StreamFrom ¶
StreamFrom continues a run from a previously yielded Step: routing restarts from from.Node with from.State, so the checkpointed node is not re-executed. MaxSteps counts from zero again.
func (*App[S]) StreamThread ¶
func (r *App[S]) StreamThread(ctx context.Context, saver Checkpointer[S], thread string, initial S) iter.Seq2[Step[S], error]
StreamThread is Stream with durability. If the thread has a saved Step the run resumes from it and initial is ignored; otherwise the run starts fresh. Every successful Step is saved before it is yielded, and an Interrupt's Step is saved too — so a process can die at any point and the thread continues where it left off. Ordinary node errors are not saved: rerunning the thread retries from the last good Step.
type Checkpointer ¶
type Checkpointer[S any] interface { Save(ctx context.Context, thread string, step Step[S]) error Load(ctx context.Context, thread string) (Step[S], bool, error) }
Checkpointer persists the latest Step of each thread, making runs durable: a run that crashed, was interrupted, or was broken out of continues from its last saved Step. Implementations should serialize S (e.g. JSON) when storing outside process memory.
type Graph ¶
type Graph[S any] struct { // contains filtered or unexported fields }
Graph is a mutable builder. Add nodes and edges, then Compile. Building mistakes accumulate silently and are all reported by Compile.
func (*Graph[S]) AddEdge ¶
AddEdge wires from → to unconditionally. Every node has exactly one outgoing edge; from may be Start, to may be End.
func (*Graph[S]) AddNode ¶
AddNode registers fn under name. Names must be unique and not Start or End.
type Interrupt ¶
type Interrupt struct {
Payload any // what the node wants to tell whoever resumes the run
Node string // set by the engine: the node that paused
}
Interrupt pauses a run for outside input — human approval, missing data, anything the graph can't decide alone. Return one from a node:
return s, &Interrupt{Payload: "ok to send this email?"}
Unlike an ordinary error, the state returned alongside an Interrupt is kept: the run yields it as the final Step, which is the checkpoint to continue from once the outside world has answered (usually after editing the state):
var intr *Interrupt
if errors.As(err, &intr) {
state.Approved = true
final, err = app.InvokeFrom(ctx, Step[S]{Node: intr.Node, State: state})
}
InvokeFrom routes onward from the interrupted node; the node itself does not re-run. Inside Parallel branches an Interrupt cannot pause the run and is treated as a plain error.
type MemorySaver ¶
type MemorySaver[S any] struct { // contains filtered or unexported fields }
MemorySaver is an in-process Checkpointer, good for tests and single-run durability (interrupt/resume). The zero value is ready to use. Steps are stored by value: reference fields inside S still point at shared data.
type Node ¶
Node transforms the state: it receives the current state and returns the next one.
func Parallel ¶
func Parallel[S any](merge func(ctx context.Context, base S, results []S) (S, error), branches ...Node[S]) Node[S]
Parallel composes branches into a single Node: every branch runs concurrently on the same starting state, then merge folds the results — ordered like the branches — into the next state. It is fan-out/join as a combinator: the graph stays sequential and this counts as one step.
Because a App's Invoke has a Node's signature, branches can be whole compiled subgraphs: Parallel(merge, subA.Invoke, subB.Invoke).
Branches receive shallow copies of the state, so reference fields (slices, maps, pointers) are shared: treat them as read-only inside a branch and put new data in the branch's own copy for merge to reconcile. The first branch error cancels the siblings and fails the node; an Interrupt inside a branch is treated as a plain error.
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
agent
command
Command agent shows the classic LangGraph shape — an agent that keeps calling tools until it can answer — as a minigraph over a typed state.
|
Command agent shows the classic LangGraph shape — an agent that keeps calling tools until it can answer — as a minigraph over a typed state. |
|
approval
command
Command approval shows human-in-the-loop with interrupts and a durable thread: an agent drafts an email, pauses for approval, incorporates rejection feedback, and only sends once a human says yes.
|
Command approval shows human-in-the-loop with interrupts and a durable thread: an agent drafts an email, pauses for approval, incorporates rejection feedback, and only sends once a human says yes. |
|
fanout
command
Command fanout shows parallel fan-out/join: three researchers run concurrently as one graph step via Parallel, a merge folds their findings, and a writer summarizes.
|
Command fanout shows parallel fan-out/join: three researchers run concurrently as one graph step via Parallel, a merge folds their findings, and a writer summarizes. |
|
react
command
Command react runs a ReAct (Reason + Act) agent on minigraph.
|
Command react runs a ReAct (Reason + Act) agent on minigraph. |