langgraph_rb 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.
- checksums.yaml +7 -0
- data/Gemfile +9 -0
- data/README.md +350 -0
- data/SUMMARY.md +170 -0
- data/examples/advanced_example.rb +388 -0
- data/examples/basic_example.rb +211 -0
- data/examples/simple_test.rb +266 -0
- data/langgraph_rb.gemspec +43 -0
- data/lib/langgraph_rb/command.rb +132 -0
- data/lib/langgraph_rb/edge.rb +141 -0
- data/lib/langgraph_rb/graph.rb +268 -0
- data/lib/langgraph_rb/node.rb +112 -0
- data/lib/langgraph_rb/runner.rb +360 -0
- data/lib/langgraph_rb/state.rb +70 -0
- data/lib/langgraph_rb/stores/memory.rb +265 -0
- data/lib/langgraph_rb/version.rb +3 -0
- data/lib/langgraph_rb.rb +15 -0
- data/test_runner.rb +160 -0
- metadata +151 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d21ea984522f684793c24a7be4f2ccd5c90dfad98512647949e42b9e2b8c1dee
|
4
|
+
data.tar.gz: 99b3ebfdc7a42fb86cee874d3471f3dc21a728eba018497c695acc7f9af50611
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 94c90d4d802c354776a8440662bb9f50af883b78baacd9891bb6f43c76052540a0a7767facc238931c53c4752a0802787dd82ba277b370e19049a4939b7d5c0e
|
7
|
+
data.tar.gz: c12b92e058b0eccf5150d4491e603746abadb946386d7b0e51379d5ec481f8e1f01512023d8f0e492adf203355c5450a2b32aded362840efe4bb1be9ee11088c
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,350 @@
|
|
1
|
+
# LangGraphRB 🔄
|
2
|
+
|
3
|
+
A Ruby library for building stateful, multi-actor applications with directed graphs, inspired by [LangGraph](https://langchain-ai.github.io/langgraph/).
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
LangGraphRB models complex workflows as directed graphs where:
|
8
|
+
- **Nodes** are executable functions that process state and return updates
|
9
|
+
- **Edges** define the flow between nodes with support for conditional routing
|
10
|
+
- **State** is a centralized, typed object that flows through the entire execution
|
11
|
+
- **Commands** control execution flow with operations like `goto`, `send`, and `interrupt`
|
12
|
+
|
13
|
+
## Key Features
|
14
|
+
|
15
|
+
- 🔄 **Graph-based Orchestration**: Model complex workflows as directed graphs
|
16
|
+
- 🏃 **Parallel Execution**: Execute multiple nodes simultaneously with thread-safe state management
|
17
|
+
- 💾 **Checkpointing**: Automatic state persistence and resumption support
|
18
|
+
- 🤖 **Human-in-the-Loop**: Built-in support for human intervention and approval workflows
|
19
|
+
- 🔀 **Map-Reduce Operations**: Fan-out to parallel processing and collect results
|
20
|
+
- 📊 **Visualization**: Generate Mermaid diagrams of your graphs
|
21
|
+
- 🎯 **Type-Safe State**: Centralized state with customizable reducers
|
22
|
+
- ⚡ **Streaming Execution**: Real-time progress monitoring
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Add this line to your application's Gemfile:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
gem 'langgraph_rb'
|
30
|
+
```
|
31
|
+
|
32
|
+
And then execute:
|
33
|
+
|
34
|
+
```bash
|
35
|
+
$ bundle install
|
36
|
+
```
|
37
|
+
|
38
|
+
Or install it yourself as:
|
39
|
+
|
40
|
+
```bash
|
41
|
+
$ gem install langgraph_rb
|
42
|
+
```
|
43
|
+
|
44
|
+
## Quick Start
|
45
|
+
|
46
|
+
Here's a simple example of building a chatbot with conditional routing:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
require 'langgraph_rb'
|
50
|
+
|
51
|
+
# Create a graph with a DSL
|
52
|
+
graph = LangGraphRB::Graph.new do
|
53
|
+
# Define nodes
|
54
|
+
node :greet do |state|
|
55
|
+
{ message: "Hello! How can I help you?" }
|
56
|
+
end
|
57
|
+
|
58
|
+
node :analyze_intent do |state|
|
59
|
+
user_input = state[:user_input].to_s.downcase
|
60
|
+
intent = user_input.include?('weather') ? 'weather' : 'general'
|
61
|
+
{ intent: intent }
|
62
|
+
end
|
63
|
+
|
64
|
+
node :weather_response do |state|
|
65
|
+
{ message: "The weather is sunny today!" }
|
66
|
+
end
|
67
|
+
|
68
|
+
node :general_response do |state|
|
69
|
+
{ message: "That's interesting! Tell me more." }
|
70
|
+
end
|
71
|
+
|
72
|
+
# Define the flow
|
73
|
+
set_entry_point :greet
|
74
|
+
edge :greet, :analyze_intent
|
75
|
+
|
76
|
+
# Conditional routing based on intent
|
77
|
+
conditional_edge :analyze_intent, ->(state) { state[:intent] }, {
|
78
|
+
'weather' => :weather_response,
|
79
|
+
'general' => :general_response
|
80
|
+
}
|
81
|
+
|
82
|
+
# Both responses end the conversation
|
83
|
+
set_finish_point :weather_response
|
84
|
+
set_finish_point :general_response
|
85
|
+
end
|
86
|
+
|
87
|
+
# Compile and execute
|
88
|
+
graph.compile!
|
89
|
+
result = graph.invoke({ user_input: "How's the weather?" })
|
90
|
+
puts result[:message] # => "The weather is sunny today!"
|
91
|
+
```
|
92
|
+
|
93
|
+
## Core Concepts
|
94
|
+
|
95
|
+
### State Management
|
96
|
+
|
97
|
+
State is centralized and flows through the entire graph. You can define reducers for specific keys to control how state updates are merged:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
# State with custom reducers
|
101
|
+
state = LangGraphRB::State.new(
|
102
|
+
{ messages: [], count: 0 },
|
103
|
+
{
|
104
|
+
messages: LangGraphRB::State.add_messages, # Append to array
|
105
|
+
count: ->(old, new) { (old || 0) + new } # Sum values
|
106
|
+
}
|
107
|
+
)
|
108
|
+
```
|
109
|
+
|
110
|
+
### Nodes
|
111
|
+
|
112
|
+
Nodes are the executable units of your graph. They receive the current state and return updates:
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
# Simple node
|
116
|
+
node :process_data do |state|
|
117
|
+
processed = state[:data].map(&:upcase)
|
118
|
+
{ processed_data: processed, processing_complete: true }
|
119
|
+
end
|
120
|
+
|
121
|
+
# Node with context
|
122
|
+
node :call_api do |state, context|
|
123
|
+
api_client = context[:api_client]
|
124
|
+
result = api_client.call(state[:query])
|
125
|
+
{ api_result: result }
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
### Edges and Routing
|
130
|
+
|
131
|
+
Define how execution flows between nodes:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
# Simple edge
|
135
|
+
edge :node_a, :node_b
|
136
|
+
|
137
|
+
# Conditional edge with router function
|
138
|
+
conditional_edge :decision_node, ->(state) {
|
139
|
+
state[:condition] ? :path_a : :path_b
|
140
|
+
}
|
141
|
+
|
142
|
+
# Fan-out to multiple nodes
|
143
|
+
fan_out_edge :distributor, [:worker_1, :worker_2, :worker_3]
|
144
|
+
```
|
145
|
+
|
146
|
+
### Commands
|
147
|
+
|
148
|
+
Control execution flow with commands:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
node :decision_node do |state|
|
152
|
+
if state[:should_continue]
|
153
|
+
LangGraphRB::Commands.update_and_goto(
|
154
|
+
{ status: 'continuing' },
|
155
|
+
:next_node
|
156
|
+
)
|
157
|
+
else
|
158
|
+
LangGraphRB::Commands.end_execution({ status: 'stopped' })
|
159
|
+
end
|
160
|
+
end
|
161
|
+
```
|
162
|
+
|
163
|
+
### Parallel Processing with Send
|
164
|
+
|
165
|
+
Use `Send` commands for map-reduce operations:
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
node :fan_out do |state|
|
169
|
+
tasks = state[:tasks]
|
170
|
+
|
171
|
+
# Send each task to parallel processing
|
172
|
+
sends = tasks.map do |task|
|
173
|
+
LangGraphRB::Send.new(to: :process_task, payload: { task: task })
|
174
|
+
end
|
175
|
+
|
176
|
+
LangGraphRB::MultiSend.new(sends)
|
177
|
+
end
|
178
|
+
```
|
179
|
+
|
180
|
+
## Advanced Features
|
181
|
+
|
182
|
+
### Checkpointing and Resumption
|
183
|
+
|
184
|
+
Persist execution state and resume from any point:
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
# Use a persistent store
|
188
|
+
store = LangGraphRB::Stores::FileStore.new('./checkpoints')
|
189
|
+
thread_id = 'my_workflow_123'
|
190
|
+
|
191
|
+
# Execute with checkpointing
|
192
|
+
result = graph.invoke(
|
193
|
+
{ input: 'data' },
|
194
|
+
store: store,
|
195
|
+
thread_id: thread_id
|
196
|
+
)
|
197
|
+
|
198
|
+
# Resume later
|
199
|
+
resumed_result = graph.resume(
|
200
|
+
thread_id,
|
201
|
+
{ additional_input: 'more_data' },
|
202
|
+
store: store
|
203
|
+
)
|
204
|
+
```
|
205
|
+
|
206
|
+
### Human-in-the-Loop
|
207
|
+
|
208
|
+
Pause execution for human input:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
node :request_approval do |state|
|
212
|
+
LangGraphRB::Commands.interrupt(
|
213
|
+
message: "Please review and approve this action",
|
214
|
+
data: { action: state[:proposed_action] }
|
215
|
+
)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Set up interrupt handler
|
219
|
+
runner = LangGraphRB::Runner.new(graph, store: store, thread_id: thread_id)
|
220
|
+
runner.on_interrupt do |interrupt|
|
221
|
+
puts interrupt.message
|
222
|
+
# Get user input (this would be from a UI in practice)
|
223
|
+
user_response = gets.chomp
|
224
|
+
{ approval: user_response == 'approve' }
|
225
|
+
end
|
226
|
+
```
|
227
|
+
|
228
|
+
### Streaming Execution
|
229
|
+
|
230
|
+
Monitor execution progress in real-time:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
graph.stream({ input: 'data' }) do |step_result|
|
234
|
+
puts "Step #{step_result[:step]}: #{step_result[:active_nodes]}"
|
235
|
+
puts "State keys: #{step_result[:state].keys}"
|
236
|
+
puts "Completed: #{step_result[:completed]}"
|
237
|
+
end
|
238
|
+
```
|
239
|
+
|
240
|
+
### Visualization
|
241
|
+
|
242
|
+
Generate Mermaid diagrams of your graphs:
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
graph.compile!
|
246
|
+
puts graph.to_mermaid
|
247
|
+
|
248
|
+
# Output:
|
249
|
+
# graph TD
|
250
|
+
# start((START))
|
251
|
+
# node_a["node_a"]
|
252
|
+
# node_b["node_b"]
|
253
|
+
# __end__((END))
|
254
|
+
# start --> node_a
|
255
|
+
# node_a --> node_b
|
256
|
+
# node_b --> __end__
|
257
|
+
```
|
258
|
+
|
259
|
+
## Storage Options
|
260
|
+
|
261
|
+
Choose from different storage backends:
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
# In-memory (default, not persistent)
|
265
|
+
store = LangGraphRB::Stores::InMemoryStore.new
|
266
|
+
|
267
|
+
# File-based with YAML
|
268
|
+
store = LangGraphRB::Stores::FileStore.new('./data/checkpoints')
|
269
|
+
|
270
|
+
# File-based with JSON
|
271
|
+
store = LangGraphRB::Stores::JsonStore.new('./data/checkpoints')
|
272
|
+
```
|
273
|
+
|
274
|
+
## Specialized Nodes
|
275
|
+
|
276
|
+
### LLM Nodes
|
277
|
+
|
278
|
+
For LLM integration (bring your own client):
|
279
|
+
|
280
|
+
```ruby
|
281
|
+
llm_node :chat, llm_client: my_llm_client, system_prompt: "You are a helpful assistant"
|
282
|
+
|
283
|
+
# Or with custom logic
|
284
|
+
llm_node :custom_chat, llm_client: my_llm_client do |state, context|
|
285
|
+
messages = prepare_messages(state[:conversation])
|
286
|
+
response = context[:llm_client].call(messages)
|
287
|
+
{ messages: [{ role: 'assistant', content: response }] }
|
288
|
+
end
|
289
|
+
```
|
290
|
+
|
291
|
+
### Tool Nodes
|
292
|
+
|
293
|
+
For tool/function calls:
|
294
|
+
|
295
|
+
```ruby
|
296
|
+
tool_node :search, tool: SearchTool.new
|
297
|
+
|
298
|
+
# The tool should respond to #call
|
299
|
+
class SearchTool
|
300
|
+
def call(args)
|
301
|
+
# Perform search and return results
|
302
|
+
search_api.query(args[:query])
|
303
|
+
end
|
304
|
+
end
|
305
|
+
```
|
306
|
+
|
307
|
+
## Examples
|
308
|
+
|
309
|
+
Check out the `examples/` directory for complete working examples:
|
310
|
+
|
311
|
+
- `basic_example.rb` - Simple chatbot with conditional routing
|
312
|
+
- `advanced_example.rb` - Research assistant with parallel processing and human-in-the-loop
|
313
|
+
|
314
|
+
Run them with:
|
315
|
+
|
316
|
+
```bash
|
317
|
+
$ ruby examples/basic_example.rb
|
318
|
+
$ ruby examples/advanced_example.rb
|
319
|
+
```
|
320
|
+
|
321
|
+
## Comparison with LangGraph (Python)
|
322
|
+
|
323
|
+
| Feature | LangGraphRB | LangGraph |
|
324
|
+
|---------|-------------|-----------|
|
325
|
+
| Graph Definition | ✅ DSL + Builder | ✅ Builder Pattern |
|
326
|
+
| Parallel Execution | ✅ Thread-based | ✅ AsyncIO |
|
327
|
+
| Checkpointing | ✅ Multiple stores | ✅ Multiple stores |
|
328
|
+
| Human-in-the-loop | ✅ Interrupt system | ✅ Interrupt system |
|
329
|
+
| Map-Reduce | ✅ Send commands | ✅ Send API |
|
330
|
+
| Streaming | ✅ Block-based | ✅ AsyncIO streams |
|
331
|
+
| Visualization | ✅ Mermaid | ✅ Mermaid |
|
332
|
+
| State Management | ✅ Reducers | ✅ Reducers |
|
333
|
+
|
334
|
+
## Contributing
|
335
|
+
|
336
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/yourusername/langgraph_rb.
|
337
|
+
|
338
|
+
## License
|
339
|
+
|
340
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
341
|
+
|
342
|
+
## Roadmap
|
343
|
+
|
344
|
+
- [ ] Redis-based checkpointing store
|
345
|
+
- [ ] Built-in LLM client integrations
|
346
|
+
- [ ] Web UI for monitoring executions
|
347
|
+
- [ ] Performance optimizations
|
348
|
+
- [ ] More comprehensive test suite
|
349
|
+
- [ ] Integration with Sidekiq for background processing
|
350
|
+
- [ ] Metrics and observability features
|
data/SUMMARY.md
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
# LangGraphRB - Summary of Implementation
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
Successfully created a Ruby library inspired by LangGraph (Python) that provides a framework for building stateful, multi-actor applications using directed graphs. The library models complex workflows as graphs where nodes are executable functions and edges define flow control.
|
6
|
+
|
7
|
+
## Core Components Implemented
|
8
|
+
|
9
|
+
### 1. State Management (`lib/langgraph_rb/state.rb`)
|
10
|
+
- **State Class**: Extends Hash with reducer support
|
11
|
+
- **Reducers**: Functions that define how state updates are merged
|
12
|
+
- **Built-in Reducers**:
|
13
|
+
- `add_messages` - Appends to arrays
|
14
|
+
- `append_string` - Concatenates strings
|
15
|
+
- `merge_hash` - Deep merges hashes
|
16
|
+
|
17
|
+
### 2. Node System (`lib/langgraph_rb/node.rb`)
|
18
|
+
- **Base Node**: Callable functions that process state
|
19
|
+
- **LLMNode**: Specialized node for LLM integrations
|
20
|
+
- **ToolNode**: Specialized node for tool/function calls
|
21
|
+
- **Flexible Arity**: Supports 0, 1, or 2 parameter node functions
|
22
|
+
|
23
|
+
### 3. Edge Routing (`lib/langgraph_rb/edge.rb`)
|
24
|
+
- **Simple Edges**: Direct node-to-node connections
|
25
|
+
- **Conditional Edges**: Router-function based routing with path mapping
|
26
|
+
- **Fan-out Edges**: Parallel execution to multiple destinations
|
27
|
+
- **Router Helper**: Builder pattern for complex conditional logic
|
28
|
+
|
29
|
+
### 4. Execution Control (`lib/langgraph_rb/command.rb`)
|
30
|
+
- **Command**: Combines state update + routing decision
|
31
|
+
- **Send**: Creates parallel execution branches (map-reduce)
|
32
|
+
- **MultiSend**: Multiple parallel branches
|
33
|
+
- **Interrupt**: Human-in-the-loop pause points
|
34
|
+
- **Helper Methods**: Convenient command creation
|
35
|
+
|
36
|
+
### 5. Graph Definition (`lib/langgraph_rb/graph.rb`)
|
37
|
+
- **DSL**: Clean syntax for defining workflows
|
38
|
+
- **Validation**: Compile-time graph validation
|
39
|
+
- **Mermaid Generation**: Automatic diagram creation
|
40
|
+
- **Entry/Exit Points**: START and FINISH node management
|
41
|
+
|
42
|
+
### 6. Execution Engine (`lib/langgraph_rb/runner.rb`)
|
43
|
+
- **Parallel Execution**: Thread-based super-step processing
|
44
|
+
- **State Checkpointing**: Automatic state persistence
|
45
|
+
- **Streaming Support**: Real-time progress monitoring
|
46
|
+
- **Error Handling**: Safe node execution with error propagation
|
47
|
+
- **Resume Capability**: Restart from any checkpoint
|
48
|
+
|
49
|
+
### 7. Persistence Layer (`lib/langgraph_rb/stores/memory.rb`)
|
50
|
+
- **In-Memory Store**: For testing and development
|
51
|
+
- **File Store**: YAML-based persistence
|
52
|
+
- **JSON Store**: JSON-based persistence
|
53
|
+
- **Extensible**: Abstract base for custom stores
|
54
|
+
|
55
|
+
## Key Features Achieved
|
56
|
+
|
57
|
+
✅ **Graph-based Orchestration**: Model workflows as directed graphs
|
58
|
+
✅ **Parallel Execution**: Thread-safe super-step processing
|
59
|
+
✅ **State Management**: Centralized state with reducers
|
60
|
+
✅ **Conditional Routing**: Dynamic flow control
|
61
|
+
✅ **Checkpointing**: Persistent execution state
|
62
|
+
✅ **Human-in-the-Loop**: Interrupt-driven workflows
|
63
|
+
✅ **Map-Reduce**: Fan-out parallel processing
|
64
|
+
✅ **Streaming**: Real-time execution monitoring
|
65
|
+
✅ **Visualization**: Mermaid diagram generation
|
66
|
+
✅ **Error Handling**: Robust failure management
|
67
|
+
|
68
|
+
## Architecture Highlights
|
69
|
+
|
70
|
+
### Thread-Safe Execution
|
71
|
+
- Uses Ruby's Thread class for parallel node execution
|
72
|
+
- Mutex-protected result collection
|
73
|
+
- Super-step synchronization
|
74
|
+
|
75
|
+
### State Flow
|
76
|
+
- Immutable state transitions
|
77
|
+
- Reducer-based merge operations
|
78
|
+
- Type-safe state management
|
79
|
+
|
80
|
+
### Command System
|
81
|
+
- Explicit execution control
|
82
|
+
- Support for complex routing patterns
|
83
|
+
- Clean separation of concerns
|
84
|
+
|
85
|
+
## Testing & Validation
|
86
|
+
|
87
|
+
Created comprehensive test suite covering:
|
88
|
+
- ✅ State management and reducers
|
89
|
+
- ✅ Basic graph execution
|
90
|
+
- ✅ Conditional routing
|
91
|
+
- ✅ Command-based flow control
|
92
|
+
- ✅ Checkpointing and resumption
|
93
|
+
- ✅ Streaming execution
|
94
|
+
- ✅ Error handling
|
95
|
+
|
96
|
+
## Examples Provided
|
97
|
+
|
98
|
+
### Basic Examples
|
99
|
+
- `examples/simple_test.rb` - Linear workflows and conditional routing
|
100
|
+
- `test_runner.rb` - Comprehensive feature testing
|
101
|
+
|
102
|
+
### Advanced Examples
|
103
|
+
- `examples/basic_example.rb` - Chatbot with intent routing
|
104
|
+
- `examples/advanced_example.rb` - Research assistant with parallel processing
|
105
|
+
|
106
|
+
## Comparison with LangGraph (Python)
|
107
|
+
|
108
|
+
| Feature | LangGraphRB | LangGraph (Python) |
|
109
|
+
|---------|-------------|-------------------|
|
110
|
+
| Graph Definition | ✅ Ruby DSL | ✅ Python Builder |
|
111
|
+
| Parallel Execution | ✅ Threads | ✅ AsyncIO |
|
112
|
+
| State Management | ✅ Reducers | ✅ Reducers |
|
113
|
+
| Checkpointing | ✅ Multiple stores | ✅ Multiple stores |
|
114
|
+
| Human-in-the-loop | ✅ Interrupts | ✅ Interrupts |
|
115
|
+
| Map-Reduce | ✅ Send commands | ✅ Send API |
|
116
|
+
| Streaming | ✅ Blocks | ✅ AsyncIO |
|
117
|
+
| Visualization | ✅ Mermaid | ✅ Mermaid |
|
118
|
+
|
119
|
+
## Usage Patterns
|
120
|
+
|
121
|
+
### Simple Linear Workflow
|
122
|
+
```ruby
|
123
|
+
graph = LangGraphRB::Graph.new do
|
124
|
+
node :process { |state| { result: process(state[:input]) } }
|
125
|
+
node :validate { |state| { valid: validate(state[:result]) } }
|
126
|
+
|
127
|
+
set_entry_point :process
|
128
|
+
edge :process, :validate
|
129
|
+
set_finish_point :validate
|
130
|
+
end
|
131
|
+
```
|
132
|
+
|
133
|
+
### Conditional Routing
|
134
|
+
```ruby
|
135
|
+
conditional_edge :router, ->(state) {
|
136
|
+
state[:priority] == 'high' ? :urgent_handler : :normal_handler
|
137
|
+
}
|
138
|
+
```
|
139
|
+
|
140
|
+
### Parallel Processing
|
141
|
+
```ruby
|
142
|
+
node :fan_out do |state|
|
143
|
+
sends = state[:items].map do |item|
|
144
|
+
LangGraphRB::Send.new(to: :process_item, payload: { item: item })
|
145
|
+
end
|
146
|
+
LangGraphRB::MultiSend.new(sends)
|
147
|
+
end
|
148
|
+
```
|
149
|
+
|
150
|
+
## Ready for Production Use
|
151
|
+
|
152
|
+
The library provides:
|
153
|
+
- **Robust error handling** with try/catch in node execution
|
154
|
+
- **Persistent checkpointing** for durable workflows
|
155
|
+
- **Thread-safe operations** for concurrent execution
|
156
|
+
- **Memory management** with configurable stores
|
157
|
+
- **Comprehensive validation** at compile time
|
158
|
+
- **Clean abstractions** for extensibility
|
159
|
+
|
160
|
+
## Next Steps for Enhancement
|
161
|
+
|
162
|
+
Potential improvements:
|
163
|
+
- Redis-based store implementation
|
164
|
+
- Built-in LLM client integrations
|
165
|
+
- Web UI for execution monitoring
|
166
|
+
- Metrics and observability
|
167
|
+
- Performance optimizations
|
168
|
+
- Background job integration (Sidekiq)
|
169
|
+
|
170
|
+
The LangGraphRB library successfully replicates the core concepts and capabilities of LangGraph in Ruby, providing a powerful framework for building complex, stateful workflows with parallel execution, persistence, and human-in-the-loop capabilities.
|