roast-ai 0.2.3 → 0.3.1

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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/CLAUDE.md +3 -1
  4. data/Gemfile +1 -0
  5. data/Gemfile.lock +15 -10
  6. data/README.md +214 -20
  7. data/bin/roast +1 -1
  8. data/examples/bash_prototyping/README.md +53 -0
  9. data/examples/bash_prototyping/analyze_network/prompt.md +13 -0
  10. data/examples/bash_prototyping/analyze_system/prompt.md +11 -0
  11. data/examples/bash_prototyping/api_testing.yml +14 -0
  12. data/examples/bash_prototyping/check_processes/prompt.md +11 -0
  13. data/examples/bash_prototyping/generate_report/prompt.md +16 -0
  14. data/examples/bash_prototyping/process_json_response/prompt.md +24 -0
  15. data/examples/bash_prototyping/system_analysis.yml +14 -0
  16. data/examples/bash_prototyping/test_public_api/prompt.md +22 -0
  17. data/examples/cmd/README.md +99 -0
  18. data/examples/cmd/analyze_project/prompt.md +57 -0
  19. data/examples/cmd/basic_demo/prompt.md +48 -0
  20. data/examples/cmd/basic_workflow.yml +17 -0
  21. data/examples/cmd/check_repository/prompt.md +57 -0
  22. data/examples/cmd/create_and_verify/prompt.md +56 -0
  23. data/examples/cmd/dev_workflow.yml +26 -0
  24. data/examples/cmd/explore_project/prompt.md +67 -0
  25. data/examples/cmd/explorer_workflow.yml +21 -0
  26. data/examples/cmd/smart_tool_selection/prompt.md +99 -0
  27. data/examples/grading/README.md +71 -0
  28. data/examples/grading/read_dependencies/prompt.md +4 -2
  29. data/examples/grading/run_coverage.rb +9 -0
  30. data/examples/grading/workflow.yml +0 -2
  31. data/examples/mcp/README.md +223 -0
  32. data/examples/mcp/analyze_changes/prompt.md +8 -0
  33. data/examples/mcp/analyze_issues/prompt.md +4 -0
  34. data/examples/mcp/analyze_schema/prompt.md +4 -0
  35. data/examples/mcp/check_data_quality/prompt.md +5 -0
  36. data/examples/mcp/check_documentation/prompt.md +4 -0
  37. data/examples/mcp/create_recommendations/prompt.md +5 -0
  38. data/examples/mcp/database_workflow.yml +29 -0
  39. data/examples/mcp/env_demo/workflow.yml +34 -0
  40. data/examples/mcp/fetch_pr_context/prompt.md +4 -0
  41. data/examples/mcp/filesystem_demo/create_test_file/prompt.md +2 -0
  42. data/examples/mcp/filesystem_demo/list_files/prompt.md +6 -0
  43. data/examples/mcp/filesystem_demo/read_with_mcp/prompt.md +7 -0
  44. data/examples/mcp/filesystem_demo/workflow.yml +38 -0
  45. data/examples/mcp/generate_insights/prompt.md +4 -0
  46. data/examples/mcp/generate_report/prompt.md +6 -0
  47. data/examples/mcp/generate_review/prompt.md +16 -0
  48. data/examples/mcp/github_workflow.yml +32 -0
  49. data/examples/mcp/multi_mcp_workflow.yml +58 -0
  50. data/examples/mcp/post_review/prompt.md +3 -0
  51. data/examples/mcp/save_report/prompt.md +6 -0
  52. data/examples/mcp/search_issues/prompt.md +2 -0
  53. data/examples/mcp/summarize/prompt.md +1 -0
  54. data/examples/mcp/test_filesystem/prompt.md +6 -0
  55. data/examples/mcp/test_github/prompt.md +8 -0
  56. data/examples/mcp/test_read/prompt.md +1 -0
  57. data/examples/mcp/workflow.yml +35 -0
  58. data/examples/shared_config/README.md +52 -0
  59. data/examples/shared_config/example_with_shared_config/workflow.yml +6 -0
  60. data/examples/shared_config/shared.yml +7 -0
  61. data/examples/step_configuration/README.md +0 -3
  62. data/examples/step_configuration/workflow.yml +0 -3
  63. data/examples/tool_config_example/README.md +109 -0
  64. data/examples/tool_config_example/example_step/prompt.md +42 -0
  65. data/examples/tool_config_example/workflow.yml +17 -0
  66. data/examples/workflow_generator/workflow.yml +0 -1
  67. data/lib/roast/helpers/function_caching_interceptor.rb +0 -4
  68. data/lib/roast/helpers/prompt_loader.rb +0 -1
  69. data/lib/roast/tools/bash.rb +62 -0
  70. data/lib/roast/tools/cmd.rb +121 -34
  71. data/lib/roast/tools/coding_agent.rb +86 -7
  72. data/lib/roast/tools/helpers/coding_agent_message_formatter.rb +87 -0
  73. data/lib/roast/tools/search_file.rb +13 -1
  74. data/lib/roast/tools.rb +5 -5
  75. data/lib/roast/version.rb +1 -1
  76. data/lib/roast/workflow/base_step.rb +29 -21
  77. data/lib/roast/workflow/base_workflow.rb +8 -10
  78. data/lib/roast/workflow/configuration.rb +68 -3
  79. data/lib/roast/workflow/configuration_loader.rb +63 -4
  80. data/lib/roast/workflow/configuration_parser.rb +0 -3
  81. data/lib/roast/workflow/error_handler.rb +0 -1
  82. data/lib/roast/workflow/file_state_repository.rb +0 -1
  83. data/lib/roast/workflow/iteration_executor.rb +0 -1
  84. data/lib/roast/workflow/output_manager.rb +0 -1
  85. data/lib/roast/workflow/prompt_step.rb +1 -1
  86. data/lib/roast/workflow/step_executor_coordinator.rb +5 -3
  87. data/lib/roast/workflow/step_executors/hash_step_executor.rb +1 -1
  88. data/lib/roast/workflow/step_loader.rb +35 -8
  89. data/lib/roast/workflow/step_orchestrator.rb +4 -2
  90. data/lib/roast/workflow/workflow_execution_context.rb +0 -2
  91. data/lib/roast/workflow/workflow_executor.rb +1 -3
  92. data/lib/roast/workflow/workflow_initializer.rb +66 -2
  93. data/lib/roast/workflow/workflow_runner.rb +1 -2
  94. data/lib/roast.rb +8 -0
  95. data/package-lock.json +6 -0
  96. data/roast.gemspec +2 -1
  97. metadata +73 -3
@@ -22,13 +22,15 @@ module Roast
22
22
  @workflow_executor = workflow_executor
23
23
  end
24
24
 
25
- def execute_step(name, exit_on_error: true)
25
+ def execute_step(name, exit_on_error: true, step_key: nil)
26
26
  resource_type = @workflow.respond_to?(:resource) ? @workflow.resource&.type : nil
27
27
 
28
28
  @error_handler.with_error_handling(name, resource_type: resource_type) do
29
29
  $stderr.puts "Executing: #{name} (Resource type: #{resource_type || "unknown"})"
30
30
 
31
- step_object = @step_loader.load(name)
31
+ # Use step_key for loading if provided, otherwise use name
32
+ load_key = step_key || name
33
+ step_object = @step_loader.load(name, step_key: load_key)
32
34
  step_result = step_object.call
33
35
 
34
36
  # Store result in workflow output
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/string/inflections"
4
-
5
3
  module Roast
6
4
  module Workflow
7
5
  # Manages execution context across pre-processing, target workflows, and post-processing phases
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "English"
4
- require "active_support"
5
- require "active_support/isolated_execution_state"
6
- require "active_support/notifications"
4
+
7
5
  require "roast/workflow/command_executor"
8
6
  require "roast/workflow/conditional_executor"
9
7
  require "roast/workflow/error_handler"
@@ -5,6 +5,7 @@ require "roast/initializers"
5
5
  require "roast/helpers/function_caching_interceptor"
6
6
  require "roast/helpers/logger"
7
7
  require "roast/workflow/base_workflow"
8
+ require "roast/workflow/interpolator"
8
9
 
9
10
  module Roast
10
11
  module Workflow
@@ -27,11 +28,57 @@ module Roast
27
28
  end
28
29
 
29
30
  def include_tools
30
- return unless @configuration.tools.present?
31
+ return unless @configuration.tools.present? || @configuration.mcp_tools.present?
31
32
 
32
33
  BaseWorkflow.include(Raix::FunctionDispatch)
33
34
  BaseWorkflow.include(Roast::Helpers::FunctionCachingInterceptor) # Add caching support
34
- BaseWorkflow.include(*@configuration.tools.map(&:constantize))
35
+
36
+ if @configuration.tools.present?
37
+ BaseWorkflow.include(*@configuration.tools.map(&:constantize))
38
+ end
39
+
40
+ if @configuration.mcp_tools.present?
41
+ BaseWorkflow.include(Raix::MCP)
42
+
43
+ # Create an interpolator for MCP tool configuration
44
+ # We use Object.new as the context because this interpolation happens during
45
+ # initialization, before any workflow instance exists. Since we don't have
46
+ # a workflow instance yet, we use a minimal object that can still evaluate
47
+ # Ruby expressions like ENV['HOME'] or any other valid Ruby code.
48
+ interpolator = Interpolator.new(Object.new)
49
+
50
+ @configuration.mcp_tools.each do |tool|
51
+ # Interpolate the config values
52
+ config = interpolate_config(tool.config, interpolator)
53
+
54
+ # Create the appropriate client based on config
55
+ client = if config["url"]
56
+ Raix::MCP::SseClient.new(
57
+ config["url"],
58
+ headers: config["env"] || {},
59
+ )
60
+ elsif config["command"]
61
+ args = [config["command"]]
62
+ args += config["args"] if config["args"]
63
+ Raix::MCP::StdioClient.new(*args, config["env"] || {})
64
+ end
65
+
66
+ BaseWorkflow.mcp(client: client, only: tool.only, except: tool.except)
67
+ end
68
+ end
69
+
70
+ post_configure_tools
71
+ end
72
+
73
+ def post_configure_tools
74
+ @configuration.tools.each do |tool_name|
75
+ tool_module = tool_name.constantize
76
+
77
+ if tool_module.respond_to?(:post_configuration_setup)
78
+ tool_config = @configuration.tool_config(tool_name)
79
+ tool_module.post_configuration_setup(BaseWorkflow, tool_config)
80
+ end
81
+ end
35
82
  end
36
83
 
37
84
  def configure_api_client
@@ -116,6 +163,23 @@ module Roast
116
163
  # Make a lightweight API call to validate the token
117
164
  client.models.list if client.respond_to?(:models)
118
165
  end
166
+
167
+ def interpolate_config(config, interpolator)
168
+ interpolated = {}
169
+ config.each do |key, value|
170
+ interpolated[key] = case value
171
+ when String
172
+ interpolator.interpolate(value)
173
+ when Array
174
+ value.map { |v| v.is_a?(String) ? interpolator.interpolate(v) : v }
175
+ when Hash
176
+ interpolate_config(value, interpolator)
177
+ else
178
+ value
179
+ end
180
+ end
181
+ interpolated
182
+ end
119
183
  end
120
184
  end
121
185
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/notifications"
4
3
  require "erb"
5
4
  require "roast/workflow/replay_handler"
6
5
  require "roast/workflow/workflow_executor"
@@ -168,7 +167,7 @@ module Roast
168
167
  context_path: @configuration.context_path,
169
168
  resource: @configuration.resource,
170
169
  session_name: @configuration.name,
171
- configuration: @configuration,
170
+ workflow_configuration: @configuration,
172
171
  pre_processing_data:,
173
172
  ).tap do |workflow|
174
173
  workflow.output_file = @options[:output] if @options[:output].present?
data/lib/roast.rb CHANGED
@@ -1,5 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support"
4
+ require "active_support/cache"
5
+ require "active_support/notifications"
6
+ require "active_support/core_ext/hash/indifferent_access"
7
+ require "active_support/core_ext/string"
8
+ require "active_support/core_ext/string/inflections"
9
+ require "active_support/core_ext/module/delegation"
10
+ require "active_support/isolated_execution_state"
3
11
  require "fileutils"
4
12
  require "cli/ui"
5
13
  require "raix"
data/package-lock.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "roast",
3
+ "lockfileVersion": 3,
4
+ "requires": true,
5
+ "packages": {}
6
+ }
data/roast.gemspec CHANGED
@@ -41,6 +41,7 @@ Gem::Specification.new do |spec|
41
41
  spec.add_dependency("diff-lcs", "~> 1.5")
42
42
  spec.add_dependency("faraday-retry")
43
43
  spec.add_dependency("json-schema")
44
- spec.add_dependency("raix", "~> 0.8.6")
44
+ spec.add_dependency("open_router", "~> 0.3")
45
+ spec.add_dependency("raix", "~> 1.0")
45
46
  spec.add_dependency("thor", "~> 1.3")
46
47
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roast-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
@@ -79,20 +79,34 @@ dependencies:
79
79
  - - ">="
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: open_router
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.3'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.3'
82
96
  - !ruby/object:Gem::Dependency
83
97
  name: raix
84
98
  requirement: !ruby/object:Gem::Requirement
85
99
  requirements:
86
100
  - - "~>"
87
101
  - !ruby/object:Gem::Version
88
- version: 0.8.6
102
+ version: '1.0'
89
103
  type: :runtime
90
104
  prerelease: false
91
105
  version_requirements: !ruby/object:Gem::Requirement
92
106
  requirements:
93
107
  - - "~>"
94
108
  - !ruby/object:Gem::Version
95
- version: 0.8.6
109
+ version: '1.0'
96
110
  - !ruby/object:Gem::Dependency
97
111
  name: thor
98
112
  requirement: !ruby/object:Gem::Requirement
@@ -142,9 +156,28 @@ files:
142
156
  - examples/api_workflow/prompt.md
143
157
  - examples/api_workflow/transform_data/prompt.md
144
158
  - examples/api_workflow/workflow.yml
159
+ - examples/bash_prototyping/README.md
160
+ - examples/bash_prototyping/analyze_network/prompt.md
161
+ - examples/bash_prototyping/analyze_system/prompt.md
162
+ - examples/bash_prototyping/api_testing.yml
163
+ - examples/bash_prototyping/check_processes/prompt.md
164
+ - examples/bash_prototyping/generate_report/prompt.md
165
+ - examples/bash_prototyping/process_json_response/prompt.md
166
+ - examples/bash_prototyping/system_analysis.yml
167
+ - examples/bash_prototyping/test_public_api/prompt.md
145
168
  - examples/case_when/README.md
146
169
  - examples/case_when/detect_language/prompt.md
147
170
  - examples/case_when/workflow.yml
171
+ - examples/cmd/README.md
172
+ - examples/cmd/analyze_project/prompt.md
173
+ - examples/cmd/basic_demo/prompt.md
174
+ - examples/cmd/basic_workflow.yml
175
+ - examples/cmd/check_repository/prompt.md
176
+ - examples/cmd/create_and_verify/prompt.md
177
+ - examples/cmd/dev_workflow.yml
178
+ - examples/cmd/explore_project/prompt.md
179
+ - examples/cmd/explorer_workflow.yml
180
+ - examples/cmd/smart_tool_selection/prompt.md
148
181
  - examples/conditional/README.md
149
182
  - examples/conditional/check_condition/prompt.md
150
183
  - examples/conditional/simple_workflow.yml
@@ -157,6 +190,7 @@ files:
157
190
  - examples/exit_on_error/analyze_lint_output/prompt.md
158
191
  - examples/exit_on_error/apply_fixes/prompt.md
159
192
  - examples/exit_on_error/workflow.yml
193
+ - examples/grading/README.md
160
194
  - examples/grading/analyze_coverage/prompt.md
161
195
  - examples/grading/calculate_final_grade.rb
162
196
  - examples/grading/format_result.rb
@@ -203,6 +237,33 @@ files:
203
237
  - examples/iteration/workflow.yml
204
238
  - examples/json_handling/README.md
205
239
  - examples/json_handling/workflow.yml
240
+ - examples/mcp/README.md
241
+ - examples/mcp/analyze_changes/prompt.md
242
+ - examples/mcp/analyze_issues/prompt.md
243
+ - examples/mcp/analyze_schema/prompt.md
244
+ - examples/mcp/check_data_quality/prompt.md
245
+ - examples/mcp/check_documentation/prompt.md
246
+ - examples/mcp/create_recommendations/prompt.md
247
+ - examples/mcp/database_workflow.yml
248
+ - examples/mcp/env_demo/workflow.yml
249
+ - examples/mcp/fetch_pr_context/prompt.md
250
+ - examples/mcp/filesystem_demo/create_test_file/prompt.md
251
+ - examples/mcp/filesystem_demo/list_files/prompt.md
252
+ - examples/mcp/filesystem_demo/read_with_mcp/prompt.md
253
+ - examples/mcp/filesystem_demo/workflow.yml
254
+ - examples/mcp/generate_insights/prompt.md
255
+ - examples/mcp/generate_report/prompt.md
256
+ - examples/mcp/generate_review/prompt.md
257
+ - examples/mcp/github_workflow.yml
258
+ - examples/mcp/multi_mcp_workflow.yml
259
+ - examples/mcp/post_review/prompt.md
260
+ - examples/mcp/save_report/prompt.md
261
+ - examples/mcp/search_issues/prompt.md
262
+ - examples/mcp/summarize/prompt.md
263
+ - examples/mcp/test_filesystem/prompt.md
264
+ - examples/mcp/test_github/prompt.md
265
+ - examples/mcp/test_read/prompt.md
266
+ - examples/mcp/workflow.yml
206
267
  - examples/openrouter_example/README.md
207
268
  - examples/openrouter_example/analyze_input/prompt.md
208
269
  - examples/openrouter_example/generate_response/prompt.md
@@ -225,6 +286,9 @@ files:
225
286
  - examples/rspec_to_minitest/run_and_improve/prompt.md
226
287
  - examples/rspec_to_minitest/workflow.md
227
288
  - examples/rspec_to_minitest/workflow.yml
289
+ - examples/shared_config/README.md
290
+ - examples/shared_config/example_with_shared_config/workflow.yml
291
+ - examples/shared_config/shared.yml
228
292
  - examples/single_target_prepost/README.md
229
293
  - examples/single_target_prepost/post_processing/output.txt
230
294
  - examples/single_target_prepost/pre_processing/gather_dependencies/prompt.md
@@ -233,6 +297,9 @@ files:
233
297
  - examples/smart_coercion_defaults/workflow.yml
234
298
  - examples/step_configuration/README.md
235
299
  - examples/step_configuration/workflow.yml
300
+ - examples/tool_config_example/README.md
301
+ - examples/tool_config_example/example_step/prompt.md
302
+ - examples/tool_config_example/workflow.yml
236
303
  - examples/workflow_generator/README.md
237
304
  - examples/workflow_generator/analyze_user_request/prompt.md
238
305
  - examples/workflow_generator/create_workflow_files/prompt.md
@@ -261,9 +328,11 @@ files:
261
328
  - lib/roast/resources/url_resource.rb
262
329
  - lib/roast/tools.rb
263
330
  - lib/roast/tools/ask_user.rb
331
+ - lib/roast/tools/bash.rb
264
332
  - lib/roast/tools/cmd.rb
265
333
  - lib/roast/tools/coding_agent.rb
266
334
  - lib/roast/tools/grep.rb
335
+ - lib/roast/tools/helpers/coding_agent_message_formatter.rb
267
336
  - lib/roast/tools/read_file.rb
268
337
  - lib/roast/tools/search_file.rb
269
338
  - lib/roast/tools/update_files.rb
@@ -325,6 +394,7 @@ files:
325
394
  - lib/roast/workflow/workflow_executor.rb
326
395
  - lib/roast/workflow/workflow_initializer.rb
327
396
  - lib/roast/workflow/workflow_runner.rb
397
+ - package-lock.json
328
398
  - roast.gemspec
329
399
  - schema/workflow.json
330
400
  - shipit.rubygems.yml