Skip to content

Commit 5e447f2

Browse files
Update execution context usage (#36)
* update execution context usage * update sequential * update specs and execution_context * Fix tests * Fix tests, issues and remove halt --------- Co-authored-by: Ignacio Perez <ignacio.perez@rootstrap.com>
1 parent 6bce6d4 commit 5e447f2

14 files changed

Lines changed: 74 additions & 307 deletions

lib/mars/agent_step.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ def agent(klass = nil)
88
end
99
end
1010

11-
def run(input)
12-
self.class.agent.new.ask(input).content
11+
def run(context)
12+
self.class.agent.new.ask(context.current_input).content
1313
end
1414
end
1515
end

lib/mars/aggregator.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,15 @@ def initialize(name = "Aggregator", operation: nil, **kwargs)
1010
@operation = operation || ->(inputs) { inputs }
1111
end
1212

13-
def run(inputs)
14-
operation.call(inputs)
13+
def run(context)
14+
context = ensure_context(context)
15+
operation.call(context.current_input)
16+
end
17+
18+
private
19+
20+
def ensure_context(input)
21+
input.is_a?(ExecutionContext) ? input : ExecutionContext.new(input: input)
1522
end
1623
end
1724
end

lib/mars/execution_context.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
module MARS
44
class ExecutionContext
5-
attr_reader :current_input, :outputs, :global_state
5+
attr_reader :outputs, :global_state
6+
attr_accessor :current_input
67

78
def initialize(input: nil, global_state: {})
89
@current_input = input
@@ -19,8 +20,8 @@ def record(step_name, output)
1920
@current_input = output
2021
end
2122

22-
def fork(input: current_input)
23-
self.class.new(input: input, global_state: global_state)
23+
def fork(input: current_input, state: {})
24+
self.class.new(input: input, global_state: global_state.merge(state))
2425
end
2526

2627
def merge(child_contexts)

lib/mars/gate.rb

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,26 @@ def fallback(key, runnable)
1616
def fallbacks_map
1717
@fallbacks_map ||= {}
1818
end
19-
20-
def halt_scope(scope = nil)
21-
scope ? @halt_scope = scope : @halt_scope
22-
end
2319
end
2420

25-
def initialize(name = "Gate", check: nil, fallbacks: nil, halt_scope: nil, **kwargs)
21+
def initialize(name = "Gate", check: nil, fallbacks: nil, **kwargs)
2622
super(name: name, **kwargs)
2723

2824
@check = check || self.class.check_block
2925
@fallbacks = fallbacks || self.class.fallbacks_map
30-
@halt_scope = halt_scope || self.class.halt_scope || :local
3126
end
3227

33-
def run(input)
28+
def run(context)
29+
context = ensure_context(context)
30+
input = context.current_input
3431
result = check.call(input)
3532

3633
return input unless result
3734

3835
branch = fallbacks[result]
3936
raise ArgumentError, "No fallback registered for #{result.inspect}" unless branch
4037

41-
Halt.new(resolve_branch(branch).run(input), scope: @halt_scope)
38+
resolve_branch(branch).run(context)
4239
end
4340

4441
private
@@ -48,5 +45,9 @@ def run(input)
4845
def resolve_branch(branch)
4946
branch.is_a?(Class) ? branch.new : branch
5047
end
48+
49+
def ensure_context(input)
50+
input.is_a?(ExecutionContext) ? input : ExecutionContext.new(input: input)
51+
end
5152
end
5253
end

lib/mars/halt.rb

Lines changed: 0 additions & 15 deletions
This file was deleted.

lib/mars/runnable.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def initialize(name: self.class.step_name, state: {}, formatter: nil)
2626
@formatter = formatter || self.class.formatter&.new || Formatter.new
2727
end
2828

29-
def run(input)
29+
def run(context)
3030
raise NotImplementedError
3131
end
3232
end

lib/mars/workflows/parallel.rb

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,27 @@ def initialize(name, steps:, aggregator: nil, **kwargs)
1010
@aggregator = aggregator || Aggregator.new("#{name} Aggregator")
1111
end
1212

13-
def run(input)
14-
context = ensure_context(input)
13+
def run(context)
14+
context = ensure_context(context)
1515
errors = []
1616
child_contexts = []
1717
results = execute_steps(context, errors, child_contexts)
1818

1919
raise AggregateError, errors if errors.any?
2020

2121
context.merge(child_contexts)
22-
aggregate_results(results)
22+
context.current_input = results
23+
aggregator.run(context)
2324
end
2425

2526
private
2627

2728
attr_reader :steps, :aggregator
2829

29-
def aggregate_results(results)
30-
has_global_halt = results.any? { |r| r.is_a?(Halt) && r.global? }
31-
unwrapped = results.map { |r| r.is_a?(Halt) ? r.result : r }
32-
result = aggregator.run(unwrapped)
33-
has_global_halt ? Halt.new(result, scope: :global) : result
34-
end
35-
3630
def execute_steps(context, errors, child_contexts)
3731
Async do |workflow|
3832
tasks = steps.map do |step|
39-
child_ctx = context.fork
33+
child_ctx = context.fork(state: step.state)
4034
child_contexts << child_ctx
4135

4236
workflow.async do
@@ -54,17 +48,14 @@ def workflow_step(step, child_ctx)
5448
step.run_before_hooks(child_ctx)
5549

5650
step_input = step.formatter.format_input(child_ctx)
57-
result = step.run(step_input)
51+
child_ctx.current_input = step_input
52+
53+
result = step.run(child_ctx)
5854

59-
if result.is_a?(Halt)
60-
step.run_after_hooks(child_ctx, result)
61-
result
62-
else
63-
formatted = step.formatter.format_output(result)
64-
child_ctx.record(step.name, formatted)
65-
step.run_after_hooks(child_ctx, formatted)
66-
formatted
67-
end
55+
formatted = step.formatter.format_output(result)
56+
child_ctx.record(step.name, formatted)
57+
step.run_after_hooks(child_ctx, formatted)
58+
formatted
6859
end
6960

7061
def ensure_context(input)

lib/mars/workflows/sequential.rb

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,16 @@ def initialize(name, steps:, **kwargs)
99
@steps = steps
1010
end
1111

12-
def run(input)
13-
context = ensure_context(input)
12+
def run(context)
13+
context = ensure_context(context)
1414

1515
@steps.each do |step|
1616
step.run_before_hooks(context)
1717

1818
step_input = step.formatter.format_input(context)
19-
result = step.run(step_input)
20-
21-
if result.is_a?(Halt)
22-
if result.global?
23-
step.run_after_hooks(context, result)
24-
return result
25-
end
26-
27-
formatted = step.formatter.format_output(result.result)
28-
context.record(step.name, formatted)
29-
step.run_after_hooks(context, formatted)
30-
break
31-
end
19+
context.current_input = step_input
20+
21+
result = step.run(context)
3222

3323
formatted = step.formatter.format_output(result)
3424
context.record(step.name, formatted)

spec/mars/agent_step_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
it "creates a new agent instance and calls ask" do
4141
step = step_class.new
42-
result = step.run("hello")
42+
result = step.run(MARS::ExecutionContext.new(input: "hello"))
4343

4444
expect(result).to eq("agent response")
4545
expect(mock_agent_class).to have_received(:new)

spec/mars/execution_context_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,13 @@
7979
expect(child.current_input).to eq("custom")
8080
end
8181

82-
it "shares global_state with the parent" do
82+
it "does not share global_state with the parent" do
8383
context = described_class.new(input: "query", global_state: { shared: true })
8484
child = context.fork
8585

8686
child.global_state[:added_by_child] = true
8787

88-
expect(context.global_state[:added_by_child]).to be(true)
88+
expect(context.global_state[:added_by_child]).to be_nil
8989
end
9090

9191
it "has independent outputs from the parent" do

0 commit comments

Comments
 (0)