ask-graph 0.1.3 → 0.3.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 +4 -4
- data/CHANGELOG.md +66 -0
- data/lib/ask/graph/runner.rb +71 -38
- data/lib/ask/graph/version.rb +1 -1
- data/lib/ask/graph.rb +112 -43
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 59959ae9ec12f0d79aecfe21ae07748baa067bb47efb9c519d291dd352032873
|
|
4
|
+
data.tar.gz: ea54f68d9693259b6fbe2833693391e7844c26b9f442551af09fe3d1e4d6b84d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 221a7565d2feb4ac3769793dbb510687b56f0058bc259ecf94a32acb59e4d8dcebe23a4d7cc14888a6001ffc53a3e06bbc940e45032138dcd734fb6476b76a28
|
|
7
|
+
data.tar.gz: 68e22b21cffae4f146781926d89dd7c767f31234212181ce60707f9dd8e35ec90841f868677517d772a0221ca80fe7a53b15f93a7a067f6c5a280c4ebd5e7ae4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,69 @@
|
|
|
1
|
+
## [0.3.0] — 2026-07-27
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
- **Class-level `timeout`** — set a default timeout for all steps in a graph.
|
|
6
|
+
Steps without an explicit `timeout:` option inherit the class default.
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
class MyGraph < Ask::Graph
|
|
10
|
+
timeout 30
|
|
11
|
+
step FastOp # uses 30s
|
|
12
|
+
step SlowOp, timeout: 120 # overrides
|
|
13
|
+
end
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- **Global default timeout** — `Ask::Graph.timeout 30` applies to all graphs
|
|
17
|
+
that don't set their own `timeout`. Resolution order: step option → graph
|
|
18
|
+
class → `Ask::Graph`.
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
Ask::Graph.timeout 30
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- **Child override and clearing** — child graphs can override or clear
|
|
25
|
+
(`timeout nil`) the parent's default.
|
|
26
|
+
|
|
27
|
+
### Tested
|
|
28
|
+
|
|
29
|
+
- 62 tests, 83 assertions, 0 failures
|
|
30
|
+
|
|
31
|
+
## [0.2.0] — 2026-07-29
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- **Step timeouts** — `step SlowOp, timeout: 30` raises `StepFailed` if a step takes longer than the given seconds.
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
step FetchApi, timeout: 10, retry: 2
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- **Retry policy** — `step FlakyOp, retry: 3` retries failed steps up to the specified number of times with exponential backoff.
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
step ApiCall, retry: 3
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- **Lifecycle hooks** — `before_step`, `after_step`, and `on_failure` hooks for observability, logging, and monitoring.
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
class MyGraph < Ask::Graph
|
|
51
|
+
before_step :log_start
|
|
52
|
+
after_step :log_completion
|
|
53
|
+
on_failure :alert_team
|
|
54
|
+
|
|
55
|
+
step ProcessPayment, timeout: 15, retry: 2
|
|
56
|
+
end
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Hooks receive `declaration:` and `context:` keyword args. `on_failure` also receives `error:`.
|
|
60
|
+
|
|
61
|
+
- **Step metadata** — `step X, description: "Human-readable label"` stores metadata in the declaration for debugging and monitoring.
|
|
62
|
+
|
|
63
|
+
### Tested
|
|
64
|
+
|
|
65
|
+
- 55 tests, 73 assertions, 0 failures
|
|
66
|
+
|
|
1
67
|
## [0.1.3] — 2026-07-28
|
|
2
68
|
|
|
3
69
|
### Changed
|
data/lib/ask/graph/runner.rb
CHANGED
|
@@ -1,41 +1,42 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "timeout"
|
|
4
5
|
|
|
5
6
|
module Ask
|
|
6
7
|
class Graph
|
|
7
8
|
# Error raised when a step fails.
|
|
8
9
|
class StepFailed < StandardError; end
|
|
9
10
|
|
|
11
|
+
# Error raised when a step times out.
|
|
12
|
+
class StepTimeout < StandardError; end
|
|
13
|
+
|
|
10
14
|
# Error raised when a step pauses for human approval.
|
|
11
15
|
class Paused < StandardError; end
|
|
12
16
|
|
|
13
17
|
# Executes the declared steps of a graph, managing checkpointing,
|
|
14
|
-
# condition evaluation, parallel execution,
|
|
15
|
-
#
|
|
16
|
-
# Checkpoints save the full context state after each step so that
|
|
17
|
-
# crashes resume from the last completed step with all data intact.
|
|
18
|
-
# Uses an in-memory store by default; pass a persistent store for
|
|
19
|
-
# crash recovery across restarts.
|
|
18
|
+
# condition evaluation, parallel execution, timeouts, retries,
|
|
19
|
+
# lifecycle hooks, and human-in-the-loop pauses.
|
|
20
20
|
class Runner
|
|
21
|
-
|
|
22
|
-
attr_reader :declarations
|
|
23
|
-
|
|
24
|
-
# @return [#set, #get, #delete] the checkpoint store
|
|
25
|
-
attr_reader :store
|
|
21
|
+
attr_reader :declarations, :store
|
|
26
22
|
|
|
27
23
|
# @param declarations [Array<Hash>] step declarations
|
|
28
|
-
# @param checkpoint_store [#set, #get, #delete] key-value store
|
|
29
|
-
#
|
|
30
|
-
|
|
24
|
+
# @param checkpoint_store [#set, #get, #delete] key-value store
|
|
25
|
+
# @param hooks [Hash] lifecycle hook method names
|
|
26
|
+
# @param graph_instance [Object] the graph instance (for hooks)
|
|
27
|
+
# @param default_timeout [Integer, nil] fallback timeout for steps with no explicit timeout
|
|
28
|
+
def initialize(declarations, checkpoint_store: nil,
|
|
29
|
+
hooks: { before_step: [], after_step: [], on_failure: [] },
|
|
30
|
+
graph_instance: nil,
|
|
31
|
+
default_timeout: nil)
|
|
31
32
|
@declarations = declarations
|
|
32
33
|
@store = checkpoint_store
|
|
34
|
+
@hooks = hooks
|
|
35
|
+
@graph = graph_instance
|
|
36
|
+
@default_timeout = default_timeout
|
|
33
37
|
@completed_steps = []
|
|
34
38
|
end
|
|
35
39
|
|
|
36
|
-
# Run the graph from the beginning or resume from the last checkpoint.
|
|
37
|
-
# @param context [Ask::Graph::Context] the shared context
|
|
38
|
-
# @return [Ask::Graph::Context] the completed context
|
|
39
40
|
def run(context)
|
|
40
41
|
resume_index = load_checkpoint(context)
|
|
41
42
|
|
|
@@ -47,7 +48,10 @@ module Ask
|
|
|
47
48
|
next
|
|
48
49
|
end
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
run_hooks(:before_step, decl, context)
|
|
52
|
+
execute_with_retry(decl, context)
|
|
53
|
+
run_hooks(:after_step, decl, context)
|
|
54
|
+
|
|
51
55
|
record_completion(idx, :completed)
|
|
52
56
|
save_checkpoint(context, idx)
|
|
53
57
|
end
|
|
@@ -55,26 +59,17 @@ module Ask
|
|
|
55
59
|
context
|
|
56
60
|
end
|
|
57
61
|
|
|
58
|
-
# Resume a paused graph with human input.
|
|
59
|
-
# @param context [Ask::Graph::Context] the context at pause point
|
|
60
|
-
# @param input [Object] the human's input
|
|
61
|
-
# @return [Ask::Graph::Context] the completed context
|
|
62
62
|
def resume(context, input:)
|
|
63
63
|
context.resume_input = input
|
|
64
64
|
run(context)
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
# Get the index to resume from for an {Context#each} iteration.
|
|
68
|
-
# @param items [Array] the full list of items
|
|
69
|
-
# @return [Integer, nil] the index to resume from, or nil
|
|
70
67
|
def resume_index_for(items)
|
|
71
68
|
key = each_checkpoint_key
|
|
72
69
|
raw = @store.get(key)
|
|
73
70
|
raw ? raw.to_i : nil
|
|
74
71
|
end
|
|
75
72
|
|
|
76
|
-
# Checkpoint after a single iteration of {Context#each}.
|
|
77
|
-
# @param index [Integer] the completed iteration index
|
|
78
73
|
def checkpoint_each!(index)
|
|
79
74
|
key = each_checkpoint_key
|
|
80
75
|
@store.set(key, index.to_s)
|
|
@@ -82,6 +77,50 @@ module Ask
|
|
|
82
77
|
|
|
83
78
|
private
|
|
84
79
|
|
|
80
|
+
def execute_with_retry(decl, context)
|
|
81
|
+
retries = decl[:retry] || 0
|
|
82
|
+
|
|
83
|
+
(retries + 1).times do |attempt|
|
|
84
|
+
begin
|
|
85
|
+
run_with_timeout(decl, context, decl[:timeout])
|
|
86
|
+
return
|
|
87
|
+
rescue StepFailed => e
|
|
88
|
+
run_hooks(:on_failure, decl, context, error: e)
|
|
89
|
+
raise if attempt >= retries
|
|
90
|
+
sleep backoff_seconds(attempt, decl[:backoff])
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def run_with_timeout(decl, context, timeout_value)
|
|
96
|
+
timeout_value ||= @default_timeout
|
|
97
|
+
if timeout_value
|
|
98
|
+
::Timeout.timeout(timeout_value) { execute_step(decl, context) }
|
|
99
|
+
else
|
|
100
|
+
execute_step(decl, context)
|
|
101
|
+
end
|
|
102
|
+
rescue ::Timeout::Error
|
|
103
|
+
raise StepFailed, "#{decl[:name]} timed out after #{timeout_value}s"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def backoff_seconds(attempt, strategy)
|
|
107
|
+
return 0 if attempt == 0
|
|
108
|
+
case strategy
|
|
109
|
+
when :exponential then 2 ** attempt
|
|
110
|
+
when :constant then 2
|
|
111
|
+
else 2 ** attempt
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def run_hooks(hook_type, decl, context, error: nil)
|
|
116
|
+
@hooks[hook_type]&.each do |method_name|
|
|
117
|
+
next unless @graph&.respond_to?(method_name, true)
|
|
118
|
+
args = { declaration: decl, context: context }
|
|
119
|
+
args[:error] = error if error
|
|
120
|
+
@graph.send(method_name, **args)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
85
124
|
def execute_step(decl, context)
|
|
86
125
|
case decl[:type]
|
|
87
126
|
when :step
|
|
@@ -98,19 +137,17 @@ module Ask
|
|
|
98
137
|
instance.call(context)
|
|
99
138
|
rescue Paused
|
|
100
139
|
raise
|
|
101
|
-
rescue
|
|
140
|
+
rescue => e
|
|
102
141
|
raise StepFailed, "#{klass.name} failed: #{e.message}"
|
|
103
142
|
end
|
|
104
143
|
|
|
105
144
|
def run_parallel(classes, _name, context)
|
|
106
145
|
threads = classes.map do |klass|
|
|
107
146
|
Thread.new do
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
raise StepFailed, "#{klass.name} failed: #{e.message}"
|
|
113
|
-
end
|
|
147
|
+
instance = klass.new
|
|
148
|
+
instance.call(context)
|
|
149
|
+
rescue => e
|
|
150
|
+
raise StepFailed, "#{klass.name} failed: #{e.message}"
|
|
114
151
|
end
|
|
115
152
|
end
|
|
116
153
|
threads.each(&:join)
|
|
@@ -149,8 +186,6 @@ module Ask
|
|
|
149
186
|
"#{checkpoint_key}:each"
|
|
150
187
|
end
|
|
151
188
|
|
|
152
|
-
# Save checkpoint with full context state so resumed graphs
|
|
153
|
-
# have access to all data produced by completed steps.
|
|
154
189
|
def save_checkpoint(context, idx)
|
|
155
190
|
data = {
|
|
156
191
|
completed_index: idx,
|
|
@@ -160,8 +195,6 @@ module Ask
|
|
|
160
195
|
@store.set(checkpoint_key, JSON.generate(data))
|
|
161
196
|
end
|
|
162
197
|
|
|
163
|
-
# Load checkpoint and restore context state if available.
|
|
164
|
-
# Returns the completed_index to skip, or nil for a fresh run.
|
|
165
198
|
def load_checkpoint(context)
|
|
166
199
|
raw = @store.get(checkpoint_key)
|
|
167
200
|
return nil unless raw
|
data/lib/ask/graph/version.rb
CHANGED
data/lib/ask/graph.rb
CHANGED
|
@@ -6,8 +6,8 @@ require_relative "graph/runner"
|
|
|
6
6
|
|
|
7
7
|
module Ask
|
|
8
8
|
# Define durable workflow graphs with named steps, conditional routing,
|
|
9
|
-
# parallel execution, human-in-the-loop approval,
|
|
10
|
-
#
|
|
9
|
+
# parallel execution, human-in-the-loop approval, per-item checkpointing
|
|
10
|
+
# loops, step timeouts, retry policies, and lifecycle hooks.
|
|
11
11
|
#
|
|
12
12
|
# @example Basic workflow
|
|
13
13
|
# class HandleCall < Ask::Graph
|
|
@@ -16,11 +16,21 @@ module Ask
|
|
|
16
16
|
# step BookAppointment
|
|
17
17
|
# end
|
|
18
18
|
#
|
|
19
|
-
#
|
|
19
|
+
# @example With timeout and retry
|
|
20
|
+
# class ApiWorkflow < Ask::Graph
|
|
21
|
+
# step FetchData, timeout: 30, retry: 3
|
|
22
|
+
# step ProcessData, description: "Transform raw data into reports"
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# @example With lifecycle hooks
|
|
26
|
+
# class MonitoredWorkflow < Ask::Graph
|
|
27
|
+
# before_step :log_start
|
|
28
|
+
# after_step :log_completion
|
|
29
|
+
# on_failure :alert_team
|
|
20
30
|
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
31
|
+
# step ValidateOrder
|
|
32
|
+
# step ProcessPayment, timeout: 15, retry: 2
|
|
33
|
+
# end
|
|
24
34
|
#
|
|
25
35
|
class Graph
|
|
26
36
|
class << self
|
|
@@ -33,33 +43,91 @@ module Ask
|
|
|
33
43
|
def inherited(subclass)
|
|
34
44
|
super
|
|
35
45
|
subclass.instance_variable_set(:@declarations, declarations.dup)
|
|
46
|
+
subclass.instance_variable_set(:@lifecycle_hooks, lifecycle_hooks.dup)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# --- Timeout ---
|
|
50
|
+
|
|
51
|
+
# Set or get the default timeout (in seconds) for steps in this graph.
|
|
52
|
+
# Steps without an explicit +timeout:+ option will inherit this value.
|
|
53
|
+
# Setting on {Ask::Graph} itself applies to all graphs that don't set
|
|
54
|
+
# their own default — a global default.
|
|
55
|
+
#
|
|
56
|
+
# @example Global default for all graphs
|
|
57
|
+
# Ask::Graph.timeout 30
|
|
58
|
+
#
|
|
59
|
+
# @example Per-graph override
|
|
60
|
+
# class MyGraph < Ask::Graph
|
|
61
|
+
# timeout 15
|
|
62
|
+
# step FastOp # uses 15s
|
|
63
|
+
# step SlowOp, timeout: 60 # overrides
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# @param seconds [Integer, nil] timeout in seconds, or nil to clear
|
|
67
|
+
# @return [Integer, nil] the current default timeout for this graph
|
|
68
|
+
def timeout(seconds = :not_set)
|
|
69
|
+
if seconds == :not_set
|
|
70
|
+
if instance_variable_defined?(:@timeout)
|
|
71
|
+
@timeout
|
|
72
|
+
elsif superclass.respond_to?(:timeout)
|
|
73
|
+
superclass.timeout
|
|
74
|
+
end
|
|
75
|
+
else
|
|
76
|
+
@timeout = seconds
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# --- Lifecycle hooks ---
|
|
81
|
+
|
|
82
|
+
def lifecycle_hooks
|
|
83
|
+
@lifecycle_hooks ||= { before_step: [], after_step: [], on_failure: [] }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Register a callback to run before every step.
|
|
87
|
+
# @param method_name [Symbol] method name on the graph class
|
|
88
|
+
def before_step(method_name)
|
|
89
|
+
lifecycle_hooks[:before_step] << method_name
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Register a callback to run after every successful step.
|
|
93
|
+
# @param method_name [Symbol] method name on the graph class
|
|
94
|
+
def after_step(method_name)
|
|
95
|
+
lifecycle_hooks[:after_step] << method_name
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Register a callback to run when a step fails.
|
|
99
|
+
# @param method_name [Symbol] method name on the graph class
|
|
100
|
+
def on_failure(method_name)
|
|
101
|
+
lifecycle_hooks[:on_failure] << method_name
|
|
36
102
|
end
|
|
37
103
|
|
|
104
|
+
# --- Step declarations ---
|
|
105
|
+
|
|
38
106
|
# Declare a sequential step.
|
|
39
107
|
#
|
|
40
108
|
# @param klass [Class] a class that responds to +#call(context)+
|
|
41
|
-
# @param conditions [Hash] optional +if:+ or +unless:+ condition method name
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
name: klass.name || klass.to_s,
|
|
47
|
-
if: conditions[:if],
|
|
48
|
-
unless: conditions[:unless]
|
|
49
|
-
}
|
|
109
|
+
# @param conditions [Hash] optional +if:+ or +unless:+ condition method name,
|
|
110
|
+
# +description:+ human-readable label, +timeout:+ seconds,
|
|
111
|
+
# +retry:+ number of retries on failure
|
|
112
|
+
def step(klass, **opts)
|
|
113
|
+
declarations << build_declaration(:step, klass, opts)
|
|
50
114
|
end
|
|
51
115
|
|
|
52
116
|
# Declare parallel steps — all run simultaneously.
|
|
53
117
|
#
|
|
54
118
|
# @param klasses [Array<Class>] step classes to run in parallel
|
|
55
|
-
# @param
|
|
56
|
-
|
|
119
|
+
# @param opts [Hash] optional +if:+, +unless:+, +timeout:+ seconds,
|
|
120
|
+
# +retry:+ number of retries
|
|
121
|
+
def steps(*klasses, **opts)
|
|
57
122
|
declarations << {
|
|
58
123
|
classes: klasses,
|
|
59
124
|
type: :steps,
|
|
60
125
|
name: klasses.map { |k| k.name || k.to_s }.join(", "),
|
|
61
|
-
if:
|
|
62
|
-
unless:
|
|
126
|
+
if: opts[:if],
|
|
127
|
+
unless: opts[:unless],
|
|
128
|
+
description: opts[:description],
|
|
129
|
+
timeout: opts[:timeout],
|
|
130
|
+
retry: opts[:retry]
|
|
63
131
|
}
|
|
64
132
|
end
|
|
65
133
|
|
|
@@ -67,45 +135,49 @@ module Ask
|
|
|
67
135
|
# and waits for external input via {Ask::Graph#resume}.
|
|
68
136
|
#
|
|
69
137
|
# @param klass [Class] a class that responds to +#call(context)+
|
|
70
|
-
# @param
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
type: :approve,
|
|
75
|
-
name: klass.name || klass.to_s,
|
|
76
|
-
if: conditions[:if],
|
|
77
|
-
unless: conditions[:unless]
|
|
78
|
-
}
|
|
138
|
+
# @param opts [Hash] optional +if:+, +unless:+, +description:+,
|
|
139
|
+
# +timeout:+, +retry:+
|
|
140
|
+
def approve(klass, **opts)
|
|
141
|
+
declarations << build_declaration(:approve, klass, opts)
|
|
79
142
|
end
|
|
80
143
|
|
|
81
144
|
# Convenience: create instance and call.
|
|
82
|
-
# @param input [Object] optional input
|
|
83
|
-
# @param checkpoint_store [#set, #get, #delete] optional persistent store
|
|
84
|
-
# @return [Ask::Graph::Context] the completed context
|
|
85
145
|
def call(input = nil, checkpoint_store: nil)
|
|
86
146
|
new(input, checkpoint_store: checkpoint_store).call
|
|
87
147
|
end
|
|
88
148
|
alias run call
|
|
149
|
+
|
|
150
|
+
private
|
|
151
|
+
|
|
152
|
+
def build_declaration(type, klass, opts)
|
|
153
|
+
{
|
|
154
|
+
class: klass,
|
|
155
|
+
type: type,
|
|
156
|
+
name: klass.name || klass.to_s,
|
|
157
|
+
if: opts[:if],
|
|
158
|
+
unless: opts[:unless],
|
|
159
|
+
description: opts[:description],
|
|
160
|
+
timeout: opts[:timeout],
|
|
161
|
+
retry: opts[:retry]
|
|
162
|
+
}
|
|
163
|
+
end
|
|
89
164
|
end
|
|
90
165
|
|
|
91
|
-
# @param input [Object, nil] initial input for the graph execution
|
|
92
|
-
# @param checkpoint_store [#set, #get, #delete, nil] optional persistent store.
|
|
93
|
-
# Defaults to in-memory store. Pass a persistent store for crash recovery.
|
|
94
166
|
def initialize(input = nil, checkpoint_store: nil)
|
|
95
167
|
@input = input
|
|
96
168
|
store = checkpoint_store || Ask::State::Memory.new
|
|
97
|
-
|
|
169
|
+
hooks = self.class.lifecycle_hooks
|
|
170
|
+
@runner = Runner.new(self.class.declarations,
|
|
171
|
+
checkpoint_store: store,
|
|
172
|
+
hooks: hooks,
|
|
173
|
+
graph_instance: self,
|
|
174
|
+
default_timeout: self.class.timeout)
|
|
98
175
|
@context = nil
|
|
99
176
|
end
|
|
100
177
|
|
|
101
|
-
# @return [Ask::Graph::Runner] the runner (exposed for checkpoint coordination)
|
|
102
178
|
attr_reader :runner
|
|
103
|
-
|
|
104
|
-
# @return [Ask::Graph::Context, nil] the shared context
|
|
105
179
|
attr_reader :context
|
|
106
180
|
|
|
107
|
-
# Execute the graph.
|
|
108
|
-
# @return [Ask::Graph::Context] the completed context
|
|
109
181
|
def call
|
|
110
182
|
@context = Context.new(self, @input)
|
|
111
183
|
@runner.run(@context)
|
|
@@ -116,9 +188,6 @@ module Ask
|
|
|
116
188
|
end
|
|
117
189
|
alias run call
|
|
118
190
|
|
|
119
|
-
# Resume a paused graph with human input.
|
|
120
|
-
# @param input [Object] the human's input
|
|
121
|
-
# @return [Ask::Graph::Context] the completed context
|
|
122
191
|
def resume(input:)
|
|
123
192
|
@context.resume_input = input.to_s
|
|
124
193
|
@runner.run(@context)
|