ask-graph 0.4.0 → 0.5.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 +54 -0
- data/lib/ask/graph/context.rb +22 -1
- data/lib/ask/graph/runner.rb +18 -3
- data/lib/ask/graph/version.rb +1 -1
- data/lib/ask/graph.rb +15 -2
- 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: 5bcdf4454ef1639db46defba3c2b59377dd0aa719036b27be25b77a7a805fdec
|
|
4
|
+
data.tar.gz: eef23d886d551984bbd8f1514e7bdfacc38be0d4b029ec832b1e7c61f2d2036f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bef581ebc5816f79ab0b8d7da98dd9cf53fba824e1e68691e5b39ef8ee0eca3380fa2994dde965ad17db24267f9541b4c537c87fa26a3852ba9fa128afc60237
|
|
7
|
+
data.tar.gz: 78d63a0b802ee4050d09a08ab4d6f62a7fa8e71425745ef055d2f02824c6fb92f48c3149fadb275723aefb93b04bf0a04c258246b115c4ad028b5a56179a9188
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,57 @@
|
|
|
1
|
+
## [0.5.0] — 2026-07-27
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
- **Sub-graph composition** — use any `Ask::Graph` subclass as a step in another
|
|
6
|
+
graph. The sub-graph runs all its internal steps and merges its context back
|
|
7
|
+
into the outer graph.
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
class NotifyCustomer < Ask::Graph
|
|
11
|
+
step SendEmail
|
|
12
|
+
step LogNotification
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class HandleOrder < Ask::Graph
|
|
16
|
+
step ValidatePayment
|
|
17
|
+
step NotifyCustomer # runs the sub-graph, merges its context
|
|
18
|
+
step ShipOrder
|
|
19
|
+
end
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- Sub-graphs read the outer graph's context directly — no special wiring
|
|
23
|
+
- Sub-graph writes are merged back automatically
|
|
24
|
+
- Supports nesting (sub-graphs within sub-graphs)
|
|
25
|
+
- Supports `timeout:`, `retry:`, and `if:`/`unless:` on the outer step
|
|
26
|
+
- Supports parallel steps inside sub-graphs
|
|
27
|
+
- Shares the same `storage` backend with the outer graph
|
|
28
|
+
|
|
29
|
+
- **`Context#export_data`** — returns the raw store hash without JSON
|
|
30
|
+
serialization. Used internally for sub-graph data passing.
|
|
31
|
+
|
|
32
|
+
- **`Context#import(other)`** — merges data from another context or hash
|
|
33
|
+
into this one. Used internally by sub-graph composition.
|
|
34
|
+
|
|
35
|
+
- **Hash inputs now flatten into context keys** — when a Hash is passed as
|
|
36
|
+
input to a graph, its keys are directly accessible on the context in
|
|
37
|
+
addition to `context.input`. This enables sub-graphs to transparently
|
|
38
|
+
read outer context values.
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
g.new({ value: 42 }).call
|
|
42
|
+
ctx.value # => 42 (new — directly accessible)
|
|
43
|
+
ctx.input # => { value: 42 } (still works)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Limitations
|
|
47
|
+
|
|
48
|
+
- Sub-graphs containing `approve` steps are not yet supported and raise
|
|
49
|
+
`ArgumentError`. Nested approval will be added in a future release.
|
|
50
|
+
|
|
51
|
+
### Tested
|
|
52
|
+
|
|
53
|
+
- 87 tests, 114 assertions, 0 failures
|
|
54
|
+
|
|
1
55
|
## [0.4.0] — 2026-07-27
|
|
2
56
|
|
|
3
57
|
### Changed
|
data/lib/ask/graph/context.rb
CHANGED
|
@@ -31,7 +31,12 @@ module Ask
|
|
|
31
31
|
@item = nil
|
|
32
32
|
@mutex = Mutex.new
|
|
33
33
|
@resume_input = nil
|
|
34
|
-
|
|
34
|
+
if input.is_a?(Hash)
|
|
35
|
+
@store[:input] = input
|
|
36
|
+
@store.merge!(input)
|
|
37
|
+
elsif input
|
|
38
|
+
@store[:input] = input
|
|
39
|
+
end
|
|
35
40
|
end
|
|
36
41
|
|
|
37
42
|
# @return [Object, nil] input provided on resume for approval steps
|
|
@@ -102,6 +107,22 @@ module Ask
|
|
|
102
107
|
end
|
|
103
108
|
end
|
|
104
109
|
|
|
110
|
+
# @return [Hash] raw store data with original object references.
|
|
111
|
+
# Unlike {to_h}, this returns the actual Ruby objects without
|
|
112
|
+
# serialization. Useful for passing state to sub-graphs.
|
|
113
|
+
def export_data
|
|
114
|
+
@mutex.synchronize { @store.dup }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Merge data from another context (or hash) into this one.
|
|
118
|
+
# Existing keys in this context are overwritten.
|
|
119
|
+
#
|
|
120
|
+
# @param other [Context, Hash] source of data to merge in
|
|
121
|
+
def import(other)
|
|
122
|
+
data = other.is_a?(Context) ? other.export_data : other
|
|
123
|
+
@mutex.synchronize { @store.merge!(data) }
|
|
124
|
+
end
|
|
125
|
+
|
|
105
126
|
private
|
|
106
127
|
|
|
107
128
|
# Recursively convert a value to a JSON-safe structure.
|
data/lib/ask/graph/runner.rb
CHANGED
|
@@ -133,14 +133,29 @@ module Ask
|
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
def run_single(klass, _name, context)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
if klass < Ask::Graph
|
|
137
|
+
run_subgraph(klass, context)
|
|
138
|
+
else
|
|
139
|
+
instance = klass.new
|
|
140
|
+
instance.call(context)
|
|
141
|
+
end
|
|
142
|
+
rescue Paused, ArgumentError
|
|
139
143
|
raise
|
|
140
144
|
rescue => e
|
|
141
145
|
raise StepFailed, "#{klass.name} failed: #{e.message}"
|
|
142
146
|
end
|
|
143
147
|
|
|
148
|
+
def run_subgraph(klass, context)
|
|
149
|
+
if klass.respond_to?(:declarations) && klass.declarations.any? { |d| d[:type] == :approve }
|
|
150
|
+
raise ArgumentError,
|
|
151
|
+
"#{klass.name} contains approve steps — sub-graphs with approve are not yet supported"
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
sub = klass.new(context.export_data, storage: @store)
|
|
155
|
+
sub_ctx = sub.call
|
|
156
|
+
context.import(sub_ctx) if sub_ctx
|
|
157
|
+
end
|
|
158
|
+
|
|
144
159
|
def run_parallel(classes, _name, context)
|
|
145
160
|
threads = classes.map do |klass|
|
|
146
161
|
Thread.new do
|
data/lib/ask/graph/version.rb
CHANGED
data/lib/ask/graph.rb
CHANGED
|
@@ -6,8 +6,9 @@ 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
|
-
# loops, step timeouts, retry policies, and
|
|
9
|
+
# parallel execution, sub-graph composition, human-in-the-loop approval,
|
|
10
|
+
# per-item checkpointing loops, step timeouts, retry policies, and
|
|
11
|
+
# lifecycle hooks.
|
|
11
12
|
#
|
|
12
13
|
# @example Basic workflow
|
|
13
14
|
# class HandleCall < Ask::Graph
|
|
@@ -16,6 +17,18 @@ module Ask
|
|
|
16
17
|
# step BookAppointment
|
|
17
18
|
# end
|
|
18
19
|
#
|
|
20
|
+
# @example Sub-graph composition (reuse a graph as a step)
|
|
21
|
+
# class NotifyCustomer < Ask::Graph
|
|
22
|
+
# step SendEmail
|
|
23
|
+
# step LogNotification
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# class HandleOrder < Ask::Graph
|
|
27
|
+
# step ValidatePayment
|
|
28
|
+
# step NotifyCustomer # runs the sub-graph, merges its context
|
|
29
|
+
# step ShipOrder
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
19
32
|
# @example With timeout and retry
|
|
20
33
|
# class ApiWorkflow < Ask::Graph
|
|
21
34
|
# step FetchData, timeout: 30, retry: 3
|