roast-ai 0.4.9 → 0.4.10

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -7
  3. data/Gemfile.lock +14 -2
  4. data/dsl/demo/Gemfile +4 -0
  5. data/dsl/demo/Gemfile.lock +120 -0
  6. data/dsl/demo/cogs/local.rb +15 -0
  7. data/dsl/demo/simple_external_cog.rb +17 -0
  8. data/dsl/plugin-gem-example/.gitignore +8 -0
  9. data/dsl/plugin-gem-example/Gemfile +13 -0
  10. data/dsl/plugin-gem-example/Gemfile.lock +178 -0
  11. data/dsl/plugin-gem-example/lib/other.rb +17 -0
  12. data/dsl/plugin-gem-example/lib/plugin_gem_example.rb +5 -0
  13. data/dsl/plugin-gem-example/lib/simple.rb +15 -0
  14. data/dsl/plugin-gem-example/lib/version.rb +10 -0
  15. data/dsl/plugin-gem-example/plugin-gem-example.gemspec +28 -0
  16. data/dsl/prototype.rb +11 -3
  17. data/dsl/scoped_executors.rb +28 -0
  18. data/dsl/simple_chat.rb +12 -0
  19. data/dsl/step_communication.rb +10 -4
  20. data/lib/roast/dsl/cog/config.rb +6 -1
  21. data/lib/roast/dsl/cog/input.rb +30 -0
  22. data/lib/roast/dsl/cog/output.rb +24 -0
  23. data/lib/roast/dsl/cog/registry.rb +39 -0
  24. data/lib/roast/dsl/cog/stack.rb +2 -1
  25. data/lib/roast/dsl/cog/store.rb +8 -5
  26. data/lib/roast/dsl/cog.rb +49 -28
  27. data/lib/roast/dsl/cog_input_context.rb +9 -0
  28. data/lib/roast/dsl/cog_input_manager.rb +47 -0
  29. data/lib/roast/dsl/cogs/chat.rb +78 -0
  30. data/lib/roast/dsl/cogs/cmd.rb +97 -20
  31. data/lib/roast/dsl/cogs/execute.rb +46 -0
  32. data/lib/roast/dsl/cogs/graph.rb +3 -3
  33. data/lib/roast/dsl/config_context.rb +2 -47
  34. data/lib/roast/dsl/config_manager.rb +96 -0
  35. data/lib/roast/dsl/execution_context.rb +9 -0
  36. data/lib/roast/dsl/execution_manager.rb +137 -0
  37. data/lib/roast/dsl/workflow.rb +113 -0
  38. data/lib/roast/version.rb +1 -1
  39. data/lib/roast.rb +3 -2
  40. data/roast.gemspec +1 -0
  41. data/sorbet/config +1 -0
  42. data/sorbet/rbi/gems/marcel@1.1.0.rbi +239 -0
  43. data/sorbet/rbi/gems/{rack@2.2.18.rbi → rack@2.2.19.rbi} +55 -38
  44. data/sorbet/rbi/gems/ruby_llm@1.8.2.rbi +5703 -0
  45. data/sorbet/rbi/shims/lib/roast/dsl/cog_input_context.rbi +17 -0
  46. data/sorbet/rbi/shims/lib/roast/dsl/config_context.rbi +6 -0
  47. data/sorbet/rbi/shims/lib/roast/dsl/execution_context.rbi +17 -0
  48. metadata +45 -8
  49. data/lib/roast/dsl/cog_execution_context.rb +0 -29
  50. data/lib/roast/dsl/cogs.rb +0 -65
  51. data/lib/roast/dsl/executor.rb +0 -82
  52. data/lib/roast/dsl/workflow_execution_context.rb +0 -47
  53. data/sorbet/rbi/gems/rbs-inline@0.12.0.rbi +0 -2170
  54. data/sorbet/rbi/shims/lib/roast/dsl/workflow_execution_context.rbi +0 -11
@@ -0,0 +1,30 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ class Cog
7
+ # Abstract parent class for inputs provided to a cog when it runs.
8
+ # Cogs should extend this class with their own input types
9
+ # Input classes should be instantiatable with a no-arg constructor,
10
+ # and expose methods to incrementally set their values.
11
+ class Input
12
+ class InputError < Roast::Error; end
13
+ class InvalidInputError < InputError; end
14
+
15
+ # Validate that the input instance has all required parameters set in an acceptable manner.
16
+ # Inheriting cog must implement this for its input class.
17
+ #: () -> void
18
+ def validate!
19
+ raise NotImplementedError
20
+ end
21
+
22
+ # Use the value returned from the cog's input block to attempt to coerce the input to a valid state.
23
+ # to coerce the input to a valid state.
24
+ # Inheriting cog may implement this for its input class; it is optional
25
+ #: (untyped) -> void
26
+ def coerce(input_return_value); end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ class Cog
7
+ # Generic output from running a cog.
8
+ # Cogs should extend this class with their own output types.
9
+ class Output
10
+ #: bool
11
+ attr_reader :success
12
+
13
+ #: bool
14
+ attr_reader :abort
15
+
16
+ #: (?success: bool, ?abort_workflow: bool) -> void
17
+ def initialize(success: true, abort_workflow: false)
18
+ @success = success #: bool
19
+ @abort = abort_workflow #: bool
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,39 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ class Cog
7
+ class Registry
8
+ class CogRegistryError < Roast::Error; end
9
+ class CouldNotDeriveCogNameError < CogRegistryError; end
10
+
11
+ def initialize
12
+ @cogs = {}
13
+ create_registration(Cogs::Cmd)
14
+ create_registration(Cogs::Chat)
15
+ create_registration(Cogs::Execute)
16
+ end
17
+
18
+ #: Hash[Symbol, singleton(Cog)]
19
+ attr_reader :cogs
20
+
21
+ #: (singleton(Roast::DSL::Cog)) -> void
22
+ def use(cog_class)
23
+ reg = create_registration(cog_class)
24
+ cogs[reg.first] = reg.second
25
+ end
26
+
27
+ private
28
+
29
+ #: (singleton(Roast::DSL::Cog)) -> Array(Symbol, singleton(Cog))
30
+ def create_registration(cog_class)
31
+ cog_class_name = cog_class.name
32
+ raise CouldNotDeriveCogNameError if cog_class_name.nil?
33
+
34
+ [cog_class_name.demodulize.underscore.to_sym, cog_class]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -7,8 +7,9 @@ module Roast
7
7
  class Stack
8
8
  delegate :map, :push, :size, :empty?, to: :@queue
9
9
 
10
+ #: () -> void
10
11
  def initialize
11
- @queue = []
12
+ @queue = [] #: Array[Cog]
12
13
  end
13
14
 
14
15
  #: () -> Roast::DSL::Cog?
@@ -9,17 +9,20 @@ module Roast
9
9
 
10
10
  delegate :[], to: :store
11
11
 
12
+ #: Hash[Symbol, Cog]
13
+ attr_reader :store
14
+
15
+ #: () -> void
16
+ def initialize
17
+ @store = {}
18
+ end
19
+
12
20
  #: (Symbol, Roast::DSL::Cog) -> Roast::DSL::Cog
13
21
  def insert(id, inst)
14
22
  raise CogAlreadyDefinedError if store.key?(id)
15
23
 
16
24
  store[id] = inst
17
25
  end
18
-
19
- #: () -> Hash[Symbol, Roast::DSL::Cog]
20
- def store
21
- @store ||= {}
22
- end
23
26
  end
24
27
  end
25
28
  end
data/lib/roast/dsl/cog.rb CHANGED
@@ -4,67 +4,88 @@
4
4
  module Roast
5
5
  module DSL
6
6
  class Cog
7
- class CogAlreadyRanError < StandardError; end
7
+ class CogError < Roast::Error; end
8
8
 
9
- class << self
10
- def on_create
11
- eigen = self
12
- proc do |instance_name = Random.uuid, &action|
13
- #: self as Roast::DSL::WorkflowExecutionContext
14
- add_cog_instance(instance_name, eigen.new(instance_name, action))
15
- end
16
- end
17
-
18
- def on_config
19
- eigen = self
20
- proc do |cog_name = nil, &configuration|
21
- #: self as Roast::DSL::ConfigContext
22
- config_object = if cog_name.nil?
23
- fetch_execution_scope(eigen)
24
- else
25
- fetch_or_create_cog_config(eigen, cog_name)
26
- end
27
-
28
- config_object.instance_exec(&configuration) if configuration
29
- end
30
- end
9
+ class CogAlreadyRanError < CogError; end
31
10
 
11
+ class << self
12
+ #: () -> singleton(Cog::Config)
32
13
  def config_class
33
14
  @config_class ||= find_child_config_or_default
34
15
  end
35
16
 
17
+ #: () -> singleton(Cog::Input)
18
+ def input_class
19
+ @input_class ||= find_child_input_or_default #: singleton(Cog::Input)?
20
+ end
21
+
36
22
  private
37
23
 
24
+ #: () -> singleton(Cog::Config)
38
25
  def find_child_config_or_default
39
26
  config_constant = "#{name}::Config"
40
27
  const_defined?(config_constant) ? const_get(config_constant) : Cog::Config # rubocop:disable Sorbet/ConstantsFromStrings
41
28
  end
29
+
30
+ #: () -> singleton(Cog::Input)
31
+ def find_child_input_or_default
32
+ input_constant = "#{name}::Input"
33
+ const_defined?(input_constant) ? const_get(input_constant) : Cog::Input # rubocop:disable Sorbet/ConstantsFromStrings
34
+ end
42
35
  end
43
36
 
44
- attr_reader :name, :output
37
+ #: Symbol
38
+ attr_reader :name
45
39
 
40
+ #: Cog::Output?
41
+ attr_reader :output
42
+
43
+ #: (Symbol, ^(Cog::Input) -> untyped) -> void
46
44
  def initialize(name, cog_input_proc)
47
45
  @name = name
48
- @cog_input_proc = cog_input_proc
49
- @finished = false
46
+ @cog_input_proc = cog_input_proc #: ^(Cog::Input) -> untyped
47
+ @output = nil #: Cog::Output?
48
+ @finished = false #: bool
49
+
50
+ # Make sure a config is always defined, so we don't have to worry about nils
51
+ @config = self.class.config_class.new #: Cog::Config
50
52
  end
51
53
 
52
- def run!(config, cog_execution_context)
54
+ #: (Cog::Config, CogInputContext) -> void
55
+ def run!(config, input_context)
53
56
  raise CogAlreadyRanError if ran?
54
57
 
55
58
  @config = config
56
- @output = execute(cog_execution_context.instance_exec(&@cog_input_proc))
59
+ input_instance = self.class.input_class.new
60
+ input_return = input_context.instance_exec(input_instance, &@cog_input_proc) if @cog_input_proc
61
+ coerce_and_validate_input!(input_instance, input_return)
62
+ @output = execute(input_instance)
57
63
  @finished = true
58
64
  end
59
65
 
66
+ #: () -> bool
60
67
  def ran?
61
68
  @finished
62
69
  end
63
70
 
64
71
  # Inheriting cog must implement this
72
+ #: (Cog::Input) -> Cog::Output
65
73
  def execute(input)
66
74
  raise NotImplementedError
67
75
  end
76
+
77
+ private
78
+
79
+ #: (Cog::Input, untyped) -> void
80
+ def coerce_and_validate_input!(input, return_value)
81
+ # Check if the input is already valid
82
+ input.validate!
83
+ rescue Cog::Input::InvalidInputError
84
+ # If it's not valid, attempt to coerce if possible
85
+ input.coerce(return_value)
86
+ # Re-validate because coerce! should not be responsible for validation
87
+ input.validate!
88
+ end
68
89
  end
69
90
  end
70
91
  end
@@ -0,0 +1,9 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ # Context in which the individual cog input blocks within the `execute` block of a workflow definition are evaluated
7
+ class CogInputContext; end
8
+ end
9
+ end
@@ -0,0 +1,47 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ # Context in which an individual cog block within the `execute` block of a workflow is evaluated
7
+ class CogInputManager
8
+ class CogOutputAccessError < Roast::Error; end
9
+ class CogNotYetRunError < CogOutputAccessError; end
10
+ class CogNotDefinedError < CogOutputAccessError; end
11
+
12
+ #: (Cog::Registry, Cog::Store) -> void
13
+ def initialize(cog_registry, cogs)
14
+ @cog_registry = cog_registry
15
+ @cogs = cogs
16
+ @context = CogInputContext.new
17
+ bind_registered_cogs
18
+ end
19
+
20
+ #: CogInputContext
21
+ attr_reader :context
22
+
23
+ private
24
+
25
+ #: () -> void
26
+ def bind_registered_cogs
27
+ @cog_registry.cogs.keys.each(&method(:bind_cog))
28
+ end
29
+
30
+ #: (Symbol) -> void
31
+ def bind_cog(cog_method_name)
32
+ cog_output_method = method(:cog_output)
33
+ @context.instance_eval do
34
+ define_singleton_method(cog_method_name, proc { |cog_name| cog_output_method.call(cog_name) })
35
+ end
36
+ end
37
+
38
+ #: (Symbol) -> Cog::Output
39
+ def cog_output(cog_name)
40
+ @cogs[cog_name].tap do |cog|
41
+ raise CogNotYetRunError unless cog.ran?
42
+ raise CogNotDefinedError unless cog.output.present?
43
+ end.output
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,78 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ module Cogs
7
+ class Chat < Cog
8
+ class Input < Cog::Input
9
+ #: String?
10
+ attr_accessor :prompt
11
+
12
+ #: () -> void
13
+ def initialize
14
+ super
15
+ @prompt = nil #: String?
16
+ end
17
+
18
+ #: () -> void
19
+ def validate!
20
+ raise Cog::Input::InvalidInputError, "'prompt' is required" unless prompt.present?
21
+ end
22
+
23
+ #: (untyped) -> void
24
+ def coerce!(input_return_value)
25
+ if input_return_value.is_a?(String)
26
+ self.prompt = input_return_value
27
+ end
28
+ end
29
+ end
30
+
31
+ class Output < Cog::Output
32
+ #: String
33
+ attr_reader :response
34
+
35
+ #: (String response) -> void
36
+ def initialize(response)
37
+ super()
38
+ @response = response
39
+ end
40
+ end
41
+
42
+ class Config < Cog::Config
43
+ #: () -> String?
44
+ def openai_api_key
45
+ @values[:openai_api_key] ||= ENV["OPENAI_API_KEY"]
46
+ end
47
+
48
+ #: () -> String?
49
+ def openai_api_base_url
50
+ @values[:openai_api_base_url] ||= ENV["OPENAI_API_BASE_URL"]
51
+ end
52
+ end
53
+
54
+ #: (Input) -> Output
55
+ def execute(input)
56
+ config = @config #: as Config
57
+ RubyLLM.configure do |ruby_llm_config|
58
+ ruby_llm_config.openai_api_key = config.openai_api_key
59
+ ruby_llm_config.openai_api_base = config.openai_api_base_url
60
+ end
61
+
62
+ chat = RubyLLM.chat
63
+ resp = chat.ask(input.prompt)
64
+ puts "Model: #{resp.model_id}"
65
+ puts "Role: #{resp.role}"
66
+ puts "Input Tokens: #{resp.input_tokens}"
67
+ puts "Output Tokens: #{resp.output_tokens}"
68
+
69
+ chat.messages.each do |message|
70
+ puts "[#{message.role.to_s.upcase}] #{message.content}"
71
+ end
72
+
73
+ Output.new(resp.content)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -5,49 +5,126 @@ module Roast
5
5
  module DSL
6
6
  module Cogs
7
7
  class Cmd < Cog
8
- class Output
8
+ class Input < Cog::Input
9
9
  #: String?
10
- attr_reader :command_output
10
+ attr_accessor :command
11
11
 
12
- #: String?
12
+ #: Array[String]
13
+ attr_accessor :args
14
+
15
+ #: () -> void
16
+ def initialize
17
+ super
18
+ @command = nil
19
+ @args = []
20
+ end
21
+
22
+ #: () -> void
23
+ def validate!
24
+ raise Cog::Input::InvalidInputError, "'command' is required" unless command.present?
25
+ end
26
+
27
+ #: (String | Array[untyped]) -> void
28
+ def coerce(input_return_value)
29
+ case input_return_value
30
+ when String
31
+ self.command = input_return_value
32
+ when Array
33
+ input_return_value.map!(&:to_s)
34
+ self.command = input_return_value.shift
35
+ self.args = input_return_value
36
+ end
37
+ end
38
+ end
39
+
40
+ class Output < Cog::Output
41
+ #: String
42
+ attr_reader :out
43
+
44
+ #: String
13
45
  attr_reader :err
14
46
 
15
- #: Process::Status?
47
+ #: Process::Status
16
48
  attr_reader :status
17
49
 
18
- #: (
19
- #| String? output,
20
- #| String? error,
21
- #| Process::Status? status
22
- #| ) -> void
23
- def initialize(output, error, status)
24
- @command_output = output
25
- @err = error
26
- @status = status
50
+ #: ( String, String, Process::Status) -> void
51
+ def initialize(out, err, status)
52
+ super()
53
+ @out = out #: String
54
+ @err = err #: String
55
+ @status = status #: Process::Status
27
56
  end
28
57
  end
29
58
 
30
59
  class Config < Cog::Config
31
60
  #: () -> void
32
61
  def print_all!
33
- @values[:print_all] = true
62
+ @values[:print_stdout] = true
63
+ @values[:print_stderr] = true
64
+ end
65
+
66
+ #: () -> void
67
+ def print_stdout!
68
+ @values[:print_stdout] = true
69
+ end
70
+
71
+ #: () -> void
72
+ def print_stderr!
73
+ @values[:print_stderr] = true
74
+ end
75
+
76
+ #: () -> bool
77
+ def print_stdout?
78
+ !!@values[:print_stdout]
34
79
  end
35
80
 
36
81
  #: () -> bool
37
- def print_all?
38
- !!@values[:print_all]
82
+ def print_stderr?
83
+ !!@values[:print_stderr]
39
84
  end
40
85
 
86
+ #: () -> void
41
87
  def display!
42
88
  print_all!
43
89
  end
44
90
  end
45
91
 
46
- #: (String) -> Output
92
+ #: (Input) -> Output
47
93
  def execute(input)
48
- result = Output.new(*Roast::Helpers::CmdRunner.capture3(input))
49
- puts result.command_output if @config.print_all?
50
- result
94
+ config = @config #: as Config
95
+ result = T.unsafe(Roast::Helpers::CmdRunner).popen3(input.command, *input.args) do |stdin, stdout, stderr, wait_thread|
96
+ stdin.close
97
+ command_output = ""
98
+ command_error = ""
99
+
100
+ # Thread to read and accumulate stdout
101
+ stdout_thread = Thread.new do
102
+ stdout.each_line do |line|
103
+ command_output += line
104
+ $stdout.puts(line) if config.print_stdout?
105
+ end
106
+ rescue IOError => e
107
+ Roast::Helpers::Logger.debug("IOError while reading stdout: #{e.message}")
108
+ end
109
+
110
+ # Thread to read and accumulate stderr
111
+ stderr_thread = Thread.new do
112
+ stderr.each_line do |line|
113
+ command_error += line
114
+ $stderr.puts(line) if config.print_stderr?
115
+ end
116
+ rescue IOError => e
117
+ Roast::Helpers::Logger.debug("IOError while reading stderr: #{e.message}")
118
+ end
119
+
120
+ # Wait for threads to finish
121
+ stdout_thread.join
122
+ stderr_thread.join
123
+
124
+ [command_output, command_error, wait_thread.value]
125
+ end #: as [String, String, Process::Status]
126
+
127
+ Output.new(*result)
51
128
  end
52
129
  end
53
130
  end
@@ -0,0 +1,46 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ module Cogs
7
+ class Execute < Cog
8
+ class Input < Cog::Input
9
+ #: Symbol?
10
+ attr_accessor :scope
11
+
12
+ #: () -> void
13
+ def initialize
14
+ super
15
+ @scope = nil
16
+ end
17
+
18
+ #: () -> void
19
+ def validate!
20
+ raise Cog::Input::InvalidInputError, "'scope' is required" unless scope.present?
21
+ end
22
+
23
+ #: (Symbol) -> void
24
+ def coerce(input_return_value)
25
+ self.scope = input_return_value
26
+ end
27
+ end
28
+
29
+ #: (Symbol, ^(Input) -> untyped, ^(Input) -> void) -> void
30
+ def initialize(name, cog_input_proc, trigger)
31
+ # NOTE: Sorbet expects the proc passed to super to be declared as taking a Cog::Input explicitly,
32
+ # not a subclass of Cog::Input.
33
+ cog_input_proc = cog_input_proc #: as ^(Cog::Input) -> untyped
34
+ super(name, cog_input_proc)
35
+ @trigger = trigger
36
+ end
37
+
38
+ #: (Input) -> Cog::Output
39
+ def execute(input)
40
+ @trigger.call(input)
41
+ Cog::Output.new
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -8,12 +8,12 @@ module Roast
8
8
  #: Proc
9
9
  attr_reader :block
10
10
 
11
- #: (Symbol) { (Roast::DSL::Cogs::Graph) -> void } -> void
11
+ #: (Symbol) { (Cog::Input) -> untyped } -> void
12
12
  def initialize(name, &block)
13
13
  @name = name
14
14
  @block = block
15
15
  @graph = Roast::Graph.new
16
- super(name, proc {})
16
+ super(name, block)
17
17
  end
18
18
 
19
19
  #: () -> void
@@ -36,7 +36,7 @@ module Roast
36
36
  end
37
37
 
38
38
  # Populates the provided graph in-place, with the definition of how to populate in the block
39
- #: (Roast::DSL::Cogs::Graph) -> void
39
+ #: (Cog::Input) -> void
40
40
  def populate!(graph)
41
41
  return if @block.nil?
42
42
 
@@ -3,52 +3,7 @@
3
3
 
4
4
  module Roast
5
5
  module DSL
6
- class ConfigContext
7
- def initialize(cogs, config_proc)
8
- @cogs = cogs
9
- @executor_scoped_configs = {}
10
- @cog_scoped_configs = {}
11
- @config_proc = config_proc
12
- end
13
-
14
- def fetch_merged_config(cog_class, name = nil)
15
- # All configs have an entry, even if it's empty.
16
- configs = fetch_execution_scope(cog_class)
17
- instance_configs = fetch_cog_config(cog_class, name) unless name.nil?
18
- configs = configs.merge(instance_configs) if instance_configs
19
- configs
20
- end
21
-
22
- def prepare!
23
- bind_default_cogs
24
- instance_eval(&@config_proc)
25
- end
26
-
27
- #: () -> void
28
- def bind_default_cogs
29
- bind_cog(Cogs::Cmd, :cmd)
30
- end
31
-
32
- def fetch_cog_config(cog_class, name)
33
- @cog_scoped_configs[cog_class][name]
34
- end
35
-
36
- def fetch_or_create_cog_config(cog_class, name)
37
- @cog_scoped_configs[cog_class][name] = cog_class.config_class.new unless @cog_scoped_configs.key?(name)
38
- @cog_scoped_configs[cog_class][name]
39
- end
40
-
41
- def fetch_execution_scope(cog_class)
42
- @executor_scoped_configs[cog_class]
43
- end
44
-
45
- def bind_cog(cog_class, method_name)
46
- @cog_scoped_configs[cog_class] = {}
47
- @executor_scoped_configs[cog_class] = cog_class.config_class.new
48
- instance_eval do
49
- define_singleton_method(method_name, &cog_class.on_config)
50
- end
51
- end
52
- end
6
+ # Context in which the `config` blocks of a workflow definition are evaluated
7
+ class ConfigContext; end
53
8
  end
54
9
  end