roast-ai 0.4.10 → 0.5.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 (175) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/commands/docs/write-comments.md +36 -0
  3. data/.github/CODEOWNERS +1 -1
  4. data/.github/workflows/ci.yaml +10 -6
  5. data/.gitignore +0 -1
  6. data/.rubocop.yml +7 -1
  7. data/.ruby-version +1 -1
  8. data/CLAUDE.md +2 -2
  9. data/CONTRIBUTING.md +2 -0
  10. data/Gemfile +19 -18
  11. data/Gemfile.lock +35 -58
  12. data/README.md +118 -1432
  13. data/README_LEGACY.md +1464 -0
  14. data/Rakefile +39 -4
  15. data/dev.yml +29 -0
  16. data/dsl/agent_sessions.rb +20 -0
  17. data/dsl/async_cogs.rb +49 -0
  18. data/dsl/async_cogs_complex.rb +67 -0
  19. data/dsl/call.rb +44 -0
  20. data/dsl/collect_from.rb +72 -0
  21. data/dsl/json_output.rb +28 -0
  22. data/dsl/map.rb +55 -0
  23. data/dsl/map_reduce.rb +37 -0
  24. data/dsl/map_with_index.rb +49 -0
  25. data/dsl/next_break.rb +45 -0
  26. data/dsl/next_break_parallel.rb +44 -0
  27. data/dsl/outputs.rb +39 -0
  28. data/dsl/outputs_bang.rb +36 -0
  29. data/dsl/parallel_map.rb +37 -0
  30. data/dsl/prompts/simple_prompt.md.erb +3 -0
  31. data/dsl/prototype.rb +5 -7
  32. data/dsl/repeat_loop_results.rb +53 -0
  33. data/dsl/ruby_cog.rb +72 -0
  34. data/dsl/simple_agent.rb +18 -0
  35. data/dsl/simple_chat.rb +15 -1
  36. data/dsl/simple_repeat.rb +29 -0
  37. data/dsl/skip.rb +36 -0
  38. data/dsl/step_communication.rb +2 -3
  39. data/dsl/targets_and_params.rb +57 -0
  40. data/dsl/temperature.rb +17 -0
  41. data/dsl/temporary_directory.rb +22 -0
  42. data/dsl/tutorial/01_your_first_workflow/README.md +179 -0
  43. data/dsl/tutorial/01_your_first_workflow/configured_chat.rb +33 -0
  44. data/dsl/tutorial/01_your_first_workflow/hello.rb +23 -0
  45. data/dsl/tutorial/02_chaining_cogs/README.md +310 -0
  46. data/dsl/tutorial/02_chaining_cogs/code_review.rb +104 -0
  47. data/dsl/tutorial/02_chaining_cogs/session_resumption.rb +92 -0
  48. data/dsl/tutorial/02_chaining_cogs/simple_chain.rb +84 -0
  49. data/dsl/tutorial/03_targets_and_params/README.md +230 -0
  50. data/dsl/tutorial/03_targets_and_params/multiple_targets.rb +65 -0
  51. data/dsl/tutorial/03_targets_and_params/single_target.rb +65 -0
  52. data/dsl/tutorial/04_configuration_options/README.md +209 -0
  53. data/dsl/tutorial/04_configuration_options/control_display_and_temperature.rb +104 -0
  54. data/dsl/tutorial/04_configuration_options/simple_config.rb +68 -0
  55. data/dsl/tutorial/05_control_flow/README.md +156 -0
  56. data/dsl/tutorial/05_control_flow/conditional_execution.rb +62 -0
  57. data/dsl/tutorial/05_control_flow/handling_failures.rb +77 -0
  58. data/dsl/tutorial/06_reusable_scopes/README.md +172 -0
  59. data/dsl/tutorial/06_reusable_scopes/accessing_scope_outputs.rb +126 -0
  60. data/dsl/tutorial/06_reusable_scopes/basic_scope.rb +63 -0
  61. data/dsl/tutorial/06_reusable_scopes/parameterized_scope.rb +78 -0
  62. data/dsl/tutorial/07_processing_collections/README.md +152 -0
  63. data/dsl/tutorial/07_processing_collections/basic_map.rb +70 -0
  64. data/dsl/tutorial/07_processing_collections/parallel_map.rb +74 -0
  65. data/dsl/tutorial/08_iterative_workflows/README.md +231 -0
  66. data/dsl/tutorial/08_iterative_workflows/basic_repeat.rb +57 -0
  67. data/dsl/tutorial/08_iterative_workflows/conditional_break.rb +57 -0
  68. data/dsl/tutorial/09_async_cogs/README.md +197 -0
  69. data/dsl/tutorial/09_async_cogs/basic_async.rb +38 -0
  70. data/dsl/tutorial/README.md +222 -0
  71. data/dsl/working_directory.rb +16 -0
  72. data/exe/roast +1 -1
  73. data/internal/documentation/architectural-notes.md +115 -0
  74. data/internal/documentation/doc-comments-external.md +686 -0
  75. data/internal/documentation/doc-comments-internal.md +342 -0
  76. data/internal/documentation/doc-comments.md +211 -0
  77. data/lib/roast/dsl/cog/config.rb +274 -3
  78. data/lib/roast/dsl/cog/input.rb +53 -10
  79. data/lib/roast/dsl/cog/output.rb +297 -8
  80. data/lib/roast/dsl/cog/registry.rb +35 -3
  81. data/lib/roast/dsl/cog/stack.rb +1 -1
  82. data/lib/roast/dsl/cog/store.rb +5 -5
  83. data/lib/roast/dsl/cog.rb +70 -14
  84. data/lib/roast/dsl/cog_input_context.rb +36 -1
  85. data/lib/roast/dsl/cog_input_manager.rb +116 -7
  86. data/lib/roast/dsl/cogs/agent/config.rb +465 -0
  87. data/lib/roast/dsl/cogs/agent/input.rb +81 -0
  88. data/lib/roast/dsl/cogs/agent/output.rb +59 -0
  89. data/lib/roast/dsl/cogs/agent/provider.rb +51 -0
  90. data/lib/roast/dsl/cogs/agent/providers/claude/claude_invocation.rb +185 -0
  91. data/lib/roast/dsl/cogs/agent/providers/claude/message.rb +73 -0
  92. data/lib/roast/dsl/cogs/agent/providers/claude/messages/assistant_message.rb +36 -0
  93. data/lib/roast/dsl/cogs/agent/providers/claude/messages/result_message.rb +61 -0
  94. data/lib/roast/dsl/cogs/agent/providers/claude/messages/system_message.rb +47 -0
  95. data/lib/roast/dsl/cogs/agent/providers/claude/messages/text_message.rb +36 -0
  96. data/lib/roast/dsl/cogs/agent/providers/claude/messages/tool_result_message.rb +47 -0
  97. data/lib/roast/dsl/cogs/agent/providers/claude/messages/tool_use_message.rb +46 -0
  98. data/lib/roast/dsl/cogs/agent/providers/claude/messages/unknown_message.rb +27 -0
  99. data/lib/roast/dsl/cogs/agent/providers/claude/messages/user_message.rb +37 -0
  100. data/lib/roast/dsl/cogs/agent/providers/claude/tool_result.rb +51 -0
  101. data/lib/roast/dsl/cogs/agent/providers/claude/tool_use.rb +48 -0
  102. data/lib/roast/dsl/cogs/agent/providers/claude.rb +31 -0
  103. data/lib/roast/dsl/cogs/agent/stats.rb +92 -0
  104. data/lib/roast/dsl/cogs/agent/usage.rb +62 -0
  105. data/lib/roast/dsl/cogs/agent.rb +75 -0
  106. data/lib/roast/dsl/cogs/chat/config.rb +453 -0
  107. data/lib/roast/dsl/cogs/chat/input.rb +92 -0
  108. data/lib/roast/dsl/cogs/chat/output.rb +64 -0
  109. data/lib/roast/dsl/cogs/chat/session.rb +68 -0
  110. data/lib/roast/dsl/cogs/chat.rb +59 -56
  111. data/lib/roast/dsl/cogs/cmd.rb +251 -61
  112. data/lib/roast/dsl/cogs/ruby.rb +171 -0
  113. data/lib/roast/dsl/command_runner.rb +191 -0
  114. data/lib/roast/dsl/config_manager.rb +58 -11
  115. data/lib/roast/dsl/control_flow.rb +41 -0
  116. data/lib/roast/dsl/execution_manager.rb +162 -32
  117. data/lib/roast/dsl/nil_assertions.rb +23 -0
  118. data/lib/roast/dsl/system_cog/params.rb +32 -0
  119. data/lib/roast/dsl/system_cog.rb +36 -0
  120. data/lib/roast/dsl/system_cogs/call.rb +163 -0
  121. data/lib/roast/dsl/system_cogs/map.rb +454 -0
  122. data/lib/roast/dsl/system_cogs/repeat.rb +242 -0
  123. data/lib/roast/dsl/workflow.rb +26 -16
  124. data/lib/roast/dsl/workflow_context.rb +20 -0
  125. data/lib/roast/dsl/workflow_params.rb +24 -0
  126. data/lib/roast/helpers/minitest_coverage_runner.rb +1 -1
  127. data/lib/roast/sorbet_runtime_stub.rb +154 -0
  128. data/lib/roast/tools/apply_diff.rb +1 -3
  129. data/lib/roast/tools/cmd.rb +4 -3
  130. data/lib/roast/tools/read_file.rb +1 -1
  131. data/lib/roast/tools/update_files.rb +1 -1
  132. data/lib/roast/tools/write_file.rb +1 -1
  133. data/lib/roast/version.rb +1 -1
  134. data/lib/roast/workflow/base_workflow.rb +4 -0
  135. data/lib/roast/workflow/step_loader.rb +14 -2
  136. data/lib/roast-ai.rb +4 -0
  137. data/lib/roast.rb +58 -21
  138. data/{roast.gemspec → roast-ai.gemspec} +9 -13
  139. data/sorbet/rbi/gems/async@2.34.0.rbi +1577 -0
  140. data/sorbet/rbi/gems/cli-kit@5.2.0.rbi +2063 -0
  141. data/sorbet/rbi/gems/{cli-ui@2.3.0.rbi → cli-ui@2.7.0-6bdefd1d06305e5d6ae312ac76f9c88f88658dda.rbi} +1418 -1013
  142. data/sorbet/rbi/gems/console@1.34.2.rbi +1193 -0
  143. data/sorbet/rbi/gems/fiber-annotation@0.2.0.rbi +50 -0
  144. data/sorbet/rbi/gems/fiber-local@1.1.0.rbi +35 -0
  145. data/sorbet/rbi/gems/fiber-storage@1.0.1.rbi +41 -0
  146. data/sorbet/rbi/gems/io-event@1.14.0.rbi +724 -0
  147. data/sorbet/rbi/gems/metrics@0.15.0.rbi +9 -0
  148. data/sorbet/rbi/gems/traces@0.18.2.rbi +9 -0
  149. data/sorbet/rbi/shims/lib/roast/dsl/cog_input_context.rbi +1185 -5
  150. data/sorbet/rbi/shims/lib/roast/dsl/config_context.rbi +311 -5
  151. data/sorbet/rbi/shims/lib/roast/dsl/execution_context.rbi +486 -5
  152. data/sorbet/tapioca/config.yml +6 -0
  153. data/sorbet/tapioca/require.rb +2 -0
  154. metadata +157 -30
  155. data/dsl/less_simple.rb +0 -112
  156. data/dsl/scoped_executors.rb +0 -28
  157. data/dsl/simple.rb +0 -8
  158. data/lib/roast/dsl/cogs/execute.rb +0 -46
  159. data/lib/roast/dsl/cogs/graph.rb +0 -53
  160. data/sorbet/rbi/gems/cgi@0.5.0.rbi +0 -2961
  161. data/sorbet/rbi/gems/claude_swarm@0.1.19.rbi +0 -568
  162. data/sorbet/rbi/gems/cli-kit@5.0.1.rbi +0 -1991
  163. data/sorbet/rbi/gems/dry-configurable@1.3.0.rbi +0 -672
  164. data/sorbet/rbi/gems/dry-core@1.1.0.rbi +0 -1894
  165. data/sorbet/rbi/gems/dry-inflector@1.2.0.rbi +0 -659
  166. data/sorbet/rbi/gems/dry-initializer@3.2.0.rbi +0 -781
  167. data/sorbet/rbi/gems/dry-logic@1.6.0.rbi +0 -1127
  168. data/sorbet/rbi/gems/dry-schema@1.14.1.rbi +0 -3727
  169. data/sorbet/rbi/gems/dry-types@1.8.3.rbi +0 -3969
  170. data/sorbet/rbi/gems/fast-mcp-annotations@1.5.3.rbi +0 -1588
  171. data/sorbet/rbi/gems/mime-types-data@3.2025.0617.rbi +0 -136
  172. data/sorbet/rbi/gems/mime-types@3.7.0.rbi +0 -1342
  173. data/sorbet/rbi/gems/rack@2.2.19.rbi +0 -5676
  174. data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +0 -435
  175. data/sorbet/rbi/gems/yard@0.9.37.rbi +0 -18492
data/lib/roast.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Standard library requires
5
+ require "benchmark"
5
6
  require "digest"
6
7
  require "English"
7
8
  require "erb"
@@ -11,6 +12,7 @@ require "logger"
11
12
  require "net/http"
12
13
  require "open3"
13
14
  require "pathname"
15
+ require "pp"
14
16
  require "securerandom"
15
17
  require "shellwords"
16
18
  require "tempfile"
@@ -28,6 +30,8 @@ require "active_support/core_ext/string"
28
30
  require "active_support/core_ext/string/inflections"
29
31
  require "active_support/isolated_execution_state"
30
32
  require "active_support/notifications"
33
+ require "async"
34
+ require "async/semaphore"
31
35
  require "cli/kit"
32
36
  require "cli/ui"
33
37
  require "diff/lcs"
@@ -40,12 +44,23 @@ require "ruby_llm"
40
44
  require "thor"
41
45
  require "timeout"
42
46
 
47
+ unless defined?(T)
48
+ # NOTE: stubs for sorbet-runtime were being imported from cli-kit. They were removed in cli-kit v5.2
49
+ # Ideally we will not need them at all in the future, but for now I have brought them into the project
50
+ # because a large quantity of legacy code is using sorbet runtime assertions.
51
+ require("roast/sorbet_runtime_stub")
52
+ end
53
+
54
+ # Require project components that will not get automatically loaded
55
+ require "roast/dsl/nil_assertions"
56
+
43
57
  # Autoloading setup
44
58
  require "zeitwerk"
45
59
 
46
60
  # Set up Zeitwerk autoloader
47
61
  loader = Zeitwerk::Loader.for_gem
48
62
  loader.inflector.inflect("dsl" => "DSL")
63
+ loader.ignore("#{__dir__}/roast-ai.rb")
49
64
  loader.setup
50
65
 
51
66
  module Roast
@@ -60,7 +75,7 @@ module Roast
60
75
  option :replay, type: :string, aliases: "-r", desc: "Resume workflow from a specific step. Format: step_name or session_timestamp:step_name"
61
76
  option :pause, type: :string, aliases: "-p", desc: "Pause workflow after a specific step. Format: step_name"
62
77
  option :file_storage, type: :boolean, aliases: "-f", desc: "Use filesystem storage for sessions instead of SQLite"
63
- option :executor, type: :string, default: "default", desc: "Set workflow executor - experimental syntax"
78
+ option :executor, type: :string, default: "default", desc: "Set workflow executor (use 'dsl' for Roast 1.0 Feature Preview)"
64
79
 
65
80
  def execute(*paths)
66
81
  raise Thor::Error, "Workflow configuration file is required" if paths.empty?
@@ -68,8 +83,13 @@ module Roast
68
83
  workflow_path, *files = paths
69
84
 
70
85
  if options[:executor] == "dsl"
71
- puts "⚠️ WARNING: This is an experimental syntax and may break at any time. Don't depend on it."
72
- Roast::DSL::Workflow.from_file(workflow_path)
86
+ $stderr.puts "⚠️ WARNING: You are using Roast 1.0 feature preview. This syntax has not yet been officially released and should not be considered fully stable." if $stderr.tty?
87
+ targets, workflow_args, workflow_kwargs = parse_custom_workflow_args(files, ARGV)
88
+ targets.unshift(options[:target]) if options[:target]
89
+ workflow_params = Roast::DSL::WorkflowParams.new(targets, workflow_args, workflow_kwargs)
90
+ Dir.chdir(ENV["ROAST_WORKING_DIRECTORY"] || Dir.pwd) do
91
+ Roast::DSL::Workflow.from_file(workflow_path, workflow_params)
92
+ end
73
93
  else
74
94
  expanded_workflow_path = if workflow_path.include?("workflow.yml")
75
95
  File.expand_path(workflow_path)
@@ -287,6 +307,24 @@ module Roast
287
307
 
288
308
  private
289
309
 
310
+ #: (Array[String], Array[String]) -> [Array[String], Array[Symbol], Hash[Symbol, String]]
311
+ def parse_custom_workflow_args(parsed_args, raw_args)
312
+ separator_index = raw_args.index("--")
313
+ extra_args = (separator_index ? raw_args[(separator_index + 1)..] : []) || []
314
+ targets = parsed_args.shift(parsed_args.length - extra_args.length)
315
+ args = []
316
+ kwargs = {}
317
+ parsed_args.each do |arg|
318
+ if arg.include?("=")
319
+ key, value = arg.split("=", 2)
320
+ kwargs[key.to_sym] = value if key
321
+ else
322
+ args << arg.to_sym
323
+ end
324
+ end
325
+ [targets, args, kwargs]
326
+ end
327
+
290
328
  def show_example_picker
291
329
  examples = available_examples
292
330
 
@@ -296,7 +334,7 @@ module Roast
296
334
  end
297
335
 
298
336
  puts "Select an option:"
299
- choices = ["Pick from examples", "New from prompt (beta)"]
337
+ choices = ["Pick from examples", "New from prompt (coming soon)"]
300
338
 
301
339
  selected = run_picker(choices, "Select initialization method:")
302
340
 
@@ -304,8 +342,8 @@ module Roast
304
342
  when "Pick from examples"
305
343
  example_choice = run_picker(examples, "Select an example:")
306
344
  copy_example(example_choice) if example_choice
307
- when "New from prompt (beta)"
308
- create_from_prompt
345
+ when "New from prompt (coming soon)"
346
+ show_coming_soon_message
309
347
  end
310
348
  end
311
349
 
@@ -349,22 +387,21 @@ module Roast
349
387
  puts "Successfully copied example '#{example_name}' to current directory."
350
388
  end
351
389
 
352
- def create_from_prompt
353
- puts("Create a new workflow from a description")
390
+ def show_coming_soon_message
391
+ puts
392
+ puts ::CLI::UI.fmt("{{bold:Workflow Generator - Coming Soon}}")
393
+ puts
394
+ puts "The 'New from prompt' workflow generator is being rebuilt to ensure"
395
+ puts "generated workflows are reliable and properly validated."
396
+ puts
397
+ puts "This feature will return with:"
398
+ puts " • Better AI-generated workflow quality"
399
+ puts " • Validation to ensure generated workflows actually work"
400
+ puts " • Integration with Roast's upcoming DSL features"
401
+ puts
402
+ puts "For now, please use 'Pick from examples' to get started."
403
+ puts "You can then customize the example workflow for your needs."
354
404
  puts
355
-
356
- # Execute the workflow generator
357
- generator_path = File.join(Roast::ROOT, "examples", "workflow_generator", "workflow.yml")
358
-
359
- begin
360
- # Execute the workflow generator (it will handle user input)
361
- Roast::Workflow::WorkflowRunner.new(generator_path, [], {}).begin!
362
-
363
- puts
364
- puts("Workflow generation complete!")
365
- rescue => e
366
- puts("Error generating workflow: #{e.message}")
367
- end
368
405
  end
369
406
 
370
407
  class << self
@@ -15,17 +15,10 @@ Gem::Specification.new do |spec|
15
15
  spec.homepage = "https://github.com/Shopify/roast"
16
16
  spec.license = "MIT"
17
17
 
18
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
19
- # to allow pushing to a single host or delete this section to allow pushing to any host.
20
- if spec.respond_to?(:metadata)
21
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
22
- spec.metadata["homepage_uri"] = spec.homepage
23
- spec.metadata["source_code_uri"] = "https://github.com/Shopify/roast"
24
- spec.metadata["changelog_uri"] = "https://github.com/Shopify/roast/blob/main/CHANGELOG.md"
25
- else
26
- raise "RubyGems 2.0 or newer is required to protect against " \
27
- "public gem pushes."
28
- end
18
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = "https://github.com/Shopify/roast"
21
+ spec.metadata["changelog_uri"] = "https://github.com/Shopify/roast/blob/main/CHANGELOG.md"
29
22
 
30
23
  # Specify which files should be added to the gem when it is released.
31
24
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -37,12 +30,15 @@ Gem::Specification.new do |spec|
37
30
  spec.require_paths = ["lib"]
38
31
 
39
32
  spec.add_dependency("activesupport", ">= 7.0")
40
- spec.add_dependency("cli-kit", "~> 5.0")
41
- spec.add_dependency("cli-ui", "2.3.0")
33
+ spec.add_dependency("async", "~> 2.34")
34
+ spec.add_dependency("benchmark", "~> 0.4.1")
35
+ spec.add_dependency("cli-kit", "~> 5.2")
36
+ spec.add_dependency("cli-ui", "~> 2.7")
42
37
  spec.add_dependency("diff-lcs", "~> 1.5")
43
38
  spec.add_dependency("json-schema")
44
39
  spec.add_dependency("open_router", "~> 0.3")
45
40
  spec.add_dependency("raix", "~> 1.0.2")
41
+ spec.add_dependency("rake", "~> 13.3.0") # NOTE: required by Thor
46
42
  spec.add_dependency("ruby-graphviz", "~> 1.2")
47
43
  spec.add_dependency("ruby_llm")
48
44
  spec.add_dependency("sqlite3", "~> 2.6")