graph-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +50 -0
  3. data/.github/workflows/release.yml +49 -0
  4. data/.gitignore +6 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +126 -0
  7. data/CHANGELOG.md +26 -0
  8. data/CLAUDE.md +128 -0
  9. data/Gemfile +11 -0
  10. data/Gemfile.lock +94 -0
  11. data/LICENSE +21 -0
  12. data/Makefile +114 -0
  13. data/README.md +464 -0
  14. data/Rakefile +15 -0
  15. data/docs/README.md +55 -0
  16. data/docs/api_reference.md +832 -0
  17. data/docs/concepts.md +216 -0
  18. data/docs/edges.md +265 -0
  19. data/docs/error_handling.md +241 -0
  20. data/docs/human_in_the_loop.md +231 -0
  21. data/docs/persistence.md +276 -0
  22. data/docs/quickstart.md +154 -0
  23. data/docs/send_and_command.md +218 -0
  24. data/docs/state.md +181 -0
  25. data/docs/streaming.md +172 -0
  26. data/graph-agent.gemspec +48 -0
  27. data/lib/graph_agent/channels/base_channel.rb +52 -0
  28. data/lib/graph_agent/channels/binary_operator_aggregate.rb +56 -0
  29. data/lib/graph_agent/channels/ephemeral_value.rb +59 -0
  30. data/lib/graph_agent/channels/last_value.rb +49 -0
  31. data/lib/graph_agent/channels/topic.rb +58 -0
  32. data/lib/graph_agent/checkpoint/base_saver.rb +38 -0
  33. data/lib/graph_agent/checkpoint/in_memory_saver.rb +145 -0
  34. data/lib/graph_agent/constants.rb +9 -0
  35. data/lib/graph_agent/errors.rb +41 -0
  36. data/lib/graph_agent/graph/compiled_state_graph.rb +362 -0
  37. data/lib/graph_agent/graph/conditional_edge.rb +57 -0
  38. data/lib/graph_agent/graph/edge.rb +23 -0
  39. data/lib/graph_agent/graph/mermaid_visualizer.rb +154 -0
  40. data/lib/graph_agent/graph/message_graph.rb +18 -0
  41. data/lib/graph_agent/graph/node.rb +61 -0
  42. data/lib/graph_agent/graph/state_graph.rb +197 -0
  43. data/lib/graph_agent/reducers.rb +34 -0
  44. data/lib/graph_agent/state/schema.rb +54 -0
  45. data/lib/graph_agent/types/cache_policy.rb +12 -0
  46. data/lib/graph_agent/types/command.rb +26 -0
  47. data/lib/graph_agent/types/interrupt.rb +28 -0
  48. data/lib/graph_agent/types/retry_policy.rb +42 -0
  49. data/lib/graph_agent/types/send.rb +26 -0
  50. data/lib/graph_agent/types/state_snapshot.rb +28 -0
  51. data/lib/graph_agent/version.rb +5 -0
  52. data/lib/graph_agent.rb +29 -0
  53. metadata +158 -0
@@ -0,0 +1,832 @@
1
+ # API Reference
2
+
3
+ Complete reference for all public classes, methods, and constants.
4
+
5
+ ---
6
+
7
+ ## Constants
8
+
9
+ Defined in `lib/graph_agent/constants.rb`.
10
+
11
+ | Constant | Value | Description |
12
+ |----------|-------|-------------|
13
+ | `GraphAgent::START` | `:"__start__"` | Virtual entry point; edges from START define where execution begins |
14
+ | `GraphAgent::END_NODE` | `:"__end__"` | Virtual terminal node; routing here stops execution |
15
+ | `GraphAgent::TAG_NOSTREAM` | `:nostream` | Tag to suppress streaming for a node |
16
+ | `GraphAgent::TAG_HIDDEN` | `:"langsmith:hidden"` | Tag to hide a node from tracing |
17
+
18
+ ---
19
+
20
+ ## GraphAgent::Graph::StateGraph
21
+
22
+ Defined in `lib/graph_agent/graph/state_graph.rb`.
23
+
24
+ The primary graph builder. Define nodes, edges, and conditional routing, then
25
+ compile into an executable graph.
26
+
27
+ ### Constructor
28
+
29
+ ```ruby
30
+ StateGraph.new(schema = nil, input_schema: nil, output_schema: nil)
31
+ ```
32
+
33
+ | Parameter | Type | Description |
34
+ |-----------|------|-------------|
35
+ | `schema` | `Schema`, `Hash`, or `nil` | State schema defining fields, reducers, and defaults |
36
+ | `input_schema:` | `Schema`/`nil` | Input-only schema (stored, not yet enforced) |
37
+ | `output_schema:` | `Schema`/`nil` | Output-only schema (stored, not yet enforced) |
38
+
39
+ Hash schemas are auto-converted to `Schema` objects (see [State](state.md)).
40
+
41
+ ### Attributes
42
+
43
+ | Attribute | Type | Description |
44
+ |-----------|------|-------------|
45
+ | `schema` | `Schema` | The normalized state schema |
46
+ | `nodes` | `Hash{String => Node}` | Registered nodes by name |
47
+ | `edges` | `Set<Edge>` | Registered static edges |
48
+ | `branches` | `Hash{String => Hash{String => ConditionalEdge}}` | Conditional edges by source |
49
+ | `waiting_edges` | `Set<[Array<String>, String]>` | Multi-source waiting edges |
50
+
51
+ ### Methods
52
+
53
+ #### `add_node(name, action = nil, metadata: nil, retry_policy: nil, cache_policy: nil, &block)`
54
+
55
+ Add a node to the graph.
56
+
57
+ | Parameter | Type | Description |
58
+ |-----------|------|-------------|
59
+ | `name` | String/Symbol | Node name (must be unique, not reserved) |
60
+ | `action` | Proc/callable/nil | The node function; can also be passed as a block |
61
+ | `metadata:` | Hash/nil | Arbitrary metadata attached to the node |
62
+ | `retry_policy:` | `RetryPolicy`/nil | Retry configuration for transient failures |
63
+ | `cache_policy:` | `CachePolicy`/nil | Cache configuration |
64
+
65
+ Returns `self` for chaining.
66
+
67
+ Raises `InvalidGraphError` if:
68
+ - No action provided
69
+ - Name already exists
70
+ - Name is reserved (`START` or `END_NODE`)
71
+
72
+ ```ruby
73
+ graph.add_node("process") do |state|
74
+ { result: compute(state[:input]) }
75
+ end
76
+
77
+ graph.add_node("fetch", method(:fetch_data), retry_policy: policy)
78
+ ```
79
+
80
+ #### `add_edge(start_key, end_key)`
81
+
82
+ Add a directed edge between two nodes.
83
+
84
+ | Parameter | Type | Description |
85
+ |-----------|------|-------------|
86
+ | `start_key` | String/Symbol/Array | Source node (or array for waiting edges) |
87
+ | `end_key` | String/Symbol | Target node |
88
+
89
+ Returns `self` for chaining.
90
+
91
+ When `start_key` is an Array, creates a **waiting edge** that fires only when
92
+ all source nodes have executed.
93
+
94
+ Raises `InvalidGraphError` if `END_NODE` is used as source or `START` as
95
+ target.
96
+
97
+ ```ruby
98
+ graph.add_edge("a", "b")
99
+ graph.add_edge(GraphAgent::START, "first")
100
+ graph.add_edge("last", GraphAgent::END_NODE)
101
+ graph.add_edge(["fetch_a", "fetch_b"], "merge")
102
+ ```
103
+
104
+ #### `add_conditional_edges(source, path, path_map = nil)`
105
+
106
+ Add a conditional edge that routes based on state.
107
+
108
+ | Parameter | Type | Description |
109
+ |-----------|------|-------------|
110
+ | `source` | String/Symbol | Source node name |
111
+ | `path` | Proc/callable | Function `(state) → target` or `(state, config) → target` |
112
+ | `path_map` | Hash/nil | Maps path return values to node names |
113
+
114
+ Returns `self` for chaining.
115
+
116
+ ```ruby
117
+ graph.add_conditional_edges("router", ->(state) { state[:route] })
118
+
119
+ graph.add_conditional_edges(
120
+ "classifier",
121
+ ->(state) { state[:category] },
122
+ { "a" => "handler_a", "b" => "handler_b", default: "fallback" }
123
+ )
124
+ ```
125
+
126
+ #### `add_sequence(nodes)`
127
+
128
+ Add a linear sequence of nodes with edges between consecutive pairs.
129
+
130
+ | Parameter | Type | Description |
131
+ |-----------|------|-------------|
132
+ | `nodes` | Array | Array of `[name, action]` pairs, callables, or existing node names |
133
+
134
+ Returns `self` for chaining.
135
+
136
+ ```ruby
137
+ graph.add_sequence([
138
+ ["step1", ->(s) { { x: 1 } }],
139
+ ["step2", ->(s) { { x: s[:x] + 1 } }]
140
+ ])
141
+ ```
142
+
143
+ #### `set_entry_point(node_name)`
144
+
145
+ Shorthand for `add_edge(START, node_name)`.
146
+
147
+ #### `set_finish_point(node_name)`
148
+
149
+ Shorthand for `add_edge(node_name, END_NODE)`.
150
+
151
+ #### `set_conditional_entry_point(path, path_map = nil)`
152
+
153
+ Shorthand for `add_conditional_edges(START, path, path_map)`.
154
+
155
+ #### `compile(checkpointer: nil, interrupt_before: nil, interrupt_after: nil, debug: false)`
156
+
157
+ Validate the graph and return a `CompiledStateGraph`.
158
+
159
+ | Parameter | Type | Description |
160
+ |-----------|------|-------------|
161
+ | `checkpointer:` | `BaseSaver`/nil | Checkpoint saver for persistence |
162
+ | `interrupt_before:` | Array/nil | Node names to interrupt before |
163
+ | `interrupt_after:` | Array/nil | Node names to interrupt after |
164
+ | `debug:` | Boolean | Enable debug mode |
165
+
166
+ Raises `InvalidGraphError` if validation fails.
167
+
168
+ ```ruby
169
+ app = graph.compile(
170
+ checkpointer: GraphAgent::Checkpoint::InMemorySaver.new,
171
+ interrupt_before: ["review"]
172
+ )
173
+ ```
174
+
175
+ ---
176
+
177
+ ## GraphAgent::Graph::CompiledStateGraph
178
+
179
+ Defined in `lib/graph_agent/graph/compiled_state_graph.rb`.
180
+
181
+ The compiled, executable form of a graph. Implements the Pregel execution
182
+ model.
183
+
184
+ ### Constants
185
+
186
+ | Constant | Value | Description |
187
+ |----------|-------|-------------|
188
+ | `DEFAULT_RECURSION_LIMIT` | `25` | Default maximum supersteps |
189
+
190
+ ### Attributes
191
+
192
+ | Attribute | Type | Description |
193
+ |-----------|------|-------------|
194
+ | `builder` | `StateGraph` | The original graph builder |
195
+ | `checkpointer` | `BaseSaver`/nil | The checkpoint saver |
196
+
197
+ ### Methods
198
+
199
+ #### `invoke(input, config: {}, recursion_limit: DEFAULT_RECURSION_LIMIT)`
200
+
201
+ Run the graph to completion and return the final state.
202
+
203
+ | Parameter | Type | Description |
204
+ |-----------|------|-------------|
205
+ | `input` | Hash/nil | Initial state values; `nil` to resume from checkpoint |
206
+ | `config:` | Hash | Config with `{ configurable: { thread_id: ... } }` |
207
+ | `recursion_limit:` | Integer | Maximum supersteps before raising `GraphRecursionError` |
208
+
209
+ Returns a Hash of the final state.
210
+
211
+ Raises:
212
+ - `GraphRecursionError` if the limit is exceeded
213
+ - `GraphInterrupt` if an interrupt fires
214
+ - `NodeExecutionError` if a node raises
215
+
216
+ ```ruby
217
+ result = app.invoke({ messages: [{ role: "user", content: "Hi" }] })
218
+ result = app.invoke({ query: "hello" }, config: config, recursion_limit: 50)
219
+ result = app.invoke(nil, config: config) # resume from checkpoint
220
+ ```
221
+
222
+ #### `stream(input, config: {}, recursion_limit: DEFAULT_RECURSION_LIMIT, stream_mode: :values, &block)`
223
+
224
+ Stream execution events. See [Streaming](streaming.md).
225
+
226
+ | Parameter | Type | Description |
227
+ |-----------|------|-------------|
228
+ | `input` | Hash/nil | Initial state values |
229
+ | `config:` | Hash | Config hash |
230
+ | `recursion_limit:` | Integer | Maximum supersteps |
231
+ | `stream_mode:` | Symbol | `:values`, `:updates`, or `:debug` |
232
+ | `&block` | Block | Event handler; omit for Enumerator |
233
+
234
+ Returns `Enumerator` if no block given; `nil` otherwise.
235
+
236
+ ```ruby
237
+ app.stream(input, stream_mode: :values) { |state| puts state }
238
+ events = app.stream(input, stream_mode: :updates)
239
+ ```
240
+
241
+ #### `get_state(config)`
242
+
243
+ Retrieve the current state snapshot for a thread.
244
+
245
+ | Parameter | Type | Description |
246
+ |-----------|------|-------------|
247
+ | `config` | Hash | Config with `thread_id` |
248
+
249
+ Returns `StateSnapshot` or `nil`.
250
+
251
+ ```ruby
252
+ snapshot = app.get_state(config)
253
+ snapshot.values # => { messages: [...] }
254
+ snapshot.next_nodes # => ["process"]
255
+ ```
256
+
257
+ #### `update_state(config, values, as_node: nil)`
258
+
259
+ Manually update the state of a thread.
260
+
261
+ | Parameter | Type | Description |
262
+ |-----------|------|-------------|
263
+ | `config` | Hash | Config with `thread_id` |
264
+ | `values` | Hash | State updates to apply |
265
+ | `as_node:` | String/nil | Reserved; node to attribute the update to |
266
+
267
+ Returns the new checkpoint config Hash, or `nil`.
268
+
269
+ ```ruby
270
+ app.update_state(config, { approved: true })
271
+ ```
272
+
273
+ #### `get_graph`
274
+
275
+ Return the graph structure as a Hash.
276
+
277
+ ```ruby
278
+ app.get_graph
279
+ # => { nodes: ["a", "b"], edges: [["__start__", "a"], ["a", "b"]] }
280
+ ```
281
+
282
+ ---
283
+
284
+ ## GraphAgent::Graph::MessageGraph
285
+
286
+ Defined in `lib/graph_agent/graph/message_graph.rb`.
287
+
288
+ A convenience subclass of `StateGraph` pre-configured with a `messages` field
289
+ using the `add_messages` reducer.
290
+
291
+ ### Constructor
292
+
293
+ ```ruby
294
+ MessageGraph.new
295
+ ```
296
+
297
+ No arguments. Internally creates a `MessagesState` schema with:
298
+
299
+ ```ruby
300
+ field :messages, type: Array, reducer: Reducers.method(:add_messages), default: []
301
+ ```
302
+
303
+ ```ruby
304
+ graph = GraphAgent::Graph::MessageGraph.new
305
+ graph.add_node("chat") { |s| { messages: [{ role: "ai", content: "Hi" }] } }
306
+ graph.set_entry_point("chat")
307
+ graph.set_finish_point("chat")
308
+ app = graph.compile
309
+ ```
310
+
311
+ ---
312
+
313
+ ## GraphAgent::Graph::MessagesState
314
+
315
+ Defined in `lib/graph_agent/graph/message_graph.rb`.
316
+
317
+ A `Schema` subclass with a single `:messages` field. Used internally by
318
+ `MessageGraph`.
319
+
320
+ ---
321
+
322
+ ## GraphAgent::State::Schema
323
+
324
+ Defined in `lib/graph_agent/state/schema.rb`.
325
+
326
+ DSL for defining state fields, types, reducers, and defaults.
327
+
328
+ ### Constructor
329
+
330
+ ```ruby
331
+ Schema.new(&block)
332
+ ```
333
+
334
+ ### Attributes
335
+
336
+ | Attribute | Type | Description |
337
+ |-----------|------|-------------|
338
+ | `fields` | `Hash{Symbol => Field}` | Registered fields |
339
+
340
+ ### Methods
341
+
342
+ #### `field(name, type: nil, reducer: nil, default: nil)`
343
+
344
+ Define a state field.
345
+
346
+ | Parameter | Type | Description |
347
+ |-----------|------|-------------|
348
+ | `name` | String/Symbol | Field name |
349
+ | `type:` | Class/nil | Type annotation (not enforced) |
350
+ | `reducer:` | Proc/nil | `(current, new) → merged` |
351
+ | `default:` | Object/nil | Initial value (duplicated per invocation) |
352
+
353
+ #### `initial_state`
354
+
355
+ Returns a Hash of field names to duplicated defaults.
356
+
357
+ ```ruby
358
+ schema.initial_state # => { messages: [], count: 0 }
359
+ ```
360
+
361
+ #### `apply(state, updates)`
362
+
363
+ Apply updates to state using reducers. Mutates and returns `state`.
364
+
365
+ ### Schema::Field
366
+
367
+ A `Data.define(:name, :type, :reducer, :default)` value object.
368
+
369
+ ---
370
+
371
+ ## GraphAgent::Reducers
372
+
373
+ Defined in `lib/graph_agent/reducers.rb`.
374
+
375
+ ### Constants
376
+
377
+ | Constant | Lambda | Description |
378
+ |----------|--------|-------------|
379
+ | `ADD` | `(a, b) → a + b` | Concatenation / addition |
380
+ | `APPEND` | `(a, b) → Array(a) + Array(b)` | Array append |
381
+ | `MERGE` | `(a, b) → a.merge(b)` | Hash merge |
382
+ | `REPLACE` | `(_, b) → b` | Always replace |
383
+
384
+ ### Module Methods
385
+
386
+ #### `add_messages(existing, new_messages)`
387
+
388
+ Smart message reducer. Matches by `:id` key — updates existing messages
389
+ in-place, appends new ones.
390
+
391
+ | Parameter | Type | Description |
392
+ |-----------|------|-------------|
393
+ | `existing` | Array | Current messages |
394
+ | `new_messages` | Array | New messages to merge |
395
+
396
+ Returns a new Array.
397
+
398
+ ---
399
+
400
+ ## GraphAgent::Send
401
+
402
+ Defined in `lib/graph_agent/types/send.rb`.
403
+
404
+ Routes execution to a specific node with custom arguments.
405
+
406
+ ### Constructor
407
+
408
+ ```ruby
409
+ Send.new(node, arg)
410
+ ```
411
+
412
+ | Parameter | Type | Description |
413
+ |-----------|------|-------------|
414
+ | `node` | String/Symbol | Target node name (converted to String) |
415
+ | `arg` | Object | Argument passed as state override |
416
+
417
+ ### Attributes
418
+
419
+ | Attribute | Type |
420
+ |-----------|------|
421
+ | `node` | String |
422
+ | `arg` | Object |
423
+
424
+ ### Methods
425
+
426
+ | Method | Description |
427
+ |--------|-------------|
428
+ | `==` / `eql?` | Equality by `node` and `arg` |
429
+ | `hash` | Hash code |
430
+ | `to_s` / `inspect` | `"Send(node=..., arg=...)"` |
431
+
432
+ ---
433
+
434
+ ## GraphAgent::Command
435
+
436
+ Defined in `lib/graph_agent/types/command.rb`.
437
+
438
+ Combines state updates with routing decisions.
439
+
440
+ ### Constants
441
+
442
+ | Constant | Value | Description |
443
+ |----------|-------|-------------|
444
+ | `PARENT` | `:__parent__` | Sentinel for routing to parent graph |
445
+
446
+ ### Constructor
447
+
448
+ ```ruby
449
+ Command.new(graph: nil, update: nil, resume: nil, goto: [])
450
+ ```
451
+
452
+ | Parameter | Type | Description |
453
+ |-----------|------|-------------|
454
+ | `graph:` | Object/nil | Target subgraph (reserved) |
455
+ | `update:` | Hash/nil | State updates to apply |
456
+ | `resume:` | Object/nil | Resume value for interrupt workflows |
457
+ | `goto:` | String/Symbol/Send/Array | Next node(s) to route to |
458
+
459
+ ### Attributes
460
+
461
+ | Attribute | Type |
462
+ |-----------|------|
463
+ | `graph` | Object/nil |
464
+ | `update` | Hash/nil |
465
+ | `resume` | Object/nil |
466
+ | `goto` | Array |
467
+
468
+ ### Methods
469
+
470
+ | Method | Description |
471
+ |--------|-------------|
472
+ | `to_s` / `inspect` | `"Command(update=..., goto=...)"` |
473
+
474
+ ---
475
+
476
+ ## GraphAgent::Interrupt
477
+
478
+ Defined in `lib/graph_agent/types/interrupt.rb`.
479
+
480
+ Represents a single interrupt event.
481
+
482
+ ### Constructor
483
+
484
+ ```ruby
485
+ Interrupt.new(value, id: nil)
486
+ ```
487
+
488
+ | Parameter | Type | Description |
489
+ |-----------|------|-------------|
490
+ | `value` | Object | Description of the interrupt |
491
+ | `id:` | String/nil | Unique ID (auto-generated UUID if nil) |
492
+
493
+ ### Attributes
494
+
495
+ | Attribute | Type |
496
+ |-----------|------|
497
+ | `value` | Object |
498
+ | `id` | String |
499
+
500
+ ### Methods
501
+
502
+ | Method | Description |
503
+ |--------|-------------|
504
+ | `==` / `eql?` | Equality by `id` and `value` |
505
+ | `hash` | Hash code |
506
+ | `to_s` / `inspect` | `"Interrupt(value=..., id=...)"` |
507
+
508
+ ---
509
+
510
+ ## GraphAgent::RetryPolicy
511
+
512
+ Defined in `lib/graph_agent/types/retry_policy.rb`.
513
+
514
+ Configures automatic retries with exponential backoff.
515
+
516
+ ### Constructor
517
+
518
+ ```ruby
519
+ RetryPolicy.new(
520
+ initial_interval: 0.5,
521
+ backoff_factor: 2.0,
522
+ max_interval: 128.0,
523
+ max_attempts: 3,
524
+ jitter: true,
525
+ retry_on: StandardError
526
+ )
527
+ ```
528
+
529
+ | Parameter | Type | Default | Description |
530
+ |-----------|------|---------|-------------|
531
+ | `initial_interval:` | Float | `0.5` | Seconds before first retry |
532
+ | `backoff_factor:` | Float | `2.0` | Multiplier per attempt |
533
+ | `max_interval:` | Float | `128.0` | Maximum interval cap |
534
+ | `max_attempts:` | Integer | `3` | Total attempts |
535
+ | `jitter:` | Boolean | `true` | Add random jitter |
536
+ | `retry_on:` | Class/Array/Proc | `StandardError` | Which errors to retry |
537
+
538
+ ### Attributes
539
+
540
+ All constructor parameters are exposed as readers.
541
+
542
+ ### Methods
543
+
544
+ #### `should_retry?(error)`
545
+
546
+ Returns `true` if the error matches the `retry_on` configuration.
547
+
548
+ #### `interval_for(attempt)`
549
+
550
+ Returns the sleep interval (Float) for the given attempt number (0-indexed).
551
+
552
+ ---
553
+
554
+ ## GraphAgent::CachePolicy
555
+
556
+ Defined in `lib/graph_agent/types/cache_policy.rb`.
557
+
558
+ Configures caching for node results.
559
+
560
+ ### Constructor
561
+
562
+ ```ruby
563
+ CachePolicy.new(key_func: nil, ttl: nil)
564
+ ```
565
+
566
+ | Parameter | Type | Description |
567
+ |-----------|------|-------------|
568
+ | `key_func:` | Proc/nil | Function to compute cache key from state |
569
+ | `ttl:` | Numeric/nil | Time-to-live in seconds |
570
+
571
+ ### Attributes
572
+
573
+ | Attribute | Type |
574
+ |-----------|------|
575
+ | `key_func` | Proc/nil |
576
+ | `ttl` | Numeric/nil |
577
+
578
+ ---
579
+
580
+ ## GraphAgent::StateSnapshot
581
+
582
+ Defined in `lib/graph_agent/types/state_snapshot.rb`.
583
+
584
+ Read-only snapshot of graph state returned by `get_state`.
585
+
586
+ ### Constructor
587
+
588
+ ```ruby
589
+ StateSnapshot.new(
590
+ values:,
591
+ next_nodes: [],
592
+ config: {},
593
+ metadata: nil,
594
+ created_at: nil,
595
+ parent_config: nil,
596
+ tasks: [],
597
+ interrupts: []
598
+ )
599
+ ```
600
+
601
+ ### Attributes
602
+
603
+ | Attribute | Type | Description |
604
+ |-----------|------|-------------|
605
+ | `values` | Hash | Current state values |
606
+ | `next_nodes` | Array<String> | Nodes that would execute next |
607
+ | `config` | Hash | Config including `checkpoint_id` |
608
+ | `metadata` | Hash/nil | Step, source, etc. |
609
+ | `created_at` | Time/nil | When the snapshot was created |
610
+ | `parent_config` | Hash/nil | Config of the parent checkpoint |
611
+ | `tasks` | Array | Pending tasks |
612
+ | `interrupts` | Array | Active interrupts |
613
+
614
+ ---
615
+
616
+ ## GraphAgent::Checkpoint::BaseSaver
617
+
618
+ Defined in `lib/graph_agent/checkpoint/base_saver.rb`.
619
+
620
+ Abstract base class for checkpoint persistence. Subclass and implement all
621
+ methods to create a custom saver.
622
+
623
+ ### Methods
624
+
625
+ #### `get(config)`
626
+
627
+ Convenience method. Calls `get_tuple(config)` and returns the checkpoint hash,
628
+ or `nil`.
629
+
630
+ #### `get_tuple(config)` (abstract)
631
+
632
+ Return a `CheckpointTuple` for the given config, or `nil`.
633
+
634
+ #### `list(config, filter: nil, before: nil, limit: nil)` (abstract)
635
+
636
+ Return an Array of `CheckpointTuple` matching the criteria.
637
+
638
+ #### `put(config, checkpoint, metadata, new_versions)` (abstract)
639
+
640
+ Save a checkpoint. Return the new config hash with `checkpoint_id`.
641
+
642
+ #### `put_writes(config, writes, task_id)` (abstract)
643
+
644
+ Save pending writes for a checkpoint.
645
+
646
+ #### `delete_thread(thread_id)` (abstract)
647
+
648
+ Delete all data for a thread.
649
+
650
+ ---
651
+
652
+ ## GraphAgent::Checkpoint::CheckpointTuple
653
+
654
+ Defined in `lib/graph_agent/checkpoint/base_saver.rb`.
655
+
656
+ A `Data.define` value object for checkpoint data.
657
+
658
+ ### Fields
659
+
660
+ | Field | Type | Default | Description |
661
+ |-------|------|---------|-------------|
662
+ | `config` | Hash | required | Config with thread/checkpoint IDs |
663
+ | `checkpoint` | Hash | required | Serialized state |
664
+ | `metadata` | Hash/nil | `nil` | Step, source, parents |
665
+ | `parent_config` | Hash/nil | `nil` | Parent checkpoint config |
666
+ | `pending_writes` | Array | `[]` | `[task_id, channel, value]` triples |
667
+
668
+ ---
669
+
670
+ ## GraphAgent::Checkpoint::InMemorySaver
671
+
672
+ Defined in `lib/graph_agent/checkpoint/in_memory_saver.rb`.
673
+
674
+ In-memory implementation of `BaseSaver`. Stores data in Ruby Hashes. Data is
675
+ lost when the process exits.
676
+
677
+ ### Constructor
678
+
679
+ ```ruby
680
+ InMemorySaver.new
681
+ ```
682
+
683
+ ### Methods
684
+
685
+ Implements all `BaseSaver` abstract methods:
686
+
687
+ - `get_tuple(config)` — retrieve by `thread_id` and optional `checkpoint_id`
688
+ - `list(config, filter:, before:, limit:)` — list checkpoints newest first
689
+ - `put(config, checkpoint, metadata, new_versions)` — store a checkpoint
690
+ - `put_writes(config, writes, task_id)` — store pending writes
691
+ - `delete_thread(thread_id)` — remove all data for a thread
692
+
693
+ ---
694
+
695
+ ## GraphAgent::Graph::Node
696
+
697
+ Defined in `lib/graph_agent/graph/node.rb`.
698
+
699
+ Internal wrapper around a node's callable action.
700
+
701
+ ### Attributes
702
+
703
+ | Attribute | Type | Description |
704
+ |-----------|------|-------------|
705
+ | `name` | String | Node name |
706
+ | `action` | Proc/callable | The node function |
707
+ | `metadata` | Hash | Arbitrary metadata |
708
+ | `retry_policy` | `RetryPolicy`/nil | Retry configuration |
709
+ | `cache_policy` | `CachePolicy`/nil | Cache configuration |
710
+
711
+ ### Methods
712
+
713
+ #### `call(state, config = {})`
714
+
715
+ Execute the node action with retry support. Returns the normalized result
716
+ (Hash, Command, Send, Array, or nil).
717
+
718
+ ---
719
+
720
+ ## GraphAgent::Graph::Edge
721
+
722
+ Defined in `lib/graph_agent/graph/edge.rb`.
723
+
724
+ A static directed edge between two nodes.
725
+
726
+ ### Attributes
727
+
728
+ | Attribute | Type |
729
+ |-----------|------|
730
+ | `source` | String |
731
+ | `target` | String |
732
+
733
+ ### Methods
734
+
735
+ | Method | Description |
736
+ |--------|-------------|
737
+ | `==` / `eql?` | Equality by source and target |
738
+ | `hash` | Hash code |
739
+
740
+ ---
741
+
742
+ ## GraphAgent::Graph::ConditionalEdge
743
+
744
+ Defined in `lib/graph_agent/graph/conditional_edge.rb`.
745
+
746
+ A dynamic edge that routes based on a callable path function.
747
+
748
+ ### Attributes
749
+
750
+ | Attribute | Type | Description |
751
+ |-----------|------|-------------|
752
+ | `source` | String | Source node |
753
+ | `path` | Proc/callable | Routing function |
754
+ | `path_map` | Hash/nil | Maps return values to node names |
755
+
756
+ ### Methods
757
+
758
+ #### `resolve(state, config = {})`
759
+
760
+ Invoke the path function and map the result. Returns a String (node name),
761
+ Array of Strings, or Array of `Send` objects.
762
+
763
+ ---
764
+
765
+ ## Channels
766
+
767
+ Defined in `lib/graph_agent/channels/`. These are internal types used by the
768
+ execution engine.
769
+
770
+ ### GraphAgent::Channels::BaseChannel
771
+
772
+ Abstract base. Key methods: `get`, `update(values)`, `checkpoint`,
773
+ `from_checkpoint(value)`, `available?`, `consume`, `finish`, `copy`.
774
+
775
+ Sentinel constant: `MISSING` — represents an unset value.
776
+
777
+ ### GraphAgent::Channels::LastValue
778
+
779
+ Single-value channel. Raises `InvalidUpdateError` if more than one value is
780
+ written per step. Constructor: `LastValue.new(key:, default:)`.
781
+
782
+ ### GraphAgent::Channels::BinaryOperatorAggregate
783
+
784
+ Aggregation channel using a binary operator (reducer). Constructor:
785
+ `BinaryOperatorAggregate.new(operator:, key:, default:)`.
786
+
787
+ ### GraphAgent::Channels::EphemeralValue
788
+
789
+ Single-value channel that resets to `MISSING` between steps. Constructor:
790
+ `EphemeralValue.new(key:, guard:)`. When `guard: true` (default), raises
791
+ `InvalidUpdateError` on multiple writes.
792
+
793
+ ### GraphAgent::Channels::Topic
794
+
795
+ Multi-value channel that collects values into an array. Constructor:
796
+ `Topic.new(key:, accumulate:)`. When `accumulate: false` (default), values
797
+ are cleared between steps.
798
+
799
+ ---
800
+
801
+ ## Error Classes
802
+
803
+ Defined in `lib/graph_agent/errors.rb`.
804
+
805
+ | Class | Parent | Description |
806
+ |-------|--------|-------------|
807
+ | `GraphError` | `StandardError` | Base class for all GraphAgent errors |
808
+ | `GraphRecursionError` | `GraphError` | Recursion limit exceeded |
809
+ | `InvalidUpdateError` | `GraphError` | Invalid channel update |
810
+ | `EmptyChannelError` | `GraphError` | Reading from an empty channel |
811
+ | `InvalidGraphError` | `GraphError` | Invalid graph structure (compile-time) |
812
+ | `NodeExecutionError` | `GraphError` | Wraps errors raised inside nodes |
813
+ | `GraphInterrupt` | `GraphError` | Graph paused by interrupt |
814
+ | `EmptyInputError` | `GraphError` | Empty input where input is required |
815
+ | `TaskNotFound` | `GraphError` | Referenced task does not exist |
816
+
817
+ ### NodeExecutionError
818
+
819
+ Extra attributes:
820
+
821
+ | Attribute | Type | Description |
822
+ |-----------|------|-------------|
823
+ | `node_name` | String | Name of the failed node |
824
+ | `original_error` | Exception | The wrapped error |
825
+
826
+ ### GraphInterrupt
827
+
828
+ Extra attributes:
829
+
830
+ | Attribute | Type | Description |
831
+ |-----------|------|-------------|
832
+ | `interrupts` | Array<Interrupt> | The interrupt objects |