Class: LangGraphRB::Graph
- Inherits:
-
Object
- Object
- LangGraphRB::Graph
- Defined in:
- lib/langgraph_rb/graph.rb
Constant Summary collapse
- START =
:__start__
- FINISH =
:__end__
Instance Attribute Summary collapse
-
#compiled ⇒ Object
readonly
Returns the value of attribute compiled.
-
#edges ⇒ Object
readonly
Returns the value of attribute edges.
-
#nodes ⇒ Object
readonly
Returns the value of attribute nodes.
-
#state_class ⇒ Object
readonly
Returns the value of attribute state_class.
Instance Method Summary collapse
-
#compile! ⇒ Object
Compile the graph (validate and prepare for execution).
- #compiled? ⇒ Boolean
- #conditional_edge(from, router, path_map = nil) ⇒ Object
-
#draw_mermaid ⇒ Object
Print Mermaid diagram.
- #edge(from, to) ⇒ Object
- #fan_out_edge(from, destinations) ⇒ Object
-
#get_edges_from(node_name) ⇒ Object
Get all edges from a specific node.
-
#get_next_nodes(from_node) ⇒ Object
Get all possible next nodes from a given node.
-
#initialize(state_class: State, &dsl_block) ⇒ Graph
constructor
A new instance of Graph.
-
#invoke(input_state = {}, context: nil, store: nil, thread_id: nil, observers: []) ⇒ Object
Execute the graph synchronously.
- #llm_node(name, llm_client:, system_prompt: nil, &block) ⇒ Object
-
#node(name, callable = nil, **options, &block) ⇒ Object
DSL Methods for building the graph.
-
#resume(thread_id, input_state = {}, context: nil, store: nil) ⇒ Object
Resume execution from a checkpoint.
-
#set_entry_point(node_name) ⇒ Object
Set the entry point (typically from START).
-
#set_finish_point(node_name) ⇒ Object
Set exit point (typically to FINISH).
-
#stream(input_state = {}, context: nil, store: nil, thread_id: nil, observers: []) ⇒ Object
Stream execution results.
-
#to_mermaid ⇒ Object
Generate Mermaid diagram.
- #tool_node(name, tool:, &block) ⇒ Object
Constructor Details
#initialize(state_class: State, &dsl_block) ⇒ Graph
Returns a new instance of Graph.
11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/langgraph_rb/graph.rb', line 11 def initialize(state_class: State, &dsl_block) @nodes = {} @edges = [] @state_class = state_class @compiled = false # Built-in START and FINISH nodes @nodes[START] = Node.new(START) { |state| state } @nodes[FINISH] = Node.new(FINISH) { |state| state } instance_eval(&dsl_block) if dsl_block end |
Instance Attribute Details
#compiled ⇒ Object (readonly)
Returns the value of attribute compiled.
9 10 11 |
# File 'lib/langgraph_rb/graph.rb', line 9 def compiled @compiled end |
#edges ⇒ Object (readonly)
Returns the value of attribute edges.
9 10 11 |
# File 'lib/langgraph_rb/graph.rb', line 9 def edges @edges end |
#nodes ⇒ Object (readonly)
Returns the value of attribute nodes.
9 10 11 |
# File 'lib/langgraph_rb/graph.rb', line 9 def nodes @nodes end |
#state_class ⇒ Object (readonly)
Returns the value of attribute state_class.
9 10 11 |
# File 'lib/langgraph_rb/graph.rb', line 9 def state_class @state_class end |
Instance Method Details
#compile! ⇒ Object
Compile the graph (validate and prepare for execution)
88 89 90 91 92 |
# File 'lib/langgraph_rb/graph.rb', line 88 def compile! validate_graph! @compiled = true self end |
#compiled? ⇒ Boolean
94 95 96 |
# File 'lib/langgraph_rb/graph.rb', line 94 def compiled? @compiled end |
#conditional_edge(from, router, path_map = nil) ⇒ Object
60 61 62 63 64 65 |
# File 'lib/langgraph_rb/graph.rb', line 60 def conditional_edge(from, router, path_map = nil) from = from.to_sym validate_node_exists!(from) @edges << ConditionalEdge.new(from, router, path_map) end |
#draw_mermaid ⇒ Object
Print Mermaid diagram
164 165 166 |
# File 'lib/langgraph_rb/graph.rb', line 164 def draw_mermaid puts to_mermaid end |
#edge(from, to) ⇒ Object
52 53 54 55 56 57 58 |
# File 'lib/langgraph_rb/graph.rb', line 52 def edge(from, to) from, to = from.to_sym, to.to_sym validate_node_exists!(from) validate_node_exists!(to) @edges << Edge.new(from, to) end |
#fan_out_edge(from, destinations) ⇒ Object
67 68 69 70 71 72 73 74 75 |
# File 'lib/langgraph_rb/graph.rb', line 67 def fan_out_edge(from, destinations) from = from.to_sym validate_node_exists!(from) destinations = destinations.map(&:to_sym) destinations.each { |dest| validate_node_exists!(dest) } @edges << FanOutEdge.new(from, destinations) end |
#get_edges_from(node_name) ⇒ Object
Get all edges from a specific node
189 190 191 192 |
# File 'lib/langgraph_rb/graph.rb', line 189 def get_edges_from(node_name) node_name = node_name.to_sym @edges.select { |edge| edge.from == node_name } end |
#get_next_nodes(from_node) ⇒ Object
Get all possible next nodes from a given node
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/langgraph_rb/graph.rb', line 169 def get_next_nodes(from_node) from_node = from_node.to_sym next_nodes = [] @edges.each do |edge| if edge.from == from_node case edge when Edge next_nodes << edge.to when ConditionalEdge, FanOutEdge # These require runtime evaluation next_nodes << :conditional end end end next_nodes.uniq end |
#invoke(input_state = {}, context: nil, store: nil, thread_id: nil, observers: []) ⇒ Object
Execute the graph synchronously
99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/langgraph_rb/graph.rb', line 99 def invoke(input_state = {}, context: nil, store: nil, thread_id: nil, observers: []) raise GraphError, "Graph must be compiled before execution" unless compiled? store ||= Stores::InMemoryStore.new thread_id ||= SecureRandom.hex(8) initial_state = @state_class.new(input_state) Runner.new(self, store: store, thread_id: thread_id, observers: observers) .invoke(initial_state, context: context) end |
#llm_node(name, llm_client:, system_prompt: nil, &block) ⇒ Object
38 39 40 41 42 43 |
# File 'lib/langgraph_rb/graph.rb', line 38 def llm_node(name, llm_client:, system_prompt: nil, &block) name = name.to_sym raise GraphError, "Node '#{name}' already exists" if @nodes.key?(name) @nodes[name] = LLMNode.new(name, llm_client: llm_client, system_prompt: system_prompt, &block) end |
#node(name, callable = nil, **options, &block) ⇒ Object
DSL Methods for building the graph
25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/langgraph_rb/graph.rb', line 25 def node(name, callable = nil, **, &block) name = name.to_sym raise GraphError, "Node '#{name}' already exists" if @nodes.key?(name) if callable.respond_to?(:call) @nodes[name] = Node.new(name, callable) elsif block @nodes[name] = Node.new(name, &block) else raise GraphError, "Node '#{name}' must have a callable or block" end end |
#resume(thread_id, input_state = {}, context: nil, store: nil) ⇒ Object
Resume execution from a checkpoint
125 126 127 128 129 130 |
# File 'lib/langgraph_rb/graph.rb', line 125 def resume(thread_id, input_state = {}, context: nil, store: nil) raise GraphError, "Graph must be compiled before execution" unless compiled? raise GraphError, "Store required for resuming execution" unless store Runner.new(self, store: store, thread_id: thread_id).resume(input_state, context: context) end |
#set_entry_point(node_name) ⇒ Object
Set the entry point (typically from START)
78 79 80 |
# File 'lib/langgraph_rb/graph.rb', line 78 def set_entry_point(node_name) edge(START, node_name) end |
#set_finish_point(node_name) ⇒ Object
Set exit point (typically to FINISH)
83 84 85 |
# File 'lib/langgraph_rb/graph.rb', line 83 def set_finish_point(node_name) edge(node_name, FINISH) end |
#stream(input_state = {}, context: nil, store: nil, thread_id: nil, observers: []) ⇒ Object
Stream execution results
112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/langgraph_rb/graph.rb', line 112 def stream(input_state = {}, context: nil, store: nil, thread_id: nil, observers: []) raise GraphError, "Graph must be compiled before execution" unless compiled? store ||= Stores::InMemoryStore.new thread_id ||= SecureRandom.hex(8) initial_state = @state_class.new(input_state) Runner.new(self, store: store, thread_id: thread_id, observers: observers) .stream(initial_state, context: context) end |
#to_mermaid ⇒ Object
Generate Mermaid diagram
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/langgraph_rb/graph.rb', line 133 def to_mermaid lines = ["graph TD"] # Add nodes @nodes.each do |name, node| next if [START, FINISH].include?(name) lines << " #{name}[\"#{name}\"]" end # Add special nodes lines << " #{START}((START))" lines << " #{FINISH}((FINISH))" # Add edges @edges.each do |edge| case edge when Edge lines << " #{edge.from} --> #{edge.to}" when ConditionalEdge lines << " #{edge.from} --> |condition| #{edge.from}_decision{condition}" when FanOutEdge edge.destinations.each do |dest| lines << " #{edge.from} --> #{dest}" end end end lines.join("\n") end |
#tool_node(name, tool:, &block) ⇒ Object
45 46 47 48 49 50 |
# File 'lib/langgraph_rb/graph.rb', line 45 def tool_node(name, tool:, &block) name = name.to_sym raise GraphError, "Node '#{name}' already exists" if @nodes.key?(name) @nodes[name] = ToolNode.new(name, tool: tool, &block) end |